@pihanga2/shadcn 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/AGENT.building-cards.md +87 -0
  2. package/AGENT.using-cards.md +47 -0
  3. package/README.md +5 -1
  4. package/cards/avatar/avatar.component.d.ts +11 -0
  5. package/cards/avatar/avatar.component.js +26 -0
  6. package/cards/avatar/avatar.component.js.map +1 -0
  7. package/cards/avatar/avatar.types.d.ts +46 -0
  8. package/cards/avatar/avatar.types.js +7 -0
  9. package/cards/avatar/avatar.types.js.map +1 -0
  10. package/cards/avatar/index.d.ts +1 -0
  11. package/cards/avatar/index.js +12 -0
  12. package/cards/avatar/index.js.map +1 -0
  13. package/cards/badge/badge.component.js +4 -4
  14. package/cards/codeMirror/codeMirror.component.d.ts +4 -0
  15. package/cards/codeMirror/codeMirror.types.d.ts +83 -0
  16. package/cards/codeMirror/index.d.ts +1 -0
  17. package/cards/dataTable/dataTable.component.js +43 -42
  18. package/cards/dataTable/dataTable.component.js.map +1 -1
  19. package/cards/dataTable/dataTable.types.d.ts +26 -2
  20. package/cards/dataTable/dataTable.types.js +1 -0
  21. package/cards/dataTable/dataTable.types.js.map +1 -1
  22. package/cards/drawer/drawer.component.d.ts +4 -0
  23. package/cards/drawer/drawer.component.js +83 -0
  24. package/cards/drawer/drawer.component.js.map +1 -0
  25. package/cards/drawer/drawer.types.d.ts +95 -0
  26. package/cards/drawer/drawer.types.js +11 -0
  27. package/cards/drawer/drawer.types.js.map +1 -0
  28. package/cards/drawer/index.d.ts +1 -0
  29. package/cards/drawer/index.js +13 -0
  30. package/cards/drawer/index.js.map +1 -0
  31. package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
  32. package/cards/emptyCard/index.d.ts +7 -0
  33. package/cards/fileDrop/fileDrop.component.js +1 -1
  34. package/cards/fileDrop/fileDrop.css +1 -0
  35. package/cards/graphin/eventDispatcher.component.d.ts +2 -1
  36. package/cards/graphin/graphin.types.d.ts +14 -0
  37. package/cards/jsonViewer/jsonViewer.component.js +1 -1
  38. package/cards/jsonViewer/jsonViewer.css +1 -0
  39. package/cards/list/list.component.js +21 -21
  40. package/cards/loadingOverlay/loadingOverlay.component.js +1 -1
  41. package/cards/loadingOverlay/loadingOverlay.css +1 -0
  42. package/cards/pageWithNavbar/pageWithNavbar.component.js +1 -1
  43. package/cards/pageWithNavbar/pageWithNavbar.css +1 -0
  44. package/cards/pageWithNavbarMeta/index.d.ts +1 -0
  45. package/cards/pageWithNavbarMeta/index.js +118 -0
  46. package/cards/pageWithNavbarMeta/index.js.map +1 -0
  47. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +78 -0
  48. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js +7 -0
  49. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.js.map +1 -0
  50. package/cards/pasteTarget/pasteTarget.component.js +1 -1
  51. package/cards/pasteTarget/pasteTarget.css +1 -0
  52. package/cards/scrollbarWithAnnotations/index.d.ts +1 -0
  53. package/cards/scrollbarWithAnnotations/index.js +13 -0
  54. package/cards/scrollbarWithAnnotations/index.js.map +1 -0
  55. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.d.ts +23 -0
  56. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js +78 -0
  57. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.component.js.map +1 -0
  58. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.css +1 -0
  59. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.d.ts +123 -0
  60. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js +7 -0
  61. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.js.map +1 -0
  62. package/cards/slider/slider.component.js +67 -48
  63. package/cards/slider/slider.component.js.map +1 -1
  64. package/cards/slider/slider.types.d.ts +31 -0
  65. package/cards/slider/slider.types.js.map +1 -1
  66. package/cards/stepper/stepper.component.js +1 -1
  67. package/cards/stepper/stepper.css +1 -0
  68. package/components/ui/avatar.js +5 -5
  69. package/components/ui/badge.js +7 -7
  70. package/components/ui/button.js +6 -6
  71. package/components/ui/drawer.js +79 -0
  72. package/components/ui/drawer.js.map +1 -0
  73. package/components/ui/field.js +16 -16
  74. package/components/ui/label.js +3 -3
  75. package/components/ui/separator.js +1 -1
  76. package/components/ui/toggle-group.js +5 -5
  77. package/components/ui/toggle.js +2 -2
  78. package/lib/utils.d.ts +15 -0
  79. package/lib/utils.js.map +1 -1
  80. package/package.json +28 -3
  81. package/pihanga-shadcn.css +0 -2
