@pihanga2/shadcn 0.2.22 → 0.2.25
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 +22 -1
- package/cards/chart/chart.types.d.ts +21 -3
- package/cards/jsonViewer/jsonViewer.component.js +1 -2
- package/cards/jsonViewer/jsonViewer.component.js.map +1 -1
- package/cards/slider/slider.component.js +47 -37
- package/cards/slider/slider.component.js.map +1 -1
- package/cards/slider/slider.types.d.ts +15 -7
- package/cards/slider/slider.types.js.map +1 -1
- package/cards/swimlane/index.d.ts +2 -0
- package/cards/swimlane/index.js +14 -0
- package/cards/swimlane/index.js.map +1 -0
- package/cards/swimlane/swimlane.component.d.ts +4 -0
- package/cards/swimlane/swimlane.component.js +570 -0
- package/cards/swimlane/swimlane.component.js.map +1 -0
- package/cards/swimlane/swimlane.css +1 -0
- package/cards/swimlane/swimlane.demo.d.ts +12 -0
- package/cards/swimlane/swimlane.model.d.ts +61 -0
- package/cards/swimlane/swimlane.model.js +235 -0
- package/cards/swimlane/swimlane.model.js.map +1 -0
- package/cards/swimlane/swimlane.model.test.d.ts +1 -0
- package/cards/swimlane/swimlane.types.d.ts +389 -0
- package/cards/swimlane/swimlane.types.js +7 -0
- package/cards/swimlane/swimlane.types.js.map +1 -0
- package/cards.schema.json +7053 -0
- package/components/ui/drawer.js +24 -24
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -62,7 +62,27 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## Card catalogue (for code generators)
|
|
66
|
+
|
|
67
|
+
Every build also writes `dist-lib/cards.schema.json` (`@pihanga2/shadcn/cards.schema.json`):
|
|
68
|
+
a machine-readable catalogue of every card type in this package — a JSON
|
|
69
|
+
Schema for its props, and for each event payload plus the event's action
|
|
70
|
+
type. It's generated straight from the compiled cards and their `.d.ts`
|
|
71
|
+
files, so it can never drift from what's actually in `dist-lib/`.
|
|
72
|
+
|
|
73
|
+
Backends/other languages can use it to generate typed proxies instead of
|
|
74
|
+
hand-maintaining bindings. See `scripts/schema/extract-card-schemas.mjs` for
|
|
75
|
+
how it's produced, and the `pihanga-remote` project's Python code generator
|
|
76
|
+
(`pihanga_remote.codegen`) for a consumer.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import catalogue from "@pihanga2/shadcn/cards.schema.json";
|
|
80
|
+
// catalogue.cards["shad/button"].props / .events...
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Included cards (54)
|
|
66
86
|
|
|
67
87
|
- `attachment`
|
|
68
88
|
- `avatar`
|
|
@@ -110,6 +130,7 @@ import "@pihanga2/shadcn/cards/dataTable";
|
|
|
110
130
|
- `stack`
|
|
111
131
|
- `stepper`
|
|
112
132
|
- `suspense`
|
|
133
|
+
- `swimlane`
|
|
113
134
|
- `switch`
|
|
114
135
|
- `tabs`
|
|
115
136
|
- `textArea`
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PiCardRef } from '@pihanga2/core';
|
|
1
2
|
import { ChartConfig } from '../../components/ui/chart';
|
|
2
3
|
export declare const PI_CHART_GRAPH_CARD = "shad/chart-graph";
|
|
3
4
|
export declare const Chart: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<PiChartGraphProps, S, {}>) => import('@pihanga2/core').PiCardDef;
|
|
@@ -143,9 +144,9 @@ export type PiChartReferenceLine = {
|
|
|
143
144
|
};
|
|
144
145
|
export type PiChartGraphProps = {
|
|
145
146
|
/**
|
|
146
|
-
* Whether to render an
|
|
147
|
+
* Whether to render an area, line, or bar chart.
|
|
147
148
|
*/
|
|
148
|
-
chartType: "area" | "line";
|
|
149
|
+
chartType: "area" | "line" | "bar";
|
|
149
150
|
/**
|
|
150
151
|
* Array of data points. Each entry must contain:
|
|
151
152
|
* - a value for `xDataKey` (used for the x-axis labels), and
|
|
@@ -161,7 +162,7 @@ export type PiChartGraphProps = {
|
|
|
161
162
|
*/
|
|
162
163
|
data: Array<Record<string, unknown>>;
|
|
163
164
|
/**
|
|
164
|
-
* Series definitions.
|
|
165
|
+
* Series definitions. Each entry describes one plotted line, area, or bar.
|
|
165
166
|
* At least one series is required.
|
|
166
167
|
*/
|
|
167
168
|
series: PiChartSeries[];
|
|
@@ -248,6 +249,16 @@ export type PiChartGraphProps = {
|
|
|
248
249
|
* Range 0–1. Defaults to `0.4`.
|
|
249
250
|
*/
|
|
250
251
|
fillOpacity?: number;
|
|
252
|
+
/**
|
|
253
|
+
* Gap between bar categories as a percentage string or pixel value.
|
|
254
|
+
* Only applies to bar charts. Defaults to `"10%"` (the Recharts default).
|
|
255
|
+
*/
|
|
256
|
+
barGap?: number | string;
|
|
257
|
+
/**
|
|
258
|
+
* Radius in pixels applied to the top corners of each bar.
|
|
259
|
+
* Only applies to bar charts. Defaults to `0`.
|
|
260
|
+
*/
|
|
261
|
+
barRadius?: number;
|
|
251
262
|
/**
|
|
252
263
|
* Suppress the recharts entry animation so the chart renders immediately
|
|
253
264
|
* without the "draw-in" / "unfold" effect.
|
|
@@ -281,6 +292,13 @@ export type PiChartGraphProps = {
|
|
|
281
292
|
* ```
|
|
282
293
|
*/
|
|
283
294
|
referenceAreas?: PiChartReferenceArea[];
|
|
295
|
+
/**
|
|
296
|
+
* Optional Pihanga card rendered directly below the chart. Useful for
|
|
297
|
+
* controls that operate on the plotted data, such as a range slider.
|
|
298
|
+
*/
|
|
299
|
+
footerCard?: PiCardRef;
|
|
300
|
+
/** Extra Tailwind / CSS classes applied to the footer card wrapper. */
|
|
301
|
+
footerClassName?: string;
|
|
284
302
|
/** Extra Tailwind / CSS classes forwarded to the outermost element. */
|
|
285
303
|
className?: string;
|
|
286
304
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getIconElement as e } from "../icons.js";
|
|
2
|
-
import './jsonViewer.css'
|
|
3
|
-
/* empty css */
|
|
2
|
+
import './jsonViewer.css';/* empty css */
|
|
4
3
|
import { useCallback as t, useLayoutEffect as n, useRef as r, useState as i } from "react";
|
|
5
4
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
5
|
import { Check as s, Copy as c } from "lucide-react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonViewer.component.js","names":[],"sources":["../../../src/cards/jsonViewer/jsonViewer.component.tsx"],"sourcesContent":["import React, {useLayoutEffect, useRef, useState, useCallback} from \"react\";\nimport type {PiCardProps} from \"@pihanga2/core\";\nimport {JsonView, allExpanded, defaultStyles} from \"react-json-view-lite\";\nimport {Copy, Check} from \"lucide-react\";\
|
|
1
|
+
{"version":3,"file":"jsonViewer.component.js","names":[],"sources":["../../../src/cards/jsonViewer/jsonViewer.component.tsx"],"sourcesContent":["import React, {useLayoutEffect, useRef, useState, useCallback} from \"react\";\nimport type {PiCardProps} from \"@pihanga2/core\";\nimport {JsonView, allExpanded, defaultStyles} from \"react-json-view-lite\";\nimport {Copy, Check} from \"lucide-react\";\n// Note: react-json-view-lite's own CSS is intentionally NOT imported here.\n// Every style-name it defines is overridden below by `compactStyles` (the\n// `jv-*` classes), whose rules live entirely in \"./jsonViewer.css\". Importing\n// the library's own dist/index.css pulled in dead styles and, worse, caused\n// Vite to copy that CSS file into our build tree, which rollup then\n// referenced via a broken \"../../node_modules/react-json-view-lite/...\"\n// relative path once published to npm (external deps aren't republished with\n// the package). See jsonViewer.css for the real, already-overridden styles.\nimport \"./jsonViewer.css\";\n\nimport {getIconElement} from \"@/cards/icons\";\nimport type {JsonViewerProps, JsonViewerEvents} from \"./jsonViewer.types\";\n\n/**\n * Converts the `collapsed` prop (from the react-json-view API) into a\n * `shouldExpandNode` predicate for react-json-view-lite.\n *\n * - `false` → expand everything\n * - `true` → collapse everything\n * - number N → expand nodes at depth < N (root is depth 0)\n */\nfunction toShouldExpandNode(\n collapsed: boolean | number | undefined,\n): (level: number) => boolean {\n if (collapsed === false) return allExpanded;\n if (collapsed === true) return () => false;\n // default: collapsed = 1 → only root level expanded\n const depth = collapsed ?? 1;\n return (level: number) => level < depth;\n}\n\n/**\n * Compact, code-editor style for react-json-view-lite.\n *\n * The expand/collapse icon is positioned absolutely inside a fixed left gutter\n * (via padding-left on `.jv-basic-child`), so the opening `{` and closing `}`\n * always start at the same column — fixing the original misalignment where the\n * icon pushed the open-brace further right than the close-brace.\n */\nconst compactStyles = {\n // spread defaultStyles first to satisfy required fields (ariaLables, stringifyStringValues, …)\n ...defaultStyles,\n container: \"jv-container\",\n basicChildStyle: \"jv-basic-child\",\n label: \"jv-label\",\n clickableLabel: \"jv-clickable-label\",\n nullValue: \"jv-null\",\n undefinedValue: \"jv-undefined\",\n numberValue: \"jv-number\",\n stringValue: \"jv-string\",\n booleanValue: \"jv-boolean\",\n otherValue: \"jv-other\",\n punctuation: \"jv-punctuation\",\n expandIcon: \"jv-expand-icon\",\n collapseIcon: \"jv-collapse-icon\",\n collapsedContent: \"jv-collapsed-content\",\n childFieldsContainer: \"jv-child-fields-container\",\n};\n\n/**\n * Resolve the icon element to use for the copy button.\n *\n * Resolution order:\n * 1. `iconName` looked up in the global icon registry\n * 2. Lucide `Copy` as the built-in fallback\n */\nfunction resolveCopyIcon(iconName?: string): React.ElementType {\n if (iconName) {\n const registered = getIconElement(iconName);\n if (registered) return registered;\n }\n return Copy;\n}\n\n/** Write `text` to the clipboard, preferring `ClipboardItem` for explicit MIME. */\nasync function writeToClipboard(text: string): Promise<void> {\n if (typeof ClipboardItem !== \"undefined\") {\n const blob = new Blob([text], {type: \"text/plain\"});\n await navigator.clipboard.write([new ClipboardItem({\"text/plain\": blob})]);\n } else {\n // Fallback for browsers without ClipboardItem support\n await navigator.clipboard.writeText(text);\n }\n}\n\nexport const JsonViewerComponent = (\n props: PiCardProps<JsonViewerProps, JsonViewerEvents>,\n): React.ReactNode => {\n const {\n source,\n collapsed = 1,\n modifyFn,\n style,\n className,\n cardName,\n _cls,\n copyToClipboard,\n copyIcon,\n onCopied,\n } = props;\n\n const elRef = useRef<HTMLDivElement>(null);\n const [copied, setCopied] = useState(false);\n\n useLayoutEffect(() => {\n if (modifyFn) {\n modifyFn(source, elRef.current);\n }\n }, [modifyFn, source]);\n\n const shouldExpandNode = toShouldExpandNode(collapsed);\n\n const handleCopy = useCallback(async () => {\n const text = JSON.stringify(source, null, 2);\n let success = false;\n try {\n await writeToClipboard(text);\n success = true;\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.warn(\"[JsonViewer] clipboard write failed:\", err);\n }\n onCopied?.({success});\n }, [source, onCopied]);\n\n const CopyIconEl = resolveCopyIcon(copyIcon);\n const ConfirmIconEl = Check;\n\n return (\n <div\n className={[_cls(\"root\", className), \"jv-wrapper\"].join(\" \")}\n ref={elRef}\n data-pihanga={cardName}\n style={style as React.CSSProperties | undefined}\n >\n {copyToClipboard && (\n <button\n type=\"button\"\n aria-label={copied ? \"Copied!\" : \"Copy JSON to clipboard\"}\n title={copied ? \"Copied!\" : \"Copy JSON to clipboard\"}\n className={`jv-copy-btn${copied ? \" jv-copy-btn--done\" : \"\"}`}\n onClick={handleCopy}\n >\n {copied ? (\n <ConfirmIconEl size={13} strokeWidth={2.5} />\n ) : (\n <CopyIconEl size={13} strokeWidth={2} />\n )}\n </button>\n )}\n <JsonView\n data={source as object | unknown[]}\n shouldExpandNode={shouldExpandNode}\n style={compactStyles}\n clickToExpandNode\n />\n </div>\n );\n};\n"],"mappings":";;;;;;;AAyBA,SAAS,EACP,GAC4B;CAC5B,IAAI,MAAc,IAAO,OAAO;CAChC,IAAI,MAAc,IAAM,aAAa;CAErC,IAAM,IAAQ,KAAa;CAC3B,QAAQ,MAAkB,IAAQ;AACpC;AAUA,IAAM,IAAgB;CAEpB,GAAG;CACH,WAAW;CACX,iBAAiB;CACjB,OAAO;CACP,gBAAgB;CAChB,WAAW;CACX,gBAAgB;CAChB,aAAa;CACb,aAAa;CACb,cAAc;CACd,YAAY;CACZ,aAAa;CACb,YAAY;CACZ,cAAc;CACd,kBAAkB;CAClB,sBAAsB;AACxB;AASA,SAAS,EAAgB,GAAsC;CAC7D,IAAI,GAAU;EACZ,IAAM,IAAa,EAAe,CAAQ;EAC1C,IAAI,GAAY,OAAO;CACzB;CACA,OAAO;AACT;AAGA,eAAe,EAAiB,GAA6B;CAC3D,IAAI,OAAO,gBAAkB,KAAa;EACxC,IAAM,IAAO,IAAI,KAAK,CAAC,CAAI,GAAG,EAAC,MAAM,aAAY,CAAC;EAClD,MAAM,UAAU,UAAU,MAAM,CAAC,IAAI,cAAc,EAAC,cAAc,EAAI,CAAC,CAAC,CAAC;CAC3E,OAEE,MAAM,UAAU,UAAU,UAAU,CAAI;AAE5C;AAEA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,WACA,eAAY,GACZ,aACA,UACA,cACA,aACA,SACA,oBACA,aACA,gBACE,GAEE,IAAQ,EAAuB,IAAI,GACnC,CAAC,GAAQ,KAAa,EAAS,EAAK;CAE1C,QAAsB;EACpB,AAAI,KACF,EAAS,GAAQ,EAAM,OAAO;CAElC,GAAG,CAAC,GAAU,CAAM,CAAC;CAErB,IAAM,IAAmB,EAAmB,CAAS,GAE/C,IAAa,EAAY,YAAY;EACzC,IAAM,IAAO,KAAK,UAAU,GAAQ,MAAM,CAAC,GACvC,IAAU;EACd,IAAI;GAIF,AAHA,MAAM,EAAiB,CAAI,GAC3B,IAAU,IACV,EAAU,EAAI,GACd,iBAAiB,EAAU,EAAK,GAAG,GAAI;EACzC,SAAS,GAAK;GACZ,QAAQ,KAAK,wCAAwC,CAAG;EAC1D;EACA,IAAW,EAAC,WAAO,CAAC;CACtB,GAAG,CAAC,GAAQ,CAAQ,CAAC,GAEf,IAAa,EAAgB,CAAQ,GACrC,IAAgB;CAEtB,OACE,kBAAC,OAAD;EACE,WAAW,CAAC,EAAK,QAAQ,CAAS,GAAG,YAAY,EAAE,KAAK,GAAG;EAC3D,KAAK;EACL,gBAAc;EACP;YAJT,CAMG,KACC,kBAAC,UAAD;GACE,MAAK;GACL,cAAY,IAAS,YAAY;GACjC,OAAO,IAAS,YAAY;GAC5B,WAAW,cAAc,IAAS,uBAAuB;GACzD,SAAS;aAER,IACC,kBAAC,GAAD;IAAe,MAAM;IAAI,aAAa;GAAM,CAAA,IAE5C,kBAAC,GAAD;IAAY,MAAM;IAAI,aAAa;GAAI,CAAA;EAEnC,CAAA,GAEV,kBAAC,GAAD;GACE,MAAM;GACY;GAClB,OAAO;GACP,mBAAA;EACD,CAAA,CACE;;AAET"}
|
|
@@ -5,66 +5,76 @@ import { useEffect as r, useRef as i, useState as a } from "react";
|
|
|
5
5
|
import "@pihanga2/core";
|
|
6
6
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
7
|
//#region src/cards/slider/slider.component.tsx
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
function c(e) {
|
|
9
|
+
return Array.isArray(e) ? e : [e];
|
|
10
|
+
}
|
|
11
|
+
function l(e, t) {
|
|
12
|
+
return e.length > 1 ? [e[0] ?? t, e[1] ?? t] : e[0] ?? t;
|
|
13
|
+
}
|
|
14
|
+
function ee(e) {
|
|
15
|
+
return Array.isArray(e) ? `${e[0]} – ${e[1]}` : String(e);
|
|
16
|
+
}
|
|
17
|
+
var u = (u) => {
|
|
18
|
+
let { name: d, value: f, defaultValue: te, selfManaged: p = !1, min: m = 0, max: h = 100, step: g = 1, minStepsBetweenThumbs: _, disabled: v, debounceMs: y = 0, suppressChangedEvents: b = !1, label: x, showTicks: S = !1, tickStep: C, majorTickStep: w, suppressTickLabels: ne = !1, tickLabels: T, className: E, cardName: D, onChanged: O, onCommitted: k } = u, A = t(), j = A.isInForm && !!d, [M, N] = a(te ?? f ?? m), P = j ? A.formData[d] ?? m : p ? M : f ?? m, F = i(P);
|
|
19
|
+
F.current = P;
|
|
20
|
+
let I = i(!1), [L, R] = a(P), z = I.current ? L : P, B = i(null), V = i(P);
|
|
12
21
|
r(() => () => {
|
|
13
|
-
|
|
22
|
+
B.current != null && clearTimeout(B.current);
|
|
14
23
|
}, []);
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
name:
|
|
24
|
+
function H(e) {
|
|
25
|
+
b || (j ? A.handleChange(d, e) : O({
|
|
26
|
+
name: d,
|
|
18
27
|
value: e
|
|
19
28
|
}));
|
|
20
29
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
function U(e) {
|
|
25
|
-
let t = e[0] ?? p;
|
|
26
|
-
F.current && (L(t), f && !A && M(t), _ > 0 ? (B.current = t, z.current != null && clearTimeout(z.current), z.current = setTimeout(() => {
|
|
27
|
-
z.current = null, V(B.current);
|
|
28
|
-
}, _)) : V(t));
|
|
30
|
+
function U() {
|
|
31
|
+
I.current = !0, R(F.current);
|
|
29
32
|
}
|
|
30
33
|
function W(e) {
|
|
31
|
-
let t = e
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
let t = l(e, m);
|
|
35
|
+
I.current && (R(t), p && !j && N(t), y > 0 ? (V.current = t, B.current != null && clearTimeout(B.current), B.current = setTimeout(() => {
|
|
36
|
+
B.current = null, H(V.current);
|
|
37
|
+
}, y)) : H(t));
|
|
38
|
+
}
|
|
39
|
+
function re(e) {
|
|
40
|
+
let t = l(e, m);
|
|
41
|
+
I.current = !1, R(F.current), B.current != null && (clearTimeout(B.current), B.current = null), y > 0 && !b && H(t), k({
|
|
42
|
+
name: d,
|
|
34
43
|
value: t
|
|
35
44
|
});
|
|
36
45
|
}
|
|
37
|
-
let G =
|
|
46
|
+
let G = C === void 0 ? g : C, K = G > 0, q = K ? G : g, ie = q > 0 ? Math.max(q, Math.round((h - m) / 5 / q) * q) : 0, J = w === void 0 ? ie : w, Y = J > 0, X = S && (K || Y), Z = K ? G : J, ae = X ? Array.from({ length: Math.round((h - m) / Z) + 1 }, (e, t) => m + t * Z) : [], Q = c(z), $ = Q[0] ?? m, oe = Q[1] ?? $;
|
|
38
47
|
return /* @__PURE__ */ s("div", {
|
|
39
|
-
"data-pihanga":
|
|
40
|
-
className: e("flex flex-col gap-2",
|
|
48
|
+
"data-pihanga": D,
|
|
49
|
+
className: e("flex flex-col gap-2", E),
|
|
41
50
|
children: [
|
|
42
|
-
|
|
51
|
+
x && /* @__PURE__ */ s("div", {
|
|
43
52
|
className: "flex items-center justify-between",
|
|
44
53
|
children: [/* @__PURE__ */ o("span", {
|
|
45
54
|
className: "text-sm font-medium leading-none",
|
|
46
|
-
children:
|
|
55
|
+
children: x
|
|
47
56
|
}), /* @__PURE__ */ o("span", {
|
|
48
57
|
className: "text-sm text-muted-foreground tabular-nums",
|
|
49
|
-
children:
|
|
58
|
+
children: ee(z)
|
|
50
59
|
})]
|
|
51
60
|
}),
|
|
52
61
|
/* @__PURE__ */ o(n, {
|
|
53
|
-
value:
|
|
54
|
-
min:
|
|
55
|
-
max:
|
|
56
|
-
step:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
value: Q,
|
|
63
|
+
min: m,
|
|
64
|
+
max: h,
|
|
65
|
+
step: g,
|
|
66
|
+
minStepsBetweenThumbs: _,
|
|
67
|
+
disabled: v,
|
|
68
|
+
onPointerDown: U,
|
|
69
|
+
onValueChange: W,
|
|
70
|
+
onValueCommit: re,
|
|
61
71
|
className: "w-full"
|
|
62
72
|
}),
|
|
63
|
-
|
|
73
|
+
X && /* @__PURE__ */ o("div", {
|
|
64
74
|
"aria-hidden": "true",
|
|
65
75
|
className: "flex w-full items-baseline justify-between px-0.5",
|
|
66
|
-
children:
|
|
67
|
-
let n =
|
|
76
|
+
children: ae.map((t) => {
|
|
77
|
+
let n = Y && (t - m) % J === 0, r = Q.length > 1 ? t >= $ && t <= oe : t <= $, i = !ne && (n || !Y), a = i ? T && t in T ? T[t] : String(t) : "";
|
|
68
78
|
return /* @__PURE__ */ s("div", {
|
|
69
79
|
className: "flex flex-col items-center gap-1",
|
|
70
80
|
children: [/* @__PURE__ */ o("div", { className: e("w-0.5 rounded-full transition-all duration-300", r ? "bg-primary" : "bg-primary/20", n ? "h-3" : "h-1.5") }), /* @__PURE__ */ o("span", {
|
|
@@ -78,6 +88,6 @@ var c = (c) => {
|
|
|
78
88
|
});
|
|
79
89
|
};
|
|
80
90
|
//#endregion
|
|
81
|
-
export {
|
|
91
|
+
export { u as SliderComponent };
|
|
82
92
|
|
|
83
93
|
//# sourceMappingURL=slider.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.component.js","names":[],"sources":["../../../src/cards/slider/slider.component.tsx"],"sourcesContent":["import React, {useEffect, useRef, useState} from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Slider as SliderUI} from \"@/components/ui/slider\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport {cn} from \"@/lib/utils\";\nimport type {PiSliderEvents, PiSliderProps} from \"./slider.types\";\n\nexport const SliderComponent = (\n props: PiCardProps<PiSliderProps, PiSliderEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue,\n defaultValue,\n selfManaged = false,\n min = 0,\n max = 100,\n step = 1,\n disabled,\n debounceMs = 0,\n suppressChangedEvents = false,\n label,\n showTicks = false,\n tickStep,\n majorTickStep,\n suppressTickLabels = false,\n tickLabels,\n className,\n cardName,\n onChanged,\n onCommitted,\n } = props;\n\n // Detect if we are inside a pi/form card via React context.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n // Internal state used only when selfManaged=true and not bound to a form.\n const [managedValue, setManagedValue] = useState<number>(\n defaultValue ?? propValue ?? min,\n );\n\n // The \"canonical\" value from props / form / self-managed state.\n const canonicalValue = useFormData\n ? ((form.formData[name!] as number | undefined) ?? min)\n : selfManaged\n ? managedValue\n : (propValue ?? min);\n\n // Keep a ref to the latest canonical value so event handlers always see\n // the most up-to-date external value even if it changed during a drag.\n const canonicalValueRef = useRef(canonicalValue);\n canonicalValueRef.current = canonicalValue;\n\n // \"Interactive\" drag state — tracks knob position independently while the\n // user is actively dragging so we don't need an external value round-trip.\n const isDragging = useRef(false);\n const [interactiveValue, setInteractiveValue] =\n useState<number>(canonicalValue);\n\n // While dragging the knob follows pointer; otherwise it reflects the canonical value.\n const displayValue = isDragging.current ? interactiveValue : canonicalValue;\n\n // Refs for debounce: timer handle + latest pending value.\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingValue = useRef<number>(canonicalValue);\n\n // Clean up any pending debounce timer on unmount.\n useEffect(() => {\n return () => {\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n };\n }, []);\n\n function dispatchChanged(newValue: number) {\n // Silently skip if the caller has opted out of continuous change events.\n if (suppressChangedEvents) return;\n\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n onChanged({name, value: newValue});\n }\n }\n\n // Called on pointer/touch down — enter interactive mode so the knob can\n // move freely without waiting for an external state update.\n function handlePointerDown() {\n isDragging.current = true;\n setInteractiveValue(canonicalValueRef.current);\n }\n\n function handleValueChange(newValues: number[]) {\n const newValue = newValues[0] ?? min;\n\n // Guard: only update interactive display when actively dragging.\n if (!isDragging.current) return;\n\n setInteractiveValue(newValue);\n\n // Update internal state immediately so the thumb moves without lag.\n if (selfManaged && !useFormData) {\n setManagedValue(newValue);\n }\n\n if (debounceMs > 0) {\n // Record the latest value and (re)start the quiet-window timer.\n pendingValue.current = newValue;\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null;\n dispatchChanged(pendingValue.current);\n }, debounceMs);\n } else {\n dispatchChanged(newValue);\n }\n }\n\n function handleValueCommit(newValues: number[]) {\n const newValue = newValues[0] ?? min;\n\n // Leave interactive mode — on next render displayValue reverts to canonicalValue,\n // snapping the knob back to whatever the external state currently says.\n isDragging.current = false;\n setInteractiveValue(canonicalValueRef.current);\n\n // Cancel any pending debounced onChanged — the committed event supersedes it.\n if (debounceTimer.current != null) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n }\n\n // When debounce is active (and not suppressed), flush the final value via\n // onChanged before the committed event so listeners always see both.\n if (debounceMs > 0 && !suppressChangedEvents) {\n dispatchChanged(newValue);\n }\n\n onCommitted({name, value: newValue});\n }\n\n // --- Tick calculations ---\n // tickStep=0 → hide minor ticks only (major still shown if majorTickStep > 0)\n // majorTickStep=0 → hide major ticks only (minor still shown if tickStep > 0)\n // Both 0 → nothing shown\n const effectiveMinorStep = tickStep !== undefined ? tickStep : step;\n const showMinorTicks = effectiveMinorStep > 0;\n\n // Auto major step: use minor step as base when minor ticks are on;\n // fall back to `step` when minor ticks are off (tickStep=0) so that\n // major ticks can still be auto-calculated from the slider's step.\n const autoMajorBase = showMinorTicks ? effectiveMinorStep : step;\n const autoMajorStep =\n autoMajorBase > 0\n ? Math.max(\n autoMajorBase,\n Math.round((max - min) / 5 / autoMajorBase) * autoMajorBase,\n )\n : 0;\n // majorTickStep undefined → auto; 0 → no major ticks; >0 → explicit value\n const resolvedMajorStep =\n majorTickStep !== undefined ? majorTickStep : autoMajorStep;\n const showMajorTicks = resolvedMajorStep > 0;\n\n const renderTicks = showTicks && (showMinorTicks || showMajorTicks);\n\n // Use minor spacing as base when available; fall back to major spacing.\n const baseStep = showMinorTicks ? effectiveMinorStep : resolvedMajorStep;\n const ticks = renderTicks\n ? Array.from(\n {length: Math.round((max - min) / baseStep) + 1},\n (_, i) => min + i * baseStep,\n )\n : [];\n\n return (\n <div\n data-pihanga={cardName}\n className={cn(\"flex flex-col gap-2\", className)}\n >\n {label && (\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n <span className=\"text-sm text-muted-foreground tabular-nums\">\n {displayValue}\n </span>\n </div>\n )}\n <SliderUI\n value={[displayValue]}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n onPointerDown={handlePointerDown}\n onValueChange={handleValueChange}\n onValueCommit={handleValueCommit}\n className=\"w-full\"\n />\n {renderTicks && (\n <div\n aria-hidden=\"true\"\n className=\"flex w-full items-baseline justify-between px-0.5\"\n >\n {ticks.map((tick) => {\n const isMajor =\n showMajorTicks && (tick - min) % resolvedMajorStep === 0;\n const isActive = tick <= displayValue;\n // Show label when:\n // • suppressTickLabels is false, AND\n // • tick is major OR there are no major ticks (label every minor tick)\n const showLabel =\n !suppressTickLabels && (isMajor || !showMajorTicks);\n const labelText = showLabel\n ? tickLabels && tick in tickLabels\n ? tickLabels[tick]\n : String(tick)\n : \"\";\n\n return (\n <div key={tick} className=\"flex flex-col items-center gap-1\">\n <div\n className={cn(\n \"w-0.5 rounded-full transition-all duration-300\",\n isActive ? \"bg-primary\" : \"bg-primary/20\",\n isMajor ? \"h-3\" : \"h-1.5\",\n )}\n />\n <span\n className={cn(\n \"text-xs font-medium transition-colors\",\n showLabel\n ? \"text-muted-foreground opacity-100\"\n : \"opacity-0\",\n )}\n >\n {labelText}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slider.component.js","names":[],"sources":["../../../src/cards/slider/slider.component.tsx"],"sourcesContent":["import React, {useEffect, useRef, useState} from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Slider as SliderUI} from \"@/components/ui/slider\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport {cn} from \"@/lib/utils\";\nimport type {\n PiSliderEvents,\n PiSliderProps,\n PiSliderValue,\n} from \"./slider.types\";\n\nfunction toValues(value: PiSliderValue): number[] {\n return Array.isArray(value) ? value : [value];\n}\n\nfunction fromValues(values: number[], fallback: number): PiSliderValue {\n return values.length > 1\n ? [values[0] ?? fallback, values[1] ?? fallback]\n : (values[0] ?? fallback);\n}\n\nfunction formatValue(value: PiSliderValue): string {\n return Array.isArray(value) ? `${value[0]} – ${value[1]}` : String(value);\n}\n\nexport const SliderComponent = (\n props: PiCardProps<PiSliderProps, PiSliderEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue,\n defaultValue,\n selfManaged = false,\n min = 0,\n max = 100,\n step = 1,\n minStepsBetweenThumbs,\n disabled,\n debounceMs = 0,\n suppressChangedEvents = false,\n label,\n showTicks = false,\n tickStep,\n majorTickStep,\n suppressTickLabels = false,\n tickLabels,\n className,\n cardName,\n onChanged,\n onCommitted,\n } = props;\n\n // Detect if we are inside a pi/form card via React context.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n // Internal state used only when selfManaged=true and not bound to a form.\n const [managedValue, setManagedValue] = useState<PiSliderValue>(\n defaultValue ?? propValue ?? min,\n );\n\n // The \"canonical\" value from props / form / self-managed state.\n const canonicalValue = useFormData\n ? ((form.formData[name!] as PiSliderValue | undefined) ?? min)\n : selfManaged\n ? managedValue\n : (propValue ?? min);\n\n // Keep a ref to the latest canonical value so event handlers always see\n // the most up-to-date external value even if it changed during a drag.\n const canonicalValueRef = useRef(canonicalValue);\n canonicalValueRef.current = canonicalValue;\n\n // \"Interactive\" drag state — tracks knob position independently while the\n // user is actively dragging so we don't need an external value round-trip.\n const isDragging = useRef(false);\n const [interactiveValue, setInteractiveValue] =\n useState<PiSliderValue>(canonicalValue);\n\n // While dragging the knob follows pointer; otherwise it reflects the canonical value.\n const displayValue = isDragging.current ? interactiveValue : canonicalValue;\n\n // Refs for debounce: timer handle + latest pending value.\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingValue = useRef<PiSliderValue>(canonicalValue);\n\n // Clean up any pending debounce timer on unmount.\n useEffect(() => {\n return () => {\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n };\n }, []);\n\n function dispatchChanged(newValue: PiSliderValue) {\n // Silently skip if the caller has opted out of continuous change events.\n if (suppressChangedEvents) return;\n\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n onChanged({name, value: newValue});\n }\n }\n\n // Called on pointer/touch down — enter interactive mode so the knob can\n // move freely without waiting for an external state update.\n function handlePointerDown() {\n isDragging.current = true;\n setInteractiveValue(canonicalValueRef.current);\n }\n\n function handleValueChange(newValues: number[]) {\n const newValue = fromValues(newValues, min);\n\n // Guard: only update interactive display when actively dragging.\n if (!isDragging.current) return;\n\n setInteractiveValue(newValue);\n\n // Update internal state immediately so the thumb moves without lag.\n if (selfManaged && !useFormData) {\n setManagedValue(newValue);\n }\n\n if (debounceMs > 0) {\n // Record the latest value and (re)start the quiet-window timer.\n pendingValue.current = newValue;\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null;\n dispatchChanged(pendingValue.current);\n }, debounceMs);\n } else {\n dispatchChanged(newValue);\n }\n }\n\n function handleValueCommit(newValues: number[]) {\n const newValue = fromValues(newValues, min);\n\n // Leave interactive mode — on next render displayValue reverts to canonicalValue,\n // snapping the knob back to whatever the external state currently says.\n isDragging.current = false;\n setInteractiveValue(canonicalValueRef.current);\n\n // Cancel any pending debounced onChanged — the committed event supersedes it.\n if (debounceTimer.current != null) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n }\n\n // When debounce is active (and not suppressed), flush the final value via\n // onChanged before the committed event so listeners always see both.\n if (debounceMs > 0 && !suppressChangedEvents) {\n dispatchChanged(newValue);\n }\n\n onCommitted({name, value: newValue});\n }\n\n // --- Tick calculations ---\n // tickStep=0 → hide minor ticks only (major still shown if majorTickStep > 0)\n // majorTickStep=0 → hide major ticks only (minor still shown if tickStep > 0)\n // Both 0 → nothing shown\n const effectiveMinorStep = tickStep !== undefined ? tickStep : step;\n const showMinorTicks = effectiveMinorStep > 0;\n\n // Auto major step: use minor step as base when minor ticks are on;\n // fall back to `step` when minor ticks are off (tickStep=0) so that\n // major ticks can still be auto-calculated from the slider's step.\n const autoMajorBase = showMinorTicks ? effectiveMinorStep : step;\n const autoMajorStep =\n autoMajorBase > 0\n ? Math.max(\n autoMajorBase,\n Math.round((max - min) / 5 / autoMajorBase) * autoMajorBase,\n )\n : 0;\n // majorTickStep undefined → auto; 0 → no major ticks; >0 → explicit value\n const resolvedMajorStep =\n majorTickStep !== undefined ? majorTickStep : autoMajorStep;\n const showMajorTicks = resolvedMajorStep > 0;\n\n const renderTicks = showTicks && (showMinorTicks || showMajorTicks);\n\n // Use minor spacing as base when available; fall back to major spacing.\n const baseStep = showMinorTicks ? effectiveMinorStep : resolvedMajorStep;\n const ticks = renderTicks\n ? Array.from(\n {length: Math.round((max - min) / baseStep) + 1},\n (_, i) => min + i * baseStep,\n )\n : [];\n\n const displayValues = toValues(displayValue);\n const selectedMin = displayValues[0] ?? min;\n const selectedMax = displayValues[1] ?? selectedMin;\n\n return (\n <div\n data-pihanga={cardName}\n className={cn(\"flex flex-col gap-2\", className)}\n >\n {label && (\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium leading-none\">{label}</span>\n <span className=\"text-sm text-muted-foreground tabular-nums\">\n {formatValue(displayValue)}\n </span>\n </div>\n )}\n <SliderUI\n value={displayValues}\n min={min}\n max={max}\n step={step}\n minStepsBetweenThumbs={minStepsBetweenThumbs}\n disabled={disabled}\n onPointerDown={handlePointerDown}\n onValueChange={handleValueChange}\n onValueCommit={handleValueCommit}\n className=\"w-full\"\n />\n {renderTicks && (\n <div\n aria-hidden=\"true\"\n className=\"flex w-full items-baseline justify-between px-0.5\"\n >\n {ticks.map((tick) => {\n const isMajor =\n showMajorTicks && (tick - min) % resolvedMajorStep === 0;\n const isActive =\n displayValues.length > 1\n ? tick >= selectedMin && tick <= selectedMax\n : tick <= selectedMin;\n // Show label when:\n // • suppressTickLabels is false, AND\n // • tick is major OR there are no major ticks (label every minor tick)\n const showLabel =\n !suppressTickLabels && (isMajor || !showMajorTicks);\n const labelText = showLabel\n ? tickLabels && tick in tickLabels\n ? tickLabels[tick]\n : String(tick)\n : \"\";\n\n return (\n <div key={tick} className=\"flex flex-col items-center gap-1\">\n <div\n className={cn(\n \"w-0.5 rounded-full transition-all duration-300\",\n isActive ? \"bg-primary\" : \"bg-primary/20\",\n isMajor ? \"h-3\" : \"h-1.5\",\n )}\n />\n <span\n className={cn(\n \"text-xs font-medium transition-colors\",\n showLabel\n ? \"text-muted-foreground opacity-100\"\n : \"opacity-0\",\n )}\n >\n {labelText}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -24,6 +24,8 @@ export declare const onSliderCommitted: <S extends import('@pihanga2/core').Redu
|
|
|
24
24
|
export declare const onPiSliderCommitted: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
25
25
|
cardID: string;
|
|
26
26
|
} & PiSliderCommittedEvent>) => void;
|
|
27
|
+
/** A single selected value or an inclusive two-thumb range. */
|
|
28
|
+
export type PiSliderValue = number | [number, number];
|
|
27
29
|
export type PiSliderProps = {
|
|
28
30
|
/**
|
|
29
31
|
* Field name used to bind to FormContext when inside a pi/form card.
|
|
@@ -32,16 +34,17 @@ export type PiSliderProps = {
|
|
|
32
34
|
*/
|
|
33
35
|
name?: string;
|
|
34
36
|
/**
|
|
35
|
-
* Controlled
|
|
37
|
+
* Controlled value. A number renders one thumb; a tuple renders two thumbs
|
|
38
|
+
* with the selected range highlighted between them.
|
|
36
39
|
* Ignored when `name` is set and the component is inside a pi/form,
|
|
37
40
|
* and also ignored when `selfManaged` is true (use `defaultValue` instead).
|
|
38
41
|
*/
|
|
39
|
-
value?:
|
|
42
|
+
value?: PiSliderValue;
|
|
40
43
|
/**
|
|
41
44
|
* Initial value used when `selfManaged` is true.
|
|
42
45
|
* Falls back to `value` → `min` → 0 if not provided.
|
|
43
46
|
*/
|
|
44
|
-
defaultValue?:
|
|
47
|
+
defaultValue?: PiSliderValue;
|
|
45
48
|
/**
|
|
46
49
|
* When true the slider keeps its own internal value state.
|
|
47
50
|
* Dragging updates the displayed value immediately without needing an
|
|
@@ -58,6 +61,11 @@ export type PiSliderProps = {
|
|
|
58
61
|
max?: number;
|
|
59
62
|
/** Stepping interval between selectable values. Defaults to 1. */
|
|
60
63
|
step?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Minimum permitted distance between two thumbs, measured in `step`
|
|
66
|
+
* increments. Only applies when `value` is a range.
|
|
67
|
+
*/
|
|
68
|
+
minStepsBetweenThumbs?: number;
|
|
61
69
|
/** When true, the slider is disabled and non-interactive. */
|
|
62
70
|
disabled?: boolean;
|
|
63
71
|
/**
|
|
@@ -126,14 +134,14 @@ export type PiSliderProps = {
|
|
|
126
134
|
export type PiSliderChangedEvent = {
|
|
127
135
|
/** Field name, mirrors the `name` prop if provided. */
|
|
128
136
|
name?: string;
|
|
129
|
-
/** New
|
|
130
|
-
value:
|
|
137
|
+
/** New scalar or range value after the change. */
|
|
138
|
+
value: PiSliderValue;
|
|
131
139
|
};
|
|
132
140
|
export type PiSliderCommittedEvent = {
|
|
133
141
|
/** Field name, mirrors the `name` prop if provided. */
|
|
134
142
|
name?: string;
|
|
135
|
-
/** Final settled value when the user released
|
|
136
|
-
value:
|
|
143
|
+
/** Final settled scalar or range value when the user released a thumb. */
|
|
144
|
+
value: PiSliderValue;
|
|
137
145
|
};
|
|
138
146
|
export type PiSliderEvents = {
|
|
139
147
|
onChanged: PiSliderChangedEvent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.types.js","names":[],"sources":["../../../src/cards/slider/slider.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_SLIDER_CARD = \"shad/slider\";\n\nexport const Slider = createCardDeclaration<PiSliderProps, PiSliderEvents>(\n PI_SLIDER_CARD,\n);\n\nexport const PI_SLIDER_ACTION = registerActions(PI_SLIDER_CARD, [\n \"changed\",\n \"committed\",\n]);\n\nexport const onSliderChanged = createOnAction<PiSliderChangedEvent>(\n PI_SLIDER_ACTION.CHANGED,\n);\n\n/** @deprecated Use `onSliderChanged` instead. */\nexport const onPiSliderChanged = onSliderChanged;\n\n/**\n * Fired once when the user **finishes** dragging (mouse-up / touch-end).\n *\n * Use this instead of `onSliderChanged` when you only care about the final\n * settled value and do not want to process every intermediate drag position.\n */\nexport const onSliderCommitted = createOnAction<PiSliderCommittedEvent>(\n PI_SLIDER_ACTION.COMMITTED,\n);\n\n/** @deprecated Use `onSliderCommitted` instead. */\nexport const onPiSliderCommitted = onSliderCommitted;\n\n// ---------------------------------------------------------------------------\n// Props & Events\n// ---------------------------------------------------------------------------\n\nexport type PiSliderProps = {\n /**\n * Field name used to bind to FormContext when inside a pi/form card.\n * When provided the component reads its value from form data and writes\n * back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled
|
|
1
|
+
{"version":3,"file":"slider.types.js","names":[],"sources":["../../../src/cards/slider/slider.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_SLIDER_CARD = \"shad/slider\";\n\nexport const Slider = createCardDeclaration<PiSliderProps, PiSliderEvents>(\n PI_SLIDER_CARD,\n);\n\nexport const PI_SLIDER_ACTION = registerActions(PI_SLIDER_CARD, [\n \"changed\",\n \"committed\",\n]);\n\nexport const onSliderChanged = createOnAction<PiSliderChangedEvent>(\n PI_SLIDER_ACTION.CHANGED,\n);\n\n/** @deprecated Use `onSliderChanged` instead. */\nexport const onPiSliderChanged = onSliderChanged;\n\n/**\n * Fired once when the user **finishes** dragging (mouse-up / touch-end).\n *\n * Use this instead of `onSliderChanged` when you only care about the final\n * settled value and do not want to process every intermediate drag position.\n */\nexport const onSliderCommitted = createOnAction<PiSliderCommittedEvent>(\n PI_SLIDER_ACTION.COMMITTED,\n);\n\n/** @deprecated Use `onSliderCommitted` instead. */\nexport const onPiSliderCommitted = onSliderCommitted;\n\n// ---------------------------------------------------------------------------\n// Props & Events\n// ---------------------------------------------------------------------------\n\n/** A single selected value or an inclusive two-thumb range. */\nexport type PiSliderValue = number | [number, number];\n\nexport type PiSliderProps = {\n /**\n * Field name used to bind to FormContext when inside a pi/form card.\n * When provided the component reads its value from form data and writes\n * back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled value. A number renders one thumb; a tuple renders two thumbs\n * with the selected range highlighted between them.\n * Ignored when `name` is set and the component is inside a pi/form,\n * and also ignored when `selfManaged` is true (use `defaultValue` instead).\n */\n value?: PiSliderValue;\n\n /**\n * Initial value used when `selfManaged` is true.\n * Falls back to `value` → `min` → 0 if not provided.\n */\n defaultValue?: PiSliderValue;\n\n /**\n * When true the slider keeps its own internal value state.\n * Dragging updates the displayed value immediately without needing an\n * external state update. `onChanged` is still fired on every change so\n * the app can react (or log) without being responsible for feeding the\n * value back as a prop.\n *\n * Ignored when inside a pi/form (form state takes precedence).\n */\n selfManaged?: boolean;\n\n /** Minimum value of the slider range. Defaults to 0. */\n min?: number;\n\n /** Maximum value of the slider range. Defaults to 100. */\n max?: number;\n\n /** Stepping interval between selectable values. Defaults to 1. */\n step?: number;\n\n /**\n * Minimum permitted distance between two thumbs, measured in `step`\n * increments. Only applies when `value` is a range.\n */\n minStepsBetweenThumbs?: number;\n\n /** When true, the slider is disabled and non-interactive. */\n disabled?: boolean;\n\n /**\n * Debounce delay in milliseconds applied to `onChanged` during continuous\n * drag. Only the last value within each quiet window is dispatched.\n *\n * Useful when the `onChanged` handler is expensive (e.g. triggers an API\n * call) — set e.g. `debounceMs: 200` to cap the event rate.\n *\n * Has no effect on `onCommitted`, which always fires exactly once at\n * drag-end regardless of this setting.\n *\n * Omit (or set to 0) to dispatch on every drag position (default behaviour).\n */\n debounceMs?: number;\n\n /**\n * When true, `onSliderChanged` is **never** dispatched during drag.\n *\n * Use this together with `onSliderCommitted` when you only care about\n * the final settled value and want to eliminate all intermediate Redux\n * actions entirely (stricter than `debounceMs`).\n *\n * `onSliderCommitted` is unaffected and always fires on release.\n * `selfManaged` visual updates are also unaffected.\n */\n suppressChangedEvents?: boolean;\n\n /**\n * Optional label text rendered above the slider.\n * When provided, the current numeric value is shown to the right of the label.\n */\n label?: string;\n\n /**\n * When true, tick marks are rendered below the slider track.\n */\n showTicks?: boolean;\n\n /**\n * Spacing between consecutive **minor** tick marks in value units.\n * Defaults to `step`.\n * Set to `0` to hide minor ticks only — major ticks are still shown\n * if `majorTickStep` is non-zero.\n */\n tickStep?: number;\n\n /**\n * Interval (in value units) between **major** (tall, labelled) ticks.\n * Defaults to `(max - min) / 5` rounded to the nearest `tickStep`.\n * Set to `0` to hide major ticks only — minor ticks are still shown\n * if `tickStep` is non-zero.\n */\n majorTickStep?: number;\n\n /**\n * When true, no tick labels are rendered at all (only the tick marks).\n * Overrides `tickLabels` and the default numeric labels.\n */\n suppressTickLabels?: boolean;\n\n /**\n * Custom labels keyed by value. When provided for a value, the custom\n * string is shown instead of the numeric value. Pass `\"\"` to suppress the\n * label for a specific tick.\n *\n * @example { 0: \"Min\", 50: \"Mid\", 100: \"Max\" }\n */\n tickLabels?: Record<number, string>;\n\n /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */\n className?: string;\n};\n\nexport type PiSliderChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New scalar or range value after the change. */\n value: PiSliderValue;\n};\n\nexport type PiSliderCommittedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** Final settled scalar or range value when the user released a thumb. */\n value: PiSliderValue;\n};\n\nexport type PiSliderEvents = {\n onChanged: PiSliderChangedEvent;\n onCommitted: PiSliderCommittedEvent;\n};\n"],"mappings":";;AAMA,IAAa,IAAiB,eAEjB,IAAS,EACpB,CACF,GAEa,IAAmB,EAAgB,GAAgB,CAC9D,WACA,WACF,CAAC,GAEY,IAAkB,EAC7B,EAAiB,OACnB,GAGa,IAAoB,GAQpB,IAAoB,EAC/B,EAAiB,SACnB,GAGa,IAAsB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DEF_GUTTER_WIDTH as e, DEF_HEADER_HEIGHT as t, DEF_LANE_WIDTH as n, DEF_MAX_ROWS as r, DEF_ROW_HEIGHT as i, SWIMLANE_ACTION as a, SWIMLANE_CARD as o, SWIMLANE_DATA_ACTION as s, Swimlane as c, dispatchSwimlaneEvents as l, dispatchSwimlaneRowsCleared as u, onSwimlaneEventsReceived as d, onSwimlaneHoverChanged as f, onSwimlaneItemClicked as p, onSwimlaneRowsCleared as m } from "./swimlane.types.js";
|
|
2
|
+
import { clearSwimlaneRows as h, createSwimlaneModel as g, describeSwimlaneTarget as _, formatTs as v, ingestSwimlaneEvents as y, projectPending as b, registerSwimlaneModel as x, relatedCallIds as S, rowTouches as C, stepKeyOf as w, stepRows as T } from "./swimlane.model.js";
|
|
3
|
+
import { SwimlaneComponent as E } from "./swimlane.component.js";
|
|
4
|
+
import { actionTypesToEvents as D, registerCardComponent as O } from "@pihanga2/core";
|
|
5
|
+
//#region src/cards/swimlane/index.ts
|
|
6
|
+
O({
|
|
7
|
+
name: o,
|
|
8
|
+
component: E,
|
|
9
|
+
events: D(a)
|
|
10
|
+
});
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as DEF_GUTTER_WIDTH, t as DEF_HEADER_HEIGHT, n as DEF_LANE_WIDTH, r as DEF_MAX_ROWS, i as DEF_ROW_HEIGHT, a as SWIMLANE_ACTION, o as SWIMLANE_CARD, s as SWIMLANE_DATA_ACTION, c as Swimlane, h as clearSwimlaneRows, g as createSwimlaneModel, _ as describeSwimlaneTarget, l as dispatchSwimlaneEvents, u as dispatchSwimlaneRowsCleared, v as formatTs, y as ingestSwimlaneEvents, d as onSwimlaneEventsReceived, f as onSwimlaneHoverChanged, p as onSwimlaneItemClicked, m as onSwimlaneRowsCleared, b as projectPending, x as registerSwimlaneModel, S as relatedCallIds, C as rowTouches, w as stepKeyOf, T as stepRows };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/swimlane/index.ts"],"sourcesContent":["import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {SwimlaneComponent} from \"./swimlane.component\";\nimport {SWIMLANE_ACTION, SWIMLANE_CARD} from \"./swimlane.types\";\n\nexport * from \"./swimlane.types\";\nexport * from \"./swimlane.model\";\n\nregisterCardComponent({\n name: SWIMLANE_CARD,\n component: SwimlaneComponent,\n events: actionTypesToEvents(SWIMLANE_ACTION),\n});\n"],"mappings":";;;;;AAQA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAe;AAC7C,CAAC"}
|