@pihanga2/shadcn 0.2.0 → 0.2.2

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 (130) hide show
  1. package/AGENT.building-cards.md +208 -3
  2. package/AGENT.md +66 -4
  3. package/AGENT.using-cards.md +197 -250
  4. package/README.md +4 -1
  5. package/cards/badge/badge.component.js +1 -0
  6. package/cards/badge/badge.component.js.map +1 -1
  7. package/cards/box/box.component.js +2 -2
  8. package/cards/box/box.component.js.map +1 -1
  9. package/cards/box/box.types.d.ts +0 -8
  10. package/cards/box/box.types.js.map +1 -1
  11. package/cards/button/button.types.d.ts +4 -0
  12. package/cards/button/button.types.js +2 -2
  13. package/cards/button/button.types.js.map +1 -1
  14. package/cards/button/index.js +5 -5
  15. package/cards/chart/chart.component.d.ts +4 -0
  16. package/cards/chart/chart.types.d.ts +223 -0
  17. package/cards/chart/index.d.ts +1 -0
  18. package/cards/checkbox/checkbox.component.js +1 -0
  19. package/cards/checkbox/checkbox.component.js.map +1 -1
  20. package/cards/checkbox/checkbox.types.d.ts +4 -0
  21. package/cards/checkbox/checkbox.types.js +2 -2
  22. package/cards/checkbox/checkbox.types.js.map +1 -1
  23. package/cards/checkbox/index.js +5 -5
  24. package/cards/conditional/conditional.component.d.ts +14 -3
  25. package/cards/conditional/conditional.component.js +17 -9
  26. package/cards/conditional/conditional.component.js.map +1 -1
  27. package/cards/conditional/conditional.types.d.ts +115 -8
  28. package/cards/conditional/conditional.types.js.map +1 -1
  29. package/cards/core-index.d.ts +3 -0
  30. package/cards/core-index.js +38 -31
  31. package/cards/dataTable/dataTable.types.js.map +1 -1
  32. package/cards/dataTable/dataTableRowDetail.component.js +1 -0
  33. package/cards/dataTable/dataTableRowDetail.component.js.map +1 -1
  34. package/cards/field/field.types.js.map +1 -1
  35. package/cards/fileDrop/fileDrop.component.js +90 -0
  36. package/cards/fileDrop/fileDrop.component.js.map +1 -0
  37. package/cards/fileDrop/fileDrop.types.js +11 -0
  38. package/cards/fileDrop/fileDrop.types.js.map +1 -0
  39. package/cards/fileDrop/index.js +13 -0
  40. package/cards/fileDrop/index.js.map +1 -0
  41. package/cards/flexGrid/flexGrid.types.js.map +1 -1
  42. package/cards/form/form.types.d.ts +4 -0
  43. package/cards/form/form.types.js +2 -2
  44. package/cards/form/form.types.js.map +1 -1
  45. package/cards/form/index.js +5 -5
  46. package/cards/graphin/contextMenu.component.d.ts +28 -0
  47. package/cards/graphin/eventDispatcher.component.d.ts +8 -0
  48. package/cards/graphin/graphin.component.d.ts +2 -2
  49. package/cards/graphin/graphin.playground-cards.d.ts +1 -0
  50. package/cards/graphin/graphin.types.d.ts +477 -4
  51. package/cards/graphin/graphinOpHandler.component.d.ts +8 -0
  52. package/cards/graphin/index.d.ts +1 -0
  53. package/cards/graphin/tooltip.component.d.ts +13 -1
  54. package/cards/input/index.js +5 -5
  55. package/cards/input/input.component.js +1 -0
  56. package/cards/input/input.component.js.map +1 -1
  57. package/cards/input/input.types.d.ts +10 -2
  58. package/cards/input/input.types.js +2 -2
  59. package/cards/input/input.types.js.map +1 -1
  60. package/cards/list/list.types.js +1 -0
  61. package/cards/list/list.types.js.map +1 -1
  62. package/cards/pageWithNavbar/pageWithNavbar.component.d.ts +5 -7
  63. package/cards/pageWithNavbar/pageWithNavbar.component.js +1 -1
  64. package/cards/pageWithNavbar/pageWithNavbar.component.js.map +1 -1
  65. package/cards/pasteTarget/pasteTarget.component.js.map +1 -1
  66. package/cards/select/index.js +5 -5
  67. package/cards/select/select.component.js +1 -0
  68. package/cards/select/select.component.js.map +1 -1
  69. package/cards/select/select.types.d.ts +12 -0
  70. package/cards/select/select.types.js +2 -2
  71. package/cards/select/select.types.js.map +1 -1
  72. package/cards/slider/index.d.ts +1 -0
  73. package/cards/slider/index.js +13 -0
  74. package/cards/slider/index.js.map +1 -0
  75. package/cards/slider/slider.component.d.ts +4 -0
  76. package/cards/slider/slider.component.js +64 -0
  77. package/cards/slider/slider.component.js.map +1 -0
  78. package/cards/slider/slider.types.d.ts +110 -0
  79. package/cards/slider/slider.types.js +7 -0
  80. package/cards/slider/slider.types.js.map +1 -0
  81. package/cards/sliderValue/index.d.ts +1 -0
  82. package/cards/sliderValue/index.js +12 -0
  83. package/cards/sliderValue/index.js.map +1 -0
  84. package/cards/sliderValue/sliderValue.component.d.ts +15 -0
  85. package/cards/sliderValue/sliderValue.component.js +33 -0
  86. package/cards/sliderValue/sliderValue.component.js.map +1 -0
  87. package/cards/sliderValue/sliderValue.types.d.ts +21 -0
  88. package/cards/sliderValue/sliderValue.types.js +7 -0
  89. package/cards/sliderValue/sliderValue.types.js.map +1 -0
  90. package/cards/stack/stack.component.js +1 -1
  91. package/cards/stack/stack.component.js.map +1 -1
  92. package/cards/stack/stack.types.js.map +1 -1
  93. package/cards/switch/index.js +5 -5
  94. package/cards/switch/switch.component.js +1 -0
  95. package/cards/switch/switch.component.js.map +1 -1
  96. package/cards/switch/switch.types.d.ts +4 -0
  97. package/cards/switch/switch.types.js +2 -2
  98. package/cards/switch/switch.types.js.map +1 -1
  99. package/cards/tabs/tabs.component.js +51 -25
  100. package/cards/tabs/tabs.component.js.map +1 -1
  101. package/cards/tabs/tabs.types.d.ts +10 -0
  102. package/cards/tabs/tabs.types.js.map +1 -1
  103. package/cards/textField/index.js +5 -5
  104. package/cards/textField/textField.component.js +1 -0
  105. package/cards/textField/textField.component.js.map +1 -1
  106. package/cards/textField/textField.types.d.ts +4 -0
  107. package/cards/textField/textField.types.js +2 -2
  108. package/cards/textField/textField.types.js.map +1 -1
  109. package/cards/toast/index.js +7 -7
  110. package/cards/toast/toast.component.js.map +1 -1
  111. package/cards/toast/toast.types.d.ts +4 -0
  112. package/cards/toast/toast.types.js +2 -2
  113. package/cards/toast/toast.types.js.map +1 -1
  114. package/cards/toggleGroup/index.js +5 -5
  115. package/cards/toggleGroup/toggleGroup.component.js +1 -0
  116. package/cards/toggleGroup/toggleGroup.component.js.map +1 -1
  117. package/cards/toggleGroup/toggleGroup.types.d.ts +4 -0
  118. package/cards/toggleGroup/toggleGroup.types.js +2 -2
  119. package/cards/toggleGroup/toggleGroup.types.js.map +1 -1
  120. package/cards/typography/typography.types.js +1 -0
  121. package/cards/typography/typography.types.js.map +1 -1
  122. package/components/hooks/use-breakpoint.d.ts +49 -0
  123. package/components/hooks/use-breakpoint.js +73 -0
  124. package/components/hooks/use-breakpoint.js.map +1 -0
  125. package/components/ui/slider.js +36 -0
  126. package/components/ui/slider.js.map +1 -0
  127. package/components/ui/toggle-group.js +1 -0
  128. package/components/ui/toggle-group.js.map +1 -1
  129. package/package.json +19 -2
  130. package/pihanga-shadcn.css +1 -1
@@ -0,0 +1,21 @@
1
+ export declare const PI_SLIDER_VALUE_CARD = "shad/slider-value";
2
+ export declare const SliderValue: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<PiSliderValueProps, S, {}>) => import('@pihanga2/core').PiCardDef;
3
+ export type PiSliderValueProps = {
4
+ /**
5
+ * The numeric value to display on the track.
6
+ * Clamped between `min` and `max`.
7
+ */
8
+ value: number;
9
+ /** Minimum value of the range. Defaults to 0. */
10
+ min?: number;
11
+ /** Maximum value of the range. Defaults to 100. */
12
+ max?: number;
13
+ /**
14
+ * Optional label text rendered above the track.
15
+ * When provided, the numeric value is shown to the right of the label,
16
+ * matching the interactive `shad/slider` layout exactly.
17
+ */
18
+ label?: string;
19
+ /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */
20
+ className?: string;
21
+ };
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e } from "@pihanga2/core";
2
+ //#region src/cards/sliderValue/sliderValue.types.ts
3
+ var t = "shad/slider-value", n = e(t);
4
+ //#endregion
5
+ export { t as PI_SLIDER_VALUE_CARD, n as SliderValue };
6
+
7
+ //# sourceMappingURL=sliderValue.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliderValue.types.js","names":[],"sources":["../../../src/cards/sliderValue/sliderValue.types.ts"],"sourcesContent":["import {createCardDeclaration} from \"@pihanga2/core\";\n\nexport const PI_SLIDER_VALUE_CARD = \"shad/slider-value\";\n\nexport const SliderValue =\n createCardDeclaration<PiSliderValueProps>(PI_SLIDER_VALUE_CARD);\n\n// ---------------------------------------------------------------------------\n// Props (no events — display-only)\n// ---------------------------------------------------------------------------\n\nexport type PiSliderValueProps = {\n /**\n * The numeric value to display on the track.\n * Clamped between `min` and `max`.\n */\n value: number;\n\n /** Minimum value of the range. Defaults to 0. */\n min?: number;\n\n /** Maximum value of the range. Defaults to 100. */\n max?: number;\n\n /**\n * Optional label text rendered above the track.\n * When provided, the numeric value is shown to the right of the label,\n * matching the interactive `shad/slider` layout exactly.\n */\n label?: string;\n\n /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */\n className?: string;\n};\n"],"mappings":";;AAEA,IAAa,IAAuB,qBAEvB,IACX,EAA0C,CAAoB"}
@@ -6,7 +6,7 @@ import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
6
  var a = (a) => {
7
7
  let { content: o, direction: s, divider: c, spacing: l, justifyContent: u, alignItems: d, className: f, style: p, cardName: m } = a, h = [
8
8
  f,
9
- (p?.shad || {}).root,
9
+ (p ?? {}).root,
10
10
  "flex"
11
11
  ];
12
12
  if (s) switch (s) {
@@ -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 } = props;\n const sd: SelectSD = (style as {shad?: SelectSD} | undefined)?.shad || {};\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 return (\n <div className={clsx(cn)} data-pihanga={cardName}>\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,gBACE,GAGE,IAAK;EAAC;GAFU,GAAyC,QAAQ,CAAC,GAE9C;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,OACE,kBAAC,OAAD;EAAK,WAAW,EAAK,CAAE;EAAG,gBAAc;YAAxC,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} 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 } = 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 return (\n <div className={clsx(cn)} data-pihanga={cardName}>\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,gBACE,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,OACE,kBAAC,OAAD;EAAK,WAAW,EAAK,CAAE;EAAG,gBAAc;YAAxC,CACG,EAAc,GACd,EAAM,QACJ;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"stack.types.js","names":[],"sources":["../../../src/cards/stack/stack.types.ts"],"sourcesContent":["import {type PiCardRef, createCardDeclaration} from \"@pihanga2/core\";\nimport {AlignItemsT} from \"../types\";\n\nexport const STACK_CARD = \"pi/stack\";\n\n/**\n * Factory function for declaring a `stack` card instance.\n *\n * ```ts\n * import {registerCard} from \"@pihanga2/core\";\n * import {Stack} from \"@/cards/stack\";\n *\n * registerCard(\"myApp/toolbar\", Stack({\n * direction: \"row\",\n * spacing: 2,\n * alignItems: \"center\",\n * justifyContent: \"space-between\",\n * content: [\"myApp/logo\", \"myApp/navLinks\", \"myApp/userMenu\"],\n * }));\n * ```\n */\nexport const Stack = createCardDeclaration<StackProps>(STACK_CARD);\n\n/**\n * CSS `flex-direction` values supported by the Stack card.\n */\nexport type DirectionT = \"column-reverse\" | \"column\" | \"row-reverse\" | \"row\";\n\n/**\n * CSS `justify-content` values supported by the Stack card.\n */\nexport type JustifyContentT =\n | \"flex-start\"\n | \"center\"\n | \"flex-end\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n\nexport type StackProps<S = object> = {\n /** Ordered list of child card refs to render */\n content: PiCardRef[];\n\n /** Flex direction — defaults to `\"column\"` */\n direction?: DirectionT;\n /** Optional card ref rendered as a separator between children */\n divider?: PiCardRef;\n /** Tailwind gap spacing units between children */\n spacing?: number;\n\n justifyContent?: JustifyContentT;\n alignItems?: AlignItemsT;\n\n /** Additional Tailwind utility classes */\n className?: string;\n /** Card style object (use the `shad` key for Tailwind-compatible overrides) */\n style?: S;\n};\n"],"mappings":";;AAGA,IAAa,IAAa,YAkBb,IAAQ,EAAkC,CAAU"}
1
+ {"version":3,"file":"stack.types.js","names":[],"sources":["../../../src/cards/stack/stack.types.ts"],"sourcesContent":["import {type PiCardRef, createCardDeclaration} from \"@pihanga2/core\";\nimport type {AlignItemsT} from \"../types\";\n\nexport const STACK_CARD = \"pi/stack\";\n\n/**\n * Factory function for declaring a `stack` card instance.\n *\n * ```ts\n * import {registerCard} from \"@pihanga2/core\";\n * import {Stack} from \"@/cards/stack\";\n *\n * registerCard(\"myApp/toolbar\", Stack({\n * direction: \"row\",\n * spacing: 2,\n * alignItems: \"center\",\n * justifyContent: \"space-between\",\n * content: [\"myApp/logo\", \"myApp/navLinks\", \"myApp/userMenu\"],\n * }));\n * ```\n */\nexport const Stack = createCardDeclaration<StackProps>(STACK_CARD);\n\n/**\n * CSS `flex-direction` values supported by the Stack card.\n */\nexport type DirectionT = \"column-reverse\" | \"column\" | \"row-reverse\" | \"row\";\n\n/**\n * CSS `justify-content` values supported by the Stack card.\n */\nexport type JustifyContentT =\n | \"flex-start\"\n | \"center\"\n | \"flex-end\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\n\nexport type StackProps<S = object> = {\n /** Ordered list of child card refs to render */\n content: PiCardRef[];\n\n /** Flex direction — defaults to `\"column\"` */\n direction?: DirectionT;\n /** Optional card ref rendered as a separator between children */\n divider?: PiCardRef;\n /** Tailwind gap spacing units between children */\n spacing?: number;\n\n justifyContent?: JustifyContentT;\n alignItems?: AlignItemsT;\n\n /** Additional Tailwind utility classes */\n className?: string;\n /** Card style object (use the `shad` key for Tailwind-compatible overrides) */\n style?: S;\n};\n"],"mappings":";;AAGA,IAAa,IAAa,YAkBb,IAAQ,EAAkC,CAAU"}
@@ -1,13 +1,13 @@
1
1
  import { SwitchComponent as e } from "./switch.component.js";
