@pihanga2/shadcn 0.2.18 → 0.2.19

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 (70) hide show
  1. package/README.md +4 -1
  2. package/cards/button/button.types.d.ts +2 -2
  3. package/cards/checkbox/checkbox.types.d.ts +2 -2
  4. package/cards/codeMirror/codeMirror.types.d.ts +1 -1
  5. package/cards/collapsibleCard/collapsibleCard.types.d.ts +1 -1
  6. package/cards/dataTable/dataTable.types.d.ts +5 -5
  7. package/cards/dialog/dialog.types.d.ts +3 -3
  8. package/cards/drawer/drawer.types.d.ts +3 -3
  9. package/cards/dropDownMenu/drop-down.types.d.ts +1 -1
  10. package/cards/emptyCard/emptyCard.component.js +25 -0
  11. package/cards/emptyCard/emptyCard.component.js.map +1 -0
  12. package/cards/emptyCard/emptyCard.types.js +7 -0
  13. package/cards/emptyCard/emptyCard.types.js.map +1 -0
  14. package/cards/emptyCard/index.js +12 -0
  15. package/cards/emptyCard/index.js.map +1 -0
  16. package/cards/fileDrop/fileDrop.types.d.ts +2 -2
  17. package/cards/form/form.types.d.ts +2 -2
  18. package/cards/graphin/graphin.types.d.ts +9 -9
  19. package/cards/input/input.component.js +28 -23
  20. package/cards/input/input.component.js.map +1 -1
  21. package/cards/input/input.types.d.ts +10 -4
  22. package/cards/input/input.types.js.map +1 -1
  23. package/cards/jsonViewer/jsonViewer.types.d.ts +2 -2
  24. package/cards/keyboardOverlay/keyboardOverlay.component.js +1 -0
  25. package/cards/keyboardOverlay/keyboardOverlay.component.js.map +1 -1
  26. package/cards/keyboardOverlay/keyboardOverlay.types.d.ts +1 -1
  27. package/cards/list/list.types.d.ts +1 -1
  28. package/cards/menu/menu.types.d.ts +1 -1
  29. package/cards/modeToggle/mode-toggle.types.d.ts +1 -1
  30. package/cards/navbarSearch/navbarSearch.type.d.ts +3 -3
  31. package/cards/observable/index.d.ts +1 -0
  32. package/cards/observable/index.js +13 -0
  33. package/cards/observable/index.js.map +1 -0
  34. package/cards/observable/observable.component.d.ts +4 -0
  35. package/cards/observable/observable.component.js +74 -0
  36. package/cards/observable/observable.component.js.map +1 -0
  37. package/cards/observable/observable.types.d.ts +253 -0
  38. package/cards/observable/observable.types.js +21 -0
  39. package/cards/observable/observable.types.js.map +1 -0
  40. package/cards/pageWithNavbar/pageWithNavbar.type.d.ts +1 -1
  41. package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +1 -1
  42. package/cards/pasteTarget/pasteTarget.types.d.ts +2 -2
  43. package/cards/scrollbarWithAnnotations/scrollbarWithAnnotations.types.d.ts +2 -2
  44. package/cards/select/select.types.d.ts +6 -6
  45. package/cards/sheetCard/sheetCard.types.d.ts +3 -3
  46. package/cards/slider/slider.types.d.ts +4 -4
  47. package/cards/stack/stack.component.js +51 -38
  48. package/cards/stack/stack.component.js.map +1 -1
  49. package/cards/stepper/stepper.types.d.ts +1 -1
  50. package/cards/switch/switch.types.d.ts +2 -2
  51. package/cards/tabs/tabs.types.d.ts +1 -1
  52. package/cards/textArea/index.d.ts +1 -0
  53. package/cards/textArea/index.js +13 -0
  54. package/cards/textArea/index.js.map +1 -0
  55. package/cards/textArea/textArea.component.d.ts +4 -0
  56. package/cards/textArea/textArea.component.js +83 -0
  57. package/cards/textArea/textArea.component.js.map +1 -0
  58. package/cards/textArea/textArea.types.d.ts +147 -0
  59. package/cards/textArea/textArea.types.js +7 -0
  60. package/cards/textArea/textArea.types.js.map +1 -0
  61. package/cards/textField/textField.types.d.ts +2 -2
  62. package/cards/toast/toast.types.d.ts +3 -3
  63. package/cards/toggleGroup/toggleGroup.types.d.ts +2 -2
  64. package/components/ui/empty.js +40 -0
  65. package/components/ui/empty.js.map +1 -0
  66. package/components/ui/input.js +11 -11
  67. package/components/ui/input.js.map +1 -1
  68. package/components/ui/textarea.js +15 -0
  69. package/components/ui/textarea.js.map +1 -0
  70. package/package.json +18 -2
@@ -3,83 +3,96 @@ import { Card as t } from "@pihanga2/core";
3
3
  import n from "clsx";
4
4
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
5
5
  //#region src/cards/stack/stack.component.tsx
