@mav3rick/warp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/dist/GridLayoutEngine.d.ts +56 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.es +4 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/vite.svg +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# React + TypeScript + Vite
|
|
2
|
+
|
|
3
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
+
|
|
5
|
+
Currently, two official plugins are available:
|
|
6
|
+
|
|
7
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
|
|
8
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
9
|
+
|
|
10
|
+
## React Compiler
|
|
11
|
+
|
|
12
|
+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
13
|
+
|
|
14
|
+
## Expanding the ESLint configuration
|
|
15
|
+
|
|
16
|
+
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
export default defineConfig([
|
|
20
|
+
globalIgnores(['dist']),
|
|
21
|
+
{
|
|
22
|
+
files: ['**/*.{ts,tsx}'],
|
|
23
|
+
extends: [
|
|
24
|
+
// Other configs...
|
|
25
|
+
|
|
26
|
+
// Remove tseslint.configs.recommended and replace with this
|
|
27
|
+
tseslint.configs.recommendedTypeChecked,
|
|
28
|
+
// Alternatively, use this for stricter rules
|
|
29
|
+
tseslint.configs.strictTypeChecked,
|
|
30
|
+
// Optionally, add this for stylistic rules
|
|
31
|
+
tseslint.configs.stylisticTypeChecked,
|
|
32
|
+
|
|
33
|
+
// Other configs...
|
|
34
|
+
],
|
|
35
|
+
languageOptions: {
|
|
36
|
+
parserOptions: {
|
|
37
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
38
|
+
tsconfigRootDir: import.meta.dirname,
|
|
39
|
+
},
|
|
40
|
+
// other options...
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
])
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// eslint.config.js
|
|
50
|
+
import reactX from 'eslint-plugin-react-x'
|
|
51
|
+
import reactDom from 'eslint-plugin-react-dom'
|
|
52
|
+
|
|
53
|
+
export default defineConfig([
|
|
54
|
+
globalIgnores(['dist']),
|
|
55
|
+
{
|
|
56
|
+
files: ['**/*.{ts,tsx}'],
|
|
57
|
+
extends: [
|
|
58
|
+
// Other configs...
|
|
59
|
+
// Enable lint rules for React
|
|
60
|
+
reactX.configs['recommended-typescript'],
|
|
61
|
+
// Enable lint rules for React DOM
|
|
62
|
+
reactDom.configs.recommended,
|
|
63
|
+
],
|
|
64
|
+
languageOptions: {
|
|
65
|
+
parserOptions: {
|
|
66
|
+
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
|
67
|
+
tsconfigRootDir: import.meta.dirname,
|
|
68
|
+
},
|
|
69
|
+
// other options...
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
])
|
|
73
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure layout calculation engine for dynamic grid
|
|
3
|
+
* Separated from React components for testability and reusability
|
|
4
|
+
*/
|
|
5
|
+
import type { GridConfig, GridDimensions, GridItem, GridPosition } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Utility functions
|
|
8
|
+
*/
|
|
9
|
+
export declare class GridUtils {
|
|
10
|
+
static getRandomInt(min: number, max: number): number;
|
|
11
|
+
static getMedian(values: number[]): number;
|
|
12
|
+
static calculateBaseSize(totalWidth: number, columns: number, gapSize: number): number;
|
|
13
|
+
static calculateDimensions(position: GridPosition, baseSize: number, gapSize: number): Pick<GridDimensions, 'width' | 'height' | 'x' | 'y'>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Main grid layout engine
|
|
17
|
+
*/
|
|
18
|
+
export declare class GridLayoutEngine {
|
|
19
|
+
private config;
|
|
20
|
+
constructor(config: GridConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Calculate correct width based on column count and gap size
|
|
23
|
+
*/
|
|
24
|
+
calculateGridWidth(containerWidth: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* Generate initial grid layout for items
|
|
27
|
+
*/
|
|
28
|
+
generateLayout<T>(items: T[], gridWidth: number): GridItem<T>[];
|
|
29
|
+
/**
|
|
30
|
+
* Find next available position for a grid item
|
|
31
|
+
*/
|
|
32
|
+
private findNextPosition;
|
|
33
|
+
/**
|
|
34
|
+
* Optimize end elements to have smoother bottom edge
|
|
35
|
+
*/
|
|
36
|
+
optimizeEndElements<T>(elements: GridItem<T>[], gridWidth: number): GridItem<T>[];
|
|
37
|
+
/**
|
|
38
|
+
* Extract elements at the end of the grid
|
|
39
|
+
*/
|
|
40
|
+
private extractEndElements;
|
|
41
|
+
/**
|
|
42
|
+
* Create preview item and shift lower elements
|
|
43
|
+
*/
|
|
44
|
+
createPreviewLayout<T>(originalElements: GridItem<T>[], selectedElement: GridItem<T>, gridWidth: number): {
|
|
45
|
+
elements: GridItem<T>[];
|
|
46
|
+
previewItem: GridItem<T>;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Shift rows down by specified amount
|
|
50
|
+
*/
|
|
51
|
+
private shiftRowsDown;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate total grid height
|
|
54
|
+
*/
|
|
55
|
+
calculateGridHeight<T>(elements: GridItem<T>[], gridWidth: number): number;
|
|
56
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main entry point for the Dynamic Grid Library
|
|
3
|
+
* Export all public APIs for easy importing
|
|
4
|
+
*/
|
|
5
|
+
export { DynamicGrid } from './DynamicGrid';
|
|
6
|
+
export { GridLayoutEngine, GridUtils } from './GridLayoutEngine';
|
|
7
|
+
export type { DataAdapter, GridConfig, GridDimensions, GridItem, GridPosition, } from './types';
|
|
8
|
+
export { DEFAULT_GRID_CONFIG } from './types';
|
package/dist/index.es
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import e,{forwardRef as t,createElement as r,useRef as o,useState as n,useEffect as i}from"react";var a,l={exports:{}},s={};var c,u,f={};function m(){return c||(c=1,"production"!==process.env.NODE_ENV&&function(){function t(e){if(null==e)return null;if("function"==typeof e)return e.$$typeof===N?null:e.displayName||e.name||null;if("string"==typeof e)return e;switch(e){case h:return"Fragment";case y:return"Profiler";case g:return"StrictMode";case S:return"Suspense";case R:return"SuspenseList";case j:return"Activity"}if("object"==typeof e)switch("number"==typeof e.tag&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case d:return"Portal";case b:return e.displayName||"Context";case w:return(e._context.displayName||"Context")+".Consumer";case v:var r=e.render;return(e=e.displayName)||(e=""!==(e=r.displayName||r.name||"")?"ForwardRef("+e+")":"ForwardRef"),e;case k:return null!==(r=e.displayName||null)?r:t(e.type)||"Memo";case x:r=e._payload,e=e._init;try{return t(e(r))}catch(o){}}return null}function r(e){return""+e}function o(e){try{r(e);var t=!1}catch(i){t=!0}if(t){var o=(t=console).error,n="function"==typeof Symbol&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return o.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n),r(e)}}function n(e){if(e===h)return"<>";if("object"==typeof e&&null!==e&&e.$$typeof===x)return"<...>";try{var r=t(e);return r?"<"+r+">":"<...>"}catch(o){return"<...>"}}function i(){return Error("react-stack-top-frame")}function a(){var e=t(this.type);return E[e]||(E[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),void 0!==(e=this.props.ref)?e:null}function l(e,r,n,i,l,c){var f,m=r.children;if(void 0!==m)if(i)if(C(m)){for(i=0;i<m.length;i++)s(m[i]);Object.freeze&&Object.freeze(m)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else s(m);if(z.call(r,"key")){m=t(e);var d=Object.keys(r).filter(function(e){return"key"!==e});i=0<d.length?"{key: someKey, "+d.join(": ..., ")+": ...}":"{key: someKey}",T[m+i]||(d=0<d.length?"{"+d.join(": ..., ")+": ...}":"{}",console.error('A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',i,m,d,m),T[m+i]=!0)}if(m=null,void 0!==n&&(o(n),m=""+n),function(e){if(z.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return void 0!==e.key}(r)&&(o(r.key),m=""+r.key),"key"in r)for(var h in n={},r)"key"!==h&&(n[h]=r[h]);else n=r;return m&&function(e,t){function r(){u||(u=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}r.isReactWarning=!0,Object.defineProperty(e,"key",{get:r,configurable:!0})}(n,"function"==typeof e?e.displayName||e.name||"Unknown":e),function(e,t,r,o,n,i){var l=r.ref;return e={$$typeof:p,type:e,key:t,props:r,_owner:o},null!==(void 0!==l?l:null)?Object.defineProperty(e,"ref",{enumerable:!1,get:a}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:n}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}(e,m,n,null===(f=_.A)?null:f.getOwner(),l,c)}function s(e){c(e)?e._store&&(e._store.validated=1):"object"==typeof e&&null!==e&&e.$$typeof===x&&("fulfilled"===e._payload.status?c(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function c(e){return"object"==typeof e&&null!==e&&e.$$typeof===p}var u,m=e,p=/* @__PURE__ */Symbol.for("react.transitional.element"),d=/* @__PURE__ */Symbol.for("react.portal"),h=/* @__PURE__ */Symbol.for("react.fragment"),g=/* @__PURE__ */Symbol.for("react.strict_mode"),y=/* @__PURE__ */Symbol.for("react.profiler"),w=/* @__PURE__ */Symbol.for("react.consumer"),b=/* @__PURE__ */Symbol.for("react.context"),v=/* @__PURE__ */Symbol.for("react.forward_ref"),S=/* @__PURE__ */Symbol.for("react.suspense"),R=/* @__PURE__ */Symbol.for("react.suspense_list"),k=/* @__PURE__ */Symbol.for("react.memo"),x=/* @__PURE__ */Symbol.for("react.lazy"),j=/* @__PURE__ */Symbol.for("react.activity"),N=/* @__PURE__ */Symbol.for("react.client.reference"),_=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,z=Object.prototype.hasOwnProperty,C=Array.isArray,O=console.createTask?console.createTask:function(){return null},E={},$=(m={react_stack_bottom_frame:function(e){return e()}}).react_stack_bottom_frame.bind(m,i)(),P=O(n(i)),T={};f.Fragment=h,f.jsx=function(e,t,r){var o=1e4>_.recentlyCreatedOwnerStacks++;return l(e,t,r,!1,o?Error("react-stack-top-frame"):$,o?O(n(e)):P)},f.jsxs=function(e,t,r){var o=1e4>_.recentlyCreatedOwnerStacks++;return l(e,t,r,!0,o?Error("react-stack-top-frame"):$,o?O(n(e)):P)}}()),f}var p=(u||(u=1,"production"===process.env.NODE_ENV?l.exports=function(){if(a)return s;a=1;var e=/* @__PURE__ */Symbol.for("react.transitional.element"),t=/* @__PURE__ */Symbol.for("react.fragment");function r(t,r,o){var n=null;if(void 0!==o&&(n=""+o),void 0!==r.key&&(n=""+r.key),"key"in r)for(var i in o={},r)"key"!==i&&(o[i]=r[i]);else o=r;return r=o.ref,{$$typeof:e,type:t,key:n,ref:void 0!==r?r:null,props:o}}return s.Fragment=t,s.jsx=r,s.jsxs=r,s}():l.exports=m()),l.exports);const d=(...e)=>e.filter((e,t,r)=>Boolean(e)&&""!==e.trim()&&r.indexOf(e)===t).join(" ").trim(),h=e=>{const t=(e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,r)=>r?r.toUpperCase():t.toLowerCase()))(e);return t.charAt(0).toUpperCase()+t.slice(1)};var g={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const y=e=>{for(const t in e)if(t.startsWith("aria-")||"role"===t||"title"===t)return!0;return!1},w=t(({color:e="currentColor",size:t=24,strokeWidth:o=2,absoluteStrokeWidth:n,className:i="",children:a,iconNode:l,...s},c)=>r("svg",{ref:c,...g,width:t,height:t,stroke:e,strokeWidth:n?24*Number(o)/Number(t):o,className:d("lucide",i),...!a&&!y(s)&&{"aria-hidden":"true"},...s},[...l.map(([e,t])=>r(e,t)),...Array.isArray(a)?a:[a]])),b=((e,o)=>{const n=t(({className:t,...n},i)=>{return r(w,{ref:i,iconNode:o,className:d(`lucide-${a=h(e),a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`,`lucide-${e}`,t),...n});var a});return n.displayName=h(e),n})("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);class v{static getRandomInt(e,t){return Math.floor(Math.random()*(t-e+1))+e}static getMedian(e){if(0===e.length)return 0;const t=[...e].sort((e,t)=>e-t),r=Math.floor(t.length/2);return t.length%2?t[r]:Math.floor((t[r-1]+t[r])/2)}static calculateBaseSize(e,t,r){return Math.floor((e-r*(t-1))/t)}static calculateDimensions(e,t,r){const o=e.toCol-e.fromCol,n=e.toRow-e.fromRow;return{width:t*o+r*(o-1),height:t*n+r*(n-1),x:(t+r)*(e.fromCol-1),y:(t+r)*(e.fromRow-1)}}}class S{config;constructor(e){this.config=e}calculateGridWidth(e){return v.calculateBaseSize(e,this.config.columns,this.config.gapSize)*this.config.columns+this.config.gapSize*(this.config.columns-1)}generateLayout(e,t){const r=v.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=[],n=/* @__PURE__ */new Map;for(let i=1;i<=this.config.columns;i++)n.set(i,0);for(let i=0;i<e.length;i++){const t=this.findNextPosition(n),a=v.calculateDimensions(t,r,this.config.gapSize);o.push({...t,...a,elementNum:i+1,data:e[i]});for(let e=t.fromCol;e<t.toCol;e++)n.set(e,t.toRow)}return o}findNextPosition(e){const t=[];let r=1/0;e.forEach((e,o)=>{e<r?(t.length=0,t.push(o),r=e):e===r&&t[t.length-1]===o-1&&t.push(o)});const o=t[0],n=t[t.length-1]+1,i=n-o,a=Math.min(v.getRandomInt(this.config.minColumnSpan,Math.min(i,this.config.maxColumnSpan)),i);let l;l=o+this.config.minColumnSpan===n?n:n-(o+a)<=1&&n-o!==1?Math.min(o+a+1,n):o+a;const s=0===r?r+1:r;return{fromCol:o,toCol:l,fromRow:s,toRow:s+v.getRandomInt(this.config.minRowSpan,this.config.maxRowSpan)}}optimizeEndElements(e,t){if(0===e.length)return e;const r=v.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=e.map(e=>({...e})),n=this.extractEndElements(o),i=n.map(e=>e.element.toRow);let a=v.getMedian(i);for(const l of n)if(a-l.element.fromRow<=1){a++;break}for(const{index:l,element:s}of n)s.toRow=a,s.height=r*(s.toRow-s.fromRow)+this.config.gapSize*(s.toRow-s.fromRow-1),o[l]=s;return o}extractEndElements(e){const t=[];for(let r=e.length-1;r>=0;r--){const o=e[r];e.some(e=>e.fromRow===o.toRow)||t.push({index:r,element:o})}return t}createPreviewLayout(e,t,r){const o=v.calculateBaseSize(r,this.config.columns,this.config.gapSize),n=this.optimizeEndElements(e.filter(e=>e.fromRow<t.fromRow),r),i=e.filter(e=>e.fromRow>=t.fromRow),a=this.config.previewSectionRows??3,l={...t,width:r,fromCol:1,toCol:this.config.columns+1,fromRow:n.length>0?n[n.length-1].toRow:1,toRow:n.length>0?n[n.length-1].toRow+a+1:a+1,x:0,y:n.length>0?n[n.length-1].y+n[n.length-1].height+this.config.gapSize:0,height:o*a+this.config.gapSize*(a-1),elementNum:-1},s=n.length>0?l.toRow-t.fromRow-1:l.toRow-t.fromRow,c=this.shiftRowsDown(i,s,r);return{elements:[...n,...c],previewItem:l}}shiftRowsDown(e,t,r){const o=v.calculateBaseSize(r,this.config.columns,this.config.gapSize);return e.map(e=>({...e,fromRow:e.fromRow+t,toRow:e.toRow+t,y:(o+this.config.gapSize)*(e.fromRow+t-1)}))}calculateGridHeight(e,t){if(0===e.length)return 0;const r=v.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=e[e.length-1];return o.toRow*r+this.config.gapSize*(o.toRow-1)}}const R={columns:6,gapSize:16,minColumnSpan:2,maxColumnSpan:4,minRowSpan:2,maxRowSpan:4,previewSectionRows:3};function k({items:e,adapter:t,config:r,enablePreview:a=!0,className:l="",onItemClick:s}){const c={...R,...r},u=new S(c),f=o(null),m=o(null),[d,h]=n(!0),[g,y]=n([]),[w,v]=n([]),[k,j]=n(0),[N,_]=n(0),[z,C]=n({open:!1,item:null});i(()=>{if(f.current&&0!==e.length)try{h(!0);const t=f.current.clientWidth,r=u.calculateGridWidth(t),o=u.generateLayout(e,r),n=u.optimizeEndElements(o,r),i=u.calculateGridHeight(n,r);y(n),v(n),j(r),_(i)}finally{h(!1)}},[e,c.columns,c.gapSize]),i(()=>{z.open&&m.current&&setTimeout(()=>{m.current?.scrollIntoView({behavior:"smooth",block:"center"})},500)},[z.open]);const O=e=>{if(s&&s(e.data,e.elementNum-1),!a)return;const t=g.find(t=>t.elementNum===e.elementNum);if(!t)return;const{elements:r,previewItem:o}=u.createPreviewLayout(g,t,k);v(r),C({open:!0,item:o})};return 0===e.length?null:/* @__PURE__ */p.jsxs("div",{ref:f,className:`w-full relative transition-all duration-500 ease-in-out ${d?"invisible opacity-0":"visible opacity-100"} ${l}`,style:{height:N},children:[w.map((e,r)=>/* @__PURE__ */p.jsx(x,{item:e,adapter:t,onClick:O},t.getKey(e.data,r))),a&&z.open&&z.item&&/* @__PURE__ */p.jsx("div",{ref:m,className:"absolute bg-blue-500/10 rounded transition-all duration-500 ease-in-out "+(z.open?"visible opacity-100":"invisible opacity-0"),style:{top:z.item.y,left:z.item.x,width:z.item.width,height:z.item.height},children:/* @__PURE__ */p.jsxs("div",{className:"relative w-full h-full border-2 border-blue-500",children:[
|
|
2
|
+
/* @__PURE__ */p.jsx("button",{onClick:()=>{C({open:!1,item:null}),v(g)},className:"absolute top-2 right-2 z-50 bg-white rounded-[25px] p-3 w-[50px] h-[50px] flex items-center justify-center hover:bg-gray-100 transition-colors","aria-label":"Close preview",children:/* @__PURE__ */p.jsx(b,{className:"w-6 h-6 text-black"})}),
|
|
3
|
+
/* @__PURE__ */p.jsx("div",{className:"w-full h-full overflow-hidden",children:t.renderPreview?t.renderPreview(z.item.data):t.renderContent(z.item.data)})]})})]})}function x({item:e,adapter:t,onClick:r}){/* @__PURE__ */
|
|
4
|
+
return p.jsx("div",{className:"bg-zinc-200 dark:bg-zinc-700 rounded shrink-0 flex items-center justify-center overflow-hidden cursor-pointer transition-all duration-300 ease-in-out hover:shadow-lg",style:{position:"absolute",width:`${e.width}px`,height:`${e.height}px`,top:`${e.y}px`,left:`${e.x}px`},onClick:()=>r(e),children:t.renderContent(e.data)})}export{R as DEFAULT_GRID_CONFIG,k as DynamicGrid,S as GridLayoutEngine,v as GridUtils};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Warp={},e.React)}(this,function(e,t){"use strict";var r,o={exports:{}},n={};var i,a,l={};function s(){return i||(i=1,"production"!==process.env.NODE_ENV&&function(){function e(t){if(null==t)return null;if("function"==typeof t)return t.$$typeof===_?null:t.displayName||t.name||null;if("string"==typeof t)return t;switch(t){case h:return"Fragment";case y:return"Profiler";case g:return"StrictMode";case S:return"Suspense";case R:return"SuspenseList";case j:return"Activity"}if("object"==typeof t)switch("number"==typeof t.tag&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),t.$$typeof){case d:return"Portal";case b:return t.displayName||"Context";case w:return(t._context.displayName||"Context")+".Consumer";case v:var r=t.render;return(t=t.displayName)||(t=""!==(t=r.displayName||r.name||"")?"ForwardRef("+t+")":"ForwardRef"),t;case k:return null!==(r=t.displayName||null)?r:e(t.type)||"Memo";case x:r=t._payload,t=t._init;try{return e(t(r))}catch(o){}}return null}function r(e){return""+e}function o(e){try{r(e);var t=!1}catch(i){t=!0}if(t){var o=(t=console).error,n="function"==typeof Symbol&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return o.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",n),r(e)}}function n(t){if(t===h)return"<>";if("object"==typeof t&&null!==t&&t.$$typeof===x)return"<...>";try{var r=e(t);return r?"<"+r+">":"<...>"}catch(o){return"<...>"}}function i(){return Error("react-stack-top-frame")}function a(){var t=e(this.type);return O[t]||(O[t]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),void 0!==(t=this.props.ref)?t:null}function s(t,r,n,i,l,s){var u,m=r.children;if(void 0!==m)if(i)if(z(m)){for(i=0;i<m.length;i++)c(m[i]);Object.freeze&&Object.freeze(m)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else c(m);if(C.call(r,"key")){m=e(t);var d=Object.keys(r).filter(function(e){return"key"!==e});i=0<d.length?"{key: someKey, "+d.join(": ..., ")+": ...}":"{key: someKey}",T[m+i]||(d=0<d.length?"{"+d.join(": ..., ")+": ...}":"{}",console.error('A props object containing a "key" prop is being spread into JSX:\n let props = %s;\n <%s {...props} />\nReact keys must be passed directly to JSX without using spread:\n let props = %s;\n <%s key={someKey} {...props} />',i,m,d,m),T[m+i]=!0)}if(m=null,void 0!==n&&(o(n),m=""+n),function(e){if(C.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return void 0!==e.key}(r)&&(o(r.key),m=""+r.key),"key"in r)for(var h in n={},r)"key"!==h&&(n[h]=r[h]);else n=r;return m&&function(e,t){function r(){f||(f=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}r.isReactWarning=!0,Object.defineProperty(e,"key",{get:r,configurable:!0})}(n,"function"==typeof t?t.displayName||t.name||"Unknown":t),function(e,t,r,o,n,i){var l=r.ref;return e={$$typeof:p,type:e,key:t,props:r,_owner:o},null!==(void 0!==l?l:null)?Object.defineProperty(e,"ref",{enumerable:!1,get:a}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:n}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}(t,m,n,null===(u=N.A)?null:u.getOwner(),l,s)}function c(e){u(e)?e._store&&(e._store.validated=1):"object"==typeof e&&null!==e&&e.$$typeof===x&&("fulfilled"===e._payload.status?u(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function u(e){return"object"==typeof e&&null!==e&&e.$$typeof===p}var f,m=t,p=Symbol.for("react.transitional.element"),d=Symbol.for("react.portal"),h=Symbol.for("react.fragment"),g=Symbol.for("react.strict_mode"),y=Symbol.for("react.profiler"),w=Symbol.for("react.consumer"),b=Symbol.for("react.context"),v=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),R=Symbol.for("react.suspense_list"),k=Symbol.for("react.memo"),x=Symbol.for("react.lazy"),j=Symbol.for("react.activity"),_=Symbol.for("react.client.reference"),N=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,C=Object.prototype.hasOwnProperty,z=Array.isArray,E=console.createTask?console.createTask:function(){return null},O={},$=(m={react_stack_bottom_frame:function(e){return e()}}).react_stack_bottom_frame.bind(m,i)(),P=E(n(i)),T={};l.Fragment=h,l.jsx=function(e,t,r){var o=1e4>N.recentlyCreatedOwnerStacks++;return s(e,t,r,!1,o?Error("react-stack-top-frame"):$,o?E(n(e)):P)},l.jsxs=function(e,t,r){var o=1e4>N.recentlyCreatedOwnerStacks++;return s(e,t,r,!0,o?Error("react-stack-top-frame"):$,o?E(n(e)):P)}}()),l}var c=(a||(a=1,"production"===process.env.NODE_ENV?o.exports=function(){if(r)return n;r=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function o(t,r,o){var n=null;if(void 0!==o&&(n=""+o),void 0!==r.key&&(n=""+r.key),"key"in r)for(var i in o={},r)"key"!==i&&(o[i]=r[i]);else o=r;return r=o.ref,{$$typeof:e,type:t,key:n,ref:void 0!==r?r:null,props:o}}return n.Fragment=t,n.jsx=o,n.jsxs=o,n}():o.exports=s()),o.exports);const u=(...e)=>e.filter((e,t,r)=>Boolean(e)&&""!==e.trim()&&r.indexOf(e)===t).join(" ").trim(),f=e=>{const t=(e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,r)=>r?r.toUpperCase():t.toLowerCase()))(e);return t.charAt(0).toUpperCase()+t.slice(1)};var m={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const p=e=>{for(const t in e)if(t.startsWith("aria-")||"role"===t||"title"===t)return!0;return!1},d=t.forwardRef(({color:e="currentColor",size:r=24,strokeWidth:o=2,absoluteStrokeWidth:n,className:i="",children:a,iconNode:l,...s},c)=>t.createElement("svg",{ref:c,...m,width:r,height:r,stroke:e,strokeWidth:n?24*Number(o)/Number(r):o,className:u("lucide",i),...!a&&!p(s)&&{"aria-hidden":"true"},...s},[...l.map(([e,r])=>t.createElement(e,r)),...Array.isArray(a)?a:[a]])),h=((e,r)=>{const o=t.forwardRef(({className:o,...n},i)=>{return t.createElement(d,{ref:i,iconNode:r,className:u(`lucide-${a=f(e),a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`,`lucide-${e}`,o),...n});var a});return o.displayName=f(e),o})("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);class g{static getRandomInt(e,t){return Math.floor(Math.random()*(t-e+1))+e}static getMedian(e){if(0===e.length)return 0;const t=[...e].sort((e,t)=>e-t),r=Math.floor(t.length/2);return t.length%2?t[r]:Math.floor((t[r-1]+t[r])/2)}static calculateBaseSize(e,t,r){return Math.floor((e-r*(t-1))/t)}static calculateDimensions(e,t,r){const o=e.toCol-e.fromCol,n=e.toRow-e.fromRow;return{width:t*o+r*(o-1),height:t*n+r*(n-1),x:(t+r)*(e.fromCol-1),y:(t+r)*(e.fromRow-1)}}}class y{config;constructor(e){this.config=e}calculateGridWidth(e){return g.calculateBaseSize(e,this.config.columns,this.config.gapSize)*this.config.columns+this.config.gapSize*(this.config.columns-1)}generateLayout(e,t){const r=g.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=[],n=new Map;for(let i=1;i<=this.config.columns;i++)n.set(i,0);for(let i=0;i<e.length;i++){const t=this.findNextPosition(n),a=g.calculateDimensions(t,r,this.config.gapSize);o.push({...t,...a,elementNum:i+1,data:e[i]});for(let e=t.fromCol;e<t.toCol;e++)n.set(e,t.toRow)}return o}findNextPosition(e){const t=[];let r=1/0;e.forEach((e,o)=>{e<r?(t.length=0,t.push(o),r=e):e===r&&t[t.length-1]===o-1&&t.push(o)});const o=t[0],n=t[t.length-1]+1,i=n-o,a=Math.min(g.getRandomInt(this.config.minColumnSpan,Math.min(i,this.config.maxColumnSpan)),i);let l;l=o+this.config.minColumnSpan===n?n:n-(o+a)<=1&&n-o!==1?Math.min(o+a+1,n):o+a;const s=0===r?r+1:r;return{fromCol:o,toCol:l,fromRow:s,toRow:s+g.getRandomInt(this.config.minRowSpan,this.config.maxRowSpan)}}optimizeEndElements(e,t){if(0===e.length)return e;const r=g.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=e.map(e=>({...e})),n=this.extractEndElements(o),i=n.map(e=>e.element.toRow);let a=g.getMedian(i);for(const l of n)if(a-l.element.fromRow<=1){a++;break}for(const{index:l,element:s}of n)s.toRow=a,s.height=r*(s.toRow-s.fromRow)+this.config.gapSize*(s.toRow-s.fromRow-1),o[l]=s;return o}extractEndElements(e){const t=[];for(let r=e.length-1;r>=0;r--){const o=e[r];e.some(e=>e.fromRow===o.toRow)||t.push({index:r,element:o})}return t}createPreviewLayout(e,t,r){const o=g.calculateBaseSize(r,this.config.columns,this.config.gapSize),n=this.optimizeEndElements(e.filter(e=>e.fromRow<t.fromRow),r),i=e.filter(e=>e.fromRow>=t.fromRow),a=this.config.previewSectionRows??3,l={...t,width:r,fromCol:1,toCol:this.config.columns+1,fromRow:n.length>0?n[n.length-1].toRow:1,toRow:n.length>0?n[n.length-1].toRow+a+1:a+1,x:0,y:n.length>0?n[n.length-1].y+n[n.length-1].height+this.config.gapSize:0,height:o*a+this.config.gapSize*(a-1),elementNum:-1},s=n.length>0?l.toRow-t.fromRow-1:l.toRow-t.fromRow,c=this.shiftRowsDown(i,s,r);return{elements:[...n,...c],previewItem:l}}shiftRowsDown(e,t,r){const o=g.calculateBaseSize(r,this.config.columns,this.config.gapSize);return e.map(e=>({...e,fromRow:e.fromRow+t,toRow:e.toRow+t,y:(o+this.config.gapSize)*(e.fromRow+t-1)}))}calculateGridHeight(e,t){if(0===e.length)return 0;const r=g.calculateBaseSize(t,this.config.columns,this.config.gapSize),o=e[e.length-1];return o.toRow*r+this.config.gapSize*(o.toRow-1)}}const w={columns:6,gapSize:16,minColumnSpan:2,maxColumnSpan:4,minRowSpan:2,maxRowSpan:4,previewSectionRows:3};function b({item:e,adapter:t,onClick:r}){return c.jsx("div",{className:"bg-zinc-200 dark:bg-zinc-700 rounded shrink-0 flex items-center justify-center overflow-hidden cursor-pointer transition-all duration-300 ease-in-out hover:shadow-lg",style:{position:"absolute",width:`${e.width}px`,height:`${e.height}px`,top:`${e.y}px`,left:`${e.x}px`},onClick:()=>r(e),children:t.renderContent(e.data)})}e.DEFAULT_GRID_CONFIG=w,e.DynamicGrid=function({items:e,adapter:r,config:o,enablePreview:n=!0,className:i="",onItemClick:a}){const l={...w,...o},s=new y(l),u=t.useRef(null),f=t.useRef(null),[m,p]=t.useState(!0),[d,g]=t.useState([]),[v,S]=t.useState([]),[R,k]=t.useState(0),[x,j]=t.useState(0),[_,N]=t.useState({open:!1,item:null});t.useEffect(()=>{if(u.current&&0!==e.length)try{p(!0);const t=u.current.clientWidth,r=s.calculateGridWidth(t),o=s.generateLayout(e,r),n=s.optimizeEndElements(o,r),i=s.calculateGridHeight(n,r);g(n),S(n),k(r),j(i)}finally{p(!1)}},[e,l.columns,l.gapSize]),t.useEffect(()=>{_.open&&f.current&&setTimeout(()=>{f.current?.scrollIntoView({behavior:"smooth",block:"center"})},500)},[_.open]);const C=e=>{if(a&&a(e.data,e.elementNum-1),!n)return;const t=d.find(t=>t.elementNum===e.elementNum);if(!t)return;const{elements:r,previewItem:o}=s.createPreviewLayout(d,t,R);S(r),N({open:!0,item:o})};return 0===e.length?null:c.jsxs("div",{ref:u,className:`w-full relative transition-all duration-500 ease-in-out ${m?"invisible opacity-0":"visible opacity-100"} ${i}`,style:{height:x},children:[v.map((e,t)=>c.jsx(b,{item:e,adapter:r,onClick:C},r.getKey(e.data,t))),n&&_.open&&_.item&&c.jsx("div",{ref:f,className:"absolute bg-blue-500/10 rounded transition-all duration-500 ease-in-out "+(_.open?"visible opacity-100":"invisible opacity-0"),style:{top:_.item.y,left:_.item.x,width:_.item.width,height:_.item.height},children:c.jsxs("div",{className:"relative w-full h-full border-2 border-blue-500",children:[c.jsx("button",{onClick:()=>{N({open:!1,item:null}),S(d)},className:"absolute top-2 right-2 z-50 bg-white rounded-[25px] p-3 w-[50px] h-[50px] flex items-center justify-center hover:bg-gray-100 transition-colors","aria-label":"Close preview",children:c.jsx(h,{className:"w-6 h-6 text-black"})}),c.jsx("div",{className:"w-full h-full overflow-hidden",children:r.renderPreview?r.renderPreview(_.item.data):r.renderContent(_.item.data)})]})})]})},e.GridLayoutEngine=y,e.GridUtils=g,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the dynamic grid library
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Base grid item position and dimensions
|
|
6
|
+
*/
|
|
7
|
+
export interface GridPosition {
|
|
8
|
+
fromCol: number;
|
|
9
|
+
toCol: number;
|
|
10
|
+
fromRow: number;
|
|
11
|
+
toRow: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Computed dimensions for grid items
|
|
15
|
+
*/
|
|
16
|
+
export interface GridDimensions extends GridPosition {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Grid item with content reference
|
|
24
|
+
*/
|
|
25
|
+
export interface GridItem<T = unknown> extends GridDimensions {
|
|
26
|
+
elementNum: number;
|
|
27
|
+
data: T;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Grid configuration options
|
|
31
|
+
*/
|
|
32
|
+
export interface GridConfig {
|
|
33
|
+
/** Maximum number of columns in the grid */
|
|
34
|
+
columns: number;
|
|
35
|
+
/** Gap size between grid items in pixels */
|
|
36
|
+
gapSize: number;
|
|
37
|
+
/** Minimum column span for items */
|
|
38
|
+
minColumnSpan: number;
|
|
39
|
+
/** Maximum column span for items */
|
|
40
|
+
maxColumnSpan: number;
|
|
41
|
+
/** Minimum row span for items */
|
|
42
|
+
minRowSpan: number;
|
|
43
|
+
/** Maximum row span for items */
|
|
44
|
+
maxRowSpan: number;
|
|
45
|
+
/** Number of rows for preview section */
|
|
46
|
+
previewSectionRows?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Default grid configuration
|
|
50
|
+
*/
|
|
51
|
+
export declare const DEFAULT_GRID_CONFIG: GridConfig;
|
|
52
|
+
/**
|
|
53
|
+
* Data adapter interface for custom data types
|
|
54
|
+
*/
|
|
55
|
+
export interface DataAdapter<T> {
|
|
56
|
+
/** Extract unique key from data item */
|
|
57
|
+
getKey: (item: T, index: number) => string | number;
|
|
58
|
+
/** Render content for grid item */
|
|
59
|
+
renderContent: (item: T) => React.ReactNode;
|
|
60
|
+
/** Render preview content (optional, defaults to renderContent) */
|
|
61
|
+
renderPreview?: (item: T) => React.ReactNode;
|
|
62
|
+
}
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mav3rick/warp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A generic, highly performant dynamic grid component library for React with intelligent layout optimization",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.es.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.es.js",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"react",
|
|
21
|
+
"grid",
|
|
22
|
+
"dynamic",
|
|
23
|
+
"layout",
|
|
24
|
+
"component",
|
|
25
|
+
"performance",
|
|
26
|
+
"responsive"
|
|
27
|
+
],
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": ""
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": ""
|
|
34
|
+
},
|
|
35
|
+
"homepage": "",
|
|
36
|
+
"author": "mav3rick",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
40
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
41
|
+
"tailwindcss": "^3.0.0 || ^4.0.0"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"lucide-react": "^0.563.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@eslint/js": "^9.39.1",
|
|
48
|
+
"@tailwindcss/vite": "^4.1.18",
|
|
49
|
+
"@types/node": "^24.10.1",
|
|
50
|
+
"@types/react": "^19.2.5",
|
|
51
|
+
"@types/react-dom": "^19.2.3",
|
|
52
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
53
|
+
"eslint": "^9.39.1",
|
|
54
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
55
|
+
"eslint-plugin-react-refresh": "^0.4.24",
|
|
56
|
+
"globals": "^16.5.0",
|
|
57
|
+
"react": "^19.2.0",
|
|
58
|
+
"react-dom": "^19.2.0",
|
|
59
|
+
"tailwindcss": "^4.1.18",
|
|
60
|
+
"terser": "^5.46.0",
|
|
61
|
+
"typescript": "~5.9.3",
|
|
62
|
+
"typescript-eslint": "^8.46.4",
|
|
63
|
+
"vite": "^7.2.4",
|
|
64
|
+
"vite-plugin-dts": "^4.5.4"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"dev": "vite",
|
|
68
|
+
"build": "tsc -b && vite build",
|
|
69
|
+
"lint": "eslint .",
|
|
70
|
+
"preview": "vite preview"
|
|
71
|
+
}
|
|
72
|
+
}
|