2
- import { PI_SWITCH_ACTION as t, PI_SWITCH_CARD as n, Switch as r, onPiSwitchChanged as i } from "./switch.types.js";
3
- import { actionTypesToEvents as a, registerCardComponent as o } from "@pihanga2/core";
2
+ import { PI_SWITCH_ACTION as t, PI_SWITCH_CARD as n, Switch as r, onPiSwitchChanged as i, onSwitchChanged as a } from "./switch.types.js";
3
+ import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
4
4
  //#region src/cards/switch/index.ts
5
- o({
5
+ s({
6
6
  name: n,
7
7
  component: e,
8
- events: a(t)
8
+ events: o(t)
9
9
  });
10
10
  //#endregion
11
- export { t as PI_SWITCH_ACTION, n as PI_SWITCH_CARD, r as Switch, i as onPiSwitchChanged };
11
+ export { t as PI_SWITCH_ACTION, n as PI_SWITCH_CARD, r as Switch, i as onPiSwitchChanged, a as onSwitchChanged };
12
12
 
13
13
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,7 @@
1
1
  import { useFormContext as e } from "../form/form.context.js";
2
2
  import { Label as t } from "../../components/ui/label.js";
3
3
  import { Switch as n } from "../../components/ui/switch.js";
4
+ import "@pihanga2/core";
4
5
  import "react";
5
6
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
7
  //#region src/cards/switch/switch.component.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"switch.component.js","names":[],"sources":["../../../src/cards/switch/switch.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Switch as SwitchUI} from \"@/components/ui/switch\";\nimport {Label} from \"@/components/ui/label\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiSwitchEvents, PiSwitchProps} from \"./switch.types\";\n\nexport const SwitchComponent = (\n props: PiCardProps<PiSwitchProps, PiSwitchEvents>,\n): React.ReactNode => {\n const {\n name,\n checked: propChecked = false,\n disabled,\n label,\n className,\n cardName,\n onChanged,\n } = props;\n\n // `id` and `invalid` may be injected by a parent pi/field card via\n // Pihanga's extra-prop forwarding. They are not in the official type so\n // we read them through an escape hatch.\n const injectedId = (props as {id?: string}).id;\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 const checked = useFormData\n ? Boolean(form.formData[name!] ?? false)\n : propChecked;\n\n function handleCheckedChange(newChecked: boolean) {\n if (useFormData) {\n form.handleChange(name!, newChecked);\n } else {\n onChanged({name, checked: newChecked});\n }\n }\n\n // Use the id injected by pi/field; fall back to a local id when standalone.\n const selfId = `${cardName}-${name ?? \"switch\"}`;\n const fieldId = injectedId ?? selfId;\n\n return (\n <div\n data-pihanga={cardName}\n className={`flex items-center gap-2 ${className ?? \"\"}`}\n >\n <SwitchUI\n id={fieldId}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n disabled={disabled}\n />\n {label && (\n <Label htmlFor={fieldId} className=\"cursor-pointer select-none\">\n {label}\n </Label>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;AAOA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,SAAS,IAAc,IACvB,aACA,UACA,cACA,aACA,iBACE,GAKE,IAAc,EAAwB,IAGtC,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAEvC,IAAU,IACZ,GAAQ,EAAK,SAAS,MAAU,MAChC;CAEJ,SAAS,EAAoB,GAAqB;EAChD,AAAI,IACF,EAAK,aAAa,GAAO,CAAU,IAEnC,EAAU;GAAC;GAAM,SAAS;EAAU,CAAC;CAEzC;CAGA,IAAM,IAAS,GAAG,EAAS,GAAG,KAAQ,YAChC,IAAU,KAAc;CAE9B,OACE,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,2BAA2B,KAAa;YAFrD,CAIE,kBAAC,GAAD;GACE,IAAI;GACK;GACT,iBAAiB;GACP;EACX,CAAA,GACA,KACC,kBAAC,GAAD;GAAO,SAAS;GAAS,WAAU;aAChC;EACI,CAAA,CAEN;;AAET"}
1
+ {"version":3,"file":"switch.component.js","names":[],"sources":["../../../src/cards/switch/switch.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Switch as SwitchUI} from \"@/components/ui/switch\";\nimport {Label} from \"@/components/ui/label\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiSwitchEvents, PiSwitchProps} from \"./switch.types\";\n\nexport const SwitchComponent = (\n props: PiCardProps<PiSwitchProps, PiSwitchEvents>,\n): React.ReactNode => {\n const {\n name,\n checked: propChecked = false,\n disabled,\n label,\n className,\n cardName,\n onChanged,\n } = props;\n\n // `id` and `invalid` may be injected by a parent pi/field card via\n // Pihanga's extra-prop forwarding. They are not in the official type so\n // we read them through an escape hatch.\n const injectedId = (props as {id?: string}).id;\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 const checked = useFormData\n ? Boolean(form.formData[name!] ?? false)\n : propChecked;\n\n function handleCheckedChange(newChecked: boolean) {\n if (useFormData) {\n form.handleChange(name!, newChecked);\n } else {\n onChanged({name, checked: newChecked});\n }\n }\n\n // Use the id injected by pi/field; fall back to a local id when standalone.\n const selfId = `${cardName}-${name ?? \"switch\"}`;\n const fieldId = injectedId ?? selfId;\n\n return (\n <div\n data-pihanga={cardName}\n className={`flex items-center gap-2 ${className ?? \"\"}`}\n >\n <SwitchUI\n id={fieldId}\n checked={checked}\n onCheckedChange={handleCheckedChange}\n disabled={disabled}\n />\n {label && (\n <Label htmlFor={fieldId} className=\"cursor-pointer select-none\">\n {label}\n </Label>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;AAOA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,SAAS,IAAc,IACvB,aACA,UACA,cACA,aACA,iBACE,GAKE,IAAc,EAAwB,IAGtC,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAEvC,IAAU,IACZ,GAAQ,EAAK,SAAS,MAAU,MAChC;CAEJ,SAAS,EAAoB,GAAqB;EAChD,AAAI,IACF,EAAK,aAAa,GAAO,CAAU,IAEnC,EAAU;GAAC;GAAM,SAAS;EAAU,CAAC;CAEzC;CAGA,IAAM,IAAS,GAAG,EAAS,GAAG,KAAQ,YAChC,IAAU,KAAc;CAE9B,OACE,kBAAC,OAAD;EACE,gBAAc;EACd,WAAW,2BAA2B,KAAa;YAFrD,CAIE,kBAAC,GAAD;GACE,IAAI;GACK;GACT,iBAAiB;GACP;EACX,CAAA,GACA,KACC,kBAAC,GAAD;GAAO,SAAS;GAAS,WAAU;aAChC;EACI,CAAA,CAEN;;AAET"}
@@ -3,6 +3,10 @@ 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 & {
7
+ cardID: string;
8
+ } & PiSwitchChangedEvent>) => void;
9
+ /** @deprecated Use `onSwitchChanged` instead. */
6
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 & {
7
11
  cardID: string;
8
12
  } & PiSwitchChangedEvent>) => void;
@@ -1,7 +1,7 @@
1
1
  import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
2
  //#region src/cards/switch/switch.types.ts
3
- var r = "pi/switch", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED);
3
+ var r = "pi/switch", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED), s = o;
4
4
  //#endregion
5
- export { a as PI_SWITCH_ACTION, r as PI_SWITCH_CARD, i as Switch, o as onPiSwitchChanged };
5
+ export { a as PI_SWITCH_ACTION, r as PI_SWITCH_CARD, i as Switch, s as onPiSwitchChanged, o as onSwitchChanged };
6
6
 
7
7
  //# sourceMappingURL=switch.types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"switch.types.js","names":[],"sources":["../../../src/cards/switch/switch.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_SWITCH_CARD = \"pi/switch\";\n\nexport const Switch = createCardDeclaration<PiSwitchProps, PiSwitchEvents>(\n PI_SWITCH_CARD,\n);\n\nexport const PI_SWITCH_ACTION = registerActions(PI_SWITCH_CARD, [\"changed\"]);\n\nexport const onPiSwitchChanged = createOnAction<PiSwitchChangedEvent>(\n PI_SWITCH_ACTION.CHANGED,\n);\n\n// ---------------------------------------------------------------------------\n// Props & Events\n// ---------------------------------------------------------------------------\n\nexport type PiSwitchProps = {\n /**\n * Field name used to bind to FormContext when inside a pi/form card.\n * When provided the component reads its checked state from form data and\n * writes back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled checked state used in standalone mode (outside a Form).\n * Ignored when `name` is set and the component is inside a pi/form.\n */\n checked?: boolean;\n\n /** When true, the switch is disabled and non-interactive. */\n disabled?: boolean;\n\n /**\n * Optional label text rendered beside the switch.\n * The label is automatically associated with the switch via `htmlFor`.\n */\n label?: string;\n\n /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */\n className?: string;\n};\n\nexport type PiSwitchChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New checked state after the toggle. */\n checked: boolean;\n};\n\nexport type PiSwitchEvents = {\n onChanged: PiSwitchChangedEvent;\n};\n"],"mappings":";;AAMA,IAAa,IAAiB,aAEjB,IAAS,EACpB,CACF,GAEa,IAAmB,EAAgB,GAAgB,CAAC,SAAS,CAAC,GAE9D,IAAoB,EAC/B,EAAiB,OACnB"}