@@ -0,0 +1,123 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ export declare const SCROLLBAR_WITH_ANNOTATIONS_CARD = "pi/scrollbar-with-annotations";
3
+ export declare const ScrollbarWithAnnotations: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<ScrollbarWithAnnotationsProps, S, ScrollbarWithAnnotationsEvents>) => import('@pihanga2/core').PiCardDef;
4
+ export declare const SCROLLBAR_WITH_ANNOTATIONS_ACTION: {
5
+ ANNOTATION_CLICKED: string;
6
+ ANNOTATION_HOVERED: string;
7
+ };
8
+ export declare const onScrollbarAnnotationClicked: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
9
+ cardID: string;
10
+ } & AnnotationClickedEvent>) => void;
11
+ export declare const onScrollbarAnnotationHovered: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
12
+ cardID: string;
13
+ } & AnnotationHoveredEvent>) => void;
14
+ /**
15
+ * The visual category of an annotation, which determines its colour on the
16
+ * scrollbar minimap.
17
+ */
18
+ export type AnnotationType = "error" | "warning" | "todo" | "comment" | "review" | "fixme";
19
+ /**
20
+ * Shape of the marker drawn on the scrollbar track.
21
+ *
22
+ * - `"point"` – a small circular dot (default).
23
+ * - `"bar"` – a short vertical rectangle with a fixed CSS height; useful for
24
+ * discrete events that have a known position but no meaningful
25
+ * extent.
26
+ * - `"range"` – a vertical rectangle whose height is proportional to `extent`
27
+ * in the content's scroll space, with a CSS-enforced minimum
28
+ * height so tiny ranges remain clickable. Requires `extent`.
29
+ */
30
+ export type MarkerType = "point" | "bar" | "range";
31
+ /**
32
+ * A single annotation marker placed on the scrollbar minimap.
33
+ *
34
+ * All positions are **pixel offsets from the top of the scrollable content**
35
+ * (i.e. relative to `scrollHeight`).
36
+ *
37
+ * | markerType | required fields |
38
+ * |------------|--------------------------|
39
+ * | `"point"` | `position` |
40
+ * | `"bar"` | `position` |
41
+ * | `"range"` | `position` + `extent` |
42
+ */
43
+ export type ScrollbarAnnotation = {
44
+ /** Unique identifier for this annotation. */
45
+ id: string;
46
+ /**
47
+ * Pixel offset from the top of the scrollable content.
48
+ * Acts as the start position for range markers.
49
+ */
50
+ position: number;
51
+ /**
52
+ * Length of the annotation in content pixels.
53
+ *
54
+ * Required when `markerType === "range"`. The marker will span
55
+ * `[position, position + extent]` in content space.
56
+ */
57
+ extent?: number;
58
+ /**
59
+ * Shape of the minimap marker. Defaults to `"point"`.
60
+ */
61
+ markerType?: MarkerType;
62
+ /** Visual category – controls colour. */
63
+ type: AnnotationType;
64
+ /** Short human-readable label shown in detail views. */
65
+ title: string;
66
+ /** Full description shown when the annotation is selected/inspected. */
67
+ description: string;
68
+ /**
69
+ * Optional extra CSS class(es) applied to this marker's DOM element.
70
+ *
71
+ * Use this to style individual annotations differently from the default
72
+ * type-based colour, e.g. to highlight a "selected" annotation:
73
+ *
74
+ * className: "swa-selected"
75
+ */
76
+ className?: string;
77
+ };
78
+ export type ScrollbarWithAnnotationsProps = {
79
+ /**
80
+ * Pihanga card reference for the scrollable main content.
81
+ *
82
+ * The card is rendered inside the scroll container, so it can be any
83
+ * Pihanga card (plain text, a Plate editor, a list, etc.).
84
+ */
85
+ contentCard: PiCardRef;
86
+ /**
87
+ * Annotations to display as coloured markers on the scrollbar track.
88
+ */
89
+ annotations: ScrollbarAnnotation[];
90
+ /** Optional additional CSS class applied to the root element. */
91
+ className?: string;
92
+ /**
93
+ * When `true`, `onAnnotationHovered` events are emitted even while the
94
+ * content container is being scrolled.
95
+ *
96
+ * Defaults to `false` (suppression is the default) to avoid flooding Redux
97
+ * with hover actions as markers pass under the cursor during scroll.
98
+ */
99
+ reportEventsOnScroll?: boolean;
100
+ };
101
+ /** Emitted when the user clicks an annotation marker. */
102
+ export type AnnotationClickedEvent = {
103
+ /** ID of the clicked annotation. */
104
+ annotationId: string;
105
+ /** Full annotation object for convenience. */
106
+ annotation: ScrollbarAnnotation;
107
+ };
108
+ /**
109
+ * Emitted when the user hovers over (or away from) an annotation marker.
110
+ *
111
+ * `annotationId` / `annotation` are `null` when the pointer leaves a marker.
112
+ *
113
+ * ⚠️ This event fires frequently during normal cursor movement. Handlers
114
+ * should be kept lightweight (e.g. update a single piece of local state).
115
+ */
116
+ export type AnnotationHoveredEvent = {
117
+ annotationId: string | null;
118
+ annotation: ScrollbarAnnotation | null;
119
+ };
120
+ export type ScrollbarWithAnnotationsEvents = {
121
+ onAnnotationClicked: AnnotationClickedEvent;
122
+ onAnnotationHovered: AnnotationHoveredEvent;
123
+ };
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.ts
3
+ var r = "pi/scrollbar-with-annotations", i = e(r), a = n(r, ["annotation_clicked", "annotation_hovered"]), o = t(a.ANNOTATION_CLICKED), s = t(a.ANNOTATION_HOVERED);
4
+ //#endregion
5
+ export { a as SCROLLBAR_WITH_ANNOTATIONS_ACTION, r as SCROLLBAR_WITH_ANNOTATIONS_CARD, i as ScrollbarWithAnnotations, o as onScrollbarAnnotationClicked, s as onScrollbarAnnotationHovered };
6
+
7
+ //# sourceMappingURL=scrollbarWithAnnotations.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollbarWithAnnotations.types.js","names":[],"sources":["../../../src/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const SCROLLBAR_WITH_ANNOTATIONS_CARD = \"pi/scrollbar-with-annotations\";\n\nexport const ScrollbarWithAnnotations = createCardDeclaration<\n ScrollbarWithAnnotationsProps,\n ScrollbarWithAnnotationsEvents\n>(SCROLLBAR_WITH_ANNOTATIONS_CARD);\n\nexport const SCROLLBAR_WITH_ANNOTATIONS_ACTION = registerActions(\n SCROLLBAR_WITH_ANNOTATIONS_CARD,\n [\"annotation_clicked\", \"annotation_hovered\"],\n);\n\nexport const onScrollbarAnnotationClicked =\n createOnAction<AnnotationClickedEvent>(\n SCROLLBAR_WITH_ANNOTATIONS_ACTION.ANNOTATION_CLICKED,\n );\n\nexport const onScrollbarAnnotationHovered =\n createOnAction<AnnotationHoveredEvent>(\n SCROLLBAR_WITH_ANNOTATIONS_ACTION.ANNOTATION_HOVERED,\n );\n\n/**\n * The visual category of an annotation, which determines its colour on the\n * scrollbar minimap.\n */\nexport type AnnotationType =\n | \"error\"\n | \"warning\"\n | \"todo\"\n | \"comment\"\n | \"review\"\n | \"fixme\";\n\n/**\n * Shape of the marker drawn on the scrollbar track.\n *\n * - `\"point\"` – a small circular dot (default).\n * - `\"bar\"` – a short vertical rectangle with a fixed CSS height; useful for\n * discrete events that have a known position but no meaningful\n * extent.\n * - `\"range\"` – a vertical rectangle whose height is proportional to `extent`\n * in the content's scroll space, with a CSS-enforced minimum\n * height so tiny ranges remain clickable. Requires `extent`.\n */\nexport type MarkerType = \"point\" | \"bar\" | \"range\";\n\n/**\n * A single annotation marker placed on the scrollbar minimap.\n *\n * All positions are **pixel offsets from the top of the scrollable content**\n * (i.e. relative to `scrollHeight`).\n *\n * | markerType | required fields |\n * |------------|--------------------------|\n * | `\"point\"` | `position` |\n * | `\"bar\"` | `position` |\n * | `\"range\"` | `position` + `extent` |\n */\nexport type ScrollbarAnnotation = {\n /** Unique identifier for this annotation. */\n id: string;\n\n /**\n * Pixel offset from the top of the scrollable content.\n * Acts as the start position for range markers.\n */\n position: number;\n\n /**\n * Length of the annotation in content pixels.\n *\n * Required when `markerType === \"range\"`. The marker will span\n * `[position, position + extent]` in content space.\n */\n extent?: number;\n\n /**\n * Shape of the minimap marker. Defaults to `\"point\"`.\n */\n markerType?: MarkerType;\n\n /** Visual category – controls colour. */\n type: AnnotationType;\n\n /** Short human-readable label shown in detail views. */\n title: string;\n\n /** Full description shown when the annotation is selected/inspected. */\n description: string;\n\n /**\n * Optional extra CSS class(es) applied to this marker's DOM element.\n *\n * Use this to style individual annotations differently from the default\n * type-based colour, e.g. to highlight a \"selected\" annotation:\n *\n * className: \"swa-selected\"\n */\n className?: string;\n};\n\nexport type ScrollbarWithAnnotationsProps = {\n /**\n * Pihanga card reference for the scrollable main content.\n *\n * The card is rendered inside the scroll container, so it can be any\n * Pihanga card (plain text, a Plate editor, a list, etc.).\n */\n contentCard: PiCardRef;\n\n /**\n * Annotations to display as coloured markers on the scrollbar track.\n */\n annotations: ScrollbarAnnotation[];\n\n /** Optional additional CSS class applied to the root element. */\n className?: string;\n\n /**\n * When `true`, `onAnnotationHovered` events are emitted even while the\n * content container is being scrolled.\n *\n * Defaults to `false` (suppression is the default) to avoid flooding Redux\n * with hover actions as markers pass under the cursor during scroll.\n */\n reportEventsOnScroll?: boolean;\n};\n\n/** Emitted when the user clicks an annotation marker. */\nexport type AnnotationClickedEvent = {\n /** ID of the clicked annotation. */\n annotationId: string;\n /** Full annotation object for convenience. */\n annotation: ScrollbarAnnotation;\n};\n\n/**\n * Emitted when the user hovers over (or away from) an annotation marker.\n *\n * `annotationId` / `annotation` are `null` when the pointer leaves a marker.\n *\n * ⚠️ This event fires frequently during normal cursor movement. Handlers\n * should be kept lightweight (e.g. update a single piece of local state).\n */\nexport type AnnotationHoveredEvent = {\n annotationId: string | null;\n annotation: ScrollbarAnnotation | null;\n};\n\nexport type ScrollbarWithAnnotationsEvents = {\n onAnnotationClicked: AnnotationClickedEvent;\n onAnnotationHovered: AnnotationHoveredEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAkC,iCAElC,IAA2B,EAGtC,CAA+B,GAEpB,IAAoC,EAC/C,GACA,CAAC,sBAAsB,oBAAoB,CAC7C,GAEa,IACX,EACE,EAAkC,kBACpC,GAEW,IACX,EACE,EAAkC,kBACpC"}
@@ -1,64 +1,83 @@
1
- import { useFormContext as e } from "../form/form.context.js";
2
- import { Slider as t } from "../../components/ui/slider.js";
3
- import { useEffect as n, useRef as r, useState as i } from "react";
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { useFormContext as t } from "../form/form.context.js";
3
+ import { Slider as n } from "../../components/ui/slider.js";
4
+ import { useEffect as r, useRef as i, useState as a } from "react";
4
5
  import "@pihanga2/core";
