panelgrid 0.1.1 → 0.1.3

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.
Files changed (51) hide show
  1. package/dist/PanelGridProvider.cjs +54 -0
  2. package/dist/PanelGridProvider.cjs.map +1 -0
  3. package/dist/PanelGridProvider.d.cts +45 -0
  4. package/dist/PanelGridProvider.d.mts +45 -0
  5. package/dist/PanelGridProvider.mjs +52 -0
  6. package/dist/PanelGridProvider.mjs.map +1 -0
  7. package/dist/PanelGridRenderer.cjs +76 -0
  8. package/dist/PanelGridRenderer.cjs.map +1 -0
  9. package/dist/PanelGridRenderer.d.cts +15 -0
  10. package/dist/PanelGridRenderer.d.mts +15 -0
  11. package/dist/PanelGridRenderer.mjs +76 -0
  12. package/dist/PanelGridRenderer.mjs.map +1 -0
  13. package/dist/helpers/animation.cjs +24 -0
  14. package/dist/helpers/animation.cjs.map +1 -0
  15. package/dist/helpers/animation.mjs +23 -0
  16. package/dist/helpers/animation.mjs.map +1 -0
  17. package/dist/helpers/gridCalculations.cjs +76 -0
  18. package/dist/helpers/gridCalculations.cjs.map +1 -0
  19. package/dist/helpers/gridCalculations.mjs +71 -0
  20. package/dist/helpers/gridCalculations.mjs.map +1 -0
  21. package/dist/helpers/panelDetection.cjs +21 -0
  22. package/dist/helpers/panelDetection.cjs.map +1 -0
  23. package/dist/helpers/panelDetection.mjs +20 -0
  24. package/dist/helpers/panelDetection.mjs.map +1 -0
  25. package/dist/helpers/rearrangement.cjs +161 -0
  26. package/dist/helpers/rearrangement.cjs.map +1 -0
  27. package/dist/helpers/rearrangement.d.cts +14 -0
  28. package/dist/helpers/rearrangement.d.mts +14 -0
  29. package/dist/helpers/rearrangement.mjs +159 -0
  30. package/dist/helpers/rearrangement.mjs.map +1 -0
  31. package/dist/index.cjs +11 -665
  32. package/dist/index.d.cts +6 -128
  33. package/dist/index.d.mts +6 -128
  34. package/dist/index.mjs +5 -660
  35. package/dist/types.d.cts +26 -0
  36. package/dist/types.d.mts +26 -0
  37. package/dist/usePanel.cjs +11 -0
  38. package/dist/usePanel.cjs.map +1 -0
  39. package/dist/usePanel.d.cts +12 -0
  40. package/dist/usePanel.d.mts +12 -0
  41. package/dist/usePanel.mjs +11 -0
  42. package/dist/usePanel.mjs.map +1 -0
  43. package/dist/usePanelGrid.cjs +343 -0
  44. package/dist/usePanelGrid.cjs.map +1 -0
  45. package/dist/usePanelGrid.d.cts +53 -0
  46. package/dist/usePanelGrid.d.mts +53 -0
  47. package/dist/usePanelGrid.mjs +343 -0
  48. package/dist/usePanelGrid.mjs.map +1 -0
  49. package/package.json +17 -5
  50. package/dist/index.cjs.map +0 -1
  51. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,54 @@
