tempest-react-sdk 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/charts/AreaChart.cjs +1 -1
- package/dist/charts/AreaChart.cjs.map +1 -1
- package/dist/charts/AreaChart.js +7 -7
- package/dist/charts/AreaChart.js.map +1 -1
- package/dist/charts/BarChart.cjs +1 -1
- package/dist/charts/BarChart.cjs.map +1 -1
- package/dist/charts/BarChart.js +7 -7
- package/dist/charts/BarChart.js.map +1 -1
- package/dist/charts/LineChart.cjs +1 -1
- package/dist/charts/LineChart.cjs.map +1 -1
- package/dist/charts/LineChart.js +6 -6
- package/dist/charts/LineChart.js.map +1 -1
- package/dist/charts/PieChart.cjs +1 -1
- package/dist/charts/PieChart.cjs.map +1 -1
- package/dist/charts/PieChart.js +6 -6
- package/dist/charts/PieChart.js.map +1 -1
- package/dist/charts/RadarChart.cjs +1 -1
- package/dist/charts/RadarChart.cjs.map +1 -1
- package/dist/charts/RadarChart.js +6 -6
- package/dist/charts/RadarChart.js.map +1 -1
- package/dist/charts/palette.cjs +1 -1
- package/dist/charts/palette.cjs.map +1 -1
- package/dist/charts/palette.js +19 -2
- package/dist/charts/palette.js.map +1 -1
- package/dist/charts/use-chart-colors.cjs +2 -0
- package/dist/charts/use-chart-colors.cjs.map +1 -0
- package/dist/charts/use-chart-colors.js +29 -0
- package/dist/charts/use-chart-colors.js.map +1 -0
- package/dist/charts.cjs +1 -1
- package/dist/charts.d.ts +59 -10
- package/dist/charts.js +8 -7
- package/dist/components/AvatarGroup/AvatarGroup.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.js +39 -0
- package/dist/components/AvatarGroup/AvatarGroup.js.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.cjs +2 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.cjs.map +1 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.js +16 -0
- package/dist/components/AvatarGroup/AvatarGroup.module.js.map +1 -0
- package/dist/components/Lightbox/Lightbox.cjs +2 -0
- package/dist/components/Lightbox/Lightbox.cjs.map +1 -0
- package/dist/components/Lightbox/Lightbox.js +148 -0
- package/dist/components/Lightbox/Lightbox.js.map +1 -0
- package/dist/components/Lightbox/Lightbox.module.cjs +2 -0
- package/dist/components/Lightbox/Lightbox.module.cjs.map +1 -0
- package/dist/components/Lightbox/Lightbox.module.js +21 -0
- package/dist/components/Lightbox/Lightbox.module.js.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.cjs +2 -0
- package/dist/components/SignaturePad/SignaturePad.cjs.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.js +115 -0
- package/dist/components/SignaturePad/SignaturePad.js.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.module.cjs +2 -0
- package/dist/components/SignaturePad/SignaturePad.module.cjs.map +1 -0
- package/dist/components/SignaturePad/SignaturePad.module.js +11 -0
- package/dist/components/SignaturePad/SignaturePad.module.js.map +1 -0
- package/dist/components/Stepper/Stepper.cjs +1 -1
- package/dist/components/Stepper/Stepper.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.js +43 -19
- package/dist/components/Stepper/Stepper.js.map +1 -1
- package/dist/components/Stepper/Stepper.module.cjs +1 -1
- package/dist/components/Stepper/Stepper.module.cjs.map +1 -1
- package/dist/components/Stepper/Stepper.module.js +6 -3
- package/dist/components/Stepper/Stepper.module.js.map +1 -1
- package/dist/components/TreeView/TreeView.cjs +2 -0
- package/dist/components/TreeView/TreeView.cjs.map +1 -0
- package/dist/components/TreeView/TreeView.js +124 -0
- package/dist/components/TreeView/TreeView.js.map +1 -0
- package/dist/components/TreeView/TreeView.module.cjs +2 -0
- package/dist/components/TreeView/TreeView.module.cjs.map +1 -0
- package/dist/components/TreeView/TreeView.module.js +17 -0
- package/dist/components/TreeView/TreeView.module.js.map +1 -0
- package/dist/components/Wizard/Wizard.cjs +2 -0
- package/dist/components/Wizard/Wizard.cjs.map +1 -0
- package/dist/components/Wizard/Wizard.js +111 -0
- package/dist/components/Wizard/Wizard.js.map +1 -0
- package/dist/components/Wizard/Wizard.module.cjs +2 -0
- package/dist/components/Wizard/Wizard.module.cjs.map +1 -0
- package/dist/components/Wizard/Wizard.module.js +10 -0
- package/dist/components/Wizard/Wizard.module.js.map +1 -0
- package/dist/offline/create-offline-sync.cjs +1 -1
- package/dist/offline/create-offline-sync.cjs.map +1 -1
- package/dist/offline/create-offline-sync.js +8 -2
- package/dist/offline/create-offline-sync.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/tempest-react-sdk.cjs +1 -1
- package/dist/tempest-react-sdk.d.ts +605 -2
- package/dist/tempest-react-sdk.js +255 -246
- package/dist/theme/apply-theme.cjs +2 -0
- package/dist/theme/apply-theme.cjs.map +1 -0
- package/dist/theme/apply-theme.js +24 -0
- package/dist/theme/apply-theme.js.map +1 -0
- package/dist/theme/color.cjs +2 -0
- package/dist/theme/color.cjs.map +1 -0
- package/dist/theme/color.js +130 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/create-theme.cjs +5 -0
- package/dist/theme/create-theme.cjs.map +1 -0
- package/dist/theme/create-theme.js +135 -0
- package/dist/theme/create-theme.js.map +1 -0
- package/dist/theme/theme-presets.cjs +2 -0
- package/dist/theme/theme-presets.cjs.map +1 -0
- package/dist/theme/theme-presets.js +82 -0
- package/dist/theme/theme-presets.js.map +1 -0
- package/dist/utilities.css +432 -0
- package/package.json +4 -3
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import { Button as t } from "../Button/Button.js";
|
|
3
|
+
import n from "./SignaturePad.module.js";
|
|
4
|
+
import { forwardRef as r, useCallback as i, useEffect as a, useImperativeHandle as o, useRef as s, useState as c } from "react";
|
|
5
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/SignaturePad/SignaturePad.tsx
|
|
7
|
+
var d = r(function({ width: r = 400, height: d = 160, penColor: f, penWidth: p = 2, disabled: m = !1, label: h = "Signature", onBegin: g, onEnd: _, onEmptyChange: v, showActions: y = !0, clearLabel: b = "Clear", undoLabel: x = "Undo", className: S }, C) {
|
|
8
|
+
let w = s(null), T = s([]), E = s(!1), [D, O] = c(!0), k = i(() => {
|
|
9
|
+
if (f) return f;
|
|
10
|
+
let e = w.current;
|
|
11
|
+
return !e || typeof window > "u" ? "#101828" : window.getComputedStyle(e).color || "#101828";
|
|
12
|
+
}, [f]), A = i(() => {
|
|
13
|
+
let e = w.current, t = e?.getContext("2d");
|
|
14
|
+
if (!e || !t) return;
|
|
15
|
+
let n = typeof window > "u" ? 1 : window.devicePixelRatio || 1;
|
|
16
|
+
e.width = r * n, e.height = d * n, t.setTransform(n, 0, 0, n, 0, 0), t.clearRect(0, 0, r, d), t.lineWidth = p, t.lineCap = "round", t.lineJoin = "round", t.strokeStyle = k();
|
|
17
|
+
for (let e of T.current) if (e.length !== 0) {
|
|
18
|
+
t.beginPath(), t.moveTo(e[0].x, e[0].y);
|
|
19
|
+
for (let n of e.slice(1)) t.lineTo(n.x, n.y);
|
|
20
|
+
e.length === 1 && t.lineTo(e[0].x, e[0].y), t.stroke();
|
|
21
|
+
}
|
|
22
|
+
}, [
|
|
23
|
+
d,
|
|
24
|
+
p,
|
|
25
|
+
k,
|
|
26
|
+
r
|
|
27
|
+
]);
|
|
28
|
+
a(() => {
|
|
29
|
+
A();
|
|
30
|
+
}, [A]);
|
|
31
|
+
let j = i((e) => {
|
|
32
|
+
O((t) => (t !== e && v?.(e), e));
|
|
33
|
+
}, [v]), M = i((e) => {
|
|
34
|
+
let t = w.current?.getBoundingClientRect();
|
|
35
|
+
return {
|
|
36
|
+
x: e.clientX - (t?.left ?? 0),
|
|
37
|
+
y: e.clientY - (t?.top ?? 0)
|
|
38
|
+
};
|
|
39
|
+
}, []), N = i((e) => {
|
|
40
|
+
m || (E.current = !0, T.current = [...T.current, [M(e)]], w.current?.setPointerCapture?.(e.pointerId), g?.(), j(!1), A());
|
|
41
|
+
}, [
|
|
42
|
+
m,
|
|
43
|
+
g,
|
|
44
|
+
M,
|
|
45
|
+
A,
|
|
46
|
+
j
|
|
47
|
+
]), P = i((e) => {
|
|
48
|
+
if (!E.current || m) return;
|
|
49
|
+
let t = T.current;
|
|
50
|
+
t[t.length - 1].push(M(e)), A();
|
|
51
|
+
}, [
|
|
52
|
+
m,
|
|
53
|
+
M,
|
|
54
|
+
A
|
|
55
|
+
]), F = i((e) => {
|
|
56
|
+
E.current && (E.current = !1, w.current?.releasePointerCapture?.(e.pointerId), _?.(w.current?.toDataURL() ?? ""));
|
|
57
|
+
}, [_]), I = i(() => {
|
|
58
|
+
T.current = [], j(!0), A();
|
|
59
|
+
}, [A, j]), L = i(() => {
|
|
60
|
+
T.current = T.current.slice(0, -1), j(T.current.length === 0), A();
|
|
61
|
+
}, [A, j]);
|
|
62
|
+
return o(C, () => ({
|
|
63
|
+
clear: I,
|
|
64
|
+
undo: L,
|
|
65
|
+
isEmpty: () => T.current.length === 0,
|
|
66
|
+
toDataURL: (e, t) => w.current?.toDataURL(e, t) ?? "",
|
|
67
|
+
toBlob: (e, t) => new Promise((n) => {
|
|
68
|
+
let r = w.current;
|
|
69
|
+
if (!r?.toBlob) {
|
|
70
|
+
n(null);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
r.toBlob((e) => n(e), e, t);
|
|
74
|
+
})
|
|
75
|
+
}), [I, L]), /* @__PURE__ */ u("div", {
|
|
76
|
+
className: e(n.pad, m && n.disabled, S),
|
|
77
|
+
children: [/* @__PURE__ */ l("canvas", {
|
|
78
|
+
ref: w,
|
|
79
|
+
role: "img",
|
|
80
|
+
"aria-label": h,
|
|
81
|
+
"aria-disabled": m || void 0,
|
|
82
|
+
className: n.canvas,
|
|
83
|
+
style: {
|
|
84
|
+
width: r,
|
|
85
|
+
height: d,
|
|
86
|
+
touchAction: "none"
|
|
87
|
+
},
|
|
88
|
+
onPointerDown: N,
|
|
89
|
+
onPointerMove: P,
|
|
90
|
+
onPointerUp: F,
|
|
91
|
+
onPointerLeave: F
|
|
92
|
+
}), y ? /* @__PURE__ */ u("div", {
|
|
93
|
+
className: n.actions,
|
|
94
|
+
children: [/* @__PURE__ */ l(t, {
|
|
95
|
+
type: "button",
|
|
96
|
+
variant: "ghost",
|
|
97
|
+
size: "sm",
|
|
98
|
+
onClick: L,
|
|
99
|
+
disabled: m || D,
|
|
100
|
+
children: x
|
|
101
|
+
}), /* @__PURE__ */ l(t, {
|
|
102
|
+
type: "button",
|
|
103
|
+
variant: "ghost",
|
|
104
|
+
size: "sm",
|
|
105
|
+
onClick: I,
|
|
106
|
+
disabled: m || D,
|
|
107
|
+
children: b
|
|
108
|
+
})]
|
|
109
|
+
}) : null]
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
//#endregion
|
|
113
|
+
export { d as SignaturePad };
|
|
114
|
+
|
|
115
|
+
//# sourceMappingURL=SignaturePad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignaturePad.js","names":[],"sources":["../../../src/components/SignaturePad/SignaturePad.tsx"],"sourcesContent":["import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport type { PointerEvent as ReactPointerEvent } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Button } from \"../Button\";\nimport styles from \"./SignaturePad.module.css\";\n\n/** A single sampled point of a stroke, in CSS pixels relative to the canvas. */\ninterface Point {\n x: number;\n y: number;\n}\n\n/** Imperative handle exposed through `ref`. */\nexport interface SignaturePadHandle {\n /** Drop every stroke. */\n clear: () => void;\n /** Drop the last stroke. */\n undo: () => void;\n /** `true` while nothing has been drawn. */\n isEmpty: () => boolean;\n /** Export as a data URL. Returns `\"\"` when the canvas is unavailable. */\n toDataURL: (type?: string, quality?: number) => string;\n /** Export as a `Blob` — what you actually upload. `null` when unavailable. */\n toBlob: (type?: string, quality?: number) => Promise<Blob | null>;\n}\n\nexport interface SignaturePadProps {\n /** Drawing surface width in CSS pixels. Default `400`. */\n width?: number;\n /** Drawing surface height in CSS pixels. Default `160`. */\n height?: number;\n /**\n * Stroke color. Defaults to the canvas' computed `color`, which the\n * stylesheet binds to `--tempest-text` — so the signature follows the theme\n * (including dark mode) instead of being hardcoded black.\n */\n penColor?: string;\n /** Stroke width in CSS pixels. Default `2`. */\n penWidth?: number;\n /** Blocks drawing and dims the surface. */\n disabled?: boolean;\n /** Accessible name of the surface. Default `\"Signature\"`. */\n label?: string;\n /** Called on the first move of each stroke. */\n onBegin?: () => void;\n /** Called when a stroke ends, with the current image as a data URL. */\n onEnd?: (dataUrl: string) => void;\n /** Called whenever the emptiness changes — wire it to a submit button. */\n onEmptyChange?: (isEmpty: boolean) => void;\n /** Renders the Clear/Undo buttons. Default `true`. */\n showActions?: boolean;\n clearLabel?: string;\n undoLabel?: string;\n className?: string;\n}\n\n/**\n * Signature capture on a canvas — the \"sign here\" field of a delivery receipt,\n * a service order, a term of acceptance.\n *\n * Strokes are kept as point lists and the canvas is **redrawn** from them, which\n * is what makes `undo` possible at all: a canvas holds pixels, not history, so\n * removing the last stroke means replaying the rest.\n *\n * The backing store is scaled by `devicePixelRatio`, so the line is crisp on a\n * phone instead of the blurry 1x bitmap a naive canvas produces.\n *\n * @example\n * ```tsx\n * const pad = useRef<SignaturePadHandle>(null);\n * const [empty, setEmpty] = useState(true);\n *\n * async function submit() {\n * const blob = await pad.current?.toBlob(\"image/png\");\n * if (blob) await api.upload(\"/receipts/42/signature\", blob);\n * }\n *\n * <SignaturePad ref={pad} label=\"Assinatura do cliente\" onEmptyChange={setEmpty} />\n * <Button disabled={empty} onClick={submit}>Enviar</Button>\n * ```\n */\nexport const SignaturePad = forwardRef<SignaturePadHandle, SignaturePadProps>(function SignaturePad(\n {\n width = 400,\n height = 160,\n penColor,\n penWidth = 2,\n disabled = false,\n label = \"Signature\",\n onBegin,\n onEnd,\n onEmptyChange,\n showActions = true,\n clearLabel = \"Clear\",\n undoLabel = \"Undo\",\n className,\n },\n ref,\n) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const strokesRef = useRef<Point[][]>([]);\n const drawingRef = useRef(false);\n const [isEmpty, setIsEmpty] = useState(true);\n\n const resolvePenColor = useCallback((): string => {\n if (penColor) return penColor;\n const canvas = canvasRef.current;\n if (!canvas || typeof window === \"undefined\") return \"#101828\";\n return window.getComputedStyle(canvas).color || \"#101828\";\n }, [penColor]);\n\n /**\n * Repaint the whole surface from the stroke list, honouring the pixel ratio.\n *\n * A one-point stroke (a tap) gets a line back to its own origin: `stroke()`\n * over a path with a single point paints nothing, so without it a tap would\n * silently produce no dot while still counting as \"not empty\".\n */\n const redraw = useCallback((): void => {\n const canvas = canvasRef.current;\n const context = canvas?.getContext(\"2d\");\n if (!canvas || !context) return;\n\n const ratio = typeof window === \"undefined\" ? 1 : window.devicePixelRatio || 1;\n canvas.width = width * ratio;\n canvas.height = height * ratio;\n context.setTransform(ratio, 0, 0, ratio, 0, 0);\n context.clearRect(0, 0, width, height);\n\n context.lineWidth = penWidth;\n context.lineCap = \"round\";\n context.lineJoin = \"round\";\n context.strokeStyle = resolvePenColor();\n\n for (const stroke of strokesRef.current) {\n if (stroke.length === 0) continue;\n context.beginPath();\n context.moveTo(stroke[0].x, stroke[0].y);\n for (const point of stroke.slice(1)) {\n context.lineTo(point.x, point.y);\n }\n if (stroke.length === 1) context.lineTo(stroke[0].x, stroke[0].y);\n context.stroke();\n }\n }, [height, penWidth, resolvePenColor, width]);\n\n useEffect(() => {\n redraw();\n }, [redraw]);\n\n const setEmptiness = useCallback(\n (next: boolean): void => {\n setIsEmpty((current) => {\n if (current !== next) onEmptyChange?.(next);\n return next;\n });\n },\n [onEmptyChange],\n );\n\n const pointFrom = useCallback((event: ReactPointerEvent<HTMLCanvasElement>): Point => {\n const rect = canvasRef.current?.getBoundingClientRect();\n return {\n x: event.clientX - (rect?.left ?? 0),\n y: event.clientY - (rect?.top ?? 0),\n };\n }, []);\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): void => {\n if (disabled) return;\n drawingRef.current = true;\n strokesRef.current = [...strokesRef.current, [pointFrom(event)]];\n canvasRef.current?.setPointerCapture?.(event.pointerId);\n onBegin?.();\n setEmptiness(false);\n redraw();\n },\n [disabled, onBegin, pointFrom, redraw, setEmptiness],\n );\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): void => {\n if (!drawingRef.current || disabled) return;\n const strokes = strokesRef.current;\n strokes[strokes.length - 1].push(pointFrom(event));\n redraw();\n },\n [disabled, pointFrom, redraw],\n );\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): void => {\n if (!drawingRef.current) return;\n drawingRef.current = false;\n canvasRef.current?.releasePointerCapture?.(event.pointerId);\n onEnd?.(canvasRef.current?.toDataURL() ?? \"\");\n },\n [onEnd],\n );\n\n const clear = useCallback((): void => {\n strokesRef.current = [];\n setEmptiness(true);\n redraw();\n }, [redraw, setEmptiness]);\n\n const undo = useCallback((): void => {\n strokesRef.current = strokesRef.current.slice(0, -1);\n setEmptiness(strokesRef.current.length === 0);\n redraw();\n }, [redraw, setEmptiness]);\n\n useImperativeHandle(\n ref,\n () => ({\n clear,\n undo,\n isEmpty: () => strokesRef.current.length === 0,\n toDataURL: (type, quality) => canvasRef.current?.toDataURL(type, quality) ?? \"\",\n toBlob: (type, quality) =>\n new Promise((resolve) => {\n const canvas = canvasRef.current;\n if (!canvas?.toBlob) {\n resolve(null);\n return;\n }\n canvas.toBlob((blob) => resolve(blob), type, quality);\n }),\n }),\n [clear, undo],\n );\n\n return (\n <div className={cn(styles.pad, disabled && styles.disabled, className)}>\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={label}\n aria-disabled={disabled || undefined}\n className={styles.canvas}\n style={{ width, height, touchAction: \"none\" }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerLeave={handlePointerUp}\n />\n {showActions ? (\n <div className={styles.actions}>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={undo}\n disabled={disabled || isEmpty}\n >\n {undoLabel}\n </Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={clear}\n disabled={disabled || isEmpty}\n >\n {clearLabel}\n </Button>\n </div>\n ) : null}\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=`tempest_pad_mrFAb`,t=`tempest_canvas_Jbknm`,n=`tempest_actions_iM9T-`,r=`tempest_disabled_0E3Fa`,i={pad:e,canvas:t,actions:n,disabled:r};exports.actions=n,exports.canvas=t,exports.default=i,exports.disabled=r,exports.pad=e;
|
|
2
|
+
//# sourceMappingURL=SignaturePad.module.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignaturePad.module.cjs","names":[],"sources":["../../../src/components/SignaturePad/SignaturePad.module.css"],"sourcesContent":[".pad {\n display: inline-flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n}\n\n.canvas {\n color: var(--tempest-text);\n background-color: var(--tempest-bg);\n border: 1px dashed var(--tempest-border-strong);\n border-radius: var(--tempest-radius-md);\n cursor: crosshair;\n}\n\n.canvas:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n}\n\n.disabled .canvas {\n cursor: not-allowed;\n opacity: 0.6;\n background-color: var(--tempest-surface-2);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/components/SignaturePad/SignaturePad.module.css
|
|
2
|
+
var e = "tempest_pad_mrFAb", t = "tempest_canvas_Jbknm", n = "tempest_actions_iM9T-", r = "tempest_disabled_0E3Fa", i = {
|
|
3
|
+
pad: e,
|
|
4
|
+
canvas: t,
|
|
5
|
+
actions: n,
|
|
6
|
+
disabled: r
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { n as actions, t as canvas, i as default, r as disabled, e as pad };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=SignaturePad.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignaturePad.module.js","names":[],"sources":["../../../src/components/SignaturePad/SignaturePad.module.css"],"sourcesContent":[".pad {\n display: inline-flex;\n flex-direction: column;\n gap: var(--tempest-space-2);\n}\n\n.canvas {\n color: var(--tempest-text);\n background-color: var(--tempest-bg);\n border: 1px dashed var(--tempest-border-strong);\n border-radius: var(--tempest-radius-md);\n cursor: crosshair;\n}\n\n.canvas:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--tempest-space-2);\n}\n\n.disabled .canvas {\n cursor: not-allowed;\n opacity: 0.6;\n background-color: var(--tempest-surface-2);\n}\n"],"mappings":""}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../utils/cn.cjs"),t=require("./Stepper.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i({steps:i,current:a,orientation:o=`horizontal`,className:
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("./Stepper.module.cjs");let n=require("react"),r=require("react/jsx-runtime");function i({steps:i,current:a,orientation:o=`horizontal`,onStepClick:s,className:c}){return(0,r.jsx)(`ol`,{className:e.cn(t.default.stepper,o===`vertical`&&t.default.vertical,c),children:i.map((o,c)=>{let l=c<a,u=c===a;return(0,r.jsxs)(n.Fragment,{children:[(0,r.jsx)(`li`,{className:e.cn(t.default.step,l&&t.default.completed,u&&t.default.active),"aria-current":u?`step`:void 0,children:s?(0,r.jsxs)(`button`,{type:`button`,className:t.default.trigger,"aria-current":u?`step`:void 0,onClick:()=>s(c),children:[(0,r.jsx)(`span`,{className:t.default.dot,children:l?`✓`:c+1}),(0,r.jsxs)(`span`,{className:t.default.labelGroup,children:[(0,r.jsx)(`span`,{className:t.default.label,children:o.label}),o.description?(0,r.jsx)(`span`,{className:t.default.description,children:o.description}):null]})]}):(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(`span`,{className:t.default.dot,children:l?`✓`:c+1}),(0,r.jsxs)(`span`,{className:t.default.labelGroup,children:[(0,r.jsx)(`span`,{className:t.default.label,children:o.label}),o.description?(0,r.jsx)(`span`,{className:t.default.description,children:o.description}):null]})]})}),c<i.length-1&&(0,r.jsx)(`span`,{className:e.cn(t.default.connector,l&&t.default.completed),"aria-hidden":!0})]},c)})})}exports.Stepper=i;
|
|
2
2
|
//# sourceMappingURL=Stepper.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.cjs","names":[],"sources":["../../../src/components/Stepper/Stepper.tsx"],"sourcesContent":["import { Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Stepper.module.css\";\n\nexport interface StepItem {\n label: ReactNode;\n}\n\nexport interface StepperProps {\n steps: StepItem[];\n /** Index of the currently active step (0-based). */\n current: number;\n orientation?: \"horizontal\" | \"vertical\";\n className?: string;\n}\n\n/**\n * Linear progress indicator for multi-step flows. Steps before `current`\n * render as completed; the step at `current` is active; later steps are\n * upcoming.\n */\nexport function Stepper({
|
|
1
|
+
{"version":3,"file":"Stepper.cjs","names":[],"sources":["../../../src/components/Stepper/Stepper.tsx"],"sourcesContent":["import { Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Stepper.module.css\";\n\nexport interface StepItem {\n label: ReactNode;\n /** Secondary line under the label — a hint, or \"optional\". */\n description?: ReactNode;\n}\n\nexport interface StepperProps {\n steps: StepItem[];\n /** Index of the currently active step (0-based). */\n current: number;\n orientation?: \"horizontal\" | \"vertical\";\n /**\n * Makes each step activatable. Without it the steps are a read-only\n * indicator, which is the right default — in a gated flow, jumping ahead\n * would skip the gates.\n */\n onStepClick?: (index: number) => void;\n className?: string;\n}\n\n/**\n * Linear progress indicator for multi-step flows. Steps before `current`\n * render as completed; the step at `current` is active; later steps are\n * upcoming.\n */\nexport function Stepper({\n steps,\n current,\n orientation = \"horizontal\",\n onStepClick,\n className,\n}: StepperProps) {\n return (\n <ol\n className={cn(styles.stepper, orientation === \"vertical\" && styles.vertical, className)}\n >\n {steps.map((step, index) => {\n const completed = index < current;\n const active = index === current;\n return (\n <Fragment key={index}>\n <li\n className={cn(\n styles.step,\n completed && styles.completed,\n active && styles.active,\n )}\n aria-current={active ? \"step\" : undefined}\n >\n {onStepClick ? (\n <button\n type=\"button\"\n className={styles.trigger}\n aria-current={active ? \"step\" : undefined}\n onClick={() => onStepClick(index)}\n >\n <span className={styles.dot}>\n {completed ? \"✓\" : index + 1}\n </span>\n <span className={styles.labelGroup}>\n <span className={styles.label}>{step.label}</span>\n {step.description ? (\n <span className={styles.description}>\n {step.description}\n </span>\n ) : null}\n </span>\n </button>\n ) : (\n <>\n <span className={styles.dot}>\n {completed ? \"✓\" : index + 1}\n </span>\n <span className={styles.labelGroup}>\n <span className={styles.label}>{step.label}</span>\n {step.description ? (\n <span className={styles.description}>\n {step.description}\n </span>\n ) : null}\n </span>\n </>\n )}\n </li>\n {index < steps.length - 1 && (\n <span\n className={cn(styles.connector, completed && styles.completed)}\n aria-hidden\n />\n )}\n </Fragment>\n );\n })}\n </ol>\n );\n}\n"],"mappings":"8HA8BA,SAAgB,EAAQ,CACpB,QACA,UACA,cAAc,aACd,cACA,aACa,CACb,OACI,EAAA,EAAA,IAAA,CAAC,KAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,QAAS,IAAgB,YAAc,EAAA,QAAO,SAAU,CAAS,WAErF,EAAM,KAAK,EAAM,IAAU,CACxB,IAAM,EAAY,EAAQ,EACpB,EAAS,IAAU,EACzB,OACI,EAAA,EAAA,KAAA,CAAC,EAAA,SAAD,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,KAAD,CACI,UAAW,EAAA,GACP,EAAA,QAAO,KACP,GAAa,EAAA,QAAO,UACpB,GAAU,EAAA,QAAO,MACrB,EACA,eAAc,EAAS,OAAS,IAAA,YAE/B,GACG,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,QAAO,QAClB,eAAc,EAAS,OAAS,IAAA,GAChC,YAAe,EAAY,CAAK,WAJpC,EAMI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,aACnB,EAAY,IAAM,EAAQ,CACzB,CAAA,GACN,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,oBAAxB,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,EAAK,KAAY,CAAA,EAChD,EAAK,aACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,qBACnB,EAAK,WACJ,CAAA,EACN,IACF,GACF,KAER,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,aACnB,EAAY,IAAM,EAAQ,CACzB,CAAA,GACN,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,oBAAxB,EACI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,eAAQ,EAAK,KAAY,CAAA,EAChD,EAAK,aACF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,qBACnB,EAAK,WACJ,CAAA,EACN,IACF,GACR,CAAA,CAAA,CAEN,CAAA,EACH,EAAQ,EAAM,OAAS,IACpB,EAAA,EAAA,IAAA,CAAC,OAAD,CACI,UAAW,EAAA,GAAG,EAAA,QAAO,UAAW,GAAa,EAAA,QAAO,SAAS,EAC7D,cAAA,EACH,CAAA,CAEC,CAAA,EAlDK,CAkDL,CAElB,CAAC,CACD,CAAA,CAEZ"}
|
|
@@ -1,31 +1,55 @@
|
|
|
1
1
|
import { cn as e } from "../../utils/cn.js";
|
|
2
2
|
import t from "./Stepper.module.js";
|
|
3
3
|
import { Fragment as n } from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Stepper/Stepper.tsx
|
|
6
|
-
function
|
|
7
|
-
return /* @__PURE__ */
|
|
8
|
-
className: e(t.stepper,
|
|
9
|
-
children:
|
|
10
|
-
let
|
|
11
|
-
return /* @__PURE__ */
|
|
12
|
-
className: e(t.step,
|
|
13
|
-
"aria-current":
|
|
14
|
-
children:
|
|
6
|
+
function o({ steps: o, current: s, orientation: c = "horizontal", onStepClick: l, className: u }) {
|
|
7
|
+
return /* @__PURE__ */ i("ol", {
|
|
8
|
+
className: e(t.stepper, c === "vertical" && t.vertical, u),
|
|
9
|
+
children: o.map((c, u) => {
|
|
10
|
+
let d = u < s, f = u === s;
|
|
11
|
+
return /* @__PURE__ */ a(n, { children: [/* @__PURE__ */ i("li", {
|
|
12
|
+
className: e(t.step, d && t.completed, f && t.active),
|
|
13
|
+
"aria-current": f ? "step" : void 0,
|
|
14
|
+
children: l ? /* @__PURE__ */ a("button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
className: t.trigger,
|
|
17
|
+
"aria-current": f ? "step" : void 0,
|
|
18
|
+
onClick: () => l(u),
|
|
19
|
+
children: [/* @__PURE__ */ i("span", {
|
|
20
|
+
className: t.dot,
|
|
21
|
+
children: d ? "✓" : u + 1
|
|
22
|
+
}), /* @__PURE__ */ a("span", {
|
|
23
|
+
className: t.labelGroup,
|
|
24
|
+
children: [/* @__PURE__ */ i("span", {
|
|
25
|
+
className: t.label,
|
|
26
|
+
children: c.label
|
|
27
|
+
}), c.description ? /* @__PURE__ */ i("span", {
|
|
28
|
+
className: t.description,
|
|
29
|
+
children: c.description
|
|
30
|
+
}) : null]
|
|
31
|
+
})]
|
|
32
|
+
}) : /* @__PURE__ */ a(r, { children: [/* @__PURE__ */ i("span", {
|
|
15
33
|
className: t.dot,
|
|
16
|
-
children:
|
|
17
|
-
}), /* @__PURE__ */
|
|
18
|
-
className: t.
|
|
19
|
-
children:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
children: d ? "✓" : u + 1
|
|
35
|
+
}), /* @__PURE__ */ a("span", {
|
|
36
|
+
className: t.labelGroup,
|
|
37
|
+
children: [/* @__PURE__ */ i("span", {
|
|
38
|
+
className: t.label,
|
|
39
|
+
children: c.label
|
|
40
|
+
}), c.description ? /* @__PURE__ */ i("span", {
|
|
41
|
+
className: t.description,
|
|
42
|
+
children: c.description
|
|
43
|
+
}) : null]
|
|
44
|
+
})] })
|
|
45
|
+
}), u < o.length - 1 && /* @__PURE__ */ i("span", {
|
|
46
|
+
className: e(t.connector, d && t.completed),
|
|
23
47
|
"aria-hidden": !0
|
|
24
|
-
})] },
|
|
48
|
+
})] }, u);
|
|
25
49
|
})
|
|
26
50
|
});
|
|
27
51
|
}
|
|
28
52
|
//#endregion
|
|
29
|
-
export {
|
|
53
|
+
export { o as Stepper };
|
|
30
54
|
|
|
31
55
|
//# sourceMappingURL=Stepper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.js","names":[],"sources":["../../../src/components/Stepper/Stepper.tsx"],"sourcesContent":["import { Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Stepper.module.css\";\n\nexport interface StepItem {\n label: ReactNode;\n}\n\nexport interface StepperProps {\n steps: StepItem[];\n /** Index of the currently active step (0-based). */\n current: number;\n orientation?: \"horizontal\" | \"vertical\";\n className?: string;\n}\n\n/**\n * Linear progress indicator for multi-step flows. Steps before `current`\n * render as completed; the step at `current` is active; later steps are\n * upcoming.\n */\nexport function Stepper({
|
|
1
|
+
{"version":3,"file":"Stepper.js","names":[],"sources":["../../../src/components/Stepper/Stepper.tsx"],"sourcesContent":["import { Fragment } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Stepper.module.css\";\n\nexport interface StepItem {\n label: ReactNode;\n /** Secondary line under the label — a hint, or \"optional\". */\n description?: ReactNode;\n}\n\nexport interface StepperProps {\n steps: StepItem[];\n /** Index of the currently active step (0-based). */\n current: number;\n orientation?: \"horizontal\" | \"vertical\";\n /**\n * Makes each step activatable. Without it the steps are a read-only\n * indicator, which is the right default — in a gated flow, jumping ahead\n * would skip the gates.\n */\n onStepClick?: (index: number) => void;\n className?: string;\n}\n\n/**\n * Linear progress indicator for multi-step flows. Steps before `current`\n * render as completed; the step at `current` is active; later steps are\n * upcoming.\n */\nexport function Stepper({\n steps,\n current,\n orientation = \"horizontal\",\n onStepClick,\n className,\n}: StepperProps) {\n return (\n <ol\n className={cn(styles.stepper, orientation === \"vertical\" && styles.vertical, className)}\n >\n {steps.map((step, index) => {\n const completed = index < current;\n const active = index === current;\n return (\n <Fragment key={index}>\n <li\n className={cn(\n styles.step,\n completed && styles.completed,\n active && styles.active,\n )}\n aria-current={active ? \"step\" : undefined}\n >\n {onStepClick ? (\n <button\n type=\"button\"\n className={styles.trigger}\n aria-current={active ? \"step\" : undefined}\n onClick={() => onStepClick(index)}\n >\n <span className={styles.dot}>\n {completed ? \"✓\" : index + 1}\n </span>\n <span className={styles.labelGroup}>\n <span className={styles.label}>{step.label}</span>\n {step.description ? (\n <span className={styles.description}>\n {step.description}\n </span>\n ) : null}\n </span>\n </button>\n ) : (\n <>\n <span className={styles.dot}>\n {completed ? \"✓\" : index + 1}\n </span>\n <span className={styles.labelGroup}>\n <span className={styles.label}>{step.label}</span>\n {step.description ? (\n <span className={styles.description}>\n {step.description}\n </span>\n ) : null}\n </span>\n </>\n )}\n </li>\n {index < steps.length - 1 && (\n <span\n className={cn(styles.connector, completed && styles.completed)}\n aria-hidden\n />\n )}\n </Fragment>\n );\n })}\n </ol>\n );\n}\n"],"mappings":";;;;;AA8BA,SAAgB,EAAQ,EACpB,UACA,YACA,iBAAc,cACd,gBACA,gBACa;CACb,OACI,kBAAC,MAAD;EACI,WAAW,EAAG,EAAO,SAAS,MAAgB,cAAc,EAAO,UAAU,CAAS;YAErF,EAAM,KAAK,GAAM,MAAU;GACxB,IAAM,IAAY,IAAQ,GACpB,IAAS,MAAU;GACzB,OACI,kBAAC,GAAD,EAAA,UAAA,CACI,kBAAC,MAAD;IACI,WAAW,EACP,EAAO,MACP,KAAa,EAAO,WACpB,KAAU,EAAO,MACrB;IACA,gBAAc,IAAS,SAAS,KAAA;cAE/B,IACG,kBAAC,UAAD;KACI,MAAK;KACL,WAAW,EAAO;KAClB,gBAAc,IAAS,SAAS,KAAA;KAChC,eAAe,EAAY,CAAK;eAJpC,CAMI,kBAAC,QAAD;MAAM,WAAW,EAAO;gBACnB,IAAY,MAAM,IAAQ;KACzB,CAAA,GACN,kBAAC,QAAD;MAAM,WAAW,EAAO;gBAAxB,CACI,kBAAC,QAAD;OAAM,WAAW,EAAO;iBAAQ,EAAK;MAAY,CAAA,GAChD,EAAK,cACF,kBAAC,QAAD;OAAM,WAAW,EAAO;iBACnB,EAAK;MACJ,CAAA,IACN,IACF;OACF;SAER,kBAAA,GAAA,EAAA,UAAA,CACI,kBAAC,QAAD;KAAM,WAAW,EAAO;eACnB,IAAY,MAAM,IAAQ;IACzB,CAAA,GACN,kBAAC,QAAD;KAAM,WAAW,EAAO;eAAxB,CACI,kBAAC,QAAD;MAAM,WAAW,EAAO;gBAAQ,EAAK;KAAY,CAAA,GAChD,EAAK,cACF,kBAAC,QAAD;MAAM,WAAW,EAAO;gBACnB,EAAK;KACJ,CAAA,IACN,IACF;MACR,EAAA,CAAA;GAEN,CAAA,GACH,IAAQ,EAAM,SAAS,KACpB,kBAAC,QAAD;IACI,WAAW,EAAG,EAAO,WAAW,KAAa,EAAO,SAAS;IAC7D,eAAA;GACH,CAAA,CAEC,EAAA,GAlDK,CAkDL;EAElB,CAAC;CACD,CAAA;AAEZ"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=`tempest_stepper_w3qjQ`,t=`tempest_vertical_d4mOs`,n=`tempest_step_s2nqL`,r=`tempest_dot_d1bSL`,i=`tempest_completed_gcFHM`,a=`tempest_active_kL-CH`,o=`tempest_label_8irAI`,s=`tempest_connector_lyeWp`,c={stepper:e,vertical:t,step:n,dot:r,completed:i,active:a,label:o,connector:s};exports.active=a,exports.completed=i,exports.connector=s,exports.default=
|
|
1
|
+
var e=`tempest_stepper_w3qjQ`,t=`tempest_vertical_d4mOs`,n=`tempest_step_s2nqL`,r=`tempest_dot_d1bSL`,i=`tempest_completed_gcFHM`,a=`tempest_active_kL-CH`,o=`tempest_label_8irAI`,s=`tempest_connector_lyeWp`,c=`tempest_labelGroup_PVn4m`,l=`tempest_description_xHXx3`,u=`tempest_trigger_vcUwl`,d={stepper:e,vertical:t,step:n,dot:r,completed:i,active:a,label:o,connector:s,labelGroup:c,description:l,trigger:u};exports.active=a,exports.completed=i,exports.connector=s,exports.default=d,exports.description=l,exports.dot=r,exports.label=o,exports.labelGroup=c,exports.step=n,exports.stepper=e,exports.trigger=u,exports.vertical=t;
|
|
2
2
|
//# sourceMappingURL=Stepper.module.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.module.cjs","names":[],"sources":["../../../src/components/Stepper/Stepper.module.css"],"sourcesContent":[".stepper {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.stepper.vertical {\n flex-direction: column;\n align-items: stretch;\n}\n\n.step {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n flex: 1;\n}\n\n.dot {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: 2px solid var(--tempest-border-strong);\n background-color: var(--tempest-bg);\n color: var(--tempest-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-bold);\n flex-shrink: 0;\n transition: var(--tempest-transition-color);\n}\n\n.step.completed .dot {\n background-color: var(--tempest-primary);\n border-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.step.active .dot {\n border-color: var(--tempest-primary-on-soft);\n color: var(--tempest-primary-on-soft);\n box-shadow: 0 0 0 4px var(--tempest-primary-soft);\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n}\n\n.step.active .label,\n.step.completed .label {\n color: var(--tempest-text);\n}\n\n.connector {\n flex: 1;\n height: 2px;\n background-color: var(--tempest-border);\n margin: 0 var(--tempest-space-1);\n transition: background-color var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.connector.completed {\n background-color: var(--tempest-primary);\n}\n\n.stepper.vertical .connector {\n width: 2px;\n height: 24px;\n margin: 0 0 0 13px;\n}\n\n/* Mobile — horizontal stepper becomes vertical automatically. */\n@media (max-width: 639.98px) {\n .stepper:not(.vertical) {\n flex-direction: column;\n align-items: stretch;\n }\n .stepper:not(.vertical) .connector {\n width: 2px;\n height: 16px;\n margin: 0 0 0 13px;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Stepper.module.cjs","names":[],"sources":["../../../src/components/Stepper/Stepper.module.css"],"sourcesContent":[".stepper {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.stepper.vertical {\n flex-direction: column;\n align-items: stretch;\n}\n\n.step {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n flex: 1;\n}\n\n.dot {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: 2px solid var(--tempest-border-strong);\n background-color: var(--tempest-bg);\n color: var(--tempest-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-bold);\n flex-shrink: 0;\n transition: var(--tempest-transition-color);\n}\n\n.step.completed .dot {\n background-color: var(--tempest-primary);\n border-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.step.active .dot {\n border-color: var(--tempest-primary-on-soft);\n color: var(--tempest-primary-on-soft);\n box-shadow: 0 0 0 4px var(--tempest-primary-soft);\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n}\n\n.step.active .label,\n.step.completed .label {\n color: var(--tempest-text);\n}\n\n.connector {\n flex: 1;\n height: 2px;\n background-color: var(--tempest-border);\n margin: 0 var(--tempest-space-1);\n transition: background-color var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.connector.completed {\n background-color: var(--tempest-primary);\n}\n\n.stepper.vertical .connector {\n width: 2px;\n height: 24px;\n margin: 0 0 0 13px;\n}\n\n/* Mobile — horizontal stepper becomes vertical automatically. */\n@media (max-width: 639.98px) {\n .stepper:not(.vertical) {\n flex-direction: column;\n align-items: stretch;\n }\n .stepper:not(.vertical) .connector {\n width: 2px;\n height: 16px;\n margin: 0 0 0 13px;\n }\n}\n\n.labelGroup {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.description {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-subtle);\n}\n\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: 0;\n background: none;\n border: 0;\n font: inherit;\n color: inherit;\n cursor: pointer;\n border-radius: var(--tempest-radius-sm);\n}\n\n.trigger:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":""}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/components/Stepper/Stepper.module.css
|
|
2
|
-
var e = "tempest_stepper_w3qjQ", t = "tempest_vertical_d4mOs", n = "tempest_step_s2nqL", r = "tempest_dot_d1bSL", i = "tempest_completed_gcFHM", a = "tempest_active_kL-CH", o = "tempest_label_8irAI", s = "tempest_connector_lyeWp", c = {
|
|
2
|
+
var e = "tempest_stepper_w3qjQ", t = "tempest_vertical_d4mOs", n = "tempest_step_s2nqL", r = "tempest_dot_d1bSL", i = "tempest_completed_gcFHM", a = "tempest_active_kL-CH", o = "tempest_label_8irAI", s = "tempest_connector_lyeWp", c = "tempest_labelGroup_PVn4m", l = "tempest_description_xHXx3", u = "tempest_trigger_vcUwl", d = {
|
|
3
3
|
stepper: e,
|
|
4
4
|
vertical: t,
|
|
5
5
|
step: n,
|
|
@@ -7,9 +7,12 @@ var e = "tempest_stepper_w3qjQ", t = "tempest_vertical_d4mOs", n = "tempest_step
|
|
|
7
7
|
completed: i,
|
|
8
8
|
active: a,
|
|
9
9
|
label: o,
|
|
10
|
-
connector: s
|
|
10
|
+
connector: s,
|
|
11
|
+
labelGroup: c,
|
|
12
|
+
description: l,
|
|
13
|
+
trigger: u
|
|
11
14
|
};
|
|
12
15
|
//#endregion
|
|
13
|
-
export { a as active, i as completed, s as connector,
|
|
16
|
+
export { a as active, i as completed, s as connector, d as default, l as description, r as dot, o as label, c as labelGroup, n as step, e as stepper, u as trigger, t as vertical };
|
|
14
17
|
|
|
15
18
|
//# sourceMappingURL=Stepper.module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stepper.module.js","names":[],"sources":["../../../src/components/Stepper/Stepper.module.css"],"sourcesContent":[".stepper {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.stepper.vertical {\n flex-direction: column;\n align-items: stretch;\n}\n\n.step {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n flex: 1;\n}\n\n.dot {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: 2px solid var(--tempest-border-strong);\n background-color: var(--tempest-bg);\n color: var(--tempest-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-bold);\n flex-shrink: 0;\n transition: var(--tempest-transition-color);\n}\n\n.step.completed .dot {\n background-color: var(--tempest-primary);\n border-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.step.active .dot {\n border-color: var(--tempest-primary-on-soft);\n color: var(--tempest-primary-on-soft);\n box-shadow: 0 0 0 4px var(--tempest-primary-soft);\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n}\n\n.step.active .label,\n.step.completed .label {\n color: var(--tempest-text);\n}\n\n.connector {\n flex: 1;\n height: 2px;\n background-color: var(--tempest-border);\n margin: 0 var(--tempest-space-1);\n transition: background-color var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.connector.completed {\n background-color: var(--tempest-primary);\n}\n\n.stepper.vertical .connector {\n width: 2px;\n height: 24px;\n margin: 0 0 0 13px;\n}\n\n/* Mobile — horizontal stepper becomes vertical automatically. */\n@media (max-width: 639.98px) {\n .stepper:not(.vertical) {\n flex-direction: column;\n align-items: stretch;\n }\n .stepper:not(.vertical) .connector {\n width: 2px;\n height: 16px;\n margin: 0 0 0 13px;\n }\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"Stepper.module.js","names":[],"sources":["../../../src/components/Stepper/Stepper.module.css"],"sourcesContent":[".stepper {\n display: flex;\n align-items: flex-start;\n gap: var(--tempest-space-2);\n width: 100%;\n font-family: var(--tempest-font-sans);\n}\n\n.stepper.vertical {\n flex-direction: column;\n align-items: stretch;\n}\n\n.step {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n flex: 1;\n}\n\n.dot {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n border: 2px solid var(--tempest-border-strong);\n background-color: var(--tempest-bg);\n color: var(--tempest-text-muted);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--tempest-text-xs);\n font-weight: var(--tempest-weight-bold);\n flex-shrink: 0;\n transition: var(--tempest-transition-color);\n}\n\n.step.completed .dot {\n background-color: var(--tempest-primary);\n border-color: var(--tempest-primary);\n color: var(--tempest-primary-foreground);\n}\n\n.step.active .dot {\n border-color: var(--tempest-primary-on-soft);\n color: var(--tempest-primary-on-soft);\n box-shadow: 0 0 0 4px var(--tempest-primary-soft);\n}\n\n.label {\n font-size: var(--tempest-text-sm);\n color: var(--tempest-text-muted);\n font-weight: var(--tempest-weight-semibold);\n line-height: var(--tempest-leading-snug);\n}\n\n.step.active .label,\n.step.completed .label {\n color: var(--tempest-text);\n}\n\n.connector {\n flex: 1;\n height: 2px;\n background-color: var(--tempest-border);\n margin: 0 var(--tempest-space-1);\n transition: background-color var(--tempest-duration-base) var(--tempest-ease-out);\n}\n\n.connector.completed {\n background-color: var(--tempest-primary);\n}\n\n.stepper.vertical .connector {\n width: 2px;\n height: 24px;\n margin: 0 0 0 13px;\n}\n\n/* Mobile — horizontal stepper becomes vertical automatically. */\n@media (max-width: 639.98px) {\n .stepper:not(.vertical) {\n flex-direction: column;\n align-items: stretch;\n }\n .stepper:not(.vertical) .connector {\n width: 2px;\n height: 16px;\n margin: 0 0 0 13px;\n }\n}\n\n.labelGroup {\n display: flex;\n flex-direction: column;\n gap: var(--tempest-space-1);\n min-width: 0;\n}\n\n.description {\n font-size: var(--tempest-text-xs);\n color: var(--tempest-text-subtle);\n}\n\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n padding: 0;\n background: none;\n border: 0;\n font: inherit;\n color: inherit;\n cursor: pointer;\n border-radius: var(--tempest-radius-sm);\n}\n\n.trigger:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: var(--tempest-focus-ring-offset);\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../../utils/cn.cjs"),t=require("./TreeView.module.cjs");let n=require("react"),r=require("react/jsx-runtime"),i=require("lucide-react");function a(e,t,n=0,r=null,i=[]){for(let o of e){let e=Array.isArray(o.children),s=e&&t.has(o.id);i.push({node:o,depth:n,parentId:r,hasChildren:e,expanded:s}),s&&o.children&&a(o.children,t,n+1,o.id,i)}return i}function o({nodes:o,expandedIds:s,defaultExpandedIds:c=[],onExpandedChange:l,selectedId:u,defaultSelectedId:d=null,onSelect:f,toggleOnSelect:p=!0,label:m,className:h}){let g=s!==void 0,[_,v]=(0,n.useState)(c),y=g?s:_,b=u!==void 0,[x,S]=(0,n.useState)(d),C=b?u:x,w=(0,n.useMemo)(()=>new Set(y),[y]),T=(0,n.useMemo)(()=>a(o,w),[o,w]),[E,D]=(0,n.useState)(null),O=(0,n.useRef)(null),k=E??C??T.find(e=>!e.node.disabled)?.node.id??null,A=(0,n.useCallback)(e=>{g||v(e),l?.(e)},[g,l]),j=(0,n.useCallback)(e=>{A(y.includes(e)?y.filter(t=>t!==e):[...y,e])},[y,A]),M=(0,n.useCallback)(e=>{e.node.disabled||(b||S(e.node.id),D(e.node.id),f?.(e.node),e.hasChildren&&p&&j(e.node.id))},[f,b,j,p]),N=(0,n.useCallback)(e=>{D(e),(O.current?.querySelector(`[data-tree-id="${e}"]`))?.focus()},[]),P=(0,n.useCallback)((e,t)=>{for(let n=e+t;n>=0&&n<T.length;n+=t)if(!T[n].node.disabled){N(T[n].node.id);return}},[T,N]),F=(0,n.useCallback)((e,t,n)=>{switch(e.key){case`ArrowDown`:e.preventDefault(),P(n,1);break;case`ArrowUp`:e.preventDefault(),P(n,-1);break;case`ArrowRight`:e.preventDefault(),t.hasChildren&&!t.expanded?j(t.node.id):t.expanded&&P(n,1);break;case`ArrowLeft`:e.preventDefault(),t.expanded?j(t.node.id):t.parentId&&N(t.parentId);break;case`Home`:e.preventDefault(),P(-1,1);break;case`End`:e.preventDefault(),P(T.length,-1);break;case`Enter`:case` `:e.preventDefault(),M(t);break;default:break}},[P,T.length,M,j,N]);return(0,r.jsx)(`ul`,{ref:O,role:`tree`,"aria-label":m,className:e.cn(t.default.tree,h),children:T.map((n,a)=>{let o=C===n.node.id;return(0,r.jsx)(`li`,{role:`treeitem`,"aria-expanded":n.hasChildren?n.expanded:void 0,"aria-selected":o,"aria-level":n.depth+1,"aria-disabled":n.node.disabled||void 0,className:t.default.item,children:(0,r.jsxs)(`div`,{"data-tree-id":n.node.id,className:e.cn(t.default.row,o&&t.default.selected,n.node.disabled&&t.default.disabled),style:{paddingInlineStart:`calc(${n.depth} * var(--tempest-space-5))`},tabIndex:k===n.node.id&&!n.node.disabled?0:-1,onClick:()=>M(n),onFocus:()=>D(n.node.id),onKeyDown:e=>F(e,n,a),children:[n.hasChildren?(0,r.jsx)(`span`,{className:e.cn(t.default.chevron,n.expanded&&t.default.chevronOpen),"aria-hidden":`true`,onClick:e=>{e.stopPropagation(),n.node.disabled||j(n.node.id)},children:(0,r.jsx)(i.ChevronRight,{size:14})}):(0,r.jsx)(`span`,{className:t.default.chevronPlaceholder,"aria-hidden":`true`}),n.node.icon?(0,r.jsx)(`span`,{className:t.default.icon,"aria-hidden":`true`,children:n.node.icon}):null,(0,r.jsx)(`span`,{className:t.default.label,children:n.node.label})]})},n.node.id)})})}exports.TreeView=o;
|
|
2
|
+
//# sourceMappingURL=TreeView.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.cjs","names":[],"sources":["../../../src/components/TreeView/TreeView.tsx"],"sourcesContent":["import { ChevronRight } from \"lucide-react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TreeView.module.css\";\n\n/** One node of the tree. Children make it a branch; no children makes it a leaf. */\nexport interface TreeNode {\n /** Stable identifier, unique across the whole tree. */\n id: string;\n /** Rendered label. */\n label: ReactNode;\n /** Child nodes. An empty array still renders as a branch (an empty folder). */\n children?: TreeNode[];\n /** Icon rendered before the label. */\n icon?: ReactNode;\n /** Blocks selection and expansion, and skips the node in keyboard navigation. */\n disabled?: boolean;\n}\n\nexport interface TreeViewProps {\n /** Root nodes. */\n nodes: TreeNode[];\n /** Controlled expanded ids. */\n expandedIds?: string[];\n /** Uncontrolled initial expanded ids. */\n defaultExpandedIds?: string[];\n onExpandedChange?: (expandedIds: string[]) => void;\n /** Controlled selected id. `null` means nothing selected. */\n selectedId?: string | null;\n /** Uncontrolled initial selection. */\n defaultSelectedId?: string | null;\n onSelect?: (node: TreeNode) => void;\n /**\n * Selecting a branch also toggles it. Default `true` — matches how a file\n * explorer behaves; set `false` when a branch is itself a meaningful choice\n * (a category that owns items, for instance).\n */\n toggleOnSelect?: boolean;\n /** Accessible name for the tree. */\n label?: string;\n className?: string;\n}\n\ninterface FlatNode {\n node: TreeNode;\n depth: number;\n parentId: string | null;\n hasChildren: boolean;\n expanded: boolean;\n}\n\n/**\n * Walk the tree into the list of *currently visible* rows.\n *\n * Keyboard navigation works on this flattened view, which is what makes\n * ArrowDown from the last child of a collapsed-sibling branch land on the right\n * row: rows that are not rendered simply are not in the list.\n */\nfunction flatten(\n nodes: TreeNode[],\n expandedIds: Set<string>,\n depth = 0,\n parentId: string | null = null,\n out: FlatNode[] = [],\n): FlatNode[] {\n for (const node of nodes) {\n const hasChildren = Array.isArray(node.children);\n const expanded = hasChildren && expandedIds.has(node.id);\n out.push({ node, depth, parentId, hasChildren, expanded });\n if (expanded && node.children) {\n flatten(node.children, expandedIds, depth + 1, node.id, out);\n }\n }\n return out;\n}\n\n/**\n * Accessible tree for hierarchical data — categories, permissions, folders, an\n * org chart.\n *\n * Implements the `tree` role with **roving tabindex**: exactly one row is\n * tabbable, and the arrow keys move focus within the widget. That is what keeps a\n * 500-node tree from adding 500 stops to the page's tab order.\n *\n * Keyboard map: `↓`/`↑` move, `→` expands (or descends), `←` collapses (or goes to\n * the parent), `Home`/`End` jump to the first/last visible row, `Enter`/`Space`\n * select.\n *\n * The chevron is decoration (`aria-hidden`), not a button: the row itself carries\n * `aria-expanded`, so a second focusable control there would only add noise for a\n * screen reader while duplicating an action the keyboard map already has. It still\n * accepts a click, with the event stopped so it toggles without also selecting.\n *\n * @example\n * ```tsx\n * const nodes: TreeNode[] = [\n * {\n * id: \"vendas\",\n * label: \"Vendas\",\n * children: [\n * { id: \"vendas.ler\", label: \"Ler\" },\n * { id: \"vendas.editar\", label: \"Editar\" },\n * ],\n * },\n * { id: \"config\", label: \"Configurações\", children: [] },\n * ];\n *\n * <TreeView nodes={nodes} defaultExpandedIds={[\"vendas\"]} onSelect={(node) => console.log(node.id)} />\n * ```\n */\nexport function TreeView({\n nodes,\n expandedIds,\n defaultExpandedIds = [],\n onExpandedChange,\n selectedId,\n defaultSelectedId = null,\n onSelect,\n toggleOnSelect = true,\n label,\n className,\n}: TreeViewProps) {\n const expandedControlled = expandedIds !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<string[]>(defaultExpandedIds);\n const expanded = expandedControlled ? expandedIds : internalExpanded;\n\n const selectionControlled = selectedId !== undefined;\n const [internalSelected, setInternalSelected] = useState<string | null>(defaultSelectedId);\n const selected = selectionControlled ? selectedId : internalSelected;\n\n const expandedSet = useMemo(() => new Set(expanded), [expanded]);\n const rows = useMemo(() => flatten(nodes, expandedSet), [nodes, expandedSet]);\n\n const [focusedId, setFocusedId] = useState<string | null>(null);\n const containerRef = useRef<HTMLUListElement>(null);\n\n const activeId =\n focusedId ?? selected ?? rows.find((row) => !row.node.disabled)?.node.id ?? null;\n\n const setExpanded = useCallback(\n (next: string[]): void => {\n if (!expandedControlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n },\n [expandedControlled, onExpandedChange],\n );\n\n const toggle = useCallback(\n (id: string): void => {\n setExpanded(\n expanded.includes(id) ? expanded.filter((x) => x !== id) : [...expanded, id],\n );\n },\n [expanded, setExpanded],\n );\n\n const select = useCallback(\n (row: FlatNode): void => {\n if (row.node.disabled) return;\n if (!selectionControlled) setInternalSelected(row.node.id);\n setFocusedId(row.node.id);\n onSelect?.(row.node);\n if (row.hasChildren && toggleOnSelect) toggle(row.node.id);\n },\n [onSelect, selectionControlled, toggle, toggleOnSelect],\n );\n\n /** Move DOM focus to a row by id, so the roving tabindex actually roves. */\n const focusRow = useCallback((id: string): void => {\n setFocusedId(id);\n const element = containerRef.current?.querySelector<HTMLElement>(`[data-tree-id=\"${id}\"]`);\n element?.focus();\n }, []);\n\n const moveFocus = useCallback(\n (from: number, delta: number): void => {\n for (let index = from + delta; index >= 0 && index < rows.length; index += delta) {\n if (!rows[index].node.disabled) {\n focusRow(rows[index].node.id);\n return;\n }\n }\n },\n [rows, focusRow],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>, row: FlatNode, index: number): void => {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n moveFocus(index, 1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n moveFocus(index, -1);\n break;\n case \"ArrowRight\":\n event.preventDefault();\n if (row.hasChildren && !row.expanded) toggle(row.node.id);\n else if (row.expanded) moveFocus(index, 1);\n break;\n case \"ArrowLeft\":\n event.preventDefault();\n if (row.expanded) {\n toggle(row.node.id);\n } else if (row.parentId) {\n focusRow(row.parentId);\n }\n break;\n case \"Home\":\n event.preventDefault();\n moveFocus(-1, 1);\n break;\n case \"End\":\n event.preventDefault();\n moveFocus(rows.length, -1);\n break;\n case \"Enter\":\n case \" \":\n event.preventDefault();\n select(row);\n break;\n default:\n break;\n }\n },\n [moveFocus, rows.length, select, toggle, focusRow],\n );\n\n return (\n <ul\n ref={containerRef}\n role=\"tree\"\n aria-label={label}\n className={cn(styles.tree, className)}\n >\n {rows.map((row, index) => {\n const isSelected = selected === row.node.id;\n return (\n <li\n key={row.node.id}\n role=\"treeitem\"\n aria-expanded={row.hasChildren ? row.expanded : undefined}\n aria-selected={isSelected}\n aria-level={row.depth + 1}\n aria-disabled={row.node.disabled || undefined}\n className={styles.item}\n >\n <div\n data-tree-id={row.node.id}\n className={cn(\n styles.row,\n isSelected && styles.selected,\n row.node.disabled && styles.disabled,\n )}\n style={{\n paddingInlineStart: `calc(${row.depth} * var(--tempest-space-5))`,\n }}\n tabIndex={activeId === row.node.id && !row.node.disabled ? 0 : -1}\n onClick={() => select(row)}\n onFocus={() => setFocusedId(row.node.id)}\n onKeyDown={(event) => handleKeyDown(event, row, index)}\n >\n {row.hasChildren ? (\n <span\n className={cn(\n styles.chevron,\n row.expanded && styles.chevronOpen,\n )}\n aria-hidden=\"true\"\n onClick={(event) => {\n event.stopPropagation();\n if (!row.node.disabled) toggle(row.node.id);\n }}\n >\n <ChevronRight size={14} />\n </span>\n ) : (\n <span className={styles.chevronPlaceholder} aria-hidden=\"true\" />\n )}\n {row.node.icon ? (\n <span className={styles.icon} aria-hidden=\"true\">\n {row.node.icon}\n </span>\n ) : null}\n <span className={styles.label}>{row.node.label}</span>\n </div>\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { cn as e } from "../../utils/cn.js";
|
|
2
|
+
import t from "./TreeView.module.js";
|
|
3
|
+
import { useCallback as n, useMemo as r, useRef as i, useState as a } from "react";
|
|
4
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
5
|
+
import { ChevronRight as c } from "lucide-react";
|
|
6
|
+
//#region src/components/TreeView/TreeView.tsx
|
|
7
|
+
function l(e, t, n = 0, r = null, i = []) {
|
|
8
|
+
for (let a of e) {
|
|
9
|
+
let e = Array.isArray(a.children), o = e && t.has(a.id);
|
|
10
|
+
i.push({
|
|
11
|
+
node: a,
|
|
12
|
+
depth: n,
|
|
13
|
+
parentId: r,
|
|
14
|
+
hasChildren: e,
|
|
15
|
+
expanded: o
|
|
16
|
+
}), o && a.children && l(a.children, t, n + 1, a.id, i);
|
|
17
|
+
}
|
|
18
|
+
return i;
|
|
19
|
+
}
|
|
20
|
+
function u({ nodes: u, expandedIds: d, defaultExpandedIds: f = [], onExpandedChange: p, selectedId: m, defaultSelectedId: h = null, onSelect: g, toggleOnSelect: _ = !0, label: v, className: y }) {
|
|
21
|
+
let b = d !== void 0, [x, S] = a(f), C = b ? d : x, w = m !== void 0, [T, E] = a(h), D = w ? m : T, O = r(() => new Set(C), [C]), k = r(() => l(u, O), [u, O]), [A, j] = a(null), M = i(null), N = A ?? D ?? k.find((e) => !e.node.disabled)?.node.id ?? null, P = n((e) => {
|
|
22
|
+
b || S(e), p?.(e);
|
|
23
|
+
}, [b, p]), F = n((e) => {
|
|
24
|
+
P(C.includes(e) ? C.filter((t) => t !== e) : [...C, e]);
|
|
25
|
+
}, [C, P]), I = n((e) => {
|
|
26
|
+
e.node.disabled || (w || E(e.node.id), j(e.node.id), g?.(e.node), e.hasChildren && _ && F(e.node.id));
|
|
27
|
+
}, [
|
|
28
|
+
g,
|
|
29
|
+
w,
|
|
30
|
+
F,
|
|
31
|
+
_
|
|
32
|
+
]), L = n((e) => {
|
|
33
|
+
j(e), (M.current?.querySelector(`[data-tree-id="${e}"]`))?.focus();
|
|
34
|
+
}, []), R = n((e, t) => {
|
|
35
|
+
for (let n = e + t; n >= 0 && n < k.length; n += t) if (!k[n].node.disabled) {
|
|
36
|
+
L(k[n].node.id);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}, [k, L]), z = n((e, t, n) => {
|
|
40
|
+
switch (e.key) {
|
|
41
|
+
case "ArrowDown":
|
|
42
|
+
e.preventDefault(), R(n, 1);
|
|
43
|
+
break;
|
|
44
|
+
case "ArrowUp":
|
|
45
|
+
e.preventDefault(), R(n, -1);
|
|
46
|
+
break;
|
|
47
|
+
case "ArrowRight":
|
|
48
|
+
e.preventDefault(), t.hasChildren && !t.expanded ? F(t.node.id) : t.expanded && R(n, 1);
|
|
49
|
+
break;
|
|
50
|
+
case "ArrowLeft":
|
|
51
|
+
e.preventDefault(), t.expanded ? F(t.node.id) : t.parentId && L(t.parentId);
|
|
52
|
+
break;
|
|
53
|
+
case "Home":
|
|
54
|
+
e.preventDefault(), R(-1, 1);
|
|
55
|
+
break;
|
|
56
|
+
case "End":
|
|
57
|
+
e.preventDefault(), R(k.length, -1);
|
|
58
|
+
break;
|
|
59
|
+
case "Enter":
|
|
60
|
+
case " ":
|
|
61
|
+
e.preventDefault(), I(t);
|
|
62
|
+
break;
|
|
63
|
+
default: break;
|
|
64
|
+
}
|
|
65
|
+
}, [
|
|
66
|
+
R,
|
|
67
|
+
k.length,
|
|
68
|
+
I,
|
|
69
|
+
F,
|
|
70
|
+
L
|
|
71
|
+
]);
|
|
72
|
+
return /* @__PURE__ */ o("ul", {
|
|
73
|
+
ref: M,
|
|
74
|
+
role: "tree",
|
|
75
|
+
"aria-label": v,
|
|
76
|
+
className: e(t.tree, y),
|
|
77
|
+
children: k.map((n, r) => {
|
|
78
|
+
let i = D === n.node.id;
|
|
79
|
+
return /* @__PURE__ */ o("li", {
|
|
80
|
+
role: "treeitem",
|
|
81
|
+
"aria-expanded": n.hasChildren ? n.expanded : void 0,
|
|
82
|
+
"aria-selected": i,
|
|
83
|
+
"aria-level": n.depth + 1,
|
|
84
|
+
"aria-disabled": n.node.disabled || void 0,
|
|
85
|
+
className: t.item,
|
|
86
|
+
children: /* @__PURE__ */ s("div", {
|
|
87
|
+
"data-tree-id": n.node.id,
|
|
88
|
+
className: e(t.row, i && t.selected, n.node.disabled && t.disabled),
|
|
89
|
+
style: { paddingInlineStart: `calc(${n.depth} * var(--tempest-space-5))` },
|
|
90
|
+
tabIndex: N === n.node.id && !n.node.disabled ? 0 : -1,
|
|
91
|
+
onClick: () => I(n),
|
|
92
|
+
onFocus: () => j(n.node.id),
|
|
93
|
+
onKeyDown: (e) => z(e, n, r),
|
|
94
|
+
children: [
|
|
95
|
+
n.hasChildren ? /* @__PURE__ */ o("span", {
|
|
96
|
+
className: e(t.chevron, n.expanded && t.chevronOpen),
|
|
97
|
+
"aria-hidden": "true",
|
|
98
|
+
onClick: (e) => {
|
|
99
|
+
e.stopPropagation(), n.node.disabled || F(n.node.id);
|
|
100
|
+
},
|
|
101
|
+
children: /* @__PURE__ */ o(c, { size: 14 })
|
|
102
|
+
}) : /* @__PURE__ */ o("span", {
|
|
103
|
+
className: t.chevronPlaceholder,
|
|
104
|
+
"aria-hidden": "true"
|
|
105
|
+
}),
|
|
106
|
+
n.node.icon ? /* @__PURE__ */ o("span", {
|
|
107
|
+
className: t.icon,
|
|
108
|
+
"aria-hidden": "true",
|
|
109
|
+
children: n.node.icon
|
|
110
|
+
}) : null,
|
|
111
|
+
/* @__PURE__ */ o("span", {
|
|
112
|
+
className: t.label,
|
|
113
|
+
children: n.node.label
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
})
|
|
117
|
+
}, n.node.id);
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { u as TreeView };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=TreeView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.js","names":[],"sources":["../../../src/components/TreeView/TreeView.tsx"],"sourcesContent":["import { ChevronRight } from \"lucide-react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./TreeView.module.css\";\n\n/** One node of the tree. Children make it a branch; no children makes it a leaf. */\nexport interface TreeNode {\n /** Stable identifier, unique across the whole tree. */\n id: string;\n /** Rendered label. */\n label: ReactNode;\n /** Child nodes. An empty array still renders as a branch (an empty folder). */\n children?: TreeNode[];\n /** Icon rendered before the label. */\n icon?: ReactNode;\n /** Blocks selection and expansion, and skips the node in keyboard navigation. */\n disabled?: boolean;\n}\n\nexport interface TreeViewProps {\n /** Root nodes. */\n nodes: TreeNode[];\n /** Controlled expanded ids. */\n expandedIds?: string[];\n /** Uncontrolled initial expanded ids. */\n defaultExpandedIds?: string[];\n onExpandedChange?: (expandedIds: string[]) => void;\n /** Controlled selected id. `null` means nothing selected. */\n selectedId?: string | null;\n /** Uncontrolled initial selection. */\n defaultSelectedId?: string | null;\n onSelect?: (node: TreeNode) => void;\n /**\n * Selecting a branch also toggles it. Default `true` — matches how a file\n * explorer behaves; set `false` when a branch is itself a meaningful choice\n * (a category that owns items, for instance).\n */\n toggleOnSelect?: boolean;\n /** Accessible name for the tree. */\n label?: string;\n className?: string;\n}\n\ninterface FlatNode {\n node: TreeNode;\n depth: number;\n parentId: string | null;\n hasChildren: boolean;\n expanded: boolean;\n}\n\n/**\n * Walk the tree into the list of *currently visible* rows.\n *\n * Keyboard navigation works on this flattened view, which is what makes\n * ArrowDown from the last child of a collapsed-sibling branch land on the right\n * row: rows that are not rendered simply are not in the list.\n */\nfunction flatten(\n nodes: TreeNode[],\n expandedIds: Set<string>,\n depth = 0,\n parentId: string | null = null,\n out: FlatNode[] = [],\n): FlatNode[] {\n for (const node of nodes) {\n const hasChildren = Array.isArray(node.children);\n const expanded = hasChildren && expandedIds.has(node.id);\n out.push({ node, depth, parentId, hasChildren, expanded });\n if (expanded && node.children) {\n flatten(node.children, expandedIds, depth + 1, node.id, out);\n }\n }\n return out;\n}\n\n/**\n * Accessible tree for hierarchical data — categories, permissions, folders, an\n * org chart.\n *\n * Implements the `tree` role with **roving tabindex**: exactly one row is\n * tabbable, and the arrow keys move focus within the widget. That is what keeps a\n * 500-node tree from adding 500 stops to the page's tab order.\n *\n * Keyboard map: `↓`/`↑` move, `→` expands (or descends), `←` collapses (or goes to\n * the parent), `Home`/`End` jump to the first/last visible row, `Enter`/`Space`\n * select.\n *\n * The chevron is decoration (`aria-hidden`), not a button: the row itself carries\n * `aria-expanded`, so a second focusable control there would only add noise for a\n * screen reader while duplicating an action the keyboard map already has. It still\n * accepts a click, with the event stopped so it toggles without also selecting.\n *\n * @example\n * ```tsx\n * const nodes: TreeNode[] = [\n * {\n * id: \"vendas\",\n * label: \"Vendas\",\n * children: [\n * { id: \"vendas.ler\", label: \"Ler\" },\n * { id: \"vendas.editar\", label: \"Editar\" },\n * ],\n * },\n * { id: \"config\", label: \"Configurações\", children: [] },\n * ];\n *\n * <TreeView nodes={nodes} defaultExpandedIds={[\"vendas\"]} onSelect={(node) => console.log(node.id)} />\n * ```\n */\nexport function TreeView({\n nodes,\n expandedIds,\n defaultExpandedIds = [],\n onExpandedChange,\n selectedId,\n defaultSelectedId = null,\n onSelect,\n toggleOnSelect = true,\n label,\n className,\n}: TreeViewProps) {\n const expandedControlled = expandedIds !== undefined;\n const [internalExpanded, setInternalExpanded] = useState<string[]>(defaultExpandedIds);\n const expanded = expandedControlled ? expandedIds : internalExpanded;\n\n const selectionControlled = selectedId !== undefined;\n const [internalSelected, setInternalSelected] = useState<string | null>(defaultSelectedId);\n const selected = selectionControlled ? selectedId : internalSelected;\n\n const expandedSet = useMemo(() => new Set(expanded), [expanded]);\n const rows = useMemo(() => flatten(nodes, expandedSet), [nodes, expandedSet]);\n\n const [focusedId, setFocusedId] = useState<string | null>(null);\n const containerRef = useRef<HTMLUListElement>(null);\n\n const activeId =\n focusedId ?? selected ?? rows.find((row) => !row.node.disabled)?.node.id ?? null;\n\n const setExpanded = useCallback(\n (next: string[]): void => {\n if (!expandedControlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n },\n [expandedControlled, onExpandedChange],\n );\n\n const toggle = useCallback(\n (id: string): void => {\n setExpanded(\n expanded.includes(id) ? expanded.filter((x) => x !== id) : [...expanded, id],\n );\n },\n [expanded, setExpanded],\n );\n\n const select = useCallback(\n (row: FlatNode): void => {\n if (row.node.disabled) return;\n if (!selectionControlled) setInternalSelected(row.node.id);\n setFocusedId(row.node.id);\n onSelect?.(row.node);\n if (row.hasChildren && toggleOnSelect) toggle(row.node.id);\n },\n [onSelect, selectionControlled, toggle, toggleOnSelect],\n );\n\n /** Move DOM focus to a row by id, so the roving tabindex actually roves. */\n const focusRow = useCallback((id: string): void => {\n setFocusedId(id);\n const element = containerRef.current?.querySelector<HTMLElement>(`[data-tree-id=\"${id}\"]`);\n element?.focus();\n }, []);\n\n const moveFocus = useCallback(\n (from: number, delta: number): void => {\n for (let index = from + delta; index >= 0 && index < rows.length; index += delta) {\n if (!rows[index].node.disabled) {\n focusRow(rows[index].node.id);\n return;\n }\n }\n },\n [rows, focusRow],\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>, row: FlatNode, index: number): void => {\n switch (event.key) {\n case \"ArrowDown\":\n event.preventDefault();\n moveFocus(index, 1);\n break;\n case \"ArrowUp\":\n event.preventDefault();\n moveFocus(index, -1);\n break;\n case \"ArrowRight\":\n event.preventDefault();\n if (row.hasChildren && !row.expanded) toggle(row.node.id);\n else if (row.expanded) moveFocus(index, 1);\n break;\n case \"ArrowLeft\":\n event.preventDefault();\n if (row.expanded) {\n toggle(row.node.id);\n } else if (row.parentId) {\n focusRow(row.parentId);\n }\n break;\n case \"Home\":\n event.preventDefault();\n moveFocus(-1, 1);\n break;\n case \"End\":\n event.preventDefault();\n moveFocus(rows.length, -1);\n break;\n case \"Enter\":\n case \" \":\n event.preventDefault();\n select(row);\n break;\n default:\n break;\n }\n },\n [moveFocus, rows.length, select, toggle, focusRow],\n );\n\n return (\n <ul\n ref={containerRef}\n role=\"tree\"\n aria-label={label}\n className={cn(styles.tree, className)}\n >\n {rows.map((row, index) => {\n const isSelected = selected === row.node.id;\n return (\n <li\n key={row.node.id}\n role=\"treeitem\"\n aria-expanded={row.hasChildren ? row.expanded : undefined}\n aria-selected={isSelected}\n aria-level={row.depth + 1}\n aria-disabled={row.node.disabled || undefined}\n className={styles.item}\n >\n <div\n data-tree-id={row.node.id}\n className={cn(\n styles.row,\n isSelected && styles.selected,\n row.node.disabled && styles.disabled,\n )}\n style={{\n paddingInlineStart: `calc(${row.depth} * var(--tempest-space-5))`,\n }}\n tabIndex={activeId === row.node.id && !row.node.disabled ? 0 : -1}\n onClick={() => select(row)}\n onFocus={() => setFocusedId(row.node.id)}\n onKeyDown={(event) => handleKeyDown(event, row, index)}\n >\n {row.hasChildren ? (\n <span\n className={cn(\n styles.chevron,\n row.expanded && styles.chevronOpen,\n )}\n aria-hidden=\"true\"\n onClick={(event) => {\n event.stopPropagation();\n if (!row.node.disabled) toggle(row.node.id);\n }}\n >\n <ChevronRight size={14} />\n </span>\n ) : (\n <span className={styles.chevronPlaceholder} aria-hidden=\"true\" />\n )}\n {row.node.icon ? (\n <span className={styles.icon} aria-hidden=\"true\">\n {row.node.icon}\n </span>\n ) : null}\n <span className={styles.label}>{row.node.label}</span>\n </div>\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=`tempest_tree_velMm`,t=`tempest_item_A2xw2`,n=`tempest_row_BsqpV`,r=`tempest_selected_uhjg8`,i=`tempest_disabled_vKxfJ`,a=`tempest_chevron_5v99r`,o=`tempest_chevronOpen_H3jAu`,s=`tempest_chevronPlaceholder_j0xjc`,c=`tempest_icon_O4r1C`,l=`tempest_label_MqR1B`,u={tree:e,item:t,row:n,selected:r,disabled:i,chevron:a,chevronOpen:o,chevronPlaceholder:s,icon:c,label:l};exports.chevron=a,exports.chevronOpen=o,exports.chevronPlaceholder=s,exports.default=u,exports.disabled=i,exports.icon=c,exports.item=t,exports.label=l,exports.row=n,exports.selected=r,exports.tree=e;
|
|
2
|
+
//# sourceMappingURL=TreeView.module.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TreeView.module.cjs","names":[],"sources":["../../../src/components/TreeView/TreeView.module.css"],"sourcesContent":[".tree {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n color: var(--tempest-text);\n font-size: var(--tempest-text-sm);\n}\n\n.item {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.row {\n display: flex;\n align-items: center;\n gap: var(--tempest-space-2);\n width: 100%;\n padding-block: var(--tempest-space-2);\n padding-inline-end: var(--tempest-space-3);\n border-radius: var(--tempest-radius-sm);\n cursor: pointer;\n user-select: none;\n transition:\n background-color var(--tempest-duration-fast) var(--tempest-ease-out),\n color var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.row:hover {\n background-color: var(--tempest-surface-2);\n}\n\n.row:focus-visible {\n outline: var(--tempest-focus-ring-width) solid var(--tempest-focus-ring-color);\n outline-offset: calc(var(--tempest-focus-ring-offset) * -1);\n}\n\n.selected {\n background-color: var(--tempest-primary-soft);\n color: var(--tempest-primary-on-soft);\n font-weight: var(--tempest-weight-medium);\n}\n\n.selected:hover {\n background-color: var(--tempest-primary-soft-hover);\n}\n\n.disabled {\n color: var(--tempest-text-subtle);\n cursor: not-allowed;\n}\n\n.disabled:hover {\n background-color: transparent;\n}\n\n.chevron {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 18px;\n height: 18px;\n border-radius: var(--tempest-radius-xs);\n color: var(--tempest-text-muted);\n transition: transform var(--tempest-duration-fast) var(--tempest-ease-out);\n}\n\n.chevron:hover {\n background-color: var(--tempest-surface-3);\n}\n\n.chevronOpen {\n transform: rotate(90deg);\n}\n\n.chevronPlaceholder {\n display: inline-block;\n flex: 0 0 auto;\n width: 18px;\n height: 18px;\n}\n\n.icon {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n color: var(--tempest-text-muted);\n}\n\n.label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .row,\n .chevron {\n transition: none;\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/components/TreeView/TreeView.module.css
|
|
2
|
+
var e = "tempest_tree_velMm", t = "tempest_item_A2xw2", n = "tempest_row_BsqpV", r = "tempest_selected_uhjg8", i = "tempest_disabled_vKxfJ", a = "tempest_chevron_5v99r", o = "tempest_chevronOpen_H3jAu", s = "tempest_chevronPlaceholder_j0xjc", c = "tempest_icon_O4r1C", l = "tempest_label_MqR1B", u = {
|
|
3
|
+
tree: e,
|
|
4
|
+
item: t,
|
|
5
|
+
row: n,
|
|
6
|
+
selected: r,
|
|
7
|
+
disabled: i,
|
|
8
|
+
chevron: a,
|
|
9
|
+
chevronOpen: o,
|
|
10
|
+
chevronPlaceholder: s,
|
|
11
|
+
icon: c,
|
|
12
|
+
label: l
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { a as chevron, o as chevronOpen, s as chevronPlaceholder, u as default, i as disabled, c as icon, t as item, l as label, n as row, r as selected, e as tree };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=TreeView.module.js.map
|