@pihanga2/shadcn 0.2.6 → 0.2.8

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 (35) hide show
  1. package/AGENT.building-cards.md +118 -0
  2. package/README.md +3 -1
  3. package/cards/collapsibleCard/collapsibleCard.component.d.ts +4 -0
  4. package/cards/collapsibleCard/collapsibleCard.component.js +61 -0
  5. package/cards/collapsibleCard/collapsibleCard.component.js.map +1 -0
  6. package/cards/collapsibleCard/collapsibleCard.types.d.ts +91 -0
  7. package/cards/collapsibleCard/collapsibleCard.types.js +7 -0
  8. package/cards/collapsibleCard/collapsibleCard.types.js.map +1 -0
  9. package/cards/collapsibleCard/index.d.ts +1 -0
  10. package/cards/collapsibleCard/index.js +13 -0
  11. package/cards/collapsibleCard/index.js.map +1 -0
  12. package/cards/collapsibleCard.d.ts +1 -0
  13. package/cards/emptyCard/emptyCard.component.d.ts +4 -0
  14. package/cards/emptyCard/emptyCard.types.d.ts +36 -0
  15. package/cards/emptyCard/index.d.ts +1 -7
  16. package/cards/emptyCard.d.ts +1 -7
  17. package/cards/flexGrid/flexGrid.types.d.ts +1 -2
  18. package/cards/flexGrid/flexGrid.types.js.map +1 -1
  19. package/cards/graphin/eventDispatcher.component.d.ts +1 -0
  20. package/cards/infoCard/index.d.ts +1 -0
  21. package/cards/infoCard/index.js +12 -0
  22. package/cards/infoCard/index.js.map +1 -0
  23. package/cards/infoCard/infoCard.component.d.ts +4 -0
  24. package/cards/infoCard/infoCard.component.js +55 -0
  25. package/cards/infoCard/infoCard.component.js.map +1 -0
  26. package/cards/infoCard/infoCard.types.d.ts +65 -0
  27. package/cards/infoCard/infoCard.types.js +7 -0
  28. package/cards/infoCard/infoCard.types.js.map +1 -0
  29. package/cards/infoCard.d.ts +1 -0
  30. package/cards/toggleGroup/toggleGroup.component.js +1 -1
  31. package/cards/toggleGroup/toggleGroup.component.js.map +1 -1
  32. package/components/ui/card.js +50 -0
  33. package/components/ui/card.js.map +1 -0
  34. package/package.json +15 -1
  35. package/theme.css +102 -0
@@ -703,3 +703,121 @@ Rules:
703
703
  - `src/cards/BUILDING_CARDS_HOWTO.md` — human-oriented narrative version of this guide
704
704
  - `scripts/gen-card-dependencies.mjs` — dependency scanner
705
705
  - `scripts/gen-registry.mjs` — registry builder
706
+
707
+ ---
708
+
709
+ ## Theme-aware cards — working with CSS variables
710
+
711
+ shadcn/ui components (and therefore pihanga-shadcn cards built on top of them)
712
+ use **CSS custom properties** for all semantic colours, radii, and shadows.
713
+ Understanding the token system is essential for cards that carry their own
714
+ visual chrome (borders, backgrounds, elevation).
715
+
716
+ ### How the token system works
717
+
718
+ `src/theme.css` (shipped as `@pihanga2/shadcn/theme.css`) defines three layers:
719
+
720
+ | Layer | Purpose | Example |
721
+ |---|---|---|
722
+ | `:root { --card: oklch(...) }` | **Palette** — raw colour values | `--card`, `--border`, `--radius` |
723
+ | `@theme inline { --color-card: var(--card) }` | **Tailwind mapping** — wires vars to utility classes | `bg-card`, `border-border`, `rounded-xl` |
724
+ | `.dark { --card: oklch(...) }` | **Dark-mode overrides** | Same tokens, different values |
725
+
726
+ A consumer who overrides `:root { --card: oklch(0.9 0 0); }` in their own CSS
727
+ automatically rethemes every card that uses `bg-card` — no card code changes
728
+ needed.
729
+
730
+ ### Using theme tokens in a new card
731
+
732
+ **Prefer shadcn semantic tokens over hardcoded colours.** This makes the card
733
+ rethemable by the consumer:
734
+
735
+ ```tsx
736
+ // ✅ Rethemable — uses CSS variable tokens
737
+ <div className="bg-card text-card-foreground border border-border rounded-xl shadow-sm">
738
+
739
+ // ❌ Hard-wired — ignores consumer theme
740
+ <div className="bg-white text-gray-900 border border-gray-200 rounded-xl shadow-sm">
741
+ ```
742
+
743
+ Standard shadcn tokens available as Tailwind utilities:
744
+
745
+ | Tailwind class | CSS variable | Default (light) |
746
+ |---|---|---|
747
+ | `bg-card` | `--card` | white |
748
+ | `text-card-foreground` | `--card-foreground` | near-black |
749
+ | `bg-background` | `--background` | white |
750
+ | `text-foreground` | `--foreground` | near-black |
751
+ | `bg-muted` | `--muted` | light gray |
752
+ | `text-muted-foreground` | `--muted-foreground` | medium gray |
753
+ | `bg-primary` | `--primary` | dark |
754
+ | `text-primary-foreground` | `--primary-foreground` | near-white |
755
+ | `border-border` | `--border` | light gray |
756
+ | `rounded-xl` | `--radius-xl` = `--radius + 4px` | ~14px |
757
+ | `rounded-lg` | `--radius-lg` = `--radius` | 10px |
758
+ | `shadow-sm` | Tailwind built-in | subtle shadow |
759
+
760
+ ### Adding a new theme token for a card
761
+
762
+ When a card needs a design token consumers can override (e.g. a brand-specific
763
+ colour or radius), add it to **`src/theme.css`** following the same pattern:
764
+
765
+ ```css
766
+ /* In src/theme.css — @theme inline block */
767
+ @theme inline {
768
+ /* … existing tokens … */
769
+ --color-my-card-accent: var(--my-card-accent);
770
+ }
771
+
772
+ /* default in :root */
773
+ :root {
774
+ --my-card-accent: oklch(0.5 0.2 260); /* a blue */
775
+ }
776
+ ```
777
+
778
+ Then use `bg-my-card-accent` / `text-my-card-accent` in your component.
779
+ Consumers override by setting `--my-card-accent` in their own `:root`.
780
+
781
+ > **Do not** add tokens that are only useful for a single card to the global
782
+ > `theme.css`. For card-local defaults, prefer explicit Tailwind colour classes
783
+ > or a `className` prop.
784
+
785
+ ### The `@container` gotcha with shadcn composites
786
+
787
+ shadcn's `<CardHeader>` applies `@container/card-header`
788
+ (`container-type: inline-size`). CSS containment makes the element's
789
+ intrinsic inline size appear as **0** to its parent for `min-width` / `max-content`
790
+ calculations — your card will collapse to a tiny width if it relies on `min-w-max`.
791
+
792
+ **Fix:** replace `<CardHeader>` with a plain `<div data-slot="card-header">` that
793
+ carries the same Tailwind classes but without the `@container` prefix:
794
+
795
+ ```tsx
796
+ // ❌ @container breaks min-w-max on the parent Card
797
+ <CardHeader className={headerClassName}>
798
+
799
+ // ✅ Same visual styles, no CSS containment
800
+ <div
801
+ data-slot="card-header"
802
+ className={cn(
803
+ "grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6",
804
+ "has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
805
+ headerClassName,
806
+ )}
807
+ >
808
+ ```
809
+
810
+ This is safe because the `has-data-[slot=card-action]` selector is a CSS `:has()`
811
+ rule, not a container query — it doesn't require `@container` to function.
812
+
813
+ ### Consumer setup (reminder)
814
+
815
+ Cards in this library render correctly only when the consuming app's CSS
816
+ includes `@import "@pihanga2/shadcn/theme.css"`. That single import:
817
+
818
+ 1. Defines the CSS custom property palette (`:root`, `.dark`)
819
+ 2. Maps them to Tailwind v4 utility tokens (`@theme inline`)
820
+ 3. Tells Tailwind to scan the library's compiled files (`@source "."`)
821
+
822
+ Apps that already use shadcn/ui with their own theme setup do not need the
823
+ import — their `:root` variables cascade over the defaults.
package/README.md CHANGED
@@ -62,13 +62,14 @@ import "@pihanga2/shadcn/cards/dataTable";
62
62
 
