From 811c6e62db81d61007e11d738e7dc5f7cf5417e1 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 7 Mar 2025 18:37:25 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20tree=20=EA=B3=B5=ED=86=B5=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/assets/src/images/icon_file.png | Bin 0 -> 1588 bytes .../assets/src/images/icon_folder_off.png | Bin 0 -> 1835 bytes .../assets/src/images/icon_folder_on.png | Bin 0 -> 2174 bytes packages/common/assets/src/images/index.ts | 4 + packages/common/components/package.json | 3 + .../components/src/ui/tree/CustomNode.tsx | 39 +++++ .../components/src/ui/tree/TypeIcon.tsx | 19 ++ .../components/src/ui/tree/__mock__.json | 38 ++++ .../components/src/ui/tree/tree.stories.tsx | 68 ++++++++ .../common/components/src/ui/tree/types.ts | 4 + pnpm-lock.yaml | 164 +++++++++++++++++- 11 files changed, 332 insertions(+), 7 deletions(-) create mode 100644 packages/common/assets/src/images/icon_file.png create mode 100644 packages/common/assets/src/images/icon_folder_off.png create mode 100644 packages/common/assets/src/images/icon_folder_on.png create mode 100644 packages/common/components/src/ui/tree/CustomNode.tsx create mode 100644 packages/common/components/src/ui/tree/TypeIcon.tsx create mode 100644 packages/common/components/src/ui/tree/__mock__.json create mode 100644 packages/common/components/src/ui/tree/tree.stories.tsx create mode 100644 packages/common/components/src/ui/tree/types.ts diff --git a/packages/common/assets/src/images/icon_file.png b/packages/common/assets/src/images/icon_file.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d06d28729416f37ad016669e38260dfcca97fd GIT binary patch literal 1588 zcmeAS@N?(olHy`uVBq!ia0vp^DImc-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuU%v{0TQqR!T z+}y-mN5ROz&{W^RSl`${*T~q)#K6kLNC66zfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$IMft0!ZY(y z^2>`g!FqgstvvIJOA_;vQ$1a5m4K$`WoD*WIhq<<8d#VZxR@Ea85+7eS~?qAxH_4; zIXb%-8M#_G!SuT1Czs}?=9R$orXchh;?xUD4!H$Dn_W_iGRsm^+=}vZ6~NxM%Eajw zV^^H!LG`BKbc?YYPQCg-$LND17b&t~LckORV#1RykONQrsd>N@Uj$6rtnsg77#NtA zc)B=-RNQ)V*WO1sQ0BnL`@6%~QVR;1!y;2n`}p|!`mA=!9F%b8xY*L#D3Qc7QKNbG z;>F#an>R~^y9uz13wl)NzPGJ^e=6~>u=C#C`<(aPUy{lBRRQ1U#N2yvkp2 zIfDQb3ka=RkoH3T!>_yFI_(;-r>V_Q)QL3NE zuTO>OrhCL1K3VYiPjPj@!eZgxLiUGGIo-hG_Hk>q-@dPb_q0xhIymv(n6dbHr+a3)M!v{XD+R~2 zj-M}ItCVh9t#Rs;S7084(Icsg@15U0(eR7YI_2xYbZ)|)ytX9UQ{1jQc~5khf3;r} zF>!rY(p;PHDV7dy8&f1dUw{9-ZowMuQ??FFx{=LG+ckD|*@jJV1@ZPTdb4fK{`wUf z-VGt&v`)+XPA_fylHN5n)ish$<-#P>8MZDL_ojLVhB0XV^{V}$_*~YwTizr+jwpzn;=2 zlD~iQ-uXiFZ70iCi%n28;xaO}4Si*J*<|Y6x##~S#)!1oPti`5%-OK=|8{RJcH2RVAr+B4j*ARS0*T)iKetnHfAC@fdr)?0hJz0A)`o)$jLZK z`f)hpR_J2lnfUN91gG=@%!(11^+uM>;rIoZjToLrGJu9m(HZ=CcMc!r0Xo8;7bgh^ z!;MNZRTq+LBBOI7V({EFTtV;x<^Xst^0FuaLV%diP3_=niC=!Z5J}g4SAR>l=(TB%cGZ9)O z3Jo5$#oqjRsSIO8gu?9XY(ch2K$%j6kV2slg0K*V`7DA@=NK5w%s0@UV;WGB#!WgS zqoWLfRU@XMG8um!>*+`cdSiI_OT`9yG*N8Igl5brgan{aueZiEjHa0=@_#p8i>708 zjHED%q^V33&elWgIYwr4_hv&@AnOgXz@%e~f~BJro~b7dj0*MVv0ns)jzFZK6bcFq zhCm1og4mNnq?829K-oMQtdM}>pfMe<(jp3XO49 z2AaVPI5}ol$J!m`D&NROlqM2mC{qkYrH^$$WGcl_bSh;8l*-|X13qy&13_iezSa_r zM2wOqT^30MngqB26mQA?9gDjscLo>1662XjQL`Jd1y!sHofr0!ju!Dh@_~JLijb?_0ip-zGu(-xNvwhv^V+$H2 z!wQqfQP0b(*G5(b9K2pXSC$*nIJf9|Rl|y&eLYvd*uJ#$SWe}$2lBC{)z|FZpAZ{!?vO{v=@fb6%^C3pKZKGP*-`uBp*qH)=o|jdV_w+6Kslg4i+rHkuQgmrbD&b42nR>g1@$T^v z2f3M+6?vD+X7!t=ru+ zFA4}1L{}z7cH4H>b=@nBUeDO zw5r)a?nwr1J{l0j2d#v?t~Wt-u1mGPy^cF{eb;)SP!{uWs9$AY<_k?mHV!>5aR~LM z uNI*%nLm}5yP56|ItQDx5u(9;mIB?u1w{&k@+b4AqK1i{B;m+K#po)KqpUEs39GfIBgfgW$QJC z2u!PJ(zwKTq~e4d0Y0We0T!7}5>weA0CLDQ76>xIH2|GTV^OFK3WG|bGax1vV$y;4 z4-xmKLL^YMAmqI-{KO@uYBWlSLeXlqWG#b?siYJdhr^*z=@dGhglmx0SqcrTBPrD0 zGZqA>TC9>OH8M;ASS`XLEK|cJ;!NL#AXf^79}Fwh?-PZmjG}{;6dIXIk;|=dO>3() z(dhqad{kQZn=Y_og9Ko3 zFb(7jcwi8XK^M$m!xU-_tPrC!er34d_gL0nVj;c?g*BKe7Q@nKI$&ceroq&ym=fUg zrz;Mu+#*vTm{#p;Ez!G(1*l544Mjp!m>ihSF(ms42be16up}^z#1V6tBo>1SlQ=LP zC4s02kx=O{8;1Re@A1f=a`&!B@f$o2Fw0LwLj3%w zEC~x`F+eeqf>Wee+vZPgG;@Xbrd9kf6!_u8SfL7hmQ?uA%x_-%C4n&KNSGifR@Y}b zAxw3Vy8Y|aaiikl9}8=Kdd6nD`tlZKr=HPOe6>tCf8f*Z@T!zbL#*Jr&&|B(@amtl z5A6iyKU<8`8juq1z^7`ip08rk;10w%;@t zkB?5==rA@EyVc5_OY0&MX9eydESx22`saiJXhRdT*7TYgi^|*FjB4u zo>9@XlS630#m};iM;B#o)8_3z7jxul^5G7*T(@1x$**7M&Ni&vAWbUS+&<}aqgT>1 z?C#M24WWA3kqef7=R1plaAi2R;?(l8yR}aK^y^Ks&^49NNymKT$JK<=srm4%wh>lX z*X}!!$GmH#^2_%xU6t=ZT$W|}2=u|N;gtiMmPOrJJ$A3#r;48$lkfeXsU%BYa)09w zFFE#WF=fHXfm^y_V%x7fGf#K2dA~`|($=*fyKjoWlw;`1s+c%?afle;ddR4~wW#H+ zDW|WWU1@d$*jqYRv@F$A^w)%=@tZBfgw7<F$cp3#Jk(-Z(fF+uj>lKKARuKJQ^$_F-ddXxV4w{`?YYP78TXf6=a0+I4>U z3$Oi0BKBK21%t_DA^Jv9&aHt(fos1%?{EHx+qT6XbhBUk zS0f&az==*b=V66tfV_%JejCR7OTSgd7o8sL*f}8T>gXB|$~^viHoGxs-=y5((wl|C z%Pt#AU;ln|iMyt>FsVj*uCY2a;X8Hg39mh+B^lq=A2pDhFSph0c2+F^x&hg0iR(EA zQC7;mE8_XdKzQ7nV{cEjHw|Civ93wU<<6~t$M*K6R9KYpn@@&&d2=iK$WOh$%yHxSRpr?C zIte;G$A-?!_jZk4+S5|LdH$O~m!yMny`1dOZKY3gR4LSz;$uZHR zxetl@sABj1O7|2|O?=y-4i3lD=h|X>ie9wZS-U0djz`_Dt#ag!>;<*3*p{=aGOhX0 z-N&E&*QR&GD^hwZa!UF2-UprwA`kU4b^O`HCf_DsCl9R9ckt1JP_XOD&rSy8y{xT? z+iNwT>aoeNee>$U6+4ce|BW*8I@6r-OMD$Fo4ifwDDsNQeOcJ^tiJAGeQ4e|^!M^r z-4TI|?pKWi#Y(VQ|Dx(U<3G0x9bYq6^&8J4>x; + depth: number; + isOpen: boolean; + onToggle: (id: NodeModel["id"]) => void; +}; + +export const CustomNode: React.FC = (props) => { + const { droppable, id, text } = props.node; + const indent = props.depth * 24; + + const handleToggle = (e: React.MouseEvent) => { + if (!droppable) return; + e.stopPropagation(); + props.onToggle(id); + }; + + return ( +
+
+
+ +
+
+
+ {text} +
+
+ ); +}; diff --git a/packages/common/components/src/ui/tree/TypeIcon.tsx b/packages/common/components/src/ui/tree/TypeIcon.tsx new file mode 100644 index 000000000..f99a91639 --- /dev/null +++ b/packages/common/components/src/ui/tree/TypeIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { images } from "@common/assets"; + +type Props = { + droppable?: boolean; + isOpen?: boolean; +}; + +export const TypeIcon: React.FC = (props) => { + if (props.droppable) { + return ( + + ); + } + return ; +}; diff --git a/packages/common/components/src/ui/tree/__mock__.json b/packages/common/components/src/ui/tree/__mock__.json new file mode 100644 index 000000000..f86fa3ad7 --- /dev/null +++ b/packages/common/components/src/ui/tree/__mock__.json @@ -0,0 +1,38 @@ +[ + { + "id": 1, + "parent": 0, + "droppable": true, + "text": "Folder 1" + }, + { + "id": 2, + "parent": 1, + "droppable": false, + "text": "File 1-1" + }, + { + "id": 3, + "parent": 1, + "droppable": false, + "text": "File 1-2" + }, + { + "id": 4, + "parent": 0, + "droppable": true, + "text": "Folder 2" + }, + { + "id": 5, + "parent": 4, + "droppable": true, + "text": "Folder 2-1" + }, + { + "id": 6, + "parent": 5, + "droppable": false, + "text": "File 2-1-1" + } +] diff --git a/packages/common/components/src/ui/tree/tree.stories.tsx b/packages/common/components/src/ui/tree/tree.stories.tsx new file mode 100644 index 000000000..6678f756b --- /dev/null +++ b/packages/common/components/src/ui/tree/tree.stories.tsx @@ -0,0 +1,68 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { useState } from "react"; +import { DndProvider } from "react-dnd"; +import { + Tree, + MultiBackend, + getBackendOptions, + type NodeModel, +} from "@minoru/react-dnd-treeview"; +import { type CustomData } from "./types"; +import { CustomNode } from "./CustomNode"; +import SampleData from "./__mock__.json"; + +const meta: Meta = { + title: "UI/Tree", + component: Tree, + parameters: { + docs: { + description: { + component: ` +- [Docs](https://github.com/minop1205/react-dnd-treeview/blob/next/README.md) + `, + }, + }, + }, +}; +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => , +}; + +function TreeView() { + const [treeData, setTreeData] = useState[]>(SampleData); + const handleDrop = (newTree: NodeModel[]) => setTreeData(newTree); + + return ( + +
+ + tree={treeData} + rootId={0} + render={( + node: NodeModel, + { depth, isOpen, onToggle }, + ) => ( + + )} + onDrop={handleDrop} + classes={{ + root: "", + container: "flex flex-col", + listItem: "", + dropTarget: "bg-primary rounded-sm", + draggingSource: "", + placeholder: "", + }} + /> +
+
+ ); +} diff --git a/packages/common/components/src/ui/tree/types.ts b/packages/common/components/src/ui/tree/types.ts new file mode 100644 index 000000000..36cfd322b --- /dev/null +++ b/packages/common/components/src/ui/tree/types.ts @@ -0,0 +1,4 @@ +export type CustomData = { + fileType: string; + fileSize: string; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e72143d63..762d9fae0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,6 +121,9 @@ importers: '@common/assets': specifier: workspace:* version: link:../assets + '@minoru/react-dnd-treeview': + specifier: ^3.5.0 + version: 3.5.0(dnd-core@16.0.1)(react-dnd@16.0.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-accordion': specifier: ^1.2.3 version: 1.2.3(@types/react-dom@18.3.5)(@types/react@18.3.18)(react-dom@18.3.1)(react@18.3.1) @@ -184,6 +187,12 @@ importers: react-day-picker: specifier: ^8.10.1 version: 8.10.1(date-fns@3.6.0)(react@18.3.1) + react-dnd: + specifier: ^16.0.1 + version: 16.0.1(@types/node@22.13.5)(@types/react@18.3.18)(react@18.3.1) + react-dnd-html5-backend: + specifier: ^16.0.1 + version: 16.0.1 tailwind-merge: specifier: ^3.0.1 version: 3.0.2 @@ -228,7 +237,7 @@ importers: specifier: ^8.5.5 version: 8.6.0(storybook@8.6.0) '@types/node': - specifier: ^22.13.5 + specifier: ^22.13.1 version: 22.13.5 '@vitejs/plugin-react': specifier: ^4.3.4 @@ -457,7 +466,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: true /@babel/template@7.26.9: resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} @@ -1360,6 +1368,10 @@ packages: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + /@juggle/resize-observer@3.4.0: + resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==} + dev: false + /@kurkle/color@0.3.4: resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} dev: false @@ -1375,6 +1387,27 @@ packages: react: 18.3.1 dev: true + /@minoru/react-dnd-treeview@3.5.0(dnd-core@16.0.1)(react-dnd@16.0.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-kDHGQ0UK18w6ie5EH68NynATSP9BAzNLmWBXuVSoaGkraWWFdEdAWqQxAZiMorAixFu40MzYkn2N9/Gam6q17w==} + peerDependencies: + react: ^18.3.1 + react-dnd: 15.x || 16.x + react-dom: ^18.3.1 + dependencies: + '@juggle/resize-observer': 3.4.0 + dnd-multi-backend: 8.1.2(dnd-core@16.0.1) + framer-motion: 11.18.2(react-dom@18.3.1)(react@18.3.1) + react: 18.3.1 + react-dnd: 16.0.1(@types/node@22.13.5)(@types/react@18.3.18)(react@18.3.1) + react-dnd-html5-backend: 16.0.1 + react-dnd-touch-backend: 16.0.1 + react-dom: 18.3.1(react@18.3.1) + react-use-measure: 2.1.7(react-dom@18.3.1)(react@18.3.1) + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - dnd-core + dev: false + /@next/env@15.1.7: resolution: {integrity: sha512-d9jnRrkuOH7Mhi+LHav2XW91HOgTAWHxjMPkXMGBc9B2b7614P7kjt8tAplRvJpbSt4nbO1lugcT/kAaWzjlLQ==} dev: false @@ -2225,6 +2258,18 @@ packages: resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} dev: false + /@react-dnd/asap@5.0.2: + resolution: {integrity: sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==} + dev: false + + /@react-dnd/invariant@4.0.2: + resolution: {integrity: sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==} + dev: false + + /@react-dnd/shallowequal@4.0.2: + resolution: {integrity: sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==} + dev: false + /@rollup/pluginutils@5.1.4: resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} engines: {node: '>=14.0.0'} @@ -2928,7 +2973,6 @@ packages: resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} dependencies: undici-types: 6.20.0 - dev: true /@types/node@22.13.9: resolution: {integrity: sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==} @@ -4098,6 +4142,22 @@ packages: /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + /dnd-core@16.0.1: + resolution: {integrity: sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==} + dependencies: + '@react-dnd/asap': 5.0.2 + '@react-dnd/invariant': 4.0.2 + redux: 4.2.1 + dev: false + + /dnd-multi-backend@8.1.2(dnd-core@16.0.1): + resolution: {integrity: sha512-KPDVEsiM+6gNEegqZYTWJQgJxYV4vB91tUrvoKJjaS0wwWqT/jNU0P7xJAwCue/cbasJNvk2dFZH7tC+bjX1Rg==} + peerDependencies: + dnd-core: ^16.0.1 + dependencies: + dnd-core: 16.0.1 + dev: false + /doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -4745,7 +4805,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-glob@3.3.1: resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} @@ -4872,6 +4931,27 @@ packages: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true + /framer-motion@11.18.2(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.3.1 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + dependencies: + motion-dom: 11.18.1 + motion-utils: 11.18.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.8.1 + dev: false + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -5083,6 +5163,12 @@ packages: dependencies: function-bind: 1.1.2 + /hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + dependencies: + react-is: 16.13.1 + dev: false + /ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -5653,6 +5739,16 @@ packages: node-source-walk: 7.0.1 dev: true + /motion-dom@11.18.1: + resolution: {integrity: sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==} + dependencies: + motion-utils: 11.18.1 + dev: false + + /motion-utils@11.18.1: + resolution: {integrity: sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==} + dev: false + /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true @@ -6216,6 +6312,44 @@ packages: react: 18.3.1 dev: false + /react-dnd-html5-backend@16.0.1: + resolution: {integrity: sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==} + dependencies: + dnd-core: 16.0.1 + dev: false + + /react-dnd-touch-backend@16.0.1: + resolution: {integrity: sha512-NonoCABzzjyWGZuDxSG77dbgMZ2Wad7eQiCd/ECtsR2/NBLTjGksPUx9UPezZ1nQ/L7iD130Tz3RUshL/ClKLA==} + dependencies: + '@react-dnd/invariant': 4.0.2 + dnd-core: 16.0.1 + dev: false + + /react-dnd@16.0.1(@types/node@22.13.5)(@types/react@18.3.18)(react@18.3.1): + resolution: {integrity: sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==} + peerDependencies: + '@types/hoist-non-react-statics': '>= 3.3.1' + '@types/node': '>= 12' + '@types/react': ^18.3.18 + react: ^18.3.1 + peerDependenciesMeta: + '@types/hoist-non-react-statics': + optional: true + '@types/node': + optional: true + '@types/react': + optional: true + dependencies: + '@react-dnd/invariant': 4.0.2 + '@react-dnd/shallowequal': 4.0.2 + '@types/node': 22.13.5 + '@types/react': 18.3.18 + dnd-core: 16.0.1 + fast-deep-equal: 3.1.3 + hoist-non-react-statics: 3.3.2 + react: 18.3.1 + dev: false + /react-docgen-typescript@2.2.2(typescript@5.6.3): resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} peerDependencies: @@ -6253,7 +6387,6 @@ packages: /react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true /react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -6315,6 +6448,19 @@ packages: tslib: 2.8.1 dev: false + /react-use-measure@2.1.7(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} + peerDependencies: + react: ^18.3.1 + react-dom: ^18.3.1 + peerDependenciesMeta: + react-dom: + optional: true + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -6356,6 +6502,12 @@ packages: strip-indent: 3.0.0 dev: true + /redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + dependencies: + '@babel/runtime': 7.26.9 + dev: false + /reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -6372,7 +6524,6 @@ packages: /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true /regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} @@ -7305,7 +7456,6 @@ packages: /undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - dev: true /unicorn-magic@0.3.0: resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}