1
+ {"version":3,"file":"switch.types.js","names":[],"sources":["../../../src/cards/switch/switch.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_SWITCH_CARD = \"pi/switch\";\n\nexport const Switch = createCardDeclaration<PiSwitchProps, PiSwitchEvents>(\n PI_SWITCH_CARD,\n);\n\nexport const PI_SWITCH_ACTION = registerActions(PI_SWITCH_CARD, [\"changed\"]);\n\nexport const onSwitchChanged = createOnAction<PiSwitchChangedEvent>(\n PI_SWITCH_ACTION.CHANGED,\n);\n\n/** @deprecated Use `onSwitchChanged` instead. */\nexport const onPiSwitchChanged = onSwitchChanged;\n\n// ---------------------------------------------------------------------------\n// Props & Events\n// ---------------------------------------------------------------------------\n\nexport type PiSwitchProps = {\n /**\n * Field name used to bind to FormContext when inside a pi/form card.\n * When provided the component reads its checked state from form data and\n * writes back via form.handleChange.\n */\n name?: string;\n\n /**\n * Controlled checked state used in standalone mode (outside a Form).\n * Ignored when `name` is set and the component is inside a pi/form.\n */\n checked?: boolean;\n\n /** When true, the switch is disabled and non-interactive. */\n disabled?: boolean;\n\n /**\n * Optional label text rendered beside the switch.\n * The label is automatically associated with the switch via `htmlFor`.\n */\n label?: string;\n\n /** Extra Tailwind / CSS classes forwarded to the root wrapper element. */\n className?: string;\n};\n\nexport type PiSwitchChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New checked state after the toggle. */\n checked: boolean;\n};\n\nexport type PiSwitchEvents = {\n onChanged: PiSwitchChangedEvent;\n};\n"],"mappings":";;AAMA,IAAa,IAAiB,aAEjB,IAAS,EACpB,CACF,GAEa,IAAmB,EAAgB,GAAgB,CAAC,SAAS,CAAC,GAE9D,IAAkB,EAC7B,EAAiB,OACnB,GAGa,IAAoB"}
@@ -1,42 +1,68 @@
1
- import { Tabs as e, TabsContent as t, TabsList as n, TabsTrigger as r } from "../../components/ui/tabs.js";
2
- import { Card as i } from "@pihanga2/core";
3
- import { useState as a } from "react";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
1
+ import { Select as e, SelectContent as t, SelectItem as n, SelectTrigger as r, SelectValue as i } from "../../components/ui/select.js";
2
+ import { Tabs as a, TabsContent as o, TabsList as s, TabsTrigger as c } from "../../components/ui/tabs.js";
3
+ import { Card as l } from "@pihanga2/core";
4
+ import { useState as u } from "react";
5
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
5
6
  //#region src/cards/tabs/tabs.component.tsx