63
63
  ---
64
64
 
65
- ## Included cards (39)
65
+ ## Included cards (41)
66
66
 
67
67
  - `avatar`
68
68
  - `badge`
69
69
  - `box`
70
70
  - `button`
71
71
  - `checkbox`
72
+ - `collapsibleCard`
72
73
  - `conditional`
73
74
  - `dataTable`
74
75
  - `dialog`
@@ -79,6 +80,7 @@ import "@pihanga2/shadcn/cards/dataTable";
79
80
  - `flexGrid`
80
81
  - `form`
81
82
  - `framework`
83
+ - `infoCard`
82
84
  - `input`
83
85
  - `jsonViewer`
84
86
  - `list`
@@ -0,0 +1,4 @@
1
+ import { PiCardProps } from '@pihanga2/core';
2
+ import { CollapsibleCardProps, CollapsibleCardEvents } from './collapsibleCard.types';
3
+ import * as React from "react";
4
+ export declare const CollapsibleCardComponent: (props: PiCardProps<CollapsibleCardProps, CollapsibleCardEvents>) => React.ReactNode;
@@ -0,0 +1,61 @@
1
+ import { getIcon as e } from "../icons.js";
2
+ import { cn as t } from "../../lib/utils.js";
3
+ import * as n from "react";
4
+ import { Card as r } from "@pihanga2/core";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ import * as o from "@radix-ui/react-collapsible";
7
+ import { ChevronsUpDown as s } from "lucide-react";
8
+ //#region src/cards/collapsibleCard/collapsibleCard.component.tsx
9
+ var c = {
10
+ h1: "scroll-m-20 text-4xl font-extrabold tracking-tight",
11
+ h2: "scroll-m-20 text-3xl font-semibold tracking-tight",
12
+ h3: "scroll-m-20 text-2xl font-semibold tracking-tight",
13
+ h4: "scroll-m-20 text-xl font-semibold tracking-tight",
14
+ p: "leading-7",
15
+ lead: "text-xl text-muted-foreground",
16
+ large: "text-lg font-semibold",
17
+ small: "text-sm font-medium leading-none",
18
+ muted: "text-sm text-muted-foreground"
19
+ }, l = (l) => {
20
+ let { title: u, titleLevel: d = "h4", titleCard: f, icon: p, contentCard: m, defaultOpen: h = !1, open: g, onOpenChanged: _, className: v, headerClassName: y, contentClassName: b, style: x, cardName: S } = l, [C, w] = n.useState(h), T = g === void 0 ? C : g;
21
+ function E(e) {
22
+ w(e), _?.({ open: e });
23
+ }
24
+ let D = p ? e(p) : /* @__PURE__ */ i(s, { className: "h-4 w-4" });
25
+ return /* @__PURE__ */ a(o.Root, {
26
+ open: T,
27
+ onOpenChange: E,
28
+ className: t("w-full", v),
29
+ style: x,
30
+ "data-pihanga": S,
31
+ children: [/* @__PURE__ */ a("div", {
32
+ className: t("flex items-center justify-between space-x-4 py-2", y),
33
+ children: [f ? /* @__PURE__ */ i(r, {
34
+ cardName: f,
35
+ parentCard: S
36
+ }) : /* @__PURE__ */ i("span", {
37
+ className: c[d],
38
+ children: u
39
+ }), /* @__PURE__ */ i(o.Trigger, {
40
+ asChild: !0,
41
+ children: /* @__PURE__ */ i("button", {
42
+ type: "button",
43
+ className: "shrink-0 rounded-sm p-1 transition-colors hover:bg-accent hover:text-accent-foreground",
44
+ "aria-expanded": T,
45
+ "aria-label": T ? "Collapse" : "Expand",
46
+ children: D
47
+ })
48
+ })]
49
+ }), /* @__PURE__ */ i(o.Content, {
50
+ className: t("overflow-hidden", b),
51
+ children: m && /* @__PURE__ */ i(r, {
52
+ cardName: m,
53
+ parentCard: S
54
+ })
55
+ })]
56
+ });
57
+ };
58
+ //#endregion
59
+ export { l as CollapsibleCardComponent };
60
+
61
+ //# sourceMappingURL=collapsibleCard.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapsibleCard.component.js","names":[],"sources":["../../../src/cards/collapsibleCard/collapsibleCard.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport * as CollapsiblePrimitive from \"@radix-ui/react-collapsible\";\nimport {ChevronsUpDown} from \"lucide-react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {cn} from \"@/lib/utils\";\nimport {getIcon} from \"@/cards/icons\";\nimport type {\n CollapsibleCardProps,\n CollapsibleCardEvents,\n CollapsibleTitleLevel,\n} from \"./collapsibleCard.types\";\n\nconst TITLE_CLASSES: Record<CollapsibleTitleLevel, string> = {\n h1: \"scroll-m-20 text-4xl font-extrabold tracking-tight\",\n h2: \"scroll-m-20 text-3xl font-semibold tracking-tight\",\n h3: \"scroll-m-20 text-2xl font-semibold tracking-tight\",\n h4: \"scroll-m-20 text-xl font-semibold tracking-tight\",\n p: \"leading-7\",\n lead: \"text-xl text-muted-foreground\",\n large: \"text-lg font-semibold\",\n small: \"text-sm font-medium leading-none\",\n muted: \"text-sm text-muted-foreground\",\n};\n\nexport const CollapsibleCardComponent = (\n props: PiCardProps<CollapsibleCardProps, CollapsibleCardEvents>,\n): React.ReactNode => {\n const {\n title,\n titleLevel = \"h4\",\n titleCard,\n icon,\n contentCard,\n defaultOpen = false,\n open,\n onOpenChanged,\n className,\n headerClassName,\n contentClassName,\n style,\n cardName,\n } = props;\n\n const [localOpen, setLocalOpen] = React.useState(defaultOpen);\n const openState = open !== undefined ? open : localOpen;\n\n function handleOpenChange(next: boolean): void {\n setLocalOpen(next);\n onOpenChanged?.({open: next});\n }\n\n const triggerIcon = icon ? (\n getIcon(icon)\n ) : (\n <ChevronsUpDown className=\"h-4 w-4\" />\n );\n\n return (\n <CollapsiblePrimitive.Root\n open={openState}\n onOpenChange={handleOpenChange}\n className={cn(\"w-full\", className)}\n style={style}\n data-pihanga={cardName}\n >\n <div\n className={cn(\n \"flex items-center justify-between space-x-4 py-2\",\n headerClassName,\n )}\n >\n {titleCard ? (\n <Card cardName={titleCard} parentCard={cardName} />\n ) : (\n <span className={TITLE_CLASSES[titleLevel]}>{title}</span>\n )}\n <CollapsiblePrimitive.Trigger asChild>\n <button\n type=\"button\"\n className=\"shrink-0 rounded-sm p-1 transition-colors hover:bg-accent hover:text-accent-foreground\"\n aria-expanded={openState}\n aria-label={openState ? \"Collapse\" : \"Expand\"}\n >\n {triggerIcon}\n </button>\n </CollapsiblePrimitive.Trigger>\n </div>\n <CollapsiblePrimitive.Content\n className={cn(\"overflow-hidden\", contentClassName)}\n >\n {contentCard && <Card cardName={contentCard} parentCard={cardName} />}\n </CollapsiblePrimitive.Content>\n </CollapsiblePrimitive.Root>\n );\n};\n"],"mappings":";;;;;;;;AAYA,IAAM,IAAuD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,GAAG;CACH,MAAM;CACN,OAAO;CACP,OAAO;CACP,OAAO;AACT,GAEa,KACX,MACoB;CACpB,IAAM,EACJ,UACA,gBAAa,MACb,cACA,SACA,gBACA,iBAAc,IACd,SACA,kBACA,cACA,oBACA,qBACA,UACA,gBACE,GAEE,CAAC,GAAW,KAAgB,EAAM,SAAS,CAAW,GACtD,IAAY,MAAS,KAAA,IAAmB,IAAP;CAEvC,SAAS,EAAiB,GAAqB;EAE7C,AADA,EAAa,CAAI,GACjB,IAAgB,EAAC,MAAM,EAAI,CAAC;CAC9B;CAEA,IAAM,IAAc,IAClB,EAAQ,CAAI,IAEZ,kBAAC,GAAD,EAAgB,WAAU,UAAW,CAAA;CAGvC,OACE,kBAAC,EAAqB,MAAtB;EACE,MAAM;EACN,cAAc;EACd,WAAW,EAAG,UAAU,CAAS;EAC1B;EACP,gBAAc;YALhB,CAOE,kBAAC,OAAD;GACE,WAAW,EACT,oDACA,CACF;aAJF,CAMG,IACC,kBAAC,GAAD;IAAM,UAAU;IAAW,YAAY;GAAW,CAAA,IAElD,kBAAC,QAAD;IAAM,WAAW,EAAc;cAAc;GAAY,CAAA,GAE3D,kBAAC,EAAqB,SAAtB;IAA8B,SAAA;cAC5B,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,iBAAe;KACf,cAAY,IAAY,aAAa;eAEpC;IACK,CAAA;GACoB,CAAA,CAC3B;MACL,kBAAC,EAAqB,SAAtB;GACE,WAAW,EAAG,mBAAmB,CAAgB;aAEhD,KAAe,kBAAC,GAAD;IAAM,UAAU;IAAa,YAAY;GAAW,CAAA;EACxC,CAAA,CACL;;AAE/B"}
@@ -0,0 +1,91 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ import { default as React } from 'react';
3
+ export declare const COLLAPSIBLE_CARD = "shad/collapsible";
4
+ export declare const COLLAPSIBLE_CARD_ACTION: {
5
+ OPENCHANGED: string;
6
+ };
7
+ export type CollapsibleCardOpenChangedEvent = {
8
+ open: boolean;
9
+ };
10
+ export declare const onCollapsibleCardOpenChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core').PiRegister, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
11
+ cardID: string;
12
+ } & CollapsibleCardOpenChangedEvent>) => void;
13
+ export type CollapsibleCardEvents = {
14
+ onOpenChanged: CollapsibleCardOpenChangedEvent;
15
+ };
16
+ /**
17
+ * Subset of shadcn/ui typography levels supported for the built-in title slot.
18
+ */
19
+ export type CollapsibleTitleLevel = "h1" | "h2" | "h3" | "h4" | "p" | "lead" | "large" | "small" | "muted";
20
+ export type CollapsibleCardProps = {
21
+ /**
22
+ * Plain-text title rendered in the trigger row using the built-in
23
+ * Typography styles. Use `titleCard` instead to supply a full Pihanga card.
24
+ */
25
+ title?: string;
26
+ /**
27
+ * Typography level applied to `title`.
28
+ * @default "h4"
29
+ */
30
+ titleLevel?: CollapsibleTitleLevel;
31
+ /**
32
+ * Alternative to `title` — any Pihanga card reference rendered as the
33
+ * header (e.g. a `shad/typography` or `shad/badge` card).
34
+ * When provided, `title` and `titleLevel` are ignored.
35
+ */
36
+ titleCard?: PiCardRef;
37
+ /**
38
+ * Icon name from the Pihanga icon registry, shown inside the toggle button.
39
+ * Falls back to the built-in `ChevronsUpDown` icon when omitted.
40
+ *
41
+ * @example
42
+ * import {registerIcon} from "@/cards/icons";
43
+ * import {ChevronDown} from "lucide-react";
44
+ * registerIcon("chevron-down", ChevronDown);
45
+ * CollapsibleCard({ icon: "chevron-down", ... });
46
+ */
47
+ icon?: string;
48
+ /**
49
+ * Pihanga card reference rendered inside the collapsible body.
50
+ */
51
+ contentCard?: PiCardRef;
52
+ /**
53
+ * Whether the panel is open on first render (uncontrolled mode).
54
+ * @default false
55
+ */
56
+ defaultOpen?: boolean;
57
+ /**
58
+ * Controlled open state. When provided, the component delegates all open
59
+ * state management to the consumer — update this via `onOpenChanged`.
60
+ */
61
+ open?: boolean;
62
+ /** CSS classes applied to the root `<div>`. */
63
+ className?: string;
64
+ /** CSS classes applied to the trigger row (title + toggle button). */
65
+ headerClassName?: string;
66
+ /** CSS classes applied to the collapsible content wrapper `<div>`. */
67
+ contentClassName?: string;
68
+ /** Inline styles on the root element. */
69
+ style?: React.CSSProperties;
70
+ };
71
+ /**
72
+ * Factory function for declaring a `shad/collapsible` card instance.
73
+ *
74
+ * ```ts
75
+ * import {registerCard} from "@pihanga2/core";
76
+ * import {CollapsibleCard} from "@/cards/collapsibleCard";
77
+ * import {Typography} from "@/cards/typography";
78
+ *
79
+ * registerCard("myApp/details", CollapsibleCard({
80
+ * title: "Advanced options",
81
+ * titleLevel: "h4",
82
+ * contentCard: "myApp/detailsBody",
83
+ * }));
84
+ *
85
+ * registerCard("myApp/detailsBody", Typography({
86
+ * text: "Hidden content revealed when expanded.",
87
+ * level: "p",
88
+ * }));
89
+ * ```
90
+ */
91
+ export declare const CollapsibleCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<CollapsibleCardProps, S, CollapsibleCardEvents>) => import('@pihanga2/core').PiCardDef;
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
2
+ //#region src/cards/collapsibleCard/collapsibleCard.types.ts
3
+ var r = "shad/collapsible", i = n(r, ["openChanged"]), a = t(i.OPENCHANGED), o = e(r);
4
+ //#endregion
5
+ export { r as COLLAPSIBLE_CARD, i as COLLAPSIBLE_CARD_ACTION, o as CollapsibleCard, a as onCollapsibleCardOpenChanged };
6
+
7
+ //# sourceMappingURL=collapsibleCard.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapsibleCard.types.js","names":[],"sources":["../../../src/cards/collapsibleCard/collapsibleCard.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n type PiCardRef,\n} from \"@pihanga2/core\";\nimport type React from \"react\";\n\nexport const COLLAPSIBLE_CARD = \"shad/collapsible\";\n\nexport const COLLAPSIBLE_CARD_ACTION = registerActions(COLLAPSIBLE_CARD, [\n \"openChanged\",\n]);\n\nexport type CollapsibleCardOpenChangedEvent = {open: boolean};\n\nexport const onCollapsibleCardOpenChanged =\n createOnAction<CollapsibleCardOpenChangedEvent>(\n COLLAPSIBLE_CARD_ACTION.OPENCHANGED,\n );\n\nexport type CollapsibleCardEvents = {\n onOpenChanged: CollapsibleCardOpenChangedEvent;\n};\n\n/**\n * Subset of shadcn/ui typography levels supported for the built-in title slot.\n */\nexport type CollapsibleTitleLevel =\n | \"h1\"\n | \"h2\"\n | \"h3\"\n | \"h4\"\n | \"p\"\n | \"lead\"\n | \"large\"\n | \"small\"\n | \"muted\";\n\nexport type CollapsibleCardProps = {\n /**\n * Plain-text title rendered in the trigger row using the built-in\n * Typography styles. Use `titleCard` instead to supply a full Pihanga card.\n */\n title?: string;\n\n /**\n * Typography level applied to `title`.\n * @default \"h4\"\n */\n titleLevel?: CollapsibleTitleLevel;\n\n /**\n * Alternative to `title` — any Pihanga card reference rendered as the\n * header (e.g. a `shad/typography` or `shad/badge` card).\n * When provided, `title` and `titleLevel` are ignored.\n */\n titleCard?: PiCardRef;\n\n /**\n * Icon name from the Pihanga icon registry, shown inside the toggle button.\n * Falls back to the built-in `ChevronsUpDown` icon when omitted.\n *\n * @example\n * import {registerIcon} from \"@/cards/icons\";\n * import {ChevronDown} from \"lucide-react\";\n * registerIcon(\"chevron-down\", ChevronDown);\n * CollapsibleCard({ icon: \"chevron-down\", ... });\n */\n icon?: string;\n\n /**\n * Pihanga card reference rendered inside the collapsible body.\n */\n contentCard?: PiCardRef;\n\n /**\n * Whether the panel is open on first render (uncontrolled mode).\n * @default false\n */\n defaultOpen?: boolean;\n\n /**\n * Controlled open state. When provided, the component delegates all open\n * state management to the consumer — update this via `onOpenChanged`.\n */\n open?: boolean;\n\n /** CSS classes applied to the root `<div>`. */\n className?: string;\n\n /** CSS classes applied to the trigger row (title + toggle button). */\n headerClassName?: string;\n\n /** CSS classes applied to the collapsible content wrapper `<div>`. */\n contentClassName?: string;\n\n /** Inline styles on the root element. */\n style?: React.CSSProperties;\n};\n\n/**\n * Factory function for declaring a `shad/collapsible` card instance.\n *\n * ```ts\n * import {registerCard} from \"@pihanga2/core\";\n * import {CollapsibleCard} from \"@/cards/collapsibleCard\";\n * import {Typography} from \"@/cards/typography\";\n *\n * registerCard(\"myApp/details\", CollapsibleCard({\n * title: \"Advanced options\",\n * titleLevel: \"h4\",\n * contentCard: \"myApp/detailsBody\",\n * }));\n *\n * registerCard(\"myApp/detailsBody\", Typography({\n * text: \"Hidden content revealed when expanded.\",\n * level: \"p\",\n * }));\n * ```\n */\nexport const CollapsibleCard = createCardDeclaration<\n CollapsibleCardProps,\n CollapsibleCardEvents\n>(COLLAPSIBLE_CARD);\n"],"mappings":";;AAQA,IAAa,IAAmB,oBAEnB,IAA0B,EAAgB,GAAkB,CACvE,aACF,CAAC,GAIY,IACX,EACE,EAAwB,WAC1B,GAsGW,IAAkB,EAG7B,CAAgB"}
@@ -0,0 +1 @@
1
+ export * from './collapsibleCard.types';
@@ -0,0 +1,13 @@
1
+ import { CollapsibleCardComponent as e } from "./collapsibleCard.component.js";
2
+ import { COLLAPSIBLE_CARD as t, COLLAPSIBLE_CARD_ACTION as n, CollapsibleCard as r, onCollapsibleCardOpenChanged as i } from "./collapsibleCard.types.js";
3
+ import { actionTypesToEvents as a, registerCardComponent as o } from "@pihanga2/core";
4
+ //#region src/cards/collapsibleCard/index.tsx
5
+ o({
6
+ name: t,
7
+ component: e,
8
+ events: a(n)
9
+ });
10
+ //#endregion
11
+ export { t as COLLAPSIBLE_CARD, n as COLLAPSIBLE_CARD_ACTION, r as CollapsibleCard, i as onCollapsibleCardOpenChanged };
12
+
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/collapsibleCard/index.tsx"],"sourcesContent":["import {actionTypesToEvents, registerCardComponent} from \"@pihanga2/core\";\n\nimport {CollapsibleCardComponent} from \"./collapsibleCard.component\";\nimport {\n COLLAPSIBLE_CARD,\n COLLAPSIBLE_CARD_ACTION,\n} from \"./collapsibleCard.types\";\n\nexport * from \"./collapsibleCard.types\";\n\nregisterCardComponent({\n name: COLLAPSIBLE_CARD,\n component: CollapsibleCardComponent,\n events: actionTypesToEvents(COLLAPSIBLE_CARD_ACTION),\n});\n"],"mappings":";;;;AAUA,EAAsB;CACpB,MAAM;CACN,WAAW;CACX,QAAQ,EAAoB,CAAuB;AACrD,CAAC"}
@@ -0,0 +1 @@
1
+ export * from './collapsibleCard/index';
@@ -0,0 +1,4 @@
1
+ import { PiCardProps } from '@pihanga2/core';
2
+ import { EmptyCardProps } from './emptyCard.types';
3
+ import * as React from "react";
4
+ export declare const EmptyCardComponent: (props: PiCardProps<EmptyCardProps>) => React.ReactNode;
@@ -0,0 +1,36 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ import { default as React } from 'react';
3
+ export declare const EMPTY_CARD = "empty-card";
4
+ export type EmptyCardProps = {
5
+ /**
6
+ * Icon name from the pihanga icon registry.
7
+ * When provided, renders an `EmptyMedia` slot with `variant="icon"`.
8
+ */
9
+ icon?: string;
10
+ /**
11
+ * Pihanga card reference rendered inside `EmptyContent`.
12
+ * Use this to show a call-to-action button, form, or any other card.
13
+ */
14
+ content?: PiCardRef;
15
+ /** Additional Tailwind / CSS classes forwarded to the root `Empty` element. */
16
+ className?: string;
17
+ /** Inline styles forwarded to the root `Empty` element. */
18
+ style?: React.CSSProperties;
19
+ };
20
+ /**
21
+ * Factory function for declaring an `empty-card` instance.
22
+ *
23
+ * ```ts
24
+ * import {registerCard} from "@pihanga2/core";
25
+ * import {EmptyCard} from "@/cards/emptyCard";
26
+ * import {Button} from "@/cards/button";
27
+ *
28
+ * registerCard("myApp/noResults", EmptyCard({
29
+ * icon: "search",
30
+ * content: "myApp/createButton",
31
+ * }));
32
+ *
33
+ * registerCard("myApp/createButton", Button({label: "Create new"}));
34
+ * ```
35
+ */
36
+ export declare const EmptyCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<EmptyCardProps, S, {}>) => import('@pihanga2/core').PiCardDef;
@@ -1,7 +1 @@
1
- import { PiCardProps } from '@pihanga2/core';
2
- import * as React from "react";
3
- export declare const EmptyCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<EmptyProps, S, {}>) => import('@pihanga2/core').PiCardDef;
4
- export type EmptyProps = {
5
- style?: React.CSSProperties;
6
- };
7
- export declare const EmptyComponent: (props: PiCardProps<EmptyProps>) => React.ReactNode;
1
+ export * from './emptyCard.types';
@@ -1,7 +1 @@
1
- import { PiCardProps } from '@pihanga2/core';
2
- import * as React from "react";
3
- export declare const EmptyCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<EmptyProps, S, {}>) => import('@pihanga2/core').PiCardDef;
4
- export type EmptyProps = {
5
- style?: React.CSSProperties;
6
- };
7
- export declare const EmptyComponent: (props: PiCardProps<EmptyProps>) => React.ReactNode;
1
+ export * from './emptyCard/index';
@@ -1,9 +1,8 @@
1
- import { PiCardRef } from '@pihanga2/core';
2
1
  export declare const FLEX_GRID_CARD = "flex_grid";