1
+ const require_usePanelGrid = require('./usePanelGrid.cjs');
2
+ let react = require("react");
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+
5
+ //#region src/PanelGridProvider.tsx
6
+ const PanelGridStateContext = (0, react.createContext)(void 0);
7
+ const PanelGridControlsContext = (0, react.createContext)(void 0);
8
+ function PanelGridProvider({ panels: initialPanels, columnCount, gap, children, rearrangement }) {
9
+ const [baseSize, setBaseSize] = (0, react.useState)(null);
10
+ const { panels, panelMap, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState, ghostPanelRef } = require_usePanelGrid.usePanelGrid({
11
+ panels: initialPanels,
12
+ columnCount,
13
+ baseSize: baseSize || 256,
14
+ gap,
15
+ rearrangement
16
+ });
17
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelGridStateContext.Provider, {
18
+ value: {
19
+ panels,
20
+ panelMap,
21
+ columnCount,
22
+ gap,
23
+ baseSize,
24
+ ghostPanelRef
25
+ },
26
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelGridControlsContext.Provider, {
27
+ value: {
28
+ setBaseSize,
29
+ addPanel,
30
+ removePanel,
31
+ lockPanelSize,
32
+ unlockPanelSize,
33
+ exportState
34
+ },
35
+ children
36
+ })
37
+ });
38
+ }
39
+ function usePanelGridState() {
40
+ const context = (0, react.useContext)(PanelGridStateContext);
41
+ if (!context) throw new Error("usePanelGridState must be used within a PanelGridProvider");
42
+ return context;
43
+ }
44
+ function usePanelGridControls() {
45
+ const context = (0, react.useContext)(PanelGridControlsContext);
46
+ if (!context) throw new Error("usePanelGridControls must be used within a PanelGridProvider");
47
+ return context;
48
+ }
49
+
50
+ //#endregion
51
+ exports.PanelGridProvider = PanelGridProvider;
52
+ exports.usePanelGridControls = usePanelGridControls;
53
+ exports.usePanelGridState = usePanelGridState;
54
+ //# sourceMappingURL=PanelGridProvider.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelGridProvider.cjs","names":["usePanelGrid"],"sources":["../src/PanelGridProvider.tsx"],"sourcesContent":["import { createContext, useContext, useState } from \"react\";\nimport type { PanelCoordinate, PanelId, RearrangementFunction } from \"./types\";\nimport { usePanelGrid } from \"./usePanelGrid\";\n\ntype PanelGridState = ReturnType<typeof usePanelGrid>;\n\ninterface PanelGridContextType {\n panels: PanelGridState[\"panels\"];\n panelMap: PanelGridState[\"panelMap\"];\n baseSize: number | null;\n columnCount: number;\n gap: number;\n ghostPanelRef: React.RefObject<HTMLDivElement | null>;\n}\n\ninterface PanelGridControlsContextType {\n setBaseSize: (baseSize: number) => void;\n addPanel: (panel: Partial<PanelCoordinate>) => void;\n removePanel: (id: PanelId) => void;\n lockPanelSize: (id: PanelId) => void;\n unlockPanelSize: (id: PanelId) => void;\n exportState: () => PanelCoordinate[];\n}\n\nconst PanelGridStateContext = createContext<PanelGridContextType | undefined>(undefined);\nconst PanelGridControlsContext = createContext<PanelGridControlsContextType | undefined>(undefined);\n\ninterface PanelGridProviderProps {\n panels: PanelCoordinate[];\n columnCount: number;\n gap: number;\n children: React.ReactNode;\n /**\n * Optional custom rearrangement function to override default collision resolution logic\n * If provided, this function will be called instead of the default rearrangePanels\n */\n rearrangement?: RearrangementFunction;\n}\n\nexport function PanelGridProvider({\n panels: initialPanels,\n columnCount,\n gap,\n children,\n rearrangement,\n}: PanelGridProviderProps) {\n const [baseSize, setBaseSize] = useState<number | null>(null);\n\n const { panels, panelMap, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState, ghostPanelRef } =\n usePanelGrid({\n panels: initialPanels,\n columnCount,\n baseSize: baseSize || 256,\n gap,\n rearrangement,\n });\n\n return (\n <PanelGridStateContext.Provider value={{ panels, panelMap, columnCount, gap, baseSize, ghostPanelRef }}>\n <PanelGridControlsContext.Provider\n value={{ setBaseSize, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState }}\n >\n {children}\n </PanelGridControlsContext.Provider>\n </PanelGridStateContext.Provider>\n );\n}\n\nexport function usePanelGridState() {\n const context = useContext(PanelGridStateContext);\n if (!context) {\n throw new Error(\"usePanelGridState must be used within a PanelGridProvider\");\n }\n return context;\n}\n\nexport function usePanelGridControls() {\n const context = useContext(PanelGridControlsContext);\n if (!context) {\n throw new Error(\"usePanelGridControls must be used within a PanelGridProvider\");\n }\n return context;\n}\n"],"mappings":";;;;;AAwBA,MAAM,iDAAwE,OAAU;AACxF,MAAM,oDAAmF,OAAU;AAcnG,SAAgB,kBAAkB,EAChC,QAAQ,eACR,aACA,KACA,UACA,iBACyB;CACzB,MAAM,CAAC,UAAU,mCAAuC,KAAK;CAE7D,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,eAAe,iBAAiB,aAAa,kBAC5FA,kCAAa;EACX,QAAQ;EACR;EACA,UAAU,YAAY;EACtB;EACA;EACD,CAAC;AAEJ,QACE,2CAAC,sBAAsB;EAAS,OAAO;GAAE;GAAQ;GAAU;GAAa;GAAK;GAAU;GAAe;YACpG,2CAAC,yBAAyB;GACxB,OAAO;IAAE;IAAa;IAAU;IAAa;IAAe;IAAiB;IAAa;GAEzF;IACiC;GACL;;AAIrC,SAAgB,oBAAoB;CAClC,MAAM,gCAAqB,sBAAsB;AACjD,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,4DAA4D;AAE9E,QAAO;;AAGT,SAAgB,uBAAuB;CACrC,MAAM,gCAAqB,yBAAyB;AACpD,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,+DAA+D;AAEjF,QAAO"}
@@ -0,0 +1,45 @@
1
+ import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.cjs";
2
+ import { usePanelGrid } from "./usePanelGrid.cjs";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/PanelGridProvider.d.ts
6
+ type PanelGridState = ReturnType<typeof usePanelGrid>;
7
+ interface PanelGridContextType {
8
+ panels: PanelGridState["panels"];
9
+ panelMap: PanelGridState["panelMap"];
10
+ baseSize: number | null;
11
+ columnCount: number;
12
+ gap: number;
13
+ ghostPanelRef: React.RefObject<HTMLDivElement | null>;
14
+ }
15
+ interface PanelGridControlsContextType {
16
+ setBaseSize: (baseSize: number) => void;
17
+ addPanel: (panel: Partial<PanelCoordinate>) => void;
18
+ removePanel: (id: PanelId) => void;
19
+ lockPanelSize: (id: PanelId) => void;
20
+ unlockPanelSize: (id: PanelId) => void;
21
+ exportState: () => PanelCoordinate[];
22
+ }
23
+ interface PanelGridProviderProps {
24
+ panels: PanelCoordinate[];
25
+ columnCount: number;
26
+ gap: number;
27
+ children: React.ReactNode;
28
+ /**
29
+ * Optional custom rearrangement function to override default collision resolution logic
30
+ * If provided, this function will be called instead of the default rearrangePanels
31
+ */
32
+ rearrangement?: RearrangementFunction;
33
+ }
34
+ declare function PanelGridProvider({
35
+ panels: initialPanels,
36
+ columnCount,
37
+ gap,
38
+ children,
39
+ rearrangement
40
+ }: PanelGridProviderProps): react_jsx_runtime0.JSX.Element;
41
+ declare function usePanelGridState(): PanelGridContextType;
42
+ declare function usePanelGridControls(): PanelGridControlsContextType;
43
+ //#endregion
44
+ export { PanelGridProvider, usePanelGridControls, usePanelGridState };
45
+ //# sourceMappingURL=PanelGridProvider.d.cts.map
@@ -0,0 +1,45 @@
1
+ import { PanelCoordinate, PanelId, RearrangementFunction } from "./types.mjs";
2
+ import { usePanelGrid } from "./usePanelGrid.mjs";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/PanelGridProvider.d.ts
6
+ type PanelGridState = ReturnType<typeof usePanelGrid>;
7
+ interface PanelGridContextType {
8
+ panels: PanelGridState["panels"];
9
+ panelMap: PanelGridState["panelMap"];
10
+ baseSize: number | null;
11
+ columnCount: number;
12
+ gap: number;
13
+ ghostPanelRef: React.RefObject<HTMLDivElement | null>;
14
+ }
15
+ interface PanelGridControlsContextType {
16
+ setBaseSize: (baseSize: number) => void;
17
+ addPanel: (panel: Partial<PanelCoordinate>) => void;
18
+ removePanel: (id: PanelId) => void;
19
+ lockPanelSize: (id: PanelId) => void;
20
+ unlockPanelSize: (id: PanelId) => void;
21
+ exportState: () => PanelCoordinate[];
22
+ }
23
+ interface PanelGridProviderProps {
24
+ panels: PanelCoordinate[];
25
+ columnCount: number;
26
+ gap: number;
27
+ children: React.ReactNode;
28
+ /**
29
+ * Optional custom rearrangement function to override default collision resolution logic
30
+ * If provided, this function will be called instead of the default rearrangePanels
31
+ */
32
+ rearrangement?: RearrangementFunction;
33
+ }
34
+ declare function PanelGridProvider({
35
+ panels: initialPanels,
36
+ columnCount,
37
+ gap,
38
+ children,
39
+ rearrangement
40
+ }: PanelGridProviderProps): react_jsx_runtime0.JSX.Element;
41
+ declare function usePanelGridState(): PanelGridContextType;
42
+ declare function usePanelGridControls(): PanelGridControlsContextType;
43
+ //#endregion
44
+ export { PanelGridProvider, usePanelGridControls, usePanelGridState };
45
+ //# sourceMappingURL=PanelGridProvider.d.mts.map
@@ -0,0 +1,52 @@
1
+ import { usePanelGrid } from "./usePanelGrid.mjs";
2
+ import { createContext, useContext, useState } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/PanelGridProvider.tsx
6
+ const PanelGridStateContext = createContext(void 0);
7
+ const PanelGridControlsContext = createContext(void 0);
8
+ function PanelGridProvider({ panels: initialPanels, columnCount, gap, children, rearrangement }) {
9
+ const [baseSize, setBaseSize] = useState(null);
10
+ const { panels, panelMap, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState, ghostPanelRef } = usePanelGrid({
11
+ panels: initialPanels,
12
+ columnCount,
13
+ baseSize: baseSize || 256,
14
+ gap,
15
+ rearrangement
16
+ });
17
+ return /* @__PURE__ */ jsx(PanelGridStateContext.Provider, {
18
+ value: {
19
+ panels,
20
+ panelMap,
21
+ columnCount,
22
+ gap,
23
+ baseSize,
24
+ ghostPanelRef
25
+ },
26
+ children: /* @__PURE__ */ jsx(PanelGridControlsContext.Provider, {
27
+ value: {
28
+ setBaseSize,
29
+ addPanel,
30
+ removePanel,
31
+ lockPanelSize,
32
+ unlockPanelSize,
33
+ exportState
34
+ },
35
+ children
36
+ })
37
+ });
38
+ }
39
+ function usePanelGridState() {
40
+ const context = useContext(PanelGridStateContext);
41
+ if (!context) throw new Error("usePanelGridState must be used within a PanelGridProvider");
42
+ return context;
43
+ }
44
+ function usePanelGridControls() {
45
+ const context = useContext(PanelGridControlsContext);
46
+ if (!context) throw new Error("usePanelGridControls must be used within a PanelGridProvider");
47
+ return context;
48
+ }
49
+
50
+ //#endregion
51
+ export { PanelGridProvider, usePanelGridControls, usePanelGridState };
52
+ //# sourceMappingURL=PanelGridProvider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelGridProvider.mjs","names":[],"sources":["../src/PanelGridProvider.tsx"],"sourcesContent":["import { createContext, useContext, useState } from \"react\";\nimport type { PanelCoordinate, PanelId, RearrangementFunction } from \"./types\";\nimport { usePanelGrid } from \"./usePanelGrid\";\n\ntype PanelGridState = ReturnType<typeof usePanelGrid>;\n\ninterface PanelGridContextType {\n panels: PanelGridState[\"panels\"];\n panelMap: PanelGridState[\"panelMap\"];\n baseSize: number | null;\n columnCount: number;\n gap: number;\n ghostPanelRef: React.RefObject<HTMLDivElement | null>;\n}\n\ninterface PanelGridControlsContextType {\n setBaseSize: (baseSize: number) => void;\n addPanel: (panel: Partial<PanelCoordinate>) => void;\n removePanel: (id: PanelId) => void;\n lockPanelSize: (id: PanelId) => void;\n unlockPanelSize: (id: PanelId) => void;\n exportState: () => PanelCoordinate[];\n}\n\nconst PanelGridStateContext = createContext<PanelGridContextType | undefined>(undefined);\nconst PanelGridControlsContext = createContext<PanelGridControlsContextType | undefined>(undefined);\n\ninterface PanelGridProviderProps {\n panels: PanelCoordinate[];\n columnCount: number;\n gap: number;\n children: React.ReactNode;\n /**\n * Optional custom rearrangement function to override default collision resolution logic\n * If provided, this function will be called instead of the default rearrangePanels\n */\n rearrangement?: RearrangementFunction;\n}\n\nexport function PanelGridProvider({\n panels: initialPanels,\n columnCount,\n gap,\n children,\n rearrangement,\n}: PanelGridProviderProps) {\n const [baseSize, setBaseSize] = useState<number | null>(null);\n\n const { panels, panelMap, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState, ghostPanelRef } =\n usePanelGrid({\n panels: initialPanels,\n columnCount,\n baseSize: baseSize || 256,\n gap,\n rearrangement,\n });\n\n return (\n <PanelGridStateContext.Provider value={{ panels, panelMap, columnCount, gap, baseSize, ghostPanelRef }}>\n <PanelGridControlsContext.Provider\n value={{ setBaseSize, addPanel, removePanel, lockPanelSize, unlockPanelSize, exportState }}\n >\n {children}\n </PanelGridControlsContext.Provider>\n </PanelGridStateContext.Provider>\n );\n}\n\nexport function usePanelGridState() {\n const context = useContext(PanelGridStateContext);\n if (!context) {\n throw new Error(\"usePanelGridState must be used within a PanelGridProvider\");\n }\n return context;\n}\n\nexport function usePanelGridControls() {\n const context = useContext(PanelGridControlsContext);\n if (!context) {\n throw new Error(\"usePanelGridControls must be used within a PanelGridProvider\");\n }\n return context;\n}\n"],"mappings":";;;;;AAwBA,MAAM,wBAAwB,cAAgD,OAAU;AACxF,MAAM,2BAA2B,cAAwD,OAAU;AAcnG,SAAgB,kBAAkB,EAChC,QAAQ,eACR,aACA,KACA,UACA,iBACyB;CACzB,MAAM,CAAC,UAAU,eAAe,SAAwB,KAAK;CAE7D,MAAM,EAAE,QAAQ,UAAU,UAAU,aAAa,eAAe,iBAAiB,aAAa,kBAC5F,aAAa;EACX,QAAQ;EACR;EACA,UAAU,YAAY;EACtB;EACA;EACD,CAAC;AAEJ,QACE,oBAAC,sBAAsB;EAAS,OAAO;GAAE;GAAQ;GAAU;GAAa;GAAK;GAAU;GAAe;YACpG,oBAAC,yBAAyB;GACxB,OAAO;IAAE;IAAa;IAAU;IAAa;IAAe;IAAiB;IAAa;GAEzF;IACiC;GACL;;AAIrC,SAAgB,oBAAoB;CAClC,MAAM,UAAU,WAAW,sBAAsB;AACjD,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,4DAA4D;AAE9E,QAAO;;AAGT,SAAgB,uBAAuB;CACrC,MAAM,UAAU,WAAW,yBAAyB;AACpD,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,+DAA+D;AAEjF,QAAO"}
@@ -0,0 +1,76 @@
1
+ const require_gridCalculations = require('./helpers/gridCalculations.cjs');
2
+ const require_PanelGridProvider = require('./PanelGridProvider.cjs');
3
+ let react = require("react");
4
+ let react_jsx_runtime = require("react/jsx-runtime");
5
+
6
+ //#region src/PanelGridRenderer.tsx
7
+ function PanelGridRenderer({ itemRenderer: ItemRenderer }) {
8
+ const { panels, columnCount, gap, baseSize, ghostPanelRef } = require_PanelGridProvider.usePanelGridState();
9
+ const { setBaseSize } = require_PanelGridProvider.usePanelGridControls();
10
+ const containerRef = (0, react.useRef)(null);
11
+ const rowCount = require_gridCalculations.getGridRowCount(panels.map(({ panelProps: p }) => ({
12
+ id: p.key,
13
+ x: p.positionData.x,
14
+ y: p.positionData.y,
15
+ w: p.positionData.w,
16
+ h: p.positionData.h
17
+ })));
18
+ const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);
19
+ (0, react.useLayoutEffect)(() => {
20
+ if (!containerRef.current) return;
21
+ const observer = new ResizeObserver((entries) => {
22
+ const [entry] = entries;
23
+ const rect = entry.contentRect;
24
+ setBaseSize(Math.floor((rect.width - gap * (columnCount - 1)) / columnCount));
25
+ });
26
+ observer.observe(containerRef.current);
27
+ return () => observer.disconnect();
28
+ }, [
29
+ columnCount,
30
+ gap,
31
+ setBaseSize
32
+ ]);
33
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
34
+ className: "panelgrid-renderer",
35
+ style: {
36
+ "--column-count": `${columnCount}`,
37
+ "--gap": `${gap}px`,
38
+ opacity: baseSize ? 1 : 0
39
+ },
40
+ ref: containerRef,
41
+ children: [
42
+ Array.from({ length: count }).map((_, i) => {
43
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "panelgrid-panel-placeholder" }, i);
44
+ }),
45
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
46
+ className: "panelgrid-panel-ghost",
47
+ ref: ghostPanelRef
48
+ }),
49
+ panels.map((panel) => {
50
+ const { panelProps, resizeHandleProps } = panel;
51
+ const { key, lockSize, style, positionData, ref, onMouseDown } = panelProps;
52
+ const className = lockSize ? "panelgrid-panel panelgrid-panel--size-locked" : "panelgrid-panel";
53
+ const { x, y, w, h } = positionData;
54
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
55
+ className,
56
+ style,
57
+ ref,
58
+ onMouseDown,
59
+ "data-panel-id": key,
60
+ "data-pg-x": x,
61
+ "data-pg-y": y,
62
+ "data-pg-w": w,
63
+ "data-pg-h": h,
64
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ItemRenderer, { id: key }), resizeHandleProps && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
65
+ className: "panelgrid-resize-handle",
66
+ ...resizeHandleProps
67
+ })]
68
+ }, key);
69
+ })
70
+ ]
71
+ });
72
+ }
73
+
74
+ //#endregion
75
+ exports.PanelGridRenderer = PanelGridRenderer;
76
+ //# sourceMappingURL=PanelGridRenderer.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelGridRenderer.cjs","names":["usePanelGridState","usePanelGridControls","getGridRowCount"],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["import { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n itemRenderer: React.ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ itemRenderer: ItemRenderer }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = lockSize ? \"panelgrid-panel panelgrid-panel--size-locked\" : \"panelgrid-panel\";\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemRenderer id={key} />\n {resizeHandleProps && <span className=\"panelgrid-resize-handle\" {...resizeHandleProps}></span>}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;AASA,SAAgB,kBAAkB,EAAE,cAAc,gBAAwC;CACxF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,kBAAkBA,6CAAmB;CACjF,MAAM,EAAE,gBAAgBC,gDAAsB;CAC9C,MAAM,iCAA6C,KAAK;CACxD,MAAM,WAAWC,yCACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,kCAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,4CAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAC3C,WAAO,2CAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,2CAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,OAAO,cAAc,KAAK,gBAAgB;IAEjE,MAAM,YAAY,WAAW,iDAAiD;IAC9E,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,4CAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,2CAAC,gBAAa,IAAI,MAAO,EACxB,qBAAqB,2CAAC;MAAK,WAAU;MAA0B,GAAI;OAA0B;OAZzF,IAaD;KAER;;GACE"}
@@ -0,0 +1,15 @@
1
+ import { PanelId } from "./types.cjs";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/PanelGridRenderer.d.ts
5
+ interface PanelGridRendererProps {
6
+ itemRenderer: React.ComponentType<{
7
+ id: PanelId;
8
+ }>;
9
+ }
10
+ declare function PanelGridRenderer({
11
+ itemRenderer: ItemRenderer
12
+ }: PanelGridRendererProps): react_jsx_runtime0.JSX.Element;
13
+ //#endregion
14
+ export { PanelGridRenderer };
15
+ //# sourceMappingURL=PanelGridRenderer.d.cts.map
@@ -0,0 +1,15 @@
1
+ import { PanelId } from "./types.mjs";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/PanelGridRenderer.d.ts
5
+ interface PanelGridRendererProps {
6
+ itemRenderer: React.ComponentType<{
7
+ id: PanelId;
8
+ }>;
9
+ }
10
+ declare function PanelGridRenderer({
11
+ itemRenderer: ItemRenderer
12
+ }: PanelGridRendererProps): react_jsx_runtime0.JSX.Element;
13
+ //#endregion
14
+ export { PanelGridRenderer };
15
+ //# sourceMappingURL=PanelGridRenderer.d.mts.map
@@ -0,0 +1,76 @@
1
+ import { getGridRowCount } from "./helpers/gridCalculations.mjs";
2
+ import { usePanelGridControls, usePanelGridState } from "./PanelGridProvider.mjs";
3
+ import { useLayoutEffect, useRef } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/PanelGridRenderer.tsx
7
+ function PanelGridRenderer({ itemRenderer: ItemRenderer }) {
8
+ const { panels, columnCount, gap, baseSize, ghostPanelRef } = usePanelGridState();
9
+ const { setBaseSize } = usePanelGridControls();
10
+ const containerRef = useRef(null);
11
+ const rowCount = getGridRowCount(panels.map(({ panelProps: p }) => ({
12
+ id: p.key,
13
+ x: p.positionData.x,
14
+ y: p.positionData.y,
15
+ w: p.positionData.w,
16
+ h: p.positionData.h
17
+ })));
18
+ const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);
19
+ useLayoutEffect(() => {
20
+ if (!containerRef.current) return;
21
+ const observer = new ResizeObserver((entries) => {
22
+ const [entry] = entries;
23
+ const rect = entry.contentRect;
24
+ setBaseSize(Math.floor((rect.width - gap * (columnCount - 1)) / columnCount));
25
+ });
26
+ observer.observe(containerRef.current);
27
+ return () => observer.disconnect();
28
+ }, [
29
+ columnCount,
30
+ gap,
31
+ setBaseSize
32
+ ]);
33
+ return /* @__PURE__ */ jsxs("div", {
34
+ className: "panelgrid-renderer",
35
+ style: {
36
+ "--column-count": `${columnCount}`,
37
+ "--gap": `${gap}px`,
38
+ opacity: baseSize ? 1 : 0
39
+ },
40
+ ref: containerRef,
41
+ children: [
42
+ Array.from({ length: count }).map((_, i) => {
43
+ return /* @__PURE__ */ jsx("div", { className: "panelgrid-panel-placeholder" }, i);
44
+ }),
45
+ /* @__PURE__ */ jsx("div", {
46
+ className: "panelgrid-panel-ghost",
47
+ ref: ghostPanelRef
48
+ }),
49
+ panels.map((panel) => {
50
+ const { panelProps, resizeHandleProps } = panel;
51
+ const { key, lockSize, style, positionData, ref, onMouseDown } = panelProps;
52
+ const className = lockSize ? "panelgrid-panel panelgrid-panel--size-locked" : "panelgrid-panel";
53
+ const { x, y, w, h } = positionData;
54
+ return /* @__PURE__ */ jsxs("div", {
55
+ className,
56
+ style,
57
+ ref,
58
+ onMouseDown,
59
+ "data-panel-id": key,
60
+ "data-pg-x": x,
61
+ "data-pg-y": y,
62
+ "data-pg-w": w,
63
+ "data-pg-h": h,
64
+ children: [/* @__PURE__ */ jsx(ItemRenderer, { id: key }), resizeHandleProps && /* @__PURE__ */ jsx("span", {
65
+ className: "panelgrid-resize-handle",
66
+ ...resizeHandleProps
67
+ })]
68
+ }, key);
69
+ })
70
+ ]
71
+ });
72
+ }
73
+
74
+ //#endregion
75
+ export { PanelGridRenderer };
76
+ //# sourceMappingURL=PanelGridRenderer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PanelGridRenderer.mjs","names":[],"sources":["../src/PanelGridRenderer.tsx"],"sourcesContent":["import { useLayoutEffect, useRef } from \"react\";\nimport { getGridRowCount } from \"./helpers/gridCalculations\";\nimport { usePanelGridControls, usePanelGridState } from \"./PanelGridProvider\";\nimport type { PanelId } from \"./types\";\n\ninterface PanelGridRendererProps {\n itemRenderer: React.ComponentType<{ id: PanelId }>;\n}\n\nexport function PanelGridRenderer({ itemRenderer: ItemRenderer }: PanelGridRendererProps) {\n const { panels, columnCount, gap, baseSize, ghostPanelRef } = usePanelGridState();\n const { setBaseSize } = usePanelGridControls();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const rowCount = getGridRowCount(\n panels.map(({ panelProps: p }) => ({\n id: p.key,\n x: p.positionData.x,\n y: p.positionData.y,\n w: p.positionData.w,\n h: p.positionData.h,\n }))\n );\n const count = Math.max(columnCount * (rowCount + 1), columnCount * columnCount);\n\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n const observer = new ResizeObserver((entries) => {\n const [entry] = entries;\n const rect = entry.contentRect;\n const baseSize = Math.floor((rect.width - gap * (columnCount - 1)) / columnCount);\n setBaseSize(baseSize);\n });\n observer.observe(containerRef.current);\n return () => observer.disconnect();\n }, [columnCount, gap, setBaseSize]);\n\n return (\n <div\n className=\"panelgrid-renderer\"\n style={{\n \"--column-count\": `${columnCount}`,\n \"--gap\": `${gap}px`,\n opacity: baseSize ? 1 : 0,\n }}\n ref={containerRef}\n >\n {Array.from({ length: count }).map((_, i) => {\n return <div key={i} className=\"panelgrid-panel-placeholder\" />;\n })}\n\n <div className=\"panelgrid-panel-ghost\" ref={ghostPanelRef}></div>\n\n {panels.map((panel) => {\n const { panelProps, resizeHandleProps } = panel;\n const { key, lockSize, style, positionData, ref, onMouseDown } = panelProps;\n\n const className = lockSize ? \"panelgrid-panel panelgrid-panel--size-locked\" : \"panelgrid-panel\";\n const { x, y, w, h } = positionData;\n\n return (\n <div\n key={key}\n className={className}\n style={style}\n ref={ref}\n onMouseDown={onMouseDown}\n data-panel-id={key}\n data-pg-x={x}\n data-pg-y={y}\n data-pg-w={w}\n data-pg-h={h}\n >\n <ItemRenderer id={key} />\n {resizeHandleProps && <span className=\"panelgrid-resize-handle\" {...resizeHandleProps}></span>}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;AASA,SAAgB,kBAAkB,EAAE,cAAc,gBAAwC;CACxF,MAAM,EAAE,QAAQ,aAAa,KAAK,UAAU,kBAAkB,mBAAmB;CACjF,MAAM,EAAE,gBAAgB,sBAAsB;CAC9C,MAAM,eAAe,OAA8B,KAAK;CACxD,MAAM,WAAW,gBACf,OAAO,KAAK,EAAE,YAAY,SAAS;EACjC,IAAI,EAAE;EACN,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EAClB,GAAG,EAAE,aAAa;EACnB,EAAE,CACJ;CACD,MAAM,QAAQ,KAAK,IAAI,eAAe,WAAW,IAAI,cAAc,YAAY;AAE/E,uBAAsB;AACpB,MAAI,CAAC,aAAa,QAAS;EAC3B,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,CAAC,SAAS;GAChB,MAAM,OAAO,MAAM;AAEnB,eADiB,KAAK,OAAO,KAAK,QAAQ,OAAO,cAAc,MAAM,YAAY,CAC5D;IACrB;AACF,WAAS,QAAQ,aAAa,QAAQ;AACtC,eAAa,SAAS,YAAY;IACjC;EAAC;EAAa;EAAK;EAAY,CAAC;AAEnC,QACE,qBAAC;EACC,WAAU;EACV,OAAO;GACL,kBAAkB,GAAG;GACrB,SAAS,GAAG,IAAI;GAChB,SAAS,WAAW,IAAI;GACzB;EACD,KAAK;;GAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,MAAM;AAC3C,WAAO,oBAAC,SAAY,WAAU,iCAAb,EAA6C;KAC9D;GAEF,oBAAC;IAAI,WAAU;IAAwB,KAAK;KAAqB;GAEhE,OAAO,KAAK,UAAU;IACrB,MAAM,EAAE,YAAY,sBAAsB;IAC1C,MAAM,EAAE,KAAK,UAAU,OAAO,cAAc,KAAK,gBAAgB;IAEjE,MAAM,YAAY,WAAW,iDAAiD;IAC9E,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM;AAEvB,WACE,qBAAC;KAEY;KACJ;KACF;KACQ;KACb,iBAAe;KACf,aAAW;KACX,aAAW;KACX,aAAW;KACX,aAAW;gBAEX,oBAAC,gBAAa,IAAI,MAAO,EACxB,qBAAqB,oBAAC;MAAK,WAAU;MAA0B,GAAI;OAA0B;OAZzF,IAaD;KAER;;GACE"}
@@ -0,0 +1,24 @@
1
+
2
+ //#region src/helpers/animation.ts
3
+ /**
4
+ * Applies snap-back animation to element
5
+ * Smoothly animates the element from its dropped position to the snapped grid position
6
+ */
7
+ function applySnapAnimation(options) {
8
+ const { element, droppedLeft, droppedTop, nextLeft, nextTop, originalTransition } = options;
9
+ const deltaX = droppedLeft - nextLeft;
10
+ const deltaY = droppedTop - nextTop;
11
+ element.style.transform = `translate3D(${deltaX}px, ${deltaY}px, 0)`;
12
+ element.style.transition = "";
13
+ window.requestAnimationFrame(() => {
14
+ element.style.transform = "translate3D(0, 0, 0)";
15
+ element.style.transition = "transform 0.1s ease-out";
16
+ });
17
+ element.style.left = `${nextLeft}px`;
18
+ element.style.top = `${nextTop}px`;
19
+ element.style.transition = originalTransition;
20
+ }
21
+
22
+ //#endregion
23
+ exports.applySnapAnimation = applySnapAnimation;
24
+ //# sourceMappingURL=animation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.cjs","names":[],"sources":["../../src/helpers/animation.ts"],"sourcesContent":["/**\n * Options for applying snap-back animation\n */\ninterface ApplySnapAnimationOptions {\n element: HTMLElement;\n droppedLeft: number;\n droppedTop: number;\n nextLeft: number;\n nextTop: number;\n originalTransition: string;\n}\n\n/**\n * Applies snap-back animation to element\n * Smoothly animates the element from its dropped position to the snapped grid position\n */\nexport function applySnapAnimation(options: ApplySnapAnimationOptions): void {\n const { element, droppedLeft, droppedTop, nextLeft, nextTop, originalTransition } = options;\n\n const deltaX = droppedLeft - nextLeft;\n const deltaY = droppedTop - nextTop;\n\n element.style.transform = `translate3D(${deltaX}px, ${deltaY}px, 0)`;\n element.style.transition = \"\";\n\n window.requestAnimationFrame(() => {\n element.style.transform = \"translate3D(0, 0, 0)\";\n element.style.transition = \"transform 0.1s ease-out\";\n });\n\n element.style.left = `${nextLeft}px`;\n element.style.top = `${nextTop}px`;\n element.style.transition = originalTransition;\n}\n"],"mappings":";;;;;;AAgBA,SAAgB,mBAAmB,SAA0C;CAC3E,MAAM,EAAE,SAAS,aAAa,YAAY,UAAU,SAAS,uBAAuB;CAEpF,MAAM,SAAS,cAAc;CAC7B,MAAM,SAAS,aAAa;AAE5B,SAAQ,MAAM,YAAY,eAAe,OAAO,MAAM,OAAO;AAC7D,SAAQ,MAAM,aAAa;AAE3B,QAAO,4BAA4B;AACjC,UAAQ,MAAM,YAAY;AAC1B,UAAQ,MAAM,aAAa;GAC3B;AAEF,SAAQ,MAAM,OAAO,GAAG,SAAS;AACjC,SAAQ,MAAM,MAAM,GAAG,QAAQ;AAC/B,SAAQ,MAAM,aAAa"}
@@ -0,0 +1,23 @@
1
+ //#region src/helpers/animation.ts
2
+ /**
3
+ * Applies snap-back animation to element
4
+ * Smoothly animates the element from its dropped position to the snapped grid position
5
+ */
6
+ function applySnapAnimation(options) {
7
+ const { element, droppedLeft, droppedTop, nextLeft, nextTop, originalTransition } = options;
8
+ const deltaX = droppedLeft - nextLeft;
9
+ const deltaY = droppedTop - nextTop;
10
+ element.style.transform = `translate3D(${deltaX}px, ${deltaY}px, 0)`;
11
+ element.style.transition = "";
12
+ window.requestAnimationFrame(() => {
13
+ element.style.transform = "translate3D(0, 0, 0)";
14
+ element.style.transition = "transform 0.1s ease-out";
15
+ });
16
+ element.style.left = `${nextLeft}px`;
17
+ element.style.top = `${nextTop}px`;
18
+ element.style.transition = originalTransition;
19
+ }
20
+
21
+ //#endregion
22
+ export { applySnapAnimation };
23
+ //# sourceMappingURL=animation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.mjs","names":[],"sources":["../../src/helpers/animation.ts"],"sourcesContent":["/**\n * Options for applying snap-back animation\n */\ninterface ApplySnapAnimationOptions {\n element: HTMLElement;\n droppedLeft: number;\n droppedTop: number;\n nextLeft: number;\n nextTop: number;\n originalTransition: string;\n}\n\n/**\n * Applies snap-back animation to element\n * Smoothly animates the element from its dropped position to the snapped grid position\n */\nexport function applySnapAnimation(options: ApplySnapAnimationOptions): void {\n const { element, droppedLeft, droppedTop, nextLeft, nextTop, originalTransition } = options;\n\n const deltaX = droppedLeft - nextLeft;\n const deltaY = droppedTop - nextTop;\n\n element.style.transform = `translate3D(${deltaX}px, ${deltaY}px, 0)`;\n element.style.transition = \"\";\n\n window.requestAnimationFrame(() => {\n element.style.transform = \"translate3D(0, 0, 0)\";\n element.style.transition = \"transform 0.1s ease-out\";\n });\n\n element.style.left = `${nextLeft}px`;\n element.style.top = `${nextTop}px`;\n element.style.transition = originalTransition;\n}\n"],"mappings":";;;;;AAgBA,SAAgB,mBAAmB,SAA0C;CAC3E,MAAM,EAAE,SAAS,aAAa,YAAY,UAAU,SAAS,uBAAuB;CAEpF,MAAM,SAAS,cAAc;CAC7B,MAAM,SAAS,aAAa;AAE5B,SAAQ,MAAM,YAAY,eAAe,OAAO,MAAM,OAAO;AAC7D,SAAQ,MAAM,aAAa;AAE3B,QAAO,4BAA4B;AACjC,UAAQ,MAAM,YAAY;AAC1B,UAAQ,MAAM,aAAa;GAC3B;AAEF,SAAQ,MAAM,OAAO,GAAG,SAAS;AACjC,SAAQ,MAAM,MAAM,GAAG,QAAQ;AAC/B,SAAQ,MAAM,aAAa"}
@@ -0,0 +1,76 @@
1
+
2
+ //#region src/helpers/gridCalculations.ts
3
+ /**
4
+ * Converts a pixel value to grid units by dividing by the cell size (baseSize + gap)
5
+ * and rounding up with Math.ceil. Ensures the result is at least 1 and does not exceed available space.
6
+ * When columnCount and xPosition are provided, ensures x + width <= columnCount.
7
+ *
8
+ * ピクセル値をグリッド単位に変換します。セルサイズ (baseSize + gap) で割り、小数点は切り上げて整数にします。
9
+ * 結果は最小1で、columnCountとxPositionが指定された場合はx + width <= columnCountを満たすように制限されます。
10
+ */
11
+ function pixelsToGridSize(pixels, baseSize, gap, columnCount, xPosition) {
12
+ const gridSize = Math.ceil(pixels / (baseSize + gap));
13
+ const constrainedSize = Math.max(1, gridSize);
14
+ if (columnCount !== void 0 && xPosition !== void 0) {
15
+ const maxWidth = Math.max(1, columnCount - xPosition);
16
+ return Math.min(constrainedSize, maxWidth);
17
+ }
18
+ if (columnCount !== void 0) return Math.min(constrainedSize, columnCount);
19
+ return constrainedSize;
20
+ }
21
+ /**
22
+ * Converts a pixel coordinate to grid coordinate by dividing by the cell size
23
+ * and rounding down with Math.floor, ensuring the result is not negative and does not cause overflow.
24
+ * When columnCount and width are provided, ensures x + width <= columnCount
25
+ *
26
+ * ピクセル座標をグリッド座標に変換します。セルサイズで割り、小数点は切り捨てて整数にします。
27
+ * 結果が負にならず、columnCountとwidthが指定された場合はx + width <= columnCountを満たすようにします。
28
+ */
29
+ function pixelsToGridPosition(pixels, baseSize, gap, columnCount, width) {
30
+ const gridPosition = Math.max(0, Math.floor(pixels / (baseSize + gap)));
31
+ if (columnCount !== void 0 && width !== void 0) {
32
+ const maxPosition = Math.max(0, columnCount - width);
33
+ return Math.min(gridPosition, maxPosition);
34
+ }
35
+ if (columnCount !== void 0) return Math.min(gridPosition, columnCount - 1);
36
+ return gridPosition;
37
+ }
38
+ /**
39
+ * Converts grid units to pixels
40
+ * Formula: gridUnits * baseSize + max(0, gridUnits - 1) * gap
41
+ * This accounts for gaps between grid cells but not after the last cell
42
+ *
43
+ * グリッド単位をピクセルに変換します。
44
+ * 計算式: gridUnits * baseSize + max(0, gridUnits - 1) * gap
45
+ * グリッドセル間の gap を考慮しますが、最後のセルの後には gap を含めません。
46
+ */
47
+ function gridToPixels(gridUnits, baseSize, gap) {
48
+ return gridUnits * baseSize + Math.max(0, gridUnits - 1) * gap;
49
+ }
50
+ /**
51
+ * Converts grid coordinate to pixel coordinate for positioning
52
+ * Formula: max(0, gridCoord * (baseSize + gap))
53
+ * This includes the gap after each cell for proper positioning in the grid
54
+ *
55
+ * グリッド座標をピクセル座標に変換します(位置計算用)。
56
+ * 計算式: max(0, gridCoord * (baseSize + gap))
57
+ * 各セルの後に gap を含めて、グリッド内での適切な位置決めを行います。
58
+ */
59
+ function gridPositionToPixels(gridCoord, baseSize, gap) {
60
+ return Math.max(0, gridCoord * (baseSize + gap));
61
+ }
62
+ /**
63
+ * Gets the maximum Y coordinate of the panels
64
+ * パネルの最大Y座標を取得します。
65
+ */
66
+ function getGridRowCount(panels) {
67
+ return Math.max(...panels.map((p) => p.y + p.h));
68
+ }
69
+
70
+ //#endregion
71
+ exports.getGridRowCount = getGridRowCount;
72
+ exports.gridPositionToPixels = gridPositionToPixels;
73
+ exports.gridToPixels = gridToPixels;
74
+ exports.pixelsToGridPosition = pixelsToGridPosition;
75
+ exports.pixelsToGridSize = pixelsToGridSize;
76
+ //# sourceMappingURL=gridCalculations.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gridCalculations.cjs","names":[],"sources":["../../src/helpers/gridCalculations.ts"],"sourcesContent":["import type { PanelCoordinate } from \"../types\";\n\n/**\n * Converts a pixel value to grid units by dividing by the cell size (baseSize + gap)\n * and rounding up with Math.ceil. Ensures the result is at least 1 and does not exceed available space.\n * When columnCount and xPosition are provided, ensures x + width <= columnCount.\n *\n * ピクセル値をグリッド単位に変換します。セルサイズ (baseSize + gap) で割り、小数点は切り上げて整数にします。\n * 結果は最小1で、columnCountとxPositionが指定された場合はx + width <= columnCountを満たすように制限されます。\n */\nexport function pixelsToGridSize(\n pixels: number,\n baseSize: number,\n gap: number,\n columnCount?: number,\n xPosition?: number\n): number {\n const gridSize = Math.ceil(pixels / (baseSize + gap));\n const constrainedSize = Math.max(1, gridSize);\n\n if (columnCount !== undefined && xPosition !== undefined) {\n // Ensure x + width <= columnCount\n const maxWidth = Math.max(1, columnCount - xPosition);\n return Math.min(constrainedSize, maxWidth);\n }\n\n if (columnCount !== undefined) {\n // Legacy behavior: constrain to columnCount\n return Math.min(constrainedSize, columnCount);\n }\n\n return constrainedSize;\n}\n\n/**\n * Converts a pixel coordinate to grid coordinate by dividing by the cell size\n * and rounding down with Math.floor, ensuring the result is not negative and does not cause overflow.\n * When columnCount and width are provided, ensures x + width <= columnCount\n *\n * ピクセル座標をグリッド座標に変換します。セルサイズで割り、小数点は切り捨てて整数にします。\n * 結果が負にならず、columnCountとwidthが指定された場合はx + width <= columnCountを満たすようにします。\n */\nexport function pixelsToGridPosition(\n pixels: number,\n baseSize: number,\n gap: number,\n columnCount?: number,\n width?: number\n): number {\n const gridPosition = Math.max(0, Math.floor(pixels / (baseSize + gap)));\n\n if (columnCount !== undefined && width !== undefined) {\n // Ensure x + width <= columnCount\n const maxPosition = Math.max(0, columnCount - width);\n return Math.min(gridPosition, maxPosition);\n }\n\n if (columnCount !== undefined) {\n // Legacy behavior: constrain to columnCount - 1\n return Math.min(gridPosition, columnCount - 1);\n }\n\n return gridPosition;\n}\n\n/**\n * Converts grid units to pixels\n * Formula: gridUnits * baseSize + max(0, gridUnits - 1) * gap\n * This accounts for gaps between grid cells but not after the last cell\n *\n * グリッド単位をピクセルに変換します。\n * 計算式: gridUnits * baseSize + max(0, gridUnits - 1) * gap\n * グリッドセル間の gap を考慮しますが、最後のセルの後には gap を含めません。\n */\nexport function gridToPixels(gridUnits: number, baseSize: number, gap: number): number {\n return gridUnits * baseSize + Math.max(0, gridUnits - 1) * gap;\n}\n\n/**\n * Converts grid coordinate to pixel coordinate for positioning\n * Formula: max(0, gridCoord * (baseSize + gap))\n * This includes the gap after each cell for proper positioning in the grid\n *\n * グリッド座標をピクセル座標に変換します(位置計算用)。\n * 計算式: max(0, gridCoord * (baseSize + gap))\n * 各セルの後に gap を含めて、グリッド内での適切な位置決めを行います。\n */\nexport function gridPositionToPixels(gridCoord: number, baseSize: number, gap: number): number {\n return Math.max(0, gridCoord * (baseSize + gap));\n}\n\n/**\n * Snaps a pixel value to the nearest grid position\n * Useful for aligning elements to the grid after drag/resize operations\n *\n * ピクセル値を最も近いグリッド位置にスナップします。\n * ドラッグ・リサイズ操作後に要素をグリッドに整列させる際に利用する。\n */\nexport function snapToGrid(pixels: number, baseSize: number, gap: number): number {\n const gridPosition = pixelsToGridPosition(pixels, baseSize, gap);\n return gridPositionToPixels(gridPosition, baseSize, gap);\n}\n\n/**\n * Gets the maximum Y coordinate of the panels\n * パネルの最大Y座標を取得します。\n */\nexport function getGridRowCount(panels: PanelCoordinate[]): number {\n return Math.max(...panels.map((p) => p.y + p.h));\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,iBACd,QACA,UACA,KACA,aACA,WACQ;CACR,MAAM,WAAW,KAAK,KAAK,UAAU,WAAW,KAAK;CACrD,MAAM,kBAAkB,KAAK,IAAI,GAAG,SAAS;AAE7C,KAAI,gBAAgB,UAAa,cAAc,QAAW;EAExD,MAAM,WAAW,KAAK,IAAI,GAAG,cAAc,UAAU;AACrD,SAAO,KAAK,IAAI,iBAAiB,SAAS;;AAG5C,KAAI,gBAAgB,OAElB,QAAO,KAAK,IAAI,iBAAiB,YAAY;AAG/C,QAAO;;;;;;;;;;AAWT,SAAgB,qBACd,QACA,UACA,KACA,aACA,OACQ;CACR,MAAM,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,WAAW,KAAK,CAAC;AAEvE,KAAI,gBAAgB,UAAa,UAAU,QAAW;EAEpD,MAAM,cAAc,KAAK,IAAI,GAAG,cAAc,MAAM;AACpD,SAAO,KAAK,IAAI,cAAc,YAAY;;AAG5C,KAAI,gBAAgB,OAElB,QAAO,KAAK,IAAI,cAAc,cAAc,EAAE;AAGhD,QAAO;;;;;;;;;;;AAYT,SAAgB,aAAa,WAAmB,UAAkB,KAAqB;AACrF,QAAO,YAAY,WAAW,KAAK,IAAI,GAAG,YAAY,EAAE,GAAG;;;;;;;;;;;AAY7D,SAAgB,qBAAqB,WAAmB,UAAkB,KAAqB;AAC7F,QAAO,KAAK,IAAI,GAAG,aAAa,WAAW,KAAK;;;;;;AAmBlD,SAAgB,gBAAgB,QAAmC;AACjE,QAAO,KAAK,IAAI,GAAG,OAAO,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC"}
@@ -0,0 +1,71 @@
1
+ //#region src/helpers/gridCalculations.ts
2
+ /**
3
+ * Converts a pixel value to grid units by dividing by the cell size (baseSize + gap)
4
+ * and rounding up with Math.ceil. Ensures the result is at least 1 and does not exceed available space.
5
+ * When columnCount and xPosition are provided, ensures x + width <= columnCount.
6
+ *
7
+ * ピクセル値をグリッド単位に変換します。セルサイズ (baseSize + gap) で割り、小数点は切り上げて整数にします。
8
+ * 結果は最小1で、columnCountとxPositionが指定された場合はx + width <= columnCountを満たすように制限されます。
9
+ */
10
+ function pixelsToGridSize(pixels, baseSize, gap, columnCount, xPosition) {
11
+ const gridSize = Math.ceil(pixels / (baseSize + gap));
12
+ const constrainedSize = Math.max(1, gridSize);
13
+ if (columnCount !== void 0 && xPosition !== void 0) {
14
+ const maxWidth = Math.max(1, columnCount - xPosition);
15
+ return Math.min(constrainedSize, maxWidth);
16
+ }
17
+ if (columnCount !== void 0) return Math.min(constrainedSize, columnCount);
18
+ return constrainedSize;
19
+ }
20
+ /**
21
+ * Converts a pixel coordinate to grid coordinate by dividing by the cell size
22
+ * and rounding down with Math.floor, ensuring the result is not negative and does not cause overflow.
23
+ * When columnCount and width are provided, ensures x + width <= columnCount
24
+ *
25
+ * ピクセル座標をグリッド座標に変換します。セルサイズで割り、小数点は切り捨てて整数にします。
26
+ * 結果が負にならず、columnCountとwidthが指定された場合はx + width <= columnCountを満たすようにします。
27
+ */
28
+ function pixelsToGridPosition(pixels, baseSize, gap, columnCount, width) {
29
+ const gridPosition = Math.max(0, Math.floor(pixels / (baseSize + gap)));
30
+ if (columnCount !== void 0 && width !== void 0) {
31
+ const maxPosition = Math.max(0, columnCount - width);
32
+ return Math.min(gridPosition, maxPosition);
33
+ }
34
+ if (columnCount !== void 0) return Math.min(gridPosition, columnCount - 1);
35
+ return gridPosition;
36
+ }
37
+ /**
38
+ * Converts grid units to pixels
39
+ * Formula: gridUnits * baseSize + max(0, gridUnits - 1) * gap
40
+ * This accounts for gaps between grid cells but not after the last cell
41
+ *
42
+ * グリッド単位をピクセルに変換します。
43
+ * 計算式: gridUnits * baseSize + max(0, gridUnits - 1) * gap
44
+ * グリッドセル間の gap を考慮しますが、最後のセルの後には gap を含めません。
45
+ */
46
+ function gridToPixels(gridUnits, baseSize, gap) {
47
+ return gridUnits * baseSize + Math.max(0, gridUnits - 1) * gap;
48
+ }
49
+ /**
50
+ * Converts grid coordinate to pixel coordinate for positioning
51
+ * Formula: max(0, gridCoord * (baseSize + gap))
52
+ * This includes the gap after each cell for proper positioning in the grid
53
+ *
54
+ * グリッド座標をピクセル座標に変換します(位置計算用)。
55
+ * 計算式: max(0, gridCoord * (baseSize + gap))
56
+ * 各セルの後に gap を含めて、グリッド内での適切な位置決めを行います。
57
+ */
58
+ function gridPositionToPixels(gridCoord, baseSize, gap) {
59
+ return Math.max(0, gridCoord * (baseSize + gap));
60
+ }
61
+ /**
62
+ * Gets the maximum Y coordinate of the panels
63
+ * パネルの最大Y座標を取得します。
64
+ */
65
+ function getGridRowCount(panels) {
66
+ return Math.max(...panels.map((p) => p.y + p.h));
67
+ }
68
+
69
+ //#endregion
70
+ export { getGridRowCount, gridPositionToPixels, gridToPixels, pixelsToGridPosition, pixelsToGridSize };
71
+ //# sourceMappingURL=gridCalculations.mjs.map