diff --git a/README.md b/README.md
index 0dc9ea2b..24eddc59 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,19 @@
-This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+# 점 갯수 별 타입
-## Getting Started
+## 점 6개
-First, run the development server:
+### type1
-```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
-```
+
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+### type2
-You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
+
-This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
+### type3
-## Learn More
+
-To learn more about Next.js, take a look at the following resources:
+### type4
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
+
diff --git a/package.json b/package.json
index f2e0691a..78ce1907 100644
--- a/package.json
+++ b/package.json
@@ -9,10 +9,13 @@
"lint": "next lint"
},
"dependencies": {
+ "@nextui-org/react": "^2.4.2",
"fabric": "^5.3.0",
+ "framer-motion": "^11.2.13",
"next": "14.2.3",
"react": "^18",
"react-dom": "^18",
+ "recoil": "^0.7.7",
"uuid": "^9.0.1"
},
"devDependencies": {
diff --git a/public/assets/img/check.jpg b/public/assets/img/check.jpg
new file mode 100644
index 00000000..83c66d2f
Binary files /dev/null and b/public/assets/img/check.jpg differ
diff --git a/public/assets/img/check2.png b/public/assets/img/check2.png
new file mode 100644
index 00000000..6abee7b1
Binary files /dev/null and b/public/assets/img/check2.png differ
diff --git a/src/app/RecoilWrapper.js b/src/app/RecoilWrapper.js
new file mode 100644
index 00000000..89cb9776
--- /dev/null
+++ b/src/app/RecoilWrapper.js
@@ -0,0 +1,6 @@
+'use client'
+import { RecoilRoot } from 'recoil'
+
+export default function RecoilRootWrapper({ children }) {
+ return {children}
+}
diff --git a/src/app/UIProvider.js b/src/app/UIProvider.js
new file mode 100644
index 00000000..02a21441
--- /dev/null
+++ b/src/app/UIProvider.js
@@ -0,0 +1,5 @@
+import { NextUIProvider } from '@nextui-org/react'
+
+export default function UIProvider({ children }) {
+ return {children}
+}
diff --git a/src/app/changelog/page.jsx b/src/app/changelog/page.jsx
new file mode 100644
index 00000000..821254ec
--- /dev/null
+++ b/src/app/changelog/page.jsx
@@ -0,0 +1,40 @@
+'use client'
+
+import Hero from '@/components/Hero'
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableColumn,
+ TableHeader,
+ TableRow,
+} from '@nextui-org/react'
+
+export default function changelogPage() {
+ return (
+ <>
+
+
{
+ if (!canvas) {
+ return
+ }
+ changeMode(canvas, mode)
+ }, [canvas, mode])
+
+ const makeRect = () => {
+ if (canvas) {
+ const rect = new QRect({
+ left: 100,
+ top: 100,
+ fill: 'transparent',
+ stroke: 'black',
+ width: 400,
+ height: 100,
+ fontSize: fontSize,
+ })
+
+ canvas?.add(rect)
+ }
+ }
+
+ const makeLine = () => {
+ if (canvas) {
+ const line = new QLine([50, 50, 200, 50], {
+ stroke: 'black',
+ strokeWidth: 2,
+ fontSize: fontSize,
+ })
+
+ canvas?.add(line)
+ }
+ }
+
+ const makePolygon = () => {
+ if (canvas) {
+ const polygon = new QPolygon(
+ [
+ { x: 100, y: 100 },
+ { x: 600, y: 200 },
+ { x: 700, y: 800 },
+ { x: 100, y: 800 },
+ ],
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: true,
+ fontSize: fontSize,
+ },
+ canvas,
+ )
+
+ canvas?.add(polygon)
+
+ polygon.fillCell({ width: 50, height: 30, padding: 10 })
+ }
+ }
+
+ /**
+ * canvas 사이즈 변경 함수
+ */
+ const canvasSizeMode = () => {
+ if (canvas) {
+ canvas.setWidth(horizontalSize)
+ canvas.setHeight(verticalSize)
+ canvas.renderAll()
+
+ setCanvasSize(() => ({
+ vertical: verticalSize,
+ horizontal: horizontalSize,
+ }))
+ }
+ }
+
+ /**
+ * 값 변경시
+ */
+ useEffect(() => {
+ canvasSizeMode()
+ }, [verticalSize, horizontalSize])
+
+ const makeQPolygon = () => {
+ const type1 = [
+ { x: 100, y: 100 },
+ { x: 850, y: 100 },
+ { x: 850, y: 800 },
+ { x: 500, y: 800 },
+ { x: 500, y: 400 },
+ { x: 100, y: 400 },
+ ]
+ const type2 = [
+ { x: 100, y: 100 },
+ { x: 100, y: 1000 },
+ { x: 1000, y: 1000 },
+ { x: 1000, y: 600 },
+ { x: 550, y: 600 },
+ { x: 550, y: 100 },
+ ]
+
+ const type3 = [
+ { x: 200, y: 100 },
+ { x: 200, y: 800 },
+ { x: 500, y: 800 },
+ { x: 500, y: 300 },
+ { x: 800, y: 300 },
+ { x: 800, y: 100 },
+ ]
+
+ const type4 = [
+ { x: 150, y: 450 },
+ { x: 150, y: 800 },
+ { x: 750, y: 800 },
+ { x: 750, y: 300 },
+ { x: 550, y: 300 },
+ { x: 550, y: 450 },
+ ]
+ if (canvas) {
+ const polygon = new QPolygon(
+ type4,
+ {
+ fill: 'transparent',
+ stroke: 'black',
+ strokeWidth: 1,
+ selectable: true,
+ fontSize: fontSize,
+ name: 'QPolygon1',
+ },
+ canvas, // 필수로 넣어줘야 함
+ )
+
+ canvas?.add(polygon)
+
+ handleOuterlinesTest2(polygon)
+
+ // const lines = togglePolygonLine(polygon)
+ // togglePolygonLine(lines[0])
+ }
+ }
+
+ const rotateShape = () => {
+ if (canvas) {
+ const activeObject = canvas?.getActiveObject()
+
+ if (activeObject) {
+ activeObject.rotate(angle)
+ canvas?.renderAll()
+ }
+ }
+ }
+
+ const makeQLine = () => {
+ if (canvas) {
+ const line = new QLine(
+ [50, 50, 200, 50],
+ {
+ stroke: 'black',
+ strokeWidth: 1,
+ fontSize: fontSize,
+ },
+ 50,
+ )
+
+ canvas?.add(line)
+ }
+ }
+
+ const addBackgroundInPolygon = (polygon) => {
+ fabric.Image.fromURL('assets/img/check2.png', function (img) {
+ // 패턴 객체를 생성합니다.
+ const pattern = new fabric.Pattern({
+ source: img.getElement(),
+ repeat: 'repeat',
+ })
+
+ polygon.fillBackground(pattern)
+ })
+ }
+
+ function PolygonToLine() {
+ const polygon = canvas?.getActiveObject()
+
+ if (polygon.type !== 'QPolygon') {
+ return
+ }
+
+ const lines = togglePolygonLine(polygon)
+ }
+
+ const handleShowController = () => {
+ setShowControl(!showControl)
+ }
+
+ return (
+ <>
+ {canvas && (
+ <>
+
+
+ 모드 DEFAULT
+
+ changeMode(canvas, Mode.DRAW_LINE)}
+ >
+ 기준선 긋기 모드
+
+ changeMode(canvas, Mode.EDIT)}
+ >
+ 에디팅모드
+
+ changeMode(canvas, Mode.TEMPLATE)}
+ >
+ 템플릿(기둥)
+
+ {}}
+ >
+ 템플릿(A 패턴)
+
+
+ 템플릿(B 패턴)
+
+ changeMode(canvas, Mode.TEXTBOX)}
+ >
+ 텍스트박스 모드
+
+ changeMode(canvas, Mode.DRAW_RECT)}
+ >
+ 사각형 생성 모드
+
+
+ Undo
+
+
+ Redo
+
+
+ clear
+
+
+ 확대
+
+
+ 축소
+
+ 현재 줌 : {zoom}%
+
+ 사각형만들기
+
+
+ 선 추가
+
+
+ 다각형 추가
+
+ {
+ setCanvasBackgroundWithDots(canvas, 10)
+ }}
+ >
+ 점선 추가
+
+ {
+ setCanvasBackgroundWithDots(canvas, 20)
+ }}
+ >
+ 점선 추가
+
+
+ 저장
+
+
+ QPolygon
+
+
+ 회전
+
+
+ QLine
+
+
+ PolygonToLine
+
+
+ canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+ >
+ )
+}
diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js
new file mode 100644
index 00000000..9ccb1a5c
--- /dev/null
+++ b/src/components/fabric/QLine.js
@@ -0,0 +1,108 @@
+import { fabric } from 'fabric'
+
+export class QLine extends fabric.Group {
+ line
+ text
+ fontSize
+ length = 0
+ x1
+ y1
+ x2
+ y2
+ direction
+ type = 'QLine'
+ parent
+ #lengthTxt = 0
+
+ constructor(points, option, lengthTxt) {
+ const [x1, y1, x2, y2] = points
+
+ if (!option.fontSize) {
+ throw new Error('Font size is required.')
+ }
+
+ const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
+ super([line], {})
+
+ this.x1 = x1
+ this.y1 = y1
+ this.x2 = x2
+ this.y2 = y2
+ this.line = line
+ this.fontSize = option.fontSize
+ this.direction = option.direction
+ this.parent = option.parent
+
+ if (lengthTxt > 0) {
+ this.#lengthTxt = Number(lengthTxt)
+ }
+
+ this.#init()
+ this.#addControl()
+ }
+
+ #init() {
+ this.#addLengthText(true)
+ }
+
+ #addControl() {
+ this.on('moving', () => {
+ this.#addLengthText(false)
+ })
+
+ this.on('modified', (e) => {
+ this.#addLengthText(false)
+ })
+
+ this.on('selected', () => {
+ Object.keys(this.controls).forEach((controlKey) => {
+ if (controlKey !== 'ml' && controlKey !== 'mr') {
+ this.setControlVisible(controlKey, false)
+ }
+ })
+ })
+ }
+
+ #addLengthText(isFirst) {
+ if (this.text) {
+ this.removeWithUpdate(this.text)
+ this.text = null
+ }
+
+ if (isFirst && this.#lengthTxt > 0) {
+ const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), {
+ left: (this.x1 + this.x2) / 2,
+ top: (this.y1 + this.y2) / 2,
+ fontSize: this.fontSize,
+ })
+ this.length = this.#lengthTxt
+ this.text = text
+ this.addWithUpdate(text)
+ return
+ }
+
+ const scaleX = this.scaleX
+ const scaleY = this.scaleY
+ const x1 = this.left
+ const y1 = this.top
+ const x2 = this.left + this.width * scaleX
+ const y2 = this.top + this.height * scaleY
+ const dx = x2 - x1
+ const dy = y2 - y1
+ this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
+
+ const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
+ left: (x1 + x2) / 2,
+ top: (y1 + y2) / 2,
+ fontSize: this.fontSize,
+ })
+ this.text = text
+ this.addWithUpdate(text)
+ }
+
+ setFontSize(fontSize) {
+ this.fontSize = fontSize
+ this.text.set({ fontSize })
+ this.addWithUpdate()
+ }
+}
diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js
new file mode 100644
index 00000000..93d39298
--- /dev/null
+++ b/src/components/fabric/QPolygon.js
@@ -0,0 +1,924 @@
+import { fabric } from 'fabric'
+import {
+ distanceBetweenPoints,
+ findTopTwoIndexesByDistance,
+ getDegreeByChon,
+ getDirectionByPoint,
+ getRoofHeight,
+ getRoofHypotenuse,
+ sortedPoints,
+} from '@/util/canvas-util'
+import { QLine } from '@/components/fabric/QLine'
+
+export default class QPolygon extends fabric.Group {
+ type = 'QPolygon'
+ polygon
+ points
+ texts = []
+ lines = []
+ canvas
+ fontSize
+ qCells = []
+ name
+ shape = 0 // 점 6개일때의 shape 모양
+ helpPoints = []
+ helpLines = []
+ constructor(points, options, canvas) {
+ if (points.length !== 4 && points.length !== 6) {
+ throw new Error('Points must be 4 or 6.')
+ }
+ if (!options.fontSize) {
+ throw new Error('Font size is required.')
+ }
+
+ const sortPoints = sortedPoints(points)
+ const polygon = new fabric.Polygon(sortPoints, options)
+
+ super([polygon], {})
+
+ this.fontSize = options.fontSize
+ this.points = sortPoints
+ this.polygon = polygon
+ this.name = options.name
+ this.#init()
+ this.#addEvent()
+ this.#initLines()
+ this.setShape()
+ }
+
+ #initLines() {
+ this.points.forEach((point, i) => {
+ const nextPoint = this.points[(i + 1) % this.points.length]
+ const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
+ stroke: this.stroke,
+ strokeWidth: this.strokeWidth,
+ fontSize: this.fontSize,
+ direction: getDirectionByPoint(point, nextPoint),
+ })
+
+ this.lines.push(line)
+ })
+ }
+
+ #init() {
+ this.#addLengthText()
+ }
+
+ #addEvent() {
+ this.on('scaling', (e) => {
+ this.#updateLengthText()
+ })
+
+ this.on('selected', function () {
+ // 모든 컨트롤 떼기
+
+ Object.keys(this.controls).forEach((controlKey) => {
+ if (controlKey !== 'mtr') {
+ this.setControlVisible(controlKey, false)
+ }
+ })
+ })
+ }
+
+ setFontSize(fontSize) {
+ this.fontSize = fontSize
+ this.texts.forEach((text) => {
+ text.set({ fontSize })
+ })
+
+ this.getObjects().forEach((obj) => {
+ if (obj.type[0] === 'Q') {
+ obj.setFontSize(fontSize)
+ }
+ })
+
+ this.addWithUpdate()
+ }
+
+ #addLengthText() {
+ if (this.texts.length > 0) {
+ this.texts.forEach((text) => {
+ this.canvas.remove(text)
+ })
+ this.texts = []
+ }
+ const points = this.points
+
+ points.forEach((start, i) => {
+ const end = points[(i + 1) % points.length]
+ const dx = end.x - start.x
+ const dy = end.y - start.y
+ const length = Math.sqrt(dx * dx + dy * dy)
+
+ const midPoint = new fabric.Point(
+ (start.x + end.x) / 2,
+ (start.y + end.y) / 2,
+ )
+
+ // Create new text object if it doesn't exist
+ const text = new fabric.Text(length.toFixed(0), {
+ left: midPoint.x,
+ top: midPoint.y,
+ fontSize: this.fontSize,
+ selectable: false,
+ })
+
+ this.texts.push(text)
+ this.addWithUpdate(text)
+ })
+
+ this.canvas.renderAll()
+ }
+
+ #updateLengthText() {
+ const points = this.getCurrentPoints()
+
+ points.forEach((start, i) => {
+ const end = points[(i + 1) % points.length]
+ const dx = end.x - start.x
+ const dy = end.y - start.y
+ const length = Math.sqrt(dx * dx + dy * dy)
+
+ // Update the text object with the new length
+ this.texts[i].set({ text: length.toFixed(0) })
+ })
+
+ this.canvas.renderAll()
+ }
+
+ fillCell(cell = { width: 50, height: 100, padding: 10 }) {
+ const points = this.getCurrentPoints()
+ let bounds
+
+ try {
+ bounds = fabric.util.makeBoundingBoxFromPoints(points)
+ } catch (error) {
+ alert('다각형의 꼭지점이 4개 이상이어야 합니다.')
+ return
+ }
+
+ for (
+ let x = bounds.left;
+ x < bounds.left + bounds.width;
+ x += cell.width + cell.padding
+ ) {
+ for (
+ let y = bounds.top;
+ y < bounds.top + bounds.height;
+ y += cell.height + cell.padding
+ ) {
+ const rect = new fabric.Rect({
+ left: x,
+ top: y,
+ width: cell.width,
+ height: cell.height,
+ fill: 'transparent',
+ stroke: 'black',
+ selectable: false,
+ })
+
+ const rectPoints = [
+ new fabric.Point(rect.left, rect.top),
+ new fabric.Point(rect.left + rect.width, rect.top),
+ new fabric.Point(rect.left, rect.top + rect.height),
+ new fabric.Point(rect.left + rect.width, rect.top + rect.height),
+ ]
+
+ const isInside = rectPoints.every(
+ (rectPoint) =>
+ this.inPolygon(rectPoint) &&
+ this.#distanceFromEdge(rectPoint) >= cell.padding,
+ )
+
+ if (isInside) {
+ this.addWithUpdate(rect)
+ }
+ }
+ }
+
+ this.canvas.renderAll()
+ }
+
+ /**
+ * this.lines의 direction이 top 인 line의 모든 합이 bottom 인 line의 모든 합과 같은지 확인
+ * this.lines의 direction이 left 인 line의 모든 합이 right 인 line의 모든 합과 같은지 확인
+ * return {boolean}
+ */
+ isValid() {
+ const leftLinesLengthSum = this.lines
+ .filter((line) => line.direction === 'left')
+ .reduce((sum, line) => sum + line.length, 0)
+ const rightLinesLengthSum = this.lines
+ .filter((line) => line.direction === 'right')
+ .reduce((sum, line) => sum + line.length, 0)
+
+ const topLinesLengthSum = this.lines
+ .filter((line) => line.direction === 'top')
+ .reduce((sum, line) => sum + line.length, 0)
+ const bottomLinesLengthSum = this.lines
+ .filter((line) => line.direction === 'bottom')
+ .reduce((sum, line) => sum + line.length, 0)
+
+ return (
+ leftLinesLengthSum === rightLinesLengthSum &&
+ topLinesLengthSum === bottomLinesLengthSum
+ )
+ }
+
+ inPolygon(point) {
+ const vertices = this.getCurrentPoints()
+ let intersects = 0
+
+ for (let i = 0; i < vertices.length; i++) {
+ let vertex1 = vertices[i]
+ let vertex2 = vertices[(i + 1) % vertices.length]
+
+ if (vertex1.y > vertex2.y) {
+ let tmp = vertex1
+ vertex1 = vertex2
+ vertex2 = tmp
+ }
+
+ if (point.y === vertex1.y || point.y === vertex2.y) {
+ point.y += 0.01
+ }
+
+ if (point.y <= vertex1.y || point.y > vertex2.y) {
+ continue
+ }
+
+ let xInt =
+ ((point.y - vertex1.y) * (vertex2.x - vertex1.x)) /
+ (vertex2.y - vertex1.y) +
+ vertex1.x
+ if (xInt < point.x) {
+ intersects++
+ }
+ }
+
+ return intersects % 2 === 1
+ }
+
+ #distanceFromEdge(point) {
+ const vertices = this.getCurrentPoints()
+ let minDistance = Infinity
+
+ for (let i = 0; i < vertices.length; i++) {
+ let vertex1 = vertices[i]
+ let vertex2 = vertices[(i + 1) % vertices.length]
+
+ const dx = vertex2.x - vertex1.x
+ const dy = vertex2.y - vertex1.y
+
+ const t =
+ ((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) /
+ (dx * dx + dy * dy)
+
+ let closestPoint
+ if (t < 0) {
+ closestPoint = vertex1
+ } else if (t > 1) {
+ closestPoint = vertex2
+ } else {
+ closestPoint = new fabric.Point(vertex1.x + t * dx, vertex1.y + t * dy)
+ }
+
+ const distance = distanceBetweenPoints(point, closestPoint)
+ if (distance < minDistance) {
+ minDistance = distance
+ }
+ }
+
+ return minDistance
+ }
+
+ setViewLengthText(boolean) {
+ this.texts.forEach((text) => {
+ text.visible = boolean
+ })
+
+ this.canvas.renderAll()
+ }
+
+ getCurrentPoints() {
+ const scaleX = this.scaleX
+ const scaleY = this.scaleY
+
+ const left = this.left
+ const top = this.top
+
+ // 시작점
+ const point = this.points[0]
+
+ const movingX = left - point.x * scaleX
+ const movingY = top - point.y * scaleY
+
+ return this.points.map((point) => {
+ return {
+ x: point.x * scaleX + movingX,
+ y: point.y * scaleY + movingY,
+ }
+ })
+ }
+
+ fillBackground(pattern) {
+ this.polygon.set({ fill: pattern })
+ this.canvas.requestRenderAll()
+ }
+
+ // 보조선 그리기
+ drawHelpLine(chon = 4) {
+ if (!this.isValid()) {
+ return
+ }
+
+ if (this.lines.length === 4) {
+ this.#drawHelpLineInRect(chon)
+ } else if (this.lines.length === 6) {
+ // TODO : 6각형
+ this.#drawHelpLineInHexagon(chon)
+ } else if (this.lines.length === 8) {
+ // TODO : 8각형
+ this.#drawHelpLineInOctagon(chon)
+ }
+ }
+
+ /**
+ * 현재 점 6개만 가능
+ */
+ setShape() {
+ let shape = 0
+ if (this.lines.length !== 6) {
+ return
+ }
+ //외각선 기준
+ const topIndex = findTopTwoIndexesByDistance(this.lines).sort(
+ (a, b) => a - b,
+ ) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨
+
+ //일단 배열 6개 짜리 기준의 선 번호
+ if (topIndex[0] === 4) {
+ if (topIndex[1] === 5) {
+ //1번
+ shape = 1
+ }
+ } else if (topIndex[0] === 1) {
+ //4번
+ if (topIndex[1] === 2) {
+ shape = 4
+ }
+ } else if (topIndex[0] === 0) {
+ if (topIndex[1] === 1) {
+ //2번
+ shape = 2
+ } else if (topIndex[1] === 5) {
+ //3번
+ shape = 3
+ }
+ }
+
+ this.shape = shape
+ }
+
+ /**
+ * 현재 점 6개만 가능
+ * @returns {number}
+ */
+ getShape() {
+ return this.shape
+ }
+
+ #drawHelpLineInRect(chon) {
+ let type = 1
+ let smallestLength = Infinity
+ let maxLength = 0
+
+ this.lines.forEach((line) => {
+ if (line.length < smallestLength) {
+ smallestLength = line.length
+ }
+ if (line.length > maxLength) {
+ maxLength = line.length
+ }
+ })
+
+ // QPolygon 객체의 모든 선들을 가져옵니다.
+ const lines = [...this.lines]
+
+ // 이 선들을 길이에 따라 정렬합니다.
+ lines.sort((a, b) => a.length - b.length)
+
+ // 정렬된 배열에서 가장 작은 두 선을 선택합니다.
+ let smallestLines
+
+ if (smallestLength === maxLength) {
+ // 정사각형인 경우 0, 2번째 라인이 가장 짧은 라인
+
+ smallestLines = [lines[0], lines[2]]
+ } else {
+ smallestLines = lines.slice(0, 2)
+ }
+
+ let needPlusLine
+ let needMinusLine
+
+ const direction = smallestLines[0].direction
+
+ if (direction === 'top' || direction === 'bottom') {
+ needPlusLine =
+ smallestLines[0].x1 < smallestLines[1].x1
+ ? smallestLines[0]
+ : smallestLines[1]
+ needMinusLine =
+ needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
+
+ type = 1 // 가로가 긴 사각형
+ }
+
+ if (direction === 'left' || direction === 'right') {
+ needPlusLine =
+ smallestLines[0].y1 < smallestLines[1].y1
+ ? smallestLines[0]
+ : smallestLines[1]
+ needMinusLine =
+ needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
+
+ type = 2 // 세로가 긴 사각형
+ }
+
+ let point1
+ let point2
+
+ if (type === 1) {
+ point1 = {
+ x: needPlusLine.x1 + smallestLength / 2,
+ y:
+ needPlusLine.y1 > needPlusLine.y2
+ ? needPlusLine.y1 - smallestLength / 2
+ : needPlusLine.y2 - smallestLength / 2,
+ }
+
+ point2 = {
+ x: needMinusLine.x1 - smallestLength / 2,
+ y:
+ needMinusLine.y1 > needMinusLine.y2
+ ? needMinusLine.y1 - smallestLength / 2
+ : needMinusLine.y2 - smallestLength / 2,
+ }
+ } else if (type === 2) {
+ point1 = {
+ x:
+ needPlusLine.x1 > needPlusLine.x2
+ ? needPlusLine.x1 - smallestLength / 2
+ : needPlusLine.x2 - smallestLength / 2,
+ y: needPlusLine.y1 + smallestLength / 2,
+ }
+
+ point2 = {
+ x:
+ needMinusLine.x1 > needMinusLine.x2
+ ? needMinusLine.x1 - smallestLength / 2
+ : needMinusLine.x2 - smallestLength / 2,
+ y: needMinusLine.y1 - smallestLength / 2,
+ }
+ }
+
+ // 빗변1
+ const realLine1 = new QLine(
+ [needPlusLine.x1, needPlusLine.y1, point1.x, point1.y],
+ { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 },
+ getRoofHypotenuse(smallestLength / 2),
+ )
+
+ // 빗변2
+ const realLine2 = new QLine(
+ [needPlusLine.x2, needPlusLine.y2, point1.x, point1.y],
+ { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 },
+ getRoofHypotenuse(smallestLength / 2),
+ )
+
+ // 빗변3
+ const realLine3 = new QLine(
+ [needMinusLine.x1, needMinusLine.y1, point2.x, point2.y],
+ { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 },
+ getRoofHypotenuse(smallestLength / 2),
+ )
+
+ // 빗변4
+ const realLine4 = new QLine(
+ [needMinusLine.x2, needMinusLine.y2, point2.x, point2.y],
+ { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 },
+ getRoofHypotenuse(smallestLength / 2),
+ )
+
+ let centerPoint1
+ let centerPoint2
+
+ if (type === 1) {
+ centerPoint1 = { x: point1.x - smallestLength / 2, y: point1.y }
+ centerPoint2 = { x: point2.x + smallestLength / 2, y: point2.y }
+ } else if (type === 2) {
+ centerPoint1 = { x: point1.x, y: point1.y - smallestLength / 2 }
+ centerPoint2 = { x: point2.x, y: point2.y + smallestLength / 2 }
+ }
+
+ // 옆으로 누워있는 지붕의 높이
+ const realLine5 = new QLine(
+ [point1.x, point1.y, centerPoint1.x, centerPoint1.y],
+ {
+ fontSize: this.fontSize,
+ stroke: 'black',
+ strokeWidth: 1,
+ strokeDashArray: [5, 5],
+ },
+ getRoofHeight(smallestLength / 2, getDegreeByChon(chon)),
+ )
+
+ // 옆으로 누워있는 지붕의 높이
+ const realLine6 = new QLine(
+ [point2.x, point2.y, centerPoint2.x, centerPoint2.y],
+ {
+ fontSize: this.fontSize,
+ stroke: 'black',
+ strokeWidth: 1,
+ strokeDashArray: [5, 5],
+ },
+ getRoofHeight(smallestLength / 2, getDegreeByChon(chon)),
+ )
+
+ // 용마루
+ const ridge = new QLine([point1.x, point1.y, point2.x, point2.y], {
+ fontSize: this.fontSize,
+ stroke: 'black',
+ strokeWidth: 1,
+ })
+
+ this.addWithUpdate(realLine1)
+ this.addWithUpdate(realLine2)
+ this.addWithUpdate(realLine3)
+ this.addWithUpdate(realLine4)
+ this.addWithUpdate(realLine5)
+ this.addWithUpdate(realLine6)
+ if (smallestLength !== maxLength) {
+ // 정사각형이 아닌경우에만 용마루를 추가한다.
+ this.canvas.add(ridge)
+ }
+ }
+
+ #drawHelpLineInHexagon(chon) {
+ let type = this.shape
+
+ // 1 = 0, 3
+ // 2 = 2, 5
+ // 3 = 1, 4
+ // 4 = 0, 3
+
+ // 라인 기준점 1,2
+ let lines, lines2
+ // 용마루 시작점 2개
+ let vPoint1, vPoint2
+ // 용마루 시작점과 만나는 지붕의 중앙
+ let centerPoint1, centerPoint2
+
+ // 가장 긴 라인
+ let longestLines
+
+ // 용마루 길이
+ let ridgeLength = 0
+ let ridgeStartPoint1, ridgeStartPoint2
+
+ let ridgeEndPoint1, ridgeEndPoint2
+
+ let ridgeLength1, ridgeLength2
+
+ let ridgeHelpLinePoint1, ridgeHelpLinePoint2
+
+ if (type === 1) {
+ lines = [this.lines[0], this.lines[3]]
+ lines2 = [this.lines[1], this.lines[4]]
+ longestLines = [this.lines[4], this.lines[5]]
+ ridgeLength1 = lines2[0].length
+ ridgeLength2 = longestLines[0].length - lines[1].length
+ vPoint1 = {
+ x: lines[0].x1 + lines[0].length / 2,
+ y: lines[0].y1 + lines[0].length / 2,
+ }
+ vPoint2 = {
+ x: lines[1].x1 + lines[1].length / 2,
+ y: lines[1].y1 - lines[1].length / 2,
+ }
+ centerPoint1 = {
+ x: (lines[0].x1 + lines[0].x2) / 2,
+ y: (lines[0].y1 + lines[0].y2) / 2,
+ }
+ centerPoint2 = {
+ x: (lines[1].x1 + lines[1].x2) / 2,
+ y: (lines[1].y1 + lines[1].y2) / 2,
+ }
+
+ ridgeEndPoint1 = [
+ vPoint1.x,
+ vPoint1.y,
+ vPoint1.x + ridgeLength1,
+ vPoint1.y,
+ ]
+ ridgeEndPoint2 = [
+ vPoint2.x,
+ vPoint2.y,
+ vPoint2.x,
+ vPoint2.y - ridgeLength2,
+ ]
+
+ ridgeHelpLinePoint1 = [
+ lines2[0].x2,
+ lines2[0].y2,
+ ridgeEndPoint1[2],
+ ridgeEndPoint1[3],
+ ]
+ ridgeHelpLinePoint2 = [
+ lines2[1].x2,
+ lines2[1].y2,
+ ridgeEndPoint2[2],
+ ridgeEndPoint2[3],
+ ]
+ } else if (type === 2) {
+ lines = [this.lines[2], this.lines[5]]
+ lines2 = [this.lines[0], this.lines[3]]
+ longestLines = [this.lines[0], this.lines[1]]
+ ridgeLength1 = lines2[1].length
+ ridgeLength2 = longestLines[0].length - lines[1].length
+ vPoint1 = {
+ x: lines[0].x1 - lines[0].length / 2,
+ y: lines[0].y1 - lines[0].length / 2,
+ }
+ vPoint2 = {
+ x: lines[1].x1 - lines[1].length / 2,
+ y: lines[1].y1 + lines[1].length / 2,
+ }
+ centerPoint1 = {
+ x: (lines[0].x1 + lines[0].x2) / 2,
+ y: (lines[0].y1 + lines[0].y2) / 2,
+ }
+ centerPoint2 = {
+ x: (lines[1].x1 + lines[1].x2) / 2,
+ y: (lines[1].y1 + lines[1].y2) / 2,
+ }
+
+ ridgeEndPoint1 = [
+ vPoint1.x,
+ vPoint1.y,
+ vPoint1.x - ridgeLength1,
+ vPoint1.y,
+ ]
+
+ ridgeEndPoint2 = [
+ vPoint2.x,
+ vPoint2.y,
+ vPoint2.x,
+ vPoint2.y + ridgeLength2,
+ ]
+
+ ridgeHelpLinePoint1 = [
+ lines2[1].x2,
+ lines2[1].y2,
+ ridgeEndPoint1[2],
+ ridgeEndPoint1[3],
+ ]
+ ridgeHelpLinePoint2 = [
+ lines2[0].x2,
+ lines2[0].y2,
+ ridgeEndPoint2[2],
+ ridgeEndPoint2[3],
+ ]
+ } else if (type === 3) {
+ lines = [this.lines[1], this.lines[4]]
+ lines2 = [this.lines[2], this.lines[5]]
+ longestLines = [this.lines[0], this.lines[5]]
+ ridgeLength1 = this.lines[3].length
+ ridgeLength2 = longestLines[0].length - lines[0].length
+ vPoint1 = {
+ x: lines[0].x1 + lines[0].length / 2,
+ y: lines[0].y1 - lines[0].length / 2,
+ }
+ vPoint2 = {
+ x: lines[1].x1 - lines[1].length / 2,
+ y: lines[1].y1 - lines[1].length / 2,
+ }
+ centerPoint1 = {
+ x: (lines[0].x1 + lines[0].x2) / 2,
+ y: (lines[0].y1 + lines[0].y2) / 2,
+ }
+ centerPoint2 = {
+ x: (lines[1].x1 + lines[1].x2) / 2,
+ y: (lines[1].y1 + lines[1].y2) / 2,
+ }
+
+ ridgeEndPoint1 = [
+ vPoint1.x,
+ vPoint1.y,
+ vPoint1.x,
+ vPoint1.y - ridgeLength2,
+ ]
+
+ ridgeEndPoint2 = [
+ vPoint2.x,
+ vPoint2.y,
+ vPoint2.x - ridgeLength1,
+ vPoint2.y,
+ ]
+
+ ridgeHelpLinePoint1 = [
+ lines2[1].x2,
+ lines2[1].y2,
+ ridgeEndPoint1[2],
+ ridgeEndPoint1[3],
+ ]
+ ridgeHelpLinePoint2 = [
+ lines2[0].x2,
+ lines2[0].y2,
+ ridgeEndPoint2[2],
+ ridgeEndPoint2[3],
+ ]
+ } else if (type === 4) {
+ lines = [this.lines[0], this.lines[3]]
+ lines2 = [this.lines[1], this.lines[4]]
+ longestLines = [this.lines[1], this.lines[2]]
+ ridgeLength1 = longestLines[0].length - lines[0].length
+ ridgeLength2 = this.lines[4].length
+ vPoint1 = {
+ x: lines[0].x1 + lines[0].length / 2,
+ y: lines[0].y1 + lines[0].length / 2,
+ }
+ vPoint2 = {
+ x: lines[1].x1 - lines[1].length / 2,
+ y: lines[1].y1 + lines[1].length / 2,
+ }
+ centerPoint1 = {
+ x: (lines[0].x1 + lines[0].x2) / 2,
+ y: (lines[0].y1 + lines[0].y2) / 2,
+ }
+ centerPoint2 = {
+ x: (lines[1].x1 + lines[1].x2) / 2,
+ y: (lines[1].y1 + lines[1].y2) / 2,
+ }
+
+ ridgeEndPoint1 = [
+ vPoint1.x,
+ vPoint1.y,
+ vPoint1.x + ridgeLength1,
+ vPoint1.y,
+ ]
+
+ ridgeEndPoint2 = [
+ vPoint2.x,
+ vPoint2.y,
+ vPoint2.x,
+ vPoint2.y + ridgeLength2,
+ ]
+
+ ridgeHelpLinePoint1 = [
+ lines2[0].x2,
+ lines2[0].y2,
+ ridgeEndPoint1[2],
+ ridgeEndPoint1[3],
+ ]
+ ridgeHelpLinePoint2 = [
+ lines2[1].x2,
+ lines2[1].y2,
+ ridgeEndPoint2[2],
+ ridgeEndPoint2[3],
+ ]
+ }
+
+ const realLine1 = new QLine(
+ [lines[0].x1, lines[0].y1, vPoint1.x, vPoint1.y],
+ { fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
+ getRoofHypotenuse(lines[0].length / 2),
+ )
+
+ const realLine2 = new QLine(
+ [lines[0].x2, lines[0].y2, vPoint1.x, vPoint1.y],
+ { fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
+ getRoofHypotenuse(lines[0].length / 2),
+ )
+
+ const realLine3 = new QLine(
+ [lines[1].x1, lines[1].y1, vPoint2.x, vPoint2.y],
+ { fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
+ getRoofHypotenuse(lines[1].length / 2),
+ )
+
+ const realLine4 = new QLine(
+ [lines[1].x2, lines[1].y2, vPoint2.x, vPoint2.y],
+ { fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
+ getRoofHypotenuse(lines[1].length / 2),
+ )
+
+ // 옆으로 누워있는 지붕의 높이 점선
+ const realLine5 = new QLine(
+ [vPoint1.x, vPoint1.y, centerPoint1.x, centerPoint1.y],
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ strokeDashArray: [5, 5],
+ },
+ getRoofHeight(lines[0].length / 2, getDegreeByChon(chon)),
+ )
+
+ // 옆으로 누워있는 지붕의 높이 점선
+ const realLine6 = new QLine(
+ [vPoint2.x, vPoint2.y, centerPoint2.x, centerPoint2.y],
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ strokeDashArray: [5, 5],
+ },
+ getRoofHeight(lines[1].length / 2, getDegreeByChon(chon)),
+ )
+
+ // 용마루 보조선
+ const ridgeHelpLine1 = new QLine(
+ ridgeHelpLinePoint1,
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ },
+ getRoofHypotenuse(lines[0].length / 2),
+ )
+
+ // 용마루 보조선
+ const ridgeHelpLine2 = new QLine(
+ ridgeHelpLinePoint2,
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ },
+ getRoofHypotenuse(lines[1].length / 2),
+ )
+
+ // 용마루
+ const ridge1 = new QLine(
+ [vPoint1.x, vPoint1.y, ridgeEndPoint1[2], ridgeEndPoint1[3]],
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ },
+ )
+
+ // 용마루
+ const ridge2 = new QLine(
+ [vPoint2.x, vPoint2.y, ridgeEndPoint2[2], ridgeEndPoint2[3]],
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ },
+ )
+
+ const ridgeEndLine = new QLine(
+ [
+ ridgeEndPoint1[2],
+ ridgeEndPoint1[3],
+ ridgeEndPoint2[2],
+ ridgeEndPoint2[3],
+ ],
+ {
+ fontSize: this.fontSize,
+ stroke: 'blue',
+ strokeWidth: 1,
+ },
+ Math.abs(realLine1.length - realLine3.length),
+ )
+ this.helpLines = [
+ realLine1,
+ realLine2,
+ realLine3,
+ realLine4,
+ realLine5,
+ realLine6,
+ ridge1,
+ ridge2,
+ ridgeEndLine,
+ ]
+ this.addWithUpdate(realLine1)
+ this.addWithUpdate(realLine2)
+ this.addWithUpdate(realLine3)
+ this.addWithUpdate(realLine4)
+ this.addWithUpdate(realLine5)
+ this.addWithUpdate(realLine6)
+ this.addWithUpdate(ridgeHelpLine1)
+ this.addWithUpdate(ridgeHelpLine2)
+ this.addWithUpdate(ridge1)
+ this.addWithUpdate(ridge2)
+ this.addWithUpdate(ridgeEndLine)
+
+ this.canvas.renderAll()
+ }
+
+ #drawHelpLineInOctagon(chon) {}
+}
diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js
new file mode 100644
index 00000000..ad6c8ae9
--- /dev/null
+++ b/src/components/fabric/QRect.js
@@ -0,0 +1,98 @@
+import { fabric } from 'fabric'
+export default class QRect extends fabric.Rect {
+ #text = []
+ #viewLengthText
+ #fontSize
+ type = 'QRect'
+ constructor(option) {
+ if (!option.fontSize) {
+ throw new Error('Font size is required.')
+ }
+ super(option)
+ this.#fontSize = option.fontSize
+ this.#init(option)
+ this.#addControl()
+ }
+
+ #init(option) {
+ this.#viewLengthText = option.viewLengthText ?? true
+ }
+
+ setViewLengthText(bool) {
+ this.#viewLengthText = bool
+ this.#addLengthText()
+ }
+
+ setFontSize(fontSize) {
+ this.#fontSize = fontSize
+ this.#addLengthText()
+ }
+
+ #addControl() {
+ this.on('removed', () => {
+ if (this.#text.length > 0) {
+ this.#text.forEach((text) => {
+ this.canvas.remove(text)
+ })
+ this.#text = []
+ }
+ })
+
+ this.on('added', () => {
+ this.#addLengthText()
+ })
+
+ this.on('modified', (e) => {
+ this.#addLengthText()
+ })
+
+ this.on('scaling', (e) => {
+ this.#addLengthText()
+ })
+
+ this.on('moving', () => {
+ this.#addLengthText()
+ })
+ }
+ #addLengthText() {
+ if (this.#text.length > 0) {
+ this.#text.forEach((text) => {
+ this.canvas.remove(text)
+ })
+ this.#text = []
+ }
+
+ if (!this.#viewLengthText) {
+ return
+ }
+
+ const scaleX = this.scaleX
+ const scaleY = this.scaleY
+
+ const lines = [
+ {
+ start: { x: this.left, y: this.top },
+ end: { x: this.left + this.width * scaleX, y: this.top },
+ },
+ {
+ start: { x: this.left, y: this.top + this.height * scaleY },
+ end: { x: this.left, y: this.top },
+ },
+ ]
+
+ lines.forEach((line) => {
+ const dx = line.end.x - line.start.x
+ const dy = line.end.y - line.start.y
+ const length = Math.sqrt(dx * dx + dy * dy)
+
+ const text = new fabric.Text(length.toFixed(0), {
+ left: (line.start.x + line.end.x) / 2,
+ top: (line.start.y + line.end.y) / 2,
+ fontSize: this.#fontSize,
+ selectable: false,
+ })
+ this.#text.push(text)
+ this.canvas.add(text)
+ })
+ }
+}
diff --git a/src/components/ui/RangeSlider.jsx b/src/components/ui/RangeSlider.jsx
new file mode 100644
index 00000000..2250c6d9
--- /dev/null
+++ b/src/components/ui/RangeSlider.jsx
@@ -0,0 +1,28 @@
+export default function RangeSlider(
+ props = { title: 'default title', initValue: 0, onchange: () => {}, step: 1, min:0, max:100},
+) {
+ const { title, initValue, onchange, step, min, max } = props
+
+ const handleChange = (e) => {
+ // console.log(e.target.value)
+ onchange(e.target.value)
+ }
+
+ return (
+ <>
+
+ {title}
+
+
+ >
+ )
+}
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js
index 13e97982..5f44060a 100644
--- a/src/hooks/useCanvas.js
+++ b/src/hooks/useCanvas.js
@@ -3,20 +3,21 @@ import { fabric } from 'fabric'
import {
actionHandler,
anchorWrapper,
- calculateShapeLength,
polygonPositionHandler,
-} from '@/app/util/canvas-util'
+} from '@/util/canvas-util'
-const CANVAS = {
- WIDTH: 1000,
- HEIGHT: 1000,
-}
+import { useRecoilState } from 'recoil'
+import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
+import QPolygon from '@/components/fabric/QPolygon'
+import { QLine } from '@/components/fabric/QLine'
+import QRect from '@/components/fabric/QRect'
export function useCanvas(id) {
const [canvas, setCanvas] = useState()
const [isLocked, setIsLocked] = useState(false)
const [history, setHistory] = useState([])
-
+ const [canvasSize] = useRecoilState(canvasSizeState)
+ const [fontSize] = useRecoilState(fontSizeState)
const points = useRef([])
/**
@@ -24,9 +25,10 @@ export function useCanvas(id) {
*/
useEffect(() => {
const c = new fabric.Canvas(id, {
- height: CANVAS.HEIGHT,
- width: CANVAS.WIDTH,
+ height: canvasSize.vertical,
+ width: canvasSize.horizontal,
backgroundColor: 'white',
+ selection: false,
})
// settings for all canvas in the app
@@ -36,18 +38,60 @@ export function useCanvas(id) {
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
fabric.Object.prototype.cornerSize = 6
+ QPolygon.prototype.canvas = c
+ QLine.prototype.canvas = c
+ QRect.prototype.canvas = c
+
setCanvas(c)
return () => {
c.dispose()
}
}, [])
+ useEffect(() => {
+ // canvas 사이즈가 변경되면 다시
+ removeEventOnCanvas()
+ addEventOnCanvas()
+ }, [canvasSize])
+
+ useEffect(() => {
+ canvas
+ ?.getObjects()
+ .filter(
+ (obj) =>
+ obj.type === 'textbox' ||
+ obj.type === 'text' ||
+ obj.type === 'i-text',
+ )
+ .forEach((obj) => {
+ obj.set({ fontSize: fontSize })
+ })
+
+ canvas
+ ?.getObjects()
+ .filter(
+ (obj) =>
+ obj.type === 'QLine' ||
+ obj.type === 'QPolygon' ||
+ obj.type === 'QRect',
+ )
+ .forEach((obj) => {
+ obj.setFontSize(fontSize)
+ })
+ canvas?.renderAll()
+ }, [fontSize])
+
/**
* 캔버스 초기화
*/
useEffect(() => {
if (canvas) {
initialize()
+ canvas?.on('object:added', onChange)
+ canvas?.on('object:modified', onChange)
+ canvas?.on('object:removed', onChange)
+ canvas?.on('mouse:move', drawMouseLines)
+ canvas?.on('mouse:out', removeMouseLines)
}
}, [canvas])
const addEventOnCanvas = () => {
@@ -92,11 +136,11 @@ export function useCanvas(id) {
canvas?.clear()
// 기존 이벤트가 있을 경우 제거한다.
- removeEventOnCanvas()
+ // removeEventOnCanvas()
// 작업 후에 event를 추가해준다.
- addEventOnCanvas()
+ // addEventOnCanvas()
}
/**
@@ -111,7 +155,7 @@ export function useCanvas(id) {
const onChange = (e) => {
const target = e.target
if (target) {
- settleDown(target)
+ // settleDown(target)
}
if (!isLocked) {
@@ -133,25 +177,23 @@ export function useCanvas(id) {
// 가로선을 그립니다.
const horizontalLine = new fabric.Line(
- [0, pointer.y, CANVAS.WIDTH, pointer.y],
+ [0, pointer.y, canvasSize.horizontal, pointer.y],
{
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
- strokeDashArray: [5, 5],
},
)
// 세로선을 그립니다.
const verticalLine = new fabric.Line(
- [pointer.x, 0, pointer.x, CANVAS.HEIGHT],
+ [pointer.x, 0, pointer.x, canvasSize.vertical],
{
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
- strokeDashArray: [5, 5],
},
)
@@ -208,15 +250,16 @@ export function useCanvas(id) {
*/
const handleUndo = () => {
if (canvas) {
- if (canvas._objects.length > 0) {
- const poppedObject = canvas._objects.pop()
+ if (canvas?._objects.length > 0) {
+ const poppedObject = canvas?._objects.pop()
+
setHistory((prev) => {
if (prev === undefined) {
return poppedObject ? [poppedObject] : []
}
return poppedObject ? [...prev, poppedObject] : prev
})
- canvas.renderAll()
+ canvas?.renderAll()
}
}
}
@@ -225,21 +268,13 @@ export function useCanvas(id) {
if (canvas && history) {
if (history.length > 0) {
setIsLocked(true)
- canvas.add(history[history.length - 1])
+ canvas?.add(history[history.length - 1])
const newHistory = history.slice(0, -1)
setHistory(newHistory)
}
}
}
- /**
- * 해당 캔버스를 비운다.
- */
- const handleClear = () => {
- canvas?.clear()
- initialize()
- }
-
/**
* 선택한 도형을 복사한다.
*/
@@ -440,6 +475,7 @@ export function useCanvas(id) {
const lastControl = poly.points?.length - 1
poly.cornerStyle = 'rect'
poly.cornerColor = 'rgba(0,0,255,0.5)'
+ poly.objectCaching = false
poly.controls = poly.points.reduce(function (acc, point, index) {
acc['p' + index] = new fabric.Control({
positionHandler: polygonPositionHandler,
@@ -494,11 +530,45 @@ export function useCanvas(id) {
canvas?.renderAll()
}
- // 선의 길이가 변경될 때마다 텍스트를 업데이트하는 함수
- const updateTextOnLineChange = (group, text) => {
- const length = calculateShapeLength(group)
- text.set({ text: length.toString() })
- canvas?.renderAll()
+ function fillCanvasWithDots(canvas, gap) {
+ const width = canvas.getWidth()
+ const height = canvas.getHeight()
+
+ for (let x = 0; x < width; x += gap) {
+ for (let y = 0; y < height; y += gap) {
+ const circle = new fabric.Circle({
+ radius: 1,
+ fill: 'black',
+ left: x,
+ top: y,
+ selectable: false,
+ })
+ canvas.add(circle)
+ }
+ }
+
+ canvas.renderAll()
+ }
+
+ const setCanvasBackgroundWithDots = (canvas, gap) => {
+ // Create a new canvas and fill it with dots
+ const tempCanvas = new fabric.StaticCanvas()
+ tempCanvas.setDimensions({
+ width: canvas.getWidth(),
+ height: canvas.getHeight(),
+ })
+ fillCanvasWithDots(tempCanvas, gap)
+
+ // Convert the dotted canvas to an image
+ const dataUrl = tempCanvas.toDataURL({ format: 'png' })
+
+ // Set the image as the background of the original canvas
+ fabric.Image.fromURL(dataUrl, function (img) {
+ canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
+ scaleX: canvas.width / img.width,
+ scaleY: canvas.height / img.height,
+ })
+ })
}
return {
@@ -506,7 +576,6 @@ export function useCanvas(id) {
addShape,
handleUndo,
handleRedo,
- handleClear,
handleCopy,
handleDelete,
handleSave,
@@ -515,6 +584,6 @@ export function useCanvas(id) {
attachCustomControlOnPolygon,
saveImage,
handleFlip,
- updateTextOnLineChange,
+ setCanvasBackgroundWithDots,
}
}
diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js
new file mode 100644
index 00000000..18282ed8
--- /dev/null
+++ b/src/hooks/useMode.js
@@ -0,0 +1,1101 @@
+import { useEffect, useRef, useState } from 'react'
+import QRect from '@/components/fabric/QRect'
+import QPolygon from '@/components/fabric/QPolygon'
+import {
+ getStartIndex,
+ rearrangeArray,
+ findTopTwoIndexesByDistance,
+ getDirection,
+ getOddEvenPoints,
+ findLongestDistancePair,
+ getCenterPoint,
+} from '@/util/canvas-util'
+import { useRecoilState, useSetRecoilState } from 'recoil'
+import {
+ fontSizeState,
+ roofState,
+ sortedPolygonArray,
+ wallState,
+} from '@/store/canvasAtom'
+import { QLine } from '@/components/fabric/QLine'
+
+export const Mode = {
+ DRAW_LINE: 'drawLine', // 기준선 긋기모드
+ EDIT: 'edit',
+ TEMPLATE: 'template',
+ TEXTBOX: 'textbox',
+ DRAW_RECT: 'drawRect',
+ DEFAULT: 'default',
+}
+
+export function useMode() {
+ const [mode, setMode] = useState()
+ const points = useRef([])
+ const historyPoints = useRef([])
+ const historyLines = useRef([])
+ const [canvas, setCanvas] = useState(null)
+ const [zoom, setZoom] = useState(100)
+ const [fontSize] = useRecoilState(fontSizeState)
+ const [shape, setShape] = useState(0)
+ const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray)
+ const [roof, setRoof] = useRecoilState(roofState)
+ const [wall, setWall] = useRecoilState(wallState)
+
+ const addEvent = (mode) => {
+ switch (mode) {
+ case 'default':
+ canvas?.off('mouse:down')
+ break
+ case 'drawLine':
+ drawLineMode()
+ break
+ case 'edit':
+ editMode()
+ break
+ case 'template':
+ templateMode()
+ break
+ case 'textbox':
+ textboxMode()
+ break
+ case 'drawRect':
+ drawRectMode()
+ break
+ }
+ }
+
+ const changeMode = (canvas, mode) => {
+ setMode(mode)
+ // mode변경 시 이전 이벤트 제거
+ setCanvas(canvas)
+ canvas?.off('mouse:down')
+ addEvent(mode)
+ }
+
+ const editMode = () => {
+ canvas?.on('mouse:down', function (options) {
+ const pointer = canvas?.getPointer(options.e)
+ const circle = new fabric.Circle({
+ radius: 1,
+ fill: 'transparent', // 원 안을 비웁니다.
+ stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
+ left: pointer.x,
+ top: pointer.y,
+ originX: 'center',
+ originY: 'center',
+ selectable: false,
+ })
+
+ historyPoints.current.push(circle)
+ points.current.push(circle)
+ canvas?.add(circle)
+
+ if (points.current.length === 2) {
+ const length = Number(prompt('길이를 입력하세요:'))
+ // length 값이 숫자가 아닌 경우
+ if (isNaN(length) || length === 0) {
+ //마지막 추가 된 points 제거합니다.
+
+ const lastPoint =
+ historyPoints.current[historyPoints.current.length - 1]
+
+ canvas?.remove(lastPoint)
+
+ historyPoints.current.pop()
+ points.current.pop()
+ return
+ }
+
+ if (length) {
+ const vector = {
+ x: points.current[1].left - points.current[0].left,
+ y: points.current[1].top - points.current[0].top,
+ }
+ const slope = Math.abs(vector.y / vector.x) // 기울기 계산
+
+ let scaledVector
+ if (slope >= 1) {
+ // 기울기가 1 이상이면 x축 방향으로 그림
+ scaledVector = {
+ x: 0,
+ y: vector.y >= 0 ? Number(length) : -Number(length),
+ }
+ } else {
+ // 기울기가 1 미만이면 y축 방향으로 그림
+ scaledVector = {
+ x: vector.x >= 0 ? Number(length) : -Number(length),
+ y: 0,
+ }
+ }
+
+ const line = new QLine(
+ [
+ points.current[0].left,
+ points.current[0].top,
+ points.current[0].left + scaledVector.x,
+ points.current[0].top + scaledVector.y,
+ ],
+ {
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: false,
+ viewLengthText: true,
+ direction: getDirection(points.current[0], points.current[1]),
+ fontSize: fontSize,
+ },
+ )
+
+ pushHistoryLine(line)
+
+ // 라인의 끝에 점을 추가합니다.
+ const endPointCircle = new fabric.Circle({
+ radius: 1,
+ fill: 'transparent', // 원 안을 비웁니다.
+ stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
+ left: points.current[0].left + scaledVector.x,
+ top: points.current[0].top + scaledVector.y,
+ originX: 'center',
+ originY: 'center',
+ selectable: false,
+ })
+
+ canvas?.add(endPointCircle)
+
+ historyPoints.current.push(endPointCircle)
+
+ points.current.forEach((point) => {
+ canvas?.remove(point)
+ })
+ points.current = [endPointCircle]
+ }
+ }
+
+ canvas?.renderAll()
+ })
+ }
+
+ const pushHistoryLine = (line) => {
+ if (
+ historyLines.current.length > 0 &&
+ historyLines.current[historyLines.current.length - 1].direction ===
+ line.direction
+ ) {
+ // 같은 방향의 선이 두 번 연속으로 그려지면 이전 선을 제거하고, 새로운 선과 merge한다.
+
+ const lastLine = historyLines.current.pop()
+ canvas?.remove(lastLine)
+
+ const mergedLine = new QLine(
+ [lastLine.x1, lastLine.y1, line.x2, line.y2],
+ {
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: false,
+ viewLengthText: true,
+ direction: lastLine.direction,
+ fontSize: fontSize,
+ },
+ )
+ historyLines.current.push(mergedLine)
+ canvas?.add(mergedLine)
+ } else {
+ historyLines.current.push(line)
+ canvas?.add(line)
+ }
+ }
+
+ /**
+ * 마우스로 그린 점 기준으로 외벽선을 완성시켜준다.
+ * makePolygon 함수에 포함되어있던 내용을 다른 템플릿 적용에서도 사용할수 있도록 함수로 대체
+ */
+ const drawWallPolygon = () => {
+ const firstPoint = historyPoints.current[0]
+ const lastPoint = historyPoints.current[historyPoints.current.length - 1]
+ historyPoints.current.forEach((point) => {
+ canvas?.remove(point)
+ })
+ drawLineWithLength(lastPoint, firstPoint)
+ points.current = []
+ historyPoints.current = []
+
+ // handleOuterlines()
+ const wall = makePolygon()
+ setWall(wall)
+
+ return wall
+ }
+
+ const templateMode = () => {
+ changeMode(canvas, Mode.EDIT)
+
+ if (historyPoints.current.length >= 4) {
+ drawWallPolygon()
+ //아래 내용 drawWallPolygon()으로 대체
+ // const firstPoint = historyPoints.current[0]
+ // const lastPoint = historyPoints.current[historyPoints.current.length - 1]
+ // historyPoints.current.forEach((point) => {
+ // canvas?.remove(point)
+ // })
+ // drawLineWithLength(lastPoint, firstPoint)
+ // points.current = []
+ // historyPoints.current = []
+
+ // // handleOuterlines()
+ // const wall = makePolygon()
+ // setWall(wall)
+
+ handleOuterlinesTest() //외곽선 그리기 테스트
+ }
+ }
+
+ const textboxMode = () => {
+ canvas?.on('mouse:down', function (options) {
+ if (canvas?.getActiveObject()?.type === 'textbox') return
+ const pointer = canvas?.getPointer(options.e)
+
+ const textbox = new fabric.Textbox('텍스트를 입력하세요', {
+ left: pointer.x,
+ top: pointer.y,
+ width: 150, // 텍스트박스의 너비를 설정합니다.
+ fontSize: fontSize, // 텍스트의 크기를 설정합니다.
+ })
+
+ canvas?.add(textbox)
+ canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다.
+ canvas?.renderAll()
+ // textbox가 active가 풀린 경우 editing mode로 변경
+ textbox?.on('editing:exited', function () {
+ changeMode(canvas, Mode.EDIT)
+ })
+ })
+ }
+
+ const drawLineMode = () => {
+ canvas?.on('mouse:down', function (options) {
+ const pointer = canvas?.getPointer(options.e)
+
+ const line = new QLine(
+ [pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다.
+ {
+ stroke: 'black',
+ strokeWidth: 2,
+ viewLengthText: true,
+ selectable: false,
+ fontSize: fontSize,
+ },
+ )
+
+ canvas?.add(line)
+ canvas?.renderAll()
+ })
+ }
+
+ const drawRectMode = () => {
+ let rect, isDown, origX, origY
+ canvas.on('mouse:down', function (o) {
+ isDown = true
+ const pointer = canvas.getPointer(o.e)
+ origX = pointer.x
+ origY = pointer.y
+ rect = new fabric.Rect({
+ left: origX,
+ top: origY,
+ originX: 'left',
+ originY: 'top',
+ width: pointer.x - origX,
+ height: pointer.y - origY,
+ angle: 0,
+ fill: 'transparent',
+ stroke: 'black',
+ transparentCorners: false,
+ })
+ canvas.add(rect)
+ })
+
+ canvas.on('mouse:move', function (o) {
+ if (!isDown) return
+ const pointer = canvas.getPointer(o.e)
+ if (origX > pointer.x) {
+ rect.set({ left: Math.abs(pointer.x) })
+ }
+ if (origY > pointer.y) {
+ rect.set({ top: Math.abs(pointer.y) })
+ }
+
+ rect.set({ width: Math.abs(origX - pointer.x) })
+ rect.set({ height: Math.abs(origY - pointer.y) })
+ })
+
+ canvas.on('mouse:up', function (o) {
+ const pointer = canvas.getPointer(o.e)
+ const qRect = new QRect({
+ left: origX,
+ top: origY,
+ originX: 'left',
+ originY: 'top',
+ width: pointer.x - origX,
+ height: pointer.y - origY,
+ angle: 0,
+ viewLengthText: true,
+ fill: 'transparent',
+ stroke: 'black',
+ transparentCorners: false,
+ fontSize: fontSize,
+ })
+ canvas.remove(rect)
+ canvas.add(qRect)
+ isDown = false
+ })
+ }
+
+ /**
+ * 두 점을 연결하는 선과 길이를 그립니다.
+ * a : 시작점, b : 끝점
+ */
+ const drawLineWithLength = (a, b) => {
+ const line = new QLine([a.left, a.top, b.left, b.top], {
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: false,
+ viewLengthText: true,
+ direction: getDirection(a, b),
+ fontSize: fontSize,
+ })
+ pushHistoryLine(line)
+
+ canvas?.renderAll()
+ }
+
+ const makePolygon = (otherLines) => {
+ // 캔버스에서 모든 라인 객체를 찾습니다.
+ const lines = otherLines || historyLines.current
+
+ if (!otherLines) {
+ //외각선 기준
+ const topIndex = findTopTwoIndexesByDistance(sortedArray) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨
+
+ //일단 배열 6개 짜리 기준의 선 번호
+ if (topIndex[0] === 4) {
+ if (topIndex[1] === 5) {
+ //1번
+ setShape(1)
+ }
+ } else if (topIndex[0] === 1) {
+ //4번
+ if (topIndex[1] === 2) {
+ setShape(4)
+ }
+ } else if (topIndex[0] === 0) {
+ if (topIndex[1] === 1) {
+ //2번
+ setShape(2)
+ } else if (topIndex[1] === 5) {
+ setShape(3)
+ }
+ }
+
+ historyLines.current = []
+ }
+
+ // 각 라인의 시작점과 끝점을 사용하여 다각형의 점 배열을 생성합니다.
+ const points = lines.map((line) => ({ x: line.x1, y: line.y1 }))
+
+ // 모든 라인 객체를 캔버스에서 제거합니다.
+ lines.forEach((line) => {
+ canvas?.remove(line)
+ })
+
+ // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다.
+ const polygon = new QPolygon(
+ points,
+ {
+ stroke: 'black',
+ fill: 'transparent',
+ viewLengthText: true,
+ selectable: true,
+ fontSize: fontSize,
+ },
+ canvas,
+ )
+
+ // 새로운 다각형 객체를 캔버스에 추가합니다.
+ canvas.add(polygon)
+
+ // 캔버스를 다시 그립니다.
+ if (!otherLines) {
+ // polygon.fillCell()
+ canvas.renderAll()
+ polygon.setViewLengthText(false)
+ setMode(Mode.DEFAULT)
+ }
+
+ return polygon
+ }
+
+ /**
+ * 해당 캔버스를 비운다.
+ */
+ const handleClear = () => {
+ canvas?.clear()
+ points.current = []
+ historyPoints.current = []
+ historyLines.current = []
+ }
+
+ const zoomIn = () => {
+ canvas?.setZoom(canvas.getZoom() + 0.1)
+ setZoom(Math.round(zoom + 10))
+ }
+
+ const zoomOut = () => {
+ canvas?.setZoom(canvas.getZoom() - 0.1)
+ setZoom(Math.ceil(zoom - 10))
+ }
+
+ const handleOuterlines = () => {
+ const newOuterlines = []
+ for (let i = 0; i < historyLines.current.length; i++) {
+ const next = historyLines.current[i + 1]
+ const prev =
+ historyLines.current[i - 1] ??
+ historyLines.current[historyLines.current.length - 1]
+ if (next) {
+ if (next.direction === 'right') {
+ // 다름 라인이 오른쪽으로 이동
+ if (historyLines.current[i].direction === 'top') {
+ if (prev.direction !== 'right') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ // bottom
+ if (prev?.direction !== 'right') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ }
+ } else if (next.direction === 'left') {
+ if (historyLines.current[i].direction === 'top') {
+ if (prev?.direction !== 'left') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ } else {
+ // bottom
+ if (prev?.direction !== 'left') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ }
+ } else if (next.direction === 'top') {
+ if (historyLines.current[i].direction === 'right') {
+ if (prev?.direction !== 'top') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ // left
+ if (prev?.direction !== 'top') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ }
+ } else if (next.direction === 'bottom') {
+ if (historyLines.current[i].direction === 'right') {
+ if (prev?.direction !== 'bottom') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ // left
+ if (prev.direction !== 'bottom') {
+ if (historyLines.current.length === 4) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 6) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 + 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 - 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ } else if (historyLines.current.length === 8) {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 + 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 + 50,
+ })
+ }
+ } else {
+ newOuterlines.push({
+ x1: historyLines.current[i].x1 - 50,
+ y1: historyLines.current[i].y1 - 50,
+ x2: historyLines.current[i].x2 + 50,
+ y2: historyLines.current[i].y2 - 50,
+ })
+ }
+ }
+ }
+ } else {
+ const tmp = newOuterlines[newOuterlines.length - 1]
+ newOuterlines.push({
+ x1: tmp.x2,
+ y1: tmp.y2,
+ x2: newOuterlines[0].x1,
+ y2: newOuterlines[0].y1,
+ })
+ }
+ }
+
+ makePolygon(newOuterlines)
+ }
+
+ /**
+ *벽 지붕 외곽선 생성
+ */
+ const handleOuterlinesTest = (offset = 71) => {
+ var offsetPoints = []
+
+ const sortedIndex = getStartIndex(historyLines.current)
+ let tmpArraySorted = rearrangeArray(historyLines.current, sortedIndex)
+
+ if (tmpArraySorted[0].direction === 'right') {
+ //시계방향
+ tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정
+ }
+
+ setSortedArray(tmpArraySorted) //recoil에 넣음
+
+ const points = tmpArraySorted.map((line) => ({
+ x: line.x1,
+ y: line.y1,
+ }))
+
+ for (var i = 0; i < points.length; i++) {
+ var prev = points[(i - 1 + points.length) % points.length]
+ var current = points[i]
+ var next = points[(i + 1) % points.length]
+
+ // 두 벡터 계산 (prev -> current, current -> next)
+ var vector1 = { x: current.x - prev.x, y: current.y - prev.y }
+ var vector2 = { x: next.x - current.x, y: next.y - current.y }
+
+ // 벡터의 길이 계산
+ var length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y)
+ var length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)
+
+ // 벡터를 단위 벡터로 정규화
+ var unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 }
+ var unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 }
+
+ // 법선 벡터 계산 (왼쪽 방향)
+ var normal1 = { x: -unitVector1.y, y: unitVector1.x }
+ var normal2 = { x: -unitVector2.y, y: unitVector2.x }
+
+ // 법선 벡터 평균 계산
+ var averageNormal = {
+ x: (normal1.x + normal2.x) / 2,
+ y: (normal1.y + normal2.y) / 2,
+ }
+
+ // 평균 법선 벡터를 단위 벡터로 정규화
+ var lengthNormal = Math.sqrt(
+ averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y,
+ )
+ var unitNormal = {
+ x: averageNormal.x / lengthNormal,
+ y: averageNormal.y / lengthNormal,
+ }
+
+ // 오프셋 적용
+ var offsetPoint = {
+ x1: current.x + unitNormal.x * offset,
+ y1: current.y + unitNormal.y * offset,
+ }
+
+ offsetPoints.push(offsetPoint)
+ }
+
+ const roof = makePolygon(offsetPoints)
+ setRoof(roof)
+ roof.drawHelpLine()
+ }
+
+ /**
+ *벽 지붕 외곽선 생성 polygon을 입력받아 만들기
+ */
+ const handleOuterlinesTest2 = (polygon, offset = 71) => {
+ const offsetPoints = []
+ const sortedIndex = getStartIndex(polygon.lines)
+ let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex)
+
+ if (tmpArraySorted[0].direction === 'right') {
+ //시계방향
+ tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정
+ }
+
+ setSortedArray(tmpArraySorted) //recoil에 넣음
+
+ const points = tmpArraySorted.map((line) => ({
+ x: line.x1,
+ y: line.y1,
+ }))
+
+ for (let i = 0; i < points.length; i++) {
+ const prev = points[(i - 1 + points.length) % points.length]
+ const current = points[i]
+ const next = points[(i + 1) % points.length]
+
+ // 두 벡터 계산 (prev -> current, current -> next)
+ const vector1 = { x: current.x - prev.x, y: current.y - prev.y }
+ const vector2 = { x: next.x - current.x, y: next.y - current.y }
+
+ // 벡터의 길이 계산
+ const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y)
+ const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)
+
+ // 벡터를 단위 벡터로 정규화
+ const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 }
+ const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 }
+
+ // 법선 벡터 계산 (왼쪽 방향)
+ const normal1 = { x: -unitVector1.y, y: unitVector1.x }
+ const normal2 = { x: -unitVector2.y, y: unitVector2.x }
+
+ // 법선 벡터 평균 계산
+ const averageNormal = {
+ x: (normal1.x + normal2.x) / 2,
+ y: (normal1.y + normal2.y) / 2,
+ }
+
+ // 평균 법선 벡터를 단위 벡터로 정규화
+ const lengthNormal = Math.sqrt(
+ averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y,
+ )
+ const unitNormal = {
+ x: averageNormal.x / lengthNormal,
+ y: averageNormal.y / lengthNormal,
+ }
+
+ // 오프셋 적용
+ const offsetPoint = {
+ x1: current.x + unitNormal.x * offset,
+ y1: current.y + unitNormal.y * offset,
+ }
+
+ offsetPoints.push(offsetPoint)
+ }
+
+ const roof = makePolygon(offsetPoints)
+ setRoof(roof)
+ roof.drawHelpLine()
+ }
+
+ const togglePolygonLine = (obj) => {
+ const rtnLines = []
+ if (obj.type === 'QPolygon') {
+ const points = obj.getCurrentPoints()
+ points.forEach((point, index) => {
+ const nextPoint = points[(index + 1) % points.length] // 마지막 점이면 첫 번째 점으로 연결
+ const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
+ stroke: 'black',
+ strokeWidth: 2,
+ selectable: false,
+ fontSize: fontSize, // fontSize는 필요에 따라 조정
+ parent: obj,
+ })
+ obj.visible = false
+ canvas.add(line)
+ rtnLines.push(line)
+ })
+
+ canvas.renderAll()
+ }
+ if (obj.type === 'QLine') {
+ const parent = obj.parent
+ canvas
+ ?.getObjects()
+ .filter((obj) => obj.parent === parent)
+ .forEach((obj) => {
+ rtnLines.push(obj)
+ canvas.remove(obj)
+ })
+
+ parent.visible = true
+ canvas.renderAll()
+ }
+ return rtnLines
+ }
+
+ /**
+ * 템플릿 B 적용
+ * 1. 모드 체인지
+ * 2. 외벽선 그리기 마무리
+ */
+ const applyTemplateB = () => {
+ changeMode(canvas, Mode.EDIT)
+ const polygon = drawWallPolygon()
+ handleOuterLineTemplateB(polygon)
+ }
+
+ const handleOuterLineTemplateB = (polygon) => {
+ polygon.points.forEach((point, index) => {
+ let x2 =
+ index === polygon.points.length - 1
+ ? polygon.points[0].x
+ : polygon.points[index + 1].x
+ let y2 =
+ index === polygon.points.length - 1
+ ? polygon.points[0].y
+ : polygon.points[index + 1].y
+
+ let x1 = point.x
+ let y1 = point.y
+ if (index % 2 === 0) {
+ if (polygon.lines[index].direction === 'bottom') {
+ y1 = y1 - 50
+ y2 = y2 + 50
+ x1 = x1 - 20
+ x2 = x2 - 20
+ } else {
+ y1 = y1 + 50
+ y2 = y2 - 50
+ x1 = x1 + 20
+ x2 = x2 + 20
+ }
+ } else {
+ if (polygon.lines[index].direction === 'right') {
+ x1 = x1 - 20
+ x2 = x2 + 20
+ y1 = y1 + 50
+ y2 = y2 + 50
+ } else {
+ x1 = x1 + 20
+ x2 = x2 - 20
+ y1 = y1 - 50
+ y2 = y2 - 50
+ }
+ }
+
+ switch (polygon.shape) {
+ case 1:
+ break
+ case 2:
+ const centerPoint =
+ polygon.points[3].y +
+ (polygon.points[2].y - polygon.points[3].y) / 2
+ if (index === 0) {
+ const subLine = new QLine(
+ [
+ point.x - 20,
+ polygon.points[0].y +
+ (polygon.points[1].y - polygon.points[0].y) / 2,
+ polygon.points[5].x + 20,
+ polygon.points[0].y +
+ (polygon.points[1].y - polygon.points[0].y) / 2,
+ ],
+ {
+ stroke: 'blue',
+ strokeWidth: 2,
+ selectable: false,
+ fontSize: fontSize,
+ },
+ )
+ canvas.add(subLine)
+ }
+ if (index === 3) {
+ x2 = x2 + 20
+
+ const subLine = new QLine([x2, y2, x2, centerPoint], {
+ stroke: 'blue',
+ strokeWidth: 2,
+ selectable: false,
+ fontSize: fontSize,
+ })
+ canvas.add(subLine)
+ }
+ if (index === 4) {
+ y1 =
+ point.y +
+ (polygon.points[index - 2].y - polygon.points[index - 1].y) / 2
+
+ const subLine = new QLine(
+ [point.x, centerPoint, polygon.points[2].x + 20, centerPoint],
+ {
+ stroke: 'blue',
+ strokeWidth: 2,
+ selectable: false,
+ fontSize: fontSize,
+ },
+ )
+ canvas.add(subLine)
+
+ const subVerticalLine = new QLine(
+ [
+ getCenterPoint(point.x, polygon.points[2].x + 20),
+ polygon.points[3].y - 50,
+ getCenterPoint(point.x, polygon.points[2].x + 20),
+ centerPoint,
+ ],
+ {
+ stroke: 'black',
+ strokeWidth: 2,
+ strokeDashArray: [5, 5],
+ selectable: false,
+ fontSize: fontSize,
+ },
+ )
+ canvas.add(subVerticalLine)
+ }
+
+ if (index === 5) {
+ const centeredPoint = getCenterPoint(
+ polygon.points[0].x,
+ polygon.points[5].x,
+ )
+ const verticalSubLine = new QLine(
+ [
+ centeredPoint,
+ polygon.points[0].y - 50,
+ centeredPoint,
+ polygon.points[1].y + 50,
+ ],
+ {
+ stroke: 'black',
+ strokeWidth: 2,
+ strokeDashArray: [5, 5],
+ selectable: false,
+ fontSize: fontSize,
+ },
+ )
+
+ canvas.add(verticalSubLine)
+ }
+
+ break
+ case 3:
+ break
+ case 4:
+ break
+ default:
+ break
+ }
+
+ const line = new QLine([x1, y1, x2, y2], {
+ stroke: 'blue',
+ strokeWidth: 2,
+ selectable: false,
+ fontSize: fontSize,
+ })
+ canvas.add(line)
+ })
+ canvas.renderAll()
+ }
+
+ return {
+ mode,
+ changeMode,
+ setCanvas,
+ handleClear,
+ zoomIn,
+ zoomOut,
+ zoom,
+ togglePolygonLine,
+ handleOuterlinesTest2,
+ applyTemplateB,
+ }
+}
diff --git a/src/middleware.js b/src/middleware.js
new file mode 100644
index 00000000..d0329940
--- /dev/null
+++ b/src/middleware.js
@@ -0,0 +1,12 @@
+import { NextRequest, NextResponse } from 'next/server'
+
+export function middleware(request) {
+ const requestHeaders = new Headers(request.headers)
+ requestHeaders.set('x-pathname', request.nextUrl.pathname)
+
+ return NextResponse.next({
+ request: {
+ headers: requestHeaders,
+ },
+ })
+}
diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js
new file mode 100644
index 00000000..16f057b1
--- /dev/null
+++ b/src/store/canvasAtom.js
@@ -0,0 +1,37 @@
+import { atom } from 'recoil'
+
+export const textState = atom({
+ key: 'textState',
+ default: 'test text',
+})
+
+export const fontSizeState = atom({
+ key: 'fontSizeState',
+ default: 16,
+})
+
+export const canvasSizeState = atom({
+ key: 'canvasSize',
+ default: {
+ vertical: 1000,
+ horizontal: 1000,
+ },
+})
+
+export const sortedPolygonArray = atom({
+ key: 'sortedArray',
+ default: [],
+ dangerouslyAllowMutability: true,
+})
+
+export const roofState = atom({
+ key: 'roof',
+ default: {},
+ dangerouslyAllowMutability: true,
+})
+
+export const wallState = atom({
+ key: 'wall',
+ default: {},
+ dangerouslyAllowMutability: true,
+})
diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js
new file mode 100644
index 00000000..e1c4b0fa
--- /dev/null
+++ b/src/util/canvas-util.js
@@ -0,0 +1,419 @@
+/**
+ * Collection of function to use on canvas
+ */
+// define a function that can locate the controls
+export function polygonPositionHandler(dim, finalMatrix, fabricObject) {
+ // @ts-ignore
+ let x = fabricObject.points[this.pointIndex].x - fabricObject.pathOffset.x
+ // @ts-ignore
+ let y = fabricObject.points[this.pointIndex].y - fabricObject.pathOffset.y
+ return fabric.util.transformPoint(
+ { x, y },
+ fabric.util.multiplyTransformMatrices(
+ fabricObject.canvas.viewportTransform,
+ fabricObject.calcTransformMatrix(),
+ ),
+ )
+}
+
+function getObjectSizeWithStroke(object) {
+ let stroke = new fabric.Point(
+ object.strokeUniform ? 1 / object.scaleX : 1,
+ object.strokeUniform ? 1 / object.scaleY : 1,
+ ).multiply(object.strokeWidth)
+ return new fabric.Point(object.width + stroke.x, object.height + stroke.y)
+}
+
+// define a function that will define what the control does
+export function actionHandler(eventData, transform, x, y) {
+ let polygon = transform.target,
+ currentControl = polygon.controls[polygon.__corner],
+ mouseLocalPosition = polygon.toLocalPoint(
+ new fabric.Point(x, y),
+ 'center',
+ 'center',
+ ),
+ polygonBaseSize = getObjectSizeWithStroke(polygon),
+ size = polygon._getTransformedDimensions(0, 0)
+ polygon.points[currentControl.pointIndex] = {
+ x:
+ (mouseLocalPosition.x * polygonBaseSize.x) / size.x +
+ polygon.pathOffset.x,
+ y:
+ (mouseLocalPosition.y * polygonBaseSize.y) / size.y +
+ polygon.pathOffset.y,
+ }
+ return true
+}
+
+// define a function that can keep the polygon in the same position when we change its width/height/top/left
+export function anchorWrapper(anchorIndex, fn) {
+ return function (eventData, transform, x, y) {
+ let fabricObject = transform.target
+ let originX =
+ fabricObject?.points[anchorIndex].x - fabricObject.pathOffset.x
+ let originY = fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y
+ let absolutePoint = fabric.util.transformPoint(
+ {
+ x: originX,
+ y: originY,
+ },
+ fabricObject.calcTransformMatrix(),
+ )
+ let actionPerformed = fn(eventData, transform, x, y)
+ let newDim = fabricObject._setPositionDimensions({})
+ let polygonBaseSize = getObjectSizeWithStroke(fabricObject)
+ let newX =
+ (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) /
+ polygonBaseSize.x
+ let newY =
+ (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) /
+ polygonBaseSize.y
+ fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5)
+ return actionPerformed
+ }
+}
+
+/**
+ * 두 좌표의 중간점 좌표를 계산해서 반환하는 함수
+ * @param {number} point1
+ * @param {number} point2 방향에 상관없이 항상 큰 값이 뒤에 위치해야 함
+ * @returns
+ */
+export const getCenterPoint = (point1, point2) => {
+ return point1 + (point2 - point1) / 2
+}
+
+/**
+ * 두 점 사이의 거리를 계산하는 함수
+ * @param {*} x1 첫번째 점 x좌표
+ * @param {*} y1 첫번째 점 y좌표
+ * @param {*} x2 두번째 점 x좌표
+ * @param {*} y2 두번째 점 y좌표
+ * @returns
+ */
+export const getDistance = (x1, y1, x2, y2) => {
+ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
+}
+
+// polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수
+export function addDistanceTextToPolygon(polygon) {
+ const points = polygon.get('points')
+ const texts = []
+
+ for (let i = 0; i < points.length; i++) {
+ const start = points[i]
+ const end = points[(i + 1) % points.length] // 다음 점 (마지막 점의 경우 첫번째 점으로)
+ const distance = Math.sqrt(
+ Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2),
+ ) // 두 점 사이의 거리 계산
+
+ const text = new fabric.Textbox(distance.toFixed(2), {
+ // 소수 둘째자리까지 표시
+ left: (start.x + end.x) / 2, // 텍스트의 위치는 두 점의 중간
+ top: (start.y + end.y) / 2,
+ fontSize: 20,
+ })
+
+ texts.push(text)
+ }
+
+ return new fabric.Group([polygon, ...texts], {
+ // polygon과 텍스트들을 그룹화
+ selectable: true,
+ })
+}
+
+/**
+ *
+ * @param {number} value
+ * @param {boolean} useDefault
+ * @param {string} delimeter
+ * @returns
+ * ex) 1,100 mm
+ */
+export const formattedWithComma = (value, unit = 'mm') => {
+ let formatterdData = value.toLocaleString('ko-KR')
+ if (unit === 'cm') {
+ formatterdData = value.toLocaleString('ko-KR') / 10
+ } else if (unit === 'm') {
+ formatterdData = value.toLocaleString('ko-KR') / 1000
+ }
+
+ return `${formatterdData} ${unit}`
+}
+
+export const distanceBetweenPoints = (point1, point2) => {
+ const dx = point2.x - point1.x
+ const dy = point2.y - point1.y
+ return Math.sqrt(dx * dx + dy * dy)
+}
+
+/**
+ * line의 시작점을 찾는 함수
+ * @param lines
+ * @returns {number}
+ */
+export const getStartIndex = (lines) => {
+ let smallestIndex = 0
+ let smallestX1 = lines[0].x1
+ let smallestY1 = lines[0].y1
+
+ for (let i = 1; i < lines.length; i++) {
+ if (
+ lines[i].x1 < smallestX1 ||
+ (lines[i].x1 === smallestX1 && lines[i].y1 < smallestY1)
+ ) {
+ smallestIndex = i
+ smallestX1 = lines[i].x1
+ smallestY1 = lines[i].y1
+ }
+ }
+
+ return smallestIndex
+}
+
+/**
+ * points 배열에서 시작점을 찾는 함수
+ * @param points
+ * @returns {number}
+ */
+export const getStartIndexPoint = (points) => {
+ let smallestIndex = 0
+ let smallestX1 = points[0].x
+ let smallestY1 = points[0].y
+
+ for (let i = 1; i < points.length; i++) {
+ if (
+ points[i].x < smallestX1 ||
+ (points[i].x === smallestX1 && points[i].y < smallestY1)
+ ) {
+ smallestIndex = i
+ smallestX1 = points[i].x
+ smallestY1 = points[i].y
+ }
+ }
+
+ return smallestIndex
+}
+
+/**
+ * 이 함수는 두 개의 매개변수를 받습니다: array와 index.
+ * array는 재배열할 대상 배열입니다.
+ * index는 재배열의 기준이 될 배열 내의 위치입니다.
+ * 함수는 먼저 index 위치부터 배열의 마지막 요소까지를 추출합니다(fromIndexToEnd).
+ * 그 다음, 배열의 처음부터 index 위치까지의 요소를 추출합니다(fromStartToIndex).
+ * 마지막으로, fromIndexToEnd와 fromStartToIndex 두 부분을 concat 메소드를 이용해 합칩니다.
+ * 따라서, 이 함수는 주어진 index를 기준으로 배열을 두 부분으로 나누고, index부터 시작하는 부분을 앞에 두고, 그 뒤에 index 이전의 부분을 이어붙여 새로운 배열을 생성합니다. 이는 배열의 회전(rotating) 연산을 수행하는 것과 유사합니다.
+ * @param array 재배열할 대상 배열
+ * @param index 재배열 기준이 될 배열 내의 인덱스
+ * @returns {*} 새로 재배열된 배열
+ */
+export const rearrangeArray = (array, index) => {
+ // 배열의 특정 인덱스부터 마지막 요소까지를 가져옵니다.
+ const fromIndexToEnd = array.slice(index)
+
+ // 배열의 처음부터 특정 인덱스까지의 요소를 가져옵니다.
+ const fromStartToIndex = array.slice(0, index)
+
+ // 두 부분을 concat 메소드를 이용해 합칩니다.
+ return fromIndexToEnd.concat(fromStartToIndex)
+}
+
+export const findTopTwoIndexesByDistance = (objArr) => {
+ if (objArr.length < 2) {
+ return [] // 배열의 길이가 2보다 작으면 빈 배열 반환
+ }
+
+ let firstIndex = -1
+ let secondIndex = -1
+ let firstDistance = -Infinity
+ let secondDistance = -Infinity
+
+ for (let i = 0; i < objArr.length; i++) {
+ const distance = objArr[i].length
+
+ if (distance > firstDistance) {
+ secondDistance = firstDistance
+ secondIndex = firstIndex
+ firstDistance = distance
+ firstIndex = i
+ } else if (distance > secondDistance) {
+ secondDistance = distance
+ secondIndex = i
+ }
+ }
+
+ return [firstIndex, secondIndex]
+}
+
+/**
+ * 지붕의 누워있는 높이
+ * @param base 밑변
+ * @param degree 각도 ex(4촌의 경우 21.8)
+ */
+export const getRoofHeight = (base, degree) => {
+ return base / Math.cos((degree * Math.PI) / 180)
+}
+
+/**
+ * 지붕 빗변의 길이
+ * @param base 밑변
+ */
+export const getRoofHypotenuse = (base) => {
+ return Math.sqrt(base * base * 2)
+}
+
+/**
+ * 촌을 입력받아 각도를 반환
+ * @param chon
+ * @returns {number}
+ */
+export const getDegreeByChon = (chon) => {
+ // tan(theta) = height / base
+ const radians = Math.atan(chon / 10)
+ // 라디안을 도 단위로 변환
+ return Number((radians * (180 / Math.PI)).toFixed(2))
+}
+
+/**
+ * 두 점 사이의 방향을 반환합니다.
+ * @param a {fabric.Object}
+ * @param b {fabric.Object}
+ * @returns {string}
+ */
+export const getDirection = (a, b) => {
+ const vector = {
+ x: b.left - a.left,
+ y: b.top - a.top,
+ }
+
+ if (Math.abs(vector.x) > Math.abs(vector.y)) {
+ // x축 방향으로 더 많이 이동
+ return vector.x > 0 ? 'right' : 'left'
+ } else {
+ // y축 방향으로 더 많이 이동
+ return vector.y > 0 ? 'bottom' : 'top'
+ }
+}
+
+/**
+ * 두 점 사이의 방향을 반환합니다.
+ */
+export const getDirectionByPoint = (a, b) => {
+ const vector = {
+ x: b.x - a.x,
+ y: b.y - a.y,
+ }
+
+ if (Math.abs(vector.x) > Math.abs(vector.y)) {
+ // x축 방향으로 더 많이 이동
+ return vector.x > 0 ? 'right' : 'left'
+ } else {
+ // y축 방향으로 더 많이 이동
+ return vector.y > 0 ? 'bottom' : 'top'
+ }
+}
+
+/**
+ * line을 두개를 이용해서 교차점을 찾는 함수
+ * @param line1
+ * @param line2
+ * @returns {{x: number, y: number}|null}
+ */
+export function calculateIntersection(line1, line2) {
+ const x1 = line1.x1,
+ y1 = line1.y1,
+ x2 = line1.x2,
+ y2 = line1.y2
+ const x3 = line2.x1,
+ y3 = line2.y1,
+ x4 = line2.x2,
+ y4 = line2.y2
+
+ const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
+ if (denom === 0) return null // 선분이 평행하거나 일치
+
+ const intersectX =
+ ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom
+ const intersectY =
+ ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom
+
+ // 교차점이 두 선분의 x 좌표 범위 내에 있는지 확인
+ if (
+ intersectX < Math.min(x1, x2) ||
+ intersectX > Math.max(x1, x2) ||
+ intersectX < Math.min(x3, x4) ||
+ intersectX > Math.max(x3, x4)
+ ) {
+ return null // 교차점이 선분 범위 밖에 있음
+ }
+
+ return { x: intersectX, y: intersectY }
+}
+
+/**
+ * points배열을 입력받아 반시계방향으로 정렬된 points를 반환합니다.
+ * @param points
+ */
+export const sortedPoints = (points) => {
+ const copyPoints = [...points]
+ //points를 x,y좌표를 기준으로 정렬합니다.
+
+ copyPoints.sort((a, b) => {
+ if (a.x === b.x) {
+ return a.y - b.y
+ }
+ return a.x - b.x
+ })
+
+ // 이때 copyPoints를 순회하며 최초엔 x값을 비교하여 같은 점을 찾는다. 이때 이 점이 2번째 점이 된다.
+ // 그 다음점은 2번째 점과 y값이 같은 점이 된다.
+ // 또 그다음 점은 3번째 점과 x값이 같은 점이 된다.
+ // 이를 반복하여 copyPoints를 재배열한다.
+ const resultPoints = [copyPoints[0]]
+ let index = 1
+ let currentPoint = { ...copyPoints[0] }
+ copyPoints.splice(0, 1)
+
+ while (index < points.length) {
+ if (index === points.length - 1) {
+ resultPoints.push(copyPoints[0])
+ index++
+ break
+ } else if (index % 2 === 0) {
+ // 짝수번째는 y값이 같은 점을 찾는다.
+ for (let i = 0; i < copyPoints.length; i++) {
+ // y값이 같은 point가 많은 경우 그 중 x값이 가장 큰걸 찾는다.
+ const temp = copyPoints.filter((point) => point.y === currentPoint.y)
+ // temp중 x값이 가장 큰 값
+ const max = temp.reduce((prev, current) =>
+ prev.x >= current.x ? prev : current,
+ )
+ resultPoints.push(max)
+ currentPoint = max
+ copyPoints.splice(copyPoints.indexOf(max), 1)
+ index++
+ break
+ }
+ } else {
+ // 홀수번째는 x값이 같은 점을 찾는다.
+ for (let i = 0; i < copyPoints.length; i++) {
+ // x값이 같은 point가 많은 경우 그 중 y값이 가장 큰걸 찾는다.
+ const temp = copyPoints.filter((point) => point.x === currentPoint.x)
+ // temp중 y값이 가장 큰 값
+ const max = temp.reduce((prev, current) =>
+ prev.y >= current.y ? prev : current,
+ )
+
+ resultPoints.push(max)
+ currentPoint = max
+ copyPoints.splice(copyPoints.indexOf(max), 1)
+ index++
+ break
+ }
+ }
+ }
+
+ return resultPoints
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index 79803501..efe48113 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,18 +1,22 @@
+const { nextui } = require('@nextui-org/react')
+
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
- "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
- "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
+ './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
+ './src/components/**/*.{js,ts,jsx,tsx,mdx}',
+ './src/app/**/*.{js,ts,jsx,tsx,mdx}',
+ './node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
backgroundImage: {
- "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
- "gradient-conic":
- "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
+ 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
+ 'gradient-conic':
+ 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
- plugins: [],
-};
+ darkMode: 'class',
+ plugins: [nextui()],
+}
diff --git a/yarn.lock b/yarn.lock
index f37579d4..f1b9d24f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,6 +7,81 @@
resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
+"@babel/runtime@^7.20.13":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12"
+ integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@formatjs/ecma402-abstract@2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz#39197ab90b1c78b7342b129a56a7acdb8f512e17"
+ integrity sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==
+ dependencies:
+ "@formatjs/intl-localematcher" "0.5.4"
+ tslib "^2.4.0"
+
+"@formatjs/fast-memoize@2.2.0":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz#33bd616d2e486c3e8ef4e68c99648c196887802b"
+ integrity sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==
+ dependencies:
+ tslib "^2.4.0"
+
+"@formatjs/icu-messageformat-parser@2.7.8":
+ version "2.7.8"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz#f6d7643001e9bb5930d812f1f9a9856f30fa0343"
+ integrity sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.0.0"
+ "@formatjs/icu-skeleton-parser" "1.8.2"
+ tslib "^2.4.0"
+
+"@formatjs/icu-skeleton-parser@1.8.2":
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz#2252c949ae84ee66930e726130ea66731a123c9f"
+ integrity sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.0.0"
+ tslib "^2.4.0"
+
+"@formatjs/intl-localematcher@0.5.4":
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz#caa71f2e40d93e37d58be35cfffe57865f2b366f"
+ integrity sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==
+ dependencies:
+ tslib "^2.4.0"
+
+"@internationalized/date@^3.5.4":
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.5.4.tgz#49ba11634fd4350b7a9308e297032267b4063c44"
+ integrity sha512-qoVJVro+O0rBaw+8HPjUB1iH8Ihf8oziEnqMnvhJUSuVIrHOuZ6eNLHNvzXJKUvAtaDiqMnRlg8Z2mgh09BlUw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@internationalized/message@^3.1.4":
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.4.tgz#4da041155829ffb57c9563fa7c99e2b94c8a5766"
+ integrity sha512-Dygi9hH1s7V9nha07pggCkvmRfDd3q2lWnMGvrJyrOwYMe1yj4D2T9BoH9I6MGR7xz0biQrtLPsqUkqXzIrBOw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+ intl-messageformat "^10.1.0"
+
+"@internationalized/number@^3.5.3":
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.3.tgz#9fa060c1c4809f23fb3d38dd3f3d1ae4c87e95a8"
+ integrity sha512-rd1wA3ebzlp0Mehj5YTuTI50AQEx80gWFyHcQu+u91/5NgdwBecO8BH6ipPfE+lmQ9d63vpB3H9SHoIUiupllw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@internationalized/string@^3.2.3":
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.3.tgz#b0a8379e779a69e7874979714e27f2ae86761d3c"
+ integrity sha512-9kpfLoA8HegiWTeCbR2livhdVeKobCnVv8tlJ6M2jF+4tcMqDo94ezwlnrUANBWPgd8U7OXIHCk2Ov2qhk4KXw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz"
@@ -116,6 +191,925 @@
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz#2be4e39ee25bfbd85be78eea17c0e7751dc4323c"
integrity sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==
+"@nextui-org/accordion@2.0.35":
+ version "2.0.35"
+ resolved "https://registry.yarnpkg.com/@nextui-org/accordion/-/accordion-2.0.35.tgz#381cc4b514a4ab7f06dfc8d151ebf88c000c685c"
+ integrity sha512-42T8DAgpICKORry5h1UCgAQ71QJ3dCzvqrnnJQco3LICeIER2JT/wEdpxHUVT893MkL6z6CFsJmWNfFJPk59kA==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/divider" "2.0.28"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-accordion" "2.0.6"
+ "@react-aria/button" "3.9.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/tree" "3.8.1"
+ "@react-types/accordion" "3.0.0-alpha.21"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/aria-utils@2.0.21":
+ version "2.0.21"
+ resolved "https://registry.yarnpkg.com/@nextui-org/aria-utils/-/aria-utils-2.0.21.tgz#9ef84dd5d6ac6b4b3bb5446af1d38a09258eb759"
+ integrity sha512-aQXFVm4qNrXrUAHhRtr363BgRDX+zgN3Vm+7bW1qtMbnMGOqTWApCD48FP59bka5JArd3K+85tFEhkdD+UfKbQ==
+ dependencies:
+ "@nextui-org/react-rsc-utils" "2.0.12"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system" "2.2.2"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/collections" "3.10.7"
+ "@react-stately/overlays" "3.6.7"
+ "@react-types/overlays" "3.8.7"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/autocomplete@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/autocomplete/-/autocomplete-2.1.2.tgz#abf71950104cc3c4cf0004e92e972e466990a61a"
+ integrity sha512-3mtYQDBbSRLG8wZ+gDMsOsGH/0m2VG/RcwIiXoteZMyX7yhGl2JPp7ZjX6XWyUpUbq0w2QVprZ6Ld4ck3cuMKg==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/input" "2.2.2"
+ "@nextui-org/listbox" "2.1.22"
+ "@nextui-org/popover" "2.1.24"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/scroll-shadow" "2.1.17"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/spinner" "2.0.30"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/combobox" "3.9.1"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/combobox" "3.8.4"
+ "@react-types/combobox" "3.11.1"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/avatar@2.0.30":
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/@nextui-org/avatar/-/avatar-2.0.30.tgz#be8e112013dadacd45615e79af3248566adfaba2"
+ integrity sha512-FIrvdJE+dBkmU3YDR1AXTkcks/WXjbnQsojWBMAq+1oXDCcNiGMUvKBzsW0F5m5HVHhn+Edc+CbTzIZUTm78Bw==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-image" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+
+"@nextui-org/badge@2.0.29":
+ version "2.0.29"
+ resolved "https://registry.yarnpkg.com/@nextui-org/badge/-/badge-2.0.29.tgz#07c69493a5829ad328facc488581789898aab80d"
+ integrity sha512-kd6BJ1BWkX6UuHttmySUgQBPOBJCrG1+eKwWDd1HL4YuBLayuYoTZuE5Q01HYTbXjFMqzsFX3A+jcJ3RYc0X7w==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+
+"@nextui-org/breadcrumbs@2.0.10":
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/@nextui-org/breadcrumbs/-/breadcrumbs-2.0.10.tgz#e301a35c15f8d2e39929d9e4020b5742fc113e15"
+ integrity sha512-TCrOHCH/gNrPwEQyd30mu6Y9x/ojJk3vUWZJSPuVhzG6WdpUFyqen4QCoDTUTvFJBL3TwqNYwOIxooizzFSK7g==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/breadcrumbs" "3.5.13"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/breadcrumbs" "3.7.5"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/button@2.0.34":
+ version "2.0.34"
+ resolved "https://registry.yarnpkg.com/@nextui-org/button/-/button-2.0.34.tgz#0621aec4dec1c4ec3e8d091f71ba7b86b02f4c19"
+ integrity sha512-VeFpOs7trX6u6FqeGr0XCpuNqPhXTLqsmt4iaygvheZCbzrTKvWHd4QMqSh2CPsNH8UFUBSFJjr3oaf3a0SYWQ==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/ripple" "2.0.30"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/spinner" "2.0.30"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@react-aria/button" "3.9.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/button" "3.9.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/calendar@2.0.7":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@nextui-org/calendar/-/calendar-2.0.7.tgz#912abbfb099b57a1bfff8df029a1db50ea9a8cd9"
+ integrity sha512-6mdgKJSl6tWo68FJQB1txSTRQ6/6+c3hipDYvzqDZRc+NbOJ3VevbFaPj5673JxeI2J5SyHLY2AEVw4q6HfaNw==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@react-aria/calendar" "3.5.8"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/calendar" "3.5.1"
+ "@react-stately/utils" "3.10.1"
+ "@react-types/button" "3.9.4"
+ "@react-types/calendar" "3.4.6"
+ "@react-types/shared" "3.23.1"
+ "@types/lodash.debounce" "^4.0.7"
+ lodash.debounce "^4.0.8"
+ scroll-into-view-if-needed "3.0.10"
+
+"@nextui-org/card@2.0.31":
+ version "2.0.31"
+ resolved "https://registry.yarnpkg.com/@nextui-org/card/-/card-2.0.31.tgz#562fc8e60013045bb2dc8322345eef32fa84fa0a"
+ integrity sha512-KXeI4xu0HVOgC2sNBxv+OGbzYy+kA6HbsDB677j3R+MhyCrqCLsE5ahkn7FRWgIJAzoDkcHSunmc+q9ApoSWig==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/ripple" "2.0.30"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@react-aria/button" "3.9.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/checkbox@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/checkbox/-/checkbox-2.1.2.tgz#e950eeed4de1f2b0f722c6c1b4430b949af38c25"
+ integrity sha512-0C5xcYcBMM/iAva3/fFYIvUiy91guV+mehUwRcPIxEFLA9bIOdOdGTkoAXlVcGCLIuYvlPiqSH0gShXvscOlNQ==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-callback-ref" "2.0.5"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/checkbox" "3.14.3"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/checkbox" "3.6.5"
+ "@react-stately/toggle" "3.7.4"
+ "@react-types/checkbox" "3.8.1"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/chip@2.0.30":
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/@nextui-org/chip/-/chip-2.0.30.tgz#4d345e9bdbd826e7ea5417c9e7c930306202ebf2"
+ integrity sha512-u/PbKFW8pGoPzBh8dDRvhBSdhX30lJbscQJvXzmCKHpSvK8rvBG1kHtOJEJ4fiuXbo/O0CYwZVAi03XloyOCdQ==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/checkbox" "3.8.1"
+
+"@nextui-org/code@2.0.29":
+ version "2.0.29"
+ resolved "https://registry.yarnpkg.com/@nextui-org/code/-/code-2.0.29.tgz#6c3bb0540f70a2b4f21cff3fdc2d6b70270bc724"
+ integrity sha512-+aevUjVJxSkJ4Un/O3rBdI1NfHikatzDK6iD6nqWDCDR/I+9a5m+s3N8yuNt/Mt8jGKg0KEklPh3deYfCVCXdg==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system-rsc" "2.1.2"
+
+"@nextui-org/date-input@2.1.1":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@nextui-org/date-input/-/date-input-2.1.1.tgz#54222fc44189f77339bd695a40119e709648f60b"
+ integrity sha512-fts8R058AVN8dhkBGaJ/7F68ZwM/E3Imu5uhauHoXVoJhaXNft5fA23HJYpNkFrG0k/Tk7vGcGSPistiERQuKg==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/datepicker" "3.10.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/datepicker" "3.9.4"
+ "@react-types/datepicker" "3.7.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/date-picker@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/date-picker/-/date-picker-2.1.2.tgz#f4fa1f42764efbfd073dbe630e26e9418340fcf7"
+ integrity sha512-gNqhyA85SDtGNdr2CUBJ5FSy/wCtj2AKJGs2yEvKtA9A66khOH2H0tdfGALOWoAQdxGgOvP7c+9U5Oadogoygg==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/calendar" "2.0.7"
+ "@nextui-org/date-input" "2.1.1"
+ "@nextui-org/popover" "2.1.24"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/datepicker" "3.10.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/datepicker" "3.9.4"
+ "@react-stately/overlays" "3.6.7"
+ "@react-stately/utils" "3.10.1"
+ "@react-types/datepicker" "3.7.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/divider@2.0.28":
+ version "2.0.28"
+ resolved "https://registry.yarnpkg.com/@nextui-org/divider/-/divider-2.0.28.tgz#e574b5d212b0e81f78d8f9a54783ce9927b65582"
+ integrity sha512-IskKmDOO8qwmTO2WtDmrH8fZvnV2JebP3PFfwqpToAdDRbRUs78pls2e8/T9clbLLtNxjfCFAI/Yi9C+LPPEXw==
+ dependencies:
+ "@nextui-org/react-rsc-utils" "2.0.12"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system-rsc" "2.1.2"
+ "@react-types/shared" "3.22.1"
+
+"@nextui-org/dropdown@2.1.26":
+ version "2.1.26"
+ resolved "https://registry.yarnpkg.com/@nextui-org/dropdown/-/dropdown-2.1.26.tgz#e805670425d0df0843fa10563e01b3a20feb6990"
+ integrity sha512-rPrn8hN7v2nLm9OJKagvf7AivsCAT0EWUcgWGaf5GVdwGJ65TZpjR18eAOyKBZRe5cdZ+FV6qqnavGVhD3458w==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/menu" "2.0.25"
+ "@nextui-org/popover" "2.1.24"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/menu" "3.14.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/menu" "3.7.1"
+ "@react-types/menu" "3.9.9"
+
+"@nextui-org/framer-utils@2.0.21":
+ version "2.0.21"
+ resolved "https://registry.yarnpkg.com/@nextui-org/framer-utils/-/framer-utils-2.0.21.tgz#3117df92d75b2c6c7a1f24cfa0cb5bd9e87161dc"
+ integrity sha512-kZzkaAHbtuBl85mivZ1WKVCcwdk8Z2NDmJiIpaLy16yliLNV1tnhoDOzRrxhv+6cbkKftx21tRrpImB4AyeqLw==
+ dependencies:
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system" "2.2.2"
+ "@nextui-org/use-measure" "2.0.1"
+
+"@nextui-org/image@2.0.29":
+ version "2.0.29"
+ resolved "https://registry.yarnpkg.com/@nextui-org/image/-/image-2.0.29.tgz#038a72d9956421360d06236e9a16f7a4ddfdc09a"
+ integrity sha512-w8MneV/JNUTCJUcIZcxtUYw1ZEZqlpezcCgGLr0cH3vp5pa+BZ9SdptwAL2wFoJAG8xk+et9fMXTROvF4h5W1g==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-image" "2.0.5"
+
+"@nextui-org/input@2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/input/-/input-2.2.2.tgz#db5d4bac963a9e5f53403254570ddbefd262a0c9"
+ integrity sha512-mCcFsObJdlCWMuSutKTRniFIDX5+z4BAAtt/XI1uzOtUO6WXgT97BwVzMihC1l14WQsw9TCwFKAl8JWdolkNCA==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/textfield" "3.14.5"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/utils" "3.10.1"
+ "@react-types/shared" "3.23.1"
+ "@react-types/textfield" "3.9.3"
+ react-textarea-autosize "^8.5.3"
+
+"@nextui-org/kbd@2.0.30":
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/@nextui-org/kbd/-/kbd-2.0.30.tgz#06dee8ecf7be6f75cd79246177fb2f919128acb3"
+ integrity sha512-rQw71noVUIRPf8N/Z5hdIGCtjFEVZO9xs2JVkiusKDxbGXFWKxJ3sTFzEY4VyLtORt2mEOQEWh26wbTnNjJzMw==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system-rsc" "2.1.2"
+ "@react-aria/utils" "3.24.1"
+
+"@nextui-org/link@2.0.32":
+ version "2.0.32"
+ resolved "https://registry.yarnpkg.com/@nextui-org/link/-/link-2.0.32.tgz#30f640870508b36a1c7bc6f3181f42a7fb0c0949"
+ integrity sha512-NIG8Ay/WfFxwMYKB11xg0iVAzJR1jy0QrtKFGaZscyJ522beM+aMBZuourC9u7kwjucTvt5fuGRm86KBVDBXCQ==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-link" "2.0.18"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/link" "3.7.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/link" "3.5.5"
+
+"@nextui-org/listbox@2.1.22":
+ version "2.1.22"
+ resolved "https://registry.yarnpkg.com/@nextui-org/listbox/-/listbox-2.1.22.tgz#4d8649efbc82744f494c719225aa7853398f49a4"
+ integrity sha512-VFULRE7BBpNnXulhySHlENRiRUP7KdpozJfKM3X2kIwWoFekO8DDUT8RiLj2PyDtGjKam74ghHhMuAFXFhVQ+g==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/divider" "2.0.28"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-is-mobile" "2.0.8"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/listbox" "3.12.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/list" "3.10.5"
+ "@react-types/menu" "3.9.9"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/menu@2.0.25":
+ version "2.0.25"
+ resolved "https://registry.yarnpkg.com/@nextui-org/menu/-/menu-2.0.25.tgz#99fc2c3debeef9117465834866a3c870106541f9"
+ integrity sha512-VkCaaq19JKNjIgg4bmGebzHkSV1A3C1CRV5w5qRPg5AI59pdWlbMLpllm5mPqz+U0R0P5saGfCfEfcC0LrCFdQ==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/divider" "2.0.28"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-menu" "2.0.5"
+ "@nextui-org/use-is-mobile" "2.0.8"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/menu" "3.14.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/menu" "3.7.1"
+ "@react-stately/tree" "3.8.1"
+ "@react-types/menu" "3.9.9"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/modal@2.0.36":
+ version "2.0.36"
+ resolved "https://registry.yarnpkg.com/@nextui-org/modal/-/modal-2.0.36.tgz#39f52fa39ed605c8631efb98991cf7073c2c0cc4"
+ integrity sha512-ucWBobeoM8BVLpgXrtZ/H5TD9eFS2YF4W7vntWC05Q13A34LSHgBjNHJkfwW/OebGjJoaDoRiIBohWaiyyliTA==
+ dependencies:
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@nextui-org/use-aria-modal-overlay" "2.0.10"
+ "@nextui-org/use-disclosure" "2.0.9"
+ "@react-aria/dialog" "3.5.14"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/overlays" "3.6.7"
+ "@react-types/overlays" "3.8.7"
+
+"@nextui-org/navbar@2.0.33":
+ version "2.0.33"
+ resolved "https://registry.yarnpkg.com/@nextui-org/navbar/-/navbar-2.0.33.tgz#2cd2d3a3b421f5ab7ecfbdf304ef10802dd8ec29"
+ integrity sha512-WbPLEz6yE1vxKTqZDN85YPCWR/JSvpOO604xBpaaCf+OLfEsb+herz7+GDPnvHKaPDASoxU5WaSQJR9nrJ/YHg==
+ dependencies:
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-toggle-button" "2.0.9"
+ "@nextui-org/use-scroll-position" "2.0.6"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/toggle" "3.7.4"
+ "@react-stately/utils" "3.10.1"
+ react-remove-scroll "^2.5.6"
+
+"@nextui-org/pagination@2.0.33":
+ version "2.0.33"
+ resolved "https://registry.yarnpkg.com/@nextui-org/pagination/-/pagination-2.0.33.tgz#06a76917a55b49462ae9152df0583e9f1300803f"
+ integrity sha512-LiDDTSTuC0Q9gSI1gc/b+lmKR8/zFiwSfYjLh7KDND3m+qE44waICWnK1U7P6Y999Nu1LwaGSGtqayd326aPrg==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-pagination" "2.0.7"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ scroll-into-view-if-needed "3.0.10"
+
+"@nextui-org/popover@2.1.24":
+ version "2.1.24"
+ resolved "https://registry.yarnpkg.com/@nextui-org/popover/-/popover-2.1.24.tgz#fd575dc0c1ab314e7d8a18a4aec3c2812ba2412b"
+ integrity sha512-PGbTxdcc06BMxEd/HYsL0sVa0fdGjHPYNSvcSSM0KA6Fh98pznO9DoQHjIEPAul87yEwl7cDDj7mANcdK9BVnA==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/dialog" "3.5.14"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/overlays" "3.6.7"
+ "@react-types/button" "3.9.4"
+ "@react-types/overlays" "3.8.7"
+ react-remove-scroll "^2.5.6"
+
+"@nextui-org/progress@2.0.31":
+ version "2.0.31"
+ resolved "https://registry.yarnpkg.com/@nextui-org/progress/-/progress-2.0.31.tgz#b70c9c586dc5dff8b22ff761fc27a9049105ce1a"
+ integrity sha512-ZFjV4068gYPe9S4R1e/8oqwtPFKd9ag8RB0JoToq55AM5aLItOA/Q/uwBnDz7ait3C7viWawcN4leW1C8dSurQ==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-is-mounted" "2.0.5"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/progress" "3.4.13"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/progress" "3.5.4"
+
+"@nextui-org/radio@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/radio/-/radio-2.1.2.tgz#5039b098f80dd4050acbe88b247ddba25022de57"
+ integrity sha512-JcWKRqXXRwQtz5ABzykuu+S4/8cO9GKa21Gget1fdo/iSDcUtGDHIf6wlpvWSNekpvIERZd9UdpwhaXWbD4pOg==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/radio" "3.10.4"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/radio" "3.10.4"
+ "@react-types/radio" "3.8.1"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/react-rsc-utils@2.0.12":
+ version "2.0.12"
+ resolved "https://registry.yarnpkg.com/@nextui-org/react-rsc-utils/-/react-rsc-utils-2.0.12.tgz#a931a2e6a9523e9f11f3397a57cde0861ba9ff7a"
+ integrity sha512-s2IG4pM1K+kbm6A2g3UpqrS592AExpGixtZNPJ2lV5+UQi1ld3vb4EiBIOViZMoSCNCoNdaeO5Yqo6cKghwCPA==
+
+"@nextui-org/react-utils@2.0.14":
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/@nextui-org/react-utils/-/react-utils-2.0.14.tgz#e075fd8af2f59804186af6dbfd64605b945c5cbc"
+ integrity sha512-fed97WSaHt8/sC5F4DFTVj25YQsepFGDyudommPGQsTksQ6GQkMITuHckzAyPiTTuWHSW/GZykvVVAlK9hS5Wg==
+ dependencies:
+ "@nextui-org/react-rsc-utils" "2.0.12"
+ "@nextui-org/shared-utils" "2.0.5"
+
+"@nextui-org/react@^2.4.2":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/react/-/react-2.4.2.tgz#236941ccdcb103b80d186bec23b852a40d5d513c"
+ integrity sha512-g7CqAX/x0DJsIUmD+Z6I4T1699uVmu5kbuY0n1PdA4IDjFSKzgkMCIogcIKu2iUV+LVlvfF1lDhs300OIpouig==
+ dependencies:
+ "@nextui-org/accordion" "2.0.35"
+ "@nextui-org/autocomplete" "2.1.2"
+ "@nextui-org/avatar" "2.0.30"
+ "@nextui-org/badge" "2.0.29"
+ "@nextui-org/breadcrumbs" "2.0.10"
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/calendar" "2.0.7"
+ "@nextui-org/card" "2.0.31"
+ "@nextui-org/checkbox" "2.1.2"
+ "@nextui-org/chip" "2.0.30"
+ "@nextui-org/code" "2.0.29"
+ "@nextui-org/date-input" "2.1.1"
+ "@nextui-org/date-picker" "2.1.2"
+ "@nextui-org/divider" "2.0.28"
+ "@nextui-org/dropdown" "2.1.26"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/image" "2.0.29"
+ "@nextui-org/input" "2.2.2"
+ "@nextui-org/kbd" "2.0.30"
+ "@nextui-org/link" "2.0.32"
+ "@nextui-org/listbox" "2.1.22"
+ "@nextui-org/menu" "2.0.25"
+ "@nextui-org/modal" "2.0.36"
+ "@nextui-org/navbar" "2.0.33"
+ "@nextui-org/pagination" "2.0.33"
+ "@nextui-org/popover" "2.1.24"
+ "@nextui-org/progress" "2.0.31"
+ "@nextui-org/radio" "2.1.2"
+ "@nextui-org/ripple" "2.0.30"
+ "@nextui-org/scroll-shadow" "2.1.17"
+ "@nextui-org/select" "2.2.2"
+ "@nextui-org/skeleton" "2.0.29"
+ "@nextui-org/slider" "2.2.12"
+ "@nextui-org/snippet" "2.0.38"
+ "@nextui-org/spacer" "2.0.29"
+ "@nextui-org/spinner" "2.0.30"
+ "@nextui-org/switch" "2.0.31"
+ "@nextui-org/system" "2.2.2"
+ "@nextui-org/table" "2.0.36"
+ "@nextui-org/tabs" "2.0.32"
+ "@nextui-org/theme" "2.2.6"
+ "@nextui-org/tooltip" "2.0.36"
+ "@nextui-org/user" "2.0.31"
+ "@react-aria/visually-hidden" "3.8.12"
+
+"@nextui-org/ripple@2.0.30":
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/@nextui-org/ripple/-/ripple-2.0.30.tgz#abe44dc757a52e7b707284b2f57caae20ddd4c53"
+ integrity sha512-GmHwC+F2JIYQAeFuwtFbdE6av8lzOJVdA5yops9vhhzeBPT33dMjgazCn0HZT5TvP0gX+xxT/74ONE0ik0Kayg==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+
+"@nextui-org/scroll-shadow@2.1.17":
+ version "2.1.17"
+ resolved "https://registry.yarnpkg.com/@nextui-org/scroll-shadow/-/scroll-shadow-2.1.17.tgz#f037431c26e99dfffd0214ba132c6febaa191133"
+ integrity sha512-JOJc6nbdFHcMn/zpaf78AAZ8Vwo/iQO6iWJVHlN6ROjSKL7EImP/V78m14Y+kd0hkzU8CcHswdpmCefaioFlRA==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-data-scroll-overflow" "2.1.4"
+
+"@nextui-org/select@2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/select/-/select-2.2.2.tgz#eb18757529aade858d32b09c69064914c8a1fb50"
+ integrity sha512-bCk6/LJAhhSM5VXiny7rDTH5f7ri7mGKx4V+K83kY9uW01ioWWYId1EhbP6Crd9PSvmQL42mhId/5dLRxgUimA==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/listbox" "2.1.22"
+ "@nextui-org/popover" "2.1.24"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/scroll-shadow" "2.1.17"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/spinner" "2.0.30"
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@nextui-org/use-aria-multiselect" "2.2.2"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/form" "3.0.5"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/shared-icons@2.0.8":
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/@nextui-org/shared-icons/-/shared-icons-2.0.8.tgz#2dd34322503bad5ce06420940369bbc4140c9f15"
+ integrity sha512-siKuw+CN03cB2N1eUpIleP+lTpjM4gSmcco7RXTpXiwXJXlxjKo4N8gQYS04HCBXm9QMWgyngvUEt2II9NYyrw==
+
+"@nextui-org/shared-utils@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/shared-utils/-/shared-utils-2.0.5.tgz#f04072240f35b0a5748fe38b4ec1c285231d6074"
+ integrity sha512-aFc/CUL8RVfBh0IotIpxkpKjyUPc/zJaMJd5pRCQA1kIpKLdSrlh3//MLYMaP/fo/NQtE3DPeXqfKhHRr1fkEw==
+
+"@nextui-org/skeleton@2.0.29":
+ version "2.0.29"
+ resolved "https://registry.yarnpkg.com/@nextui-org/skeleton/-/skeleton-2.0.29.tgz#37b1147b3b6f814f29050a41b1fee0ed994422b6"
+ integrity sha512-s/oQdUc1Ao7XRmUP82V2/hI3B644ZQzIYuPIgp+A6DyDLfyRUx8PLWN/EhN5Ku2M/s6WYTkwulDrKeo4dlMsrw==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+
+"@nextui-org/slider@2.2.12":
+ version "2.2.12"
+ resolved "https://registry.yarnpkg.com/@nextui-org/slider/-/slider-2.2.12.tgz#a9293980c42c21b07d4538531f3491700517555c"
+ integrity sha512-5+72YlWxV6bm9hGNpWN5G+6OeqU7S9N2ECwEdO4COQ1hvMiimiJ3lrTUHIS2AvKimEpw+MLkUoKIbqAV23zxuw==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/tooltip" "2.0.36"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/slider" "3.7.8"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/slider" "3.5.4"
+
+"@nextui-org/snippet@2.0.38":
+ version "2.0.38"
+ resolved "https://registry.yarnpkg.com/@nextui-org/snippet/-/snippet-2.0.38.tgz#a5a15bacc94e7f67a2f8804f76d6197ee24ae79c"
+ integrity sha512-8lMqtB1KQtMkpZFb3x/T42zdZ+QqcGr6d/yVE+zKzyEd+xqzm2g/hDpPqy0Mf5JaC1Z+lXoRzF/6XbD99FCEbw==
+ dependencies:
+ "@nextui-org/button" "2.0.34"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/tooltip" "2.0.36"
+ "@nextui-org/use-clipboard" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/utils" "3.24.1"
+
+"@nextui-org/spacer@2.0.29":
+ version "2.0.29"
+ resolved "https://registry.yarnpkg.com/@nextui-org/spacer/-/spacer-2.0.29.tgz#2cce8bc0e69a87a91e8ee320df407fe989129e3c"
+ integrity sha512-lcgzHIvTXXllnM6MMjti0ub8jEx9jmtzdd5+zgFAHLTeDS3pDffNZndmU+RkzpyGSyK20PCrMkV/sB4SCDN1KA==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system-rsc" "2.1.2"
+
+"@nextui-org/spinner@2.0.30":
+ version "2.0.30"
+ resolved "https://registry.yarnpkg.com/@nextui-org/spinner/-/spinner-2.0.30.tgz#f8f40a45da575f73f3d94a2f804041f6b71216ba"
+ integrity sha512-+oygL2dewHZzJiSUEIvzL0tIx+G+98mvO3ToFAMXaH0N3bOQNSiFDPwUHUx6PgAQ9pr9RKtdnb4ywstcG9j+Gg==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/system-rsc" "2.1.2"
+
+"@nextui-org/switch@2.0.31":
+ version "2.0.31"
+ resolved "https://registry.yarnpkg.com/@nextui-org/switch/-/switch-2.0.31.tgz#189846066692687ad879ad7d4b048e899e7bfe55"
+ integrity sha512-WPHqWQfyISA8nmQ8ihaO5rIHm/K9nyfrV0Fxm6EcnFilTMZhh4Kt+p7FfJrZw+MMyzIEGFfMDySk1KVrMubc1g==
+ dependencies:
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/switch" "3.6.4"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/toggle" "3.7.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/system-rsc@2.1.2":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/system-rsc/-/system-rsc-2.1.2.tgz#42b6568617018ec108cb60d22cb7bff96f6117b3"
+ integrity sha512-3F7pG68Ikh1JsMtRQqmyXAojAV4lMPCKCy0n8RiIxJkEJg11RGTXhnABHF2jP6uxMH/0q5zVzuFubQJfW++ISQ==
+ dependencies:
+ clsx "^1.2.1"
+
+"@nextui-org/system@2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/system/-/system-2.2.2.tgz#2ed5758bc7589a5e958f6ff9d08fc623be41e953"
+ integrity sha512-u30lWSIO4Q7DStiK5tJjDgKBQtmODeQZcC6llz973sJ9QlE4GeC1fgu0+/zXL8AZZ8o/iEXhHWXsZIJ26EquUQ==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/system-rsc" "2.1.2"
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/utils" "3.10.1"
+
+"@nextui-org/table@2.0.36":
+ version "2.0.36"
+ resolved "https://registry.yarnpkg.com/@nextui-org/table/-/table-2.0.36.tgz#607dc9d55637e0160abf48ffe72aa52cb7142db7"
+ integrity sha512-vpohZo5p3XmT6FLOKKwmm8SdCA/h2QPQz6Y66sAfHuoqAfkmfVfAeyKgYTe20pVJy3Whvyix6IA8e0eWETDTEw==
+ dependencies:
+ "@nextui-org/checkbox" "2.1.2"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-icons" "2.0.8"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/spacer" "2.0.29"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/table" "3.14.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-aria/visually-hidden" "3.8.12"
+ "@react-stately/table" "3.11.8"
+ "@react-stately/virtualizer" "3.7.1"
+ "@react-types/grid" "3.2.6"
+ "@react-types/table" "3.9.5"
+
+"@nextui-org/tabs@2.0.32":
+ version "2.0.32"
+ resolved "https://registry.yarnpkg.com/@nextui-org/tabs/-/tabs-2.0.32.tgz#13fe104097664f6d627bc60e37673492b9069456"
+ integrity sha512-TVCwm1GI7rkf/o7+eWpklRQBTg2Y/m3eNBLU1jA+Ppqs+Mr31y7BHoNLqTZ6jpj59DA1OcpwbJH5xhGk0pOvwA==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-is-mounted" "2.0.5"
+ "@nextui-org/use-update-effect" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/tabs" "3.9.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/tabs" "3.6.6"
+ "@react-types/shared" "3.23.1"
+ "@react-types/tabs" "3.3.7"
+ scroll-into-view-if-needed "3.0.10"
+
+"@nextui-org/theme@2.2.6":
+ version "2.2.6"
+ resolved "https://registry.yarnpkg.com/@nextui-org/theme/-/theme-2.2.6.tgz#57f8fca6c2fddaf72df3c92e0e9befbd4a5a3002"
+ integrity sha512-FyDp5edpmjbvPzRx+D2+Km1oZ73wQOzKMSBPomOgP0h9OFnnTHqKlmtbGhWSk2cEyYN9VsaGvqJTw8X35/aChQ==
+ dependencies:
+ clsx "^1.2.1"
+ color "^4.2.3"
+ color2k "^2.0.2"
+ deepmerge "4.3.1"
+ flat "^5.0.2"
+ lodash.foreach "^4.5.0"
+ lodash.get "^4.4.2"
+ lodash.kebabcase "^4.1.1"
+ lodash.mapkeys "^4.6.0"
+ lodash.omit "^4.5.0"
+ tailwind-merge "^1.14.0"
+ tailwind-variants "^0.1.20"
+
+"@nextui-org/tooltip@2.0.36":
+ version "2.0.36"
+ resolved "https://registry.yarnpkg.com/@nextui-org/tooltip/-/tooltip-2.0.36.tgz#59ca20f60f7e8268659e1ee3a9b7a7ff25ef971e"
+ integrity sha512-tV3BefTvmYzSC4TX+UPV7p3F5fs52sFzQ1/Try/Bkz5B1F9yXviO9dV2/pqXSfOJVvLVJS2RMi5wZkaYh1xtNw==
+ dependencies:
+ "@nextui-org/aria-utils" "2.0.21"
+ "@nextui-org/framer-utils" "2.0.21"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/tooltip" "3.7.4"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/tooltip" "3.4.9"
+ "@react-types/overlays" "3.8.7"
+ "@react-types/tooltip" "3.4.9"
+
+"@nextui-org/use-aria-accordion@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-accordion/-/use-aria-accordion-2.0.6.tgz#6cdad59f02a9496c505782658e3a3ce996d47e2d"
+ integrity sha512-47+/gO67YufQUtL0f2TIdaa8++5EBtIK7Ltq1GpUat2qjbMFvIb6Ao/Jf3KHU5NicLLRnWPSK1vNaupkYwN/ew==
+ dependencies:
+ "@react-aria/button" "3.9.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/selection" "3.18.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/tree" "3.8.1"
+ "@react-types/accordion" "3.0.0-alpha.21"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-button@2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-button/-/use-aria-button-2.0.9.tgz#b537c0d208ad2502c0835415b039146612c5153f"
+ integrity sha512-5FjDl57/1Ey3MgJn+yB0/CPABsSVgXiE+jT7ZLnSqH9kmdXV/eMiuplF7fOOvaSMCA1cE3KCetaPVDIZoJI1/w==
+ dependencies:
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/button" "3.9.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-link@2.0.18":
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-link/-/use-aria-link-2.0.18.tgz#9cf8760a98faa4f4931f07172fae3e1c2bd42f7e"
+ integrity sha512-6ZIIOfMMGbSOF9FcJTPrsVOm2LP7OV+QwF0vYelZeEK5zFXb5f8e2J/fEbCVWKLPFDB2VyoBUDWMzRfrizixzg==
+ dependencies:
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/utils" "3.24.1"
+ "@react-types/link" "3.5.5"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-menu@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-menu/-/use-aria-menu-2.0.5.tgz#a27cdb58179eb96770e85a0d0caaae229ec09229"
+ integrity sha512-7bAwISb4vIGhAuvZEHpb/28u0k2/HxNhMJUcz/UxVJTMqSkbSJR2RKdm64WfhEq2A8ZtvED0BAJbDuPf4Q4avg==
+ dependencies:
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/menu" "3.14.1"
+ "@react-aria/selection" "3.18.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/collections" "3.10.7"
+ "@react-stately/tree" "3.8.1"
+ "@react-types/menu" "3.9.9"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-modal-overlay@2.0.10":
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-modal-overlay/-/use-aria-modal-overlay-2.0.10.tgz#863b879cc780421c1f5d4277a60309ab444a2683"
+ integrity sha512-/VONX/beH4vu7SQjAtxcQoRhdAOro+QeBk9XOW+qcNvxZG4Em1vf1KFmpHRC40DtsrUk3I0cxaZezeIgfOZ41Q==
+ dependencies:
+ "@react-aria/overlays" "3.22.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/overlays" "3.6.7"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-multiselect@2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-multiselect/-/use-aria-multiselect-2.2.2.tgz#b253d9412d5868434137551b283d770b6db2e0e2"
+ integrity sha512-iFw9CVRWTKBl+c1FbbHxp4K0B6aQTXSzXiIP09TJ1NQ10fk1GQXBIhFUIyvIwRJRGvYAL+vwkgj39Ac1p1esJQ==
+ dependencies:
+ "@react-aria/i18n" "3.11.1"
+ "@react-aria/interactions" "3.21.3"
+ "@react-aria/label" "3.7.8"
+ "@react-aria/listbox" "3.12.1"
+ "@react-aria/menu" "3.14.1"
+ "@react-aria/selection" "3.18.1"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/form" "3.0.3"
+ "@react-stately/list" "3.10.5"
+ "@react-stately/menu" "3.7.1"
+ "@react-types/button" "3.9.4"
+ "@react-types/overlays" "3.8.7"
+ "@react-types/select" "3.9.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-aria-toggle-button@2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-aria-toggle-button/-/use-aria-toggle-button-2.0.9.tgz#d97751d871e65c3ce399ebfe87b14988456de3cd"
+ integrity sha512-JpPD97tYpPwyhgXgJbWYgMDp5ZysM1LyvvmyHmq6BtvSpyYqQKU7V3LDXuirBEN6NwHHZRfXy4/mUid/L6W0wA==
+ dependencies:
+ "@nextui-org/use-aria-button" "2.0.9"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/toggle" "3.7.4"
+ "@react-types/button" "3.9.4"
+ "@react-types/shared" "3.23.1"
+
+"@nextui-org/use-callback-ref@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-callback-ref/-/use-callback-ref-2.0.5.tgz#7664dfedfb4ad35dd00b61d1d57477b805e1e8d2"
+ integrity sha512-lcjlV5yaDTiFSv06E5RtQNqy+O6XqH/Q/yz+ka1ZBlZF/FdzEPNRfJ0shN2D7Sh3DdbvV2lySbA2g/0d94geaw==
+ dependencies:
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+
+"@nextui-org/use-clipboard@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-clipboard/-/use-clipboard-2.0.5.tgz#846293369105d386ea0b6e4dfd4e776ce561ed03"
+ integrity sha512-1ExwXM8ENmc/kVDqKoiPGrBP/0B7rZ43iSv2MoWD1Qpc8GHg71Rv7NTIlBDoD/pfUfqkab6x66iKC7AVR8rifA==
+
+"@nextui-org/use-data-scroll-overflow@2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-data-scroll-overflow/-/use-data-scroll-overflow-2.1.4.tgz#56cdc6b45076b56b9e1d035fb7e2d12b6c43e41b"
+ integrity sha512-0YqUAe/b9aZftUQOH7sWqBMJHGLyC2Q/ixFyjq8Q1TijrqEyGESGQ2tm0+FHytI04drV+mnsbf6+q2QIKyqGSg==
+ dependencies:
+ "@nextui-org/shared-utils" "2.0.5"
+
+"@nextui-org/use-disclosure@2.0.9":
+ version "2.0.9"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-disclosure/-/use-disclosure-2.0.9.tgz#082f55998508241b8c9b008ee96d96c5df483da4"
+ integrity sha512-d1Pksmm6zleZAdNraD0s97E+sXHrzI0vZ8tLNzE9yGNOf/VRMBvjpfa9S4Zl7oR+StNbST3JofCqmSHtRNe7hg==
+ dependencies:
+ "@nextui-org/use-callback-ref" "2.0.5"
+ "@react-aria/utils" "3.24.1"
+ "@react-stately/utils" "3.10.1"
+
+"@nextui-org/use-image@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-image/-/use-image-2.0.5.tgz#1482fed65e152e84fe742658e6e6f42e08547608"
+ integrity sha512-FAMyvZS9XSNLqHEmU6xykMgwIFJj/V9/JpTiZAQziz2wqMiUONIBpYpGOlI+pPBNlhCkw62KHm/19vHW49FWhA==
+ dependencies:
+ "@nextui-org/use-safe-layout-effect" "2.0.5"
+
+"@nextui-org/use-is-mobile@2.0.8":
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-is-mobile/-/use-is-mobile-2.0.8.tgz#9b77f22f68a4ce959de9a0f101ce465a33fcdcd8"
+ integrity sha512-fp6UgfmYTkdri3fKeFUapr0TuJGRTskrTZixh+r1aqTcEWtaeef+Nli5VKRTJb9nqYKkgJDRhC39Z5s/rgq0mA==
+ dependencies:
+ "@react-aria/ssr" "3.9.4"
+
+"@nextui-org/use-is-mounted@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-is-mounted/-/use-is-mounted-2.0.5.tgz#bdd739c23f7cc8268bfbff35a0a57080d8837332"
+ integrity sha512-gk698Uwmj/XhchBsnI5Ups5uzEXuZvsPK45K6goi2/ADKXSYxHOcSgwoexytqJBb/7tpi+emi2CRTAjAFZDQqA==
+
+"@nextui-org/use-measure@2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-measure/-/use-measure-2.0.1.tgz#05cad80847492a3399ac5b8bf7756c86c136ea32"
+ integrity sha512-uEtdrdBdFz4Fgbfk2vmQ+rEb+eFa5o4yI90udasvfpaIrMBfrFOlRW5+yn3uXKB8JThET4Gf2on/wlJpo567Dg==
+
+"@nextui-org/use-pagination@2.0.7":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-pagination/-/use-pagination-2.0.7.tgz#164cc6f0a8b8a9811c8dc726a0bbd2cd5f2da660"
+ integrity sha512-a05vLp8YSk4nI+LmDUdjjKj2U1/d3Z1ZALUUrjWJVnTUckaiglHGeoYEh8nqcjDXj4sPC4OcK3ZnW+AGUXDGwA==
+ dependencies:
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/i18n" "3.11.1"
+
+"@nextui-org/use-safe-layout-effect@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-safe-layout-effect/-/use-safe-layout-effect-2.0.5.tgz#36c40fb2511667f3593035d995c971a29c8495f8"
+ integrity sha512-YQQlqz82aYxMoEq23jQNG/JBPHF1x3opzyXRHAVxgBEFo9OJqBMZTm23ukpTXm2Ev98T6mpWiTHdfyHJ7IoRog==
+
+"@nextui-org/use-scroll-position@2.0.6":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-scroll-position/-/use-scroll-position-2.0.6.tgz#58bd0205708709fec8e8224d6dee019449f3aa7b"
+ integrity sha512-dRwew37XnJOh8d35BuyqzRfnrmKsOUHqi0Owhk0tIGyqifQ/jw65udWpBfa6rwXcd4cKOOqXXHuNGsYTclzc6w==
+
+"@nextui-org/use-update-effect@2.0.5":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nextui-org/use-update-effect/-/use-update-effect-2.0.5.tgz#b949d5403ba05879f2a6bd78b586b8bed7839ee5"
+ integrity sha512-4r2CXAD598xc2ifMu97kf8V/lj+NDct2oITbxgXeV4ezWaXHy5/26r1iyVnBzRN/VBz3fwHx3hHdftzcYSZxdA==
+
+"@nextui-org/user@2.0.31":
+ version "2.0.31"
+ resolved "https://registry.yarnpkg.com/@nextui-org/user/-/user-2.0.31.tgz#dab104787169bb46d57cb27c0a7f0bd848affcc6"
+ integrity sha512-PXWVLB2igKi3MwjVeI5auoK6fhBgT3nizPzabBa95m0/3dg8aex/4oexCRpjef+V5cRD/2z37VHqfelQWqOHjQ==
+ dependencies:
+ "@nextui-org/avatar" "2.0.30"
+ "@nextui-org/react-utils" "2.0.14"
+ "@nextui-org/shared-utils" "2.0.5"
+ "@react-aria/focus" "3.17.1"
+ "@react-aria/utils" "3.24.1"
+
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
@@ -142,6 +1136,849 @@
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+"@react-aria/breadcrumbs@3.5.13":
+ version "3.5.13"
+ resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.13.tgz#2686f7f460f20d67fe5cdfe185e32e3e78186962"
+ integrity sha512-G1Gqf/P6kVdfs94ovwP18fTWuIxadIQgHsXS08JEVcFVYMjb9YjqnEBaohUxD1tq2WldMbYw53ahQblT4NTG+g==
+ dependencies:
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/link" "^3.7.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/breadcrumbs" "^3.7.5"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/button@3.9.5":
+ version "3.9.5"
+ resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.9.5.tgz#f0082f58394394f3d16fdf45de57b382748f3345"
+ integrity sha512-dgcYR6j8WDOMLKuVrtxzx4jIC05cVKDzc+HnPO8lNkBAOfjcuN5tkGRtIjLtqjMvpZHhQT5aDbgFpIaZzxgFIg==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/toggle" "^3.7.4"
+ "@react-types/button" "^3.9.4"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/calendar@3.5.8":
+ version "3.5.8"
+ resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.5.8.tgz#fd0858b34c8961b76957e9ac13b514f485c329a3"
+ integrity sha512-Whlp4CeAA5/ZkzrAHUv73kgIRYjw088eYGSc+cvSOCxfrc/2XkBm9rNrnSBv0DvhJ8AG0Fjz3vYakTmF3BgZBw==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/live-announcer" "^3.3.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/calendar" "^3.5.1"
+ "@react-types/button" "^3.9.4"
+ "@react-types/calendar" "^3.4.6"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/checkbox@3.14.3":
+ version "3.14.3"
+ resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.14.3.tgz#6e2579681008e460d2c764a03f1f1b54e0815868"
+ integrity sha512-EtBJL6iu0gvrw3A4R7UeVLR6diaVk/mh4kFBc7c8hQjpEJweRr4hmJT3hrNg3MBcTWLxFiMEXPGgWEwXDBygtA==
+ dependencies:
+ "@react-aria/form" "^3.0.5"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/toggle" "^3.10.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/checkbox" "^3.6.5"
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/toggle" "^3.7.4"
+ "@react-types/checkbox" "^3.8.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/combobox@3.9.1":
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.9.1.tgz#ab12b698b76fd063f386aa5516129b2c72f5bf60"
+ integrity sha512-SpK92dCmT8qn8aEcUAihRQrBb5LZUhwIbDExFII8PvUvEFy/PoQHXIo3j1V29WkutDBDpMvBv/6XRCHGXPqrhQ==
+ dependencies:
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/listbox" "^3.12.1"
+ "@react-aria/live-announcer" "^3.3.4"
+ "@react-aria/menu" "^3.14.1"
+ "@react-aria/overlays" "^3.22.1"
+ "@react-aria/selection" "^3.18.1"
+ "@react-aria/textfield" "^3.14.5"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/combobox" "^3.8.4"
+ "@react-stately/form" "^3.0.3"
+ "@react-types/button" "^3.9.4"
+ "@react-types/combobox" "^3.11.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/datepicker@3.10.1":
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.10.1.tgz#513a9d18e118d4c3d078fdbfc45dca76b7eeb37f"
+ integrity sha512-4HZL593nrNMa1GjBmWEN/OTvNS6d3/16G1YJWlqiUlv11ADulSbqBIjMmkgwrJVFcjrgqtXFy+yyrTA/oq94Zw==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@internationalized/number" "^3.5.3"
+ "@internationalized/string" "^3.2.3"
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/form" "^3.0.5"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/spinbutton" "^3.6.5"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/datepicker" "^3.9.4"
+ "@react-stately/form" "^3.0.3"
+ "@react-types/button" "^3.9.4"
+ "@react-types/calendar" "^3.4.6"
+ "@react-types/datepicker" "^3.7.4"
+ "@react-types/dialog" "^3.5.10"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/dialog@3.5.14":
+ version "3.5.14"
+ resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.14.tgz#d4b078410c00b7cc7e6f25f67dfe53fa755be769"
+ integrity sha512-oqDCjQ8hxe3GStf48XWBf2CliEnxlR9GgSYPHJPUc69WBj68D9rVcCW3kogJnLAnwIyf3FnzbX4wSjvUa88sAQ==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/overlays" "^3.22.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/dialog" "^3.5.10"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/focus@3.17.1", "@react-aria/focus@^3.17.1":
+ version "3.17.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.17.1.tgz#c796a188120421e2fedf438cadacdf463c77ad29"
+ integrity sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==
+ dependencies:
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+ clsx "^2.0.0"
+
+"@react-aria/form@3.0.5", "@react-aria/form@^3.0.5":
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.0.5.tgz#abaf6ac005dc3f98760ac74fdb6524ad189399d6"
+ integrity sha512-n290jRwrrRXO3fS82MyWR+OKN7yznVesy5Q10IclSTVYHHI3VI53xtAPr/WzNjJR1um8aLhOcDNFKwnNIUUCsQ==
+ dependencies:
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/form" "^3.0.3"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/grid@^3.9.1":
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.9.1.tgz#7fcf7a8352ece79406caf3cd149947fb9f000009"
+ integrity sha512-fGEZqAEaS8mqzV/II3N4ndoNWegIcbh+L3PmKbXdpKKUP8VgMs/WY5rYl5WAF0f5RoFwXqx3ibDLeR9tKj/bOg==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/live-announcer" "^3.3.4"
+ "@react-aria/selection" "^3.18.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/grid" "^3.8.7"
+ "@react-stately/selection" "^3.15.1"
+ "@react-stately/virtualizer" "^3.7.1"
+ "@react-types/checkbox" "^3.8.1"
+ "@react-types/grid" "^3.2.6"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/i18n@3.11.1", "@react-aria/i18n@^3.11.1":
+ version "3.11.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.11.1.tgz#2d238d2be30d8c691b5fa3161f5fb48066fc8e4b"
+ integrity sha512-vuiBHw1kZruNMYeKkTGGnmPyMnM5T+gT8bz97H1FqIq1hQ6OPzmtBZ6W6l6OIMjeHI5oJo4utTwfZl495GALFQ==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@internationalized/message" "^3.1.4"
+ "@internationalized/number" "^3.5.3"
+ "@internationalized/string" "^3.2.3"
+ "@react-aria/ssr" "^3.9.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/interactions@3.21.3", "@react-aria/interactions@^3.21.3":
+ version "3.21.3"
+ resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.21.3.tgz#a2a3e354a8b894bed7a46e1143453f397f2538d7"
+ integrity sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==
+ dependencies:
+ "@react-aria/ssr" "^3.9.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/label@3.7.8", "@react-aria/label@^3.7.8":
+ version "3.7.8"
+ resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.8.tgz#69f1c184836b04445fcedce78db9fd939a0570ea"
+ integrity sha512-MzgTm5+suPA3KX7Ug6ZBK2NX9cin/RFLsv1BdafJ6CZpmUSpWnGE/yQfYUB7csN7j31OsZrD3/P56eShYWAQfg==
+ dependencies:
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/link@3.7.1", "@react-aria/link@^3.7.1":
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.7.1.tgz#ae75feebc5c6f40e1031abf57f3125d45882e976"
+ integrity sha512-a4IaV50P3fXc7DQvEIPYkJJv26JknFbRzFT5MJOMgtzuhyJoQdILEUK6XHYjcSSNCA7uLgzpojArVk5Hz3lCpw==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/link" "^3.5.5"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/listbox@3.12.1", "@react-aria/listbox@^3.12.1":
+ version "3.12.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.12.1.tgz#cc4f0d23630f496273ca5c31b4dfacf6d6f37df1"
+ integrity sha512-7JiUp0NGykbv/HgSpmTY1wqhuf/RmjFxs1HZcNaTv8A+DlzgJYc7yQqFjP3ZA/z5RvJFuuIxggIYmgIFjaRYdA==
+ dependencies:
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/selection" "^3.18.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/list" "^3.10.5"
+ "@react-types/listbox" "^3.4.9"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/live-announcer@^3.3.4":
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.3.4.tgz#97a5830ae7da8546b2d19311fe1606c5d5e0151c"
+ integrity sha512-w8lxs35QrRrn6pBNzVfyGOeqWdxeVKf9U6bXIVwhq7rrTqRULL8jqy8RJIMfIs1s8G5FpwWYjyBOjl2g5Cu1iA==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/menu@3.14.1", "@react-aria/menu@^3.14.1":
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.14.1.tgz#c9ec25bc374ee9bb02dc3d92d8260df702349133"
+ integrity sha512-BYliRb38uAzq05UOFcD5XkjA5foQoXRbcH3ZufBsc4kvh79BcP1PMW6KsXKGJ7dC/PJWUwCui6QL1kUg8PqMHA==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/overlays" "^3.22.1"
+ "@react-aria/selection" "^3.18.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/menu" "^3.7.1"
+ "@react-stately/tree" "^3.8.1"
+ "@react-types/button" "^3.9.4"
+ "@react-types/menu" "^3.9.9"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/overlays@3.22.1", "@react-aria/overlays@^3.22.1":
+ version "3.22.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.22.1.tgz#7a01673317fa6517bb91b0b7504e303facdc9ccb"
+ integrity sha512-GHiFMWO4EQ6+j6b5QCnNoOYiyx1Gk8ZiwLzzglCI4q1NY5AG2EAmfU4Z1+Gtrf2S5Y0zHbumC7rs9GnPoGLUYg==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/ssr" "^3.9.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-aria/visually-hidden" "^3.8.12"
+ "@react-stately/overlays" "^3.6.7"
+ "@react-types/button" "^3.9.4"
+ "@react-types/overlays" "^3.8.7"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/progress@3.4.13":
+ version "3.4.13"
+ resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.13.tgz#dc86c98ed0f9a164cf62140e13865235c1991548"
+ integrity sha512-YBV9bOO5JzKvG8QCI0IAA00o6FczMgIDiK8Q9p5gKorFMatFUdRayxlbIPoYHMi+PguLil0jHgC7eOyaUcrZ0g==
+ dependencies:
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/progress" "^3.5.4"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/radio@3.10.4":
+ version "3.10.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.10.4.tgz#e1b54fa7a9ee3912a5fe170fc752000eef836c06"
+ integrity sha512-3fmoMcQtCpgjTwJReFjnvIE/C7zOZeCeWUn4JKDqz9s1ILYsC3Rk5zZ4q66tFn6v+IQnecrKT52wH6+hlVLwTA==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/form" "^3.0.5"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/radio" "^3.10.4"
+ "@react-types/radio" "^3.8.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/selection@3.18.1", "@react-aria/selection@^3.18.1":
+ version "3.18.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.18.1.tgz#fd6a10a86be187ac2a591cbbc1f41c3aa0c09f7f"
+ integrity sha512-GSqN2jX6lh7v+ldqhVjAXDcrWS3N4IsKXxO6L6Ygsye86Q9q9Mq9twWDWWu5IjHD6LoVZLUBCMO+ENGbOkyqeQ==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/selection" "^3.15.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/slider@3.7.8":
+ version "3.7.8"
+ resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.7.8.tgz#6f2109527e0ebfaa1aaf46fce2460549d5550e1b"
+ integrity sha512-MYvPcM0K8jxEJJicUK2+WxUkBIM/mquBxOTOSSIL3CszA80nXIGVnLlCUnQV3LOUzpWtabbWaZokSPtGgOgQOw==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/slider" "^3.5.4"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/slider" "^3.7.3"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/spinbutton@^3.6.5":
+ version "3.6.5"
+ resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.5.tgz#77a69c26dfc74381bc1f112835eb59c572d659dd"
+ integrity sha512-0aACBarF/Xr/7ixzjVBTQ0NBwwwsoGkf5v6AVFVMTC0uYMXHTALvRs+ULHjHMa5e/cX/aPlEvaVT7jfSs+Xy9Q==
+ dependencies:
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/live-announcer" "^3.3.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/button" "^3.9.4"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/ssr@3.9.4", "@react-aria/ssr@^3.9.4":
+ version "3.9.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.4.tgz#9da8b10342c156e816dbfa4c9e713b21f274d7ab"
+ integrity sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/switch@3.6.4":
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.6.4.tgz#6dba901414785de23ee2f4873ea5e23973fdf58d"
+ integrity sha512-2nVqz4ZuJyof47IpGSt3oZRmp+EdS8wzeDYgf42WHQXrx4uEOk1mdLJ20+NnsYhj/2NHZsvXVrjBeKMjlMs+0w==
+ dependencies:
+ "@react-aria/toggle" "^3.10.4"
+ "@react-stately/toggle" "^3.7.4"
+ "@react-types/switch" "^3.5.3"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/table@3.14.1":
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.14.1.tgz#6316349e17fe6adfe9132aab75ce72c4a44c028f"
+ integrity sha512-WaPgQe4zQF5OaluO5rm+Y2nEoFR63vsLd4BT4yjK1uaFhKhDY2Zk+1SCVQvBLLKS4WK9dhP05nrNzT0vp/ZPOw==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/grid" "^3.9.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/live-announcer" "^3.3.4"
+ "@react-aria/utils" "^3.24.1"
+ "@react-aria/visually-hidden" "^3.8.12"
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/flags" "^3.0.3"
+ "@react-stately/table" "^3.11.8"
+ "@react-stately/virtualizer" "^3.7.1"
+ "@react-types/checkbox" "^3.8.1"
+ "@react-types/grid" "^3.2.6"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/table" "^3.9.5"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/tabs@3.9.1":
+ version "3.9.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.9.1.tgz#3cfb44648de1f896499d210b80deb1ead8ec4295"
+ integrity sha512-S5v/0sRcOaSXaJYZuuy1ZVzYc7JD4sDyseG1133GjyuNjJOFHgoWMb+b4uxNIJbZxnLgynn/ZDBZSO+qU+fIxw==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/i18n" "^3.11.1"
+ "@react-aria/selection" "^3.18.1"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/tabs" "^3.6.6"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/tabs" "^3.3.7"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/textfield@3.14.5", "@react-aria/textfield@^3.14.5":
+ version "3.14.5"
+ resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.14.5.tgz#afb46b4af019dc88fc7f77396cea5ec0c9701f01"
+ integrity sha512-hj7H+66BjB1iTKKaFXwSZBZg88YT+wZboEXZ0DNdQB2ytzoz/g045wBItUuNi4ZjXI3P+0AOZznVMYadWBAmiA==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/form" "^3.0.5"
+ "@react-aria/label" "^3.7.8"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/textfield" "^3.9.3"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/toggle@^3.10.4":
+ version "3.10.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.10.4.tgz#a3673ead72c389381c6217b5bed7269300351a8e"
+ integrity sha512-bRk+CdB8QzrSyGNjENXiTWxfzYKRw753iwQXsEAU7agPCUdB8cZJyrhbaUoD0rwczzTp2zDbZ9rRbUPdsBE2YQ==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/toggle" "^3.7.4"
+ "@react-types/checkbox" "^3.8.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/tooltip@3.7.4":
+ version "3.7.4"
+ resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.7.4.tgz#0efe8b4cc543a39395e99861ad6f0c64cd746026"
+ integrity sha512-+XRx4HlLYqWY3fB8Z60bQi/rbWDIGlFUtXYbtoa1J+EyRWfhpvsYImP8qeeNO/vgjUtDy1j9oKa8p6App9mBMQ==
+ dependencies:
+ "@react-aria/focus" "^3.17.1"
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-stately/tooltip" "^3.4.9"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/tooltip" "^3.4.9"
+ "@swc/helpers" "^0.5.0"
+
+"@react-aria/utils@3.24.1", "@react-aria/utils@^3.24.1":
+ version "3.24.1"
+ resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.24.1.tgz#9d16023f07c23c41793c9030a9bd203a9c8cf0a7"
+ integrity sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==
+ dependencies:
+ "@react-aria/ssr" "^3.9.4"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+ clsx "^2.0.0"
+
+"@react-aria/visually-hidden@3.8.12", "@react-aria/visually-hidden@^3.8.12":
+ version "3.8.12"
+ resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.12.tgz#89388b4773b8fbea4b5f9682e807510c14218c93"
+ integrity sha512-Bawm+2Cmw3Xrlr7ARzl2RLtKh0lNUdJ0eNqzWcyx4c0VHUAWtThmH5l+HRqFUGzzutFZVo89SAy40BAbd0gjVw==
+ dependencies:
+ "@react-aria/interactions" "^3.21.3"
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/calendar@3.5.1", "@react-stately/calendar@^3.5.1":
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.5.1.tgz#3e865d69675ba78f56e7abfadff0ef667f438a69"
+ integrity sha512-7l7QhqGUJ5AzWHfvZzbTe3J4t72Ht5BmhW4hlVI7flQXtfrmYkVtl3ZdytEZkkHmWGYZRW9b4IQTQGZxhtlElA==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/calendar" "^3.4.6"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/checkbox@3.6.5", "@react-stately/checkbox@^3.6.5":
+ version "3.6.5"
+ resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.6.5.tgz#0566eae3ba3a84af6f29526b3feaf124d3c3a66b"
+ integrity sha512-IXV3f9k+LtmfQLE+DKIN41Q5QB/YBLDCB1YVx5PEdRp52S9+EACD5683rjVm8NVRDwjMi2SP6RnFRk7fVb5Azg==
+ dependencies:
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/checkbox" "^3.8.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/collections@3.10.7", "@react-stately/collections@^3.10.7":
+ version "3.10.7"
+ resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.10.7.tgz#b1add46cb8e2f2a0d33938ef1b232fb2d0fd11eb"
+ integrity sha512-KRo5O2MWVL8n3aiqb+XR3vP6akmHLhLWYZEmPKjIv0ghQaEebBTrN3wiEjtd6dzllv0QqcWvDLM1LntNfJ2TsA==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/combobox@3.8.4", "@react-stately/combobox@^3.8.4":
+ version "3.8.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.8.4.tgz#6540ec4d53af210e6f3a769ba3f2615a55380984"
+ integrity sha512-iLVGvKRRz0TeJXZhZyK783hveHpYA6xovOSdzSD+WGYpiPXo1QrcrNoH3AE0Z2sHtorU+8nc0j58vh5PB+m2AA==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/list" "^3.10.5"
+ "@react-stately/overlays" "^3.6.7"
+ "@react-stately/select" "^3.6.4"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/combobox" "^3.11.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/datepicker@3.9.4", "@react-stately/datepicker@^3.9.4":
+ version "3.9.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.9.4.tgz#c9862cdc09da72760ed3005169223c7743b44b2d"
+ integrity sha512-yBdX01jn6gq4NIVvHIqdjBUPo+WN8Bujc4OnPw+ZnfA4jI0eIgq04pfZ84cp1LVXW0IB0VaCu1AlQ/kvtZjfGA==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@internationalized/string" "^3.2.3"
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/overlays" "^3.6.7"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/datepicker" "^3.7.4"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/flags@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.0.3.tgz#53a58c0140d61575787127a762b7901b4a7fa896"
+ integrity sha512-/ha7XFA0RZTQsbzSPwu3KkbNMgbvuM0GuMTYLTBWpgBrovBNTM+QqI/PfZTdHg8PwCYF4H5Y8gjdSpdulCvJFw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/form@3.0.3", "@react-stately/form@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.0.3.tgz#9894f9b219cc4cfbbde814d43d3f897bc43b25b3"
+ integrity sha512-92YYBvlHEWUGUpXgIaQ48J50jU9XrxfjYIN8BTvvhBHdD63oWgm8DzQnyT/NIAMzdLnhkg7vP+fjG8LjHeyIAg==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/grid@^3.8.7":
+ version "3.8.7"
+ resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.8.7.tgz#5c8aa22c83c0cb1146edad716c218739768e72ca"
+ integrity sha512-he3TXCLAhF5C5z1/G4ySzcwyt7PEiWcVIupxebJQqRyFrNWemSuv+7tolnStmG8maMVIyV3P/3j4eRBbdSlOIg==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/selection" "^3.15.1"
+ "@react-types/grid" "^3.2.6"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/list@3.10.5", "@react-stately/list@^3.10.5":
+ version "3.10.5"
+ resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.10.5.tgz#b68ebd595b5f4a51d6719cdcabd34f0780e95b85"
+ integrity sha512-fV9plO+6QDHiewsYIhboxcDhF17GO95xepC5ki0bKXo44gr14g/LSo/BMmsaMnV+1BuGdBunB05bO4QOIaigXA==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/selection" "^3.15.1"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/menu@3.7.1", "@react-stately/menu@^3.7.1":
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.7.1.tgz#af3c259c519de036d9e80d7d8370278c7b042c6a"
+ integrity sha512-mX1w9HHzt+xal1WIT2xGrTQsoLvDwuB2R1Er1MBABs//MsJzccycatcgV/J/28m6tO5M9iuFQQvLV+i1dCtodg==
+ dependencies:
+ "@react-stately/overlays" "^3.6.7"
+ "@react-types/menu" "^3.9.9"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/overlays@3.6.7", "@react-stately/overlays@^3.6.7":
+ version "3.6.7"
+ resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.7.tgz#d4aa1b709e6e72306c33308bb031466730dd0480"
+ integrity sha512-6zp8v/iNUm6YQap0loaFx6PlvN8C0DgWHNlrlzMtMmNuvjhjR0wYXVaTfNoUZBWj25tlDM81ukXOjpRXg9rLrw==
+ dependencies:
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/overlays" "^3.8.7"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/radio@3.10.4", "@react-stately/radio@^3.10.4":
+ version "3.10.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.10.4.tgz#499ef1e781a47b5ac89b3af571fc61054327f55b"
+ integrity sha512-kCIc7tAl4L7Hu4Wt9l2jaa+MzYmAJm0qmC8G8yPMbExpWbLRu6J8Un80GZu+JxvzgDlqDyrVvyv9zFifwH/NkQ==
+ dependencies:
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/radio" "^3.8.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/select@^3.6.4":
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.6.4.tgz#efd512c94545309e2373ea2f17cd97c8a1803321"
+ integrity sha512-whZgF1N53D0/dS8tOFdrswB0alsk5Q5620HC3z+5f2Hpi8gwgAZ8TYa+2IcmMYRiT+bxVuvEc/NirU9yPmqGbA==
+ dependencies:
+ "@react-stately/form" "^3.0.3"
+ "@react-stately/list" "^3.10.5"
+ "@react-stately/overlays" "^3.6.7"
+ "@react-types/select" "^3.9.4"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/selection@^3.15.1":
+ version "3.15.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.15.1.tgz#853af4958e7eb02d75487c878460338bbec3f548"
+ integrity sha512-6TQnN9L0UY9w19B7xzb1P6mbUVBtW840Cw1SjgNXCB3NPaCf59SwqClYzoj8O2ZFzMe8F/nUJtfU1NS65/OLlw==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/slider@3.5.4", "@react-stately/slider@^3.5.4":
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.5.4.tgz#f8c1b5133769380348fa1e8a7a513ebbd88a8355"
+ integrity sha512-Jsf7K17dr93lkNKL9ij8HUcoM1sPbq8TvmibD6DhrK9If2lje+OOL8y4n4qreUnfMT56HCAeS9wCO3fg3eMyrw==
+ dependencies:
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/slider" "^3.7.3"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/table@3.11.8", "@react-stately/table@^3.11.8":
+ version "3.11.8"
+ resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.11.8.tgz#b5323b095be8937761b9c5598f38623089047cf8"
+ integrity sha512-EdyRW3lT1/kAVDp5FkEIi1BQ7tvmD2YgniGdLuW/l9LADo0T+oxZqruv60qpUS6sQap+59Riaxl91ClDxrJnpg==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/flags" "^3.0.3"
+ "@react-stately/grid" "^3.8.7"
+ "@react-stately/selection" "^3.15.1"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/grid" "^3.2.6"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/table" "^3.9.5"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/tabs@3.6.6", "@react-stately/tabs@^3.6.6":
+ version "3.6.6"
+ resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.6.6.tgz#69f4a042406cbe284ffe4c56d3bc8d57cad693fe"
+ integrity sha512-sOLxorH2uqjAA+v1ppkMCc2YyjgqvSGeBDgtR/lyPSDd4CVMoTExszROX2dqG0c8il9RQvzFuufUtQWMY6PgSA==
+ dependencies:
+ "@react-stately/list" "^3.10.5"
+ "@react-types/shared" "^3.23.1"
+ "@react-types/tabs" "^3.3.7"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/toggle@3.7.4", "@react-stately/toggle@^3.7.4":
+ version "3.7.4"
+ resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.7.4.tgz#3345b5c939db96305af7c22b73577db5536220ab"
+ integrity sha512-CoYFe9WrhLkDP4HGDpJYQKwfiYCRBAeoBQHv+JWl5eyK61S8xSwoHsveYuEZ3bowx71zyCnNAqWRrmNOxJ4CKA==
+ dependencies:
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/checkbox" "^3.8.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/tooltip@3.4.9", "@react-stately/tooltip@^3.4.9":
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.4.9.tgz#a6161db77bd5ad606caa1a302622f92bc381b4ac"
+ integrity sha512-P7CDJsdoKarz32qFwf3VNS01lyC+63gXpDZG31pUu+EO5BeQd4WKN/AH1Beuswpr4GWzxzFc1aXQgERFGVzraA==
+ dependencies:
+ "@react-stately/overlays" "^3.6.7"
+ "@react-types/tooltip" "^3.4.9"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/tree@3.8.1", "@react-stately/tree@^3.8.1":
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.8.1.tgz#a3ea36d503a0276a860842cc8bf7c759aa7fa75f"
+ integrity sha512-LOdkkruJWch3W89h4B/bXhfr0t0t1aRfEp+IMrrwdRAl23NaPqwl5ILHs4Xu5XDHqqhg8co73pHrJwUyiTWEjw==
+ dependencies:
+ "@react-stately/collections" "^3.10.7"
+ "@react-stately/selection" "^3.15.1"
+ "@react-stately/utils" "^3.10.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/utils@3.10.1", "@react-stately/utils@^3.10.1":
+ version "3.10.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.1.tgz#dc8685b4994bef0dc10c37b024074be8afbfba62"
+ integrity sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@react-stately/virtualizer@3.7.1", "@react-stately/virtualizer@^3.7.1":
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-3.7.1.tgz#eb962d2ce700c026ce1b1d901034601db9d370c0"
+ integrity sha512-voHgE6EQ+oZaLv6u2umKxakvIKNkCQuUihqKACTjdslp7SJh4Mvs3oLBI0hf0JOh+rCcFIKDvQtFwy1fXFRYBA==
+ dependencies:
+ "@react-aria/utils" "^3.24.1"
+ "@react-types/shared" "^3.23.1"
+ "@swc/helpers" "^0.5.0"
+
+"@react-types/accordion@3.0.0-alpha.21":
+ version "3.0.0-alpha.21"
+ resolved "https://registry.yarnpkg.com/@react-types/accordion/-/accordion-3.0.0-alpha.21.tgz#5e8d94c9627a0b188a21adb0cf71d180173b08ea"
+ integrity sha512-cbE06jH/ZoI+1898xd7ocQ/A/Rtkz8wTJAVOYgc8VRY1SYNQ/XZTGH5T6dD6aERAmiDwL/kjD7xhsE80DyaEKA==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/breadcrumbs@3.7.5", "@react-types/breadcrumbs@^3.7.5":
+ version "3.7.5"
+ resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.5.tgz#72bc6e8881446864d7bf786f4667a2fbdda279f8"
+ integrity sha512-lV9IDYsMiu2TgdMIjEmsOE0YWwjb3jhUNK1DCZZfq6uWuiHLgyx2EncazJBUWSjHJ4ta32j7xTuXch+8Ai6u/A==
+ dependencies:
+ "@react-types/link" "^3.5.5"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/button@3.9.4", "@react-types/button@^3.9.4":
+ version "3.9.4"
+ resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.9.4.tgz#ec10452e870660d31db1994f6fe4abfe0c800814"
+ integrity sha512-raeQBJUxBp0axNF74TXB8/H50GY8Q3eV6cEKMbZFP1+Dzr09Ngv0tJBeW0ewAxAguNH5DRoMUAUGIXtSXskVdA==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/calendar@3.4.6", "@react-types/calendar@^3.4.6":
+ version "3.4.6"
+ resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.4.6.tgz#66ddcefc3058492b3cce58a6e63b01558048b669"
+ integrity sha512-WSntZPwtvsIYWvBQRAPvuCn55UTJBZroTvX0vQvWykJRQnPAI20G1hMQ3dNsnAL+gLZUYxBXn66vphmjUuSYew==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/checkbox@3.8.1", "@react-types/checkbox@^3.8.1":
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.8.1.tgz#de82c93542b2dd85c01df2e0c85c33a2e6349d14"
+ integrity sha512-5/oVByPw4MbR/8QSdHCaalmyWC71H/QGgd4aduTJSaNi825o+v/hsN2/CH7Fq9atkLKsC8fvKD00Bj2VGaKriQ==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/combobox@3.11.1", "@react-types/combobox@^3.11.1":
+ version "3.11.1"
+ resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.11.1.tgz#d5ab2f3c12d01083a3fc7c6ed90b9a2ae9049aa0"
+ integrity sha512-UNc3OHt5cUt5gCTHqhQIqhaWwKCpaNciD8R7eQazmHiA9fq8ROlV+7l3gdNgdhJbTf5Bu/V5ISnN7Y1xwL3zqQ==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/datepicker@3.7.4", "@react-types/datepicker@^3.7.4":
+ version "3.7.4"
+ resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.7.4.tgz#8b21df1041d7e51198621984920ac290b2f09744"
+ integrity sha512-ZfvgscvNzBJpYyVWg3nstJtA/VlWLwErwSkd1ivZYam859N30w8yH+4qoYLa6FzWLCFlrsRHyvtxlEM7lUAt5A==
+ dependencies:
+ "@internationalized/date" "^3.5.4"
+ "@react-types/calendar" "^3.4.6"
+ "@react-types/overlays" "^3.8.7"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/dialog@^3.5.10":
+ version "3.5.10"
+ resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.10.tgz#c0fe93c432581eb032c28632733ea80ae242b2c3"
+ integrity sha512-S9ga+edOLNLZw7/zVOnZdT5T40etpzUYBXEKdFPbxyPYnERvRxJAsC1/ASuBU9fQAXMRgLZzADWV+wJoGS/X9g==
+ dependencies:
+ "@react-types/overlays" "^3.8.7"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/grid@3.2.6", "@react-types/grid@^3.2.6":
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.2.6.tgz#c0aba4a748d1722bafe85acf87f8d9d5134653b3"
+ integrity sha512-XfHenL2jEBUYrhKiPdeM24mbLRXUn79wVzzMhrNYh24nBwhsPPpxF+gjFddT3Cy8dt6tRInfT6pMEu9nsXwaHw==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/link@3.5.5", "@react-types/link@^3.5.5":
+ version "3.5.5"
+ resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.5.5.tgz#5ed829aa32f226fe62efb0d906b1926c110daf02"
+ integrity sha512-G6P5WagHDR87npN7sEuC5IIgL1GsoY4WFWKO4734i2CXRYx24G9P0Su3AX4GA3qpspz8sK1AWkaCzBMmvnunfw==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/listbox@^3.4.9":
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.4.9.tgz#92e9990f480b48c1849ffd57ad8f95f5e278df66"
+ integrity sha512-S5G+WmNKUIOPZxZ4svWwWQupP3C6LmVfnf8QQmPDvwYXGzVc0WovkqUWyhhjJirFDswTXRCO9p0yaTHHIlkdwQ==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/menu@3.9.9", "@react-types/menu@^3.9.9":
+ version "3.9.9"
+ resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.9.9.tgz#d7f81f6ecad7dd04fc730b4ad5c3ca39e3c0883d"
+ integrity sha512-FamUaPVs1Fxr4KOMI0YcR2rYZHoN7ypGtgiEiJ11v/tEPjPPGgeKDxii0McCrdOkjheatLN1yd2jmMwYj6hTDg==
+ dependencies:
+ "@react-types/overlays" "^3.8.7"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/overlays@3.8.7", "@react-types/overlays@^3.8.7":
+ version "3.8.7"
+ resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.8.7.tgz#a43faf524cb3fce74acceee43898b265e8dfee05"
+ integrity sha512-zCOYvI4at2DkhVpviIClJ7bRrLXYhSg3Z3v9xymuPH3mkiuuP/dm8mUCtkyY4UhVeUTHmrQh1bzaOP00A+SSQA==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/progress@3.5.4", "@react-types/progress@^3.5.4":
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.4.tgz#22032aa0a64a3ff99fcd6e6e4f22cbc09c9725f3"
+ integrity sha512-JNc246sTjasPyx5Dp7/s0rp3Bz4qlu4LrZTulZlxWyb53WgBNL7axc26CCi+I20rWL9+c7JjhrRxnLl/1cLN5g==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/radio@3.8.1", "@react-types/radio@^3.8.1":
+ version "3.8.1"
+ resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.8.1.tgz#f12ddd21d88fa278baa8ddc237b778c70b67669f"
+ integrity sha512-bK0gio/qj1+0Ldu/3k/s9BaOZvnnRgvFtL3u5ky479+aLG5qf1CmYed3SKz8ErZ70JkpuCSrSwSCFf0t1IHovw==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/select@3.9.4", "@react-types/select@^3.9.4":
+ version "3.9.4"
+ resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.9.4.tgz#6283cdcb0583a87d23aa00fd118365f80fe68484"
+ integrity sha512-xI7dnOW2st91fPPcv6hdtrTdcfetYiqZuuVPZ5TRobY7Q10/Zqqe/KqtOw1zFKUj9xqNJe4Ov3xP5GSdcO60Eg==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/shared@3.22.1":
+ version "3.22.1"
+ resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.22.1.tgz#4e5de032fcb0b7bca50f6a9f8e133fd882821930"
+ integrity sha512-PCpa+Vo6BKnRMuOEzy5zAZ3/H5tnQg1e80khMhK2xys0j6ZqzkgQC+fHMNZ7VDFNLqqNMj/o0eVeSBDh2POjkw==
+
+"@react-types/shared@3.23.1", "@react-types/shared@^3.23.1":
+ version "3.23.1"
+ resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.23.1.tgz#2f23c81d819d0ef376df3cd4c944be4d6bce84c3"
+ integrity sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==
+
+"@react-types/slider@^3.7.3":
+ version "3.7.3"
+ resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.7.3.tgz#d6de0626c6977dd10faea2dba656193106ffbdb8"
+ integrity sha512-F8qFQaD2mqug2D0XeWMmjGBikiwbdERFlhFzdvNGbypPLz3AZICBKp1ZLPWdl0DMuy03G/jy6Gl4mDobl7RT2g==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/switch@^3.5.3":
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.3.tgz#2a5faaf513e03972df3077e4ff5ef21738239d7c"
+ integrity sha512-Nb6+J5MrPaFa8ZNFKGMzAsen/NNzl5UG/BbC65SLGPy7O0VDa/sUpn7dcu8V2xRpRwwIN/Oso4v63bt2sgdkgA==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/table@3.9.5", "@react-types/table@^3.9.5":
+ version "3.9.5"
+ resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.9.5.tgz#7910debd618405598583a10588a75f97c7b15eeb"
+ integrity sha512-fgM2j9F/UR4Anmd28CueghCgBwOZoCVyN8fjaIFPd2MN4gCwUUfANwxLav65gZk4BpwUXGoQdsW+X50L3555mg==
+ dependencies:
+ "@react-types/grid" "^3.2.6"
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/tabs@3.3.7", "@react-types/tabs@^3.3.7":
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.7.tgz#8bb7a65998395bad75576f5ce32c8ce61329497f"
+ integrity sha512-ZdLe5xOcFX6+/ni45Dl2jO0jFATpTnoSqj6kLIS/BYv8oh0n817OjJkLf+DS3CLfNjApJWrHqAk34xNh6nRnEg==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/textfield@3.9.3", "@react-types/textfield@^3.9.3":
+ version "3.9.3"
+ resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.9.3.tgz#23db9d87ddadc4eddff3f85406af91e442f01dc9"
+ integrity sha512-DoAY6cYOL0pJhgNGI1Rosni7g72GAt4OVr2ltEx2S9ARmFZ0DBvdhA9lL2nywcnKMf27PEJcKMXzXc10qaHsJw==
+ dependencies:
+ "@react-types/shared" "^3.23.1"
+
+"@react-types/tooltip@3.4.9", "@react-types/tooltip@^3.4.9":
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.9.tgz#fb2291bd0b915f7c7f5024ce146412405843ec9b"
+ integrity sha512-wZ+uF1+Zc43qG+cOJzioBmLUNjRa7ApdcT0LI1VvaYvH5GdfjzUJOorLX9V/vAci0XMJ50UZ+qsh79aUlw2yqg==
+ dependencies:
+ "@react-types/overlays" "^3.8.7"
+ "@react-types/shared" "^3.23.1"
+
"@swc/counter@^0.1.3":
version "0.1.3"
resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz"
@@ -155,11 +1992,30 @@
"@swc/counter" "^0.1.3"
tslib "^2.4.0"
+"@swc/helpers@^0.5.0":
+ version "0.5.11"
+ resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.11.tgz#5bab8c660a6e23c13b2d23fcd1ee44a2db1b0cb7"
+ integrity sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==
+ dependencies:
+ tslib "^2.4.0"
+
"@tootallnate/once@2":
version "2.0.0"
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
+"@types/lodash.debounce@^4.0.7":
+ version "4.0.9"
+ resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz#0f5f21c507bce7521b5e30e7a24440975ac860a5"
+ integrity sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==
+ dependencies:
+ "@types/lodash" "*"
+
+"@types/lodash@*":
+ version "4.17.6"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.6.tgz#193ced6a40c8006cfc1ca3f4553444fb38f0e543"
+ integrity sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==
+
abab@^2.0.5, abab@^2.0.6:
version "2.0.6"
resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz"
@@ -346,6 +2202,16 @@ client-only@0.0.1:
resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
+clsx@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+ integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
+clsx@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@@ -353,16 +2219,37 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
-color-name@~1.1.4:
+color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+color-string@^1.9.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
+ integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
+ dependencies:
+ color-name "^1.0.0"
+ simple-swizzle "^0.2.2"
+
color-support@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+color2k@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.3.tgz#a771244f6b6285541c82aa65ff0a0c624046e533"
+ integrity sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==
+
+color@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
+ integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
+ dependencies:
+ color-convert "^2.0.1"
+ color-string "^1.9.0"
+
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
@@ -375,6 +2262,11 @@ commander@^4.0.0:
resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+compute-scroll-into-view@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87"
+ integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==
+
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -444,6 +2336,11 @@ decompress-response@^4.2.0:
dependencies:
mimic-response "^2.0.0"
+deepmerge@4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
@@ -459,6 +2356,11 @@ detect-libc@^2.0.0:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
+detect-node-es@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
+ integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
@@ -550,6 +2452,11 @@ fill-range@^7.1.1:
dependencies:
to-regex-range "^5.0.1"
+flat@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
+ integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
+
foreground-child@^3.1.0:
version "3.2.1"
resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz"
@@ -567,6 +2474,13 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
+framer-motion@^11.2.13:
+ version "11.2.13"
+ resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.2.13.tgz#ab23fbc386233b1a1548757d840190054e5e1f1d"
+ integrity sha512-AyIeegfkXlkX1lWEudRYsJlC+0A59cE8oFK9IsN9bUQzxLwcvN3AEaYaznkELiWlHC7a0eD7pxsYQo7BC05S5A==
+ dependencies:
+ tslib "^2.4.0"
+
fs-minipass@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
@@ -604,6 +2518,11 @@ gauge@^3.0.0:
strip-ansi "^6.0.1"
wide-align "^1.1.2"
+get-nonce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
+ integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
@@ -646,6 +2565,11 @@ graceful-fs@^4.2.11:
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+hamt_plus@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/hamt_plus/-/hamt_plus-1.0.2.tgz#e21c252968c7e33b20f6a1b094cd85787a265601"
+ integrity sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==
+
has-unicode@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -702,6 +2626,28 @@ inherits@2, inherits@^2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+intl-messageformat@^10.1.0:
+ version "10.5.14"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.14.tgz#e5bb373f8a37b88fbe647d7b941f3ab2a37ed00a"
+ integrity sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.0.0"
+ "@formatjs/fast-memoize" "2.2.0"
+ "@formatjs/icu-messageformat-parser" "2.7.8"
+ tslib "^2.4.0"
+
+invariant@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
+is-arrayish@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+ integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
@@ -815,7 +2761,37 @@ lines-and-columns@^1.1.6:
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-loose-envify@^1.1.0:
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+ integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
+lodash.foreach@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
+ integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==
+
+lodash.get@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+ integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
+
+lodash.kebabcase@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
+ integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==
+
+lodash.mapkeys@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mapkeys/-/lodash.mapkeys-4.6.0.tgz#df2cfa231d7c57c7a8ad003abdad5d73d3ea5195"
+ integrity sha512-0Al+hxpYvONWtg+ZqHpa/GaVzxuN3V7Xeo2p+bY06EaK/n+Y9R7nBePPN2o1LxmL0TWQSwP8LYZ008/hc9JzhA==
+
+lodash.omit@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
+ integrity sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -1144,6 +3120,43 @@ react-dom@^18:
loose-envify "^1.1.0"
scheduler "^0.23.2"
+react-remove-scroll-bar@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c"
+ integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==
+ dependencies:
+ react-style-singleton "^2.2.1"
+ tslib "^2.0.0"
+
+react-remove-scroll@^2.5.6:
+ version "2.5.10"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.10.tgz#5fae456a23962af6d3c38ca1978bcfe0806c4061"
+ integrity sha512-m3zvBRANPBw3qxVVjEIPEQinkcwlFZ4qyomuWVpNJdv4c6MvHfXV0C3L9Jx5rr3HeBHKNRX+1jreB5QloDIJjA==
+ dependencies:
+ react-remove-scroll-bar "^2.3.6"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-style-singleton@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
+ integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==
+ dependencies:
+ get-nonce "^1.0.0"
+ invariant "^2.2.4"
+ tslib "^2.0.0"
+
+react-textarea-autosize@^8.5.3:
+ version "8.5.3"
+ resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz#d1e9fe760178413891484847d3378706052dd409"
+ integrity sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==
+ dependencies:
+ "@babel/runtime" "^7.20.13"
+ use-composed-ref "^1.3.0"
+ use-latest "^1.2.1"
+
react@^18:
version "18.3.1"
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
@@ -1174,6 +3187,18 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
+recoil@^0.7.7:
+ version "0.7.7"
+ resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.7.7.tgz#c5f2c843224384c9c09e4a62c060fb4c1454dc8e"
+ integrity sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==
+ dependencies:
+ hamt_plus "1.0.2"
+
+regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
@@ -1231,6 +3256,13 @@ scheduler@^0.23.2:
dependencies:
loose-envify "^1.1.0"
+scroll-into-view-if-needed@3.0.10:
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz#38fbfe770d490baff0fb2ba34ae3539f6ec44e13"
+ integrity sha512-t44QCeDKAPf1mtQH3fYpWz8IM/DyvHLjs8wUvvwMYxk5moOqCzrMSxK6HQVD0QVmVjXFavoFIPRVrMuJPKAvtg==
+ dependencies:
+ compute-scroll-into-view "^3.0.2"
+
semver@^6.0.0:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
@@ -1282,6 +3314,13 @@ simple-get@^3.0.3:
once "^1.3.1"
simple-concat "^1.0.0"
+simple-swizzle@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+ integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
+ dependencies:
+ is-arrayish "^0.3.1"
+
source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
@@ -1375,6 +3414,18 @@ symbol-tree@^3.2.4:
resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
+tailwind-merge@^1.14.0:
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz#e677f55d864edc6794562c63f5001f45093cdb8b"
+ integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==
+
+tailwind-variants@^0.1.20:
+ version "0.1.20"
+ resolved "https://registry.yarnpkg.com/tailwind-variants/-/tailwind-variants-0.1.20.tgz#8aaed9094be0379a438641a42d588943e44c5fcd"
+ integrity sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==
+ dependencies:
+ tailwind-merge "^1.14.0"
+
tailwindcss@^3.4.1:
version "3.4.4"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz"
@@ -1463,7 +3514,7 @@ ts-interface-checker@^0.1.9:
resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
-tslib@^2.4.0:
+tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0:
version "2.6.3"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz"
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
@@ -1481,6 +3532,38 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
+use-callback-ref@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693"
+ integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==
+ dependencies:
+ tslib "^2.0.0"
+
+use-composed-ref@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.3.0.tgz#3d8104db34b7b264030a9d916c5e94fbe280dbda"
+ integrity sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==
+
+use-isomorphic-layout-effect@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+ integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
+use-latest@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.1.tgz#d13dfb4b08c28e3e33991546a2cee53e14038cf2"
+ integrity sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==
+ dependencies:
+ use-isomorphic-layout-effect "^1.1.1"
+
+use-sidecar@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
+ integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==
+ dependencies:
+ detect-node-es "^1.1.0"
+ tslib "^2.0.0"
+
util-deprecate@^1.0.1, util-deprecate@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"