3
2
  export declare const FlexGrid: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<FlexGridProps, S, {}>) => import('@pihanga2/core').PiCardDef;
4
3
  export type FlexGridProps = {
5
4
  cards: {
6
- [name: string]: PiCardRef;
5
+ [name: string]: string;
7
6
  };
8
7
  template: TemplateT;
9
8
  height?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"flexGrid.types.js","names":[],"sources":["../../../src/cards/flexGrid/flexGrid.types.ts"],"sourcesContent":["import {createCardDeclaration, type PiCardRef} from \"@pihanga2/core\";\n\nexport const FLEX_GRID_CARD = \"flex_grid\";\nexport const FlexGrid = createCardDeclaration<FlexGridProps>(FLEX_GRID_CARD);\n\nexport type FlexGridProps = {\n cards: {[name: string]: PiCardRef};\n template: TemplateT;\n height?: string;\n margin?: string;\n overflow?: string;\n\n style?: {\n root?: React.CSSProperties;\n item?: React.CSSProperties;\n };\n className?: string;\n};\n\n// body {\n// display: grid;\n// grid-template-areas:\n// \"header header header\"\n// \"nav article ads\"\n// \"footer footer footer\";\n// grid-template-rows: 60px 1fr 60px;\n// grid-template-columns: 20% 1fr 15%;\n// grid-gap: 10px;\n// height: 100vh;\n// margin: 0;\n// }\n\n// https://css-tricks.com/snippets/css/complete-guide-grid/\nexport type TemplateT = {\n area?: string[][]; // name of card dict\n rows?: string[]; // grid-template-rows (e.g [\"min-content\", \"1fr\", \"min-content\"])\n columns?: string[]; // grid-template-cols (e.g. [\"1fr\", \"50px\", \"1fr\", \"1fr\"])\n gap?: string;\n};\n"],"mappings":";;AAEA,IAAa,IAAiB,aACjB,IAAW,EAAqC,CAAc"}
