@pihanga2/shadcn 0.2.17 → 0.2.18
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 +3 -1
- package/cards/resizableColumns/index.js +12 -0
- package/cards/resizableColumns/index.js.map +1 -0
- package/cards/resizableColumns/resizableColumns.component.js +105 -0
- package/cards/resizableColumns/resizableColumns.component.js.map +1 -0
- package/cards/resizableColumns/resizableColumns.css +1 -0
- package/cards/resizableColumns/resizableColumns.types.js +7 -0
- package/cards/resizableColumns/resizableColumns.types.js.map +1 -0
- package/cards/resizableGrid/index.js +12 -0
- package/cards/resizableGrid/index.js.map +1 -0
- package/cards/resizableGrid/resizableGrid.component.js +166 -0
- package/cards/resizableGrid/resizableGrid.component.js.map +1 -0
- package/cards/resizableGrid/resizableGrid.css +1 -0
- package/cards/resizableGrid/resizableGrid.types.js +7 -0
- package/cards/resizableGrid/resizableGrid.types.js.map +1 -0
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
## Included cards (
|
|
65
|
+
## Included cards (47)
|
|
66
66
|
|
|
67
67
|
- `avatar`
|
|
68
68
|
- `badge`
|
|
@@ -95,6 +95,8 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
95
95
|
- `pageWithNavbarMeta`
|
|
96
96
|
- `pasteTarget`
|
|
97
97
|
- `resizable`
|
|
98
|
+
- `resizableColumns`
|
|
99
|
+
- `resizableGrid`
|
|
98
100
|
- `scrollbarWithAnnotations`
|
|
99
101
|
- `select`
|
|
100
102
|
- `sheetCard`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResizableColumnsComponent as e } from "./resizableColumns.component.js";
|
|
2
|
+
import { RESIZABLE_COLUMNS_CARD as t, ResizableColumns as n } from "./resizableColumns.types.js";
|
|
3
|
+
import { registerCardComponent as r } from "@pihanga2/core";
|
|
4
|
+
//#region src/cards/resizableColumns/index.ts
|
|
5
|
+
r({
|
|
6
|
+
name: t,
|
|
7
|
+
component: e
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { t as RESIZABLE_COLUMNS_CARD, n as ResizableColumns };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/resizableColumns/index.ts"],"sourcesContent":["import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {ResizableColumnsComponent} from \"./resizableColumns.component\";\nimport {RESIZABLE_COLUMNS_CARD} from \"./resizableColumns.types\";\n\nexport * from \"./resizableColumns.types\";\n\nregisterCardComponent({\n name: RESIZABLE_COLUMNS_CARD,\n component: ResizableColumnsComponent,\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import './resizableColumns.css';/* empty css */
|
|
2
|
+
import * as e from "react";
|
|
3
|
+
import { Card as t } from "@pihanga2/core";
|
|
4
|
+
import n from "clsx";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
//#region src/cards/resizableColumns/resizableColumns.component.tsx
|
|
7
|
+
var a = 10;
|
|
8
|
+
function o(e, t, n) {
|
|
9
|
+
if (!e?.length || e.length !== t) return Array(t).fill(100 / t);
|
|
10
|
+
let r = e.map((e) => {
|
|
11
|
+
let t = e.trim();
|
|
12
|
+
return t.endsWith("px") ? {
|
|
13
|
+
type: "px",
|
|
14
|
+
value: Math.max(0, parseFloat(t))
|
|
15
|
+
} : t.endsWith("%") ? {
|
|
16
|
+
type: "pct",
|
|
17
|
+
value: Math.max(0, parseFloat(t))
|
|
18
|
+
} : t.endsWith("fr") ? {
|
|
19
|
+
type: "fr",
|
|
20
|
+
value: Math.max(0, parseFloat(t))
|
|
21
|
+
} : {
|
|
22
|
+
type: "fr",
|
|
23
|
+
value: 1
|
|
24
|
+
};
|
|
25
|
+
}), i = n > 0 ? r.reduce((e, t) => e + (t.type === "px" ? t.value / n * 100 : 0), 0) : 0, a = r.reduce((e, t) => e + (t.type === "pct" ? t.value : 0), 0), o = Math.max(0, 100 - i - a), s = r.reduce((e, t) => e + (t.type === "fr" ? t.value : 0), 0), c = r.map((e) => e.type === "px" ? n > 0 ? e.value / n * 100 : 100 / t : e.type === "pct" ? e.value : s > 0 ? e.value / s * o : o / t), l = c.reduce((e, t) => e + t, 0);
|
|
26
|
+
return l > 0 ? c.map((e) => e / l * 100) : Array(t).fill(100 / t);
|
|
27
|
+
}
|
|
28
|
+
var s = (e, t, n) => Math.min(n, Math.max(t, e)), c = (c) => {
|
|
29
|
+
let { cardName: l, columnCards: u = [], columnWidths: d, minColumnPercent: f = a, className: p, dividerClassName: m } = c, h = u.length, [g, _] = e.useState(() => Array(h).fill(100 / h)), v = e.useRef(g), y = e.useRef(null), b = e.useRef(null);
|
|
30
|
+
e.useLayoutEffect(() => {
|
|
31
|
+
if (!y.current) return;
|
|
32
|
+
let e = y.current.getBoundingClientRect().width, t = o(d, h, e);
|
|
33
|
+
v.current = t, _(t);
|
|
34
|
+
}, [d, h]), e.useEffect(() => () => {
|
|
35
|
+
b.current?.();
|
|
36
|
+
}, []);
|
|
37
|
+
let x = (e, t) => ({
|
|
38
|
+
min: f,
|
|
39
|
+
max: t[e] + t[e + 1] - f
|
|
40
|
+
}), S = e.useCallback((e, t) => {
|
|
41
|
+
let n = v.current, r = n[e] + n[e + 1], { min: i, max: a } = x(e, n), o = s(t, i, a), c = [...n];
|
|
42
|
+
c[e] = o, c[e + 1] = r - o, v.current = c, _(c);
|
|
43
|
+
}, [f]), C = e.useCallback((e) => (t) => {
|
|
44
|
+
t.preventDefault();
|
|
45
|
+
let n = t.clientX, r = v.current[e], i = y.current;
|
|
46
|
+
if (!i) return;
|
|
47
|
+
let { width: a } = i.getBoundingClientRect();
|
|
48
|
+
if (a <= 0) return;
|
|
49
|
+
let o = (t) => {
|
|
50
|
+
S(e, r + (t.clientX - n) / a * 100);
|
|
51
|
+
}, s = () => {
|
|
52
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s), b.current = null;
|
|
53
|
+
};
|
|
54
|
+
b.current?.(), window.addEventListener("mousemove", o), window.addEventListener("mouseup", s), b.current = () => {
|
|
55
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s);
|
|
56
|
+
};
|
|
57
|
+
}, [S]), w = e.useCallback((e) => (t) => {
|
|
58
|
+
let { min: n, max: r } = x(e, v.current), i = v.current[e];
|
|
59
|
+
switch (t.key) {
|
|
60
|
+
case "ArrowLeft":
|
|
61
|
+
t.preventDefault(), S(e, i + (t.shiftKey ? -10 : -2));
|
|
62
|
+
break;
|
|
63
|
+
case "ArrowRight":
|
|
64
|
+
t.preventDefault(), S(e, i + (t.shiftKey ? 10 : 2));
|
|
65
|
+
break;
|
|
66
|
+
case "Home":
|
|
67
|
+
t.preventDefault(), S(e, n);
|
|
68
|
+
break;
|
|
69
|
+
case "End":
|
|
70
|
+
t.preventDefault(), S(e, r);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}, [S]);
|
|
74
|
+
return h === 0 ? null : /* @__PURE__ */ r("div", {
|
|
75
|
+
ref: y,
|
|
76
|
+
"data-pihanga": l,
|
|
77
|
+
className: n("pi-resizable-columns", p),
|
|
78
|
+
children: u.map((a, o) => {
|
|
79
|
+
let s = g[o] ?? 100 / h;
|
|
80
|
+
return /* @__PURE__ */ i(e.Fragment, { children: [o > 0 && /* @__PURE__ */ r("div", {
|
|
81
|
+
className: n("pi-resizable-columns-divider", m),
|
|
82
|
+
onMouseDown: C(o - 1),
|
|
83
|
+
onKeyDown: w(o - 1),
|
|
84
|
+
role: "separator",
|
|
85
|
+
"aria-orientation": "vertical",
|
|
86
|
+
"aria-label": `Resize columns ${o} and ${o + 1}`,
|
|
87
|
+
"aria-valuemin": f,
|
|
88
|
+
"aria-valuemax": (g[o - 1] ?? 0) + (g[o] ?? 0) - f,
|
|
89
|
+
"aria-valuenow": Math.round(g[o - 1] ?? 0),
|
|
90
|
+
tabIndex: 0
|
|
91
|
+
}), /* @__PURE__ */ r("div", {
|
|
92
|
+
className: "pi-resizable-columns-pane",
|
|
93
|
+
style: { width: `${s}%` },
|
|
94
|
+
children: /* @__PURE__ */ r(t, {
|
|
95
|
+
cardName: a,
|
|
96
|
+
parentCard: l
|
|
97
|
+
})
|
|
98
|
+
})] }, o);
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { c as ResizableColumnsComponent };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=resizableColumns.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizableColumns.component.js","names":[],"sources":["../../../src/cards/resizableColumns/resizableColumns.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport clsx from \"clsx\";\n\nimport \"./resizableColumns.css\";\nimport type {ResizableColumnsProps} from \"./resizableColumns.types\";\n\nconst DEFAULT_MIN_PERCENT = 10;\n\ntype ParsedUnit = {type: \"px\" | \"pct\" | \"fr\"; value: number};\n\nfunction parseColumnWidths(\n widths: string[] | undefined,\n count: number,\n containerPx: number,\n): number[] {\n if (!widths?.length || widths.length !== count) {\n return new Array(count).fill(100 / count);\n }\n\n const parsed: ParsedUnit[] = widths.map((w) => {\n const s = w.trim();\n if (s.endsWith(\"px\"))\n return {type: \"px\", value: Math.max(0, parseFloat(s))};\n if (s.endsWith(\"%\"))\n return {type: \"pct\", value: Math.max(0, parseFloat(s))};\n if (s.endsWith(\"fr\"))\n return {type: \"fr\", value: Math.max(0, parseFloat(s))};\n return {type: \"fr\", value: 1};\n });\n\n const totalPxAsPct =\n containerPx > 0\n ? parsed.reduce(\n (s, p) => s + (p.type === \"px\" ? (p.value / containerPx) * 100 : 0),\n 0,\n )\n : 0;\n const totalExplicitPct = parsed.reduce(\n (s, p) => s + (p.type === \"pct\" ? p.value : 0),\n 0,\n );\n const remainingPct = Math.max(0, 100 - totalPxAsPct - totalExplicitPct);\n const totalFr = parsed.reduce(\n (s, p) => s + (p.type === \"fr\" ? p.value : 0),\n 0,\n );\n\n const result = parsed.map((p) => {\n if (p.type === \"px\")\n return containerPx > 0 ? (p.value / containerPx) * 100 : 100 / count;\n if (p.type === \"pct\") return p.value;\n return totalFr > 0\n ? (p.value / totalFr) * remainingPct\n : remainingPct / count;\n });\n\n const total = result.reduce((s, v) => s + v, 0);\n return total > 0\n ? result.map((v) => (v / total) * 100)\n : new Array(count).fill(100 / count);\n}\n\nconst clamp = (v: number, min: number, max: number) =>\n Math.min(max, Math.max(min, v));\n\nexport const ResizableColumnsComponent = (\n props: PiCardProps<ResizableColumnsProps>,\n): React.ReactNode => {\n const {\n cardName,\n columnCards = [],\n columnWidths,\n minColumnPercent = DEFAULT_MIN_PERCENT,\n className,\n dividerClassName,\n } = props;\n\n const count = columnCards.length;\n\n // Equal split as the initial state — useLayoutEffect overwrites before paint.\n const [panePercents, setPanePercents] = React.useState<number[]>(() =>\n new Array(count).fill(100 / count),\n );\n const panePercentsRef = React.useRef(panePercents);\n const containerRef = React.useRef<HTMLDivElement | null>(null);\n const dragCleanupRef = React.useRef<(() => void) | null>(null);\n\n // Parse columnWidths once the container is mounted so px values can be resolved.\n React.useLayoutEffect(() => {\n if (!containerRef.current) return;\n const width = containerRef.current.getBoundingClientRect().width;\n const next = parseColumnWidths(columnWidths, count, width);\n panePercentsRef.current = next;\n setPanePercents(next);\n }, [columnWidths, count]);\n\n // Cleanup any in-progress drag on unmount.\n React.useEffect(() => {\n return () => {\n dragCleanupRef.current?.();\n };\n }, []);\n\n const getDividerBounds = (dividerIndex: number, percents: number[]) => {\n const combined = percents[dividerIndex] + percents[dividerIndex + 1];\n return {min: minColumnPercent, max: combined - minColumnPercent};\n };\n\n const updatePanePair = React.useCallback(\n (dividerIndex: number, nextLeadingPercent: number) => {\n const current = panePercentsRef.current;\n const combined = current[dividerIndex] + current[dividerIndex + 1];\n const {min, max} = getDividerBounds(dividerIndex, current);\n const clamped = clamp(nextLeadingPercent, min, max);\n const next = [...current];\n next[dividerIndex] = clamped;\n next[dividerIndex + 1] = combined - clamped;\n panePercentsRef.current = next;\n setPanePercents(next);\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [minColumnPercent],\n );\n\n const handleMouseDown = React.useCallback(\n (dividerIndex: number) => (event: React.MouseEvent<HTMLDivElement>) => {\n event.preventDefault();\n const startX = event.clientX;\n const startLeadingPercent = panePercentsRef.current[dividerIndex];\n const container = containerRef.current;\n if (!container) return;\n const {width} = container.getBoundingClientRect();\n if (width <= 0) return;\n\n const onMouseMove = (e: MouseEvent) => {\n const deltaPercent = ((e.clientX - startX) / width) * 100;\n updatePanePair(dividerIndex, startLeadingPercent + deltaPercent);\n };\n const onMouseUp = () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n dragCleanupRef.current = null;\n };\n\n dragCleanupRef.current?.();\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mouseup\", onMouseUp);\n dragCleanupRef.current = () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mouseup\", onMouseUp);\n };\n },\n [updatePanePair],\n );\n\n const handleKeyDown = React.useCallback(\n (dividerIndex: number) => (event: React.KeyboardEvent<HTMLDivElement>) => {\n const {min, max} = getDividerBounds(\n dividerIndex,\n panePercentsRef.current,\n );\n const current = panePercentsRef.current[dividerIndex];\n switch (event.key) {\n case \"ArrowLeft\":\n event.preventDefault();\n updatePanePair(dividerIndex, current + (event.shiftKey ? -10 : -2));\n break;\n case \"ArrowRight\":\n event.preventDefault();\n updatePanePair(dividerIndex, current + (event.shiftKey ? 10 : 2));\n break;\n case \"Home\":\n event.preventDefault();\n updatePanePair(dividerIndex, min);\n break;\n case \"End\":\n event.preventDefault();\n updatePanePair(dividerIndex, max);\n break;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [updatePanePair],\n );\n\n if (count === 0) return null;\n\n return (\n <div\n ref={containerRef}\n data-pihanga={cardName}\n className={clsx(\"pi-resizable-columns\", className)}\n >\n {columnCards.map((card, i) => {\n const pct = panePercents[i] ?? 100 / count;\n return (\n <React.Fragment key={i}>\n {i > 0 && (\n <div\n className={clsx(\n \"pi-resizable-columns-divider\",\n dividerClassName,\n )}\n onMouseDown={handleMouseDown(i - 1)}\n onKeyDown={handleKeyDown(i - 1)}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize columns ${i} and ${i + 1}`}\n aria-valuemin={minColumnPercent}\n aria-valuemax={\n (panePercents[i - 1] ?? 0) +\n (panePercents[i] ?? 0) -\n minColumnPercent\n }\n aria-valuenow={Math.round(panePercents[i - 1] ?? 0)}\n tabIndex={0}\n />\n )}\n <div\n className=\"pi-resizable-columns-pane\"\n style={{width: `${pct}%`}}\n >\n <Card cardName={card} parentCard={cardName} />\n </div>\n </React.Fragment>\n );\n })}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.pi-resizable-columns{flex-direction:row;width:100%;min-height:100%;display:flex;overflow:hidden}.pi-resizable-columns-pane{flex-shrink:0;min-width:0;overflow:hidden}.pi-resizable-columns-divider{cursor:col-resize;flex:0 0 8px;position:relative}.pi-resizable-columns-divider:before{content:"";width:var(--rg-divider-width,1px);background-color:var(--rg-divider-color,hsl(var(--border,214 32% 91%)));transition:width .12s,background-color .12s;position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%)}.pi-resizable-columns-divider:hover:before,.pi-resizable-columns-divider:focus-visible:before{width:var(--rg-divider-hover-width,4px);background-color:var(--rg-divider-hover-color,hsl(var(--muted-foreground,215 16% 47%)))}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCardDeclaration as e } from "@pihanga2/core";
|
|
2
|
+
//#region src/cards/resizableColumns/resizableColumns.types.ts
|
|
3
|
+
var t = "pi/resizable-columns", n = e(t);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { t as RESIZABLE_COLUMNS_CARD, n as ResizableColumns };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=resizableColumns.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizableColumns.types.js","names":[],"sources":["../../../src/cards/resizableColumns/resizableColumns.types.ts"],"sourcesContent":["import {createCardDeclaration, type PiCardRef} from \"@pihanga2/core\";\n\nexport const RESIZABLE_COLUMNS_CARD = \"pi/resizable-columns\";\n\nexport type ResizableColumnsProps = {\n columnCards: PiCardRef[];\n /**\n * Initial column widths. Supports CSS-like values:\n * - '200px' — fixed initial width\n * - '30%' — explicit percentage\n * - '1fr' — fraction of remaining space (after px/% columns)\n *\n * Defaults to equal split when omitted or when length doesn't match columnCards.\n * @example ['200px', '1fr', '1fr'] — fixed sidebar, two equal remaining columns\n * @example ['30%', '70%']\n * @example ['1fr', '2fr', '1fr']\n */\n columnWidths?: string[];\n /** Minimum percentage any column can shrink to during drag. Default: 10 */\n minColumnPercent?: number;\n className?: string;\n dividerClassName?: string;\n};\n\nexport const ResizableColumns = createCardDeclaration<ResizableColumnsProps>(\n RESIZABLE_COLUMNS_CARD,\n);\n"],"mappings":";;AAEA,IAAa,IAAyB,wBAsBzB,IAAmB,EAC9B,CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ResizableGridComponent as e } from "./resizableGrid.component.js";
|
|
2
|
+
import { RESIZABLE_GRID_CARD as t, ResizableGrid as n } from "./resizableGrid.types.js";
|
|
3
|
+
import { registerCardComponent as r } from "@pihanga2/core";
|
|
4
|
+
//#region src/cards/resizableGrid/index.ts
|
|
5
|
+
r({
|
|
6
|
+
name: t,
|
|
7
|
+
component: e
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { t as RESIZABLE_GRID_CARD, n as ResizableGrid };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/resizableGrid/index.ts"],"sourcesContent":["import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {ResizableGridComponent} from \"./resizableGrid.component\";\nimport {RESIZABLE_GRID_CARD} from \"./resizableGrid.types\";\n\nexport * from \"./resizableGrid.types\";\n\nregisterCardComponent({\n name: RESIZABLE_GRID_CARD,\n component: ResizableGridComponent,\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import './resizableGrid.css';/* empty css */
|
|
2
|
+
import * as e from "react";
|
|
3
|
+
import { Card as t } from "@pihanga2/core";
|
|
4
|
+
import n from "clsx";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
//#region src/cards/resizableGrid/resizableGrid.component.tsx
|
|
7
|
+
var a = 10, o = 8;
|
|
8
|
+
function s(e) {
|
|
9
|
+
let t = e.trim();
|
|
10
|
+
return t === "auto" ? {
|
|
11
|
+
type: "auto",
|
|
12
|
+
value: 0
|
|
13
|
+
} : t.endsWith("px") ? {
|
|
14
|
+
type: "px",
|
|
15
|
+
value: Math.max(0, parseFloat(t))
|
|
16
|
+
} : t.endsWith("%") ? {
|
|
17
|
+
type: "pct",
|
|
18
|
+
value: Math.max(0, parseFloat(t))
|
|
19
|
+
} : t.endsWith("fr") ? {
|
|
20
|
+
type: "fr",
|
|
21
|
+
value: Math.max(0, parseFloat(t))
|
|
22
|
+
} : {
|
|
23
|
+
type: "fr",
|
|
24
|
+
value: 1
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function c(e, t, n) {
|
|
28
|
+
if (!e?.length || e.length !== t) return Array(t).fill(100 / t);
|
|
29
|
+
let r = e.map(s), i = n > 0 ? r.reduce((e, t) => e + (t.type === "px" ? t.value / n * 100 : 0), 0) : 0, a = r.reduce((e, t) => e + (t.type === "pct" ? t.value : 0), 0), o = Math.max(0, 100 - i - a), c = r.reduce((e, t) => e + (t.type === "fr" ? t.value : 0), 0), l = r.map((e) => e.type === "auto" ? 0 : e.type === "px" ? n > 0 ? e.value / n * 100 : 0 : e.type === "pct" ? e.value : c > 0 ? e.value / c * o : 0), u = l.reduce((e, t) => e + t, 0);
|
|
30
|
+
if (u <= 0) {
|
|
31
|
+
let e = r.filter((e) => e.type !== "auto").length || t;
|
|
32
|
+
return r.map((t) => t.type === "auto" ? 0 : 100 / e);
|
|
33
|
+
}
|
|
34
|
+
return l.map((e, t) => r[t].type === "auto" ? 0 : e / u * 100);
|
|
35
|
+
}
|
|
36
|
+
function l(e, t) {
|
|
37
|
+
return e.map((n, r) => {
|
|
38
|
+
let i = n === "auto" ? "auto" : `${t[r]}fr`;
|
|
39
|
+
return r < e.length - 1 && n !== "auto" && e[r + 1] !== "auto" ? `${i} ${o}px` : i;
|
|
40
|
+
}).join(" ");
|
|
41
|
+
}
|
|
42
|
+
function u(e) {
|
|
43
|
+
let t = 1;
|
|
44
|
+
return e.map((n, r) => {
|
|
45
|
+
let i = t;
|
|
46
|
+
return t++, r < e.length - 1 && n !== "auto" && e[r + 1] !== "auto" && t++, i;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function d(e, t, n) {
|
|
50
|
+
return n >= e.length - 1 || e[n] === "auto" || e[n + 1] === "auto" ? null : t[n] + 1;
|
|
51
|
+
}
|
|
52
|
+
var f = (e, t, n) => Math.min(n, Math.max(t, e));
|
|
53
|
+
function p(e, t, n) {
|
|
54
|
+
return (r, i) => {
|
|
55
|
+
let a = e.current, o = a[r] + a[r + 1], s = f(i, Math.min(n, o - n), Math.max(n, o - n)), c = [...a];
|
|
56
|
+
c[r] = s, c[r + 1] = o - s, e.current = c, t(c);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
var m = (o) => {
|
|
60
|
+
let { cardName: s, cells: f = [], columnWidths: m, rowHeights: h, minColumnPercent: g = a, minRowPercent: _ = a, className: v, dividerClassName: y } = o, b = f.length, x = f[0]?.length ?? 0, S = e.useMemo(() => m ?? Array(x).fill("1fr"), [m, x]), C = e.useMemo(() => h ?? Array(b).fill("1fr"), [h, b]), [w, T] = e.useState(() => c(S, x, 0)), [E, D] = e.useState(() => c(C, b, 0)), O = e.useRef(w), k = e.useRef(E), A = e.useRef(null), j = e.useRef(null), M = e.useRef(null);
|
|
61
|
+
e.useLayoutEffect(() => {
|
|
62
|
+
if (!A.current) return;
|
|
63
|
+
let { width: e, height: t } = A.current.getBoundingClientRect(), n = c(S, x, e), r = c(C, b, t);
|
|
64
|
+
O.current = n, k.current = r, T(n), D(r);
|
|
65
|
+
}, [
|
|
66
|
+
S,
|
|
67
|
+
C,
|
|
68
|
+
x,
|
|
69
|
+
b
|
|
70
|
+
]), e.useEffect(() => () => {
|
|
71
|
+
j.current?.(), M.current?.();
|
|
72
|
+
}, []);
|
|
73
|
+
let N = e.useMemo(() => p(O, T, g), [g]), P = e.useMemo(() => p(k, D, _), [_]), F = e.useCallback((e) => (t) => {
|
|
74
|
+
t.preventDefault();
|
|
75
|
+
let n = t.clientX, r = O.current[e], i = A.current;
|
|
76
|
+
if (!i) return;
|
|
77
|
+
let { width: a } = i.getBoundingClientRect();
|
|
78
|
+
if (a <= 0) return;
|
|
79
|
+
let o = (t) => N(e, r + (t.clientX - n) / a * 100), s = () => {
|
|
80
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s), j.current = null;
|
|
81
|
+
};
|
|
82
|
+
j.current?.(), window.addEventListener("mousemove", o), window.addEventListener("mouseup", s), j.current = () => {
|
|
83
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s);
|
|
84
|
+
};
|
|
85
|
+
}, [N]), I = e.useCallback((e) => (t) => {
|
|
86
|
+
let n = O.current[e], r = n + O.current[e + 1], i = t.shiftKey ? 10 : 2;
|
|
87
|
+
t.key === "ArrowLeft" ? (t.preventDefault(), N(e, n - i)) : t.key === "ArrowRight" ? (t.preventDefault(), N(e, n + i)) : t.key === "Home" ? (t.preventDefault(), N(e, g)) : t.key === "End" && (t.preventDefault(), N(e, r - g));
|
|
88
|
+
}, [N, g]), L = e.useCallback((e) => (t) => {
|
|
89
|
+
t.preventDefault();
|
|
90
|
+
let n = t.clientY, r = k.current[e], i = A.current;
|
|
91
|
+
if (!i) return;
|
|
92
|
+
let { height: a } = i.getBoundingClientRect();
|
|
93
|
+
if (a <= 0) return;
|
|
94
|
+
let o = (t) => P(e, r + (t.clientY - n) / a * 100), s = () => {
|
|
95
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s), M.current = null;
|
|
96
|
+
};
|
|
97
|
+
M.current?.(), window.addEventListener("mousemove", o), window.addEventListener("mouseup", s), M.current = () => {
|
|
98
|
+
window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", s);
|
|
99
|
+
};
|
|
100
|
+
}, [P]), R = e.useCallback((e) => (t) => {
|
|
101
|
+
let n = k.current[e], r = n + k.current[e + 1], i = t.shiftKey ? 10 : 2;
|
|
102
|
+
t.key === "ArrowUp" ? (t.preventDefault(), P(e, n - i)) : t.key === "ArrowDown" ? (t.preventDefault(), P(e, n + i)) : t.key === "Home" ? (t.preventDefault(), P(e, _)) : t.key === "End" && (t.preventDefault(), P(e, r - _));
|
|
103
|
+
}, [P, _]);
|
|
104
|
+
if (b === 0 || x === 0) return null;
|
|
105
|
+
let z = l(S, w), B = l(C, E), V = u(S), H = u(C);
|
|
106
|
+
return /* @__PURE__ */ i("div", {
|
|
107
|
+
ref: A,
|
|
108
|
+
"data-pihanga": s,
|
|
109
|
+
className: n("pi-resizable-grid", v),
|
|
110
|
+
style: {
|
|
111
|
+
gridTemplateColumns: z,
|
|
112
|
+
gridTemplateRows: B
|
|
113
|
+
},
|
|
114
|
+
children: [
|
|
115
|
+
f.map((e, n) => e.map((e, i) => /* @__PURE__ */ r("div", {
|
|
116
|
+
className: "pi-resizable-grid-cell",
|
|
117
|
+
style: {
|
|
118
|
+
gridColumn: V[i],
|
|
119
|
+
gridRow: H[n]
|
|
120
|
+
},
|
|
121
|
+
children: /* @__PURE__ */ r(t, {
|
|
122
|
+
cardName: e,
|
|
123
|
+
parentCard: s
|
|
124
|
+
})
|
|
125
|
+
}, `c${n}-${i}`))),
|
|
126
|
+
S.map((e, t) => {
|
|
127
|
+
let i = d(S, V, t);
|
|
128
|
+
return i === null ? null : /* @__PURE__ */ r("div", {
|
|
129
|
+
className: n("pi-resizable-grid-col-divider", y),
|
|
130
|
+
style: {
|
|
131
|
+
gridColumn: i,
|
|
132
|
+
gridRow: "1 / -1"
|
|
133
|
+
},
|
|
134
|
+
onMouseDown: F(t),
|
|
135
|
+
onKeyDown: I(t),
|
|
136
|
+
role: "separator",
|
|
137
|
+
"aria-orientation": "vertical",
|
|
138
|
+
"aria-label": `Resize columns ${t + 1} and ${t + 2}`,
|
|
139
|
+
"aria-valuenow": Math.round(w[t]),
|
|
140
|
+
tabIndex: 0
|
|
141
|
+
}, `cd${t}`);
|
|
142
|
+
}),
|
|
143
|
+
C.map((e, t) => {
|
|
144
|
+
let i = d(C, H, t);
|
|
145
|
+
return i === null ? null : /* @__PURE__ */ r("div", {
|
|
146
|
+
className: n("pi-resizable-grid-row-divider", y),
|
|
147
|
+
style: {
|
|
148
|
+
gridRow: i,
|
|
149
|
+
gridColumn: "1 / -1"
|
|
150
|
+
},
|
|
151
|
+
onMouseDown: L(t),
|
|
152
|
+
onKeyDown: R(t),
|
|
153
|
+
role: "separator",
|
|
154
|
+
"aria-orientation": "horizontal",
|
|
155
|
+
"aria-label": `Resize rows ${t + 1} and ${t + 2}`,
|
|
156
|
+
"aria-valuenow": Math.round(E[t]),
|
|
157
|
+
tabIndex: 0
|
|
158
|
+
}, `rd${t}`);
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
164
|
+
export { m as ResizableGridComponent };
|
|
165
|
+
|
|
166
|
+
//# sourceMappingURL=resizableGrid.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizableGrid.component.js","names":[],"sources":["../../../src/cards/resizableGrid/resizableGrid.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport clsx from \"clsx\";\n\nimport \"./resizableGrid.css\";\nimport type {ResizableGridProps} from \"./resizableGrid.types\";\n\nconst DEFAULT_MIN_PERCENT = 10;\nconst DIVIDER_PX = 8;\n\ntype ParsedUnit = {type: \"px\" | \"pct\" | \"fr\" | \"auto\"; value: number};\n\nfunction parseWidthSpec(w: string): ParsedUnit {\n const s = w.trim();\n if (s === \"auto\") return {type: \"auto\", value: 0};\n if (s.endsWith(\"px\")) return {type: \"px\", value: Math.max(0, parseFloat(s))};\n if (s.endsWith(\"%\")) return {type: \"pct\", value: Math.max(0, parseFloat(s))};\n if (s.endsWith(\"fr\")) return {type: \"fr\", value: Math.max(0, parseFloat(s))};\n return {type: \"fr\", value: 1};\n}\n\n/**\n * Convert CSS-like spec strings to an array of ratio values (summing to 100 for\n * explicit tracks; auto tracks get 0). The ratios are later rendered as `{v}fr`\n * units in the CSS grid template so the browser distributes available space\n * proportionally after fixed tracks (px, dividers) are allocated.\n */\nfunction parseSpecs(\n specs: string[] | undefined,\n count: number,\n containerPx: number,\n): number[] {\n if (!specs?.length || specs.length !== count) {\n return new Array(count).fill(100 / count);\n }\n\n const parsed = specs.map(parseWidthSpec);\n\n const totalPxAsPct =\n containerPx > 0\n ? parsed.reduce(\n (s, p) => s + (p.type === \"px\" ? (p.value / containerPx) * 100 : 0),\n 0,\n )\n : 0;\n const totalExplicitPct = parsed.reduce(\n (s, p) => s + (p.type === \"pct\" ? p.value : 0),\n 0,\n );\n const remainingPct = Math.max(0, 100 - totalPxAsPct - totalExplicitPct);\n const totalFr = parsed.reduce(\n (s, p) => s + (p.type === \"fr\" ? p.value : 0),\n 0,\n );\n\n const raw = parsed.map((p) => {\n if (p.type === \"auto\") return 0;\n if (p.type === \"px\")\n return containerPx > 0 ? (p.value / containerPx) * 100 : 0;\n if (p.type === \"pct\") return p.value;\n return totalFr > 0 ? (p.value / totalFr) * remainingPct : 0;\n });\n\n // Normalise so explicit entries sum to 100 (auto entries stay 0).\n const explicitTotal = raw.reduce((s, v) => s + v, 0);\n if (explicitTotal <= 0) {\n const n = parsed.filter((p) => p.type !== \"auto\").length || count;\n return parsed.map((p) => (p.type === \"auto\" ? 0 : 100 / n));\n }\n return raw.map((v, i) =>\n parsed[i].type === \"auto\" ? 0 : (v / explicitTotal) * 100,\n );\n}\n\n/** Build CSS grid-template-columns / grid-template-rows string. */\nfunction buildTemplate(specs: string[], ratios: number[]): string {\n return specs\n .map((spec, i) => {\n const cell = spec === \"auto\" ? \"auto\" : `${ratios[i]}fr`;\n const addDivider =\n i < specs.length - 1 && spec !== \"auto\" && specs[i + 1] !== \"auto\";\n return addDivider ? `${cell} ${DIVIDER_PX}px` : cell;\n })\n .join(\" \");\n}\n\n/** Compute 1-based CSS grid track index for each cell column/row. */\nfunction computeCellTrackIndices(specs: string[]): number[] {\n let track = 1;\n return specs.map((spec, i) => {\n const idx = track;\n track++;\n if (i < specs.length - 1 && spec !== \"auto\" && specs[i + 1] !== \"auto\") {\n track++; // skip divider track\n }\n return idx;\n });\n}\n\n/**\n * CSS track index of the divider between cell[i] and cell[i+1].\n * Returns null when no divider should be rendered.\n */\nfunction dividerTrack(\n specs: string[],\n cellTracks: number[],\n i: number,\n): number | null {\n if (i >= specs.length - 1) return null;\n if (specs[i] === \"auto\" || specs[i + 1] === \"auto\") return null;\n return cellTracks[i] + 1;\n}\n\nconst clamp = (v: number, lo: number, hi: number) =>\n Math.min(hi, Math.max(lo, v));\n\n/** Update a pair of adjacent explicit tracks, keeping their combined ratio constant. */\nfunction makePairUpdater(\n ref: React.MutableRefObject<number[]>,\n setter: React.Dispatch<React.SetStateAction<number[]>>,\n minPct: number,\n) {\n return (divIdx: number, nextLeading: number) => {\n const curr = ref.current;\n const combined = curr[divIdx] + curr[divIdx + 1];\n const lo = Math.min(minPct, combined - minPct);\n const hi = Math.max(minPct, combined - minPct);\n const clamped = clamp(nextLeading, lo, hi);\n const next = [...curr];\n next[divIdx] = clamped;\n next[divIdx + 1] = combined - clamped;\n ref.current = next;\n setter(next);\n };\n}\n\nexport const ResizableGridComponent = (\n props: PiCardProps<ResizableGridProps>,\n): React.ReactNode => {\n const {\n cardName,\n cells = [],\n columnWidths,\n rowHeights,\n minColumnPercent = DEFAULT_MIN_PERCENT,\n minRowPercent = DEFAULT_MIN_PERCENT,\n className,\n dividerClassName,\n } = props;\n\n const numRows = cells.length;\n const numCols = cells[0]?.length ?? 0;\n\n const colSpecs = React.useMemo(\n () => columnWidths ?? new Array(numCols).fill(\"1fr\"),\n [columnWidths, numCols],\n );\n const rowSpecs = React.useMemo(\n () => rowHeights ?? new Array(numRows).fill(\"1fr\"),\n [rowHeights, numRows],\n );\n\n // Initialise with equal ratios; useLayoutEffect recalculates with real px.\n const [colRatios, setColRatios] = React.useState(() =>\n parseSpecs(colSpecs, numCols, 0),\n );\n const [rowRatios, setRowRatios] = React.useState(() =>\n parseSpecs(rowSpecs, numRows, 0),\n );\n const colRatiosRef = React.useRef(colRatios);\n const rowRatiosRef = React.useRef(rowRatios);\n const containerRef = React.useRef<HTMLDivElement | null>(null);\n const colCleanupRef = React.useRef<(() => void) | null>(null);\n const rowCleanupRef = React.useRef<(() => void) | null>(null);\n\n // Re-parse after mount so px specs can be resolved against actual container size.\n React.useLayoutEffect(() => {\n if (!containerRef.current) return;\n const {width, height} = containerRef.current.getBoundingClientRect();\n const nextCol = parseSpecs(colSpecs, numCols, width);\n const nextRow = parseSpecs(rowSpecs, numRows, height);\n colRatiosRef.current = nextCol;\n rowRatiosRef.current = nextRow;\n setColRatios(nextCol);\n setRowRatios(nextRow);\n }, [colSpecs, rowSpecs, numCols, numRows]);\n\n React.useEffect(\n () => () => {\n colCleanupRef.current?.();\n rowCleanupRef.current?.();\n },\n [],\n );\n\n const updateColPair = React.useMemo(\n () => makePairUpdater(colRatiosRef, setColRatios, minColumnPercent),\n [minColumnPercent],\n );\n const updateRowPair = React.useMemo(\n () => makePairUpdater(rowRatiosRef, setRowRatios, minRowPercent),\n [minRowPercent],\n );\n\n const handleColMouseDown = React.useCallback(\n (divIdx: number) => (e: React.MouseEvent) => {\n e.preventDefault();\n const startX = e.clientX;\n const startLeading = colRatiosRef.current[divIdx];\n const container = containerRef.current;\n if (!container) return;\n const {width} = container.getBoundingClientRect();\n if (width <= 0) return;\n const onMove = (ev: MouseEvent) =>\n updateColPair(\n divIdx,\n startLeading + ((ev.clientX - startX) / width) * 100,\n );\n const onUp = () => {\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n colCleanupRef.current = null;\n };\n colCleanupRef.current?.();\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n colCleanupRef.current = () => {\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n },\n [updateColPair],\n );\n\n const handleColKeyDown = React.useCallback(\n (divIdx: number) => (e: React.KeyboardEvent) => {\n const curr = colRatiosRef.current[divIdx];\n const combined = curr + colRatiosRef.current[divIdx + 1];\n const step = e.shiftKey ? 10 : 2;\n if (e.key === \"ArrowLeft\") {\n e.preventDefault();\n updateColPair(divIdx, curr - step);\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault();\n updateColPair(divIdx, curr + step);\n } else if (e.key === \"Home\") {\n e.preventDefault();\n updateColPair(divIdx, minColumnPercent);\n } else if (e.key === \"End\") {\n e.preventDefault();\n updateColPair(divIdx, combined - minColumnPercent);\n }\n },\n [updateColPair, minColumnPercent],\n );\n\n const handleRowMouseDown = React.useCallback(\n (divIdx: number) => (e: React.MouseEvent) => {\n e.preventDefault();\n const startY = e.clientY;\n const startLeading = rowRatiosRef.current[divIdx];\n const container = containerRef.current;\n if (!container) return;\n const {height} = container.getBoundingClientRect();\n if (height <= 0) return;\n const onMove = (ev: MouseEvent) =>\n updateRowPair(\n divIdx,\n startLeading + ((ev.clientY - startY) / height) * 100,\n );\n const onUp = () => {\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n rowCleanupRef.current = null;\n };\n rowCleanupRef.current?.();\n window.addEventListener(\"mousemove\", onMove);\n window.addEventListener(\"mouseup\", onUp);\n rowCleanupRef.current = () => {\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"mouseup\", onUp);\n };\n },\n [updateRowPair],\n );\n\n const handleRowKeyDown = React.useCallback(\n (divIdx: number) => (e: React.KeyboardEvent) => {\n const curr = rowRatiosRef.current[divIdx];\n const combined = curr + rowRatiosRef.current[divIdx + 1];\n const step = e.shiftKey ? 10 : 2;\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n updateRowPair(divIdx, curr - step);\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault();\n updateRowPair(divIdx, curr + step);\n } else if (e.key === \"Home\") {\n e.preventDefault();\n updateRowPair(divIdx, minRowPercent);\n } else if (e.key === \"End\") {\n e.preventDefault();\n updateRowPair(divIdx, combined - minRowPercent);\n }\n },\n [updateRowPair, minRowPercent],\n );\n\n if (numRows === 0 || numCols === 0) return null;\n\n const colTemplate = buildTemplate(colSpecs, colRatios);\n const rowTemplate = buildTemplate(rowSpecs, rowRatios);\n const colTracks = computeCellTrackIndices(colSpecs);\n const rowTracks = computeCellTrackIndices(rowSpecs);\n\n return (\n <div\n ref={containerRef}\n data-pihanga={cardName}\n className={clsx(\"pi-resizable-grid\", className)}\n style={\n {\n gridTemplateColumns: colTemplate,\n gridTemplateRows: rowTemplate,\n } as React.CSSProperties\n }\n >\n {/* Grid cells */}\n {cells.map((row, ri) =>\n row.map((card, ci) => (\n <div\n key={`c${ri}-${ci}`}\n className=\"pi-resizable-grid-cell\"\n style={{gridColumn: colTracks[ci], gridRow: rowTracks[ri]}}\n >\n <Card cardName={card} parentCard={cardName} />\n </div>\n )),\n )}\n\n {/* Vertical column dividers — each spans all row tracks */}\n {colSpecs.map((_, ci) => {\n const track = dividerTrack(colSpecs, colTracks, ci);\n if (track === null) return null;\n return (\n <div\n key={`cd${ci}`}\n className={clsx(\"pi-resizable-grid-col-divider\", dividerClassName)}\n style={{gridColumn: track, gridRow: \"1 / -1\"}}\n onMouseDown={handleColMouseDown(ci)}\n onKeyDown={handleColKeyDown(ci)}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize columns ${ci + 1} and ${ci + 2}`}\n aria-valuenow={Math.round(colRatios[ci])}\n tabIndex={0}\n />\n );\n })}\n\n {/* Horizontal row dividers — each spans all column tracks */}\n {rowSpecs.map((_, ri) => {\n const track = dividerTrack(rowSpecs, rowTracks, ri);\n if (track === null) return null;\n return (\n <div\n key={`rd${ri}`}\n className={clsx(\"pi-resizable-grid-row-divider\", dividerClassName)}\n style={{gridRow: track, gridColumn: \"1 / -1\"}}\n onMouseDown={handleRowMouseDown(ri)}\n onKeyDown={handleRowKeyDown(ri)}\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label={`Resize rows ${ri + 1} and ${ri + 2}`}\n aria-valuenow={Math.round(rowRatios[ri])}\n tabIndex={0}\n />\n );\n })}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.pi-resizable-grid{width:100%;height:100%;display:grid}.pi-resizable-grid-cell{min-width:0;min-height:0;overflow:hidden}.pi-resizable-grid-col-divider{cursor:col-resize;z-index:1;min-height:0;position:relative}.pi-resizable-grid-col-divider:before{content:"";width:var(--rg-divider-width,1px);background-color:var(--rg-divider-color,var(--border));transition:width .12s,background-color .12s;position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%)}.pi-resizable-grid-col-divider:hover:before,.pi-resizable-grid-col-divider:focus-visible:before{width:var(--rg-divider-hover-width,4px);background-color:var(--rg-divider-hover-color,var(--muted-foreground))}.pi-resizable-grid-row-divider{cursor:row-resize;z-index:1;min-width:0;position:relative}.pi-resizable-grid-row-divider:before{content:"";height:var(--rg-divider-width,1px);background-color:var(--rg-divider-color,var(--border));transition:height .12s,background-color .12s;position:absolute;top:50%;left:0;right:0;transform:translateY(-50%)}.pi-resizable-grid-row-divider:hover:before,.pi-resizable-grid-row-divider:focus-visible:before{height:var(--rg-divider-hover-width,4px);background-color:var(--rg-divider-hover-color,var(--muted-foreground))}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCardDeclaration as e } from "@pihanga2/core";
|
|
2
|
+
//#region src/cards/resizableGrid/resizableGrid.types.ts
|
|
3
|
+
var t = "pi/resizable-grid", n = e(t);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { t as RESIZABLE_GRID_CARD, n as ResizableGrid };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=resizableGrid.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizableGrid.types.js","names":[],"sources":["../../../src/cards/resizableGrid/resizableGrid.types.ts"],"sourcesContent":["import {createCardDeclaration, type PiCardRef} from \"@pihanga2/core\";\n\nexport const RESIZABLE_GRID_CARD = \"pi/resizable-grid\";\n\nexport type ResizableGridProps = {\n /**\n * 2D array of cards — cells[row][col]. Must be rectangular (all rows same length).\n */\n cells: PiCardRef[][];\n /**\n * Initial column widths using CSS-like values:\n * - '200px' — fixed initial width (resolved against container width at mount)\n * - '30%' — explicit percentage of container\n * - '1fr' — fraction of remaining space after px/% columns\n * - 'auto' — natural content width; no drag handle rendered for adjacent boundaries\n *\n * Defaults to equal `1fr` split when omitted.\n */\n columnWidths?: string[];\n /**\n * Initial row heights using the same syntax as columnWidths.\n * 'auto' rows follow content height (max across all cells in that row).\n * No drag handle is rendered between two rows unless both are explicit (non-auto).\n *\n * Defaults to equal `1fr` split when omitted.\n */\n rowHeights?: string[];\n /** Minimum percentage any explicit column can shrink to during drag. Default: 10 */\n minColumnPercent?: number;\n /** Minimum percentage any explicit row can shrink to during drag. Default: 10 */\n minRowPercent?: number;\n className?: string;\n dividerClassName?: string;\n};\n\nexport const ResizableGrid =\n createCardDeclaration<ResizableGridProps>(RESIZABLE_GRID_CARD);\n"],"mappings":";;AAEA,IAAa,IAAsB,qBAiCtB,IACX,EAA0C,CAAmB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pihanga2/shadcn",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
4
4
|
"description": "Pihanga core card components built on shadcn/ui and Radix UI — the npm distribution of pihanga-shadcn.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -128,6 +128,14 @@
|
|
|
128
128
|
"import": "./cards/resizable/index.js",
|
|
129
129
|
"types": "./cards/resizable/index.d.ts"
|
|
130
130
|
},
|
|
131
|
+
"./cards/resizableColumns": {
|
|
132
|
+
"import": "./cards/resizableColumns/index.js",
|
|
133
|
+
"types": "./cards/resizableColumns/index.d.ts"
|
|
134
|
+
},
|
|
135
|
+
"./cards/resizableGrid": {
|
|
136
|
+
"import": "./cards/resizableGrid/index.js",
|
|
137
|
+
"types": "./cards/resizableGrid/index.d.ts"
|
|
138
|
+
},
|
|
131
139
|
"./cards/scrollbarWithAnnotations": {
|
|
132
140
|
"import": "./cards/scrollbarWithAnnotations/index.js",
|
|
133
141
|
"types": "./cards/scrollbarWithAnnotations/index.d.ts"
|
|
@@ -237,6 +245,8 @@
|
|
|
237
245
|
"./cards/pageWithNavbarMeta/index.js",
|
|
238
246
|
"./cards/pasteTarget/index.js",
|
|
239
247
|
"./cards/resizable/index.js",
|
|
248
|
+
"./cards/resizableColumns/index.js",
|
|
249
|
+
"./cards/resizableGrid/index.js",
|
|
240
250
|
"./cards/scrollbarWithAnnotations/index.js",
|
|
241
251
|
"./cards/select/index.js",
|
|
242
252
|
"./cards/sheetCard/index.js",
|