6
- var a = (a) => {
7
- let { content: o, direction: s, divider: c, spacing: l, justifyContent: u, alignItems: d, className: f, style: p, cardName: m, data: h } = a, g = [
8
- f,
9
- (p ?? {}).root,
6
+ function a(e) {
7
+ let t = 2166136261;
8
+ for (let n = 0; n < e.length; n++) t ^= e.charCodeAt(n), t = Math.imul(t, 16777619);
9
+ return (t >>> 0).toString(36);
10
+ }
11
+ function o(e, t) {
12
+ if (typeof e == "string") return e;
13
+ let n = Object.keys(e).sort();
14
+ return `${a(JSON.stringify(e, n))}-${t}`;
15
+ }
16
+ var s = (a) => {
17
+ let { content: s, direction: c, divider: l, spacing: u, justifyContent: d, alignItems: f, className: p, style: m, cardName: h, data: g } = a, _ = [
18
+ p,
19
+ (m ?? {}).root,
10
20
  "flex"
11
21
  ];
12
- if (s) switch (s) {
22
+ if (c) switch (c) {
13
23
  case "row":
14
- g.push("flex-row");
24
+ _.push("flex-row");
15
25
  break;
16
26
  case "row-reverse":
17
- g.push("flex-row-reverse");
27
+ _.push("flex-row-reverse");
18
28
  break;
19
29
  case "column":
20
- g.push("flex-col");
30
+ _.push("flex-col");
21
31
  break;
22
32
  case "column-reverse":
23
- g.push("flex-col-reverse");
33
+ _.push("flex-col-reverse");
24
34
  break;
25
35
  }
26
- if (u) switch (u) {
36
+ if (d) switch (d) {
27
37
  case "flex-start":
28
- g.push("justify-start");
38
+ _.push("justify-start");
29
39
  break;
30
40
  case "center":
31
- g.push("justify-center");
41
+ _.push("justify-center");
32
42
  break;
33
43
  case "flex-end":
34
- g.push("justify-end");
44
+ _.push("justify-end");
35
45
  break;
36
46
  case "space-between":
37
- g.push("justify-between");
47
+ _.push("justify-between");
38
48
  break;
39
49
  case "space-around":
40
- g.push("justify-around");
50
+ _.push("justify-around");
41
51
  break;
42
52
  case "space-evenly":
43
- g.push("justify-evenly");
53
+ _.push("justify-evenly");
44
54
  break;
45
55
  }
46
- if (d) switch (d) {
56
+ if (f) switch (f) {
47
57
  case "flex-start":
48
- g.push("items-start");
58
+ _.push("items-start");
49
59
  break;
50
60
  case "center":
51
- g.push("items-center");
61
+ _.push("items-center");
52
62
  break;
53
63
  case "stretch":
54
- g.push("items-stretch");
64
+ _.push("items-stretch");
55
65
  break;
56
66
  case "flex-end":
57
- g.push("items-end");
67
+ _.push("items-end");
58
68
  break;
59
69
  case "baseline":
60
- g.push("items-baseline");
70
+ _.push("items-baseline");
61
71
  break;
62
- default: console.warn("stack: unsupported 'alignItems' property", d);
72
+ default: console.warn("stack: unsupported 'alignItems' property", f);
63
73
  }
64
- l && l > 0 && g.push(`gap-${l}`);
65
- function _() {
66
- return o ? o.map((n, a) => /* @__PURE__ */ i(e, { children: [/* @__PURE__ */ r(t, {
67
- cardName: n,
68
- parentCard: m
69
- }, `item-${a}`), c && a < o.length - 1 && /* @__PURE__ */ r(t, {
70
- cardName: c,
71
- parentCard: m
72
- }, `divider-${a}`)] }, a)) : null;
74
+ u && u > 0 && _.push(`gap-${u}`);
75
+ function v() {
76
+ return s ? s.map((n, a) => {
77
+ let c = o(n, a);
78
+ return /* @__PURE__ */ i(e, { children: [/* @__PURE__ */ r(t, {
79
+ cardName: n,
80
+ parentCard: h
81
+ }, `item-${c}`), l && a < s.length - 1 && /* @__PURE__ */ r(t, {
82
+ cardName: l,
83
+ parentCard: h
84
+ }, `divider-${c}`)] }, c);
85
+ }) : null;
73
86
  }
74
- let v = h ? Object.fromEntries(Object.entries(h).map(([e, t]) => [`data-${e}`, t])) : {};
87
+ let y = g ? Object.fromEntries(Object.entries(g).map(([e, t]) => [`data-${e}`, t])) : {};
75
88
  return /* @__PURE__ */ i("div", {
76
- className: n(g),
77
- "data-pihanga": m,
78
- ...v,
79
- children: [_(), a.children]
89
+ className: n(_),
90
+ "data-pihanga": h,
91
+ ...y,
92
+ children: [v(), a.children]
80
93
  });
81
94
  };
82
95
  //#endregion
83
- export { a as Component };
96
+ export { s as Component };
84
97
 
85
98
  //# sourceMappingURL=stack.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stack.component.js","names":[],"sources":["../../../src/cards/stack/stack.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport type {StackProps} from \"./stack.types\";\n\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport clsx from \"clsx\";\nimport {Fragment} from \"react\";\n\nexport type SelectSD = {\n root?: string;\n};\n\nexport const Component = (props: PiCardProps<StackProps>): React.ReactNode => {\n const {\n content,\n direction,\n divider,\n spacing,\n justifyContent,\n alignItems,\n className,\n style,\n cardName,\n data,\n } = props;\n const sd: SelectSD = (style as SelectSD | undefined) ?? {};\n\n const cn = [className, sd.root, \"flex\"];\n if (direction) {\n switch (direction) {\n // \"column-reverse\" | \"column\" | \"row-reverse\" | \"row\"\n case \"row\":\n cn.push(\"flex-row\");\n break;\n case \"row-reverse\":\n cn.push(\"flex-row-reverse\");\n break;\n case \"column\":\n cn.push(\"flex-col\");\n break;\n case \"column-reverse\":\n cn.push(\"flex-col-reverse\");\n break;\n }\n }\n if (justifyContent) {\n switch (justifyContent) {\n // \"flex-start\" | \"center\" | \"flex-end\" | \"space-between\" | \"space-around\" | \"space-evenly\"\n case \"flex-start\":\n cn.push(\"justify-start\");\n break;\n case \"center\":\n cn.push(\"justify-center\");\n break;\n case \"flex-end\":\n cn.push(\"justify-end\");\n break;\n case \"space-between\":\n cn.push(\"justify-between\");\n break;\n case \"space-around\":\n cn.push(\"justify-around\");\n break;\n case \"space-evenly\":\n cn.push(\"justify-evenly\");\n break;\n }\n }\n if (alignItems) {\n switch (alignItems) {\n // \"flex-start\" | \"center\" | \"flex-end\" | \"normal\" | \"stretch\" | \"start\" | \"end\" | \"baseline\" | \"initial\" | \"inherit\"\n case \"flex-start\":\n cn.push(\"items-start\");\n break;\n case \"center\":\n cn.push(\"items-center\");\n break;\n case \"stretch\":\n cn.push(\"items-stretch\");\n break;\n case \"flex-end\":\n cn.push(\"items-end\");\n break;\n case \"baseline\":\n cn.push(\"items-baseline\");\n break;\n default:\n console.warn(\"stack: unsupported 'alignItems' property\", alignItems);\n }\n }\n if (spacing && spacing > 0) {\n if (\n direction === undefined ||\n direction === \"row\" ||\n direction === \"row-reverse\"\n ) {\n cn.push(`gap-${spacing}`);\n } else {\n cn.push(`gap-${spacing}`);\n }\n }\n\n function renderContent() {\n if (!content) return null;\n\n return content.map((cn, i) => (\n <Fragment key={i}>\n <Card cardName={cn} parentCard={cardName} key={`item-${i}`} />\n {divider && i < content.length - 1 && (\n <Card cardName={divider} parentCard={cardName} key={`divider-${i}`} />\n )}\n </Fragment>\n ));\n }\n\n const dataAttrs = data\n ? Object.fromEntries(Object.entries(data).map(([k, v]) => [`data-${k}`, v]))\n : {};\n\n return (\n <div className={clsx(cn)} data-pihanga={cardName} {...dataAttrs}>\n {renderContent()}\n {props.children}\n </div>\n );\n};\n"],"mappings":";;;;;AAWA,IAAa,KAAa,MAAoD;CAC5E,IAAM,EACJ,YACA,cACA,YACA,YACA,mBACA,eACA,cACA,UACA,aACA,YACE,GAGE,IAAK;EAAC;GAFU,KAAkC,CAAC,GAE/B;EAAM;CAAM;CACtC,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,UAAU;GAClB;EACF,KAAK;GACH,EAAG,KAAK,kBAAkB;GAC1B;EACF,KAAK;GACH,EAAG,KAAK,UAAU;GAClB;EACF,KAAK;GACH,EAAG,KAAK,kBAAkB;GAC1B;CACJ;CAEF,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,eAAe;GACvB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,KAAK;GACH,EAAG,KAAK,aAAa;GACrB;EACF,KAAK;GACH,EAAG,KAAK,iBAAiB;GACzB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;CACJ;CAEF,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,aAAa;GACrB;EACF,KAAK;GACH,EAAG,KAAK,cAAc;GACtB;EACF,KAAK;GACH,EAAG,KAAK,eAAe;GACvB;EACF,KAAK;GACH,EAAG,KAAK,WAAW;GACnB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,SACE,QAAQ,KAAK,4CAA4C,CAAU;CACvE;CAEF,AAAI,KAAW,IAAU,KAMrB,EAAG,KAAK,OAAO,GAAS;CAM5B,SAAS,IAAgB;EAGvB,OAFK,IAEE,EAAQ,KAAK,GAAI,MACtB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAM,UAAU;GAAI,YAAY;EAA6B,GAAd,QAAQ,GAAM,GAC5D,KAAW,IAAI,EAAQ,SAAS,KAC/B,kBAAC,GAAD;GAAM,UAAU;GAAS,YAAY;EAAgC,GAAjB,WAAW,GAAM,CAE/D,EAAA,GALK,CAKL,CACX,IAToB;CAUvB;CAEA,IAAM,IAAY,IACd,OAAO,YAAY,OAAO,QAAQ,CAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,IACzE,CAAC;CAEL,OACE,kBAAC,OAAD;EAAK,WAAW,EAAK,CAAE;EAAG,gBAAc;EAAU,GAAI;YAAtD,CACG,EAAc,GACd,EAAM,QACJ;;AAET"}
1
+ {"version":3,"file":"stack.component.js","names":[],"sources":["../../../src/cards/stack/stack.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport type {StackProps} from \"./stack.types\";\n\nimport {Card, type PiCardProps, type PiCardRef} from \"@pihanga2/core\";\nimport clsx from \"clsx\";\nimport {Fragment} from \"react\";\n\nexport type SelectSD = {\n root?: string;\n};\n\n/**\n * Cheap, non-cryptographic FNV-1a hash — good enough to turn an arbitrary\n * string into a short, stable identifier for use as a React key.\n */\nfunction fnv1aHash(str: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < str.length; i++) {\n hash ^= str.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(36);\n}\n\n/**\n * Derive a stable React key for a `PiCardRef`.\n *\n * - Strings (card names) are already unique — used as-is.\n * - Inline `PiCardDef` objects have no identity of their own, and two\n * structurally-identical defs created on different renders are different\n * object references. We hash the (key-sorted) JSON content so that\n * identical content maps to the same key — preserving React's\n * reconciliation identity across re-renders/reorders — while still\n * appending `i` so a hash collision (or two genuinely different defs\n * that hash the same) can never produce a duplicate key within the list.\n */\nfunction cardRefKey(cn: PiCardRef, i: number): string {\n if (typeof cn === \"string\") return cn;\n const sortedKeys = Object.keys(cn).sort();\n const json = JSON.stringify(cn, sortedKeys);\n return `${fnv1aHash(json)}-${i}`;\n}\n\nexport const Component = (props: PiCardProps<StackProps>): React.ReactNode => {\n const {\n content,\n direction,\n divider,\n spacing,\n justifyContent,\n alignItems,\n className,\n style,\n cardName,\n data,\n } = props;\n const sd: SelectSD = (style as SelectSD | undefined) ?? {};\n\n const cn = [className, sd.root, \"flex\"];\n if (direction) {\n switch (direction) {\n // \"column-reverse\" | \"column\" | \"row-reverse\" | \"row\"\n case \"row\":\n cn.push(\"flex-row\");\n break;\n case \"row-reverse\":\n cn.push(\"flex-row-reverse\");\n break;\n case \"column\":\n cn.push(\"flex-col\");\n break;\n case \"column-reverse\":\n cn.push(\"flex-col-reverse\");\n break;\n }\n }\n if (justifyContent) {\n switch (justifyContent) {\n // \"flex-start\" | \"center\" | \"flex-end\" | \"space-between\" | \"space-around\" | \"space-evenly\"\n case \"flex-start\":\n cn.push(\"justify-start\");\n break;\n case \"center\":\n cn.push(\"justify-center\");\n break;\n case \"flex-end\":\n cn.push(\"justify-end\");\n break;\n case \"space-between\":\n cn.push(\"justify-between\");\n break;\n case \"space-around\":\n cn.push(\"justify-around\");\n break;\n case \"space-evenly\":\n cn.push(\"justify-evenly\");\n break;\n }\n }\n if (alignItems) {\n switch (alignItems) {\n // \"flex-start\" | \"center\" | \"flex-end\" | \"normal\" | \"stretch\" | \"start\" | \"end\" | \"baseline\" | \"initial\" | \"inherit\"\n case \"flex-start\":\n cn.push(\"items-start\");\n break;\n case \"center\":\n cn.push(\"items-center\");\n break;\n case \"stretch\":\n cn.push(\"items-stretch\");\n break;\n case \"flex-end\":\n cn.push(\"items-end\");\n break;\n case \"baseline\":\n cn.push(\"items-baseline\");\n break;\n default:\n console.warn(\"stack: unsupported 'alignItems' property\", alignItems);\n }\n }\n if (spacing && spacing > 0) {\n if (\n direction === undefined ||\n direction === \"row\" ||\n direction === \"row-reverse\"\n ) {\n cn.push(`gap-${spacing}`);\n } else {\n cn.push(`gap-${spacing}`);\n }\n }\n\n function renderContent() {\n if (!content) return null;\n\n return content.map((cn, i) => {\n const key = cardRefKey(cn, i);\n return (\n <Fragment key={key}>\n <Card cardName={cn} parentCard={cardName} key={`item-${key}`} />\n {divider && i < content.length - 1 && (\n <Card\n cardName={divider}\n parentCard={cardName}\n key={`divider-${key}`}\n />\n )}\n </Fragment>\n );\n });\n }\n\n const dataAttrs = data\n ? Object.fromEntries(Object.entries(data).map(([k, v]) => [`data-${k}`, v]))\n : {};\n\n return (\n <div className={clsx(cn)} data-pihanga={cardName} {...dataAttrs}>\n {renderContent()}\n {props.children}\n </div>\n );\n};\n"],"mappings":";;;;;AAeA,SAAS,EAAU,GAAqB;CACtC,IAAI,IAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAI,QAAQ,KAE9B,AADA,KAAQ,EAAI,WAAW,CAAC,GACxB,IAAO,KAAK,KAAK,GAAM,QAAU;CAEnC,QAAQ,MAAS,GAAG,SAAS,EAAE;AACjC;AAcA,SAAS,EAAW,GAAe,GAAmB;CACpD,IAAI,OAAO,KAAO,UAAU,OAAO;CACnC,IAAM,IAAa,OAAO,KAAK,CAAE,EAAE,KAAK;CAExC,OAAO,GAAG,EADG,KAAK,UAAU,GAAI,CACZ,CAAI,EAAE,GAAG;AAC/B;AAEA,IAAa,KAAa,MAAoD;CAC5E,IAAM,EACJ,YACA,cACA,YACA,YACA,mBACA,eACA,cACA,UACA,aACA,YACE,GAGE,IAAK;EAAC;GAFU,KAAkC,CAAC,GAE/B;EAAM;CAAM;CACtC,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,UAAU;GAClB;EACF,KAAK;GACH,EAAG,KAAK,kBAAkB;GAC1B;EACF,KAAK;GACH,EAAG,KAAK,UAAU;GAClB;EACF,KAAK;GACH,EAAG,KAAK,kBAAkB;GAC1B;CACJ;CAEF,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,eAAe;GACvB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,KAAK;GACH,EAAG,KAAK,aAAa;GACrB;EACF,KAAK;GACH,EAAG,KAAK,iBAAiB;GACzB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;CACJ;CAEF,IAAI,GACF,QAAQ,GAAR;EAEE,KAAK;GACH,EAAG,KAAK,aAAa;GACrB;EACF,KAAK;GACH,EAAG,KAAK,cAAc;GACtB;EACF,KAAK;GACH,EAAG,KAAK,eAAe;GACvB;EACF,KAAK;GACH,EAAG,KAAK,WAAW;GACnB;EACF,KAAK;GACH,EAAG,KAAK,gBAAgB;GACxB;EACF,SACE,QAAQ,KAAK,4CAA4C,CAAU;CACvE;CAEF,AAAI,KAAW,IAAU,KAMrB,EAAG,KAAK,OAAO,GAAS;CAM5B,SAAS,IAAgB;EAGvB,OAFK,IAEE,EAAQ,KAAK,GAAI,MAAM;GAC5B,IAAM,IAAM,EAAW,GAAI,CAAC;GAC5B,OACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAM,UAAU;IAAI,YAAY;GAA+B,GAAhB,QAAQ,GAAQ,GAC9D,KAAW,IAAI,EAAQ,SAAS,KAC/B,kBAAC,GAAD;IACE,UAAU;IACV,YAAY;GAEb,GADM,WAAW,GACjB,CAEK,EAAA,GATK,CASL;EAEd,CAAC,IAhBoB;CAiBvB;CAEA,IAAM,IAAY,IACd,OAAO,YAAY,OAAO,QAAQ,CAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,IACzE,CAAC;CAEL,OACE,kBAAC,OAAD;EAAK,WAAW,EAAK,CAAE;EAAG,gBAAc;EAAU,GAAI;YAAtD,CACG,EAAc,GACd,EAAM,QACJ;;AAET"}
@@ -4,7 +4,7 @@ export declare const Stepper: <S extends import('@pihanga2/core').ReduxState>(p:
4
4
  export declare const STEPPER_ACTION: {
5
5
  STEPCLICKED: string;
6
6
  };
7
- export declare const onStepperStepClicked: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
7
+ export declare const onStepperStepClicked: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
8
8
  cardID: string;
9
9
  } & StepperStepClickedEvent>) => void;
10
10
  /**
@@ -3,11 +3,11 @@ export declare const Switch: <S extends import('@pihanga2/core').ReduxState>(p:
3
3
  export declare const PI_SWITCH_ACTION: {
4
4
  CHANGED: string;
5
5
  };
6
- export declare const onSwitchChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
6
+ export declare const onSwitchChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
7
7
  cardID: string;
8
8
  } & PiSwitchChangedEvent>) => void;
9
9
  /** @deprecated Use `onSwitchChanged` instead. */
10
- export declare const onPiSwitchChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
10
+ export declare const onPiSwitchChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
11
  cardID: string;
12
12
  } & PiSwitchChangedEvent>) => void;
13
13
  export type PiSwitchProps = {
@@ -6,7 +6,7 @@ export declare const SdTabs: <S extends import('@pihanga2/core').ReduxState>(p:
6
6
  export declare const TABS_ACTION: {
7
7
  TABCHANGED: string;
8
8
  };
9
- export declare const onTabsTabChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
9
+ export declare const onTabsTabChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
10
10
  cardID: string;
11
11
  } & TabsTabChangedEvent>) => void;
12
12
  /**
@@ -0,0 +1 @@
1
+ export * from './textArea.types';
@@ -0,0 +1,13 @@
1
+ import { TextAreaComponent as e } from "./textArea.component.js";
2
+ import { PI_TEXT_AREA_ACTION as t, PI_TEXT_AREA_CARD as n, TextArea as r, onTextAreaChanged as i, onTextAreaSubmitted as a } from "./textArea.types.js";
3
+ import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
4
+ //#region src/cards/textArea/index.ts
5
+ s({
6
+ name: n,
7
+ component: e,
8
+ events: o(t)
9
+ });
10
+ //#endregion
11
+ export { t as PI_TEXT_AREA_ACTION, n as PI_TEXT_AREA_CARD, r as TextArea, i as onTextAreaChanged, a as onTextAreaSubmitted };
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/textArea/index.ts"],"sourcesContent":["import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {TextAreaComponent} from \"./textArea.component\";\nimport {PI_TEXT_AREA_ACTION, PI_TEXT_AREA_CARD} from \"./textArea.types\";\n\nexport * from \"./textArea.types\";\n\nregisterCardComponent({\n name: PI_TEXT_AREA_CARD,\n component: TextAreaComponent,\n events: actionTypesToEvents(PI_TEXT_AREA_ACTION),\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAmB;AACjD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ import { PiCardProps } from '@pihanga2/core';
3
+ import { PiTextAreaEvents, PiTextAreaProps } from './textArea.types';
4
+ export declare const TextAreaComponent: (props: PiCardProps<PiTextAreaProps, PiTextAreaEvents>) => React.ReactNode;
@@ -0,0 +1,83 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { useFormContext as t } from "../form/form.context.js";
3
+ import { Textarea as n } from "../../components/ui/textarea.js";
4
+ import { useEffect as r, useRef as i, useState as ee } from "react";
5
+ import "@pihanga2/core";
6
+ import { jsx as a } from "react/jsx-runtime";
7
+ //#region src/cards/textArea/textArea.component.tsx
8
+ function o(e) {
9
+ if (e !== void 0) return typeof e == "number" ? `${e}px` : e;
10
+ }
11
+ var s = (s) => {
12
+ let { name: c, value: l = "", placeholder: u, disabled: d, readOnly: f, rows: p = 4, cols: m, fieldSizing: h = "fixed", resize: g, minHeight: _, maxHeight: v, width: y, height: b, maxWidth: x, dir: S, writingMode: C, submitOnEnter: w, selfManaged: T = !1, debounceMs: E = 0, className: D, style: O, autoFocus: k, cardName: A, onChanged: j, onSubmitted: M } = s, N = i(null);
13
+ r(() => {
14
+ k && N.current?.focus();
15
+ }, []);
16
+ let P = s.id, F = !!s.invalid, I = t(), L = I.isInForm && !!c, R = L ? I.formData[c] ?? "" : l, z = T && !L, [B, V] = ee(R), H = i(null), U = i(R);
17
+ r(() => {
18
+ z && V(R);
19
+ }, [R, z]), r(() => () => {
20
+ H.current != null && clearTimeout(H.current);
21
+ }, []);
22
+ let W = z ? B : R;
23
+ function G(e) {
24
+ L ? I.handleChange(c, e) : j({
25
+ name: c,
26
+ value: e
27
+ });
28
+ }
29
+ function K(e) {
30
+ let t = e.target.value;
31
+ if (!z) {
32
+ G(t);
33
+ return;
34
+ }
35
+ V(t), U.current = t, E > 0 && (H.current != null && clearTimeout(H.current), H.current = setTimeout(() => {
36
+ H.current = null, G(U.current);
37
+ }, E));
38
+ }
39
+ function q() {
40
+ z && (H.current != null && (clearTimeout(H.current), H.current = null), G(U.current));
41
+ }
42
+ function J(e) {
43
+ if (w && e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey) {
44
+ e.preventDefault();
45
+ let t = e.currentTarget.value;
46
+ z && H.current != null && (clearTimeout(H.current), H.current = null, G(t)), M({
47
+ name: c,
48
+ value: t
49
+ });
50
+ }
51
+ }
52
+ let Y = g ?? (h === "content" ? "none" : "vertical"), X = Y === "none" ? "resize-none" : Y === "vertical" ? "resize-y" : Y === "horizontal" ? "resize-x" : "resize", Z = h === "content" ? "field-sizing-content" : "field-sizing-fixed", Q = {
53
+ minHeight: o(_),
54
+ maxHeight: o(v),
55
+ width: o(y),
56
+ height: o(b),
57
+ maxWidth: o(x),
58
+ writingMode: C,
59
+ ...O
60
+ }, $ = `${A}-${c ?? "field"}`;
61
+ return /* @__PURE__ */ a(n, {
62
+ ref: N,
63
+ id: P ?? $,
64
+ value: W,
65
+ onChange: K,
66
+ onBlur: q,
67
+ onKeyDown: J,
68
+ placeholder: u,
69
+ disabled: d,
70
+ readOnly: f,
71
+ rows: h === "fixed" ? p : void 0,
72
+ cols: h === "fixed" ? m : void 0,
73
+ dir: S,
74
+ "aria-invalid": F || void 0,
75
+ "data-pihanga": A,
76
+ className: e(Z, X, D),
77
+ style: Q
78
+ });
79
+ };
80
+ //#endregion
81
+ export { s as TextAreaComponent };
82
+
83
+ //# sourceMappingURL=textArea.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textArea.component.js","names":[],"sources":["../../../src/cards/textArea/textArea.component.tsx"],"sourcesContent":["import React, {useEffect, useRef, useState} from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Textarea} from \"@/components/ui/textarea\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport {cn} from \"@/lib/utils\";\nimport type {\n CssLength,\n PiTextAreaEvents,\n PiTextAreaProps,\n} from \"./textArea.types\";\n\nfunction toCssLength(v: CssLength | undefined): string | undefined {\n if (v === undefined) return undefined;\n return typeof v === \"number\" ? `${v}px` : v;\n}\n\nexport const TextAreaComponent = (\n props: PiCardProps<PiTextAreaProps, PiTextAreaEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue = \"\",\n placeholder,\n disabled,\n readOnly,\n rows = 4,\n cols,\n fieldSizing = \"fixed\",\n resize,\n minHeight,\n maxHeight,\n width,\n height,\n maxWidth,\n dir,\n writingMode,\n submitOnEnter,\n selfManaged = false,\n debounceMs = 0,\n className,\n style,\n autoFocus,\n cardName,\n onChanged,\n onSubmitted,\n } = props;\n\n // Focus the textarea once, the first time it is mounted/shown (e.g. when a\n // dialog or drawer opens). Intentionally an empty dependency array — this\n // must not re-fire on subsequent re-renders.\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n useEffect(() => {\n if (autoFocus) textareaRef.current?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // `id` may be injected by a parent pi/field card via Pihanga's extra-prop\n // forwarding. Not part of the official type so read through an escape hatch.\n const injectedId = (props as {id?: string}).id;\n const invalid = Boolean((props as {invalid?: boolean}).invalid);\n\n // Detect if we are inside a pi/form card via React context. When inside a\n // form, the form itself is the source of truth and buffering mechanism\n // (see pi/input, pi/text-field, etc.) — every keystroke writes straight to\n // form.formData via handleChange, and `selfManaged`/`debounceMs` are\n // ignored: there's no separate \"commit\" step to defer since the form's own\n // submit action is that commit point.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n const canonicalValue = useFormData\n ? ((form.formData[name!] as string | undefined) ?? \"\")\n : propValue;\n\n // Self-managed buffering only applies in standalone mode.\n const applySelfManaged = selfManaged && !useFormData;\n\n // ---------------------------------------------------------------------\n // Self-managed mode (standalone only): keep an internal, always-up-to-date\n // text buffer so typing never lags, but only dispatch the outgoing\n // onChanged event on blur (and, optionally, after a trailing debounce\n // window) — not on every keystroke.\n // ---------------------------------------------------------------------\n const [localValue, setLocalValue] = useState(canonicalValue);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingValue = useRef<string>(canonicalValue);\n\n // Keep the local buffer in sync if the canonical value changes from\n // outside (e.g. a reset) while not actively editing.\n useEffect(() => {\n if (applySelfManaged) setLocalValue(canonicalValue);\n }, [canonicalValue, applySelfManaged]);\n\n useEffect(() => {\n return () => {\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n };\n }, []);\n\n const value = applySelfManaged ? localValue : canonicalValue;\n\n function commitChange(newValue: string) {\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n onChanged({name, value: newValue});\n }\n }\n\n function handleChange(e: React.ChangeEvent<HTMLTextAreaElement>) {\n const newValue = e.target.value;\n\n if (!applySelfManaged) {\n // Inside a form, or selfManaged not requested: commit on every\n // keystroke, matching pi/input's default (non-onCommitted) behaviour.\n commitChange(newValue);\n return;\n }\n\n // Self-managed (standalone): update the visible text immediately, defer\n // the outgoing event.\n setLocalValue(newValue);\n pendingValue.current = newValue;\n\n if (debounceMs > 0) {\n if (debounceTimer.current != null) clearTimeout(debounceTimer.current);\n debounceTimer.current = setTimeout(() => {\n debounceTimer.current = null;\n commitChange(pendingValue.current);\n }, debounceMs);\n }\n }\n\n function handleBlur() {\n if (!applySelfManaged) return;\n if (debounceTimer.current != null) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n }\n commitChange(pendingValue.current);\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {\n if (\n submitOnEnter &&\n e.key === \"Enter\" &&\n !e.shiftKey &&\n !e.ctrlKey &&\n !e.metaKey &&\n !e.altKey\n ) {\n e.preventDefault();\n const currentValue = e.currentTarget.value;\n if (applySelfManaged && debounceTimer.current != null) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n commitChange(currentValue);\n }\n onSubmitted({name, value: currentValue});\n }\n }\n\n // Default resize behaviour: content-sizing boxes shouldn't be manually\n // resizable (dragging writes an inline width/height that permanently\n // defeats field-sizing: content).\n const resolvedResize =\n resize ?? (fieldSizing === \"content\" ? \"none\" : \"vertical\");\n\n const resizeClass =\n resolvedResize === \"none\"\n ? \"resize-none\"\n : resolvedResize === \"vertical\"\n ? \"resize-y\"\n : resolvedResize === \"horizontal\"\n ? \"resize-x\"\n : \"resize\";\n\n // `field-sizing` is expressed as a Tailwind utility class (shipped by\n // Tailwind v4) rather than an inline style — this is both more idiomatic\n // for this codebase (the base Textarea already defaults to\n // `field-sizing-content`) and avoids relying on very new CSS properties\n // being present in every CSSStyleDeclaration IDL implementation.\n const fieldSizingClass =\n fieldSizing === \"content\" ? \"field-sizing-content\" : \"field-sizing-fixed\";\n\n const inlineStyle: React.CSSProperties = {\n minHeight: toCssLength(minHeight),\n maxHeight: toCssLength(maxHeight),\n width: toCssLength(width),\n height: toCssLength(height),\n maxWidth: toCssLength(maxWidth),\n writingMode,\n ...style,\n };\n\n // Use the id injected by pi/field (for label↔control linking); fall back\n // to a locally-generated id when used standalone.\n const selfId = `${cardName}-${name ?? \"field\"}`;\n const fieldId = injectedId ?? selfId;\n\n return (\n <Textarea\n ref={textareaRef}\n id={fieldId}\n value={value}\n onChange={handleChange}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n rows={fieldSizing === \"fixed\" ? rows : undefined}\n cols={fieldSizing === \"fixed\" ? cols : undefined}\n dir={dir}\n aria-invalid={invalid || undefined}\n data-pihanga={cardName}\n className={cn(fieldSizingClass, resizeClass, className)}\n style={inlineStyle}\n />\n );\n};\n"],"mappings":";;;;;;;AAWA,SAAS,EAAY,GAA8C;CAC7D,UAAM,KAAA,GACV,OAAO,OAAO,KAAM,WAAW,GAAG,EAAE,MAAM;AAC5C;AAEA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,IAAY,IACnB,gBACA,aACA,aACA,UAAO,GACP,SACA,iBAAc,SACd,WACA,cACA,cACA,UACA,WACA,aACA,QACA,gBACA,kBACA,iBAAc,IACd,gBAAa,GACb,cACA,UACA,cACA,aACA,cACA,mBACE,GAKE,IAAc,EAA4B,IAAI;CACpD,QAAgB;EACd,AAAI,KAAW,EAAY,SAAS,MAAM;CAE5C,GAAG,CAAC,CAAC;CAIL,IAAM,IAAc,EAAwB,IACtC,IAAU,EAAS,EAA8B,SAQjD,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAEvC,IAAiB,IACjB,EAAK,SAAS,MAAiC,KACjD,GAGE,IAAmB,KAAe,CAAC,GAQnC,CAAC,GAAY,KAAiB,GAAS,CAAc,GACrD,IAAgB,EAA6C,IAAI,GACjE,IAAe,EAAe,CAAc;CAQlD,AAJA,QAAgB;EACd,AAAI,KAAkB,EAAc,CAAc;CACpD,GAAG,CAAC,GAAgB,CAAgB,CAAC,GAErC,cACe;EACX,AAAI,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO;CACvE,GACC,CAAC,CAAC;CAEL,IAAM,IAAQ,IAAmB,IAAa;CAE9C,SAAS,EAAa,GAAkB;EACtC,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,IAEjC,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAEA,SAAS,EAAa,GAA2C;EAC/D,IAAM,IAAW,EAAE,OAAO;EAE1B,IAAI,CAAC,GAAkB;GAGrB,EAAa,CAAQ;GACrB;EACF;EAOA,AAHA,EAAc,CAAQ,GACtB,EAAa,UAAU,GAEnB,IAAa,MACX,EAAc,WAAW,QAAM,aAAa,EAAc,OAAO,GACrE,EAAc,UAAU,iBAAiB;GAEvC,AADA,EAAc,UAAU,MACxB,EAAa,EAAa,OAAO;EACnC,GAAG,CAAU;CAEjB;CAEA,SAAS,IAAa;EACf,MACD,EAAc,WAAW,SAC3B,aAAa,EAAc,OAAO,GAClC,EAAc,UAAU,OAE1B,EAAa,EAAa,OAAO;CACnC;CAEA,SAAS,EAAc,GAA6C;EAClE,IACE,KACA,EAAE,QAAQ,WACV,CAAC,EAAE,YACH,CAAC,EAAE,WACH,CAAC,EAAE,WACH,CAAC,EAAE,QACH;GACA,EAAE,eAAe;GACjB,IAAM,IAAe,EAAE,cAAc;GAMrC,AALI,KAAoB,EAAc,WAAW,SAC/C,aAAa,EAAc,OAAO,GAClC,EAAc,UAAU,MACxB,EAAa,CAAY,IAE3B,EAAY;IAAC;IAAM,OAAO;GAAY,CAAC;EACzC;CACF;CAKA,IAAM,IACJ,MAAW,MAAgB,YAAY,SAAS,aAE5C,IACJ,MAAmB,SACf,gBACA,MAAmB,aACjB,aACA,MAAmB,eACjB,aACA,UAOJ,IACJ,MAAgB,YAAY,yBAAyB,sBAEjD,IAAmC;EACvC,WAAW,EAAY,CAAS;EAChC,WAAW,EAAY,CAAS;EAChC,OAAO,EAAY,CAAK;EACxB,QAAQ,EAAY,CAAM;EAC1B,UAAU,EAAY,CAAQ;EAC9B;EACA,GAAG;CACL,GAIM,IAAS,GAAG,EAAS,GAAG,KAAQ;CAGtC,OACE,kBAAC,GAAD;EACE,KAAK;EACL,IALY,KAAc;EAMnB;EACP,UAAU;EACV,QAAQ;EACR,WAAW;EACE;EACH;EACA;EACV,MAAM,MAAgB,UAAU,IAAO,KAAA;EACvC,MAAM,MAAgB,UAAU,IAAO,KAAA;EAClC;EACL,gBAAc,KAAW,KAAA;EACzB,gBAAc;EACd,WAAW,EAAG,GAAkB,GAAa,CAAS;EACtD,OAAO;CACR,CAAA;AAEL"}
@@ -0,0 +1,147 @@
1
+ import { CSSProperties } from 'react';
2
+ export declare const PI_TEXT_AREA_CARD = "pi/text-area";
3
+ export declare const TextArea: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<PiTextAreaProps, S, PiTextAreaEvents>) => import('@pihanga2/core').PiCardDef;
4
+ export declare const PI_TEXT_AREA_ACTION: {
5
+ CHANGED: string;
6
+ SUBMITTED: string;
7
+ };
8
+ export declare const onTextAreaChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
9
+ cardID: string;
10
+ } & PiTextAreaChangedEvent>) => void;
11
+ export declare const onTextAreaSubmitted: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
12
+ cardID: string;
13
+ } & PiTextAreaSubmittedEvent>) => void;
14
+ /** A CSS length. Numbers are treated as pixels, strings are used verbatim. */
15
+ export type CssLength = number | string;
16
+ /**
17
+ * How the textarea sizes itself:
18
+ * - "fixed" (default) — plain `<textarea>` behaviour. Size is governed by
19
+ * `rows`/`cols` (and any explicit `width`/`height`); the user
20
+ * may resize it per the `resize` prop. Never grows with content.
21
+ * - "content" — uses the CSS `field-sizing: content` behaviour: the box
22
+ * grows/shrinks to fit its content, clamped by any
23
+ * `minHeight`/`maxHeight`/`width`/`height`/`maxWidth` you set.
24
+ * `rows`/`cols` are ignored by the browser once this is active.
25
+ */
26
+ export type PiTextAreaFieldSizing = "fixed" | "content";
27
+ export type PiTextAreaResize = "none" | "vertical" | "horizontal" | "both";
28
+ export type PiTextAreaProps = {
29
+ /**
30
+ * Field name used to bind to FormContext when inside a pi/form card.
31
+ * When provided the component reads its value from form state and writes
32
+ * back via form.handleChange.
33
+ */
34
+ name?: string;
35
+ /**
36
+ * Controlled value used in standalone mode (outside a Form).
37
+ * Ignored when `name` is set and the component is inside a pi/form.
38
+ */
39
+ value?: string;
40
+ /** Placeholder text shown when the box is empty. May contain `\n`. */
41
+ placeholder?: string;
42
+ /** When true, the textarea is disabled and non-interactive. */
43
+ disabled?: boolean;
44
+ /** When true, the textarea's value cannot be edited by the user. */
45
+ readOnly?: boolean;
46
+ /**
47
+ * Number of visible text lines. Only meaningful when `fieldSizing` is
48
+ * `"fixed"` — browsers ignore `rows`/`cols` once `field-sizing: content`
49
+ * is active. Default: `4`.
50
+ */
51
+ rows?: number;
52
+ /** Number of visible character columns. See `rows` for caveats. */
53
+ cols?: number;
54
+ /** See `PiTextAreaFieldSizing`. Default: `"fixed"`. */
55
+ fieldSizing?: PiTextAreaFieldSizing;
56
+ /**
57
+ * CSS `resize` behaviour — whether/how the user can drag-resize the box.
58
+ * Default: `"vertical"` when `fieldSizing` is `"fixed"`, `"none"` when
59
+ * `fieldSizing` is `"content"` (dragging would otherwise permanently
60
+ * defeat the content-based sizing by writing an inline width/height).
61
+ */
62
+ resize?: PiTextAreaResize;
63
+ /** Minimum height. Accepts CSS units like `"2lh"`, `"4rem"`, or a number of px. */
64
+ minHeight?: CssLength;
65
+ /** Maximum height. Once reached, content scrolls instead of growing further. */
66
+ maxHeight?: CssLength;
67
+ /** Explicit width. Freezes the inline axis even when `fieldSizing="content"`. */
68
+ width?: CssLength;
69
+ /** Explicit height. Freezes the block axis even when `fieldSizing="content"`. */
70
+ height?: CssLength;
71
+ /**
72
+ * Maximum width — a guard against an unconstrained `fieldSizing="content"`
73
+ * box escaping its parent container.
74
+ */
75
+ maxWidth?: CssLength;
76
+ /** Text direction. Default: inherited from the document. */
77
+ dir?: "ltr" | "rtl";
78
+ /**
79
+ * CSS `writing-mode`. With `"vertical-rl"` the sizing axes swap: content
80
+ * growth under `fieldSizing="content"` runs horizontally, not vertically.
81
+ */
82
+ writingMode?: "horizontal-tb" | "vertical-rl" | "vertical-lr";
83
+ /**
84
+ * When true, pressing Enter (without Shift/Ctrl/Meta/Alt) fires
85
+ * `onSubmitted` with the current text instead of inserting a newline.
86
+ * Shift+Enter (etc.) still inserts a newline. Default: `false`.
87
+ */
88
+ submitOnEnter?: boolean;
89
+ /**
90
+ * **Standalone mode only** (ignored when used inside a `pi/form` card —
91
+ * see below). When true, the textarea keeps its own internal text state
92
+ * so the visible text always updates immediately as the user types, but
93
+ * the outgoing `onChanged` event is only dispatched at a "commit" point
94
+ * instead of on every keystroke:
95
+ *
96
+ * - always on blur,
97
+ * - and, if `debounceMs > 0`, also after that many ms of typing
98
+ * inactivity (a trailing debounce), so the value is committed even if
99
+ * the user never blurs the field (e.g. drives an autosave / API call).
100
+ *
101
+ * Use this to avoid flooding the host app / reducer with an event per
102
+ * keystroke for a card whose `onChanged` handler is expensive.
103
+ *
104
+ * When the card is used inside a `pi/form` (i.e. `name` is set and a
105
+ * `pi/form` ancestor is present), this prop has no effect: form fields
106
+ * always write back to form state on every keystroke via
107
+ * `form.handleChange`, exactly like `pi/input` and `pi/text-field` — the
108
+ * form's own submit action is the natural "commit" point in that case.
109
+ *
110
+ * Default: `false` (dispatches `onChanged` on every keystroke, as
111
+ * before).
112
+ */
113
+ selfManaged?: boolean;
114
+ /**
115
+ * Trailing-debounce window (ms) for committing changes while
116
+ * `selfManaged` is true (standalone mode only). `0` (default) means no
117
+ * debounce — the value is only committed on blur. Ignored when
118
+ * `selfManaged` is `false`, or when the card is inside a `pi/form`.
119
+ */
120
+ debounceMs?: number;
121
+ /** Additional class names merged onto the root `<textarea>`. */
122
+ className?: string;
123
+ /** Additional inline styles merged onto the root `<textarea>` (highest precedence). */
124
+ style?: CSSProperties;
125
+ /**
126
+ * When true, the textarea grabs keyboard focus the first time it is
127
+ * mounted/shown (e.g. when a dialog or drawer opens). Only applies once,
128
+ * on mount — it does not re-focus on subsequent re-renders.
129
+ */
130
+ autoFocus?: boolean;
131
+ };
132
+ export type PiTextAreaChangedEvent = {
133
+ /** Field name, mirrors the `name` prop if provided. */
134
+ name?: string;
135
+ /** New value after the change. */
136
+ value: string;
137
+ };
138
+ export type PiTextAreaSubmittedEvent = {
139
+ /** Field name, mirrors the `name` prop if provided. */
140
+ name?: string;
141
+ /** The current text at the time Enter was pressed. */
142
+ value: string;
143
+ };
144
+ export type PiTextAreaEvents = {
145
+ onChanged: PiTextAreaChangedEvent;
146
+ onSubmitted: PiTextAreaSubmittedEvent;
147
+ };
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/textArea/textArea.types.ts
3
+ var r = "pi/text-area", i = e(r), a = n(r, ["changed", "submitted"]), o = t(a.CHANGED), s = t(a.SUBMITTED);
4
+ //#endregion
5
+ export { a as PI_TEXT_AREA_ACTION, r as PI_TEXT_AREA_CARD, i as TextArea, o as onTextAreaChanged, s as onTextAreaSubmitted };
6
+
7
+ //# sourceMappingURL=textArea.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textArea.types.js","names":[],"sources":["../../../src/cards/textArea/textArea.types.ts"],"sourcesContent":["import type {CSSProperties} from \"react\";\nimport {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_TEXT_AREA_CARD = \"pi/text-area\";\n\nexport const TextArea = createCardDeclaration<\n PiTextAreaProps,\n PiTextAreaEvents\n>(PI_TEXT_AREA_CARD);\n\nexport const PI_TEXT_AREA_ACTION = registerActions(PI_TEXT_AREA_CARD, [\n \"changed\",\n \"submitted\",\n]);\n\nexport const onTextAreaChanged = createOnAction<PiTextAreaChangedEvent>(\n PI_TEXT_AREA_ACTION.CHANGED,\n);\n\nexport const onTextAreaSubmitted = createOnAction<PiTextAreaSubmittedEvent>(\n PI_TEXT_AREA_ACTION.SUBMITTED,\n);\n\n/** A CSS length. Numbers are treated as pixels, strings are used verbatim. */\nexport type CssLength = number | string;\n\n/**\n * How the textarea sizes itself:\n * - \"fixed\" (default) — plain `<textarea>` behaviour. Size is governed by\n * `rows`/`cols` (and any explicit `width`/`height`); the user\n * may resize it per the `resize` prop. Never grows with content.\n * - \"content\" — uses the CSS `field-sizing: content` behaviour: the box\n * grows/shrinks to fit its content, clamped by any\n * `minHeight`/`maxHeight`/`width`/`height`/`maxWidth` you set.\n * `rows`/`cols` are ignored by the browser once this is active.\n */\nexport type PiTextAreaFieldSizing = \"fixed\" | \"content\";\n\nexport type PiTextAreaResize = \"none\" | \"vertical\" | \"horizontal\" | \"both\";\n\nexport type PiTextAreaProps = {\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 state and writes\n * back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled value used in standalone mode (outside a Form).\n * Ignored when `name` is set and the component is inside a pi/form.\n */\n value?: string;\n\n /** Placeholder text shown when the box is empty. May contain `\\n`. */\n placeholder?: string;\n\n /** When true, the textarea is disabled and non-interactive. */\n disabled?: boolean;\n\n /** When true, the textarea's value cannot be edited by the user. */\n readOnly?: boolean;\n\n /**\n * Number of visible text lines. Only meaningful when `fieldSizing` is\n * `\"fixed\"` — browsers ignore `rows`/`cols` once `field-sizing: content`\n * is active. Default: `4`.\n */\n rows?: number;\n\n /** Number of visible character columns. See `rows` for caveats. */\n cols?: number;\n\n /** See `PiTextAreaFieldSizing`. Default: `\"fixed\"`. */\n fieldSizing?: PiTextAreaFieldSizing;\n\n /**\n * CSS `resize` behaviour — whether/how the user can drag-resize the box.\n * Default: `\"vertical\"` when `fieldSizing` is `\"fixed\"`, `\"none\"` when\n * `fieldSizing` is `\"content\"` (dragging would otherwise permanently\n * defeat the content-based sizing by writing an inline width/height).\n */\n resize?: PiTextAreaResize;\n\n /** Minimum height. Accepts CSS units like `\"2lh\"`, `\"4rem\"`, or a number of px. */\n minHeight?: CssLength;\n\n /** Maximum height. Once reached, content scrolls instead of growing further. */\n maxHeight?: CssLength;\n\n /** Explicit width. Freezes the inline axis even when `fieldSizing=\"content\"`. */\n width?: CssLength;\n\n /** Explicit height. Freezes the block axis even when `fieldSizing=\"content\"`. */\n height?: CssLength;\n\n /**\n * Maximum width — a guard against an unconstrained `fieldSizing=\"content\"`\n * box escaping its parent container.\n */\n maxWidth?: CssLength;\n\n /** Text direction. Default: inherited from the document. */\n dir?: \"ltr\" | \"rtl\";\n\n /**\n * CSS `writing-mode`. With `\"vertical-rl\"` the sizing axes swap: content\n * growth under `fieldSizing=\"content\"` runs horizontally, not vertically.\n */\n writingMode?: \"horizontal-tb\" | \"vertical-rl\" | \"vertical-lr\";\n\n /**\n * When true, pressing Enter (without Shift/Ctrl/Meta/Alt) fires\n * `onSubmitted` with the current text instead of inserting a newline.\n * Shift+Enter (etc.) still inserts a newline. Default: `false`.\n */\n submitOnEnter?: boolean;\n\n /**\n * **Standalone mode only** (ignored when used inside a `pi/form` card —\n * see below). When true, the textarea keeps its own internal text state\n * so the visible text always updates immediately as the user types, but\n * the outgoing `onChanged` event is only dispatched at a \"commit\" point\n * instead of on every keystroke:\n *\n * - always on blur,\n * - and, if `debounceMs > 0`, also after that many ms of typing\n * inactivity (a trailing debounce), so the value is committed even if\n * the user never blurs the field (e.g. drives an autosave / API call).\n *\n * Use this to avoid flooding the host app / reducer with an event per\n * keystroke for a card whose `onChanged` handler is expensive.\n *\n * When the card is used inside a `pi/form` (i.e. `name` is set and a\n * `pi/form` ancestor is present), this prop has no effect: form fields\n * always write back to form state on every keystroke via\n * `form.handleChange`, exactly like `pi/input` and `pi/text-field` — the\n * form's own submit action is the natural \"commit\" point in that case.\n *\n * Default: `false` (dispatches `onChanged` on every keystroke, as\n * before).\n */\n selfManaged?: boolean;\n\n /**\n * Trailing-debounce window (ms) for committing changes while\n * `selfManaged` is true (standalone mode only). `0` (default) means no\n * debounce — the value is only committed on blur. Ignored when\n * `selfManaged` is `false`, or when the card is inside a `pi/form`.\n */\n debounceMs?: number;\n\n /** Additional class names merged onto the root `<textarea>`. */\n className?: string;\n\n /** Additional inline styles merged onto the root `<textarea>` (highest precedence). */\n style?: CSSProperties;\n\n /**\n * When true, the textarea grabs keyboard focus the first time it is\n * mounted/shown (e.g. when a dialog or drawer opens). Only applies once,\n * on mount — it does not re-focus on subsequent re-renders.\n */\n autoFocus?: boolean;\n};\n\nexport type PiTextAreaChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New value after the change. */\n value: string;\n};\n\nexport type PiTextAreaSubmittedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** The current text at the time Enter was pressed. */\n value: string;\n};\n\nexport type PiTextAreaEvents = {\n onChanged: PiTextAreaChangedEvent;\n onSubmitted: PiTextAreaSubmittedEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAoB,gBAEpB,IAAW,EAGtB,CAAiB,GAEN,IAAsB,EAAgB,GAAmB,CACpE,WACA,WACF,CAAC,GAEY,IAAoB,EAC/B,EAAoB,OACtB,GAEa,IAAsB,EACjC,EAAoB,SACtB"}
@@ -3,11 +3,11 @@ export declare const TextField: <S extends import('@pihanga2/core').ReduxState>(
3
3
  export declare const PI_TEXT_FIELD_ACTION: {
4
4
  CHANGED: string;
5
5
  };
6
- export declare const onTextFieldChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
6
+ export declare const onTextFieldChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
7
7
  cardID: string;
8
8
  } & PiTextFieldChangedEvent>) => void;