1
+ {"version":3,"file":"flexGrid.types.js","names":[],"sources":["../../../src/cards/flexGrid/flexGrid.types.ts"],"sourcesContent":["import {createCardDeclaration} from \"@pihanga2/core\";\n\nexport const FLEX_GRID_CARD = \"flex_grid\";\nexport const FlexGrid = createCardDeclaration<FlexGridProps>(FLEX_GRID_CARD);\n\nexport type FlexGridProps = {\n cards: {[name: string]: string}; // anonymous cards are not supported\n template: TemplateT;\n height?: string;\n margin?: string;\n overflow?: string;\n\n style?: {\n root?: React.CSSProperties;\n item?: React.CSSProperties;\n };\n className?: string;\n};\n\n// body {\n// display: grid;\n// grid-template-areas:\n// \"header header header\"\n// \"nav article ads\"\n// \"footer footer footer\";\n// grid-template-rows: 60px 1fr 60px;\n// grid-template-columns: 20% 1fr 15%;\n// grid-gap: 10px;\n// height: 100vh;\n// margin: 0;\n// }\n\n// https://css-tricks.com/snippets/css/complete-guide-grid/\nexport type TemplateT = {\n area?: string[][]; // name of card dict\n rows?: string[]; // grid-template-rows (e.g [\"min-content\", \"1fr\", \"min-content\"])\n columns?: string[]; // grid-template-cols (e.g. [\"1fr\", \"50px\", \"1fr\", \"1fr\"])\n gap?: string;\n};\n"],"mappings":";;AAEA,IAAa,IAAiB,aACjB,IAAW,EAAqC,CAAc"}
@@ -1,5 +1,6 @@
1
1
  import { GraphinAfterLayoutContext, GraphinNodeEventContext } from './graphin.types';