5
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
7
  //#region src/cards/slider/slider.component.tsx
7
- var s = (s) => {
8
- let { name: c, value: l, defaultValue: u, selfManaged: d = !1, min: f = 0, max: p = 100, step: m = 1, disabled: h, debounceMs: g = 0, suppressChangedEvents: _ = !1, label: v, className: y, cardName: b, onChanged: x, onCommitted: S } = s, C = e(), w = C.isInForm && !!c, [T, E] = i(u ?? l ?? f), D = w ? C.formData[c] ?? f : d ? T : l ?? f, O = r(D);
9
- O.current = D;
10
- let k = r(!1), [A, j] = i(D), M = k.current ? A : D, N = r(null), P = r(D);
11
- n(() => () => {
12
- N.current != null && clearTimeout(N.current);
8
+ var c = (c) => {
9
+ let { name: l, value: u, defaultValue: d, selfManaged: f = !1, min: p = 0, max: m = 100, step: h = 1, disabled: g, debounceMs: _ = 0, suppressChangedEvents: v = !1, label: y, showTicks: b = !1, tickStep: x, majorTickStep: S, suppressTickLabels: C = !1, tickLabels: w, className: T, cardName: E, onChanged: D, onCommitted: O } = c, k = t(), A = k.isInForm && !!l, [j, M] = a(d ?? u ?? p), N = A ? k.formData[l] ?? p : f ? j : u ?? p, P = i(N);
10
+ P.current = N;
11
+ let F = i(!1), [I, L] = a(N), R = F.current ? I : N, z = i(null), B = i(N);
12
+ r(() => () => {
13
+ z.current != null && clearTimeout(z.current);
13
14
  }, []);
14
- function F(e) {
15
- _ || (w ? C.handleChange(c, e) : x({
16
- name: c,
15
+ function V(e) {
16
+ v || (A ? k.handleChange(l, e) : D({
17
+ name: l,
17
18
  value: e
18
19
  }));
19
20
  }
20
- function I() {
21
- k.current = !0, j(O.current);
21
+ function H() {
22
+ F.current = !0, L(P.current);
22
23
  }
23
- function L(e) {
24
- let t = e[0] ?? f;
25
- k.current && (j(t), d && !w && E(t), g > 0 ? (P.current = t, N.current != null && clearTimeout(N.current), N.current = setTimeout(() => {
26
- N.current = null, F(P.current);
27
- }, g)) : F(t));
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));
28
29
  }
29
- function R(e) {
30
- let t = e[0] ?? f;
31
- k.current = !1, j(O.current), N.current != null && (clearTimeout(N.current), N.current = null), g > 0 && !_ && F(t), S({
32
- name: c,
30
+ function W(e) {
31
+ let t = e[0] ?? p;
32
+ F.current = !1, L(P.current), z.current != null && (clearTimeout(z.current), z.current = null), _ > 0 && !v && V(t), O({
33
+ name: l,
33
34
  value: t
34
35
  });
35
36
  }
36
- return /* @__PURE__ */ o("div", {
37
- "data-pihanga": b,
38
- className: `flex flex-col gap-2 ${y ?? ""}`,
39
- children: [v && /* @__PURE__ */ o("div", {
40
- className: "flex items-center justify-between",
41
- children: [/* @__PURE__ */ a("span", {
42
- className: "text-sm font-medium leading-none",
43
- children: v
44
- }), /* @__PURE__ */ a("span", {
45
- className: "text-sm text-muted-foreground tabular-nums",
46
- children: M
47
- })]
48
- }), /* @__PURE__ */ a(t, {
49
- value: [M],
50
- min: f,
51
- max: p,
52
- step: m,
53
- disabled: h,
54
- onPointerDown: I,
55
- onValueChange: L,
56
- onValueCommit: R,
57
- className: "w-full"
58
- })]
37
+ let G = x === void 0 ? h : x, K = G > 0, q = K ? G : h, J = q > 0 ? Math.max(q, Math.round((m - p) / 5 / q) * q) : 0, Y = S === void 0 ? J : S, X = Y > 0, Z = b && (K || X), Q = K ? G : Y, $ = Z ? Array.from({ length: Math.round((m - p) / Q) + 1 }, (e, t) => p + t * Q) : [];
38
+ return /* @__PURE__ */ s("div", {
39
+ "data-pihanga": E,
40
+ className: e("flex flex-col gap-2", T),
41
+ children: [
42
+ y && /* @__PURE__ */ s("div", {
43
+ className: "flex items-center justify-between",
44
+ children: [/* @__PURE__ */ o("span", {
45
+ className: "text-sm font-medium leading-none",
46
+ children: y
47
+ }), /* @__PURE__ */ o("span", {
48
+ className: "text-sm text-muted-foreground tabular-nums",
49
+ children: R
50
+ })]
51
+ }),
52
+ /* @__PURE__ */ o(n, {
53
+ value: [R],
54
+ min: p,
55
+ max: m,
56
+ step: h,
57
+ disabled: g,
58
+ onPointerDown: H,
59
+ onValueChange: U,
60
+ onValueCommit: W,
61
+ className: "w-full"
62
+ }),
63
+ Z && /* @__PURE__ */ o("div", {
64
+ "aria-hidden": "true",
65
+ className: "flex w-full items-baseline justify-between px-0.5",
66
+ children: $.map((t) => {
67
+ let n = X && (t - p) % Y === 0, r = t <= R, i = !C && (n || !X), a = i ? w && t in w ? w[t] : String(t) : "";
68
+ return /* @__PURE__ */ s("div", {
69
+ className: "flex flex-col items-center gap-1",
70
+ 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", {
71
+ className: e("text-xs font-medium transition-colors", i ? "text-muted-foreground opacity-100" : "opacity-0"),
72
+ children: a
73
+ })]
74
+ }, t);
75
+ })
76
+ })
77
+ ]
59
78
  });
60
79
  };
61
80
  //#endregion
62
- export { s as SliderComponent };
81
+ export { c as SliderComponent };
63
82
 
64
83
  //# 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 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 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 return (\n <div\n data-pihanga={cardName}\n className={`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 </div>\n );\n};\n"],"mappings":";;;;;;AAMA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,GACP,iBACA,iBAAc,IACd,SAAM,GACN,SAAM,KACN,UAAO,GACP,aACA,gBAAa,GACb,2BAAwB,IACxB,UACA,cACA,aACA,cACA,mBACE,GAGE,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAGvC,CAAC,GAAc,KAAmB,EACtC,KAAgB,KAAa,CAC/B,GAGM,IAAiB,IACjB,EAAK,SAAS,MAAiC,IACjD,IACE,IACC,KAAa,GAId,IAAoB,EAAO,CAAc;CAC/C,EAAkB,UAAU;CAI5B,IAAM,IAAa,EAAO,EAAK,GACzB,CAAC,GAAkB,KACvB,EAAiB,CAAc,GAG3B,IAAe,EAAW,UAAU,IAAmB,GAGvD,IAAgB,EAA6C,IAAI,GACjE,IAAe,EAAe,CAAc;CAGlD,cACe;EACX,AAAI,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO;CACvE,GACC,CAAC,CAAC;CAEL,SAAS,EAAgB,GAAkB;EAErC,MAEA,IACF,EAAK,aAAa,GAAO,CAAQ,IAEjC,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAIA,SAAS,IAAoB;EAE3B,AADA,EAAW,UAAU,IACrB,EAAoB,EAAkB,OAAO;CAC/C;CAEA,SAAS,EAAkB,GAAqB;EAC9C,IAAM,IAAW,EAAU,MAAM;EAG5B,EAAW,YAEhB,EAAoB,CAAQ,GAGxB,KAAe,CAAC,KAClB,EAAgB,CAAQ,GAGtB,IAAa,KAEf,EAAa,UAAU,GACnB,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO,GACrE,EAAc,UAAU,iBAAiB;GAEvC,AADA,EAAc,UAAU,MACxB,EAAgB,EAAa,OAAO;EACtC,GAAG,CAAU,KAEb,EAAgB,CAAQ;CAE5B;CAEA,SAAS,EAAkB,GAAqB;EAC9C,IAAM,IAAW,EAAU,MAAM;EAmBjC,AAfA,EAAW,UAAU,IACrB,EAAoB,EAAkB,OAAO,GAGzC,EAAc,WAAW,SAC3B,aAAa,EAAc,OAAO,GAClC,EAAc,UAAU,OAKtB,IAAa,KAAK,CAAC,KACrB,EAAgB,CAAQ,GAG1B,EAAY;GAAC;GAAM,OAAO;EAAQ,CAAC;CACrC;CAEA,OACE,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,uBAAuB,KAAa;YAFjD,CAIG,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,QAAD;IAAM,WAAU;cAAoC;GAAY,CAAA,GAChE,kBAAC,QAAD;IAAM,WAAU;cACb;GACG,CAAA,CACH;MAEP,kBAAC,GAAD;GACE,OAAO,CAAC,CAAY;GACf;GACA;GACC;GACI;GACV,eAAe;GACf,eAAe;GACf,eAAe;GACf,WAAU;EACX,CAAA,CACE;;AAET"}
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":";;;;;;;AAOA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,GACP,iBACA,iBAAc,IACd,SAAM,GACN,SAAM,KACN,UAAO,GACP,aACA,gBAAa,GACb,2BAAwB,IACxB,UACA,eAAY,IACZ,aACA,kBACA,wBAAqB,IACrB,eACA,cACA,aACA,cACA,mBACE,GAGE,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAGvC,CAAC,GAAc,KAAmB,EACtC,KAAgB,KAAa,CAC/B,GAGM,IAAiB,IACjB,EAAK,SAAS,MAAiC,IACjD,IACE,IACC,KAAa,GAId,IAAoB,EAAO,CAAc;CAC/C,EAAkB,UAAU;CAI5B,IAAM,IAAa,EAAO,EAAK,GACzB,CAAC,GAAkB,KACvB,EAAiB,CAAc,GAG3B,IAAe,EAAW,UAAU,IAAmB,GAGvD,IAAgB,EAA6C,IAAI,GACjE,IAAe,EAAe,CAAc;CAGlD,cACe;EACX,AAAI,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO;CACvE,GACC,CAAC,CAAC;CAEL,SAAS,EAAgB,GAAkB;EAErC,MAEA,IACF,EAAK,aAAa,GAAO,CAAQ,IAEjC,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAIA,SAAS,IAAoB;EAE3B,AADA,EAAW,UAAU,IACrB,EAAoB,EAAkB,OAAO;CAC/C;CAEA,SAAS,EAAkB,GAAqB;EAC9C,IAAM,IAAW,EAAU,MAAM;EAG5B,EAAW,YAEhB,EAAoB,CAAQ,GAGxB,KAAe,CAAC,KAClB,EAAgB,CAAQ,GAGtB,IAAa,KAEf,EAAa,UAAU,GACnB,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO,GACrE,EAAc,UAAU,iBAAiB;GAEvC,AADA,EAAc,UAAU,MACxB,EAAgB,EAAa,OAAO;EACtC,GAAG,CAAU,KAEb,EAAgB,CAAQ;CAE5B;CAEA,SAAS,EAAkB,GAAqB;EAC9C,IAAM,IAAW,EAAU,MAAM;EAmBjC,AAfA,EAAW,UAAU,IACrB,EAAoB,EAAkB,OAAO,GAGzC,EAAc,WAAW,SAC3B,aAAa,EAAc,OAAO,GAClC,EAAc,UAAU,OAKtB,IAAa,KAAK,CAAC,KACrB,EAAgB,CAAQ,GAG1B,EAAY;GAAC;GAAM,OAAO;EAAQ,CAAC;CACrC;CAMA,IAAM,IAAqB,MAAa,KAAA,IAAuB,IAAX,GAC9C,IAAiB,IAAqB,GAKtC,IAAgB,IAAiB,IAAqB,GACtD,IACJ,IAAgB,IACZ,KAAK,IACH,GACA,KAAK,OAAO,IAAM,KAAO,IAAI,CAAa,IAAI,CAChD,IACA,GAEA,IACJ,MAAkB,KAAA,IAA4B,IAAhB,GAC1B,IAAiB,IAAoB,GAErC,IAAc,MAAc,KAAkB,IAG9C,IAAW,IAAiB,IAAqB,GACjD,IAAQ,IACV,MAAM,KACJ,EAAC,QAAQ,KAAK,OAAO,IAAM,KAAO,CAAQ,IAAI,EAAC,IAC9C,GAAG,MAAM,IAAM,IAAI,CACtB,IACA,CAAC;CAEL,OACE,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,EAAG,uBAAuB,CAAS;YAFhD;GAIG,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAoC;IAAY,CAAA,GAChE,kBAAC,QAAD;KAAM,WAAU;eACb;IACG,CAAA,CACH;;GAEP,kBAAC,GAAD;IACE,OAAO,CAAC,CAAY;IACf;IACA;IACC;IACI;IACV,eAAe;IACf,eAAe;IACf,eAAe;IACf,WAAU;GACX,CAAA;GACA,KACC,kBAAC,OAAD;IACE,eAAY;IACZ,WAAU;cAET,EAAM,KAAK,MAAS;KACnB,IAAM,IACJ,MAAmB,IAAO,KAAO,MAAsB,GACnD,IAAW,KAAQ,GAInB,IACJ,CAAC,MAAuB,KAAW,CAAC,IAChC,IAAY,IACd,KAAc,KAAQ,IACpB,EAAW,KACX,OAAO,CAAI,IACb;KAEJ,OACE,kBAAC,OAAD;MAAgB,WAAU;gBAA1B,CACE,kBAAC,OAAD,EACE,WAAW,EACT,kDACA,IAAW,eAAe,iBAC1B,IAAU,QAAQ,OACpB,EACD,CAAA,GACD,kBAAC,QAAD;OACE,WAAW,EACT,yCACA,IACI,sCACA,WACN;iBAEC;MACG,CAAA,CACH;QAlBK,CAkBL;IAET,CAAC;GACE,CAAA;EAEJ;;AAET"}
@@ -89,6 +89,37 @@ export type PiSliderProps = {
89
89
  * When provided, the current numeric value is shown to the right of the label.
90
90
  */
91
91
  label?: string;
92
+ /**
93
+ * When true, tick marks are rendered below the slider track.
94
+ */
95
+ showTicks?: boolean;
96
+ /**
97
+ * Spacing between consecutive **minor** tick marks in value units.
98
+ * Defaults to `step`.
99
+ * Set to `0` to hide minor ticks only — major ticks are still shown
100
+ * if `majorTickStep` is non-zero.
101
+ */
102
+ tickStep?: number;
103
+ /**
104
+ * Interval (in value units) between **major** (tall, labelled) ticks.
105
+ * Defaults to `(max - min) / 5` rounded to the nearest `tickStep`.
106
+ * Set to `0` to hide major ticks only — minor ticks are still shown
107
+ * if `tickStep` is non-zero.
108
+ */
109
+ majorTickStep?: number;
110
+ /**
111
+ * When true, no tick labels are rendered at all (only the tick marks).
112
+ * Overrides `tickLabels` and the default numeric labels.
113
+ */
114
+ suppressTickLabels?: boolean;
115
+ /**
116
+ * Custom labels keyed by value. When provided for a value, the custom
117
+ * string is shown instead of the numeric value. Pass `""` to suppress the
118
+ * label for a specific tick.
119
+ *
120
+ * @example { 0: "Min", 50: "Mid", 100: "Max" }
121
+ */
122
+ tickLabels?: Record<number, string>;
92
123
  /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */
93
124
  className?: string;
94
125
  };
@@ -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 numeric value (single thumb).\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?: number;\n\n /**\n * Initial value used when `selfManaged` is true.\n * Falls back to `value` → `min` → 0 if not provided.\n */\n defaultValue?: number;\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 /** 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 /** 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 numeric value after the change. */\n value: number;\n};\n\nexport type PiSliderCommittedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** Final settled value when the user released the thumb. */\n value: number;\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"}
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 numeric value (single thumb).\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?: number;\n\n /**\n * Initial value used when `selfManaged` is true.\n * Falls back to `value` → `min` → 0 if not provided.\n */\n defaultValue?: number;\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 /** 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 numeric value after the change. */\n value: number;\n};\n\nexport type PiSliderCommittedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** Final settled value when the user released the thumb. */\n value: number;\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"}
@@ -1,5 +1,5 @@
1
1
  import { StepperUI as e } from "../../components/ui/stepper.js";
2
- /* empty css */
2
+ import './stepper.css';/* empty css */
3
3
  import { useState as t } from "react";
4
4
  import { Card as n } from "@pihanga2/core";
5
5
  import { jsx as r } from "react/jsx-runtime";
@@ -0,0 +1 @@
1
+ .pi-stepper{--pi-stepper-indicator-size-sm:1.5rem;--pi-stepper-indicator-size-md:2rem;--pi-stepper-indicator-size-lg:2.5rem;--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-md);--pi-stepper-connector-thickness:2px;--pi-stepper-connector-min-height:1.5rem;--pi-stepper-label-max-width:6rem}.pi-stepper--sm{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-sm)}.pi-stepper--md{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-md)}.pi-stepper--lg{--pi-stepper-indicator-size:var(--pi-stepper-indicator-size-lg)}.pi-stepper__indicator{transition:background-color .2s,border-color .2s,color .2s,outline-color .2s}.pi-stepper__indicator--clickable{cursor:pointer}.pi-stepper__indicator--clickable:hover{opacity:.8}.pi-stepper__indicator--static{cursor:default}.pi-stepper__connector{transition:background-color .3s}.pi-stepper__connector--vertical{min-height:var(--pi-stepper-connector-min-height)}.pi-stepper__label-title{transition:color .2s}
@@ -1,24 +1,24 @@
1
1
  import { cn as e } from "../../lib/utils.js";
2
2
  import "react";
3
- import { jsx as t } from "react/jsx-runtime";
4
- import { Avatar as n } from "radix-ui";
3
+ import { Avatar as t } from "radix-ui";
4
+ import { jsx as n } from "react/jsx-runtime";
5
5
  //#region src/components/ui/avatar.tsx
6
6
  function r({ className: r, ...i }) {
7
- return /* @__PURE__ */ t(n.Root, {
7
+ return /* @__PURE__ */ n(t.Root, {
8
8
  "data-slot": "avatar",
9
9
  className: e("relative flex size-8 shrink-0 overflow-hidden rounded-full", r),
10
10
  ...i
11
11
  });
12
12
  }
13
13
  function i({ className: r, ...i }) {
14
- return /* @__PURE__ */ t(n.Image, {
14
+ return /* @__PURE__ */ n(t.Image, {
15
15
  "data-slot": "avatar-image",
16
16
  className: e("aspect-square size-full", r),
17
17
  ...i
18
18
  });
19
19
  }
20
20
  function a({ className: r, ...i }) {
21
- return /* @__PURE__ */ t(n.Fallback, {
21
+ return /* @__PURE__ */ n(t.Fallback, {
22
22
  "data-slot": "avatar-fallback",
23
23
  className: e("bg-muted flex size-full items-center justify-center rounded-full text-xs", r),
24
24
  ...i
@@ -1,10 +1,10 @@
1
1
  import { cn as e } from "../lib/utils.js";
2
2
  import "react";
3
- import { Slot as t } from "@radix-ui/react-slot";
4
- import { cva as n } from "class-variance-authority";
5
- import { jsx as r } from "react/jsx-runtime";
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ import { Slot as n } from "@radix-ui/react-slot";
5
+ import { cva as r } from "class-variance-authority";
6
6
  //#region src/components/ui/badge.tsx
7
- var i = n("inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", {
7
+ var i = r("inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", {
8
8
  variants: { variant: {
9
9
  default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
10
10
  secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
@@ -13,10 +13,10 @@ var i = n("inline-flex items-center justify-center rounded-full border px-2 py-0
13
13
  } },
14
14
  defaultVariants: { variant: "default" }
15
15
  });
16
- function a({ className: n, variant: a, asChild: o = !1, ...s }) {
17
- return /* @__PURE__ */ r(o ? t : "span", {
16
+ function a({ className: r, variant: a, asChild: o = !1, ...s }) {
17
+ return /* @__PURE__ */ t(o ? n : "span", {
18
18
  "data-slot": "badge",
19
- className: e(i({ variant: a }), n),
19
+ className: e(i({ variant: a }), r),
20
20
  ...s
21
21
  });
22
22
  }
@@ -1,10 +1,10 @@
1
1
  import { cn as e } from "../../lib/utils.js";
2
2
  import "react";
3
- import { cva as t } from "class-variance-authority";
3
+ import { Slot as t } from "radix-ui";
4
4
  import { jsx as n } from "react/jsx-runtime";
5
- import { Slot as r } from "radix-ui";
5
+ import { cva as r } from "class-variance-authority";
6
6
  //#region src/components/ui/button.tsx
7
- var i = t("inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
7
+ var i = r("inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
8
8
  variants: {
9
9
  variant: {
10
10
  default: "bg-primary text-primary-foreground hover:bg-primary/90",
@@ -48,8 +48,8 @@ var i = t("inline-flex shrink-0 items-center justify-center gap-2 rounded-md tex
48
48
  size: "default"
49
49
  }
50
50
  });
51
- function a({ className: t, variant: a = "default", size: o = "default", asChild: s = !1, label: c, active: l, focused: u, isMenu: d, truncate: f, loading: p, isPending: m, loadingClassName: h, ...g }) {
52
- return /* @__PURE__ */ n(s ? r.Root : "button", {
51
+ function a({ className: r, variant: a = "default", size: o = "default", asChild: s = !1, label: c, active: l, focused: u, isMenu: d, truncate: f, loading: p, isPending: m, loadingClassName: h, ...g }) {
52
+ return /* @__PURE__ */ n(s ? t.Root : "button", {
53
53
  "data-slot": "button",
54
54
  "data-variant": a,
55
55
  "data-size": o,
@@ -62,7 +62,7 @@ function a({ className: t, variant: a = "default", size: o = "default", asChild:
62
62
  className: e(i({
63
63
  variant: a,
64
64
  size: o,
65
- className: t
65
+ className: r
66
66
  }), f && "truncate"),
67
67
  ...g
68
68
  });
@@ -0,0 +1,79 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { Drawer as t } from "../../node_modules/vaul/dist/index.js";
3
+ import "react";
4
+ import { jsx as n, jsxs as r } from "react/jsx-runtime";
5
+ //#region src/components/ui/drawer.tsx
6
+ function i({ ...e }) {
7
+ return /* @__PURE__ */ n(t.Root, {
8
+ "data-slot": "drawer",
9
+ ...e
10
+ });
11
+ }
12
+ function a({ ...e }) {
13
+ return /* @__PURE__ */ n(t.Trigger, {
14
+ "data-slot": "drawer-trigger",
15
+ ...e
16
+ });
17
+ }
18
+ function o({ ...e }) {
19
+ return /* @__PURE__ */ n(t.Portal, {
20
+ "data-slot": "drawer-portal",
21
+ ...e
22
+ });
23
+ }
24
+ function s({ ...e }) {
25
+ return /* @__PURE__ */ n(t.Close, {
26
+ "data-slot": "drawer-close",
27
+ ...e
28
+ });
29
+ }
30
+ function c({ className: r, ...i }) {
31
+ return /* @__PURE__ */ n(t.Overlay, {
32
+ "data-slot": "drawer-overlay",
33
+ className: e("fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0", r),
34
+ ...i
35
+ });
36
+ }
37
+ function l({ className: i, children: a, ...s }) {
38
+ return /* @__PURE__ */ r(o, {
39
+ "data-slot": "drawer-portal",
40
+ children: [/* @__PURE__ */ n(c, {}), /* @__PURE__ */ r(t.Content, {
41
+ "data-slot": "drawer-content",
42
+ className: e("group/drawer-content fixed z-50 flex h-auto flex-col bg-background", "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b", "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t", "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm", "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm", i),
43
+ ...s,
44
+ children: [/* @__PURE__ */ n("div", { className: "mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-muted group-data-[vaul-drawer-direction=bottom]/drawer-content:block" }), a]
45
+ })]
46
+ });
47
+ }
48
+ function u({ className: t, ...r }) {
49
+ return /* @__PURE__ */ n("div", {
50
+ "data-slot": "drawer-header",
51
+ className: e("flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left", t),
52
+ ...r
53
+ });
54
+ }
55
+ function d({ className: t, ...r }) {
56
+ return /* @__PURE__ */ n("div", {
57
+ "data-slot": "drawer-footer",
58
+ className: e("mt-auto flex flex-col gap-2 p-4", t),
59
+ ...r
60
+ });
61
+ }
62
+ function f({ className: r, ...i }) {
63
+ return /* @__PURE__ */ n(t.Title, {
64
+ "data-slot": "drawer-title",
65
+ className: e("font-semibold text-foreground", r),
66
+ ...i
67
+ });
68
+ }
69
+ function p({ className: r, ...i }) {
70
+ return /* @__PURE__ */ n(t.Description, {
71
+ "data-slot": "drawer-description",
72
+ className: e("text-sm text-muted-foreground", r),
73
+ ...i
74
+ });
75
+ }
76
+ //#endregion
77
+ export { i as Drawer, s as DrawerClose, l as DrawerContent, p as DrawerDescription, d as DrawerFooter, u as DrawerHeader, f as DrawerTitle, a as DrawerTrigger };
78
+
79
+ //# sourceMappingURL=drawer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drawer.js","names":[],"sources":["../../../src/components/ui/drawer.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Root>) {\n return <DrawerPrimitive.Root data-slot=\"drawer\" {...props} />\n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {\n return <DrawerPrimitive.Trigger data-slot=\"drawer-trigger\" {...props} />\n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Portal>) {\n return <DrawerPrimitive.Portal data-slot=\"drawer-portal\" {...props} />\n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Close>) {\n return <DrawerPrimitive.Close data-slot=\"drawer-close\" {...props} />\n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {\n return (\n <DrawerPrimitive.Overlay\n data-slot=\"drawer-overlay\"\n className={cn(\n \"fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Content>) {\n return (\n <DrawerPortal data-slot=\"drawer-portal\">\n <DrawerOverlay />\n <DrawerPrimitive.Content\n data-slot=\"drawer-content\"\n className={cn(\n \"group/drawer-content fixed z-50 flex h-auto flex-col bg-background\",\n \"data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b\",\n \"data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t\",\n \"data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm\",\n \"data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm\",\n className\n )}\n {...props}\n >\n <div className=\"mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full bg-muted group-data-[vaul-drawer-direction=bottom]/drawer-content:block\" />\n {children}\n </DrawerPrimitive.Content>\n </DrawerPortal>\n )\n}\n\nfunction DrawerHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-header\"\n className={cn(\n \"flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DrawerFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"drawer-footer\"\n className={cn(\"mt-auto flex flex-col gap-2 p-4\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerTitle({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Title>) {\n return (\n <DrawerPrimitive.Title\n data-slot=\"drawer-title\"\n className={cn(\"font-semibold text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction DrawerDescription({\n className,\n ...props\n}: React.ComponentProps<typeof DrawerPrimitive.Description>) {\n return (\n <DrawerPrimitive.Description\n data-slot=\"drawer-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Drawer,\n DrawerPortal,\n DrawerOverlay,\n DrawerTrigger,\n DrawerClose,\n DrawerContent,\n DrawerHeader,\n DrawerFooter,\n DrawerTitle,\n DrawerDescription,\n}\n"],"mappings":";;;;;AAKA,SAAS,EAAO,EACd,GAAG,KACiD;CACpD,OAAO,kBAAC,EAAgB,MAAjB;EAAsB,aAAU;EAAS,GAAI;CAAQ,CAAA;AAC9D;AAEA,SAAS,EAAc,EACrB,GAAG,KACoD;CACvD,OAAO,kBAAC,EAAgB,SAAjB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,EAAa,EACpB,GAAG,KACmD;CACtD,OAAO,kBAAC,EAAgB,QAAjB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,EAAY,EACnB,GAAG,KACkD;CACrD,OAAO,kBAAC,EAAgB,OAAjB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,EAAc,EACrB,cACA,GAAG,KACoD;CACvD,OACE,kBAAC,EAAgB,SAAjB;EACE,aAAU;EACV,WAAW,EACT,0JACA,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAc,EACrB,cACA,aACA,GAAG,KACoD;CACvD,OACE,kBAAC,GAAD;EAAc,aAAU;YAAxB,CACE,kBAAC,GAAD,CAAgB,CAAA,GAChB,kBAAC,EAAgB,SAAjB;GACE,aAAU;GACV,WAAW,EACT,sEACA,kQACA,uRACA,+NACA,yNACA,CACF;GACA,GAAI;aAVN,CAYE,kBAAC,OAAD,EAAK,WAAU,kIAAmI,CAAA,GACjJ,CACsB;IACb;;AAElB;AAEA,SAAS,EAAa,EAAE,cAAW,GAAG,KAAsC;CAC1E,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,4LACA,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAa,EAAE,cAAW,GAAG,KAAsC;CAC1E,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,mCAAmC,CAAS;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAY,EACnB,cACA,GAAG,KACkD;CACrD,OACE,kBAAC,EAAgB,OAAjB;EACE,aAAU;EACV,WAAW,EAAG,iCAAiC,CAAS;EACxD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAkB,EACzB,cACA,GAAG,KACwD;CAC3D,OACE,kBAAC,EAAgB,aAAjB;EACE,aAAU;EACV,WAAW,EAAG,iCAAiC,CAAS;EACxD,GAAI;CACL,CAAA;AAEL"}