9
9
  /** @deprecated Use `onTextFieldChanged` instead. */
10
- export declare const onPiTextFieldChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
10
+ export declare const onPiTextFieldChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
11
  cardID: string;
12
12
  } & PiTextFieldChangedEvent>) => void;
13
13
  export type PiTextFieldProps = {
@@ -38,17 +38,17 @@ export declare const dispatchShowToast: (d: DispatchF, ev: ShowToastEvent) => vo
38
38
  * });
39
39
  * ```
40
40
  */
41
- export declare const onShowToast: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
41
+ export declare const onShowToast: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
42
42
  cardID: string;
43
43
  } & ShowToastEvent>) => void;
44
44
  export declare const PI_TOAST_ACTION: {
45
45
  CLOSED: string;
46
46
  };
47
- export declare const onToastClosed: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
47
+ export declare const onToastClosed: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
48
48
  cardID: string;
49
49
  } & PiToastClosedEvent>) => void;
50
50
  /** @deprecated Use `onToastClosed` instead. */
51
- export declare const onPiToastClosed: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
51
+ export declare const onPiToastClosed: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
52
52
  cardID: string;
53
53
  } & PiToastClosedEvent>) => void;
54
54
  /**
@@ -3,11 +3,11 @@ export declare const ToggleGroup: <S extends import('@pihanga2/core').ReduxState
3
3
  export declare const PI_TOGGLE_GROUP_ACTION: {
4
4
  CHANGED: string;
5
5
  };
6
- export declare const onToggleGroupChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
6
+ export declare const onToggleGroupChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
7
7
  cardID: string;
8
8
  } & PiToggleGroupChangedEvent>) => void;
9
9
  /** @deprecated Use `onToggleGroupChanged` instead. */
10
- export declare const onPiToggleGroupChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
10
+ export declare const onPiToggleGroupChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
11
  cardID: string;
12
12
  } & PiToggleGroupChangedEvent>) => void;
13
13
  export type PiToggleGroupItem = {
@@ -0,0 +1,40 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { jsx as t } from "react/jsx-runtime";
3
+ import { cva as n } from "class-variance-authority";
4
+ //#region src/components/ui/empty.tsx
5
+ function r({ className: n, ...r }) {
6
+ return /* @__PURE__ */ t("div", {
7
+ "data-slot": "empty",
8
+ className: e("flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12", n),
9
+ ...r
10
+ });
11
+ }
12
+ var i = n("mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", {
13
+ variants: { variant: {
14
+ default: "bg-transparent",
15
+ icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6"
16
+ } },
17
+ defaultVariants: { variant: "default" }
18
+ });
19
+ function a({ className: n, variant: r = "default", ...a }) {
20
+ return /* @__PURE__ */ t("div", {
21
+ "data-slot": "empty-icon",
22
+ "data-variant": r,
23
+ className: e(i({
24
+ variant: r,
25
+ className: n
26
+ })),
27
+ ...a
28
+ });
29
+ }
30
+ function o({ className: n, ...r }) {
31
+ return /* @__PURE__ */ t("div", {
32
+ "data-slot": "empty-content",
33
+ className: e("flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm", n),
34
+ ...r
35
+ });
36
+ }
37
+ //#endregion
38
+ export { r as Empty, o as EmptyContent, a as EmptyMedia };
39
+
40
+ //# sourceMappingURL=empty.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty.js","names":[],"sources":["../../../src/components/ui/empty.tsx"],"sourcesContent":["import {cva, type VariantProps} from \"class-variance-authority\";\n\nimport {cn} from \"@/lib/utils\";\n\nfunction Empty({className, ...props}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty\"\n className={cn(\n \"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction EmptyHeader({className, ...props}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-header\"\n className={cn(\n \"flex max-w-sm flex-col items-center gap-2 text-center\",\n className,\n )}\n {...props}\n />\n );\n}\n\nconst emptyMediaVariants = cva(\n \"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n icon: \"bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nfunction EmptyMedia({\n className,\n variant = \"default\",\n ...props\n}: React.ComponentProps<\"div\"> & VariantProps<typeof emptyMediaVariants>) {\n return (\n <div\n data-slot=\"empty-icon\"\n data-variant={variant}\n className={cn(emptyMediaVariants({variant, className}))}\n {...props}\n />\n );\n}\n\nfunction EmptyTitle({className, ...props}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-title\"\n className={cn(\"text-lg font-medium tracking-tight\", className)}\n {...props}\n />\n );\n}\n\nfunction EmptyDescription({className, ...props}: React.ComponentProps<\"p\">) {\n return (\n <div\n data-slot=\"empty-description\"\n className={cn(\n \"text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction EmptyContent({className, ...props}: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"empty-content\"\n className={cn(\n \"flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport {\n Empty,\n EmptyHeader,\n EmptyTitle,\n EmptyDescription,\n EmptyContent,\n EmptyMedia,\n};\n"],"mappings":";;;;AAIA,SAAS,EAAM,EAAC,cAAW,GAAG,KAAqC;CACjE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,gIACA,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAeA,IAAM,IAAqB,EACzB,+FACA;CACE,UAAU,EACR,SAAS;EACP,SAAS;EACT,MAAM;CACR,EACF;CACA,iBAAiB,EACf,SAAS,UACX;AACF,CACF;AAEA,SAAS,EAAW,EAClB,cACA,aAAU,WACV,GAAG,KACqE;CACxE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,gBAAc;EACd,WAAW,EAAG,EAAmB;GAAC;GAAS;EAAS,CAAC,CAAC;EACtD,GAAI;CACL,CAAA;AAEL;AAyBA,SAAS,EAAa,EAAC,cAAW,GAAG,KAAqC;CACxE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,iFACA,CACF;EACA,GAAI;CACL,CAAA;AAEL"}