2
2
  export type GraphinEventDispatcherProps = {
3
+ cardName: string;
3
4
  onNodeHovered?: (ctx: GraphinNodeEventContext) => void;
4
5
  onNodeHoverEnd?: (ctx: GraphinNodeEventContext) => void;
5
6
  onNodeClicked?: (ctx: GraphinNodeEventContext) => void;
@@ -0,0 +1 @@
1
+ export * from './infoCard.types';
@@ -0,0 +1,12 @@
1
+ import { InfoCardComponent as e } from "./infoCard.component.js";
2
+ import { INFO_CARD as t, InfoCard as n } from "./infoCard.types.js";
3
+ import { registerCardComponent as r } from "@pihanga2/core";
4
+ //#region src/cards/infoCard/index.tsx
5
+ r({
6
+ name: t,
7
+ component: e
8
+ });
9
+ //#endregion
10
+ export { t as INFO_CARD, n as InfoCard };
11
+
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/infoCard/index.tsx"],"sourcesContent":["import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {InfoCardComponent} from \"./infoCard.component\";\nimport {INFO_CARD} from \"./infoCard.types\";\n\nexport * from \"./infoCard.types\";\n\nregisterCardComponent({\n name: INFO_CARD,\n component: InfoCardComponent,\n});\n"],"mappings":";;;;AAOA,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { PiCardProps } from '@pihanga2/core';
2
+ import { InfoCardProps } from './infoCard.types';
3
+ import * as React from "react";
4
+ export declare const InfoCardComponent: (props: PiCardProps<InfoCardProps>) => React.ReactNode;
@@ -0,0 +1,55 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import { Card as t, CardAction as n, CardContent as r, CardDescription as i, CardFooter as a, CardTitle as o } from "../../components/ui/card.js";
3
+ import "react";
4
+ import { Card as s } from "@pihanga2/core";
5
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
+ //#region src/cards/infoCard/infoCard.component.tsx
7
+ var u = (u) => {
8
+ let { title: d, description: f, actionCard: p, contentCard: m, footerCard: h, className: g, headerClassName: _, titleClassName: v, descriptionClassName: y, actionClassName: b, contentClassName: x, footerClassName: S, style: C, cardName: w } = u, T = d || f || p;
9
+ return /* @__PURE__ */ l(t, {
10
+ className: e("min-w-max", g),
11
+ style: C,
12
+ "data-pihanga": w,
13
+ children: [
14
+ T && /* @__PURE__ */ l("div", {
15
+ "data-slot": "card-header",
16
+ className: e("grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6", "has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", _),
17
+ children: [
18
+ d && /* @__PURE__ */ c(o, {
19
+ className: v,
20
+ children: d
21
+ }),
22
+ f && /* @__PURE__ */ c(i, {
23
+ className: y,
24
+ children: f
25
+ }),
26
+ p && /* @__PURE__ */ c(n, {
27
+ className: b,
28
+ children: /* @__PURE__ */ c(s, {
29
+ cardName: p,
30
+ parentCard: w
31
+ })
32
+ })
33
+ ]
34
+ }),
35
+ m && /* @__PURE__ */ c(r, {
36
+ className: x,
37
+ children: /* @__PURE__ */ c(s, {
38
+ cardName: m,
39
+ parentCard: w
40
+ })
41
+ }),
42
+ h && /* @__PURE__ */ c(a, {
43
+ className: S,
44
+ children: /* @__PURE__ */ c(s, {
45
+ cardName: h,
46
+ parentCard: w
47
+ })
48
+ })
49
+ ]
50
+ });
51
+ };
52
+ //#endregion
53
+ export { u as InfoCardComponent };
54
+
55
+ //# sourceMappingURL=infoCard.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infoCard.component.js","names":[],"sources":["../../../src/cards/infoCard/infoCard.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {Card as PiCard, type PiCardProps} from \"@pihanga2/core\";\nimport {cn} from \"@/lib/utils\";\nimport {\n Card,\n CardTitle,\n CardDescription,\n CardAction,\n CardContent,\n CardFooter,\n} from \"@/components/ui/card\";\nimport type {InfoCardProps} from \"./infoCard.types\";\n\nexport const InfoCardComponent = (\n props: PiCardProps<InfoCardProps>,\n): React.ReactNode => {\n const {\n title,\n description,\n actionCard,\n contentCard,\n footerCard,\n className,\n headerClassName,\n titleClassName,\n descriptionClassName,\n actionClassName,\n contentClassName,\n footerClassName,\n style,\n cardName,\n } = props;\n\n const hasHeader = title || description || actionCard;\n\n return (\n <Card\n className={cn(\"min-w-max\", className)}\n style={style}\n data-pihanga={cardName}\n >\n {hasHeader && (\n // Plain <div> instead of shadcn <CardHeader> — avoids @container/card-header\n // (container-type:inline-size) which zeroes out intrinsic inline size and\n // breaks min-w-max on the parent Card. Visual classes are identical.\n <div\n data-slot=\"card-header\"\n className={cn(\n \"grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6\",\n \"has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n headerClassName,\n )}\n >\n {title && <CardTitle className={titleClassName}>{title}</CardTitle>}\n {description && (\n <CardDescription className={descriptionClassName}>\n {description}\n </CardDescription>\n )}\n {actionCard && (\n <CardAction className={actionClassName}>\n <PiCard cardName={actionCard} parentCard={cardName} />\n </CardAction>\n )}\n </div>\n )}\n {contentCard && (\n <CardContent className={contentClassName}>\n <PiCard cardName={contentCard} parentCard={cardName} />\n </CardContent>\n )}\n {footerCard && (\n <CardFooter className={footerClassName}>\n <PiCard cardName={footerCard} parentCard={cardName} />\n </CardFooter>\n )}\n </Card>\n );\n};\n"],"mappings":";;;;;;AAaA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,UACA,gBACA,eACA,gBACA,eACA,cACA,oBACA,mBACA,yBACA,oBACA,qBACA,oBACA,UACA,gBACE,GAEE,IAAY,KAAS,KAAe;CAE1C,OACE,kBAAC,GAAD;EACE,WAAW,EAAG,aAAa,CAAS;EAC7B;EACP,gBAAc;YAHhB;GAKG,KAIC,kBAAC,OAAD;IACE,aAAU;IACV,WAAW,EACT,mEACA,qEACA,CACF;cANF;KAQG,KAAS,kBAAC,GAAD;MAAW,WAAW;gBAAiB;KAAiB,CAAA;KACjE,KACC,kBAAC,GAAD;MAAiB,WAAW;gBACzB;KACc,CAAA;KAElB,KACC,kBAAC,GAAD;MAAY,WAAW;gBACrB,kBAAC,GAAD;OAAQ,UAAU;OAAY,YAAY;MAAW,CAAA;KAC3C,CAAA;IAEX;;GAEN,KACC,kBAAC,GAAD;IAAa,WAAW;cACtB,kBAAC,GAAD;KAAQ,UAAU;KAAa,YAAY;IAAW,CAAA;GAC3C,CAAA;GAEd,KACC,kBAAC,GAAD;IAAY,WAAW;cACrB,kBAAC,GAAD;KAAQ,UAAU;KAAY,YAAY;IAAW,CAAA;GAC3C,CAAA;EAEV;;AAEV"}
@@ -0,0 +1,65 @@
1
+ import { PiCardRef } from '@pihanga2/core';
2
+ import { default as React } from 'react';
3
+ export declare const INFO_CARD = "shad/info-card";
4
+ export type InfoCardProps = {
5
+ /**
6
+ * Text rendered inside `CardTitle`.
7
+ * Leave unset to omit the title element entirely.
8
+ */
9
+ title?: string;
10
+ /**
11
+ * Text rendered inside `CardDescription`.
12
+ * Leave unset to omit the description element entirely.
13
+ */
14
+ description?: string;
15
+ /**
16
+ * Pihanga card reference rendered inside the `CardAction` slot.
17
+ * Positioned at the top-right of the header (e.g. a button, badge, or icon).
18
+ */
19
+ actionCard?: PiCardRef;
20
+ /**
21
+ * Pihanga card reference rendered inside `CardContent`.
22
+ * Main body of the card — use any layout or display card.
23
+ */
24
+ contentCard?: PiCardRef;
25
+ /**
26
+ * Pihanga card reference rendered inside `CardFooter`.
27
+ * Typically a row of actions or a status line.
28
+ */
29
+ footerCard?: PiCardRef;
30
+ /** Extra CSS classes applied to the root `<div data-slot="card">`. */
31
+ className?: string;
32
+ /** Extra CSS classes applied to `<div data-slot="card-header">`. */
33
+ headerClassName?: string;
34
+ /** Extra CSS classes applied to `<div data-slot="card-title">`. */
35
+ titleClassName?: string;
36
+ /** Extra CSS classes applied to `<div data-slot="card-description">`. */
37
+ descriptionClassName?: string;
38
+ /** Extra CSS classes applied to `<div data-slot="card-action">`. */
39
+ actionClassName?: string;
40
+ /** Extra CSS classes applied to `<div data-slot="card-content">`. */
41
+ contentClassName?: string;
42
+ /** Extra CSS classes applied to `<div data-slot="card-footer">`. */
43
+ footerClassName?: string;
44
+ /** Inline styles applied to the root card element. */
45
+ style?: React.CSSProperties;
46
+ };
47
+ /**
48
+ * Factory function for declaring a `shad/info-card` instance.
49
+ *
50
+ * ```ts
51
+ * import {registerCard} from "@pihanga2/core";
52
+ * import {InfoCard} from "@/cards/infoCard";
53
+ * import {Typography} from "@/cards/typography";
54
+ * import {Button} from "@/cards/button";
55
+ *
56
+ * registerCard("myApp/userCard", InfoCard({
57
+ * title: "John Doe",
58
+ * description: "Software Engineer",
59
+ * actionCard: "myApp/editButton",
60
+ * contentCard: "myApp/userDetails",
61
+ * footerCard: "myApp/userActions",
62
+ * }));
63
+ * ```
64
+ */
65
+ export declare const InfoCard: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<InfoCardProps, S, {}>) => import('@pihanga2/core').PiCardDef;
@@ -0,0 +1,7 @@
1
+ import { createCardDeclaration as e } from "@pihanga2/core";
2
+ //#region src/cards/infoCard/infoCard.types.ts
3
+ var t = "shad/info-card", n = e(t);
4
+ //#endregion
5
+ export { t as INFO_CARD, n as InfoCard };
6
+
7
+ //# sourceMappingURL=infoCard.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infoCard.types.js","names":[],"sources":["../../../src/cards/infoCard/infoCard.types.ts"],"sourcesContent":["import {createCardDeclaration, type PiCardRef} from \"@pihanga2/core\";\nimport type React from \"react\";\n\nexport const INFO_CARD = \"shad/info-card\";\n\nexport type InfoCardProps = {\n /**\n * Text rendered inside `CardTitle`.\n * Leave unset to omit the title element entirely.\n */\n title?: string;\n\n /**\n * Text rendered inside `CardDescription`.\n * Leave unset to omit the description element entirely.\n */\n description?: string;\n\n /**\n * Pihanga card reference rendered inside the `CardAction` slot.\n * Positioned at the top-right of the header (e.g. a button, badge, or icon).\n */\n actionCard?: PiCardRef;\n\n /**\n * Pihanga card reference rendered inside `CardContent`.\n * Main body of the card — use any layout or display card.\n */\n contentCard?: PiCardRef;\n\n /**\n * Pihanga card reference rendered inside `CardFooter`.\n * Typically a row of actions or a status line.\n */\n footerCard?: PiCardRef;\n\n // ── Per-element className overrides ────────────────────────────────────────\n\n /** Extra CSS classes applied to the root `<div data-slot=\"card\">`. */\n className?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-header\">`. */\n headerClassName?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-title\">`. */\n titleClassName?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-description\">`. */\n descriptionClassName?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-action\">`. */\n actionClassName?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-content\">`. */\n contentClassName?: string;\n\n /** Extra CSS classes applied to `<div data-slot=\"card-footer\">`. */\n footerClassName?: string;\n\n /** Inline styles applied to the root card element. */\n style?: React.CSSProperties;\n};\n\n/**\n * Factory function for declaring a `shad/info-card` instance.\n *\n * ```ts\n * import {registerCard} from \"@pihanga2/core\";\n * import {InfoCard} from \"@/cards/infoCard\";\n * import {Typography} from \"@/cards/typography\";\n * import {Button} from \"@/cards/button\";\n *\n * registerCard(\"myApp/userCard\", InfoCard({\n * title: \"John Doe\",\n * description: \"Software Engineer\",\n * actionCard: \"myApp/editButton\",\n * contentCard: \"myApp/userDetails\",\n * footerCard: \"myApp/userActions\",\n * }));\n * ```\n */\nexport const InfoCard = createCardDeclaration<InfoCardProps>(INFO_CARD);\n"],"mappings":";;AAGA,IAAa,IAAY,kBA8EZ,IAAW,EAAqC,CAAS"}
@@ -0,0 +1 @@
1
+ export * from './infoCard/index';
@@ -5,7 +5,7 @@ import "@pihanga2/core";
5
5
  import { jsx as i } from "react/jsx-runtime";