6
- var c = (c) => {
7
- let { tabs: l, value: u, defaultValue: d, selfManaged: f = !1, orientation: p = "horizontal", className: m, listClassName: h, contentClassName: g, cardName: _, onTabChanged: v } = c, [y, b] = a(u ?? d ?? l[0]?.id ?? ""), x = f ? y : u ?? d ?? l[0]?.id ?? "";
8
- function S(e) {
9
- f && b(e), typeof v == "function" && v({ tabId: e });
7
+ var p = (p) => {
8
+ let { tabs: m, value: h, defaultValue: g, selfManaged: _ = !1, orientation: v = "horizontal", className: y, listClassName: b, contentClassName: x, maxTabs: S, cardName: C, onTabChanged: w } = p, [T, E] = u(h ?? g ?? m[0]?.id ?? ""), D = _ ? T : h ?? g ?? m[0]?.id ?? "";
9
+ function O(e) {
10
+ _ && E(e), typeof w == "function" && w({ tabId: e });
10
11
  }
11
- return /* @__PURE__ */ o("div", {
12
- "data-pihanga": _,
13
- children: /* @__PURE__ */ s(e, {
14
- value: x,
15
- onValueChange: S,
16
- orientation: p,
17
- className: m,
18
- children: [/* @__PURE__ */ o(n, {
19
- className: h,
20
- children: l.map((e) => /* @__PURE__ */ o(r, {
12
+ if (S !== void 0 && m.length > S) {
13
+ let a = m.find((e) => e.id === D);
14
+ return /* @__PURE__ */ f("div", {
15
+ "data-pihanga": C,
16
+ className: y,
17
+ children: [/* @__PURE__ */ f(e, {
18
+ value: D,
19
+ onValueChange: O,
20
+ children: [/* @__PURE__ */ d(r, {
21
+ className: b,
22
+ children: /* @__PURE__ */ d(i, { placeholder: "Select a tab…" })
23
+ }), /* @__PURE__ */ d(t, { children: m.map((e) => /* @__PURE__ */ d(n, {
21
24
  value: e.id,
22
25
  disabled: e.disabled,
23
- children: typeof e.title == "string" ? e.title : /* @__PURE__ */ o(i, {
26
+ children: typeof e.title == "string" ? e.title : e.id
27
+ }, e.id)) })]
28
+ }), a && /* @__PURE__ */ d("div", {
29
+ className: x,
30
+ children: /* @__PURE__ */ d(l, {
31
+ cardName: a.contentCard,
32
+ parentCard: C
33
+ })
34
+ })]
35
+ });
36
+ }
37
+ return /* @__PURE__ */ d("div", {
38
+ "data-pihanga": C,
39
+ children: /* @__PURE__ */ f(a, {
40
+ value: D,
41
+ onValueChange: O,
42
+ orientation: v,
43
+ className: y,
44
+ children: [/* @__PURE__ */ d(s, {
45
+ className: b,
46
+ children: m.map((e) => /* @__PURE__ */ d(c, {
47
+ value: e.id,
48
+ disabled: e.disabled,
49
+ children: typeof e.title == "string" ? e.title : /* @__PURE__ */ d(l, {
24
50
  cardName: e.title,
25
- parentCard: _
51
+ parentCard: C
26
52
  })
27
53
  }, e.id))
28
- }), l.map((e) => /* @__PURE__ */ o(t, {
54
+ }), m.map((e) => /* @__PURE__ */ d(o, {
29
55
  value: e.id,
30
- className: g,
31
- children: /* @__PURE__ */ o(i, {
56
+ className: x,
57
+ children: /* @__PURE__ */ d(l, {
32
58
  cardName: e.contentCard,
33
- parentCard: _
59
+ parentCard: C
34
60
  })
35
61
  }, e.id))]
36
62
  })
37
63
  });
38
64
  };
39
65
  //#endregion
40
- export { c as TabsComponent };
66
+ export { p as TabsComponent };
41
67
 
42
68
  //# sourceMappingURL=tabs.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.component.js","names":[],"sources":["../../../src/cards/tabs/tabs.component.tsx"],"sourcesContent":["import React, {useState} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {Tabs, TabsContent, TabsList, TabsTrigger} from \"@/components/ui/tabs\";\nimport type {TabsEvents, TabsProps} from \"./tabs.types\";\n\nexport const TabsComponent = (\n props: PiCardProps<TabsProps, TabsEvents>,\n): React.ReactNode => {\n const {\n tabs,\n value: propValue,\n defaultValue,\n selfManaged = false,\n orientation = \"horizontal\",\n className,\n listClassName,\n contentClassName,\n cardName,\n onTabChanged,\n } = props;\n\n // Resolve the initial value for self-managed mode:\n // prefer propValue, then defaultValue, then first tab's id.\n const initialValue = propValue ?? defaultValue ?? tabs[0]?.id ?? \"\";\n\n // Internal state used only when selfManaged=true.\n const [managedValue, setManagedValue] = useState<string>(initialValue);\n\n // Effective active tab:\n // selfManaged → use internal state\n // controlled → use the prop (fall back to first tab if not set)\n const activeValue = selfManaged\n ? managedValue\n : (propValue ?? defaultValue ?? tabs[0]?.id ?? \"\");\n\n function handleValueChange(tabId: string) {\n if (selfManaged) {\n setManagedValue(tabId);\n }\n // Always dispatch the Pihanga event so reducers can observe the change\n // even in self-managed mode.\n if (typeof onTabChanged === \"function\") {\n onTabChanged({tabId});\n }\n }\n\n return (\n <div data-pihanga={cardName}>\n <Tabs\n value={activeValue}\n onValueChange={handleValueChange}\n orientation={orientation}\n className={className}\n >\n <TabsList className={listClassName}>\n {tabs.map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id} disabled={tab.disabled}>\n {typeof tab.title !== \"string\" ? (\n <Card cardName={tab.title} parentCard={cardName} />\n ) : (\n tab.title\n )}\n </TabsTrigger>\n ))}\n </TabsList>\n\n {tabs.map((tab) => (\n <TabsContent key={tab.id} value={tab.id} className={contentClassName}>\n <Card cardName={tab.contentCard} parentCard={cardName} />\n </TabsContent>\n ))}\n </Tabs>\n </div>\n );\n};\n"],"mappings":";;;;;AAKA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,GACP,iBACA,iBAAc,IACd,iBAAc,cACd,cACA,kBACA,qBACA,aACA,oBACE,GAOE,CAAC,GAAc,KAAmB,EAHnB,KAAa,KAAgB,EAAK,IAAI,MAAM,EAGI,GAK/D,IAAc,IAChB,IACC,KAAa,KAAgB,EAAK,IAAI,MAAM;CAEjD,SAAS,EAAkB,GAAe;EAMxC,AALI,KACF,EAAgB,CAAK,GAInB,OAAO,KAAiB,cAC1B,EAAa,EAAC,SAAK,CAAC;CAExB;CAEA,OACE,kBAAC,OAAD;EAAK,gBAAc;YACjB,kBAAC,GAAD;GACE,OAAO;GACP,eAAe;GACF;GACF;aAJb,CAME,kBAAC,GAAD;IAAU,WAAW;cAClB,EAAK,KAAK,MACT,kBAAC,GAAD;KAA0B,OAAO,EAAI;KAAI,UAAU,EAAI;eACpD,OAAO,EAAI,SAAU,WAGpB,EAAI,QAFJ,kBAAC,GAAD;MAAM,UAAU,EAAI;MAAO,YAAY;KAAW,CAAA;IAIzC,GANK,EAAI,EAMT,CACd;GACO,CAAA,GAET,EAAK,KAAK,MACT,kBAAC,GAAD;IAA0B,OAAO,EAAI;IAAI,WAAW;cAClD,kBAAC,GAAD;KAAM,UAAU,EAAI;KAAa,YAAY;IAAW,CAAA;GAC7C,GAFK,EAAI,EAET,CACd,CACG;;CACH,CAAA;AAET"}
1
+ {"version":3,"file":"tabs.component.js","names":[],"sources":["../../../src/cards/tabs/tabs.component.tsx"],"sourcesContent":["import React, {useState} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {Tabs, TabsContent, TabsList, TabsTrigger} from \"@/components/ui/tabs\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"@/components/ui/select\";\nimport type {TabsEvents, TabsProps} from \"./tabs.types\";\n\nexport const TabsComponent = (\n props: PiCardProps<TabsProps, TabsEvents>,\n): React.ReactNode => {\n const {\n tabs,\n value: propValue,\n defaultValue,\n selfManaged = false,\n orientation = \"horizontal\",\n className,\n listClassName,\n contentClassName,\n maxTabs,\n cardName,\n onTabChanged,\n } = props;\n\n // Resolve the initial value for self-managed mode:\n // prefer propValue, then defaultValue, then first tab's id.\n const initialValue = propValue ?? defaultValue ?? tabs[0]?.id ?? \"\";\n\n // Internal state used only when selfManaged=true.\n const [managedValue, setManagedValue] = useState<string>(initialValue);\n\n // Effective active tab:\n // selfManaged → use internal state\n // controlled → use the prop (fall back to first tab if not set)\n const activeValue = selfManaged\n ? managedValue\n : (propValue ?? defaultValue ?? tabs[0]?.id ?? \"\");\n\n function handleValueChange(tabId: string) {\n if (selfManaged) {\n setManagedValue(tabId);\n }\n // Always dispatch the Pihanga event so reducers can observe the change\n // even in self-managed mode.\n if (typeof onTabChanged === \"function\") {\n onTabChanged({tabId});\n }\n }\n\n // When maxTabs is set and the number of tabs exceeds it, replace the tab\n // strip with a Select drop-down for navigation.\n const useDropdown = maxTabs !== undefined && tabs.length > maxTabs;\n\n if (useDropdown) {\n const activeTab = tabs.find((t) => t.id === activeValue);\n\n return (\n <div data-pihanga={cardName} className={className}>\n {/* Drop-down tab selector */}\n <Select value={activeValue} onValueChange={handleValueChange}>\n <SelectTrigger className={listClassName}>\n <SelectValue placeholder=\"Select a tab…\" />\n </SelectTrigger>\n <SelectContent>\n {tabs.map((tab) => (\n <SelectItem key={tab.id} value={tab.id} disabled={tab.disabled}>\n {typeof tab.title === \"string\" ? tab.title : tab.id}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {/* Content area — render the active tab's card directly */}\n {activeTab && (\n <div className={contentClassName}>\n <Card cardName={activeTab.contentCard} parentCard={cardName} />\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div data-pihanga={cardName}>\n <Tabs\n value={activeValue}\n onValueChange={handleValueChange}\n orientation={orientation}\n className={className}\n >\n <TabsList className={listClassName}>\n {tabs.map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id} disabled={tab.disabled}>\n {typeof tab.title !== \"string\" ? (\n <Card cardName={tab.title} parentCard={cardName} />\n ) : (\n tab.title\n )}\n </TabsTrigger>\n ))}\n </TabsList>\n\n {tabs.map((tab) => (\n <TabsContent key={tab.id} value={tab.id} className={contentClassName}>\n <Card cardName={tab.contentCard} parentCard={cardName} />\n </TabsContent>\n ))}\n </Tabs>\n </div>\n );\n};\n"],"mappings":";;;;;;AAYA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,GACP,iBACA,iBAAc,IACd,iBAAc,cACd,cACA,kBACA,qBACA,YACA,aACA,oBACE,GAOE,CAAC,GAAc,KAAmB,EAHnB,KAAa,KAAgB,EAAK,IAAI,MAAM,EAGI,GAK/D,IAAc,IAChB,IACC,KAAa,KAAgB,EAAK,IAAI,MAAM;CAEjD,SAAS,EAAkB,GAAe;EAMxC,AALI,KACF,EAAgB,CAAK,GAInB,OAAO,KAAiB,cAC1B,EAAa,EAAC,SAAK,CAAC;CAExB;CAMA,IAFoB,MAAY,KAAA,KAAa,EAAK,SAAS,GAE1C;EACf,IAAM,IAAY,EAAK,MAAM,MAAM,EAAE,OAAO,CAAW;EAEvD,OACE,kBAAC,OAAD;GAAK,gBAAc;GAAqB;aAAxC,CAEE,kBAAC,GAAD;IAAQ,OAAO;IAAa,eAAe;cAA3C,CACE,kBAAC,GAAD;KAAe,WAAW;eACxB,kBAAC,GAAD,EAAa,aAAY,gBAAiB,CAAA;IAC7B,CAAA,GACf,kBAAC,GAAD,EAAA,UACG,EAAK,KAAK,MACT,kBAAC,GAAD;KAAyB,OAAO,EAAI;KAAI,UAAU,EAAI;eACnD,OAAO,EAAI,SAAU,WAAW,EAAI,QAAQ,EAAI;IACvC,GAFK,EAAI,EAET,CACb,EACY,CAAA,CACT;OAGP,KACC,kBAAC,OAAD;IAAK,WAAW;cACd,kBAAC,GAAD;KAAM,UAAU,EAAU;KAAa,YAAY;IAAW,CAAA;GAC3D,CAAA,CAEJ;;CAET;CAEA,OACE,kBAAC,OAAD;EAAK,gBAAc;YACjB,kBAAC,GAAD;GACE,OAAO;GACP,eAAe;GACF;GACF;aAJb,CAME,kBAAC,GAAD;IAAU,WAAW;cAClB,EAAK,KAAK,MACT,kBAAC,GAAD;KAA0B,OAAO,EAAI;KAAI,UAAU,EAAI;eACpD,OAAO,EAAI,SAAU,WAGpB,EAAI,QAFJ,kBAAC,GAAD;MAAM,UAAU,EAAI;MAAO,YAAY;KAAW,CAAA;IAIzC,GANK,EAAI,EAMT,CACd;GACO,CAAA,GAET,EAAK,KAAK,MACT,kBAAC,GAAD;IAA0B,OAAO,EAAI;IAAI,WAAW;cAClD,kBAAC,GAAD;KAAM,UAAU,EAAI;KAAa,YAAY;IAAW,CAAA;GAC7C,GAFK,EAAI,EAET,CACd,CACG;;CACH,CAAA;AAET"}
@@ -63,6 +63,16 @@ export type TabsProps = {
63
63
  listClassName?: string;
64
64
  /** Additional classes applied to each TabsContent element. */
65
65
  contentClassName?: string;
66
+ /**
67
+ * Maximum number of tabs to display as a standard tab strip.
68
+ * When the number of tabs exceeds this value the tab selector is replaced
69
+ * by a drop-down `<Select>` menu while the tab content area continues to
70
+ * work as normal.
71
+ *
72
+ * When omitted (or `undefined`) the tab strip is always used regardless of
73
+ * how many tabs there are.
74
+ */
75
+ maxTabs?: number;
66
76
  };
67
77
  export type TabsTabChangedEvent = {
68
78
  /** The id of the newly selected tab. */
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.types.js","names":[],"sources":["../../../src/cards/tabs/tabs.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const TABS_CARD = \"shad/tabs\";\n\nexport const Tabs = createCardDeclaration<TabsProps, TabsEvents>(TABS_CARD);\n\n/** @deprecated Use {@link Tabs} instead. */\nexport const SdTabs = Tabs;\n\nexport const TABS_ACTION = registerActions(TABS_CARD, [\"tabChanged\"]);\n\nexport const onTabsTabChanged = createOnAction<TabsTabChangedEvent>(\n TABS_ACTION.TABCHANGED,\n);\n\n// ─── Tab item definition ──────────────────────────────────────────────────────\n\n/**\n * A single tab entry in the tabs component.\n */\nexport type TabItem = {\n /** Unique identifier used for controlled value and events. */\n id: string;\n\n /**\n * The label displayed on the tab trigger.\n * Can be a plain string or a PiCardRef for custom/rich tab labels.\n */\n title: string | PiCardRef;\n\n /**\n * The Pihanga card rendered as the body of this tab when it is active.\n */\n contentCard: PiCardRef;\n\n /** When true the tab trigger is rendered as disabled. */\n disabled?: boolean;\n};\n\n// ─── Card props ───────────────────────────────────────────────────────────────\n\nexport type TabsProps = {\n /** Ordered list of tab definitions. */\n tabs: TabItem[];\n\n /**\n * Controlled: the currently active tab id.\n * Must be provided (or supplied via a state mapper) when selfManaged is\n * false (the default).\n */\n value?: string;\n\n /**\n * Uncontrolled initial active tab id.\n * Used as the initial value in self-managed mode when value is not set;\n * falls back to the first tab id if omitted.\n */\n defaultValue?: string;\n\n /**\n * When true, the component manages its own active tab state internally.\n * The onTabChanged event is still dispatched on every change so external\n * reducers can observe the selection.\n *\n * When false (default), value fully controls the displayed tab.\n * @default false\n */\n selfManaged?: boolean;\n\n /**\n * Layout orientation of the tab list.\n * Passed directly to the Radix Tabs primitive.\n * @default \"horizontal\"\n */\n orientation?: \"horizontal\" | \"vertical\";\n\n /** Additional Tailwind/CSS classes applied to the root Tabs element. */\n className?: string;\n\n /** Additional classes applied to the TabsList element. */\n listClassName?: string;\n\n /** Additional classes applied to each TabsContent element. */\n contentClassName?: string;\n};\n\n// ─── Events ───────────────────────────────────────────────────────────────────\n\nexport type TabsTabChangedEvent = {\n /** The id of the newly selected tab. */\n tabId: string;\n};\n\nexport type TabsEvents = {\n /** Fired whenever the user selects a different tab. */\n onTabChanged: TabsTabChangedEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAY,aAEZ,IAAO,EAA6C,CAAS,GAG7D,IAAS,GAET,IAAc,EAAgB,GAAW,CAAC,YAAY,CAAC,GAEvD,IAAmB,EAC9B,EAAY,UACd"}
1
+ {"version":3,"file":"tabs.types.js","names":[],"sources":["../../../src/cards/tabs/tabs.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n type PiCardRef,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const TABS_CARD = \"shad/tabs\";\n\nexport const Tabs = createCardDeclaration<TabsProps, TabsEvents>(TABS_CARD);\n\n/** @deprecated Use {@link Tabs} instead. */\nexport const SdTabs = Tabs;\n\nexport const TABS_ACTION = registerActions(TABS_CARD, [\"tabChanged\"]);\n\nexport const onTabsTabChanged = createOnAction<TabsTabChangedEvent>(\n TABS_ACTION.TABCHANGED,\n);\n\n// ─── Tab item definition ──────────────────────────────────────────────────────\n\n/**\n * A single tab entry in the tabs component.\n */\nexport type TabItem = {\n /** Unique identifier used for controlled value and events. */\n id: string;\n\n /**\n * The label displayed on the tab trigger.\n * Can be a plain string or a PiCardRef for custom/rich tab labels.\n */\n title: string | PiCardRef;\n\n /**\n * The Pihanga card rendered as the body of this tab when it is active.\n */\n contentCard: PiCardRef;\n\n /** When true the tab trigger is rendered as disabled. */\n disabled?: boolean;\n};\n\n// ─── Card props ───────────────────────────────────────────────────────────────\n\nexport type TabsProps = {\n /** Ordered list of tab definitions. */\n tabs: TabItem[];\n\n /**\n * Controlled: the currently active tab id.\n * Must be provided (or supplied via a state mapper) when selfManaged is\n * false (the default).\n */\n value?: string;\n\n /**\n * Uncontrolled initial active tab id.\n * Used as the initial value in self-managed mode when value is not set;\n * falls back to the first tab id if omitted.\n */\n defaultValue?: string;\n\n /**\n * When true, the component manages its own active tab state internally.\n * The onTabChanged event is still dispatched on every change so external\n * reducers can observe the selection.\n *\n * When false (default), value fully controls the displayed tab.\n * @default false\n */\n selfManaged?: boolean;\n\n /**\n * Layout orientation of the tab list.\n * Passed directly to the Radix Tabs primitive.\n * @default \"horizontal\"\n */\n orientation?: \"horizontal\" | \"vertical\";\n\n /** Additional Tailwind/CSS classes applied to the root Tabs element. */\n className?: string;\n\n /** Additional classes applied to the TabsList element. */\n listClassName?: string;\n\n /** Additional classes applied to each TabsContent element. */\n contentClassName?: string;\n\n /**\n * Maximum number of tabs to display as a standard tab strip.\n * When the number of tabs exceeds this value the tab selector is replaced\n * by a drop-down `<Select>` menu while the tab content area continues to\n * work as normal.\n *\n * When omitted (or `undefined`) the tab strip is always used regardless of\n * how many tabs there are.\n */\n maxTabs?: number;\n};\n\n// ─── Events ───────────────────────────────────────────────────────────────────\n\nexport type TabsTabChangedEvent = {\n /** The id of the newly selected tab. */\n tabId: string;\n};\n\nexport type TabsEvents = {\n /** Fired whenever the user selects a different tab. */\n onTabChanged: TabsTabChangedEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAY,aAEZ,IAAO,EAA6C,CAAS,GAG7D,IAAS,GAET,IAAc,EAAgB,GAAW,CAAC,YAAY,CAAC,GAEvD,IAAmB,EAC9B,EAAY,UACd"}
@@ -1,13 +1,13 @@
1
1
  import { TextFieldComponent as e } from "./textField.component.js";
2
- import { PI_TEXT_FIELD_ACTION as t, PI_TEXT_FIELD_CARD as n, TextField as r, onPiTextFieldChanged as i } from "./textField.types.js";
3
- import { actionTypesToEvents as a, registerCardComponent as o } from "@pihanga2/core";
2
+ import { PI_TEXT_FIELD_ACTION as t, PI_TEXT_FIELD_CARD as n, TextField as r, onPiTextFieldChanged as i, onTextFieldChanged as a } from "./textField.types.js";
3
+ import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
4
4
  //#region src/cards/textField/index.ts
5
- o({
5
+ s({
6
6
  name: n,
7
7
  component: e,
8
- events: a(t)
8
+ events: o(t)
9
9
  });
10
10
  //#endregion
11
- export { t as PI_TEXT_FIELD_ACTION, n as PI_TEXT_FIELD_CARD, r as TextField, i as onPiTextFieldChanged };
11
+ export { t as PI_TEXT_FIELD_ACTION, n as PI_TEXT_FIELD_CARD, r as TextField, i as onPiTextFieldChanged, a as onTextFieldChanged };
12
12
 
13
13
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,6 @@
1
1
  import { useFormContext as e } from "../form/form.context.js";
2
2
  import { Input as t } from "../../components/ui/input.js";
3
+ import "@pihanga2/core";
3
4
  import "react";
4
5
  import { jsx as n } from "react/jsx-runtime";
5
6
  //#region src/cards/textField/textField.component.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"textField.component.js","names":[],"sources":["../../../src/cards/textField/textField.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Input} from \"@/components/ui/input\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiTextFieldEvents, PiTextFieldProps} from \"./textField.types\";\n\nexport const TextFieldComponent = (\n props: PiCardProps<PiTextFieldProps, PiTextFieldEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue = \"\",\n type = \"text\",\n placeholder,\n disabled,\n cardName,\n onChanged,\n } = props;\n\n // `id` and `invalid` may be injected by a parent pi/field card via\n // Pihanga's extra-prop forwarding. They are not in the official type so\n // we read them 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.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n const value = useFormData\n ? ((form.formData[name!] as string | undefined) ?? \"\")\n : propValue;\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n const newValue = e.target.value;\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n onChanged({name, value: newValue});\n }\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 <Input\n id={fieldId}\n type={type}\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n disabled={disabled}\n aria-invalid={invalid || undefined}\n />\n );\n};\n"],"mappings":";;;;;AAMA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,IAAY,IACnB,UAAO,QACP,gBACA,aACA,aACA,iBACE,GAKE,IAAc,EAAwB,IACtC,IAAU,EAAS,EAA8B,SAGjD,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAEvC,IAAQ,IACR,EAAK,SAAS,MAAiC,KACjD;CAEJ,SAAS,EAAa,GAAwC;EAC5D,IAAM,IAAW,EAAE,OAAO;EAC1B,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,IAEjC,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAIA,IAAM,IAAS,GAAG,EAAS,GAAG,KAAQ;CAGtC,OACE,kBAAC,GAAD;EACE,IAJY,KAAc;EAKpB;EACC;EACP,UAAU;EACG;EACH;EACV,gBAAc,KAAW,KAAA;CAC1B,CAAA;AAEL"}
1
+ {"version":3,"file":"textField.component.js","names":[],"sources":["../../../src/cards/textField/textField.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Input} from \"@/components/ui/input\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiTextFieldEvents, PiTextFieldProps} from \"./textField.types\";\n\nexport const TextFieldComponent = (\n props: PiCardProps<PiTextFieldProps, PiTextFieldEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue = \"\",\n type = \"text\",\n placeholder,\n disabled,\n cardName,\n onChanged,\n } = props;\n\n // `id` and `invalid` may be injected by a parent pi/field card via\n // Pihanga's extra-prop forwarding. They are not in the official type so\n // we read them 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.\n const form = useFormContext();\n const useFormData = form.isInForm && Boolean(name);\n\n const value = useFormData\n ? ((form.formData[name!] as string | undefined) ?? \"\")\n : propValue;\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n const newValue = e.target.value;\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n onChanged({name, value: newValue});\n }\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 <Input\n id={fieldId}\n type={type}\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n disabled={disabled}\n aria-invalid={invalid || undefined}\n />\n );\n};\n"],"mappings":";;;;;;AAMA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,IAAY,IACnB,UAAO,QACP,gBACA,aACA,aACA,iBACE,GAKE,IAAc,EAAwB,IACtC,IAAU,EAAS,EAA8B,SAGjD,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAEvC,IAAQ,IACR,EAAK,SAAS,MAAiC,KACjD;CAEJ,SAAS,EAAa,GAAwC;EAC5D,IAAM,IAAW,EAAE,OAAO;EAC1B,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,IAEjC,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAIA,IAAM,IAAS,GAAG,EAAS,GAAG,KAAQ;CAGtC,OACE,kBAAC,GAAD;EACE,IAJY,KAAc;EAKpB;EACC;EACP,UAAU;EACG;EACH;EACV,gBAAc,KAAW,KAAA;CAC1B,CAAA;AAEL"}
@@ -3,6 +3,10 @@ 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 & {
7
+ cardID: string;
8
+ } & PiTextFieldChangedEvent>) => void;
9
+ /** @deprecated Use `onTextFieldChanged` instead. */
6
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 & {
7
11
  cardID: string;
8
12
  } & PiTextFieldChangedEvent>) => void;
@@ -1,7 +1,7 @@
1
1
  import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
2
  //#region src/cards/textField/textField.types.ts
3
- var r = "pi/text-field", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED);
3
+ var r = "pi/text-field", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED), s = o;
4
4
  //#endregion
5
- export { a as PI_TEXT_FIELD_ACTION, r as PI_TEXT_FIELD_CARD, i as TextField, o as onPiTextFieldChanged };
5
+ export { a as PI_TEXT_FIELD_ACTION, r as PI_TEXT_FIELD_CARD, i as TextField, s as onPiTextFieldChanged, o as onTextFieldChanged };
6
6
 
7
7
  //# sourceMappingURL=textField.types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"textField.types.js","names":[],"sources":["../../../src/cards/textField/textField.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_TEXT_FIELD_CARD = \"pi/text-field\";\n\nexport const TextField = createCardDeclaration<\n PiTextFieldProps,\n PiTextFieldEvents\n>(PI_TEXT_FIELD_CARD);\n\nexport const PI_TEXT_FIELD_ACTION = registerActions(PI_TEXT_FIELD_CARD, [\n \"changed\",\n]);\n\nexport const onPiTextFieldChanged = createOnAction<PiTextFieldChangedEvent>(\n PI_TEXT_FIELD_ACTION.CHANGED,\n);\n\nexport type PiTextFieldProps = {\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 /** HTML input type (e.g. \"text\", \"email\", \"password\", \"number\"). */\n type?: string;\n\n /** Placeholder text shown when the input is empty. */\n placeholder?: string;\n\n /** When true, the input is disabled and non-interactive. */\n disabled?: boolean;\n};\n\nexport type PiTextFieldChangedEvent = {\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 PiTextFieldEvents = {\n onChanged: PiTextFieldChangedEvent;\n};\n"],"mappings":";;AAMA,IAAa,IAAqB,iBAErB,IAAY,EAGvB,CAAkB,GAEP,IAAuB,EAAgB,GAAoB,CACtE,SACF,CAAC,GAEY,IAAuB,EAClC,EAAqB,OACvB"}
1
+ {"version":3,"file":"textField.types.js","names":[],"sources":["../../../src/cards/textField/textField.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_TEXT_FIELD_CARD = \"pi/text-field\";\n\nexport const TextField = createCardDeclaration<\n PiTextFieldProps,\n PiTextFieldEvents\n>(PI_TEXT_FIELD_CARD);\n\nexport const PI_TEXT_FIELD_ACTION = registerActions(PI_TEXT_FIELD_CARD, [\n \"changed\",\n]);\n\nexport const onTextFieldChanged = createOnAction<PiTextFieldChangedEvent>(\n PI_TEXT_FIELD_ACTION.CHANGED,\n);\n\n/** @deprecated Use `onTextFieldChanged` instead. */\nexport const onPiTextFieldChanged = onTextFieldChanged;\n\nexport type PiTextFieldProps = {\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 /** HTML input type (e.g. \"text\", \"email\", \"password\", \"number\"). */\n type?: string;\n\n /** Placeholder text shown when the input is empty. */\n placeholder?: string;\n\n /** When true, the input is disabled and non-interactive. */\n disabled?: boolean;\n};\n\nexport type PiTextFieldChangedEvent = {\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 PiTextFieldEvents = {\n onChanged: PiTextFieldChangedEvent;\n};\n"],"mappings":";;AAMA,IAAa,IAAqB,iBAErB,IAAY,EAGvB,CAAkB,GAEP,IAAuB,EAAgB,GAAoB,CACtE,SACF,CAAC,GAEY,IAAqB,EAChC,EAAqB,OACvB,GAGa,IAAuB"}
@@ -1,13 +1,13 @@
1
- import { PI_TOAST_ACTION as e, PI_TOAST_CARD as t, TOAST_OP_ACTION as n, Toast as r, dispatchShowToast as i, onPiToastClosed as a, onShowToast as o } from "./toast.types.js";
2
- import { ToastComponent as s } from "./toast.component.js";
3
- import { actionTypesToEvents as c, registerCardComponent as l } from "@pihanga2/core";
1
+ import { PI_TOAST_ACTION as e, PI_TOAST_CARD as t, TOAST_OP_ACTION as n, Toast as r, dispatchShowToast as i, onPiToastClosed as a, onShowToast as o, onToastClosed as s } from "./toast.types.js";
2
+ import { ToastComponent as c } from "./toast.component.js";
3
+ import { actionTypesToEvents as l, registerCardComponent as u } from "@pihanga2/core";
4
4
  //#region src/cards/toast/index.ts
5
- l({
5
+ u({
6
6
  name: t,
7
- component: s,
8
- events: c(e)
7
+ component: c,
8
+ events: l(e)
9
9
  });
10
10
  //#endregion
11
- export { e as PI_TOAST_ACTION, t as PI_TOAST_CARD, n as TOAST_OP_ACTION, r as Toast, i as dispatchShowToast, a as onPiToastClosed, o as onShowToast };
11
+ export { e as PI_TOAST_ACTION, t as PI_TOAST_CARD, n as TOAST_OP_ACTION, r as Toast, i as dispatchShowToast, a as onPiToastClosed, o as onShowToast, s as onToastClosed };
12
12
 
13
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.component.js","names":[],"sources":["../../../src/cards/toast/toast.component.tsx"],"sourcesContent":["import React, {useEffect, useRef, useState} from \"react\";\nimport {\n Card,\n type PiCardProps,\n type PiCardRef,\n usePiReducer,\n type ReduxAction,\n type ReduxState,\n} from \"@pihanga2/core\";\nimport {toast} from \"sonner\";\n\nimport {\n ShowToastEvent,\n TOAST_OP_ACTION,\n ToastPosition,\n ToastType,\n type PiToastEvents,\n type PiToastProps,\n} from \"./toast.types\";\n\nexport const ToastComponent = (\n props: PiCardProps<PiToastProps, PiToastEvents>,\n): React.ReactNode => {\n const {\n variant: defaultVariant = \"default\",\n duration: defaultDuration = 4000,\n dismissible: defaultDismissible = true,\n className: defaultClassName,\n onClosed,\n cardName,\n } = props;\n\n // State for tracking Redux-triggered toast messages\n const [currentToast, setCurrentToast] = useState<{\n message?: string;\n description?: string;\n contentCard?: PiCardRef;\n variant: ToastType;\n position?: ToastPosition;\n duration: number;\n } | null>(null);\n\n // Listen for showToast Redux messages\n // This allows triggering toasts from anywhere via dispatchShowToast\n usePiReducer<ReduxState, ShowToastEvent & ReduxAction>(\n TOAST_OP_ACTION.SHOW,\n (_, action) => {\n // Only respond if message is for this card or no specific cardName is set\n if (action.cardName && action.cardName !== cardName) {\n return;\n }\n setCurrentToast({\n message: action.message,\n description: action.description,\n contentCard: action.contentCard,\n variant: action.variant ?? defaultVariant,\n position: action.position,\n duration: action.duration ?? defaultDuration,\n });\n },\n cardName,\n );\n\n // Setup hooks before conditional rendering\n const toastIdRef = useRef<string | number | undefined>(undefined);\n\n useEffect(() => {\n // Only show toast if Redux message was received\n if (!currentToast) {\n return;\n }\n\n // Map our toast types to Sonner's toast function\n const toastFn =\n {\n success: toast.success,\n error: toast.error,\n info: toast.info,\n warning: toast.warning,\n default: toast,\n }[currentToast.variant] || toast;\n\n // Build className: combine default + variant-based class\n const className = [defaultClassName, `toast-${currentToast.variant}`]\n .filter(Boolean)\n .join(\" \");\n\n // If contentCard is provided, render it as custom JSX content\n if (currentToast.contentCard) {\n const contentCard = currentToast.contentCard;\n const CustomToastContent = () => (\n <Card cardName={contentCard} parentCard={cardName} />\n );\n\n // Show the toast with custom card content\n toastIdRef.current = toastFn(CustomToastContent, {\n duration: currentToast.duration,\n position: currentToast.position || \"bottom-right\",\n dismissible: defaultDismissible,\n className,\n onDismiss: () => {\n setCurrentToast(null);\n onClosed({});\n },\n onAutoClose: () => {\n setCurrentToast(null);\n onClosed({});\n },\n });\n } else {\n // Show the toast with message and optional description\n toastIdRef.current = toastFn(currentToast.message, {\n description: currentToast.description,\n duration: currentToast.duration,\n position: currentToast.position || \"bottom-right\",\n dismissible: defaultDismissible,\n className,\n onDismiss: () => {\n setCurrentToast(null);\n onClosed({});\n },\n onAutoClose: () => {\n setCurrentToast(null);\n onClosed({});\n },\n });\n }\n\n // Cleanup on unmount\n return () => {\n if (toastIdRef.current !== undefined) {\n toast.dismiss(toastIdRef.current);\n }\n };\n }, [currentToast, defaultDismissible, defaultClassName, onClosed, cardName]);\n\n // This component doesn't render visible DOM itself\n // Sonner renders toasts in a portal via its Toaster component\n return <div data-pihanga={cardName} style={{display: \"none\"}} />;\n};\n"],"mappings":";;;;;;AAoBA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SAAS,IAAiB,WAC1B,UAAU,IAAkB,KAC5B,aAAa,IAAqB,IAClC,WAAW,GACX,aACA,gBACE,GAGE,CAAC,GAAc,KAAmB,EAO9B,IAAI;CAId,EACE,EAAgB,OACf,GAAG,MAAW;EAET,EAAO,YAAY,EAAO,aAAa,KAG3C,EAAgB;GACd,SAAS,EAAO;GAChB,aAAa,EAAO;GACpB,aAAa,EAAO;GACpB,SAAS,EAAO,WAAW;GAC3B,UAAU,EAAO;GACjB,UAAU,EAAO,YAAY;EAC/B,CAAC;CACH,GACA,CACF;CAGA,IAAM,IAAa,EAAoC,KAAA,CAAS;CA0EhE,OAxEA,QAAgB;EAEd,IAAI,CAAC,GACH;EAIF,IAAM,IACJ;GACE,SAAS,EAAM;GACf,OAAO,EAAM;GACb,MAAM,EAAM;GACZ,SAAS,EAAM;GACf,SAAS;EACX,EAAE,EAAa,YAAY,GAGvB,IAAY,CAAC,GAAkB,SAAS,EAAa,SAAS,EACjE,OAAO,OAAO,EACd,KAAK,GAAG;EAGX,IAAI,EAAa,aAAa;GAC5B,IAAM,IAAc,EAAa;GAMjC,EAAW,UAAU,QAJnB,kBAAC,GAAD;IAAM,UAAU;IAAa,YAAY;GAAW,CAAA,GAIL;IAC/C,UAAU,EAAa;IACvB,UAAU,EAAa,YAAY;IACnC,aAAa;IACb;IACA,iBAAiB;KAEf,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;IACb;IACA,mBAAmB;KAEjB,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;IACb;GACF,CAAC;EACH,OAEE,EAAW,UAAU,EAAQ,EAAa,SAAS;GACjD,aAAa,EAAa;GAC1B,UAAU,EAAa;GACvB,UAAU,EAAa,YAAY;GACnC,aAAa;GACb;GACA,iBAAiB;IAEf,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;GACb;GACA,mBAAmB;IAEjB,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;GACb;EACF,CAAC;EAIH,aAAa;GACX,AAAI,EAAW,YAAY,KAAA,KACzB,EAAM,QAAQ,EAAW,OAAO;EAEpC;CACF,GAAG;EAAC;EAAc;EAAoB;EAAkB;EAAU;CAAQ,CAAC,GAIpE,kBAAC,OAAD;EAAK,gBAAc;EAAU,OAAO,EAAC,SAAS,OAAM;CAAI,CAAA;AACjE"}
1
+ {"version":3,"file":"toast.component.js","names":[],"sources":["../../../src/cards/toast/toast.component.tsx"],"sourcesContent":["import React, {useEffect, useRef, useState} from \"react\";\nimport {\n Card,\n type PiCardProps,\n type PiCardRef,\n usePiReducer,\n type ReduxAction,\n type ReduxState,\n} from \"@pihanga2/core\";\nimport {toast} from \"sonner\";\n\nimport {\n type ShowToastEvent,\n TOAST_OP_ACTION,\n type ToastPosition,\n type ToastType,\n type PiToastEvents,\n type PiToastProps,\n} from \"./toast.types\";\n\nexport const ToastComponent = (\n props: PiCardProps<PiToastProps, PiToastEvents>,\n): React.ReactNode => {\n const {\n variant: defaultVariant = \"default\",\n duration: defaultDuration = 4000,\n dismissible: defaultDismissible = true,\n className: defaultClassName,\n onClosed,\n cardName,\n } = props;\n\n // State for tracking Redux-triggered toast messages\n const [currentToast, setCurrentToast] = useState<{\n message?: string;\n description?: string;\n contentCard?: PiCardRef;\n variant: ToastType;\n position?: ToastPosition;\n duration: number;\n } | null>(null);\n\n // Listen for showToast Redux messages\n // This allows triggering toasts from anywhere via dispatchShowToast\n usePiReducer<ReduxState, ShowToastEvent & ReduxAction>(\n TOAST_OP_ACTION.SHOW,\n (_, action) => {\n // Only respond if message is for this card or no specific cardName is set\n if (action.cardName && action.cardName !== cardName) {\n return;\n }\n setCurrentToast({\n message: action.message,\n description: action.description,\n contentCard: action.contentCard,\n variant: action.variant ?? defaultVariant,\n position: action.position,\n duration: action.duration ?? defaultDuration,\n });\n },\n cardName,\n );\n\n // Setup hooks before conditional rendering\n const toastIdRef = useRef<string | number | undefined>(undefined);\n\n useEffect(() => {\n // Only show toast if Redux message was received\n if (!currentToast) {\n return;\n }\n\n // Map our toast types to Sonner's toast function\n const toastFn =\n {\n success: toast.success,\n error: toast.error,\n info: toast.info,\n warning: toast.warning,\n default: toast,\n }[currentToast.variant] || toast;\n\n // Build className: combine default + variant-based class\n const className = [defaultClassName, `toast-${currentToast.variant}`]\n .filter(Boolean)\n .join(\" \");\n\n // If contentCard is provided, render it as custom JSX content\n if (currentToast.contentCard) {\n const contentCard = currentToast.contentCard;\n const CustomToastContent = () => (\n <Card cardName={contentCard} parentCard={cardName} />\n );\n\n // Show the toast with custom card content\n toastIdRef.current = toastFn(CustomToastContent, {\n duration: currentToast.duration,\n position: currentToast.position || \"bottom-right\",\n dismissible: defaultDismissible,\n className,\n onDismiss: () => {\n setCurrentToast(null);\n onClosed({});\n },\n onAutoClose: () => {\n setCurrentToast(null);\n onClosed({});\n },\n });\n } else {\n // Show the toast with message and optional description\n toastIdRef.current = toastFn(currentToast.message, {\n description: currentToast.description,\n duration: currentToast.duration,\n position: currentToast.position || \"bottom-right\",\n dismissible: defaultDismissible,\n className,\n onDismiss: () => {\n setCurrentToast(null);\n onClosed({});\n },\n onAutoClose: () => {\n setCurrentToast(null);\n onClosed({});\n },\n });\n }\n\n // Cleanup on unmount\n return () => {\n if (toastIdRef.current !== undefined) {\n toast.dismiss(toastIdRef.current);\n }\n };\n }, [currentToast, defaultDismissible, defaultClassName, onClosed, cardName]);\n\n // This component doesn't render visible DOM itself\n // Sonner renders toasts in a portal via its Toaster component\n return <div data-pihanga={cardName} style={{display: \"none\"}} />;\n};\n"],"mappings":";;;;;;AAoBA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SAAS,IAAiB,WAC1B,UAAU,IAAkB,KAC5B,aAAa,IAAqB,IAClC,WAAW,GACX,aACA,gBACE,GAGE,CAAC,GAAc,KAAmB,EAO9B,IAAI;CAId,EACE,EAAgB,OACf,GAAG,MAAW;EAET,EAAO,YAAY,EAAO,aAAa,KAG3C,EAAgB;GACd,SAAS,EAAO;GAChB,aAAa,EAAO;GACpB,aAAa,EAAO;GACpB,SAAS,EAAO,WAAW;GAC3B,UAAU,EAAO;GACjB,UAAU,EAAO,YAAY;EAC/B,CAAC;CACH,GACA,CACF;CAGA,IAAM,IAAa,EAAoC,KAAA,CAAS;CA0EhE,OAxEA,QAAgB;EAEd,IAAI,CAAC,GACH;EAIF,IAAM,IACJ;GACE,SAAS,EAAM;GACf,OAAO,EAAM;GACb,MAAM,EAAM;GACZ,SAAS,EAAM;GACf,SAAS;EACX,EAAE,EAAa,YAAY,GAGvB,IAAY,CAAC,GAAkB,SAAS,EAAa,SAAS,EACjE,OAAO,OAAO,EACd,KAAK,GAAG;EAGX,IAAI,EAAa,aAAa;GAC5B,IAAM,IAAc,EAAa;GAMjC,EAAW,UAAU,QAJnB,kBAAC,GAAD;IAAM,UAAU;IAAa,YAAY;GAAW,CAAA,GAIL;IAC/C,UAAU,EAAa;IACvB,UAAU,EAAa,YAAY;IACnC,aAAa;IACb;IACA,iBAAiB;KAEf,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;IACb;IACA,mBAAmB;KAEjB,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;IACb;GACF,CAAC;EACH,OAEE,EAAW,UAAU,EAAQ,EAAa,SAAS;GACjD,aAAa,EAAa;GAC1B,UAAU,EAAa;GACvB,UAAU,EAAa,YAAY;GACnC,aAAa;GACb;GACA,iBAAiB;IAEf,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;GACb;GACA,mBAAmB;IAEjB,AADA,EAAgB,IAAI,GACpB,EAAS,CAAC,CAAC;GACb;EACF,CAAC;EAIH,aAAa;GACX,AAAI,EAAW,YAAY,KAAA,KACzB,EAAM,QAAQ,EAAW,OAAO;EAEpC;CACF,GAAG;EAAC;EAAc;EAAoB;EAAkB;EAAU;CAAQ,CAAC,GAIpE,kBAAC,OAAD;EAAK,gBAAc;EAAU,OAAO,EAAC,SAAS,OAAM;CAAI,CAAA;AACjE"}
@@ -44,6 +44,10 @@ export declare const onShowToast: <S extends import('@pihanga2/core').ReduxState
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 & {
48
+ cardID: string;
49
+ } & PiToastClosedEvent>) => void;
50
+ /** @deprecated Use `onToastClosed` instead. */
47
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 & {
48
52
  cardID: string;
49
53
  } & PiToastClosedEvent>) => void;
@@ -5,8 +5,8 @@ var r = "pi/toast", i = e(r), a = n("toast/op", ["show"]), o = (e, t) => {
5
5
  ...t,
6
6
  type: a.SHOW
7
7
  });
8
- }, s = t(a.SHOW), c = n(r, ["closed"]), l = t(c.CLOSED);
8
+ }, s = t(a.SHOW), c = n(r, ["closed"]), l = t(c.CLOSED), u = l;
9
9
  //#endregion
10
- export { c as PI_TOAST_ACTION, r as PI_TOAST_CARD, a as TOAST_OP_ACTION, i as Toast, o as dispatchShowToast, l as onPiToastClosed, s as onShowToast };
10
+ export { c as PI_TOAST_ACTION, r as PI_TOAST_CARD, a as TOAST_OP_ACTION, i as Toast, o as dispatchShowToast, u as onPiToastClosed, s as onShowToast, l as onToastClosed };
11
11
 
12
12
  //# sourceMappingURL=toast.types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toast.types.js","names":[],"sources":["../../../src/cards/toast/toast.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n PiCardRef,\n registerActions,\n type DispatchF,\n} from \"@pihanga2/core\";\n\nexport const PI_TOAST_CARD = \"pi/toast\";\n\nexport const Toast = createCardDeclaration<PiToastProps, PiToastEvents>(\n PI_TOAST_CARD,\n);\n\nexport const TOAST_OP_ACTION = registerActions(\"toast/op\", [\"show\"]);\n\n/**\n * Dispatch helper to show a toast\n *\n * @param d - Dispatch function from Pihanga\n * @param ev - Toast event data\n *\n * @example\n * ```typescript\n * import {dispatchShowToast} from \"@/cards/toast\";\n *\n * dispatchShowToast(_dispatch, {\n * message: \"Success!\",\n * description: \"Your changes were saved.\",\n * variant: \"success\",\n * duration: 3000,\n * });\n * ```\n */\nexport const dispatchShowToast = (d: DispatchF, ev: ShowToastEvent) => {\n d({...ev, type: TOAST_OP_ACTION.SHOW});\n};\n\n/**\n * Action handler for when a toast is shown\n *\n * Use this in your reducers or effects to handle toast display events:\n *\n * @example\n * ```typescript\n * import {onShowToast} from \"@/cards/toast\";\n *\n * export const handleShowToast = onShowToast((state, action) => {\n * console.log(\"Toast shown:\", action.payload.message);\n * return state;\n * });\n * ```\n */\nexport const onShowToast = createOnAction<ShowToastEvent>(TOAST_OP_ACTION.SHOW);\n\nexport const PI_TOAST_ACTION = registerActions(PI_TOAST_CARD, [\"closed\"]);\n\nexport const onPiToastClosed = createOnAction<PiToastClosedEvent>(\n PI_TOAST_ACTION.CLOSED,\n);\n\n/**\n * Toast notification type/variant.\n */\nexport type ToastType = \"default\" | \"success\" | \"error\" | \"info\" | \"warning\";\n\n/**\n * Position of the toast on the screen.\n */\nexport type ToastPosition =\n | \"top-left\"\n | \"top-center\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\";\n\nexport type PiToastProps = {\n /**\n * Default variant for toasts shown by this card instance.\n * Can be overridden per individual toast via ShowToastEvent.variant.\n * @default 'default'\n */\n variant?: ToastType;\n\n /**\n * Default duration in milliseconds before the toast auto-closes.\n * Can be overridden per individual toast via ShowToastEvent.duration.\n * Set to `Infinity` to disable auto-close.\n * @default 4000\n */\n duration?: number;\n\n /**\n * Whether toasts from this card are dismissible by the user.\n * This is a card-level setting only; it cannot be overridden per individual toast.\n * @default true\n */\n dismissible?: boolean;\n\n /**\n * Custom CSS class to apply to all toasts from this card.\n */\n className?: string;\n};\n\nexport type PiToastClosedEvent = {\n id?: string;\n};\n\nexport type PiToastEvents = {\n onClosed: PiToastClosedEvent;\n};\n\n/**\n * Event payload for showing a toast\n */\nexport type ShowToastEvent = {\n cardName?: string;\n message: string;\n description?: string;\n contentCard?: PiCardRef; // Alternative: custom card for richer content\n variant?: ToastType;\n position?: ToastPosition; // Toast position on screen\n duration?: number;\n};\n"],"mappings":";;AAQA,IAAa,IAAgB,YAEhB,IAAQ,EACnB,CACF,GAEa,IAAkB,EAAgB,YAAY,CAAC,MAAM,CAAC,GAoBtD,KAAqB,GAAc,MAAuB;CACrE,EAAE;EAAC,GAAG;EAAI,MAAM,EAAgB;CAAI,CAAC;AACvC,GAiBa,IAAc,EAA+B,EAAgB,IAAI,GAEjE,IAAkB,EAAgB,GAAe,CAAC,QAAQ,CAAC,GAE3D,IAAkB,EAC7B,EAAgB,MAClB"}
1
+ {"version":3,"file":"toast.types.js","names":[],"sources":["../../../src/cards/toast/toast.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n type PiCardRef,\n registerActions,\n type DispatchF,\n} from \"@pihanga2/core\";\n\nexport const PI_TOAST_CARD = \"pi/toast\";\n\nexport const Toast = createCardDeclaration<PiToastProps, PiToastEvents>(\n PI_TOAST_CARD,\n);\n\nexport const TOAST_OP_ACTION = registerActions(\"toast/op\", [\"show\"]);\n\n/**\n * Dispatch helper to show a toast\n *\n * @param d - Dispatch function from Pihanga\n * @param ev - Toast event data\n *\n * @example\n * ```typescript\n * import {dispatchShowToast} from \"@/cards/toast\";\n *\n * dispatchShowToast(_dispatch, {\n * message: \"Success!\",\n * description: \"Your changes were saved.\",\n * variant: \"success\",\n * duration: 3000,\n * });\n * ```\n */\nexport const dispatchShowToast = (d: DispatchF, ev: ShowToastEvent) => {\n d({...ev, type: TOAST_OP_ACTION.SHOW});\n};\n\n/**\n * Action handler for when a toast is shown\n *\n * Use this in your reducers or effects to handle toast display events:\n *\n * @example\n * ```typescript\n * import {onShowToast} from \"@/cards/toast\";\n *\n * export const handleShowToast = onShowToast((state, action) => {\n * console.log(\"Toast shown:\", action.payload.message);\n * return state;\n * });\n * ```\n */\nexport const onShowToast = createOnAction<ShowToastEvent>(TOAST_OP_ACTION.SHOW);\n\nexport const PI_TOAST_ACTION = registerActions(PI_TOAST_CARD, [\"closed\"]);\n\nexport const onToastClosed = createOnAction<PiToastClosedEvent>(\n PI_TOAST_ACTION.CLOSED,\n);\n\n/** @deprecated Use `onToastClosed` instead. */\nexport const onPiToastClosed = onToastClosed;\n\n/**\n * Toast notification type/variant.\n */\nexport type ToastType = \"default\" | \"success\" | \"error\" | \"info\" | \"warning\";\n\n/**\n * Position of the toast on the screen.\n */\nexport type ToastPosition =\n | \"top-left\"\n | \"top-center\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-center\"\n | \"bottom-right\";\n\nexport type PiToastProps = {\n /**\n * Default variant for toasts shown by this card instance.\n * Can be overridden per individual toast via ShowToastEvent.variant.\n * @default 'default'\n */\n variant?: ToastType;\n\n /**\n * Default duration in milliseconds before the toast auto-closes.\n * Can be overridden per individual toast via ShowToastEvent.duration.\n * Set to `Infinity` to disable auto-close.\n * @default 4000\n */\n duration?: number;\n\n /**\n * Whether toasts from this card are dismissible by the user.\n * This is a card-level setting only; it cannot be overridden per individual toast.\n * @default true\n */\n dismissible?: boolean;\n\n /**\n * Custom CSS class to apply to all toasts from this card.\n */\n className?: string;\n};\n\nexport type PiToastClosedEvent = {\n id?: string;\n};\n\nexport type PiToastEvents = {\n onClosed: PiToastClosedEvent;\n};\n\n/**\n * Event payload for showing a toast\n */\nexport type ShowToastEvent = {\n cardName?: string;\n message: string;\n description?: string;\n contentCard?: PiCardRef; // Alternative: custom card for richer content\n variant?: ToastType;\n position?: ToastPosition; // Toast position on screen\n duration?: number;\n};\n"],"mappings":";;AAQA,IAAa,IAAgB,YAEhB,IAAQ,EACnB,CACF,GAEa,IAAkB,EAAgB,YAAY,CAAC,MAAM,CAAC,GAoBtD,KAAqB,GAAc,MAAuB;CACrE,EAAE;EAAC,GAAG;EAAI,MAAM,EAAgB;CAAI,CAAC;AACvC,GAiBa,IAAc,EAA+B,EAAgB,IAAI,GAEjE,IAAkB,EAAgB,GAAe,CAAC,QAAQ,CAAC,GAE3D,IAAgB,EAC3B,EAAgB,MAClB,GAGa,IAAkB"}
@@ -1,13 +1,13 @@
1
1
  import { ToggleGroupComponent as e } from "./toggleGroup.component.js";
2
- import { PI_TOGGLE_GROUP_ACTION as t, PI_TOGGLE_GROUP_CARD as n, ToggleGroup as r, onPiToggleGroupChanged as i } from "./toggleGroup.types.js";
3
- import { actionTypesToEvents as a, registerCardComponent as o } from "@pihanga2/core";
2
+ import { PI_TOGGLE_GROUP_ACTION as t, PI_TOGGLE_GROUP_CARD as n, ToggleGroup as r, onPiToggleGroupChanged as i, onToggleGroupChanged as a } from "./toggleGroup.types.js";
3
+ import { actionTypesToEvents as o, registerCardComponent as s } from "@pihanga2/core";
4
4
  //#region src/cards/toggleGroup/index.ts
5
- o({
5
+ s({
6
6
  name: n,
7
7
  component: e,
8
- events: a(t)
8
+ events: o(t)
9
9
  });
10
10
  //#endregion
11
- export { t as PI_TOGGLE_GROUP_ACTION, n as PI_TOGGLE_GROUP_CARD, r as ToggleGroup, i as onPiToggleGroupChanged };
11
+ export { t as PI_TOGGLE_GROUP_ACTION, n as PI_TOGGLE_GROUP_CARD, r as ToggleGroup, i as onPiToggleGroupChanged, a as onToggleGroupChanged };
12
12
 
13
13
  //# sourceMappingURL=index.js.map
@@ -1,5 +1,6 @@
1
1
  import { useFormContext as e } from "../form/form.context.js";
2
2
  import { ToggleGroup as t, ToggleGroupItem as n } from "../../components/ui/toggle-group.js";
3
+ import "@pihanga2/core";
3
4
  import r from "react";
4
5
  import { jsx as i } from "react/jsx-runtime";
5
6
  //#region src/cards/toggleGroup/toggleGroup.component.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"toggleGroup.component.js","names":[],"sources":["../../../src/cards/toggleGroup/toggleGroup.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {\n ToggleGroup as ToggleGroupUI,\n ToggleGroupItem,\n} from \"@/components/ui/toggle-group\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {\n PiToggleGroupEvents,\n PiToggleGroupProps,\n} from \"./toggleGroup.types\";\n\nexport const ToggleGroupComponent = (\n props: PiCardProps<PiToggleGroupProps, PiToggleGroupEvents>,\n): React.ReactNode => {\n const {\n name,\n items,\n type = \"single\",\n value: propValue,\n selfManaged = false,\n variant = \"default\",\n size = \"default\",\n spacing = 0,\n disabled,\n className,\n cardName,\n onChanged,\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 // ---------------------------------------------------------------------------\n // Self-managed (internal) state — only active when selfManaged=true and we\n // are NOT inside a pi/form card.\n // ---------------------------------------------------------------------------\n const initialSelfValue: string | string[] =\n type === \"multiple\"\n ? Array.isArray(propValue)\n ? propValue\n : propValue != null\n ? [String(propValue)]\n : []\n : typeof propValue === \"string\"\n ? propValue\n : \"\";\n\n const [internalValue, setInternalValue] = React.useState<string | string[]>(\n initialSelfValue,\n );\n\n // ---------------------------------------------------------------------------\n // Derive the effective value from the appropriate source.\n // 1. Form context (highest priority)\n // 2. Self-managed internal state\n // 3. Externally controlled prop value\n // ---------------------------------------------------------------------------\n const formRawValue = useFormData ? form.formData[name!] : undefined;\n const value: string | string[] = useFormData\n ? type === \"multiple\"\n ? Array.isArray(formRawValue)\n ? (formRawValue as string[])\n : formRawValue != null\n ? [String(formRawValue)]\n : []\n : formRawValue != null\n ? String(formRawValue)\n : \"\"\n : selfManaged\n ? internalValue\n : (propValue ?? (type === \"multiple\" ? [] : \"\"));\n\n function handleSingleChange(newValue: string) {\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n if (selfManaged) {\n setInternalValue(newValue);\n }\n onChanged({name: name ?? cardName, value: newValue});\n }\n }\n\n function handleMultipleChange(newValue: string[]) {\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n if (selfManaged) {\n setInternalValue(newValue);\n }\n onChanged({name: name ?? cardName, value: newValue});\n }\n }\n\n // Render single-selection group\n if (type === \"single\") {\n return (\n <ToggleGroupUI\n data-pihanga={cardName}\n type=\"single\"\n value={typeof value === \"string\" ? value : \"\"}\n onValueChange={handleSingleChange}\n variant={variant}\n size={size}\n spacing={spacing}\n disabled={disabled}\n className={className}\n >\n {items.map((item) => (\n <ToggleGroupItem\n key={item.value}\n value={item.value}\n disabled={item.disabled}\n >\n {item.label}\n </ToggleGroupItem>\n ))}\n </ToggleGroupUI>\n );\n }\n\n // Render multiple-selection group\n return (\n <ToggleGroupUI\n data-pihanga={cardName}\n type=\"multiple\"\n value={Array.isArray(value) ? value : value ? [value] : []}\n onValueChange={handleMultipleChange}\n variant={variant}\n size={size}\n spacing={spacing}\n disabled={disabled}\n className={className}\n >\n {items.map((item) => (\n <ToggleGroupItem\n key={item.value}\n value={item.value}\n disabled={item.disabled}\n >\n {item.label}\n </ToggleGroupItem>\n ))}\n </ToggleGroupUI>\n );\n};\n"],"mappings":";;;;;AAYA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,UACA,UAAO,UACP,OAAO,GACP,iBAAc,IACd,aAAU,WACV,UAAO,WACP,aAAU,GACV,aACA,cACA,aACA,iBACE,GAGE,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAMvC,IACJ,MAAS,aACL,MAAM,QAAQ,CAAS,IACrB,IACA,KAAa,OAEX,CAAC,IADD,CAAC,OAAO,CAAS,CAAC,IAEtB,OAAO,KAAc,WACnB,IACA,IAEF,CAAC,GAAe,KAAoB,EAAM,SAC9C,CACF,GAQM,IAAe,IAAc,EAAK,SAAS,KAAS,KAAA,GACpD,IAA2B,IAC7B,MAAS,aACP,MAAM,QAAQ,CAAY,IACvB,IACD,KAAgB,OAEd,CAAC,IADD,CAAC,OAAO,CAAY,CAAC,IAEzB,KAAgB,OAEd,KADA,OAAO,CAAY,IAEvB,IACE,IACC,MAAc,MAAS,aAAa,CAAC,IAAI;CAEhD,SAAS,EAAmB,GAAkB;EAC5C,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,KAE7B,KACF,EAAiB,CAAQ,GAE3B,EAAU;GAAC,MAAM,KAAQ;GAAU,OAAO;EAAQ,CAAC;CAEvD;CAEA,SAAS,EAAqB,GAAoB;EAChD,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,KAE7B,KACF,EAAiB,CAAQ,GAE3B,EAAU;GAAC,MAAM,KAAQ;GAAU,OAAO;EAAQ,CAAC;CAEvD;CA8BA,OA3BI,MAAS,WAET,kBAAC,GAAD;EACE,gBAAc;EACd,MAAK;EACL,OAAO,OAAO,KAAU,WAAW,IAAQ;EAC3C,eAAe;EACN;EACH;EACG;EACC;EACC;YAEV,EAAM,KAAK,MACV,kBAAC,GAAD;GAEE,OAAO,EAAK;GACZ,UAAU,EAAK;aAEd,EAAK;EACS,GALV,EAAK,KAKK,CAClB;CACY,CAAA,IAMjB,kBAAC,GAAD;EACE,gBAAc;EACd,MAAK;EACL,OAAO,MAAM,QAAQ,CAAK,IAAI,IAAQ,IAAQ,CAAC,CAAK,IAAI,CAAC;EACzD,eAAe;EACN;EACH;EACG;EACC;EACC;YAEV,EAAM,KAAK,MACV,kBAAC,GAAD;GAEE,OAAO,EAAK;GACZ,UAAU,EAAK;aAEd,EAAK;EACS,GALV,EAAK,KAKK,CAClB;CACY,CAAA;AAEnB"}
1
+ {"version":3,"file":"toggleGroup.component.js","names":[],"sources":["../../../src/cards/toggleGroup/toggleGroup.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {\n ToggleGroup as ToggleGroupUI,\n ToggleGroupItem,\n} from \"@/components/ui/toggle-group\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {\n PiToggleGroupEvents,\n PiToggleGroupProps,\n} from \"./toggleGroup.types\";\n\nexport const ToggleGroupComponent = (\n props: PiCardProps<PiToggleGroupProps, PiToggleGroupEvents>,\n): React.ReactNode => {\n const {\n name,\n items,\n type = \"single\",\n value: propValue,\n selfManaged = false,\n variant = \"default\",\n size = \"default\",\n spacing = 0,\n disabled,\n className,\n cardName,\n onChanged,\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 // ---------------------------------------------------------------------------\n // Self-managed (internal) state — only active when selfManaged=true and we\n // are NOT inside a pi/form card.\n // ---------------------------------------------------------------------------\n const initialSelfValue: string | string[] =\n type === \"multiple\"\n ? Array.isArray(propValue)\n ? propValue\n : propValue != null\n ? [String(propValue)]\n : []\n : typeof propValue === \"string\"\n ? propValue\n : \"\";\n\n const [internalValue, setInternalValue] = React.useState<string | string[]>(\n initialSelfValue,\n );\n\n // ---------------------------------------------------------------------------\n // Derive the effective value from the appropriate source.\n // 1. Form context (highest priority)\n // 2. Self-managed internal state\n // 3. Externally controlled prop value\n // ---------------------------------------------------------------------------\n const formRawValue = useFormData ? form.formData[name!] : undefined;\n const value: string | string[] = useFormData\n ? type === \"multiple\"\n ? Array.isArray(formRawValue)\n ? (formRawValue as string[])\n : formRawValue != null\n ? [String(formRawValue)]\n : []\n : formRawValue != null\n ? String(formRawValue)\n : \"\"\n : selfManaged\n ? internalValue\n : (propValue ?? (type === \"multiple\" ? [] : \"\"));\n\n function handleSingleChange(newValue: string) {\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n if (selfManaged) {\n setInternalValue(newValue);\n }\n onChanged({name: name ?? cardName, value: newValue});\n }\n }\n\n function handleMultipleChange(newValue: string[]) {\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n if (selfManaged) {\n setInternalValue(newValue);\n }\n onChanged({name: name ?? cardName, value: newValue});\n }\n }\n\n // Render single-selection group\n if (type === \"single\") {\n return (\n <ToggleGroupUI\n data-pihanga={cardName}\n type=\"single\"\n value={typeof value === \"string\" ? value : \"\"}\n onValueChange={handleSingleChange}\n variant={variant}\n size={size}\n spacing={spacing}\n disabled={disabled}\n className={className}\n >\n {items.map((item) => (\n <ToggleGroupItem\n key={item.value}\n value={item.value}\n disabled={item.disabled}\n >\n {item.label}\n </ToggleGroupItem>\n ))}\n </ToggleGroupUI>\n );\n }\n\n // Render multiple-selection group\n return (\n <ToggleGroupUI\n data-pihanga={cardName}\n type=\"multiple\"\n value={Array.isArray(value) ? value : value ? [value] : []}\n onValueChange={handleMultipleChange}\n variant={variant}\n size={size}\n spacing={spacing}\n disabled={disabled}\n className={className}\n >\n {items.map((item) => (\n <ToggleGroupItem\n key={item.value}\n value={item.value}\n disabled={item.disabled}\n >\n {item.label}\n </ToggleGroupItem>\n ))}\n </ToggleGroupUI>\n );\n};\n"],"mappings":";;;;;;AAYA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,UACA,UAAO,UACP,OAAO,GACP,iBAAc,IACd,aAAU,WACV,UAAO,WACP,aAAU,GACV,aACA,cACA,aACA,iBACE,GAGE,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAMvC,IACJ,MAAS,aACL,MAAM,QAAQ,CAAS,IACrB,IACA,KAAa,OAEX,CAAC,IADD,CAAC,OAAO,CAAS,CAAC,IAEtB,OAAO,KAAc,WACnB,IACA,IAEF,CAAC,GAAe,KAAoB,EAAM,SAC9C,CACF,GAQM,IAAe,IAAc,EAAK,SAAS,KAAS,KAAA,GACpD,IAA2B,IAC7B,MAAS,aACP,MAAM,QAAQ,CAAY,IACvB,IACD,KAAgB,OAEd,CAAC,IADD,CAAC,OAAO,CAAY,CAAC,IAEzB,KAAgB,OAEd,KADA,OAAO,CAAY,IAEvB,IACE,IACC,MAAc,MAAS,aAAa,CAAC,IAAI;CAEhD,SAAS,EAAmB,GAAkB;EAC5C,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,KAE7B,KACF,EAAiB,CAAQ,GAE3B,EAAU;GAAC,MAAM,KAAQ;GAAU,OAAO;EAAQ,CAAC;CAEvD;CAEA,SAAS,EAAqB,GAAoB;EAChD,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,KAE7B,KACF,EAAiB,CAAQ,GAE3B,EAAU;GAAC,MAAM,KAAQ;GAAU,OAAO;EAAQ,CAAC;CAEvD;CA8BA,OA3BI,MAAS,WAET,kBAAC,GAAD;EACE,gBAAc;EACd,MAAK;EACL,OAAO,OAAO,KAAU,WAAW,IAAQ;EAC3C,eAAe;EACN;EACH;EACG;EACC;EACC;YAEV,EAAM,KAAK,MACV,kBAAC,GAAD;GAEE,OAAO,EAAK;GACZ,UAAU,EAAK;aAEd,EAAK;EACS,GALV,EAAK,KAKK,CAClB;CACY,CAAA,IAMjB,kBAAC,GAAD;EACE,gBAAc;EACd,MAAK;EACL,OAAO,MAAM,QAAQ,CAAK,IAAI,IAAQ,IAAQ,CAAC,CAAK,IAAI,CAAC;EACzD,eAAe;EACN;EACH;EACG;EACC;EACC;YAEV,EAAM,KAAK,MACV,kBAAC,GAAD;GAEE,OAAO,EAAK;GACZ,UAAU,EAAK;aAEd,EAAK;EACS,GALV,EAAK,KAKK,CAClB;CACY,CAAA;AAEnB"}
@@ -3,6 +3,10 @@ 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 & {
7
+ cardID: string;
8
+ } & PiToggleGroupChangedEvent>) => void;
9
+ /** @deprecated Use `onToggleGroupChanged` instead. */
6
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 & {
7
11
  cardID: string;
8
12
  } & PiToggleGroupChangedEvent>) => void;
@@ -1,7 +1,7 @@
1
1
  import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
2
  //#region src/cards/toggleGroup/toggleGroup.types.ts
3
- var r = "pi/toggle-group", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED);
3
+ var r = "pi/toggle-group", i = e(r), a = n(r, ["changed"]), o = t(a.CHANGED), s = o;
4
4
  //#endregion
5
- export { a as PI_TOGGLE_GROUP_ACTION, r as PI_TOGGLE_GROUP_CARD, i as ToggleGroup, o as onPiToggleGroupChanged };
5
+ export { a as PI_TOGGLE_GROUP_ACTION, r as PI_TOGGLE_GROUP_CARD, i as ToggleGroup, s as onPiToggleGroupChanged, o as onToggleGroupChanged };
6
6
 
7
7
  //# sourceMappingURL=toggleGroup.types.js.map