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 -``` +![type1](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6+-+type1.png) -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. +![type2](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-+type2.png) -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 +![type3](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type3.png) -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. +![type4](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type4.png) 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 ( + <> + +
+ + + DATE + NAME + CONTENTS + + + + 2024.07.17 + SWYOO + ` * README.md 파일 이미지 경로 수정 ` + + + 2024.07.16 + SWYOO + ` * 버튼 정리(템플릿 적용) ` + + +
+
+ + ) +} diff --git a/src/app/globals.css b/src/app/globals.css index 3f9ae906..1c95a542 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -31,3 +31,9 @@ body { text-wrap: balance; } } */ + +.archivo-black-regular { + font-family: 'Archivo Black', sans-serif; + font-weight: 400; + font-style: normal; +} diff --git a/src/app/layout.js b/src/app/layout.js index 663a8562..55cb11f3 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,6 +1,9 @@ import { Inter } from 'next/font/google' import './globals.css' import Headers from '@/components/Headers' +import RecoilRootWrapper from './RecoilWrapper' +import UIProvider from './UIProvider' +import { headers } from 'next/headers' const inter = Inter({ subsets: ['latin'] }) @@ -10,11 +13,17 @@ export const metadata = { } export default function RootLayout({ children }) { + const headersList = headers() + const headerPathname = headersList.get('x-pathname') || '' + // console.log('headerPathname', headerPathname) + return ( - - {children} + {headerPathname !== '/login' && } + + {children} + ) diff --git a/src/app/login/page.jsx b/src/app/login/page.jsx new file mode 100644 index 00000000..c5d063fd --- /dev/null +++ b/src/app/login/page.jsx @@ -0,0 +1,91 @@ +export default function page() { + return ( + <> +
+
+
+ Your Company +

+ Sign in to your account +

+
+ +
+
+
+ +
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+ +
+
+ +

+ Not a member?{' '} + + Start a 14 day free trial + +

+
+
+
+ + ) +} diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx new file mode 100644 index 00000000..8c83730e --- /dev/null +++ b/src/app/roof2/page.jsx @@ -0,0 +1,23 @@ +'use client' + +import Hero from '@/components/Hero' +import Roof2 from '@/components/Roof2' +import { textState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { useRecoilState } from 'recoil' + +export default function Roof2Page() { + const [text, setText] = useRecoilState(textState) + + useEffect(() => { + console.log(text) + }, []) + + return ( + <> +
+ +
+ + ) +} diff --git a/src/app/util/canvas-util.js b/src/app/util/canvas-util.js deleted file mode 100644 index 493cb3c6..00000000 --- a/src/app/util/canvas-util.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * 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 - } -} - -export const getDistance = (x1, y1, x2, y2) => { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) -} -// 선의 길이를 계산하는 함수 -export const calculateLineLength = (x1, y1, x2, y2) => { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) -} - -// 선과 텍스트를 그룹으로 묶는 함수 -export const createGroupWithLineAndText = (line, text) => { - return new fabric.Group([line, text]) -} - -export const calculateShapeLength = (shape) => { - // 도형의 원래 길이를 가져옵니다. - const originalLength = shape.width - - // 도형의 scaleX 값을 가져옵니다. - const scaleX = shape.scaleX - - // 도형의 현재 길이를 계산합니다. - return originalLength * scaleX -} - -/** - * - * @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}` -} diff --git a/src/components/Headers.jsx b/src/components/Headers.jsx index c16bd077..12d36144 100644 --- a/src/components/Headers.jsx +++ b/src/components/Headers.jsx @@ -9,7 +9,9 @@ export default function Headers() {
Intro + Changelog Roof + Roof2
diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx index eeb05c67..c7ac519f 100644 --- a/src/components/Hero.jsx +++ b/src/components/Hero.jsx @@ -1,7 +1,7 @@ export default function Hero(props) { return (
-

{props.title}

+

{props.title}

) } diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx index 73562bf5..9fd3aed2 100644 --- a/src/components/Roof.jsx +++ b/src/components/Roof.jsx @@ -1,7 +1,8 @@ -import { createGroupWithLineAndText, getDistance } from '@/app/util/canvas-util' +import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util' import { useCanvas } from '@/hooks/useCanvas' import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' +import { useEffect } from 'react' export default function Roof() { const { @@ -18,9 +19,88 @@ export default function Roof() { attachCustomControlOnPolygon, saveImage, handleFlip, - updateTextOnLineChange, } = useCanvas('canvas') + useEffect(() => { + let circle = new fabric.Circle({ + radius: 40, + fill: 'rgba(200, 0, 0, 0.3)', + originX: 'center', + originY: 'center', + }) + + let text = new fabric.Textbox('AJLoveChina', { + originX: 'center', + originY: 'center', + textAlign: 'center', + fontSize: 12, + }) + + let group = new fabric.Group([circle, text], { + left: 100, + top: 100, + originX: 'center', + originY: 'center', + }) + + group.on('mousedblclick', () => { + // textForEditing is temporary obj, + // and will be removed after editing + console.log(text.type) + let textForEditing = new fabric.Textbox(text.text, { + originX: 'center', + originY: 'center', + textAlign: text.textAlign, + fontSize: text.fontSize, + + left: group.left, + top: group.top, + }) + + // hide group inside text + text.visible = false + // note important, text cannot be hidden without this + group.addWithUpdate() + + textForEditing.visible = true + // do not give controls, do not allow move/resize/rotation on this + textForEditing.hasConstrols = false + + // now add this temporary obj to canvas + canvas.add(textForEditing) + canvas.setActiveObject(textForEditing) + // make the cursor showing + textForEditing.enterEditing() + textForEditing.selectAll() + + // editing:exited means you click outside of the textForEditing + textForEditing.on('editing:exited', () => { + let newVal = textForEditing.text + let oldVal = text.text + + // then we check if text is changed + if (newVal !== oldVal) { + text.set({ + text: newVal, + visible: true, + }) + + // comment before, you must call this + group.addWithUpdate() + + // we do not need textForEditing anymore + textForEditing.visible = false + canvas?.remove(textForEditing) + + // optional, buf for better user experience + canvas?.setActiveObject(group) + } + }) + }) + + canvas?.add(group) + }, [canvas]) + const addRect = () => { const rect = new fabric.Rect({ height: 200, @@ -92,9 +172,9 @@ export default function Roof() { const trapezoid = new fabric.Polygon( [ { x: 100, y: 100 }, // 좌상단 - { x: 300, y: 100 }, // 우상단 - { x: 250, y: 200 }, // 우하단 - { x: 150, y: 200 }, // 좌하단 + { x: 500, y: 100 }, // 우상단 + { x: 750, y: 700 }, // 우하단 + { x: 250, y: 400 }, // 좌하단 ], { name: uuidv4(), @@ -102,35 +182,96 @@ export default function Roof() { opacity: 0.4, strokeWidth: 3, selectable: true, + objectCaching: false, }, ) attachCustomControlOnPolygon(trapezoid) - addShape(trapezoid) + const group = addDistanceTextToPolygon(trapezoid) + addGroupClickEvent(group) + canvas?.add(group) + canvas?.renderAll() } - const addTextWithLine = () => { - const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 } - /** - * 시작X,시작Y,도착X,도착Y 좌표 - */ - const horizontalLine = new fabric.Line([x1, y1, x2, y2], { - name: uuidv4(), - stroke: 'red', - strokeWidth: 3, - selectable: true, + // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수 + function addGroupClickEvent(group) { + group.on('selected', (e) => { + console.log(e) }) + group.on('mousedblclick', (e) => { + // textForEditing is temporary obj, + // and will be removed after editing + const pointer = canvas?.getPointer(e.e) // 마우스 클릭 위치 가져오기 + let minDistance = Infinity + let closestTextbox = null + const groupPoint = group.getCenterPoint() + group.getObjects().forEach(function (object) { + if (object.type === 'textbox') { + // 객체가 TextBox인지 확인 - const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), { - fontSize: 20, - left: (x2 - x1) / 2, - top: y1 - 20, + const objectCenter = object.getCenterPoint() // TextBox 객체의 중심점 가져오기 + const dx = objectCenter.x + groupPoint.x - pointer.x + const dy = objectCenter.y + groupPoint.y - pointer.y + const distance = Math.sqrt(dx * dx + dy * dy) // 마우스 클릭 위치와 TextBox 객체 사이의 거리 계산 + + if (distance < minDistance) { + // 가장 짧은 거리를 가진 TextBox 객체 찾기 + minDistance = distance + closestTextbox = object + } + } + }) + + let textForEditing = new fabric.Textbox(closestTextbox.text, { + originX: 'center', + originY: 'center', + textAlign: closestTextbox.textAlign, + fontSize: closestTextbox.fontSize, + left: closestTextbox.left + groupPoint.x, + top: closestTextbox.top + groupPoint.y, + }) + + // hide group inside text + closestTextbox.visible = false + // note important, text cannot be hidden without this + group.addWithUpdate() + + textForEditing.visible = true + // do not give controls, do not allow move/resize/rotation on this + textForEditing.hasConstrols = false + + // now add this temporary obj to canvas + canvas?.add(textForEditing) + canvas?.setActiveObject(textForEditing) + // make the cursor showing + textForEditing?.enterEditing() + textForEditing?.selectAll() + + // editing:exited means you click outside of the textForEditing + textForEditing?.on('editing:exited', () => { + let newVal = textForEditing.text + + // then we check if text is changed + closestTextbox.set({ + text: newVal, + visible: true, + }) + + // comment before, you must call this + group.addWithUpdate() + + // we do not need textForEditing anymore + textForEditing.visible = false + canvas?.remove(textForEditing) + + // optional, buf for better user experience + canvas?.setActiveObject(group) + }) }) + } - const group = createGroupWithLineAndText(horizontalLine, text) - addShape(group) - - // 선의 길이가 변경될 때마다 텍스트를 업데이트하는 이벤트 리스너를 추가합니다. - group.on('modified', () => updateTextOnLineChange(group, text)) + // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수 + function addTextModifiedEvent(text, polygon, index) { + text.on('editing:exited', function () {}) } const randomColor = () => { @@ -232,12 +373,6 @@ export default function Roof() { > 도형반전 -
{ + 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 && ( + <> +
+ + + + + + + + + + + + + + 현재 줌 : {zoom}% + + + + + + + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + )} +
+ +
+ + ) +} 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 ( + <> + + + + ) +} 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"