6
6
  //#region src/cards/toggleGroup/toggleGroup.component.tsx
7
7
  var a = (a) => {
8
- let { name: o, items: s, type: c = "single", value: l, selfManaged: u = !1, variant: d = "default", size: f = "default", spacing: p = 0, disabled: m, className: h, cardName: g, onChanged: _ } = a, v = e(), y = v.isInForm && !!o, b = c === "multiple" ? Array.isArray(l) ? l : l == null ? [] : [String(l)] : typeof l == "string" ? l : "", [x, S] = r.useState(b), C = y ? v.formData[o] : void 0, w = y ? c === "multiple" ? Array.isArray(C) ? C : C == null ? [] : [String(C)] : C == null ? "" : String(C) : u ? x : l ?? (c === "multiple" ? [] : "");
8
+ let { name: o, items: s = [], type: c = "single", value: l, selfManaged: u = !1, variant: d = "default", size: f = "default", spacing: p = 0, disabled: m, className: h, cardName: g, onChanged: _ } = a, v = e(), y = v.isInForm && !!o, b = c === "multiple" ? Array.isArray(l) ? l : l == null ? [] : [String(l)] : typeof l == "string" ? l : "", [x, S] = r.useState(b), C = y ? v.formData[o] : void 0, w = y ? c === "multiple" ? Array.isArray(C) ? C : C == null ? [] : [String(C)] : C == null ? "" : String(C) : u ? x : l ?? (c === "multiple" ? [] : "");
9
9
  function T(e) {
10
10
  y ? v.handleChange(o, e) : (u && S(e), _({
11
11
  name: o ?? g,
@@ -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,WAAQ,CAAC,GACT,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"}
@@ -0,0 +1,50 @@
1
+ import { cn as e } from "../../lib/utils.js";
2
+ import "react";
3
+ import { jsx as t } from "react/jsx-runtime";
4
+ //#region src/components/ui/card.tsx
5
+ function n({ className: n, ...r }) {
6
+ return /* @__PURE__ */ t("div", {
7
+ "data-slot": "card",
8
+ className: e("flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm", n),
9
+ ...r
10
+ });
11
+ }
12
+ function r({ className: n, ...r }) {
13
+ return /* @__PURE__ */ t("div", {
14
+ "data-slot": "card-title",
15
+ className: e("leading-none font-semibold", n),
16
+ ...r
17
+ });
18
+ }
19
+ function i({ className: n, ...r }) {
20
+ return /* @__PURE__ */ t("div", {
21
+ "data-slot": "card-description",
22
+ className: e("text-sm text-muted-foreground", n),
23
+ ...r
24
+ });
25
+ }
26
+ function a({ className: n, ...r }) {
27
+ return /* @__PURE__ */ t("div", {
28
+ "data-slot": "card-action",
29
+ className: e("col-start-2 row-span-2 row-start-1 self-start justify-self-end", n),
30
+ ...r
31
+ });
32
+ }
33
+ function o({ className: n, ...r }) {
34
+ return /* @__PURE__ */ t("div", {
35
+ "data-slot": "card-content",
36
+ className: e("px-6", n),
37
+ ...r
38
+ });
39
+ }
40
+ function s({ className: n, ...r }) {
41
+ return /* @__PURE__ */ t("div", {
42
+ "data-slot": "card-footer",
43
+ className: e("flex items-center px-6 [.border-t]:pt-6", n),
44
+ ...r
45
+ });
46
+ }
47
+ //#endregion
48
+ export { n as Card, a as CardAction, o as CardContent, i as CardDescription, s as CardFooter, r as CardTitle };
49
+
50
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","names":[],"sources":["../../../src/components/ui/card.tsx"],"sourcesContent":["import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Card({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card\"\n className={cn(\n \"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn(\"leading-none font-semibold\", className)}\n {...props}\n />\n )\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn(\n \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-content\"\n className={cn(\"px-6\", className)}\n {...props}\n />\n )\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn(\"flex items-center px-6 [.border-t]:pt-6\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Card,\n CardHeader,\n CardFooter,\n CardTitle,\n CardAction,\n CardDescription,\n CardContent,\n}\n"],"mappings":";;;;AAIA,SAAS,EAAK,EAAE,cAAW,GAAG,KAAsC;CAClE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,qFACA,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAeA,SAAS,EAAU,EAAE,cAAW,GAAG,KAAsC;CACvE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,8BAA8B,CAAS;EACrD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAgB,EAAE,cAAW,GAAG,KAAsC;CAC7E,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,iCAAiC,CAAS;EACxD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAAE,cAAW,GAAG,KAAsC;CACxE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EACT,kEACA,CACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAY,EAAE,cAAW,GAAG,KAAsC;CACzE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,QAAQ,CAAS;EAC/B,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,EAAW,EAAE,cAAW,GAAG,KAAsC;CACxE,OACE,kBAAC,OAAD;EACE,aAAU;EACV,WAAW,EAAG,2CAA2C,CAAS;EAClE,GAAI;CACL,CAAA;AAEL"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pihanga2/shadcn",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Pihanga core card components built on shadcn/ui and Radix UI — the npm distribution of pihanga-shadcn.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -24,6 +24,10 @@
24
24
  "import": "./cards/checkbox/index.js",
25
25
  "types": "./cards/checkbox/index.d.ts"
26
26
  },
27
+ "./cards/collapsibleCard": {
28
+ "import": "./cards/collapsibleCard/index.js",
29
+ "types": "./cards/collapsibleCard/index.d.ts"
30
+ },
27
31
  "./cards/conditional": {
28
32
  "import": "./cards/conditional/index.js",
29
33
  "types": "./cards/conditional/index.d.ts"
@@ -64,6 +68,10 @@
64
68
  "import": "./cards/framework/index.js",
65
69
  "types": "./cards/framework/index.d.ts"
66
70
  },
71
+ "./cards/infoCard": {
72
+ "import": "./cards/infoCard/index.js",
73
+ "types": "./cards/infoCard/index.d.ts"
74
+ },
67
75
  "./cards/input": {
68
76
  "import": "./cards/input/index.js",
69
77
  "types": "./cards/input/index.d.ts"
@@ -171,6 +179,9 @@
171
179
  "./lib/utils": {
172
180
  "import": "./lib/utils.js",
173
181
  "types": "./lib/utils.d.ts"
182
+ },
183
+ "./theme": {
184
+ "import": "./theme.css"
174
185
  }
175
186
  },
176
187
  "sideEffects": [
@@ -179,6 +190,7 @@
179
190
  "./cards/box/index.js",
180
191
  "./cards/button/index.js",
181
192
  "./cards/checkbox/index.js",
193
+ "./cards/collapsibleCard/index.js",
182
194
  "./cards/conditional/index.js",
183
195
  "./cards/dataTable/index.js",
184
196
  "./cards/dialog/index.js",
@@ -189,6 +201,7 @@
189
201
  "./cards/flexGrid/index.js",
190
202
  "./cards/form/index.js",
191
203
  "./cards/framework/index.js",
204
+ "./cards/infoCard/index.js",
192
205
  "./cards/input/index.js",
193
206
  "./cards/jsonViewer/index.js",
194
207
  "./cards/list/index.js",
@@ -236,6 +249,7 @@
236
249
  "@pihanga2/cards": "*"
237
250
  },
238
251
  "dependencies": {
252
+ "@radix-ui/react-collapsible": "^1.1.20",
239
253
  "@radix-ui/react-dialog": "^1.1.15",
240
254
  "@radix-ui/react-dropdown-menu": "^2.1.16",
241
255
  "@radix-ui/react-menubar": "^1.1.16",
package/theme.css ADDED
@@ -0,0 +1,102 @@
1
+ /*
2
+ * pihanga-shadcn — theme.css
3
+ *
4
+ * Add ONE line to your app's main CSS (processed by Tailwind v4):
5
+ *
6
+ * @import "tailwindcss";
7
+ * @import "@pihanga2/shadcn/theme.css";
8
+ *
9
+ * The @source directive below tells Tailwind to scan this package's
10
+ * compiled JS files for utility class names, so you don't need a
11
+ * separate @source line in your own CSS.
12
+ *
13
+ * Skip the import if your app already has a shadcn/ui theme — your
14
+ * :root variables will take precedence over the defaults below.
15
+ */
16
+
17
+ /* Scan this package's compiled files for Tailwind utility classes */
18
+ @source ".";
19
+
20
+ /* Map shadcn CSS vars to Tailwind v4 utility tokens */
21
+ @theme inline {
22
+ --color-background: var(--background);
23
+ --color-foreground: var(--foreground);
24
+ --color-card: var(--card);
25
+ --color-card-foreground: var(--card-foreground);
26
+ --color-popover: var(--popover);
27
+ --color-popover-foreground: var(--popover-foreground);
28
+ --color-primary: var(--primary);
29
+ --color-primary-foreground: var(--primary-foreground);
30
+ --color-secondary: var(--secondary);
31
+ --color-secondary-foreground: var(--secondary-foreground);
32
+ --color-muted: var(--muted);
33
+ --color-muted-foreground: var(--muted-foreground);
34
+ --color-accent: var(--accent);
35
+ --color-accent-foreground: var(--accent-foreground);
36
+ --color-destructive: var(--destructive);
37
+ --color-border: var(--border);
38
+ --color-input: var(--input);
39
+ --color-ring: var(--ring);
40
+ --radius-sm: calc(var(--radius) - 4px);
41
+ --radius-md: calc(var(--radius) - 2px);
42
+ --radius-lg: var(--radius);
43
+ --radius-xl: calc(var(--radius) + 4px);
44
+ --color-btn-brand: var(--primary);
45
+ --color-btn-brand-foreground: var(--primary-foreground);
46
+ --radius-btn-brand: var(--radius-md);
47
+ }
48
+
49
+ /* Light theme (shadcn neutral / new-york) */
50
+ :root {
51
+ --background: oklch(1 0 0);
52
+ --foreground: oklch(0.145 0 0);
53
+ --card: oklch(1 0 0);
54
+ --card-foreground: oklch(0.145 0 0);
55
+ --popover: oklch(1 0 0);
56
+ --popover-foreground: oklch(0.145 0 0);
57
+ --primary: oklch(0.205 0 0);
58
+ --primary-foreground: oklch(0.985 0 0);
59
+ --secondary: oklch(0.97 0 0);
60
+ --secondary-foreground: oklch(0.205 0 0);
61
+ --muted: oklch(0.97 0 0);
62
+ --muted-foreground: oklch(0.556 0 0);
63
+ --accent: oklch(0.97 0 0);
64
+ --accent-foreground: oklch(0.205 0 0);
65
+ --destructive: oklch(0.577 0.245 27.325);
66
+ --border: oklch(0.922 0 0);
67
+ --input: oklch(0.922 0 0);
68
+ --ring: oklch(0.708 0 0);
69
+ --radius: 0.625rem;
70
+ --chart-1: oklch(0.646 0.222 41.116);
71
+ --chart-2: oklch(0.6 0.118 184.704);
72
+ --chart-3: oklch(0.398 0.07 227.392);
73
+ --chart-4: oklch(0.828 0.189 84.429);
74
+ --chart-5: oklch(0.769 0.188 70.08);
75
+ }
76
+
77
+ /* Dark theme */
78
+ .dark {
79
+ --background: oklch(0.145 0 0);
80
+ --foreground: oklch(0.985 0 0);
81
+ --card: oklch(0.205 0 0);
82
+ --card-foreground: oklch(0.985 0 0);
83
+ --popover: oklch(0.205 0 0);
84
+ --popover-foreground: oklch(0.985 0 0);
85
+ --primary: oklch(0.922 0 0);
86
+ --primary-foreground: oklch(0.205 0 0);
87
+ --secondary: oklch(0.269 0 0);
88
+ --secondary-foreground: oklch(0.985 0 0);
89
+ --muted: oklch(0.269 0 0);
90
+ --muted-foreground: oklch(0.708 0 0);
91
+ --accent: oklch(0.269 0 0);
92
+ --accent-foreground: oklch(0.985 0 0);
93
+ --destructive: oklch(0.704 0.191 22.216);
94
+ --border: oklch(1 0 0 / 10%);
95
+ --input: oklch(1 0 0 / 15%);
96
+ --ring: oklch(0.556 0 0);
97
+ --chart-1: oklch(0.488 0.243 264.376);
98
+ --chart-2: oklch(0.696 0.17 162.48);
99
+ --chart-3: oklch(0.769 0.188 70.08);
100
+ --chart-4: oklch(0.627 0.265 303.9);
101
+ --chart-5: oklch(0.645 0.246 16.439);
102
+ }