@pihanga2/shadcn 0.2.20 → 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENT.using-cards.md +2 -2
- package/README.md +4 -1
- package/cards/attachment/attachment.component.d.ts +4 -0
- package/cards/attachment/attachment.component.js +46 -0
- package/cards/attachment/attachment.component.js.map +1 -0
- package/cards/attachment/attachment.types.d.ts +95 -0
- package/cards/attachment/attachment.types.js +7 -0
- package/cards/attachment/attachment.types.js.map +1 -0
- package/cards/attachment/attachmentGroup.component.d.ts +4 -0
- package/cards/attachment/attachmentGroup.component.js +21 -0
- package/cards/attachment/attachmentGroup.component.js.map +1 -0
- package/cards/attachment/index.d.ts +1 -0
- package/cards/attachment/index.js +16 -0
- package/cards/attachment/index.js.map +1 -0
- package/cards/bubble/bubble.component.d.ts +4 -0
- package/cards/bubble/bubble.component.js +67 -0
- package/cards/bubble/bubble.component.js.map +1 -0
- package/cards/bubble/bubble.types.d.ts +106 -0
- package/cards/bubble/bubble.types.js +7 -0
- package/cards/bubble/bubble.types.js.map +1 -0
- package/cards/bubble/bubbleGroup.component.d.ts +4 -0
- package/cards/bubble/bubbleGroup.component.js +21 -0
- package/cards/bubble/bubbleGroup.component.js.map +1 -0
- package/cards/bubble/index.d.ts +1 -0
- package/cards/bubble/index.js +16 -0
- package/cards/bubble/index.js.map +1 -0
- package/cards/button/button.component.js +56 -54
- package/cards/button/button.component.js.map +1 -1
- package/cards/button/button.types.d.ts +24 -0
- package/cards/button/button.types.js.map +1 -1
- package/cards/checkbox/checkbox.types.d.ts +2 -7
- package/cards/checkbox/checkbox.types.js.map +1 -1
- package/cards/dataTable/dataTable.component.js +191 -124
- package/cards/dataTable/dataTable.component.js.map +1 -1
- package/cards/dataTable/dataTable.types.d.ts +50 -0
- package/cards/dataTable/dataTable.types.js +6 -3
- package/cards/dataTable/dataTable.types.js.map +1 -1
- package/cards/dataTable/index.js +6 -6
- package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
- package/cards/field/field.component.js +1 -1
- package/cards/field/field.component.js.map +1 -1
- package/cards/form/form.component.js +57 -32
- package/cards/form/form.component.js.map +1 -1
- package/cards/form/form.context.d.ts +11 -0
- package/cards/form/form.context.js +1 -0
- package/cards/form/form.context.js.map +1 -1
- package/cards/form/form.types.d.ts +75 -0
- package/cards/form/form.types.js +6 -2
- package/cards/form/form.types.js.map +1 -1
- package/cards/form/index.js +5 -5
- package/cards/input/index.js +6 -6
- package/cards/input/input.component.js +38 -32
- package/cards/input/input.component.js.map +1 -1
- package/cards/input/input.types.d.ts +14 -7
- package/cards/input/input.types.js +2 -2
- package/cards/input/input.types.js.map +1 -1
- package/cards/message/index.d.ts +1 -0
- package/cards/message/index.js +15 -0
- package/cards/message/index.js.map +1 -0
- package/cards/message/message.component.d.ts +4 -0
- package/cards/message/message.component.js +47 -0
- package/cards/message/message.component.js.map +1 -0
- package/cards/message/message.types.d.ts +56 -0
- package/cards/message/message.types.js +7 -0
- package/cards/message/message.types.js.map +1 -0
- package/cards/message/messageGroup.component.d.ts +4 -0
- package/cards/message/messageGroup.component.js +21 -0
- package/cards/message/messageGroup.component.js.map +1 -0
- package/cards/pageWithNavbarMeta/index.js +35 -25
- package/cards/pageWithNavbarMeta/index.js.map +1 -1
- package/cards/pageWithNavbarMeta/pageWithNavbarMeta.types.d.ts +1 -4
- package/cards/select/select.types.d.ts +2 -7
- package/cards/select/select.types.js.map +1 -1
- package/cards/switch/switch.types.d.ts +2 -7
- package/cards/switch/switch.types.js.map +1 -1
- package/cards/textArea/textArea.component.js +1 -1
- package/cards/textArea/textArea.component.js.map +1 -1
- package/cards/textArea/textArea.types.d.ts +15 -11
- package/cards/textArea/textArea.types.js.map +1 -1
- package/cards/textField/textField.component.js +13 -9
- package/cards/textField/textField.component.js.map +1 -1
- package/cards/textField/textField.types.d.ts +12 -7
- package/cards/textField/textField.types.js.map +1 -1
- package/cards/toggleGroup/toggleGroup.types.d.ts +2 -7
- package/cards/toggleGroup/toggleGroup.types.js.map +1 -1
- package/components/ui/attachment.js +102 -0
- package/components/ui/attachment.js.map +1 -0
- package/components/ui/badge.js +7 -7
- package/components/ui/bubble.js +73 -0
- package/components/ui/bubble.js.map +1 -0
- package/components/ui/button.js +11 -11
- package/components/ui/empty.js +12 -12
- package/components/ui/field.js +16 -16
- package/components/ui/message.js +51 -0
- package/components/ui/message.js.map +1 -0
- package/components/ui/toggle-group.js +1 -1
- package/components/ui/toggle.js +1 -1
- package/package.json +17 -2
package/cards/input/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { InputComponent as e } from "./input.component.js";
|
|
2
|
-
import {
|
|
3
|
-
import { actionTypesToEvents as
|
|
2
|
+
import { Input as t, PI_INPUT_ACTION as n, PI_INPUT_CARD as r, PiInput as i, onInputChanged as a, onInputCommitted as o, onPiInputChanged as s, onPiInputCommitted as c } from "./input.types.js";
|
|
3
|
+
import { actionTypesToEvents as l, registerCardComponent as u } from "@pihanga2/core";
|
|
4
4
|
//#region src/cards/input/index.ts
|
|
5
|
-
|
|
6
|
-
name:
|
|
5
|
+
u({
|
|
6
|
+
name: r,
|
|
7
7
|
component: e,
|
|
8
|
-
events:
|
|
8
|
+
events: l(n)
|
|
9
9
|
});
|
|
10
10
|
//#endregion
|
|
11
|
-
export { t as
|
|
11
|
+
export { t as Input, n as PI_INPUT_ACTION, r as PI_INPUT_CARD, i as PiInput, a as onInputChanged, o as onInputCommitted, s as onPiInputChanged, c as onPiInputCommitted };
|
|
12
12
|
|
|
13
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,68 +1,74 @@
|
|
|
1
1
|
import { useFormContext as e } from "../form/form.context.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Input as t } from "../../components/ui/input.js";
|
|
3
|
+
import { Label as n } from "../../components/ui/label.js";
|
|
4
4
|
import r from "react";
|
|
5
5
|
import "@pihanga2/core";
|
|
6
6
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
7
7
|
//#region src/cards/input/input.component.tsx
|
|
8
8
|
var o = (o) => {
|
|
9
|
-
let { name: s, value: c = "", type: l = "text", placeholder: u, disabled: d, label: f, description: p, className: m, autoFocus: h,
|
|
9
|
+
let { name: s, value: c = "", type: l = "text", placeholder: u, disabled: d, label: f, description: p, className: m, autoFocus: h, submitOnEnter: g, cardName: _, onChanged: v, onCommitted: y } = o, b = r.useRef(null);
|
|
10
10
|
r.useEffect(() => {
|
|
11
|
-
h &&
|
|
11
|
+
h && b.current?.focus();
|
|
12
12
|
}, []);
|
|
13
|
-
let
|
|
13
|
+
let x = o.id, S = !!o.invalid, C = e(), w = C.isInForm && !!s, [T, E] = r.useState(l === "file" ? "" : c);
|
|
14
14
|
r.useEffect(() => {
|
|
15
|
-
!
|
|
15
|
+
!w && l !== "file" && E(c);
|
|
16
16
|
}, [
|
|
17
17
|
c,
|
|
18
|
-
|
|
18
|
+
w,
|
|
19
19
|
l
|
|
20
20
|
]);
|
|
21
|
-
let
|
|
22
|
-
function
|
|
21
|
+
let D = l === "file" ? void 0 : w ? C.formData[s] ?? "" : T;
|
|
22
|
+
function O(e) {
|
|
23
23
|
let t = l === "file" ? e.target.files?.[0]?.name ?? "" : e.target.value;
|
|
24
|
-
|
|
24
|
+
w ? C.handleChange(s, t) : (E(t), v({
|
|
25
25
|
name: s,
|
|
26
26
|
value: t
|
|
27
27
|
}));
|
|
28
28
|
}
|
|
29
|
-
function
|
|
30
|
-
!
|
|
29
|
+
function k() {
|
|
30
|
+
!w && l !== "file" && y({
|
|
31
31
|
name: s,
|
|
32
|
-
value:
|
|
32
|
+
value: T
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
function
|
|
36
|
-
e.key
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
function A(e) {
|
|
36
|
+
if (!(e.key !== "Enter" || l === "file")) {
|
|
37
|
+
if (w) {
|
|
38
|
+
g && C.requestAction("submit");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
y({
|
|
42
|
+
name: s,
|
|
43
|
+
value: T
|
|
44
|
+
});
|
|
45
|
+
}
|
|
40
46
|
}
|
|
41
|
-
let
|
|
47
|
+
let j = `${_}-${s ?? "input"}`, M = x ?? j;
|
|
42
48
|
return /* @__PURE__ */ a("div", {
|
|
43
|
-
"data-pihanga":
|
|
49
|
+
"data-pihanga": _,
|
|
44
50
|
className: "grid w-full gap-1.5",
|
|
45
51
|
children: [
|
|
46
|
-
f && /* @__PURE__ */ i(
|
|
47
|
-
htmlFor:
|
|
52
|
+
f && /* @__PURE__ */ i(n, {
|
|
53
|
+
htmlFor: M,
|
|
48
54
|
children: f
|
|
49
55
|
}),
|
|
50
|
-
/* @__PURE__ */ i(
|
|
51
|
-
ref:
|
|
52
|
-
id:
|
|
56
|
+
/* @__PURE__ */ i(t, {
|
|
57
|
+
ref: b,
|
|
58
|
+
id: M,
|
|
53
59
|
type: l,
|
|
54
|
-
value:
|
|
55
|
-
onChange:
|
|
56
|
-
onBlur:
|
|
57
|
-
onKeyDown:
|
|
60
|
+
value: D,
|
|
61
|
+
onChange: O,
|
|
62
|
+
onBlur: k,
|
|
63
|
+
onKeyDown: A,
|
|
58
64
|
placeholder: u,
|
|
59
65
|
disabled: d,
|
|
60
66
|
className: m,
|
|
61
|
-
"aria-invalid":
|
|
62
|
-
"aria-describedby": p ? `${
|
|
67
|
+
"aria-invalid": S || void 0,
|
|
68
|
+
"aria-describedby": p ? `${M}-desc` : void 0
|
|
63
69
|
}),
|
|
64
70
|
p && /* @__PURE__ */ i("p", {
|
|
65
|
-
id: `${
|
|
71
|
+
id: `${M}-desc`,
|
|
66
72
|
className: "text-sm text-muted-foreground",
|
|
67
73
|
children: p
|
|
68
74
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.component.js","names":[],"sources":["../../../src/cards/input/input.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Input} from \"@/components/ui/input\";\nimport {Label} from \"@/components/ui/label\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiInputEvents, PiInputProps} from \"./input.types\";\n\nexport const InputComponent = (\n props: PiCardProps<PiInputProps, PiInputEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue = \"\",\n type = \"text\",\n placeholder,\n disabled,\n label,\n description,\n className,\n autoFocus,\n cardName,\n onChanged,\n onCommitted,\n } = props;\n\n // Focus the input once, the first time it is mounted/shown (e.g. when a\n // dialog or drawer opens). Intentionally an empty dependency array — this\n // must not re-fire on subsequent re-renders.\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useEffect(() => {\n if (autoFocus) inputRef.current?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\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 // Local display state — lets the user type freely without triggering Redux\n // on every keystroke. Only `onCommitted` (blur / Enter) writes back to\n // Redux, so callers that use `onCommitted` instead of `onChanged` avoid\n // per-keystroke panel rebuilds.\n const [localValue, setLocalValue] = React.useState<string>(\n type === \"file\" ? \"\" : propValue,\n );\n\n // Sync local value when the prop changes from outside (e.g. when a different\n // card is selected in the playground, resetting the controls panel).\n React.useEffect(() => {\n if (!useFormData && type !== \"file\") {\n setLocalValue(propValue);\n }\n }, [propValue, useFormData, type]);\n\n // Derive the effective value for the controlled <Input>:\n // - inside a form → read from form.formData[name]\n // - standalone → use localValue (updated on every keystroke locally)\n // - file inputs → uncontrolled (no value binding)\n const inputValue =\n type === \"file\"\n ? undefined\n : useFormData\n ? ((form.formData[name!] as string | undefined) ?? \"\")\n : localValue;\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n const newValue =\n type === \"file\" ? (e.target.files?.[0]?.name ?? \"\") : e.target.value;\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n setLocalValue(newValue);\n onChanged({name, value: newValue});\n }\n }\n\n // Fire onCommitted when the user leaves the field or presses Enter.\n function handleBlur() {\n if (!useFormData && type !== \"file\") {\n onCommitted({name, value: localValue});\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (e.key
|
|
1
|
+
{"version":3,"file":"input.component.js","names":[],"sources":["../../../src/cards/input/input.component.tsx"],"sourcesContent":["import React from \"react\";\nimport {type PiCardProps} from \"@pihanga2/core\";\nimport {Input} from \"@/components/ui/input\";\nimport {Label} from \"@/components/ui/label\";\nimport {useFormContext} from \"@/cards/form/form.context\";\nimport type {PiInputEvents, PiInputProps} from \"./input.types\";\n\nexport const InputComponent = (\n props: PiCardProps<PiInputProps, PiInputEvents>,\n): React.ReactNode => {\n const {\n name,\n value: propValue = \"\",\n type = \"text\",\n placeholder,\n disabled,\n label,\n description,\n className,\n autoFocus,\n submitOnEnter,\n cardName,\n onChanged,\n onCommitted,\n } = props;\n\n // Focus the input once, the first time it is mounted/shown (e.g. when a\n // dialog or drawer opens). Intentionally an empty dependency array — this\n // must not re-fire on subsequent re-renders.\n const inputRef = React.useRef<HTMLInputElement>(null);\n React.useEffect(() => {\n if (autoFocus) inputRef.current?.focus();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\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 // Local display state — lets the user type freely without triggering Redux\n // on every keystroke. Only `onCommitted` (blur / Enter) writes back to\n // Redux, so callers that use `onCommitted` instead of `onChanged` avoid\n // per-keystroke panel rebuilds.\n const [localValue, setLocalValue] = React.useState<string>(\n type === \"file\" ? \"\" : propValue,\n );\n\n // Sync local value when the prop changes from outside (e.g. when a different\n // card is selected in the playground, resetting the controls panel).\n React.useEffect(() => {\n if (!useFormData && type !== \"file\") {\n setLocalValue(propValue);\n }\n }, [propValue, useFormData, type]);\n\n // Derive the effective value for the controlled <Input>:\n // - inside a form → read from form.formData[name]\n // - standalone → use localValue (updated on every keystroke locally)\n // - file inputs → uncontrolled (no value binding)\n const inputValue =\n type === \"file\"\n ? undefined\n : useFormData\n ? ((form.formData[name!] as string | undefined) ?? \"\")\n : localValue;\n\n function handleChange(e: React.ChangeEvent<HTMLInputElement>) {\n const newValue =\n type === \"file\" ? (e.target.files?.[0]?.name ?? \"\") : e.target.value;\n if (useFormData) {\n form.handleChange(name!, newValue);\n } else {\n setLocalValue(newValue);\n onChanged({name, value: newValue});\n }\n }\n\n // Fire onCommitted when the user leaves the field or presses Enter.\n function handleBlur() {\n if (!useFormData && type !== \"file\") {\n onCommitted({name, value: localValue});\n }\n }\n\n function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {\n if (e.key !== \"Enter\" || type === \"file\") return;\n\n if (useFormData) {\n // Inside a form, form.formData is already current (every keystroke\n // wrote through handleChange), so just request the form-level submit.\n if (submitOnEnter) form.requestAction(\"submit\");\n return;\n }\n\n onCommitted({name, value: localValue});\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 ?? \"input\"}`;\n const fieldId = injectedId ?? selfId;\n\n return (\n <div data-pihanga={cardName} className=\"grid w-full gap-1.5\">\n {label && <Label htmlFor={fieldId}>{label}</Label>}\n <Input\n ref={inputRef}\n id={fieldId}\n type={type}\n value={inputValue}\n onChange={handleChange}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n className={className}\n aria-invalid={invalid || undefined}\n aria-describedby={description ? `${fieldId}-desc` : undefined}\n />\n {description && (\n <p id={`${fieldId}-desc`} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;AAOA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,SACA,OAAO,IAAY,IACnB,UAAO,QACP,gBACA,aACA,UACA,gBACA,cACA,cACA,kBACA,aACA,cACA,mBACE,GAKE,IAAW,EAAM,OAAyB,IAAI;CACpD,EAAM,gBAAgB;EACpB,AAAI,KAAW,EAAS,SAAS,MAAM;CAEzC,GAAG,CAAC,CAAC;CAKL,IAAM,IAAc,EAAwB,IACtC,IAAU,EAAS,EAA8B,SAGjD,IAAO,EAAe,GACtB,IAAc,EAAK,YAAY,EAAQ,GAMvC,CAAC,GAAY,KAAiB,EAAM,SACxC,MAAS,SAAS,KAAK,CACzB;CAIA,EAAM,gBAAgB;EACpB,AAAI,CAAC,KAAe,MAAS,UAC3B,EAAc,CAAS;CAE3B,GAAG;EAAC;EAAW;EAAa;CAAI,CAAC;CAMjC,IAAM,IACJ,MAAS,SACL,KAAA,IACA,IACI,EAAK,SAAS,MAAiC,KACjD;CAER,SAAS,EAAa,GAAwC;EAC5D,IAAM,IACJ,MAAS,SAAU,EAAE,OAAO,QAAQ,IAAI,QAAQ,KAAM,EAAE,OAAO;EACjE,AAAI,IACF,EAAK,aAAa,GAAO,CAAQ,KAEjC,EAAc,CAAQ,GACtB,EAAU;GAAC;GAAM,OAAO;EAAQ,CAAC;CAErC;CAGA,SAAS,IAAa;EACpB,AAAI,CAAC,KAAe,MAAS,UAC3B,EAAY;GAAC;GAAM,OAAO;EAAU,CAAC;CAEzC;CAEA,SAAS,EAAc,GAA0C;EAC3D,QAAE,QAAQ,WAAW,MAAS,SAElC;OAAI,GAAa;IAGf,AAAI,KAAe,EAAK,cAAc,QAAQ;IAC9C;GACF;GAEA,EAAY;IAAC;IAAM,OAAO;GAAU,CAAC;EAFrC;CAGF;CAIA,IAAM,IAAS,GAAG,EAAS,GAAG,KAAQ,WAChC,IAAU,KAAc;CAE9B,OACE,kBAAC,OAAD;EAAK,gBAAc;EAAU,WAAU;YAAvC;GACG,KAAS,kBAAC,GAAD;IAAO,SAAS;cAAU;GAAa,CAAA;GACjD,kBAAC,GAAD;IACE,KAAK;IACL,IAAI;IACE;IACN,OAAO;IACP,UAAU;IACV,QAAQ;IACR,WAAW;IACE;IACH;IACC;IACX,gBAAc,KAAW,KAAA;IACzB,oBAAkB,IAAc,GAAG,EAAQ,SAAS,KAAA;GACrD,CAAA;GACA,KACC,kBAAC,KAAD;IAAG,IAAI,GAAG,EAAQ;IAAQ,WAAU;cACjC;GACA,CAAA;EAEF;;AAET"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { FormFieldProps } from '../form/form.types';
|
|
1
2
|
export declare const PI_INPUT_CARD = "pi/input";
|
|
3
|
+
export declare const Input: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<PiInputProps, S, PiInputEvents>) => import('@pihanga2/core').PiCardDef;
|
|
4
|
+
/** @deprecated Use `Input` instead. */
|
|
2
5
|
export declare const PiInput: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<PiInputProps, S, PiInputEvents>) => import('@pihanga2/core').PiCardDef;
|
|
3
6
|
export declare const PI_INPUT_ACTION: {
|
|
4
7
|
CHANGED: string;
|
|
@@ -24,13 +27,7 @@ export declare const onInputCommitted: <S extends import('@pihanga2/core').Redux
|
|
|
24
27
|
export declare const onPiInputCommitted: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
25
28
|
cardID: string;
|
|
26
29
|
} & PiInputCommittedEvent>) => void;
|
|
27
|
-
export type PiInputProps = {
|
|
28
|
-
/**
|
|
29
|
-
* Field name used to bind to FormContext when inside a pi/form card.
|
|
30
|
-
* When provided the component reads its value from form state and writes
|
|
31
|
-
* back via form.handleChange.
|
|
32
|
-
*/
|
|
33
|
-
name?: string;
|
|
30
|
+
export type PiInputProps = FormFieldProps & {
|
|
34
31
|
/**
|
|
35
32
|
* Controlled value used in standalone mode (outside a Form).
|
|
36
33
|
* Ignored when `name` is set and the component is inside a pi/form.
|
|
@@ -65,6 +62,16 @@ export type PiInputProps = {
|
|
|
65
62
|
* on mount — it does not re-focus on subsequent re-renders.
|
|
66
63
|
*/
|
|
67
64
|
autoFocus?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* When true and this input is rendered inside a `pi/form` card, pressing
|
|
67
|
+
* Enter requests the form's submit action (`FormContext.requestAction("submit")`)
|
|
68
|
+
* — equivalent to clicking a `Button` with `formAction: "submit"` — instead
|
|
69
|
+
* of (or in addition to) firing `onCommitted`.
|
|
70
|
+
*
|
|
71
|
+
* Has no effect outside a `pi/form`.
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
submitOnEnter?: boolean;
|
|
68
75
|
};
|
|
69
76
|
export type PiInputChangedEvent = {
|
|
70
77
|
/** Field name, mirrors the `name` prop if provided. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createCardDeclaration as e, createOnAction as t, registerActions as n } from "@pihanga2/core";
|
|
2
2
|
//#region src/cards/input/input.types.ts
|
|
3
|
-
var r = "pi/input", i = e(r), a = n(r, ["changed", "committed"]),
|
|
3
|
+
var r = "pi/input", i = e(r), a = i, o = n(r, ["changed", "committed"]), s = t(o.CHANGED), c = s, l = t(o.COMMITTED), u = l;
|
|
4
4
|
//#endregion
|
|
5
|
-
export {
|
|
5
|
+
export { i as Input, o as PI_INPUT_ACTION, r as PI_INPUT_CARD, a as PiInput, s as onInputChanged, l as onInputCommitted, c as onPiInputChanged, u as onPiInputCommitted };
|
|
6
6
|
|
|
7
7
|
//# sourceMappingURL=input.types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.types.js","names":[],"sources":["../../../src/cards/input/input.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\n\nexport const PI_INPUT_CARD = \"pi/input\";\n\nexport const
|
|
1
|
+
{"version":3,"file":"input.types.js","names":[],"sources":["../../../src/cards/input/input.types.ts"],"sourcesContent":["import {\n createCardDeclaration,\n createOnAction,\n registerActions,\n} from \"@pihanga2/core\";\nimport type {FormFieldProps} from \"@/cards/form/form.types\";\n\nexport const PI_INPUT_CARD = \"pi/input\";\n\nexport const Input = createCardDeclaration<PiInputProps, PiInputEvents>(\n PI_INPUT_CARD,\n);\n\n/** @deprecated Use `Input` instead. */\nexport const PiInput = Input;\n\nexport const PI_INPUT_ACTION = registerActions(PI_INPUT_CARD, [\n \"changed\",\n \"committed\",\n]);\n\nexport const onInputChanged = createOnAction<PiInputChangedEvent>(\n PI_INPUT_ACTION.CHANGED,\n);\n\n/** @deprecated Use `onInputChanged` instead. */\nexport const onPiInputChanged = onInputChanged;\n\n/**\n * Subscribe to \"committed\" events — fired when the user finishes editing\n * (blur or Enter key). Unlike `onInputChanged` (which fires on every keystroke),\n * `onInputCommitted` only fires once per editing session, making it the preferred\n * handler for controlled inputs that trigger expensive downstream work.\n */\nexport const onInputCommitted = createOnAction<PiInputCommittedEvent>(\n PI_INPUT_ACTION.COMMITTED,\n);\n\n/** @deprecated Use `onInputCommitted` instead. */\nexport const onPiInputCommitted = onInputCommitted;\n\n// ---------------------------------------------------------------------------\n// Props & Events\n// ---------------------------------------------------------------------------\n\nexport type PiInputProps = FormFieldProps & {\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 /**\n * HTML input type.\n * Common values: \"text\" | \"email\" | \"password\" | \"number\" | \"search\" |\n * \"url\" | \"tel\" | \"date\" | \"file\".\n * Defaults to \"text\".\n */\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 /**\n * Optional label text rendered in a `<label>` element above the input.\n * The label is automatically associated with the input via `htmlFor`.\n */\n label?: string;\n\n /**\n * Optional helper / description text rendered below the input.\n * Use this for hints, formatting guidance, or validation feedback.\n */\n description?: string;\n\n /** Extra Tailwind / CSS classes forwarded to the underlying <input> element. */\n className?: string;\n\n /**\n * When true, the input grabs keyboard focus the first time it is\n * mounted/shown (e.g. when a dialog or drawer opens). Only applies once,\n * on mount — it does not re-focus on subsequent re-renders.\n */\n autoFocus?: boolean;\n\n /**\n * When true and this input is rendered inside a `pi/form` card, pressing\n * Enter requests the form's submit action (`FormContext.requestAction(\"submit\")`)\n * — equivalent to clicking a `Button` with `formAction: \"submit\"` — instead\n * of (or in addition to) firing `onCommitted`.\n *\n * Has no effect outside a `pi/form`.\n * @default false\n */\n submitOnEnter?: boolean;\n};\n\nexport type PiInputChangedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** New value after the change. */\n value: string;\n};\n\n/**\n * Payload for the `onCommitted` event (blur / Enter key).\n * Same shape as `PiInputChangedEvent`.\n */\nexport type PiInputCommittedEvent = {\n /** Field name, mirrors the `name` prop if provided. */\n name?: string;\n /** Final committed value. */\n value: string;\n};\n\nexport type PiInputEvents = {\n /** Fires on every keystroke. */\n onChanged: PiInputChangedEvent;\n /**\n * Fires once when the user finishes editing (blur or Enter key).\n * Use this instead of `onChanged` when each change triggers expensive\n * downstream work (e.g. rebuilding a panel).\n */\n onCommitted: PiInputCommittedEvent;\n};\n"],"mappings":";;AAOA,IAAa,IAAgB,YAEhB,IAAQ,EACnB,CACF,GAGa,IAAU,GAEV,IAAkB,EAAgB,GAAe,CAC5D,WACA,WACF,CAAC,GAEY,IAAiB,EAC5B,EAAgB,OAClB,GAGa,IAAmB,GAQnB,IAAmB,EAC9B,EAAgB,SAClB,GAGa,IAAqB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './message.types';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MessageComponent as e } from "./message.component.js";
|
|
2
|
+
import { MessageGroupComponent as t } from "./messageGroup.component.js";
|
|
3
|
+
import { MESSAGE_CARD as n, MESSAGE_GROUP_CARD as r, Message as i, MessageGroup as a } from "./message.types.js";
|
|
4
|
+
import { registerCardComponent as o } from "@pihanga2/core";
|
|
5
|
+
o({
|
|
6
|
+
name: n,
|
|
7
|
+
component: e
|
|
8
|
+
}), o({
|
|
9
|
+
name: r,
|
|
10
|
+
component: t
|
|
11
|
+
});
|
|
12
|
+
//#endregion
|
|
13
|
+
export { n as MESSAGE_CARD, r as MESSAGE_GROUP_CARD, i as Message, a as MessageGroup };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/message/index.ts"],"sourcesContent":["import {registerCardComponent} from \"@pihanga2/core\";\n\nimport {MessageComponent} from \"./message.component\";\nimport {MessageGroupComponent} from \"./messageGroup.component\";\nimport {MESSAGE_CARD, MESSAGE_GROUP_CARD} from \"./message.types\";\n\nexport * from \"./message.types\";\n\nregisterCardComponent({\n name: MESSAGE_CARD,\n component: MessageComponent,\n});\n\nregisterCardComponent({\n name: MESSAGE_GROUP_CARD,\n component: MessageGroupComponent,\n});\n"],"mappings":";;;;AAQA,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC,GAED,EAAsB;CACpB,MAAM;CACN,WAAW;AACb,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Message as e, MessageAvatar as t, MessageContent as n, MessageFooter as r, MessageHeader as i } from "../../components/ui/message.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Card as a } from "@pihanga2/core";
|
|
4
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
5
|
+
//#region src/cards/message/message.component.tsx
|
|
6
|
+
var c = (c) => {
|
|
7
|
+
let { align: l = "start", avatarCard: u, headerCard: d, contentCard: f, footerCard: p, className: m, avatarClassName: h, contentClassName: g, headerClassName: _, footerClassName: v, style: y, cardName: b } = c;
|
|
8
|
+
return /* @__PURE__ */ s(e, {
|
|
9
|
+
align: l,
|
|
10
|
+
className: m,
|
|
11
|
+
style: y,
|
|
12
|
+
"data-pihanga": b,
|
|
13
|
+
children: [u && /* @__PURE__ */ o(t, {
|
|
14
|
+
className: h,
|
|
15
|
+
children: /* @__PURE__ */ o(a, {
|
|
16
|
+
cardName: u,
|
|
17
|
+
parentCard: b
|
|
18
|
+
})
|
|
19
|
+
}), /* @__PURE__ */ s(n, {
|
|
20
|
+
className: g,
|
|
21
|
+
children: [
|
|
22
|
+
d && /* @__PURE__ */ o(i, {
|
|
23
|
+
className: _,
|
|
24
|
+
children: /* @__PURE__ */ o(a, {
|
|
25
|
+
cardName: d,
|
|
26
|
+
parentCard: b
|
|
27
|
+
})
|
|
28
|
+
}),
|
|
29
|
+
/* @__PURE__ */ o(a, {
|
|
30
|
+
cardName: f,
|
|
31
|
+
parentCard: b
|
|
32
|
+
}),
|
|
33
|
+
p && /* @__PURE__ */ o(r, {
|
|
34
|
+
className: v,
|
|
35
|
+
children: /* @__PURE__ */ o(a, {
|
|
36
|
+
cardName: p,
|
|
37
|
+
parentCard: b
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { c as MessageComponent };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=message.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.component.js","names":[],"sources":["../../../src/cards/message/message.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {\n Message,\n MessageAvatar,\n MessageContent,\n MessageFooter,\n MessageHeader,\n} from \"@/components/ui/message\";\nimport type {MessageProps} from \"./message.types\";\n\nexport const MessageComponent = (\n props: PiCardProps<MessageProps>,\n): React.ReactNode => {\n const {\n align = \"start\",\n avatarCard,\n headerCard,\n contentCard,\n footerCard,\n className,\n avatarClassName,\n contentClassName,\n headerClassName,\n footerClassName,\n style,\n cardName,\n } = props;\n\n return (\n <Message\n align={align}\n className={className}\n style={style}\n data-pihanga={cardName}\n >\n {avatarCard && (\n <MessageAvatar className={avatarClassName}>\n <Card cardName={avatarCard} parentCard={cardName} />\n </MessageAvatar>\n )}\n\n <MessageContent className={contentClassName}>\n {headerCard && (\n <MessageHeader className={headerClassName}>\n <Card cardName={headerCard} parentCard={cardName} />\n </MessageHeader>\n )}\n\n <Card cardName={contentCard} parentCard={cardName} />\n\n {footerCard && (\n <MessageFooter className={footerClassName}>\n <Card cardName={footerCard} parentCard={cardName} />\n </MessageFooter>\n )}\n </MessageContent>\n </Message>\n );\n};\n"],"mappings":";;;;;AAWA,IAAa,KACX,MACoB;CACpB,IAAM,EACJ,WAAQ,SACR,eACA,eACA,gBACA,eACA,cACA,oBACA,qBACA,oBACA,oBACA,UACA,gBACE;CAEJ,OACE,kBAAC,GAAD;EACS;EACI;EACJ;EACP,gBAAc;YAJhB,CAMG,KACC,kBAAC,GAAD;GAAe,WAAW;aACxB,kBAAC,GAAD;IAAM,UAAU;IAAY,YAAY;GAAW,CAAA;EACtC,CAAA,GAGjB,kBAAC,GAAD;GAAgB,WAAW;aAA3B;IACG,KACC,kBAAC,GAAD;KAAe,WAAW;eACxB,kBAAC,GAAD;MAAM,UAAU;MAAY,YAAY;KAAW,CAAA;IACtC,CAAA;IAGjB,kBAAC,GAAD;KAAM,UAAU;KAAa,YAAY;IAAW,CAAA;IAEnD,KACC,kBAAC,GAAD;KAAe,WAAW;eACxB,kBAAC,GAAD;MAAM,UAAU;MAAY,YAAY;KAAW,CAAA;IACtC,CAAA;GAEH;IACT;;AAEb"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { PiCardRef } from '@pihanga2/core';
|
|
2
|
+
import { default as React } from 'react';
|
|
3
|
+
export declare const MESSAGE_CARD = "shad/message";
|
|
4
|
+
export declare const Message: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<MessageProps, S, {}>) => import('@pihanga2/core').PiCardDef;
|
|
5
|
+
export type MessageProps = {
|
|
6
|
+
/**
|
|
7
|
+
* Alignment of the message row.
|
|
8
|
+
* - `"start"` — sender / left-hand messages (default).
|
|
9
|
+
* - `"end"` — receiver / current-user messages (right-hand side).
|
|
10
|
+
* @default "start"
|
|
11
|
+
*/
|
|
12
|
+
align?: "start" | "end";
|
|
13
|
+
/**
|
|
14
|
+
* Pihanga card reference rendered inside `MessageAvatar`
|
|
15
|
+
* (typically a `shad/avatar` card). Omit to render no avatar slot.
|
|
16
|
+
*/
|
|
17
|
+
avatarCard?: PiCardRef;
|
|
18
|
+
/**
|
|
19
|
+
* Pihanga card reference rendered above the message surface, inside
|
|
20
|
+
* `MessageHeader` (e.g. a sender name via `shad/typography`).
|
|
21
|
+
*/
|
|
22
|
+
headerCard?: PiCardRef;
|
|
23
|
+
/**
|
|
24
|
+
* Pihanga card reference rendered as the message surface itself.
|
|
25
|
+
* Typically a `shad/bubble` card, but any card works — including
|
|
26
|
+
* "large" content such as a `markdown-viewer` or `shad/data-table` card.
|
|
27
|
+
*/
|
|
28
|
+
contentCard: PiCardRef;
|
|
29
|
+
/**
|
|
30
|
+
* Pihanga card reference rendered below the message surface, inside
|
|
31
|
+
* `MessageFooter` (e.g. delivery status, timestamps, or action buttons).
|
|
32
|
+
*/
|
|
33
|
+
footerCard?: PiCardRef;
|
|
34
|
+
/** Additional Tailwind classes applied to the root `Message` element. */
|
|
35
|
+
className?: string;
|
|
36
|
+
/** Additional Tailwind classes applied to `MessageAvatar`. */
|
|
37
|
+
avatarClassName?: string;
|
|
38
|
+
/** Additional Tailwind classes applied to `MessageContent`. */
|
|
39
|
+
contentClassName?: string;
|
|
40
|
+
/** Additional Tailwind classes applied to `MessageHeader`. */
|
|
41
|
+
headerClassName?: string;
|
|
42
|
+
/** Additional Tailwind classes applied to `MessageFooter`. */
|
|
43
|
+
footerClassName?: string;
|
|
44
|
+
/** Inline styles applied to the root `Message` element. */
|
|
45
|
+
style?: React.CSSProperties;
|
|
46
|
+
};
|
|
47
|
+
export declare const MESSAGE_GROUP_CARD = "shad/message-group";
|
|
48
|
+
export declare const MessageGroup: <S extends import('@pihanga2/core').ReduxState>(p: import('@pihanga2/core').PiMapProps<MessageGroupProps, S, {}>) => import('@pihanga2/core').PiCardDef;
|
|
49
|
+
export type MessageGroupProps = {
|
|
50
|
+
/** Ordered list of `shad/message` (or other) card refs to stack. */
|
|
51
|
+
content: PiCardRef[];
|
|
52
|
+
/** Additional Tailwind classes applied to the root element. */
|
|
53
|
+
className?: string;
|
|
54
|
+
/** Inline styles applied to the root element. */
|
|
55
|
+
style?: React.CSSProperties;
|
|
56
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createCardDeclaration as e } from "@pihanga2/core";
|
|
2
|
+
//#region src/cards/message/message.types.ts
|
|
3
|
+
var t = "shad/message", n = e(t), r = "shad/message-group", i = e(r);
|
|
4
|
+
//#endregion
|
|
5
|
+
export { t as MESSAGE_CARD, r as MESSAGE_GROUP_CARD, n as Message, i as MessageGroup };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=message.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.types.js","names":[],"sources":["../../../src/cards/message/message.types.ts"],"sourcesContent":["import {createCardDeclaration, type PiCardRef} from \"@pihanga2/core\";\nimport type React from \"react\";\n\nexport const MESSAGE_CARD = \"shad/message\";\n\nexport const Message = createCardDeclaration<MessageProps>(MESSAGE_CARD);\n\nexport type MessageProps = {\n /**\n * Alignment of the message row.\n * - `\"start\"` — sender / left-hand messages (default).\n * - `\"end\"` — receiver / current-user messages (right-hand side).\n * @default \"start\"\n */\n align?: \"start\" | \"end\";\n\n /**\n * Pihanga card reference rendered inside `MessageAvatar`\n * (typically a `shad/avatar` card). Omit to render no avatar slot.\n */\n avatarCard?: PiCardRef;\n\n /**\n * Pihanga card reference rendered above the message surface, inside\n * `MessageHeader` (e.g. a sender name via `shad/typography`).\n */\n headerCard?: PiCardRef;\n\n /**\n * Pihanga card reference rendered as the message surface itself.\n * Typically a `shad/bubble` card, but any card works — including\n * \"large\" content such as a `markdown-viewer` or `shad/data-table` card.\n */\n contentCard: PiCardRef;\n\n /**\n * Pihanga card reference rendered below the message surface, inside\n * `MessageFooter` (e.g. delivery status, timestamps, or action buttons).\n */\n footerCard?: PiCardRef;\n\n /** Additional Tailwind classes applied to the root `Message` element. */\n className?: string;\n /** Additional Tailwind classes applied to `MessageAvatar`. */\n avatarClassName?: string;\n /** Additional Tailwind classes applied to `MessageContent`. */\n contentClassName?: string;\n /** Additional Tailwind classes applied to `MessageHeader`. */\n headerClassName?: string;\n /** Additional Tailwind classes applied to `MessageFooter`. */\n footerClassName?: string;\n\n /** Inline styles applied to the root `Message` element. */\n style?: React.CSSProperties;\n};\n\n// ---------------------------------------------------------------------------\n// shad/message-group — stack consecutive messages from the same sender.\n// ---------------------------------------------------------------------------\n\nexport const MESSAGE_GROUP_CARD = \"shad/message-group\";\n\nexport const MessageGroup =\n createCardDeclaration<MessageGroupProps>(MESSAGE_GROUP_CARD);\n\nexport type MessageGroupProps = {\n /** Ordered list of `shad/message` (or other) card refs to stack. */\n content: PiCardRef[];\n /** Additional Tailwind classes applied to the root element. */\n className?: string;\n /** Inline styles applied to the root element. */\n style?: React.CSSProperties;\n};\n"],"mappings":";;AAGA,IAAa,IAAe,gBAEf,IAAU,EAAoC,CAAY,GAuD1D,IAAqB,sBAErB,IACX,EAAyC,CAAkB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MessageGroup as e } from "../../components/ui/message.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Card as t } from "@pihanga2/core";
|
|
4
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
5
|
+
//#region src/cards/message/messageGroup.component.tsx
|
|
6
|
+
var r = (r) => {
|
|
7
|
+
let { content: i, className: a, style: o, cardName: s } = r;
|
|
8
|
+
return /* @__PURE__ */ n(e, {
|
|
9
|
+
className: a,
|
|
10
|
+
style: o,
|
|
11
|
+
"data-pihanga": s,
|
|
12
|
+
children: i.map((e, r) => /* @__PURE__ */ n(t, {
|
|
13
|
+
cardName: e,
|
|
14
|
+
parentCard: s
|
|
15
|
+
}, r))
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { r as MessageGroupComponent };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=messageGroup.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messageGroup.component.js","names":[],"sources":["../../../src/cards/message/messageGroup.component.tsx"],"sourcesContent":["import * as React from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {MessageGroup} from \"@/components/ui/message\";\nimport type {MessageGroupProps} from \"./message.types\";\n\nexport const MessageGroupComponent = (\n props: PiCardProps<MessageGroupProps>,\n): React.ReactNode => {\n const {content, className, style, cardName} = props;\n\n return (\n <MessageGroup className={className} style={style} data-pihanga={cardName}>\n {content.map((cn, i) => (\n <Card cardName={cn} parentCard={cardName} key={i} />\n ))}\n </MessageGroup>\n );\n};\n"],"mappings":";;;;;AAKA,IAAa,KACX,MACoB;CACpB,IAAM,EAAC,YAAS,cAAW,UAAO,gBAAY;CAE9C,OACE,kBAAC,GAAD;EAAyB;EAAkB;EAAO,gBAAc;YAC7D,EAAQ,KAAK,GAAI,MAChB,kBAAC,GAAD;GAAM,UAAU;GAAI,YAAY;EAAmB,GAAJ,CAAI,CACpD;CACW,CAAA;AAElB"}
|
|
@@ -16,26 +16,36 @@ import { registerMetaCard as u } from "@pihanga2/core";
|
|
|
16
16
|
function d(e) {
|
|
17
17
|
return e ? e.charAt(0).toLocaleUpperCase() + e.slice(1) : "";
|
|
18
18
|
}
|
|
19
|
-
function f(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
function f(e) {
|
|
20
|
+
return typeof e == "function" ? e({}, {
|
|
21
|
+
cardName: "",
|
|
22
|
+
ctxtProps: {},
|
|
23
|
+
resolve: (e) => typeof e == "function" ? e({}, {
|
|
24
|
+
cardName: "",
|
|
25
|
+
ctxtProps: {}
|
|
26
|
+
}) : e
|
|
27
|
+
}) : e;
|
|
28
|
+
}
|
|
29
|
+
function p(s, c, l) {
|
|
30
|
+
let u = f(c.navLinks) ?? [], p = f(c.iconName), m = f(c.className), h = f(c.footer), g = [];
|
|
31
|
+
p && g.push(t({
|
|
32
|
+
iconLabel: p,
|
|
23
33
|
opts: {
|
|
24
34
|
variant: "none",
|
|
25
35
|
size: "icon"
|
|
26
36
|
},
|
|
27
37
|
className: "h-6 w-6 shrink-0 pointer-events-none"
|
|
28
|
-
})),
|
|
38
|
+
})), g.push(a({
|
|
29
39
|
text: c.title,
|
|
30
40
|
level: "large",
|
|
31
41
|
className: "leading-none"
|
|
32
42
|
}));
|
|
33
|
-
let
|
|
43
|
+
let _ = l("title", i({
|
|
34
44
|
direction: "row",
|
|
35
45
|
alignItems: "center",
|
|
36
46
|
spacing: 2,
|
|
37
|
-
content:
|
|
38
|
-
})),
|
|
47
|
+
content: g
|
|
48
|
+
})), v = u.map((e, n) => l(`nav-link-${n}`, t({
|
|
39
49
|
id: e.id,
|
|
40
50
|
label: e.title ?? d(e.id),
|
|
41
51
|
opts: { variant: "ghost" },
|
|
@@ -44,15 +54,15 @@ function f(s, c, l) {
|
|
|
44
54
|
type: o.NAVIGATE_TO,
|
|
45
55
|
id: e.id
|
|
46
56
|
})
|
|
47
|
-
}))),
|
|
57
|
+
}))), y = l("nav-md", n({
|
|
48
58
|
showOn: "md",
|
|
49
59
|
content: l("nav-md-inner", i({
|
|
50
60
|
direction: "row",
|
|
51
61
|
alignItems: "center",
|
|
52
62
|
spacing: 5,
|
|
53
|
-
content: [
|
|
63
|
+
content: [_, ...v]
|
|
54
64
|
}))
|
|
55
|
-
})),
|
|
65
|
+
})), b = u.length > 0 ? l("nav-sm", n({
|
|
56
66
|
showOn: "<md",
|
|
57
67
|
content: l("nav-sm-drawer", r({
|
|
58
68
|
direction: "left",
|
|
@@ -68,25 +78,25 @@ function f(s, c, l) {
|
|
|
68
78
|
direction: "column",
|
|
69
79
|
spacing: 4,
|
|
70
80
|
className: "p-4",
|
|
71
|
-
content: [
|
|
81
|
+
content: [_, ...v]
|
|
72
82
|
})),
|
|
73
83
|
footerCloseButtonText: null
|
|
74
84
|
}))
|
|
75
85
|
})) : l("nav-sm-title", n({
|
|
76
86
|
showOn: "<md",
|
|
77
|
-
content:
|
|
78
|
-
})),
|
|
79
|
-
|
|
80
|
-
let
|
|
81
|
-
|
|
87
|
+
content: _
|
|
88
|
+
})), x = f(c.headerLeftCard), S = f(c.headerRightCard), C = [];
|
|
89
|
+
x && C.push(x), S && C.push(S);
|
|
90
|
+
let w = [y, b];
|
|
91
|
+
C.length > 0 && w.push(l("header-actions", i({
|
|
82
92
|
direction: "row",
|
|
83
93
|
alignItems: "center",
|
|
84
94
|
className: "ml-auto gap-2 lg:gap-4",
|
|
85
|
-
content:
|
|
95
|
+
content: C
|
|
86
96
|
})));
|
|
87
|
-
let
|
|
97
|
+
let T = [l("header", e({
|
|
88
98
|
className: "shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6",
|
|
89
|
-
content:
|
|
99
|
+
content: w
|
|
90
100
|
})), l("main", e({
|
|
91
101
|
className: "flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4",
|
|
92
102
|
content: ((e, t) => {
|
|
@@ -94,22 +104,22 @@ function f(s, c, l) {
|
|
|
94
104
|
return n == null ? [] : [n];
|
|
95
105
|
})
|
|
96
106
|
}))];
|
|
97
|
-
return
|
|
107
|
+
return h && T.push(l("footer", e({
|
|
98
108
|
className: "shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4",
|
|
99
|
-
content: [
|
|
109
|
+
content: [h]
|
|
100
110
|
}))), i({
|
|
101
111
|
direction: "row",
|
|
102
|
-
className: `w-full h-full justify-center${
|
|
112
|
+
className: `w-full h-full justify-center${m ? ` ${m}` : ""}`,
|
|
103
113
|
content: [l("page", i({
|
|
104
114
|
direction: "column",
|
|
105
115
|
className: "flex-1 h-full w-full",
|
|
106
|
-
content:
|
|
116
|
+
content: T
|
|
107
117
|
}))]
|
|
108
118
|
});
|
|
109
119
|
}
|
|
110
120
|
u({
|
|
111
121
|
type: s,
|
|
112
|
-
mapper:
|
|
122
|
+
mapper: p,
|
|
113
123
|
events: o
|
|
114
124
|
});
|
|
115
125
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/index.ts"],"sourcesContent":["import {\n registerMetaCard,\n type PiCardDef,\n type PiCardRef,\n type PiMetaProps,\n type PiMetaResolveCtx,\n type PiRegisterMetaCard,\n type RegisterCardF,\n} from \"@pihanga2/core\";\n\nimport {Stack} from \"@/cards/stack\";\nimport {Box} from \"@/cards/box\";\nimport {Button} from \"@/cards/button\";\nimport {Typography} from \"@/cards/typography\";\nimport {Conditional} from \"@/cards/conditional\";\nimport {Drawer} from \"@/cards/drawer\";\n\nimport {\n PAGE_WITH_NAVBAR_META_ACTION,\n PI_PAGE_WITH_NAVBAR_META_CARD,\n type NavLink,\n type PageWithNavbarMetaDynProps,\n type PageWithNavbarMetaEvents,\n type PageWithNavbarMetaStaticProps,\n} from \"./pageWithNavbarMeta.types\";\n\nexport * from \"./pageWithNavbarMeta.types\";\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toLocaleUpperCase() + s.slice(1) : \"\";\n}\n\n// ── Mapper ───────────────────────────────────────────────────────────────────\n\n/**\n * `StaticProps` arrive as their plain types — TypeScript refuses memo selectors.\n * `DynProps` arrive as `StateMapper<T>` functions — must be resolved via `resolve()`.\n */\ntype MapperProps = PiMetaProps<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>;\n\nfunction PageWithNavbarMetaMapper(\n _cardName: string,\n props: MapperProps,\n reg: RegisterCardF,\n): PiCardDef {\n // ── Static props: plain types, no resolve() needed ───────────────────────\n const navLinks = props.navLinks ?? [];\n const iconName = props.iconName;\n const wrapperClass = props.className;\n const footer = props.footer;\n\n // ── Title (icon + text) ─────────────────────────────────────────────────\n // props.title is StateMapper<string> — a function, NOT a string.\n // Typography's `text` prop is typed (via PiMapProps) as `string | StateMapper<string>`,\n // so we forward the selector function directly. The framework resolves it lazily\n // (calls props.title(state, ctx)) when Typography renders. This is different from\n // using props.title as a string, which TypeScript would reject.\n const titleContent: PiCardRef[] = [];\n if (iconName) {\n titleContent.push(\n Button({\n iconLabel: iconName,\n opts: {variant: \"none\", size: \"icon\"},\n className: \"h-6 w-6 shrink-0 pointer-events-none\",\n }),\n );\n }\n titleContent.push(\n Typography({\n text: props.title,\n level: \"large\",\n className: \"leading-none\",\n }),\n );\n\n const titleStack = reg(\n \"title\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 2,\n content: titleContent,\n }),\n );\n\n // ── Nav link buttons (shared between desktop and mobile) ────────────────\n const linkButtons = navLinks.map((link: NavLink, i: number) =>\n reg(\n `nav-link-${i}`,\n Button({\n id: link.id,\n label: link.title ?? capitalize(link.id),\n opts: {variant: \"ghost\"},\n className:\n \"px-0 text-muted-foreground hover:text-foreground h-auto p-0\",\n onClickedMapper: () => ({\n type: PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n id: link.id,\n }),\n }),\n ),\n );\n\n // ── Desktop nav (md+): title + links in a row ───────────────────────────\n const desktopNav = reg(\n \"nav-md\",\n Conditional({\n showOn: \"md\",\n content: reg(\n \"nav-md-inner\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 5,\n content: [titleStack, ...linkButtons],\n }),\n ),\n }),\n );\n\n // ── Mobile nav (< md) ───────────────────────────────────────────────────\n // With nav links: hamburger drawer (left slide-in using pi/drawer).\n // Without nav links: just show the title inline.\n const mobileNav: PiCardRef =\n navLinks.length > 0\n ? reg(\n \"nav-sm\",\n Conditional({\n showOn: \"<md\",\n content: reg(\n \"nav-sm-drawer\",\n Drawer({\n direction: \"left\",\n trigger: Button({\n iconLabel: \"menu\",\n opts: {variant: \"outline\", size: \"icon\"},\n ariaLabel: \"Toggle navigation menu\",\n }),\n content: reg(\n \"nav-sm-content\",\n Stack({\n direction: \"column\",\n spacing: 4,\n className: \"p-4\",\n content: [titleStack, ...linkButtons],\n }),\n ),\n footerCloseButtonText: null,\n }),\n ),\n }),\n )\n : reg(\n \"nav-sm-title\",\n Conditional({\n showOn: \"<md\",\n content: titleStack,\n }),\n );\n\n // ── Header action slots ─────────────────────────────────────────────────\n // Static PiCardRefs — TypeScript already refuses memo() selectors here.\n const actionRefs: PiCardRef[] = [];\n if (props.headerLeftCard) {\n actionRefs.push(props.headerLeftCard);\n }\n if (props.headerRightCard) {\n actionRefs.push(props.headerRightCard);\n }\n\n const headerContent: PiCardRef[] = [desktopNav, mobileNav];\n if (actionRefs.length > 0) {\n headerContent.push(\n reg(\n \"header-actions\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n className: \"ml-auto gap-2 lg:gap-4\",\n content: actionRefs,\n }),\n ),\n );\n }\n\n // ── Header ──────────────────────────────────────────────────────────────\n const header = reg(\n \"header\",\n Box({\n className:\n \"shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6\",\n content: headerContent,\n }),\n );\n\n // ── Main ────────────────────────────────────────────────────────────────\n // props.main is a StateMapper — resolved lazily so React re-renders when\n // the referenced card changes.\n const mainBox = reg(\n \"main\",\n Box({\n className:\n \"flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4\",\n content: ((_: unknown, ctx: PiMetaResolveCtx) => {\n const ref = ctx.resolve(props.main);\n return ref != null ? [ref as PiCardRef] : [];\n }) as unknown as PiCardRef[],\n }),\n );\n\n // ── Page column ─────────────────────────────────────────────────────────\n const pageContent: PiCardRef[] = [header, mainBox];\n\n // ── Footer (optional) ───────────────────────────────────────────────────\n // `footer` is a static plain PiCardRef — use directly.\n if (footer) {\n pageContent.push(\n reg(\n \"footer\",\n Box({\n className:\n \"shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4\",\n content: [footer],\n }),\n ),\n );\n }\n\n // ── Assemble ────────────────────────────────────────────────────────────\n return Stack({\n direction: \"row\",\n className: `w-full h-full justify-center${wrapperClass ? ` ${wrapperClass}` : \"\"}`,\n content: [\n reg(\n \"page\",\n Stack({\n direction: \"column\",\n className: \"flex-1 h-full w-full\",\n content: pageContent,\n }),\n ),\n ],\n });\n}\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nregisterMetaCard({\n type: PI_PAGE_WITH_NAVBAR_META_CARD,\n mapper: PageWithNavbarMetaMapper,\n events: PAGE_WITH_NAVBAR_META_ACTION,\n} satisfies PiRegisterMetaCard);\n"],"mappings":";;;;;;;;;;;;;;;AA8BA,SAAS,EAAW,GAAmB;CACrC,OAAO,IAAI,EAAE,OAAO,CAAC,EAAE,kBAAkB,IAAI,EAAE,MAAM,CAAC,IAAI;AAC5D;AAcA,SAAS,EACP,GACA,GACA,GACW;CAEX,IAAM,IAAW,EAAM,YAAY,CAAC,GAC9B,IAAW,EAAM,UACjB,IAAe,EAAM,WACrB,IAAS,EAAM,QAQf,IAA4B,CAAC;CAUnC,AATI,KACF,EAAa,KACX,EAAO;EACL,WAAW;EACX,MAAM;GAAC,SAAS;GAAQ,MAAM;EAAM;EACpC,WAAW;CACb,CAAC,CACH,GAEF,EAAa,KACX,EAAW;EACT,MAAM,EAAM;EACZ,OAAO;EACP,WAAW;CACb,CAAC,CACH;CAEA,IAAM,IAAa,EACjB,SACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,SAAS;EACT,SAAS;CACX,CAAC,CACH,GAGM,IAAc,EAAS,KAAK,GAAe,MAC/C,EACE,YAAY,KACZ,EAAO;EACL,IAAI,EAAK;EACT,OAAO,EAAK,SAAS,EAAW,EAAK,EAAE;EACvC,MAAM,EAAC,SAAS,QAAO;EACvB,WACE;EACF,wBAAwB;GACtB,MAAM,EAA6B;GACnC,IAAI,EAAK;EACX;CACF,CAAC,CACH,CACF,GAGM,IAAa,EACjB,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,gBACA,EAAM;GACJ,WAAW;GACX,YAAY;GACZ,SAAS;GACT,SAAS,CAAC,GAAY,GAAG,CAAW;EACtC,CAAC,CACH;CACF,CAAC,CACH,GAKM,IACJ,EAAS,SAAS,IACd,EACE,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,iBACA,EAAO;GACL,WAAW;GACX,SAAS,EAAO;IACd,WAAW;IACX,MAAM;KAAC,SAAS;KAAW,MAAM;IAAM;IACvC,WAAW;GACb,CAAC;GACD,SAAS,EACP,kBACA,EAAM;IACJ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS,CAAC,GAAY,GAAG,CAAW;GACtC,CAAC,CACH;GACA,uBAAuB;EACzB,CAAC,CACH;CACF,CAAC,CACH,IACA,EACE,gBACA,EAAY;EACV,QAAQ;EACR,SAAS;CACX,CAAC,CACH,GAIA,IAA0B,CAAC;CAIjC,AAHI,EAAM,kBACR,EAAW,KAAK,EAAM,cAAc,GAElC,EAAM,mBACR,EAAW,KAAK,EAAM,eAAe;CAGvC,IAAM,IAA6B,CAAC,GAAY,CAAS;CACzD,AAAI,EAAW,SAAS,KACtB,EAAc,KACZ,EACE,kBACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,SAAS;CACX,CAAC,CACH,CACF;CA6BF,IAAM,IAA2B,CAzBlB,EACb,UACA,EAAI;EACF,WACE;EACF,SAAS;CACX,CAAC,CAmB+B,GAblB,EACd,QACA,EAAI;EACF,WACE;EACF,WAAW,GAAY,MAA0B;GAC/C,IAAM,IAAM,EAAI,QAAQ,EAAM,IAAI;GAClC,OAAO,KAAO,OAA4B,CAAC,IAAtB,CAAC,CAAgB;EACxC;CACF,CAAC,CAIuC,CAAO;CAkBjD,OAdI,KACF,EAAY,KACV,EACE,UACA,EAAI;EACF,WACE;EACF,SAAS,CAAC,CAAM;CAClB,CAAC,CACH,CACF,GAIK,EAAM;EACX,WAAW;EACX,WAAW,+BAA+B,IAAe,IAAI,MAAiB;EAC9E,SAAS,CACP,EACE,QACA,EAAM;GACJ,WAAW;GACX,WAAW;GACX,SAAS;EACX,CAAC,CACH,CACF;CACF,CAAC;AACH;AAIA,EAAiB;CACf,MAAM;CACN,QAAQ;CACR,QAAQ;AACV,CAA8B"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/cards/pageWithNavbarMeta/index.ts"],"sourcesContent":["import {\n registerMetaCard,\n type PiCardDef,\n type PiCardRef,\n type PiMetaProps,\n type PiMetaResolveCtx,\n type PiRegisterMetaCard,\n type RegisterCardF,\n type PiDefCtxtProps,\n type ReduxState,\n type StateMapper,\n type StateMapperContext,\n} from \"@pihanga2/core\";\n\nimport {Stack} from \"@/cards/stack\";\nimport {Box} from \"@/cards/box\";\nimport {Button} from \"@/cards/button\";\nimport {Typography} from \"@/cards/typography\";\nimport {Conditional} from \"@/cards/conditional\";\nimport {Drawer} from \"@/cards/drawer\";\n\nimport {\n PAGE_WITH_NAVBAR_META_ACTION,\n PI_PAGE_WITH_NAVBAR_META_CARD,\n type NavLink,\n type PageWithNavbarMetaDynProps,\n type PageWithNavbarMetaEvents,\n type PageWithNavbarMetaStaticProps,\n} from \"./pageWithNavbarMeta.types\";\n\nexport * from \"./pageWithNavbarMeta.types\";\n\n// ── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction capitalize(s: string): string {\n return s ? s.charAt(0).toLocaleUpperCase() + s.slice(1) : \"\";\n}\n\n/**\n * Resolve a `PiMetaProps`-delivered prop (always a `StateMapper<T>`, per\n * `makeLiveMetaProps` — see `@pihanga2/core`) synchronously, once, at mapper\n * run-time. Only appropriate for props this mapper reads directly in its own\n * body (as opposed to forwarding to a sub-card's own `resolve()`-based state\n * mapper) — i.e. props that control the *shape* of the expansion (how many\n * nav-link buttons, whether a footer/header-action slot exists) rather than\n * a value a sub-card should react to on every render. See the \"reactivity\n * has one hard limit\" note in AGENT.md's metacards guide.\n */\nfunction resolveOnce<T>(\n prop: StateMapper<T, ReduxState, PiDefCtxtProps> | undefined,\n): T | undefined {\n if (typeof prop !== \"function\") return prop;\n return prop({} as ReduxState, {\n cardName: \"\",\n ctxtProps: {},\n resolve: (p: unknown) =>\n typeof p === \"function\"\n ? (p as StateMapper<unknown, ReduxState, PiDefCtxtProps>)(\n {} as ReduxState,\n {cardName: \"\", ctxtProps: {}} as StateMapperContext<PiDefCtxtProps>,\n )\n : p,\n } as StateMapperContext<PiDefCtxtProps>);\n}\n\n// ── Mapper ───────────────────────────────────────────────────────────────────\n\n/**\n * `StaticProps` arrive as their plain types — TypeScript refuses memo selectors.\n * `DynProps` arrive as `StateMapper<T>` functions — must be resolved via `resolve()`.\n */\ntype MapperProps = PiMetaProps<\n PageWithNavbarMetaDynProps,\n PageWithNavbarMetaStaticProps,\n PageWithNavbarMetaEvents\n>;\n\nfunction PageWithNavbarMetaMapper(\n _cardName: string,\n props: MapperProps,\n reg: RegisterCardF,\n): PiCardDef {\n // ── Structural props: read once, synchronously, to decide the SHAPE of the\n // expansion (how many nav-link buttons, whether the footer/header-action\n // slots exist). Per PiMetaProps, every prop — dynamic or static — arrives\n // as a StateMapper; resolveOnce() unwraps it a single time at mapper\n // run-time (the mapper itself only ever runs once, so these can't become\n // reactive regardless — see AGENT.md's metacards guide).\n const navLinks = resolveOnce(props.navLinks) ?? [];\n const iconName = resolveOnce(props.iconName);\n const wrapperClass = resolveOnce(props.className);\n const footer = resolveOnce(props.footer);\n\n // ── Title (icon + text) ─────────────────────────────────────────────────\n // props.title is StateMapper<string> — a function, NOT a string.\n // Typography's `text` prop is typed (via PiMapProps) as `string | StateMapper<string>`,\n // so we forward the selector function directly. The framework resolves it lazily\n // (calls props.title(state, ctx)) when Typography renders. This is different from\n // using props.title as a string, which TypeScript would reject.\n const titleContent: PiCardRef[] = [];\n if (iconName) {\n titleContent.push(\n Button({\n iconLabel: iconName,\n opts: {variant: \"none\", size: \"icon\"},\n className: \"h-6 w-6 shrink-0 pointer-events-none\",\n }),\n );\n }\n titleContent.push(\n Typography({\n text: props.title,\n level: \"large\",\n className: \"leading-none\",\n }),\n );\n\n const titleStack = reg(\n \"title\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 2,\n content: titleContent,\n }),\n );\n\n // ── Nav link buttons (shared between desktop and mobile) ────────────────\n const linkButtons = navLinks.map((link: NavLink, i: number) =>\n reg(\n `nav-link-${i}`,\n Button({\n id: link.id,\n label: link.title ?? capitalize(link.id),\n opts: {variant: \"ghost\"},\n className:\n \"px-0 text-muted-foreground hover:text-foreground h-auto p-0\",\n onClickedMapper: () => ({\n type: PAGE_WITH_NAVBAR_META_ACTION.NAVIGATE_TO,\n id: link.id,\n }),\n }),\n ),\n );\n\n // ── Desktop nav (md+): title + links in a row ───────────────────────────\n const desktopNav = reg(\n \"nav-md\",\n Conditional({\n showOn: \"md\",\n content: reg(\n \"nav-md-inner\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n spacing: 5,\n content: [titleStack, ...linkButtons],\n }),\n ),\n }),\n );\n\n // ── Mobile nav (< md) ───────────────────────────────────────────────────\n // With nav links: hamburger drawer (left slide-in using pi/drawer).\n // Without nav links: just show the title inline.\n const mobileNav: PiCardRef =\n navLinks.length > 0\n ? reg(\n \"nav-sm\",\n Conditional({\n showOn: \"<md\",\n content: reg(\n \"nav-sm-drawer\",\n Drawer({\n direction: \"left\",\n trigger: Button({\n iconLabel: \"menu\",\n opts: {variant: \"outline\", size: \"icon\"},\n ariaLabel: \"Toggle navigation menu\",\n }),\n content: reg(\n \"nav-sm-content\",\n Stack({\n direction: \"column\",\n spacing: 4,\n className: \"p-4\",\n content: [titleStack, ...linkButtons],\n }),\n ),\n footerCloseButtonText: null,\n }),\n ),\n }),\n )\n : reg(\n \"nav-sm-title\",\n Conditional({\n showOn: \"<md\",\n content: titleStack,\n }),\n );\n\n // ── Header action slots ─────────────────────────────────────────────────\n // Structural — decide whether the action-slot Stack exists at all — so\n // read once, synchronously, like the other shape-controlling props above.\n const headerLeftCard = resolveOnce(props.headerLeftCard);\n const headerRightCard = resolveOnce(props.headerRightCard);\n const actionRefs: PiCardRef[] = [];\n if (headerLeftCard) {\n actionRefs.push(headerLeftCard);\n }\n if (headerRightCard) {\n actionRefs.push(headerRightCard);\n }\n\n const headerContent: PiCardRef[] = [desktopNav, mobileNav];\n if (actionRefs.length > 0) {\n headerContent.push(\n reg(\n \"header-actions\",\n Stack({\n direction: \"row\",\n alignItems: \"center\",\n className: \"ml-auto gap-2 lg:gap-4\",\n content: actionRefs,\n }),\n ),\n );\n }\n\n // ── Header ──────────────────────────────────────────────────────────────\n const header = reg(\n \"header\",\n Box({\n className:\n \"shrink-0 flex items-center gap-4 border-b bg-background px-4 md:px-6\",\n content: headerContent,\n }),\n );\n\n // ── Main ────────────────────────────────────────────────────────────────\n // props.main is a StateMapper — resolved lazily so React re-renders when\n // the referenced card changes.\n const mainBox = reg(\n \"main\",\n Box({\n className:\n \"flex-1 min-h-0 overflow-y-auto bg-background p-4 py-2 md:p-8 md:py-4\",\n content: ((_: unknown, ctx: PiMetaResolveCtx) => {\n const ref = ctx.resolve(props.main);\n return ref != null ? [ref as PiCardRef] : [];\n }) as unknown as PiCardRef[],\n }),\n );\n\n // ── Page column ─────────────────────────────────────────────────────────\n const pageContent: PiCardRef[] = [header, mainBox];\n\n // ── Footer (optional) ───────────────────────────────────────────────────\n // `footer` is a static plain PiCardRef — use directly.\n if (footer) {\n pageContent.push(\n reg(\n \"footer\",\n Box({\n className:\n \"shrink-0 bg-background text-muted-foreground px-4 py-2 md:px-8 md:py-4\",\n content: [footer],\n }),\n ),\n );\n }\n\n // ── Assemble ────────────────────────────────────────────────────────────\n return Stack({\n direction: \"row\",\n className: `w-full h-full justify-center${wrapperClass ? ` ${wrapperClass}` : \"\"}`,\n content: [\n reg(\n \"page\",\n Stack({\n direction: \"column\",\n className: \"flex-1 h-full w-full\",\n content: pageContent,\n }),\n ),\n ],\n });\n}\n\n// ── Registration ─────────────────────────────────────────────────────────────\n\nregisterMetaCard({\n type: PI_PAGE_WITH_NAVBAR_META_CARD,\n mapper: PageWithNavbarMetaMapper,\n events: PAGE_WITH_NAVBAR_META_ACTION,\n} satisfies PiRegisterMetaCard);\n"],"mappings":";;;;;;;;;;;;;;;AAkCA,SAAS,EAAW,GAAmB;CACrC,OAAO,IAAI,EAAE,OAAO,CAAC,EAAE,kBAAkB,IAAI,EAAE,MAAM,CAAC,IAAI;AAC5D;AAYA,SAAS,EACP,GACe;CAEf,OADI,OAAO,KAAS,aACb,EAAK,CAAC,GAAiB;EAC5B,UAAU;EACV,WAAW,CAAC;EACZ,UAAU,MACR,OAAO,KAAM,aACR,EACC,CAAC,GACD;GAAC,UAAU;GAAI,WAAW,CAAC;EAAC,CAC9B,IACA;CACR,CAAuC,IAXA;AAYzC;AAcA,SAAS,EACP,GACA,GACA,GACW;CAOX,IAAM,IAAW,EAAY,EAAM,QAAQ,KAAK,CAAC,GAC3C,IAAW,EAAY,EAAM,QAAQ,GACrC,IAAe,EAAY,EAAM,SAAS,GAC1C,IAAS,EAAY,EAAM,MAAM,GAQjC,IAA4B,CAAC;CAUnC,AATI,KACF,EAAa,KACX,EAAO;EACL,WAAW;EACX,MAAM;GAAC,SAAS;GAAQ,MAAM;EAAM;EACpC,WAAW;CACb,CAAC,CACH,GAEF,EAAa,KACX,EAAW;EACT,MAAM,EAAM;EACZ,OAAO;EACP,WAAW;CACb,CAAC,CACH;CAEA,IAAM,IAAa,EACjB,SACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,SAAS;EACT,SAAS;CACX,CAAC,CACH,GAGM,IAAc,EAAS,KAAK,GAAe,MAC/C,EACE,YAAY,KACZ,EAAO;EACL,IAAI,EAAK;EACT,OAAO,EAAK,SAAS,EAAW,EAAK,EAAE;EACvC,MAAM,EAAC,SAAS,QAAO;EACvB,WACE;EACF,wBAAwB;GACtB,MAAM,EAA6B;GACnC,IAAI,EAAK;EACX;CACF,CAAC,CACH,CACF,GAGM,IAAa,EACjB,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,gBACA,EAAM;GACJ,WAAW;GACX,YAAY;GACZ,SAAS;GACT,SAAS,CAAC,GAAY,GAAG,CAAW;EACtC,CAAC,CACH;CACF,CAAC,CACH,GAKM,IACJ,EAAS,SAAS,IACd,EACE,UACA,EAAY;EACV,QAAQ;EACR,SAAS,EACP,iBACA,EAAO;GACL,WAAW;GACX,SAAS,EAAO;IACd,WAAW;IACX,MAAM;KAAC,SAAS;KAAW,MAAM;IAAM;IACvC,WAAW;GACb,CAAC;GACD,SAAS,EACP,kBACA,EAAM;IACJ,WAAW;IACX,SAAS;IACT,WAAW;IACX,SAAS,CAAC,GAAY,GAAG,CAAW;GACtC,CAAC,CACH;GACA,uBAAuB;EACzB,CAAC,CACH;CACF,CAAC,CACH,IACA,EACE,gBACA,EAAY;EACV,QAAQ;EACR,SAAS;CACX,CAAC,CACH,GAKA,IAAiB,EAAY,EAAM,cAAc,GACjD,IAAkB,EAAY,EAAM,eAAe,GACnD,IAA0B,CAAC;CAIjC,AAHI,KACF,EAAW,KAAK,CAAc,GAE5B,KACF,EAAW,KAAK,CAAe;CAGjC,IAAM,IAA6B,CAAC,GAAY,CAAS;CACzD,AAAI,EAAW,SAAS,KACtB,EAAc,KACZ,EACE,kBACA,EAAM;EACJ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,SAAS;CACX,CAAC,CACH,CACF;CA6BF,IAAM,IAA2B,CAzBlB,EACb,UACA,EAAI;EACF,WACE;EACF,SAAS;CACX,CAAC,CAmB+B,GAblB,EACd,QACA,EAAI;EACF,WACE;EACF,WAAW,GAAY,MAA0B;GAC/C,IAAM,IAAM,EAAI,QAAQ,EAAM,IAAI;GAClC,OAAO,KAAO,OAA4B,CAAC,IAAtB,CAAC,CAAgB;EACxC;CACF,CAAC,CAIuC,CAAO;CAkBjD,OAdI,KACF,EAAY,KACV,EACE,UACA,EAAI;EACF,WACE;EACF,SAAS,CAAC,CAAM;CAClB,CAAC,CACH,CACF,GAIK,EAAM;EACX,WAAW;EACX,WAAW,+BAA+B,IAAe,IAAI,MAAiB;EAC9E,SAAS,CACP,EACE,QACA,EAAM;GACJ,WAAW;GACX,WAAW;GACX,SAAS;EACX,CAAC,CACH,CACF;CACF,CAAC;AACH;AAIA,EAAiB;CACf,MAAM;CACN,QAAQ;CACR,QAAQ;AACV,CAA8B"}
|