@alfadocs/ui-kit-debug 1.101.0 → 1.102.0
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/dist/_chunks/{calendar-appointment-editor-dialog-CUJMnFL7.js → calendar-appointment-editor-dialog-EYyVorFR.js} +3 -3
- package/dist/_chunks/{calendar-appointment-editor-dialog-CUJMnFL7.js.map → calendar-appointment-editor-dialog-EYyVorFR.js.map} +1 -1
- package/dist/_chunks/{care-plan-header-BBh0X7EO.js → care-plan-header-lROoTjYn.js} +2 -2
- package/dist/_chunks/{care-plan-header-BBh0X7EO.js.map → care-plan-header-lROoTjYn.js.map} +1 -1
- package/dist/_chunks/{contact-profile-card-CFAhByRk.js → contact-profile-card-D0KqxoE5.js} +37 -35
- package/dist/_chunks/{contact-profile-card-CFAhByRk.js.map → contact-profile-card-D0KqxoE5.js.map} +1 -1
- package/dist/_chunks/{key-value-pair-BoXOtBL1.js → key-value-pair-CB37UXsz.js} +43 -28
- package/dist/_chunks/key-value-pair-CB37UXsz.js.map +1 -0
- package/dist/_chunks/{patient-summary-card-CL04aq8h.js → patient-summary-card-B1jvxdY8.js} +2 -2
- package/dist/_chunks/{patient-summary-card-CL04aq8h.js.map → patient-summary-card-B1jvxdY8.js.map} +1 -1
- package/dist/_chunks/{payment-request-card-BbpN8GQg.js → payment-request-card-DPN5yklX.js} +2 -2
- package/dist/_chunks/{payment-request-card-BbpN8GQg.js.map → payment-request-card-DPN5yklX.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-Cw-ZsIls.js → periodontal-chart-X4_4WPK8.js} +2 -2
- package/dist/_chunks/{periodontal-chart-Cw-ZsIls.js.map → periodontal-chart-X4_4WPK8.js.map} +1 -1
- package/dist/_chunks/{periodontal-chart-card-CG8mxR62.js → periodontal-chart-card-BzL3YkEW.js} +2 -2
- package/dist/_chunks/{periodontal-chart-card-CG8mxR62.js.map → periodontal-chart-card-BzL3YkEW.js.map} +1 -1
- package/dist/_chunks/{specialty-icon-KuovHTxh.js → specialty-icon-BkpExzMh.js} +2 -1
- package/dist/_chunks/{specialty-icon-KuovHTxh.js.map → specialty-icon-BkpExzMh.js.map} +1 -1
- package/dist/_chunks/specialty-list-BzalHR8_.js +100 -0
- package/dist/_chunks/specialty-list-BzalHR8_.js.map +1 -0
- package/dist/_chunks/{use-appointment-details-read-BbIoPWO6.js → use-appointment-details-read-BNtTap_B.js} +2 -2
- package/dist/_chunks/{use-appointment-details-read-BbIoPWO6.js.map → use-appointment-details-read-BNtTap_B.js.map} +1 -1
- package/dist/_chunks/{workflow-map-k-dQkpe7.js → workflow-map-Dm27iPKB.js} +2 -2
- package/dist/_chunks/{workflow-map-k-dQkpe7.js.map → workflow-map-Dm27iPKB.js.map} +1 -1
- package/dist/agent-catalog.json +1 -1
- package/dist/components/appointment-details-panel/index.js +1 -1
- package/dist/components/care-plan-header/index.js +1 -1
- package/dist/components/contact-profile-card/contact-profile-card.d.ts.map +1 -1
- package/dist/components/contact-profile-card/index.js +1 -1
- package/dist/components/key-value-pair/index.js +1 -1
- package/dist/components/key-value-pair/key-value-pair.d.ts.map +1 -1
- package/dist/components/patient-summary-card/index.js +1 -1
- package/dist/components/payment-card/index.js +1 -1
- package/dist/components/periodontal-chart/index.js +1 -1
- package/dist/components/periodontal-chart-card/index.js +1 -1
- package/dist/components/specialty-icon/index.js +1 -1
- package/dist/components/specialty-icon/specialty-icon.d.ts.map +1 -1
- package/dist/components/specialty-list/index.js +1 -1
- package/dist/components/specialty-list/specialty-list.d.ts.map +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/core.css +1 -1
- package/dist/index.js +12 -12
- package/dist/patterns/calendar/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/key-value-pair-BoXOtBL1.js.map +0 -1
- package/dist/_chunks/specialty-list-urUQJLk3.js +0 -67
- package/dist/_chunks/specialty-list-urUQJLk3.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as a, jsxs as
|
|
1
|
+
import { jsx as a, jsxs as r, Fragment as f } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as h, useState as y, useCallback as K } from "react";
|
|
3
3
|
import { c as v } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as T } from "react-i18next";
|
|
@@ -50,8 +50,8 @@ const B = v(
|
|
|
50
50
|
), L = v("ds:flex", {
|
|
51
51
|
variants: {
|
|
52
52
|
layout: {
|
|
53
|
-
horizontal: "
|
|
54
|
-
vertical: "
|
|
53
|
+
horizontal: "",
|
|
54
|
+
vertical: ""
|
|
55
55
|
},
|
|
56
56
|
/** Internal — flips the root to a horizontal flex when an icon
|
|
57
57
|
is present so the icon can sit at the leading edge of both
|
|
@@ -62,6 +62,21 @@ const B = v(
|
|
|
62
62
|
false: ""
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
|
+
// Direction and gap are set once per combination: a vertical row with an
|
|
66
|
+
// icon used to carry both `gap-xs` and `gap-sm`, and CSS order picked the
|
|
67
|
+
// 4px one, so its label sat closer to the icon than intended.
|
|
68
|
+
compoundVariants: [
|
|
69
|
+
{
|
|
70
|
+
layout: "horizontal",
|
|
71
|
+
hasIcon: !1,
|
|
72
|
+
class: "ds:flex-row ds:items-center ds:gap-[var(--spacing-sm)]"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
layout: "vertical",
|
|
76
|
+
hasIcon: !1,
|
|
77
|
+
class: "ds:flex-col ds:gap-[var(--spacing-xs)]"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
65
80
|
defaultVariants: {
|
|
66
81
|
layout: "horizontal",
|
|
67
82
|
hasIcon: !1
|
|
@@ -69,42 +84,42 @@ const B = v(
|
|
|
69
84
|
}), S = h(
|
|
70
85
|
({
|
|
71
86
|
label: t,
|
|
72
|
-
labelNode:
|
|
87
|
+
labelNode: i,
|
|
73
88
|
value: e,
|
|
74
89
|
layout: s = "horizontal",
|
|
75
|
-
alignValue:
|
|
90
|
+
alignValue: o = "start",
|
|
76
91
|
mono: g = !1,
|
|
77
92
|
copyable: k = !1,
|
|
78
93
|
copyText: x,
|
|
79
94
|
icon: d,
|
|
80
95
|
className: V,
|
|
81
|
-
...
|
|
82
|
-
},
|
|
83
|
-
const { t:
|
|
96
|
+
...z
|
|
97
|
+
}, C) => {
|
|
98
|
+
const { t: n } = T("ui"), [N, u] = y(!1), [b, l] = y(""), c = x ?? (typeof e == "string" ? e : void 0), w = K(async () => {
|
|
84
99
|
if (c)
|
|
85
100
|
try {
|
|
86
|
-
await navigator.clipboard.writeText(c), u(!0),
|
|
87
|
-
u(!1),
|
|
101
|
+
await navigator.clipboard.writeText(c), u(!0), l(n("keyValuePair.copied")), setTimeout(() => {
|
|
102
|
+
u(!1), l("");
|
|
88
103
|
}, 2e3);
|
|
89
104
|
} catch {
|
|
90
|
-
|
|
105
|
+
l(n("keyValuePair.notAvailable")), setTimeout(() => l(""), 3e3);
|
|
91
106
|
}
|
|
92
|
-
}, [c,
|
|
107
|
+
}, [c, n]), I = B({
|
|
93
108
|
layout: s,
|
|
94
|
-
alignValue:
|
|
109
|
+
alignValue: o,
|
|
95
110
|
mono: g
|
|
96
|
-
}), m = d != null,
|
|
97
|
-
/* @__PURE__ */
|
|
98
|
-
|
|
111
|
+
}), m = d != null, P = "ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:min-w-0 ds:flex-1", p = /* @__PURE__ */ r(f, { children: [
|
|
112
|
+
/* @__PURE__ */ r("span", { className: "type-label ds:text-muted-foreground ds:shrink-0", children: [
|
|
113
|
+
i ?? t,
|
|
99
114
|
/* @__PURE__ */ a("span", { className: "ds:sr-only", children: ": " })
|
|
100
115
|
] }),
|
|
101
|
-
/* @__PURE__ */ a("span", { className:
|
|
116
|
+
/* @__PURE__ */ a("span", { className: I, children: e }),
|
|
102
117
|
k && /* @__PURE__ */ a(
|
|
103
118
|
j,
|
|
104
119
|
{
|
|
105
120
|
icon: N ? /* @__PURE__ */ a(_, {}) : /* @__PURE__ */ a(A, {}),
|
|
106
121
|
size: "sm",
|
|
107
|
-
"aria-label":
|
|
122
|
+
"aria-label": n("keyValuePair.copy", { label: t }),
|
|
108
123
|
onClick: w,
|
|
109
124
|
intent: "ghost",
|
|
110
125
|
className: s === "horizontal" ? (
|
|
@@ -113,21 +128,21 @@ const B = v(
|
|
|
113
128
|
// own `ms-auto`; a second auto margin here would split
|
|
114
129
|
// the free space between them and strand the value in
|
|
115
130
|
// the middle of the row instead of at its end.
|
|
116
|
-
|
|
131
|
+
o === "end" ? "ds:shrink-0" : "ds:ms-auto ds:shrink-0"
|
|
117
132
|
) : "ds:self-start"
|
|
118
133
|
}
|
|
119
134
|
)
|
|
120
135
|
] });
|
|
121
|
-
return /* @__PURE__ */
|
|
136
|
+
return /* @__PURE__ */ r(
|
|
122
137
|
"div",
|
|
123
138
|
{
|
|
124
|
-
ref:
|
|
139
|
+
ref: C,
|
|
125
140
|
className: L({ layout: s, hasIcon: m, className: V }),
|
|
126
141
|
"data-component": "key-value-pair",
|
|
127
142
|
"data-has-icon": m ? "" : void 0,
|
|
128
|
-
...
|
|
143
|
+
...z,
|
|
129
144
|
children: [
|
|
130
|
-
m ? /* @__PURE__ */
|
|
145
|
+
m ? /* @__PURE__ */ r(f, { children: [
|
|
131
146
|
/* @__PURE__ */ a(
|
|
132
147
|
"span",
|
|
133
148
|
{
|
|
@@ -136,7 +151,7 @@ const B = v(
|
|
|
136
151
|
children: d
|
|
137
152
|
}
|
|
138
153
|
),
|
|
139
|
-
s === "horizontal" ? p : /* @__PURE__ */ a("div", { className:
|
|
154
|
+
s === "horizontal" ? p : /* @__PURE__ */ a("div", { className: P, children: p })
|
|
140
155
|
] }) : p,
|
|
141
156
|
/* @__PURE__ */ a("span", { role: "status", "aria-live": "polite", className: "ds:sr-only", children: b })
|
|
142
157
|
]
|
|
@@ -150,10 +165,10 @@ const F = {
|
|
|
150
165
|
md: "ds:gap-y-[var(--spacing-md)]",
|
|
151
166
|
lg: "ds:gap-y-[var(--spacing-lg)]"
|
|
152
167
|
}, G = h(
|
|
153
|
-
({ children: t, className:
|
|
168
|
+
({ children: t, className: i, rowGap: e = "md", ...s }, o) => /* @__PURE__ */ a(
|
|
154
169
|
"div",
|
|
155
170
|
{
|
|
156
|
-
ref:
|
|
171
|
+
ref: o,
|
|
157
172
|
"data-component": "key-value-list",
|
|
158
173
|
className: [
|
|
159
174
|
// The label track reads a custom property, and an icon list only
|
|
@@ -180,7 +195,7 @@ const F = {
|
|
|
180
195
|
// `[gap:normal]` is the subgrid-spec way to defer to the
|
|
181
196
|
// parent.
|
|
182
197
|
'ds:[&>[data-component="key-value-pair"]]:[gap:normal]',
|
|
183
|
-
|
|
198
|
+
i
|
|
184
199
|
].filter(Boolean).join(" "),
|
|
185
200
|
...s,
|
|
186
201
|
children: t
|
|
@@ -192,4 +207,4 @@ export {
|
|
|
192
207
|
G as K,
|
|
193
208
|
S as a
|
|
194
209
|
};
|
|
195
|
-
//# sourceMappingURL=key-value-pair-
|
|
210
|
+
//# sourceMappingURL=key-value-pair-CB37UXsz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-value-pair-CB37UXsz.js","sources":["../../src/components/key-value-pair/key-value-pair.tsx"],"sourcesContent":["import { forwardRef, useState, useCallback, type HTMLAttributes } from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Copy, Check } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\n\n/* ------------------------------------------------------------------ */\n/* CVA — root wrapper */\n/* */\n/* The layout variants below describe the LOGICAL flow of label/value. */\n/* When an `icon` prop is supplied, the root flips to `flex-row` and */\n/* renders the icon at the leading edge regardless of the chosen */\n/* layout — the layout then governs the inner label/value stack. Cap- */\n/* height alignment is handled by `items-start` + a small `mt` offset */\n/* on the icon wrapper so a wrapping value doesn't push the icon */\n/* downward. */\n/* ------------------------------------------------------------------ */\n\n/* ------------------------------------------------------------------ */\n/* CVA — value cell */\n/* */\n/* `alignValue` decides whether the value starts beside the label or */\n/* is pinned to the inline-end of the row. Pinning matters when a */\n/* column of rows carries one comparable figure (a price, a count): */\n/* left where it falls, its position shifts with the label width and */\n/* the eye can't run down it. */\n/* */\n/* Standalone, the value is a flex sibling — `start` lets it absorb */\n/* the free space, `end` pushes it over with an auto inline margin. */\n/* Inside a `<KeyValueList>` the value is a grid item in the third */\n/* track (`minmax(0,1fr)`), where the same auto margin pins it to the */\n/* track's end. One pair of classes covers both. */\n/* */\n/* Horizontal only. In `vertical` the value already sits below the */\n/* label with nothing to pin against, so `alignValue` is a documented */\n/* no-op there rather than a surprise. */\n/* ------------------------------------------------------------------ */\n\nconst keyValuePairValueVariants = cva(\n 'type-body ds:text-foreground ds:min-w-0 ds:[unicode-bidi:isolate]',\n {\n variants: {\n layout: {\n horizontal: '',\n vertical: 'ds:shrink',\n },\n alignValue: {\n start: '',\n end: '',\n },\n mono: {\n true: 'ds:font-[family-name:var(--font-mono)]',\n false: '',\n },\n },\n compoundVariants: [\n // `flex-1` lets the value absorb the remaining inline space when\n // the KVP root flexes icon / label / value as direct siblings.\n // Without it the value shrinks to its content width and the row\n // leaves inline-end whitespace.\n {\n layout: 'horizontal',\n alignValue: 'start',\n class: 'ds:flex-1 ds:shrink',\n },\n // Pinned: drop `flex-1` so the cell is content-width, then let an\n // auto inline-start margin eat the slack. `ms-*` is the logical\n // spelling, so this flips correctly in a right-to-left locale.\n {\n layout: 'horizontal',\n alignValue: 'end',\n class: 'ds:ms-auto ds:shrink-0',\n },\n ],\n defaultVariants: {\n layout: 'horizontal',\n alignValue: 'start',\n mono: false,\n },\n },\n);\n\nconst keyValuePairVariants = cva('ds:flex', {\n variants: {\n layout: {\n horizontal: '',\n vertical: '',\n },\n /** Internal — flips the root to a horizontal flex when an icon\n is present so the icon can sit at the leading edge of both\n horizontal and vertical inner stacks. `items-start` keeps the\n icon anchored to the label row even when the value wraps. */\n hasIcon: {\n true: 'ds:flex-row ds:items-start ds:gap-[var(--spacing-sm)]',\n false: '',\n },\n },\n // Direction and gap are set once per combination: a vertical row with an\n // icon used to carry both `gap-xs` and `gap-sm`, and CSS order picked the\n // 4px one, so its label sat closer to the icon than intended.\n compoundVariants: [\n {\n layout: 'horizontal',\n hasIcon: false,\n class: 'ds:flex-row ds:items-center ds:gap-[var(--spacing-sm)]',\n },\n {\n layout: 'vertical',\n hasIcon: false,\n class: 'ds:flex-col ds:gap-[var(--spacing-xs)]',\n },\n ],\n defaultVariants: {\n layout: 'horizontal',\n hasIcon: false,\n },\n});\n\n/* ------------------------------------------------------------------ */\n/* KeyValuePairProps */\n/* ------------------------------------------------------------------ */\n\nexport interface KeyValuePairProps\n extends\n React.HTMLAttributes<HTMLDivElement>,\n Omit<VariantProps<typeof keyValuePairVariants>, 'hasIcon'> {\n /** The label (term). Stays a string: it is interpolated into the copy\n * button's accessible name, where a node would render \"[object Object]\". */\n label: string;\n /**\n * Display-only override for the rendered label — a node when the term needs\n * more than text (a PHI lock beside it, a badge). `label` is still required\n * and remains the string every accessible name is built from.\n */\n labelNode?: React.ReactNode;\n /** The value — accepts plain text, Badge, Tag, monospace code, any ReactNode */\n value: React.ReactNode;\n /** Layout direction */\n layout?: 'horizontal' | 'vertical';\n /** Render value in monospace font */\n mono?: boolean;\n /**\n * Where the value sits on the row.\n *\n * `start` (default) keeps the existing behaviour — the value begins\n * immediately after the label and absorbs the remaining width.\n *\n * `end` pins the value to the inline-end of the row, so its position\n * no longer moves with the label's length. Use it for the one\n * comparable figure in a list of rows — a price, a count, a score —\n * where a reader wants to scan down a column rather than read each\n * line. Pinning every row defeats the point.\n *\n * Horizontal layout only: in `vertical` the value already sits below\n * the label, so there is nothing to pin against and this is ignored.\n */\n alignValue?: 'start' | 'end';\n /** Show a copy-to-clipboard IconButton beside the value */\n copyable?: boolean;\n /** The text to copy — defaults to `value` if value is a string */\n copyText?: string;\n /**\n * Optional decorative icon rendered at the leading edge of the pair.\n * Pass a `lucide-react` icon (or any single React element) for\n * visual consistency. The wrapper applies `aria-hidden=\"true\"` and\n * paints the icon with `var(--key-value-pair-icon-color)` (defaults\n * to `--muted-foreground`); consumers can recolour the slot via\n * that token without forking the component.\n *\n * Cap-height alignment with the label is automatic — the wrapper\n * uses `mt-0.5` so the glyph rides the label row, not the\n * geometric centre of a wrapping value.\n *\n * Type is `ReactElement` (not the broader `ReactNode`) so the\n * intent is clear at the call site: this slot is for a single\n * SVG/icon, not arbitrary fragments, strings, or numbers.\n */\n icon?: React.ReactElement | null;\n}\n\n/* ------------------------------------------------------------------ */\n/* KeyValuePair */\n/* ------------------------------------------------------------------ */\n\nexport const KeyValuePair = forwardRef<HTMLDivElement, KeyValuePairProps>(\n (\n {\n label,\n labelNode,\n value,\n layout = 'horizontal',\n alignValue = 'start',\n mono = false,\n copyable = false,\n copyText,\n icon,\n className,\n ...props\n },\n ref,\n ) => {\n const { t } = useTranslation('ui');\n const [copied, setCopied] = useState(false);\n const [announcement, setAnnouncement] = useState('');\n\n const textToCopy =\n copyText ?? (typeof value === 'string' ? value : undefined);\n\n const handleCopy = useCallback(async () => {\n if (!textToCopy) {\n if (import.meta.env.DEV) {\n console.warn(\n 'KeyValuePair: copyable is true but no copyText was provided and value is not a string. Copy no-op.',\n );\n }\n return;\n }\n\n try {\n await navigator.clipboard.writeText(textToCopy);\n setCopied(true);\n setAnnouncement(t('keyValuePair.copied'));\n setTimeout(() => {\n setCopied(false);\n setAnnouncement('');\n }, 2000);\n } catch {\n setAnnouncement(t('keyValuePair.notAvailable'));\n setTimeout(() => setAnnouncement(''), 3000);\n }\n }, [textToCopy, t]);\n\n const valueClasses = keyValuePairValueVariants({\n layout,\n alignValue,\n mono,\n });\n\n const hasIcon = icon !== undefined && icon !== null;\n\n // Inner stack — used ONLY for `layout=\"vertical\"` when an icon is\n // present (icon on the leading edge, label-on-top-of-value stacked\n // next to it). For `layout=\"horizontal\"` we render the icon /\n // label / value as direct flex children of the root — wrapping\n // them in a single `<div>` would break the KeyValueList subgrid\n // (the subgrid's 3 tracks would collapse to 2: the wrapper +\n // icon). See the conditional below.\n const innerStackClass =\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:min-w-0 ds:flex-1';\n\n const stack = (\n <>\n <span className=\"type-label ds:text-muted-foreground ds:shrink-0\">\n {labelNode ?? label}\n <span className=\"ds:sr-only\">: </span>\n </span>\n <span className={valueClasses}>{value}</span>\n {copyable && (\n <IconButton\n icon={copied ? <Check /> : <Copy />}\n size=\"sm\"\n aria-label={t('keyValuePair.copy', { label })}\n onClick={handleCopy}\n intent=\"ghost\"\n className={\n layout === 'horizontal'\n ? // Only one element on the row may claim the slack. When\n // the value is pinned it has already taken it with its\n // own `ms-auto`; a second auto margin here would split\n // the free space between them and strand the value in\n // the middle of the row instead of at its end.\n alignValue === 'end'\n ? 'ds:shrink-0'\n : 'ds:ms-auto ds:shrink-0'\n : 'ds:self-start'\n }\n />\n )}\n </>\n );\n\n return (\n <div\n ref={ref}\n className={keyValuePairVariants({ layout, hasIcon, className })}\n data-component=\"key-value-pair\"\n data-has-icon={hasIcon ? '' : undefined}\n {...props}\n >\n {hasIcon ? (\n <>\n {/* Decorative icon wrapper. `aria-hidden` so SR users only\n hear \"<label>: <value>\" — the icon is brand polish,\n not semantic content.\n\n `translate-y` shifts the icon down by 2px visually so\n its centre lines up with the label's x-height centre.\n In a baseline-aligned subgrid row, the icon's margin-\n box bottom pins to the label's text baseline — that\n leaves the 16px SVG sitting visually 3-4px above the\n label's centre. `translate-y` adjusts only the paint\n position; the underlying baseline math still holds,\n so multi-line value cells (e.g. address + map link)\n stay correctly aligned with the FIRST line of the\n value. */}\n <span\n aria-hidden=\"true\"\n className=\"ds:inline-flex ds:shrink-0 ds:translate-y-0.5 ds:text-[color:var(--key-value-pair-icon-color)] ds:[&_svg]:size-4\"\n >\n {icon}\n </span>\n {/* `horizontal` layout: render label / value / copy as\n direct flex children of the root so each piece falls\n into its own track when this KVP is promoted to a\n subgrid row by `<KeyValueList>`. Wrapping them in a\n `<div>` here would collapse the subgrid's 3 tracks\n (icon | label | value) to 2 (icon | wrapper) and labels\n across rows would no longer share a column. The root's\n `flex flex-row` + `gap-sm` keeps the standalone visual\n identical.\n\n `vertical` layout still needs the wrapper because the\n stack is column-flow — label-on-top-of-value next to\n the icon. */}\n {layout === 'horizontal' ? (\n stack\n ) : (\n <div className={innerStackClass}>{stack}</div>\n )}\n </>\n ) : (\n stack\n )}\n <span role=\"status\" aria-live=\"polite\" className=\"ds:sr-only\">\n {announcement}\n </span>\n </div>\n );\n },\n);\n\nKeyValuePair.displayName = 'KeyValuePair';\n\n/* ------------------------------------------------------------------ */\n/* KeyValueList — subgrid alignment for a column of KVP rows */\n/* */\n/* When several `<KeyValuePair>` rows live in the same card (practice */\n/* profile, settings panel, contact card, etc.), the per-row flex */\n/* layout means each row's label column has a different width. The */\n/* values end up zigzagged. Wrapping in `<KeyValueList>` puts all rows */\n/* into a single 3-column CSS subgrid (icon | label | value), so */\n/* labels share a column across rows and values start at the same */\n/* inline-start edge. */\n/* */\n/* Standalone `<KeyValuePair>` instances outside a `<KeyValueList>` */\n/* keep their existing per-row flex layout — no behaviour change for */\n/* consumers that didn't opt in. */\n/* ------------------------------------------------------------------ */\n\nexport interface KeyValueListProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Gap between rows. Maps to spacing tokens — defaults to `md`.\n * Smaller gaps suit dense settings panels; larger gaps suit\n * profile cards.\n */\n rowGap?: 'sm' | 'md' | 'lg';\n}\n\nconst rowGapClassMap: Record<\n NonNullable<KeyValueListProps['rowGap']>,\n string\n> = {\n sm: 'ds:gap-y-[var(--spacing-sm)]',\n md: 'ds:gap-y-[var(--spacing-md)]',\n lg: 'ds:gap-y-[var(--spacing-lg)]',\n};\n\nexport const KeyValueList = forwardRef<HTMLDivElement, KeyValueListProps>(\n ({ children, className, rowGap = 'md', ...props }, ref) => {\n // Three-column subgrid: icon | label | value.\n // - col 1: `auto` — width of the widest icon (or 0 if no rows have icons)\n // - col 2: `auto` — width of the widest label, shared across all rows.\n // When rows have icons the label sits here, beside a `1fr` value,\n // so a long one-line label (Albanian \"Me përvojë me pacientët e\n // ankthshëm\") took the whole width and left the value about 3px\n // on a phone. A list with icon rows caps it at `fit-content(40%)`\n // so the label wraps instead. Without icons the label and value\n // share the two `auto` tracks, which shrink together, so nothing\n // changes there.\n // - col 3: `minmax(0, 1fr)` — value flexes; `minmax` prevents the\n // value from forcing the grid wider than its container when the\n // value contains a long unbroken string (e.g. an email or URL).\n //\n // Each child `<KeyValuePair>` (which renders as a `<div>` with a\n // `data-component=\"key-value-pair\"` marker) is promoted into a\n // subgrid row by the CSS below — the cell boundaries align across\n // every direct child.\n //\n // We render as `<div>` (not `<dl>`): axe enforces \"dl can only\n // contain dt/dd\" and the inner KVP renders as a `<div>`. The KVP's\n // own SR markup (label + `<span class=\"sr-only\">: </span>` + value)\n // already conveys term-value semantics — wrapping in a `<dl>`\n // doesn't add anything the screen reader doesn't already get.\n return (\n <div\n ref={ref}\n data-component=\"key-value-list\"\n className={[\n // The label track reads a custom property, and an icon list only\n // sets that property: it never re-declares the template, so a\n // host's own column layout (PatientSummaryCard's two fields per\n // row from 672px) still wins exactly as before.\n 'ds:grid ds:grid-cols-[auto_var(--kvl-label-track,auto)_minmax(0,1fr)]',\n 'ds:has-[>[data-has-icon]]:[--kvl-label-track:fit-content(40%)]',\n 'ds:gap-x-[var(--spacing-md)]',\n rowGapClassMap[rowGap],\n // Each direct `data-component=\"key-value-pair\"` child becomes\n // a subgrid row spanning all three columns. The KVP's own\n // flex layout still works inside the cell (icon shrinks-0,\n // label shrinks-0, value flexes) — subgrid just aligns the\n // boundaries between siblings.\n 'ds:[&>[data-component=\"key-value-pair\"]]:grid',\n 'ds:[&>[data-component=\"key-value-pair\"]]:grid-cols-subgrid',\n 'ds:[&>[data-component=\"key-value-pair\"]]:col-span-3',\n 'ds:[&>[data-component=\"key-value-pair\"]]:items-baseline',\n // Unset the KVP's intra-row `gap-sm` so the subgrid inherits\n // the parent KeyValueList's `gap-x-md` for every track gap\n // (icon→label and label→value). `gap-0` here would override\n // the parent's gap and crowd the icon against the label;\n // `[gap:normal]` is the subgrid-spec way to defer to the\n // parent.\n 'ds:[&>[data-component=\"key-value-pair\"]]:[gap:normal]',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n {...props}\n >\n {children}\n </div>\n );\n },\n);\n\nKeyValueList.displayName = 'KeyValueList';\n"],"names":["keyValuePairValueVariants","cva","keyValuePairVariants","KeyValuePair","forwardRef","label","labelNode","value","layout","alignValue","mono","copyable","copyText","icon","className","props","ref","t","useTranslation","copied","setCopied","useState","announcement","setAnnouncement","textToCopy","handleCopy","useCallback","valueClasses","hasIcon","innerStackClass","stack","jsxs","Fragment","jsx","IconButton","Check","Copy","rowGapClassMap","KeyValueList","children","rowGap"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@ import { A as re } from "./avatar-BoqdWsNe.js";
|
|
|
6
6
|
import { B as D } from "./badge-BUk4RjTS.js";
|
|
7
7
|
import { I as Ue } from "./icon-button-S8_weU3g.js";
|
|
8
8
|
import { C as le } from "./card-C85_Ndhb.js";
|
|
9
|
-
import { K as Be, a as Re } from "./key-value-pair-
|
|
9
|
+
import { K as Be, a as Re } from "./key-value-pair-CB37UXsz.js";
|
|
10
10
|
import { L as V } from "./link-DtCfnLnF.js";
|
|
11
11
|
import { S as k } from "./skeleton-tTWJpvAq.js";
|
|
12
12
|
import { T as oe } from "./tag-DOZGz0fT.js";
|
|
@@ -548,4 +548,4 @@ export {
|
|
|
548
548
|
Ca as P,
|
|
549
549
|
ma as p
|
|
550
550
|
};
|
|
551
|
-
//# sourceMappingURL=patient-summary-card-
|
|
551
|
+
//# sourceMappingURL=patient-summary-card-B1jvxdY8.js.map
|
package/dist/_chunks/{patient-summary-card-CL04aq8h.js.map → patient-summary-card-B1jvxdY8.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patient-summary-card-CL04aq8h.js","sources":["../../node_modules/lucide-react/dist/esm/icons/file-exclamation-point.mjs","../../node_modules/lucide-react/dist/esm/icons/message-square-warning.mjs","../../src/components/patient-summary-card/patient-summary-card.agent.ts","../../src/components/patient-summary-card/patient-summary-card.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n];\nconst FileExclamationPoint = createLucideIcon(\"file-exclamation-point\", __iconNode);\n\nexport { __iconNode, FileExclamationPoint as default };\n//# sourceMappingURL=file-exclamation-point.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\",\n key: \"18887p\"\n }\n ],\n [\"path\", { d: \"M12 15h.01\", key: \"q59x07\" }],\n [\"path\", { d: \"M12 7v4\", key: \"xawao1\" }]\n];\nconst MessageSquareWarning = createLucideIcon(\"message-square-warning\", __iconNode);\n\nexport { __iconNode, MessageSquareWarning as default };\n//# sourceMappingURL=message-square-warning.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PatientSummaryCardHandle } from './patient-summary-card';\n\n/* -------------------------------------------------------------------- */\n/* Agent adapter — PatientSummaryCard */\n/* */\n/* Read-only adapter. Surfaces a STRUCTURAL snapshot of the patient */\n/* overview — counts, flags, and the consumer id only. Never the patient */\n/* name, age, contact details, or any clinical content, so an agent / */\n/* MCP runtime can answer \"does this patient have unpaid balances / */\n/* unsigned documents / AI consent?\" without re-parsing the DOM and */\n/* without leaking PHI (PRS §Security). */\n/* -------------------------------------------------------------------- */\n\nexport const patientSummaryCardAgent: AgentAdapter<PatientSummaryCardHandle> = {\n id: 'patient-summary-card',\n // The agent surface is a structural snapshot only — the single handle method\n // is a getSummary projection. The card MAY be human-customized (the optional\n // per-context \"Customize fields\" cog), but that field reordering is a UI\n // concern and is deliberately NOT exposed as an agent action; programmatic\n // field-set control lives on PatientDetails' adapter (set_field_order).\n capabilities: [],\n state: {\n summary: {\n type: '{ id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean }',\n descriptionKey: 'ui.agent.patientSummaryCard.state.summary',\n description:\n 'Structural summary of the patient card — identifiers, counts, and consent flags only. Never patient identity or clinical content.',\n read: (handle) => handle.getSummary(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'patient-summary-card',\n description: 'Marks the PatientSummaryCard root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ArrowUpRight,\n CalendarDays,\n FileExclamationPoint,\n Mail,\n MapPin,\n MessageSquareWarning,\n Phone,\n ShieldCheck,\n Astroid,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport { Avatar } from '../avatar/avatar';\nimport { Badge } from '../badge/badge';\nimport { IconButton } from '../button/icon-button';\nimport { Card } from '../card/card';\nimport { KeyValueList, KeyValuePair } from '../key-value-pair/key-value-pair';\nimport { Link } from '../link/link';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Tag } from '../tag/tag';\nimport { TransactionChip } from '../transaction-chip/transaction-chip';\nimport { Tooltip } from '../tooltip';\nimport { HoverCard } from '../hover-card';\nimport { isSafeEntityUrl } from '../_shared/is-safe-url';\nimport {\n resolveVisibleFields,\n type PatientField,\n type PatientFieldSection,\n} from '../_shared/patient-fields';\nimport { usePatientFieldVisibility } from '../_shared/field-visibility';\nimport { FieldVisibilityCog } from '../_shared/field-visibility-cog';\nimport { AgeChip, NeutralChip, SexChip } from '../_shared/field-value';\nimport {\n PatientFieldLabel,\n PatientFieldValueCell,\n} from '../_shared/patient-field-row';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { patientSummaryCardAgent } from './patient-summary-card.agent';\n\n/** A section list reference that stays stable across renders (legacy mode). */\nconst NO_SECTIONS: PatientFieldSection[] = [];\n\n/* -------------------------------------------------------------------- */\n/* PatientSummaryCard */\n/* */\n/* The patient-overview profile card every AlfaDocs in-app surface */\n/* composes by hand today (platform patient header, alfascribe patient */\n/* sidebar, check-in landing). Templated on ContactProfileCard: composes */\n/* Card + Avatar + KeyValueList + KeyValuePair + Badge + Tag + */\n/* TransactionChip + Link so the contact rows share a column and every */\n/* row uses the same lucide icon family. */\n/* */\n/* The kit owns the ORDER, ICONS, and LABELS — consumers pass data. No */\n/* free-text clinical content (anamnesis notes, diagnoses) ever lives */\n/* here: only counts/flags/relations are surfaced, so the card stays */\n/* PHI-light and the agent state can be derived without leaking patient */\n/* identity. */\n/* */\n/* All visible text flows through `useTranslation('ui')` against the */\n/* `patientSummaryCard.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n // Matches the kit's other `surface` props (ContactProfileCard,\n // OperatorHero). `'elevated'` wraps the content in `<Card>`.\n surface: {\n flat: '',\n elevated: '',\n },\n // Density tunes the avatar size + body padding. `comfortable` reads\n // as a page header; `compact` fits an embedded sidebar / aside.\n density: {\n comfortable: '',\n compact: '',\n },\n },\n defaultVariants: {\n surface: 'elevated',\n density: 'comfortable',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Patient phone number — already formatted for display by the consumer. */\nexport interface PatientSummaryCardPhone {\n /** Display string, e.g. `\"+39 055 123 4567\"`. Compiled into a `tel:` link. */\n prefixAndNumber: string;\n /** Optional label that distinguishes this number (e.g. \"Mobile\"). */\n label?: string;\n /** Whether SMS is enabled for this number — shows a small \"SMS\" chip. */\n smsEnabled?: boolean;\n}\n\n/** A family relation row — links one patient to another. */\nexport interface PatientSummaryCardFamilyRelation {\n /** Localised relation label, consumer-supplied (e.g. \"Mother\", \"Child\"). */\n relation: string;\n /** The related patient — name + optional in-app profile URL. */\n relatedPatient: {\n name: string;\n url?: string;\n };\n}\n\n/** Operator the patient is assigned to. */\nexport interface PatientSummaryCardAssignee {\n name: string;\n avatarUrl?: string;\n}\n\n/** AI-consent grant metadata — structural only, never the consented content. */\nexport interface PatientSummaryCardAiConsent {\n /** ISO-8601 / display string of when consent was granted. */\n grantedAt: string;\n /** Optional name of who recorded the grant. */\n grantedBy?: string;\n}\n\n/** Addressable attention flags — the keys `onFlagActivate` accepts. */\nexport type PatientSummaryCardFlagId =\n | 'highlightedAnamnesis'\n | 'unsignedDocuments'\n | 'unpaid';\n\n/** Status flags rendered as glyph badges (counts / amounts only — no PHI). */\nexport interface PatientSummaryCardFlags {\n /** Number of anamnesis answers highlighted for clinical attention. */\n highlightedAnamnesisCount?: number;\n /** Outstanding balance in the smallest currency unit (cents). */\n unpaidAmountCents?: number;\n /** Number of documents awaiting the patient's signature. */\n unsignedDocumentsCount?: number;\n}\n\n/** Marketing-consent tri-state. */\nexport type PatientSummaryCardMarketingConsent = 'no' | 'yes' | 'not_specified';\n\nexport interface PatientSummaryCardHandle {\n /** Structural snapshot — identifiers and counts only, never patient identity. */\n getSummary: () => {\n id?: string;\n hasUnpaid: boolean;\n unsignedDocumentsCount: number;\n highlightedAnamnesisCount: number;\n aiConsentGranted: boolean;\n };\n}\n\nexport interface PatientSummaryCardProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children'\n> {\n /** Patient display name. Rendered as the heading. */\n name: string;\n /** Honorific — `'mr'` / `'ms'`. Prepended to the name in the heading. */\n title?: 'mr' | 'ms';\n /** Patient age in whole years — rendered in the identity line. */\n ageYears?: number;\n /** Date of birth — already formatted for display by the consumer. */\n dateOfBirth?: string;\n /** Biological sex marker — `'m'` / `'f'`. Drives the identity-line glyph copy. */\n gender?: 'm' | 'f';\n /** Optional avatar / photo URL. Falls back to initials. */\n avatarUrl?: string;\n /**\n * In-app patient profile URL. When safe, the heading becomes a link.\n * Guarded by the shared `isSafeEntityUrl` allow-list — unsafe URLs are\n * dropped and the heading renders as plain text.\n */\n patientUrl?: string;\n\n /* ----- Shared field model (preferred) ----- */\n\n /**\n * Patient fields in the shared model — the SAME `sections` shape\n * `PatientDetails` consumes (`@alfadocs/ui-kit` `PatientFieldSection`).\n * When provided, the card renders these (honouring `visibleFieldOrder`)\n * instead of the legacy contact props, so a consumer defines its patient-\n * field registry once and reuses it across every patient surface.\n *\n * The card renders each field's `label`, `value`, and `icon` only — it is\n * flat (section headings are not shown in the body) and never inline-edits;\n * `sensitive` / `copyable` / `mono` / `editable` are honoured by\n * `PatientDetails`, not the card (so the PHI lock glyph does not appear here).\n *\n * Pass `onVisibleFieldsChange` alongside `sections` to make THIS placement\n * self-curating (a \"Customize fields\" cog appears — show/hide + drag-and-drop\n * reorder).\n */\n sections?: PatientFieldSection[];\n /**\n * Ordered visible field ids for THIS placement. The order is a\n * per-INSTANCE, per-CONTEXT preference the kit never persists — wire it to\n * whatever scope the consumer wants (e.g. a global per-user setting, or a\n * different config in the care-plan view vs the patient folder). The same\n * field vocabulary can therefore display differently in different parts of\n * the app. Omit (`undefined`) ⇒ show every field; an explicit empty array\n * `[]` ⇒ show none (a card that starts collapsed to name + identity chips and\n * reveals fields via the cog). Also applied to the legacy contact rows (ids\n * `email` / `phone` / `cityProvince` / `marketingConsent` / `aiConsent` /\n * `assignedTo`).\n */\n visibleFieldOrder?: string[];\n /**\n * Make this card's field set user-customizable. When provided alongside\n * `sections`, a \"Customize fields\" cog renders in the header (show/hide +\n * drag-and-drop / Alt+Arrow reorder), and this fires with the next ordered\n * visible set. The consumer owns persistence + its scope — editing here\n * writes only THIS context's preference, never a shared/global one.\n */\n onVisibleFieldsChange?: (orderedIds: string[]) => void;\n\n /* ----- Contact rows (legacy — prefer `sections`) ----- */\n\n /** @deprecated Pass via `sections`. Patient email — `mailto:` link when `emailEnabled`. */\n email?: string;\n /** Whether email contact is enabled — gates the `mailto:` link. */\n emailEnabled?: boolean;\n /** Phone number block. Compiled into a `tel:` link. */\n phone?: PatientSummaryCardPhone;\n /** City / province display string. */\n cityProvince?: string;\n\n /* ----- Consent ----- */\n\n /** Marketing-consent tri-state. */\n marketingConsent?: PatientSummaryCardMarketingConsent;\n /** AI-consent grant metadata. When present, an \"AI consent\" row renders. */\n aiConsent?: PatientSummaryCardAiConsent;\n\n /* ----- Status flags ----- */\n\n /** Counts / amounts surfaced as glyph badges. */\n flags?: PatientSummaryCardFlags;\n\n /* ----- Relations & assignment ----- */\n\n /** Family relations — rendered as `<Tag>` chips, optionally linked. */\n familyRelations?: PatientSummaryCardFamilyRelation[];\n /** Operator the patient is assigned to. */\n assignedTo?: PatientSummaryCardAssignee;\n\n /* ----- Formatting ----- */\n\n /** ISO-4217 currency code for the unpaid-amount chip. Defaults to `EUR`. */\n currency?: string;\n /** BCP-47 locale override. Defaults to the active i18next language. */\n locale?: string;\n\n /* ----- States ----- */\n\n /** Render the skeleton loading placeholder. */\n loading?: boolean;\n\n /* ----- Slots & callbacks ----- */\n\n /** Rendered at the inline-end of the heading row (e.g. an action menu). */\n actionSlot?: ReactNode;\n\n /**\n * Make an attention chip actionable. A handler turns that chip into a\n * button — \"2 unsigned documents\" opens the signing flow, the unpaid\n * balance opens invoicing. Without a handler the chip stays a read-only\n * badge, which is the default: most surfaces have nowhere to send the\n * reader.\n */\n onFlagActivate?: Partial<Record<PatientSummaryCardFlagId, () => void>>;\n /**\n * Explain a chip on hover / focus. The chip states WHAT (\"2 unsigned\n * documents\"); this states what the reader cannot see — how the signature\n * was requested, why the balance is outstanding.\n *\n * A string renders a `Tooltip`; a node renders a `HoverCard` with that node\n * as its content, for a host that wants the fuller card grammar (an eyebrow,\n * fact rows, a hint line). Either way the chip's own text stays the\n * accessible name and the surface only describes it.\n */\n flagHover?: Partial<Record<PatientSummaryCardFlagId, ReactNode>>;\n /**\n * Accessible name for the open button a hover CARD shows in its top-end\n * corner. The button appears only where the flag has BOTH a card and an\n * `onFlagActivate` handler — it mirrors the chip's own click so a pointer\n * that has travelled into the card can still act. Name the destination\n * (\"Open signing\"), not the gesture.\n *\n * Without a label there is no button: a card that merely describes should\n * not sprout an affordance the chip does not have.\n */\n flagOpenLabel?: Partial<Record<PatientSummaryCardFlagId, string>>;\n /**\n * Extra chips appended to the attention row, for signals the CARD cannot\n * model because they do not belong to the patient. An appointment panel\n * adds its own to-invoice and paid-online chips here; the card keeps its\n * patient-level flags and does not grow an appointment vocabulary.\n */\n extraChips?: ReactNode;\n\n /* ----- Inline editing (kit-owned controls, consumer-owned write) ----- */\n\n /**\n * Master switch — show the edit affordance on fields marked `editable` in\n * `sections`. The card edits through the SAME shared control as\n * `PatientDetails`, so a field offers the same affordance and the same\n * validation wherever it is shown.\n */\n editable?: boolean;\n /**\n * The single write channel. A rejected promise keeps the row in edit mode\n * and shows the message inline — the card never optimistically mutates the\n * value it was given.\n */\n onFieldSave?: (fieldId: string, value: unknown) => Promise<void>;\n /** Return a message to block the save and keep the row in edit mode. */\n validateField?: (fieldId: string, value: unknown) => string | null;\n /** Fires when the whole card / heading is activated. */\n onActivate?: () => void;\n\n /* ----- Styling ----- */\n\n /** `'elevated'` (default) wraps in `<Card>`; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** `'comfortable'` (default) reads as a header; `'compact'` for asides. */\n density?: 'comfortable' | 'compact';\n\n /* ----- a11y ----- */\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n/** Strip everything except digits + leading `+` for `tel:` URLs. */\nfunction normalisePhone(raw: string): string {\n return raw.replace(/[^\\d+]/g, '');\n}\n\n/* -------------------------------------------------------------------- */\n/* Flag glyphs — the closed set of status indicators */\n/* -------------------------------------------------------------------- */\n\n/** The closed set of status-flag keys (icon + tonal variant defined below). */\ntype FlagKey = 'highlightedAnamnesis' | 'unsignedDocuments';\n\nconst FLAG_ICON: Record<FlagKey, LucideIcon> = {\n highlightedAnamnesis: MessageSquareWarning,\n unsignedDocuments: FileExclamationPoint,\n};\n\nconst FLAG_VARIANT: Record<FlagKey, 'warning' | 'error'> = {\n highlightedAnamnesis: 'warning',\n unsignedDocuments: 'error',\n};\n\n/** English fallbacks for the flag badge accessible names (count-interpolated). */\nconst FLAG_LABEL_DEFAULTS: Record<FlagKey, string> = {\n highlightedAnamnesis: '{{count}} highlighted anamnesis answers',\n unsignedDocuments: '{{count}} unsigned documents',\n};\n\n/** English fallbacks for the marketing-consent tri-state chip. */\nconst MARKETING_CONSENT_DEFAULTS: Record<\n PatientSummaryCardMarketingConsent,\n string\n> = {\n yes: 'Yes',\n no: 'No',\n not_specified: 'Not specified',\n};\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PatientSummaryCard = forwardRef<\n HTMLDivElement,\n PatientSummaryCardProps\n>(\n (\n {\n name,\n title,\n ageYears,\n dateOfBirth,\n gender,\n avatarUrl,\n patientUrl,\n sections,\n visibleFieldOrder,\n onVisibleFieldsChange,\n email,\n emailEnabled = false,\n phone,\n cityProvince,\n marketingConsent,\n aiConsent,\n flags,\n familyRelations,\n assignedTo,\n currency = 'EUR',\n locale,\n loading = false,\n actionSlot,\n onFlagActivate,\n flagHover,\n flagOpenLabel,\n extraChips,\n editable = false,\n onFieldSave,\n validateField,\n onActivate,\n surface = 'elevated',\n density = 'comfortable',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n // Pinned to `ui` as a guard for a host that inits i18next with its own\n // `defaultNS`: the flag badges pass a defaultValue, so a miss is silent.\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const activeLocale = locale ?? i18n.language ?? 'en';\n\n const unpaidAmountCents = flags?.unpaidAmountCents;\n const unsignedDocumentsCount = flags?.unsignedDocumentsCount ?? 0;\n const highlightedAnamnesisCount = flags?.highlightedAnamnesisCount ?? 0;\n const hasUnpaid = unpaidAmountCents != null && unpaidAmountCents > 0;\n\n // Imperative handle — structural snapshot only (counts/flags/ids),\n // never the patient name or any clinical content.\n const handle = useMemo<PatientSummaryCardHandle>(\n () => ({\n getSummary: () => ({\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsentGranted: aiConsent != null,\n }),\n }),\n [\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsent,\n ],\n );\n useAgentRegistration(patientSummaryCardAgent, handle, id);\n\n // Per-context field visibility. The cog (and live reordering) only engages\n // with the shared `sections` model AND an `onVisibleFieldsChange` handler;\n // legacy contact-prop cards stay read-only. The order is this placement's\n // own preference — never shared across surfaces.\n const customizable = !!sections && !!onVisibleFieldsChange;\n const fieldVisibility = usePatientFieldVisibility(sections ?? NO_SECTIONS, {\n value: visibleFieldOrder,\n onChange: onVisibleFieldsChange,\n });\n\n const resolvedAriaLabel =\n ariaLabel ??\n t('patientSummaryCard.regionLabel', { defaultValue: 'Patient overview' });\n\n // Heading text: optional honorific prefix + name.\n const TITLE_DEFAULTS: Record<'mr' | 'ms', string> = {\n mr: 'Mr.',\n ms: 'Ms.',\n };\n const honorific = title\n ? t(`patientSummaryCard.title.${title}`, {\n defaultValue: TITLE_DEFAULTS[title],\n })\n : undefined;\n // A translated PATTERN, not a hardcoded `${honorific} ${name}` join:\n // several of the 18 locales order or punctuate a name-with-title\n // differently (or drop it) — a locale can override the pattern\n // without touching this component.\n const headingText = honorific\n ? t('patientSummaryCard.nameWithHonorific', {\n honorific,\n name,\n defaultValue: '{{honorific}} {{name}}',\n })\n : name;\n\n // Identity line: the canonical sex / age / dob chips below the name — the\n // SAME chips the field model renders, so the header and the field rows\n // agree. Each chip is added only when its prop is present. (`dateOfBirth`\n // is a consumer-preformatted display string, so it goes through NeutralChip\n // directly rather than the date-parsing `dob` kind.)\n const identityChips: ReactNode[] = [];\n if (gender) {\n identityChips.push(<SexChip key=\"sex\" code={gender} />);\n }\n if (ageYears != null) {\n identityChips.push(<AgeChip key=\"age\" years={ageYears} />);\n }\n if (dateOfBirth) {\n identityChips.push(\n <NeutralChip key=\"dob\" icon={<CalendarDays />}>\n {dateOfBirth}\n </NeutralChip>,\n );\n }\n\n const isUrlSafe = !!patientUrl && isSafeEntityUrl(patientUrl);\n\n const avatarSize = density === 'comfortable' ? 'xl' : 'lg';\n const headingClass =\n density === 'comfortable' ? 'type-title-card' : 'type-title-item';\n const bodyGapClass =\n density === 'comfortable'\n ? 'ds:gap-[var(--spacing-md)]'\n : 'ds:gap-[var(--spacing-sm)]';\n\n /* ---------------------------------------------------------------- */\n /* Contact rows */\n /* ---------------------------------------------------------------- */\n\n const rows: Array<{\n key: string;\n icon: ReactElement;\n label: string;\n value: ReactNode;\n }> = [];\n\n if (email) {\n rows.push({\n key: 'email',\n icon: <Mail aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.email', { defaultValue: 'Email' }),\n value: emailEnabled ? (\n <Link\n href={`mailto:${email}`}\n intent=\"default\"\n onClick={onActivate}\n dir=\"ltr\"\n >\n {email}\n </Link>\n ) : (\n <span className=\"ds:text-[color:var(--muted-foreground)]\" dir=\"ltr\">\n {email}\n </span>\n ),\n });\n }\n\n if (phone) {\n rows.push({\n key: 'phone',\n icon: <Phone aria-hidden=\"true\" />,\n label:\n phone.label ??\n t('patientSummaryCard.label.phone', { defaultValue: 'Phone' }),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Link\n href={`tel:${normalisePhone(phone.prefixAndNumber)}`}\n intent=\"default\"\n dir=\"ltr\"\n >\n {phone.prefixAndNumber}\n </Link>\n {phone.smsEnabled ? (\n <Badge variant=\"success\" size=\"sm\">\n {t('patientSummaryCard.value.smsEnabled', {\n defaultValue: 'SMS',\n })}\n </Badge>\n ) : null}\n </span>\n ),\n });\n }\n\n if (cityProvince) {\n rows.push({\n key: 'cityProvince',\n icon: <MapPin aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.cityProvince', {\n defaultValue: 'City / province',\n }),\n value: cityProvince,\n });\n }\n\n if (marketingConsent) {\n rows.push({\n key: 'marketingConsent',\n icon: <ShieldCheck aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.marketingConsent', {\n defaultValue: 'Marketing consent',\n }),\n value: (\n <Badge\n variant={\n marketingConsent === 'yes'\n ? 'success'\n : marketingConsent === 'no'\n ? 'error'\n : 'neutral'\n }\n size=\"sm\"\n withDot\n >\n {t(`patientSummaryCard.marketingConsent.${marketingConsent}`, {\n defaultValue: MARKETING_CONSENT_DEFAULTS[marketingConsent],\n })}\n </Badge>\n ),\n });\n }\n\n if (aiConsent) {\n rows.push({\n key: 'aiConsent',\n icon: <Astroid aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.aiConsent', {\n defaultValue: 'AI consent',\n }),\n value: aiConsent.grantedBy\n ? t('patientSummaryCard.value.aiConsentGrantedBy', {\n date: aiConsent.grantedAt,\n by: aiConsent.grantedBy,\n defaultValue: 'Granted {{date}} by {{by}}',\n })\n : t('patientSummaryCard.value.aiConsentGrantedAt', {\n date: aiConsent.grantedAt,\n defaultValue: 'Granted {{date}}',\n }),\n });\n }\n\n if (assignedTo) {\n rows.push({\n key: 'assignedTo',\n icon: <Users aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.assignedTo', {\n defaultValue: 'Assigned to',\n }),\n value: (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Avatar\n size=\"xs\"\n name={assignedTo.name}\n src={assignedTo.avatarUrl}\n />\n <span>{assignedTo.name}</span>\n </span>\n ),\n });\n }\n\n /* ---------------------------------------------------------------- */\n /* Attention-flag chips (VERBOSE — shown in the identity line) */\n /* */\n /* The unpaid balance + warning counts sit in the chip row under the */\n /* name, BEFORE the sex / age chips, each as a self-describing chip */\n /* (\"2 unsigned documents\") rather than a collapsed count badge in a */\n /* separate strip — the attention signals lead the patient's chips. */\n /* ---------------------------------------------------------------- */\n\n const flagBadges: Array<{ key: FlagKey; count: number }> = [];\n if (highlightedAnamnesisCount > 0) {\n flagBadges.push({\n key: 'highlightedAnamnesis',\n count: highlightedAnamnesisCount,\n });\n }\n if (unsignedDocumentsCount > 0) {\n flagBadges.push({\n key: 'unsignedDocuments',\n count: unsignedDocumentsCount,\n });\n }\n\n /* A chip becomes a BUTTON only when the host gave it somewhere to go.\n The chip's own text is already its accessible name, so the wrapper adds\n no label of its own and contributes no padding — the strip's rhythm is\n identical whether or not a chip is actionable. */\n /* A chip becomes a CONTROL when it has something to reveal or somewhere\n to go, and the trigger is always a real <button> — `asChild` on a bare\n <span> badge stamps `aria-haspopup` onto something a keyboard can never\n reach, which is both a dead end and an axe violation.\n\n The division of labour is the same on every chip: the chip opens its\n card (hover, or click / Enter for keyboard and touch), and the card's\n own top-end button performs the action. One gesture to learn, and no\n chip that acts differently from its neighbour. */\n const asAction = (id: PatientSummaryCardFlagId, chip: ReactNode) => {\n const onActivateFlag = onFlagActivate?.[id];\n const hover = flagHover?.[id];\n if (hover == null && !onActivateFlag) return chip;\n\n const triggerClasses =\n 'ds:inline-flex ds:cursor-pointer ds:rounded-[var(--radius-full)] ds:p-0 ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n // No card: the chip itself is the action.\n if (hover == null) {\n return (\n <button\n key={id}\n type=\"button\"\n data-flag-action={id}\n onClick={onActivateFlag}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n }\n\n const trigger = (\n <button\n key={id}\n type=\"button\"\n data-flag-action={onActivateFlag ? id : undefined}\n data-flag-hover={id}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n\n // A string still renders a plain Tooltip, for a chip that needs naming\n // rather than a card.\n if (typeof hover === 'string') {\n return (\n <Tooltip key={id} label={hover} side=\"bottom\">\n {trigger}\n </Tooltip>\n );\n }\n\n return (\n <HoverCard key={id}>\n <HoverCard.Trigger asChild>{trigger}</HoverCard.Trigger>\n <HoverCard.Content\n side=\"bottom\"\n align=\"start\"\n size=\"sm\"\n headerAction={\n onActivateFlag && flagOpenLabel?.[id] ? (\n <IconButton\n icon={<ArrowUpRight />}\n /* Outline, not ghost: the card's own surface is already\n light, so a borderless glyph reads as decoration rather\n than a control. */\n intent=\"outline\"\n background=\"surface\"\n size=\"sm\"\n aria-label={flagOpenLabel[id] as string}\n onClick={onActivateFlag}\n />\n ) : undefined\n }\n >\n {hover}\n </HoverCard.Content>\n </HoverCard>\n );\n };\n\n const attentionChips: ReactNode[] = [];\n if (hasUnpaid) {\n attentionChips.push(\n asAction(\n 'unpaid',\n <TransactionChip\n key=\"unpaid\"\n state=\"debt\"\n amount={(unpaidAmountCents as number) / 100}\n currency={currency}\n locale={activeLocale}\n size=\"md\"\n showLabel\n />,\n ),\n );\n }\n flagBadges.forEach(({ key, count }) => {\n const FlagIcon = FLAG_ICON[key];\n // The Badge's visible text IS the count-interpolated label, so it's its\n // own accessible name — the leading glyph is decorative (aria-hidden).\n attentionChips.push(\n asAction(\n key,\n <Badge\n key={key}\n variant={FLAG_VARIANT[key]}\n size=\"md\"\n leading={<FlagIcon aria-hidden=\"true\" />}\n >\n {t(`patientSummaryCard.flag.${key}`, {\n count,\n defaultValue: FLAG_LABEL_DEFAULTS[key],\n })}\n </Badge>,\n ),\n );\n });\n if (extraChips) attentionChips.push(extraChips);\n\n /* ---------------------------------------------------------------- */\n /* Loading skeleton */\n /* ---------------------------------------------------------------- */\n\n const skeletonBody = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-md)]\">\n <Skeleton variant=\"circular\" size=\"lg\" />\n <div className=\"ds:flex ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n <Skeleton variant=\"text\" lines={3} />\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Header */\n /* ---------------------------------------------------------------- */\n\n const heading = isUrlSafe ? (\n <Link\n href={patientUrl as string}\n intent=\"default\"\n weight=\"strong\"\n onClick={onActivate}\n className={`${headingClass} ds:no-underline`}\n >\n <span id={headingId}>{headingText}</span>\n </Link>\n ) : (\n <span\n id={headingId}\n className={`${headingClass} ds:text-[color:var(--foreground)]`}\n >\n {headingText}\n </span>\n );\n\n const header = (\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-md)]\">\n <Avatar\n size={avatarSize}\n name={name}\n src={avatarUrl}\n className=\"ds:shrink-0\"\n />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {heading}\n {attentionChips.length > 0 || identityChips.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Attention flags lead, then the sex / age / dob identity chips. */}\n {attentionChips}\n {identityChips}\n </div>\n ) : null}\n </div>\n {customizable || actionSlot ? (\n <div className=\"ds:ms-auto ds:flex ds:shrink-0 ds:items-center ds:gap-[var(--spacing-xs)]\">\n {customizable && sections ? (\n <FieldVisibilityCog\n sections={sections}\n visible={fieldVisibility.visible}\n onToggleField={fieldVisibility.toggleField}\n onToggleSection={fieldVisibility.toggleSection}\n onMoveFieldOnto={fieldVisibility.moveFieldOnto}\n onReset={fieldVisibility.reset}\n />\n ) : null}\n {actionSlot}\n </div>\n ) : null}\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Family relations */\n /* ---------------------------------------------------------------- */\n\n const familyBlock =\n familyRelations && familyRelations.length > 0 ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-label ds:text-[color:var(--muted-foreground)]\">\n {t('patientSummaryCard.label.familyRelations', {\n defaultValue: 'Family relations',\n })}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {familyRelations.map((rel, index) => {\n const safeUrl =\n !!rel.relatedPatient.url &&\n isSafeEntityUrl(rel.relatedPatient.url);\n const tagLabel = t('patientSummaryCard.value.familyRelation', {\n relation: rel.relation,\n name: rel.relatedPatient.name,\n defaultValue: '{{relation}}: {{name}}',\n });\n return safeUrl ? (\n <Link\n key={`${rel.relation}-${index}`}\n href={rel.relatedPatient.url as string}\n intent=\"default\"\n className=\"ds:no-underline\"\n >\n <Tag label={tagLabel} variant=\"neutral\" />\n </Link>\n ) : (\n <Tag\n key={`${rel.relation}-${index}`}\n label={tagLabel}\n variant=\"neutral\"\n />\n );\n })}\n </div>\n </div>\n ) : null;\n\n /* ---------------------------------------------------------------- */\n /* Body */\n /* ---------------------------------------------------------------- */\n\n // Field rows resolve through the SHARED model: when the consumer passes\n // `sections` (preferred), render those; otherwise wrap the legacy contact\n // rows as a single section. Either way `resolveVisibleFields` applies the\n // shared `visibleFieldOrder` preference, so the card and PatientDetails\n // always show the same fields, honouring the same per-user choice.\n const legacyFields: PatientField[] = rows.map((row) => ({\n id: row.key,\n label: row.label,\n value: row.value,\n icon: row.icon,\n }));\n const effectiveSections: PatientFieldSection[] = sections ?? [\n { id: 'contact', heading: '', fields: legacyFields },\n ];\n // With the shared `sections` model the order comes from the visibility hook\n // (so a cog reorder reflects live); legacy contact rows honour the raw\n // `visibleFieldOrder` prop.\n const order = sections ? fieldVisibility.visible : visibleFieldOrder;\n const visibleFields = resolveVisibleFields(\n effectiveSections,\n order,\n ).flatMap((resolved) => resolved.fields);\n\n const body = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n {header}\n {visibleFields.length > 0 ? (\n // Container-queried so the fields flow into two columns when the\n // card is wide enough (the banner spans the full folder width), and\n // stay single-column in a narrow rail. The list's KeyValuePair\n // children already `col-span-3`; doubling the parent to six tracks\n // (`repeat(2, …)`) lets grid auto-flow place two fields per row while\n // each column keeps its own subgrid label/value alignment.\n // 672px, not the `@2xl` rem alias: container-query `rem` follows the\n // host root font-size, so a non-16px root moves the threshold.\n // Each label column stops at 20% of the card (every field has an\n // icon, so labels sit in the middle track of each group): a long\n // label wraps instead of squeezing its value, as KeyValueList's\n // single-column cap does at 40%.\n <div className=\"ds:@container/pfields\">\n <KeyValueList\n rowGap=\"sm\"\n className=\"ds:@[672px]/pfields:grid-cols-[repeat(2,auto_fit-content(20%)_minmax(0,1fr))]\"\n >\n {visibleFields.map((field) => (\n <KeyValuePair\n key={field.id}\n icon={field.icon ?? undefined}\n label={field.label}\n labelNode={<PatientFieldLabel field={field} />}\n // `group` is what reveals the edit pencil on hover / focus;\n // the cell itself carries no row markup.\n className=\"ds:group\"\n data-field-id={field.id}\n value={\n <PatientFieldValueCell\n field={field}\n editable={editable}\n onFieldSave={onFieldSave}\n validate={validateField}\n locale={locale}\n />\n }\n />\n ))}\n </KeyValueList>\n </div>\n ) : null}\n {familyBlock}\n </div>\n );\n\n const inner = loading ? skeletonBody : body;\n\n return (\n <div\n ref={ref}\n role=\"region\"\n // When the heading is rendered, the patient name (via\n // aria-labelledby) is the region's accessible name — the more\n // meaningful label than a generic \"Patient overview\". A consumer\n // aria-label still wins; the generic fallback only applies when\n // there is no heading to point at (loading state).\n aria-label={loading || ariaLabel ? resolvedAriaLabel : undefined}\n aria-labelledby={loading || ariaLabel ? undefined : headingId}\n aria-busy={loading || undefined}\n data-component=\"patient-summary-card\"\n data-component-id={id}\n data-density={density}\n id={id}\n className={rootVariants({ surface, density, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPatientSummaryCard.displayName = 'PatientSummaryCard';\n\n/** Variant unions re-exported for downstream typing. */\nexport type PatientSummaryCardSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\nexport type PatientSummaryCardDensity = NonNullable<\n VariantProps<typeof rootVariants>['density']\n>;\n"],"names":["__iconNode","FileExclamationPoint","createLucideIcon","MessageSquareWarning","patientSummaryCardAgent","handle","NO_SECTIONS","rootVariants","cva","normalisePhone","raw","FLAG_ICON","FLAG_VARIANT","FLAG_LABEL_DEFAULTS","MARKETING_CONSENT_DEFAULTS","PatientSummaryCard","forwardRef","name","title","ageYears","dateOfBirth","gender","avatarUrl","patientUrl","sections","visibleFieldOrder","onVisibleFieldsChange","email","emailEnabled","phone","cityProvince","marketingConsent","aiConsent","flags","familyRelations","assignedTo","currency","locale","loading","actionSlot","onFlagActivate","flagHover","flagOpenLabel","extraChips","editable","onFieldSave","validateField","onActivate","surface","density","ariaLabel","id","className","rest","ref","i18n","useTranslation","headingId","useId","activeLocale","unpaidAmountCents","unsignedDocumentsCount","highlightedAnamnesisCount","hasUnpaid","useMemo","useAgentRegistration","customizable","fieldVisibility","usePatientFieldVisibility","resolvedAriaLabel","TITLE_DEFAULTS","honorific","headingText","identityChips","jsx","SexChip","AgeChip","NeutralChip","CalendarDays","isUrlSafe","isSafeEntityUrl","avatarSize","headingClass","bodyGapClass","rows","Mail","Link","Phone","jsxs","Badge","MapPin","ShieldCheck","Astroid","Users","Avatar","flagBadges","asAction","chip","onActivateFlag","hover","triggerClasses","trigger","Tooltip","HoverCard","IconButton","ArrowUpRight","attentionChips","TransactionChip","key","count","FlagIcon","skeletonBody","Skeleton","heading","header","FieldVisibilityCog","familyBlock","rel","index","safeUrl","tagLabel","Tag","legacyFields","row","effectiveSections","order","visibleFields","resolveVisibleFields","resolved","body","KeyValueList","field","KeyValuePair","PatientFieldLabel","PatientFieldValueCell","inner","Card"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,KAAa;AAAA,EACjB;AAAA,IACE;AAAA,IACA;AAAA,MACE,GAAG;AAAA,MACH,KAAK;AAAA,IACX;AAAA,EACA;AAAA,EACE,CAAC,QAAQ,EAAE,GAAG,WAAW,KAAK,SAAQ,CAAE;AAAA,EACxC,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAQ,CAAE;AAC7C,GACMC,KAAuBC,GAAiB,0BAA0BF,EAAU;ACpBlF;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,KAAa;AAAA,EACjB;AAAA,IACE;AAAA,IACA;AAAA,MACE,GAAG;AAAA,MACH,KAAK;AAAA,IACX;AAAA,EACA;AAAA,EACE,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAQ,CAAE;AAAA,EAC3C,CAAC,QAAQ,EAAE,GAAG,WAAW,KAAK,SAAQ,CAAE;AAC1C,GACMG,KAAuBD,GAAiB,0BAA0BF,EAAU,GCNrEI,KAAkE;AAAA,EAC7E,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMJ,cAAc,CAAA;AAAA,EACd,OAAO;AAAA,IACL,SAAS;AAAA,MACP,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,aACE;AAAA,MACF,MAAM,CAACC,MAAWA,EAAO,WAAA;AAAA,IAAW;AAAA,EACtC;AAAA,EAEF,SAAS,CAAA;AAAA,EACT,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GCOMC,KAAqC,CAAA,GA0BrCC,KAAeC,GAAI,+CAA+C;AAAA,EACtE,UAAU;AAAA;AAAA;AAAA,IAGR,SAAS;AAAA,MACP,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA;AAAA;AAAA,IAIZ,SAAS;AAAA,MACP,aAAa;AAAA,MACb,SAAS;AAAA,IAAA;AAAA,EACX;AAAA,EAEF,iBAAiB;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,EAAA;AAEb,CAAC;AAoQD,SAASC,GAAeC,GAAqB;AAC3C,SAAOA,EAAI,QAAQ,WAAW,EAAE;AAClC;AASA,MAAMC,KAAyC;AAAA,EAC7C,sBAAsBR;AAAA,EACtB,mBAAmBF;AACrB,GAEMW,KAAqD;AAAA,EACzD,sBAAsB;AAAA,EACtB,mBAAmB;AACrB,GAGMC,KAA+C;AAAA,EACnD,sBAAsB;AAAA,EACtB,mBAAmB;AACrB,GAGMC,KAGF;AAAA,EACF,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,eAAe;AACjB,GAMaC,KAAqBC;AAAA,EAIhC,CACE;AAAA,IACE,MAAAC;AAAA,IACA,OAAAC;AAAA,IACA,UAAAC;AAAA,IACA,aAAAC;AAAA,IACA,QAAAC;AAAA,IACA,WAAAC;AAAA,IACA,YAAAC;AAAA,IACA,UAAAC;AAAA,IACA,mBAAAC;AAAA,IACA,uBAAAC;AAAA,IACA,OAAAC;AAAA,IACA,cAAAC,KAAe;AAAA,IACf,OAAAC;AAAA,IACA,cAAAC;AAAA,IACA,kBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,OAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,YAAAC;AAAA,IACA,UAAAC,KAAW;AAAA,IACX,QAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,YAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,eAAAC;AAAA,IACA,YAAAC;AAAA,IACA,UAAAC,KAAW;AAAA,IACX,aAAAC;AAAA,IACA,eAAAC;AAAA,IACA,YAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,cAAcC;AAAA,IACd,IAAAC;AAAA,IACA,WAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,GAELC,OACG;AAGH,UAAM,EAAE,GAAG,MAAAC,OAASC,GAAe,IAAI,GACjCC,IAAYC,GAAA,GACZC,KAAetB,KAAUkB,GAAK,YAAY,MAE1CK,IAAoB3B,KAAA,gBAAAA,EAAO,mBAC3B4B,KAAyB5B,KAAA,gBAAAA,EAAO,2BAA0B,GAC1D6B,KAA4B7B,KAAA,gBAAAA,EAAO,8BAA6B,GAChE8B,IAAYH,KAAqB,QAAQA,IAAoB,GAI7DvD,KAAS2D;AAAA,MACb,OAAO;AAAA,QACL,YAAY,OAAO;AAAA,UACjB,IAAAb;AAAA,UACA,WAAAY;AAAA,UACA,wBAAAF;AAAA,UACA,2BAAAC;AAAA,UACA,kBAAkB9B,KAAa;AAAA,QAAA;AAAA,MACjC;AAAA,MAEF;AAAA,QACEmB;AAAA,QACAY;AAAA,QACAF;AAAA,QACAC;AAAA,QACA9B;AAAA,MAAA;AAAA,IACF;AAEF,IAAAiC,GAAqB7D,IAAyBC,IAAQ8C,CAAE;AAMxD,UAAMe,IAAe,CAAC,CAAC1C,KAAY,CAAC,CAACE,GAC/ByC,IAAkBC,GAA0B5C,KAAYlB,IAAa;AAAA,MACzE,OAAOmB;AAAA,MACP,UAAUC;AAAA,IAAA,CACX,GAEK2C,KACJnB,KACA,EAAE,kCAAkC,EAAE,cAAc,oBAAoB,GAGpEoB,KAA8C;AAAA,MAClD,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA,GAEAC,IAAYrD,IACd,EAAE,4BAA4BA,CAAK,IAAI;AAAA,MACrC,cAAcoD,GAAepD,CAAK;AAAA,IAAA,CACnC,IACD,QAKEsD,IAAcD,IAChB,EAAE,wCAAwC;AAAA,MACxC,WAAAA;AAAA,MACA,MAAAtD;AAAA,MACA,cAAc;AAAA,IAAA,CACf,IACDA,GAOEwD,IAA6B,CAAA;AACnC,IAAIpD,KACFoD,EAAc,KAAK,gBAAAC,EAACC,IAAA,EAAkB,MAAMtD,EAAA,GAAZ,KAAoB,CAAE,GAEpDF,KAAY,QACdsD,EAAc,KAAK,gBAAAC,EAACE,IAAA,EAAkB,OAAOzD,EAAA,GAAb,KAAuB,CAAE,GAEvDC,KACFqD,EAAc;AAAA,wBACXI,IAAA,EAAsB,wBAAOC,IAAA,CAAA,CAAa,GACxC,eADc,KAEjB;AAAA,IAAA;AAIJ,UAAMC,KAAY,CAAC,CAACxD,KAAcyD,GAAgBzD,CAAU,GAEtD0D,KAAahC,MAAY,gBAAgB,OAAO,MAChDiC,IACJjC,MAAY,gBAAgB,oBAAoB,mBAC5CkC,KACJlC,MAAY,gBACR,+BACA,8BAMAmC,IAKD,CAAA;AAEL,IAAIzD,KACFyD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACW,IAAA,EAAK,eAAY,OAAA,CAAO;AAAA,MAC/B,OAAO,EAAE,kCAAkC,EAAE,cAAc,SAAS;AAAA,MACpE,OAAOzD,KACL,gBAAA8C;AAAA,QAACY;AAAA,QAAA;AAAA,UACC,MAAM,UAAU3D,CAAK;AAAA,UACrB,QAAO;AAAA,UACP,SAASoB;AAAA,UACT,KAAI;AAAA,UAEH,UAAApB;AAAA,QAAA;AAAA,MAAA,IAGH,gBAAA+C,EAAC,QAAA,EAAK,WAAU,2CAA0C,KAAI,OAC3D,UAAA/C,EAAA,CACH;AAAA,IAAA,CAEH,GAGCE,KACFuD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACa,IAAA,EAAM,eAAY,OAAA,CAAO;AAAA,MAChC,OACE1D,EAAM,SACN,EAAE,kCAAkC,EAAE,cAAc,SAAS;AAAA,MAC/D,OACE,gBAAA2D,EAAC,QAAA,EAAK,WAAU,oEACd,UAAA;AAAA,QAAA,gBAAAd;AAAA,UAACY;AAAA,UAAA;AAAA,YACC,MAAM,OAAO7E,GAAeoB,EAAM,eAAe,CAAC;AAAA,YAClD,QAAO;AAAA,YACP,KAAI;AAAA,YAEH,UAAAA,EAAM;AAAA,UAAA;AAAA,QAAA;AAAA,QAERA,EAAM,aACL,gBAAA6C,EAACe,GAAA,EAAM,SAAQ,WAAU,MAAK,MAC3B,UAAA,EAAE,uCAAuC;AAAA,UACxC,cAAc;AAAA,QAAA,CACf,GACH,IACE;AAAA,MAAA,EAAA,CACN;AAAA,IAAA,CAEH,GAGC3D,KACFsD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACgB,IAAA,EAAO,eAAY,OAAA,CAAO;AAAA,MACjC,OAAO,EAAE,yCAAyC;AAAA,QAChD,cAAc;AAAA,MAAA,CACf;AAAA,MACD,OAAO5D;AAAA,IAAA,CACR,GAGCC,KACFqD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACiB,IAAA,EAAY,eAAY,OAAA,CAAO;AAAA,MACtC,OAAO,EAAE,6CAA6C;AAAA,QACpD,cAAc;AAAA,MAAA,CACf;AAAA,MACD,OACE,gBAAAjB;AAAA,QAACe;AAAA,QAAA;AAAA,UACC,SACE1D,MAAqB,QACjB,YACAA,MAAqB,OACnB,UACA;AAAA,UAER,MAAK;AAAA,UACL,SAAO;AAAA,UAEN,UAAA,EAAE,uCAAuCA,CAAgB,IAAI;AAAA,YAC5D,cAAcjB,GAA2BiB,CAAgB;AAAA,UAAA,CAC1D;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,CAEH,GAGCC,KACFoD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACkB,IAAA,EAAQ,eAAY,OAAA,CAAO;AAAA,MAClC,OAAO,EAAE,sCAAsC;AAAA,QAC7C,cAAc;AAAA,MAAA,CACf;AAAA,MACD,OAAO5D,EAAU,YACb,EAAE,+CAA+C;AAAA,QAC/C,MAAMA,EAAU;AAAA,QAChB,IAAIA,EAAU;AAAA,QACd,cAAc;AAAA,MAAA,CACf,IACD,EAAE,+CAA+C;AAAA,QAC/C,MAAMA,EAAU;AAAA,QAChB,cAAc;AAAA,MAAA,CACf;AAAA,IAAA,CACN,GAGCG,KACFiD,EAAK,KAAK;AAAA,MACR,KAAK;AAAA,MACL,MAAM,gBAAAV,EAACmB,IAAA,EAAM,eAAY,OAAA,CAAO;AAAA,MAChC,OAAO,EAAE,uCAAuC;AAAA,QAC9C,cAAc;AAAA,MAAA,CACf;AAAA,MACD,OACE,gBAAAL,EAAC,QAAA,EAAK,WAAU,sDACd,UAAA;AAAA,QAAA,gBAAAd;AAAA,UAACoB;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAM3D,EAAW;AAAA,YACjB,KAAKA,EAAW;AAAA,UAAA;AAAA,QAAA;AAAA,QAElB,gBAAAuC,EAAC,QAAA,EAAM,UAAAvC,EAAW,KAAA,CAAK;AAAA,MAAA,EAAA,CACzB;AAAA,IAAA,CAEH;AAYH,UAAM4D,IAAqD,CAAA;AAC3D,IAAIjC,IAA4B,KAC9BiC,EAAW,KAAK;AAAA,MACd,KAAK;AAAA,MACL,OAAOjC;AAAA,IAAA,CACR,GAECD,IAAyB,KAC3BkC,EAAW,KAAK;AAAA,MACd,KAAK;AAAA,MACL,OAAOlC;AAAA,IAAA,CACR;AAgBH,UAAMmC,KAAW,CAAC7C,GAA8B8C,MAAoB;AAClE,YAAMC,IAAiB1D,KAAA,gBAAAA,EAAiBW,IAClCgD,IAAQ1D,KAAA,gBAAAA,EAAYU;AAC1B,UAAIgD,KAAS,QAAQ,CAACD,EAAgB,QAAOD;AAE7C,YAAMG,KACJ;AAGF,UAAID,KAAS;AACX,eACE,gBAAAzB;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,MAAK;AAAA,YACL,oBAAkBvB;AAAAA,YAClB,SAAS+C;AAAA,YACT,WAAWE;AAAA,YAEV,UAAAH;AAAA,UAAA;AAAA,UANI9C;AAAAA,QAAA;AAWX,YAAMkD,KACJ,gBAAA3B;AAAA,QAAC;AAAA,QAAA;AAAA,UAEC,MAAK;AAAA,UACL,oBAAkBwB,IAAiB/C,IAAK;AAAA,UACxC,mBAAiBA;AAAAA,UACjB,WAAWiD;AAAA,UAEV,UAAAH;AAAA,QAAA;AAAA,QANI9C;AAAAA,MAAA;AAYT,aAAI,OAAOgD,KAAU,6BAEhBG,IAAA,EAAiB,OAAOH,GAAO,MAAK,UAClC,gBADWhD,CAEd,sBAKDoD,GAAA,EACC,UAAA;AAAA,QAAA,gBAAA7B,EAAC6B,EAAU,SAAV,EAAkB,SAAO,IAAE,UAAAF,IAAQ;AAAA,QACpC,gBAAA3B;AAAA,UAAC6B,EAAU;AAAA,UAAV;AAAA,YACC,MAAK;AAAA,YACL,OAAM;AAAA,YACN,MAAK;AAAA,YACL,cACEL,MAAkBxD,KAAA,QAAAA,EAAgBS,MAChC,gBAAAuB;AAAA,cAAC8B;AAAA,cAAA;AAAA,gBACC,wBAAOC,IAAA,EAAa;AAAA,gBAIpB,QAAO;AAAA,gBACP,YAAW;AAAA,gBACX,MAAK;AAAA,gBACL,cAAY/D,EAAcS,CAAE;AAAA,gBAC5B,SAAS+C;AAAA,cAAA;AAAA,YAAA,IAET;AAAA,YAGL,UAAAC;AAAA,UAAA;AAAA,QAAA;AAAA,MACH,EAAA,GAvBchD,CAwBhB;AAAA,IAEJ,GAEMuD,IAA8B,CAAA;AACpC,IAAI3C,KACF2C,EAAe;AAAA,MACbV;AAAA,QACE;AAAA,QACA,gBAAAtB;AAAA,UAACiC;AAAA,UAAA;AAAA,YAEC,OAAM;AAAA,YACN,QAAS/C,IAA+B;AAAA,YACxC,UAAAxB;AAAA,YACA,QAAQuB;AAAA,YACR,MAAK;AAAA,YACL,WAAS;AAAA,UAAA;AAAA,UANL;AAAA,QAAA;AAAA,MAON;AAAA,IACF,GAGJoC,EAAW,QAAQ,CAAC,EAAE,KAAAa,GAAK,OAAAC,QAAY;AACrC,YAAMC,IAAWnG,GAAUiG,CAAG;AAG9B,MAAAF,EAAe;AAAA,QACbV;AAAA,UACEY;AAAA,UACA,gBAAAlC;AAAA,YAACe;AAAA,YAAA;AAAA,cAEC,SAAS7E,GAAagG,CAAG;AAAA,cACzB,MAAK;AAAA,cACL,SAAS,gBAAAlC,EAACoC,GAAA,EAAS,eAAY,OAAA,CAAO;AAAA,cAErC,UAAA,EAAE,2BAA2BF,CAAG,IAAI;AAAA,gBACnC,OAAAC;AAAA,gBACA,cAAchG,GAAoB+F,CAAG;AAAA,cAAA,CACtC;AAAA,YAAA;AAAA,YARIA;AAAA,UAAA;AAAA,QASP;AAAA,MACF;AAAA,IAEJ,CAAC,GACGjE,KAAY+D,EAAe,KAAK/D,CAAU;AAM9C,UAAMoE,KACJ,gBAAAvB,EAAC,OAAA,EAAI,WAAW,uBAAuBL,EAAY,IACjD,UAAA;AAAA,MAAA,gBAAAK,EAAC,OAAA,EAAI,WAAU,sDACb,UAAA;AAAA,QAAA,gBAAAd,EAACsC,GAAA,EAAS,SAAQ,YAAW,MAAK,MAAK;AAAA,QACvC,gBAAAxB,EAAC,OAAA,EAAI,WAAU,4DACb,UAAA;AAAA,UAAA,gBAAAd,EAACsC,GAAA,EAAS,SAAQ,QAAO,OAAM,OAAM;AAAA,UACrC,gBAAAtC,EAACsC,GAAA,EAAS,SAAQ,QAAO,OAAM,MAAA,CAAM;AAAA,QAAA,EAAA,CACvC;AAAA,MAAA,GACF;AAAA,MACA,gBAAAtC,EAACsC,GAAA,EAAS,SAAQ,QAAO,OAAO,EAAA,CAAG;AAAA,IAAA,GACrC,GAOIC,KAAUlC,KACd,gBAAAL;AAAA,MAACY;AAAA,MAAA;AAAA,QACC,MAAM/D;AAAA,QACN,QAAO;AAAA,QACP,QAAO;AAAA,QACP,SAASwB;AAAA,QACT,WAAW,GAAGmC,CAAY;AAAA,QAE1B,UAAA,gBAAAR,EAAC,QAAA,EAAK,IAAIjB,GAAY,UAAAe,EAAA,CAAY;AAAA,MAAA;AAAA,IAAA,IAGpC,gBAAAE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAIjB;AAAA,QACJ,WAAW,GAAGyB,CAAY;AAAA,QAEzB,UAAAV;AAAA,MAAA;AAAA,IAAA,GAIC0C,KACJ,gBAAA1B,EAAC,OAAA,EAAI,WAAU,qDACb,UAAA;AAAA,MAAA,gBAAAd;AAAA,QAACoB;AAAA,QAAA;AAAA,UACC,MAAMb;AAAA,UACN,MAAAhE;AAAA,UACA,KAAKK;AAAA,UACL,WAAU;AAAA,QAAA;AAAA,MAAA;AAAA,MAEZ,gBAAAkE,EAAC,OAAA,EAAI,WAAU,wEACZ,UAAA;AAAA,QAAAyB;AAAA,QACAP,EAAe,SAAS,KAAKjC,EAAc,SAAS,IACnD,gBAAAe,EAAC,OAAA,EAAI,WAAU,mEAEZ,UAAA;AAAA,UAAAkB;AAAA,UACAjC;AAAA,QAAA,EAAA,CACH,IACE;AAAA,MAAA,GACN;AAAA,MACCP,KAAgB3B,IACf,gBAAAiD,EAAC,OAAA,EAAI,WAAU,6EACZ,UAAA;AAAA,QAAAtB,KAAgB1C,IACf,gBAAAkD;AAAA,UAACyC;AAAA,UAAA;AAAA,YACC,UAAA3F;AAAA,YACA,SAAS2C,EAAgB;AAAA,YACzB,eAAeA,EAAgB;AAAA,YAC/B,iBAAiBA,EAAgB;AAAA,YACjC,iBAAiBA,EAAgB;AAAA,YACjC,SAASA,EAAgB;AAAA,UAAA;AAAA,QAAA,IAEzB;AAAA,QACH5B;AAAA,MAAA,EAAA,CACH,IACE;AAAA,IAAA,GACN,GAOI6E,KACJlF,KAAmBA,EAAgB,SAAS,IAC1C,gBAAAsD,EAAC,OAAA,EAAI,WAAU,kDACb,UAAA;AAAA,MAAA,gBAAAd,EAAC,QAAA,EAAK,WAAU,sDACb,UAAA,EAAE,4CAA4C;AAAA,QAC7C,cAAc;AAAA,MAAA,CACf,GACH;AAAA,MACA,gBAAAA,EAAC,SAAI,WAAU,oDACZ,YAAgB,IAAI,CAAC2C,GAAKC,MAAU;AACnC,cAAMC,IACJ,CAAC,CAACF,EAAI,eAAe,OACrBrC,GAAgBqC,EAAI,eAAe,GAAG,GAClCG,IAAW,EAAE,2CAA2C;AAAA,UAC5D,UAAUH,EAAI;AAAA,UACd,MAAMA,EAAI,eAAe;AAAA,UACzB,cAAc;AAAA,QAAA,CACf;AACD,eAAOE,IACL,gBAAA7C;AAAA,UAACY;AAAA,UAAA;AAAA,YAEC,MAAM+B,EAAI,eAAe;AAAA,YACzB,QAAO;AAAA,YACP,WAAU;AAAA,YAEV,UAAA,gBAAA3C,EAAC+C,IAAA,EAAI,OAAOD,GAAU,SAAQ,UAAA,CAAU;AAAA,UAAA;AAAA,UALnC,GAAGH,EAAI,QAAQ,IAAIC,CAAK;AAAA,QAAA,IAQ/B,gBAAA5C;AAAA,UAAC+C;AAAA,UAAA;AAAA,YAEC,OAAOD;AAAA,YACP,SAAQ;AAAA,UAAA;AAAA,UAFH,GAAGH,EAAI,QAAQ,IAAIC,CAAK;AAAA,QAAA;AAAA,MAKnC,CAAC,EAAA,CACH;AAAA,IAAA,EAAA,CACF,IACE,MAWAI,KAA+BtC,EAAK,IAAI,CAACuC,OAAS;AAAA,MACtD,IAAIA,EAAI;AAAA,MACR,OAAOA,EAAI;AAAA,MACX,OAAOA,EAAI;AAAA,MACX,MAAMA,EAAI;AAAA,IAAA,EACV,GACIC,KAA2CpG,KAAY;AAAA,MAC3D,EAAE,IAAI,WAAW,SAAS,IAAI,QAAQkG,GAAA;AAAA,IAAa,GAK/CG,KAAQrG,IAAW2C,EAAgB,UAAU1C,GAC7CqG,KAAgBC;AAAA,MACpBH;AAAA,MACAC;AAAA,IAAA,EACA,QAAQ,CAACG,MAAaA,EAAS,MAAM,GAEjCC,KACJ,gBAAAzC,EAAC,OAAA,EAAI,WAAW,uBAAuBL,EAAY,IAChD,UAAA;AAAA,MAAA+B;AAAA,MACAY,GAAc,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAatB,gBAAApD,EAAC,OAAA,EAAI,WAAU,yBACb,UAAA,gBAAAA;AAAA,UAACwD;AAAA,UAAA;AAAA,YACC,QAAO;AAAA,YACP,WAAU;AAAA,YAET,UAAAJ,GAAc,IAAI,CAACK,MAClB,gBAAAzD;AAAA,cAAC0D;AAAA,cAAA;AAAA,gBAEC,MAAMD,EAAM,QAAQ;AAAA,gBACpB,OAAOA,EAAM;AAAA,gBACb,WAAW,gBAAAzD,EAAC2D,IAAA,EAAkB,OAAAF,EAAA,CAAc;AAAA,gBAG5C,WAAU;AAAA,gBACV,iBAAeA,EAAM;AAAA,gBACrB,OACE,gBAAAzD;AAAA,kBAAC4D;AAAA,kBAAA;AAAA,oBACC,OAAAH;AAAA,oBACA,UAAAvF;AAAA,oBACA,aAAAC;AAAA,oBACA,UAAUC;AAAA,oBACV,QAAAT;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACF;AAAA,cAfG8F,EAAM;AAAA,YAAA,CAkBd;AAAA,UAAA;AAAA,QAAA,EACH,CACF;AAAA,UACE;AAAA,MACHf;AAAA,IAAA,GACH,GAGImB,KAAQjG,IAAUyE,KAAekB;AAEvC,WACE,gBAAAvD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAApB;AAAA,QACA,MAAK;AAAA,QAML,cAAYhB,KAAWY,IAAYmB,KAAoB;AAAA,QACvD,mBAAiB/B,KAAWY,IAAY,SAAYO;AAAA,QACpD,aAAWnB,KAAW;AAAA,QACtB,kBAAe;AAAA,QACf,qBAAmBa;AAAA,QACnB,gBAAcF;AAAA,QACd,IAAAE;AAAA,QACA,WAAW5C,GAAa,EAAE,SAAAyC,GAAS,SAAAC,GAAS,WAAAG,IAAW;AAAA,QACtD,GAAGC;AAAA,QAEH,UAAAL,MAAY,aACX,gBAAA0B,EAAC8D,IAAA,EAAK,SAAQ,YACZ,UAAA,gBAAA9D,EAAC8D,GAAK,MAAL,EAAW,UAAAD,GAAA,CAAM,EAAA,CACpB,IAEAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEAxH,GAAmB,cAAc;","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"patient-summary-card-B1jvxdY8.js","sources":["../../node_modules/lucide-react/dist/esm/icons/file-exclamation-point.mjs","../../node_modules/lucide-react/dist/esm/icons/message-square-warning.mjs","../../src/components/patient-summary-card/patient-summary-card.agent.ts","../../src/components/patient-summary-card/patient-summary-card.tsx"],"sourcesContent":["/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\",\n key: \"1oefj6\"\n }\n ],\n [\"path\", { d: \"M12 9v4\", key: \"juzpu7\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n];\nconst FileExclamationPoint = createLucideIcon(\"file-exclamation-point\", __iconNode);\n\nexport { __iconNode, FileExclamationPoint as default };\n//# sourceMappingURL=file-exclamation-point.mjs.map\n","/**\n * @license lucide-react v1.22.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.mjs';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\",\n key: \"18887p\"\n }\n ],\n [\"path\", { d: \"M12 15h.01\", key: \"q59x07\" }],\n [\"path\", { d: \"M12 7v4\", key: \"xawao1\" }]\n];\nconst MessageSquareWarning = createLucideIcon(\"message-square-warning\", __iconNode);\n\nexport { __iconNode, MessageSquareWarning as default };\n//# sourceMappingURL=message-square-warning.mjs.map\n","import type { AgentAdapter } from '../../agent/types';\nimport type { PatientSummaryCardHandle } from './patient-summary-card';\n\n/* -------------------------------------------------------------------- */\n/* Agent adapter — PatientSummaryCard */\n/* */\n/* Read-only adapter. Surfaces a STRUCTURAL snapshot of the patient */\n/* overview — counts, flags, and the consumer id only. Never the patient */\n/* name, age, contact details, or any clinical content, so an agent / */\n/* MCP runtime can answer \"does this patient have unpaid balances / */\n/* unsigned documents / AI consent?\" without re-parsing the DOM and */\n/* without leaking PHI (PRS §Security). */\n/* -------------------------------------------------------------------- */\n\nexport const patientSummaryCardAgent: AgentAdapter<PatientSummaryCardHandle> = {\n id: 'patient-summary-card',\n // The agent surface is a structural snapshot only — the single handle method\n // is a getSummary projection. The card MAY be human-customized (the optional\n // per-context \"Customize fields\" cog), but that field reordering is a UI\n // concern and is deliberately NOT exposed as an agent action; programmatic\n // field-set control lives on PatientDetails' adapter (set_field_order).\n capabilities: [],\n state: {\n summary: {\n type: '{ id?: string; hasUnpaid: boolean; unsignedDocumentsCount: number; highlightedAnamnesisCount: number; aiConsentGranted: boolean }',\n descriptionKey: 'ui.agent.patientSummaryCard.state.summary',\n description:\n 'Structural summary of the patient card — identifiers, counts, and consent flags only. Never patient identity or clinical content.',\n read: (handle) => handle.getSummary(),\n },\n },\n actions: {},\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'patient-summary-card',\n description: 'Marks the PatientSummaryCard root region.',\n },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","import {\n forwardRef,\n useId,\n useMemo,\n type ComponentPropsWithoutRef,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport {\n ArrowUpRight,\n CalendarDays,\n FileExclamationPoint,\n Mail,\n MapPin,\n MessageSquareWarning,\n Phone,\n ShieldCheck,\n Astroid,\n Users,\n type LucideIcon,\n} from 'lucide-react';\nimport { Avatar } from '../avatar/avatar';\nimport { Badge } from '../badge/badge';\nimport { IconButton } from '../button/icon-button';\nimport { Card } from '../card/card';\nimport { KeyValueList, KeyValuePair } from '../key-value-pair/key-value-pair';\nimport { Link } from '../link/link';\nimport { Skeleton } from '../skeleton/skeleton';\nimport { Tag } from '../tag/tag';\nimport { TransactionChip } from '../transaction-chip/transaction-chip';\nimport { Tooltip } from '../tooltip';\nimport { HoverCard } from '../hover-card';\nimport { isSafeEntityUrl } from '../_shared/is-safe-url';\nimport {\n resolveVisibleFields,\n type PatientField,\n type PatientFieldSection,\n} from '../_shared/patient-fields';\nimport { usePatientFieldVisibility } from '../_shared/field-visibility';\nimport { FieldVisibilityCog } from '../_shared/field-visibility-cog';\nimport { AgeChip, NeutralChip, SexChip } from '../_shared/field-value';\nimport {\n PatientFieldLabel,\n PatientFieldValueCell,\n} from '../_shared/patient-field-row';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { patientSummaryCardAgent } from './patient-summary-card.agent';\n\n/** A section list reference that stays stable across renders (legacy mode). */\nconst NO_SECTIONS: PatientFieldSection[] = [];\n\n/* -------------------------------------------------------------------- */\n/* PatientSummaryCard */\n/* */\n/* The patient-overview profile card every AlfaDocs in-app surface */\n/* composes by hand today (platform patient header, alfascribe patient */\n/* sidebar, check-in landing). Templated on ContactProfileCard: composes */\n/* Card + Avatar + KeyValueList + KeyValuePair + Badge + Tag + */\n/* TransactionChip + Link so the contact rows share a column and every */\n/* row uses the same lucide icon family. */\n/* */\n/* The kit owns the ORDER, ICONS, and LABELS — consumers pass data. No */\n/* free-text clinical content (anamnesis notes, diagnoses) ever lives */\n/* here: only counts/flags/relations are surfaced, so the card stays */\n/* PHI-light and the agent state can be derived without leaking patient */\n/* identity. */\n/* */\n/* All visible text flows through `useTranslation('ui')` against the */\n/* `patientSummaryCard.*` namespace. */\n/* -------------------------------------------------------------------- */\n\n/* -------------------------------------------------------------------- */\n/* CVA — root */\n/* -------------------------------------------------------------------- */\n\nconst rootVariants = cva('ds:w-full ds:text-[color:var(--foreground)]', {\n variants: {\n // Matches the kit's other `surface` props (ContactProfileCard,\n // OperatorHero). `'elevated'` wraps the content in `<Card>`.\n surface: {\n flat: '',\n elevated: '',\n },\n // Density tunes the avatar size + body padding. `comfortable` reads\n // as a page header; `compact` fits an embedded sidebar / aside.\n density: {\n comfortable: '',\n compact: '',\n },\n },\n defaultVariants: {\n surface: 'elevated',\n density: 'comfortable',\n },\n});\n\n/* -------------------------------------------------------------------- */\n/* Public types */\n/* -------------------------------------------------------------------- */\n\n/** Patient phone number — already formatted for display by the consumer. */\nexport interface PatientSummaryCardPhone {\n /** Display string, e.g. `\"+39 055 123 4567\"`. Compiled into a `tel:` link. */\n prefixAndNumber: string;\n /** Optional label that distinguishes this number (e.g. \"Mobile\"). */\n label?: string;\n /** Whether SMS is enabled for this number — shows a small \"SMS\" chip. */\n smsEnabled?: boolean;\n}\n\n/** A family relation row — links one patient to another. */\nexport interface PatientSummaryCardFamilyRelation {\n /** Localised relation label, consumer-supplied (e.g. \"Mother\", \"Child\"). */\n relation: string;\n /** The related patient — name + optional in-app profile URL. */\n relatedPatient: {\n name: string;\n url?: string;\n };\n}\n\n/** Operator the patient is assigned to. */\nexport interface PatientSummaryCardAssignee {\n name: string;\n avatarUrl?: string;\n}\n\n/** AI-consent grant metadata — structural only, never the consented content. */\nexport interface PatientSummaryCardAiConsent {\n /** ISO-8601 / display string of when consent was granted. */\n grantedAt: string;\n /** Optional name of who recorded the grant. */\n grantedBy?: string;\n}\n\n/** Addressable attention flags — the keys `onFlagActivate` accepts. */\nexport type PatientSummaryCardFlagId =\n | 'highlightedAnamnesis'\n | 'unsignedDocuments'\n | 'unpaid';\n\n/** Status flags rendered as glyph badges (counts / amounts only — no PHI). */\nexport interface PatientSummaryCardFlags {\n /** Number of anamnesis answers highlighted for clinical attention. */\n highlightedAnamnesisCount?: number;\n /** Outstanding balance in the smallest currency unit (cents). */\n unpaidAmountCents?: number;\n /** Number of documents awaiting the patient's signature. */\n unsignedDocumentsCount?: number;\n}\n\n/** Marketing-consent tri-state. */\nexport type PatientSummaryCardMarketingConsent = 'no' | 'yes' | 'not_specified';\n\nexport interface PatientSummaryCardHandle {\n /** Structural snapshot — identifiers and counts only, never patient identity. */\n getSummary: () => {\n id?: string;\n hasUnpaid: boolean;\n unsignedDocumentsCount: number;\n highlightedAnamnesisCount: number;\n aiConsentGranted: boolean;\n };\n}\n\nexport interface PatientSummaryCardProps extends Omit<\n ComponentPropsWithoutRef<'div'>,\n 'aria-label' | 'children'\n> {\n /** Patient display name. Rendered as the heading. */\n name: string;\n /** Honorific — `'mr'` / `'ms'`. Prepended to the name in the heading. */\n title?: 'mr' | 'ms';\n /** Patient age in whole years — rendered in the identity line. */\n ageYears?: number;\n /** Date of birth — already formatted for display by the consumer. */\n dateOfBirth?: string;\n /** Biological sex marker — `'m'` / `'f'`. Drives the identity-line glyph copy. */\n gender?: 'm' | 'f';\n /** Optional avatar / photo URL. Falls back to initials. */\n avatarUrl?: string;\n /**\n * In-app patient profile URL. When safe, the heading becomes a link.\n * Guarded by the shared `isSafeEntityUrl` allow-list — unsafe URLs are\n * dropped and the heading renders as plain text.\n */\n patientUrl?: string;\n\n /* ----- Shared field model (preferred) ----- */\n\n /**\n * Patient fields in the shared model — the SAME `sections` shape\n * `PatientDetails` consumes (`@alfadocs/ui-kit` `PatientFieldSection`).\n * When provided, the card renders these (honouring `visibleFieldOrder`)\n * instead of the legacy contact props, so a consumer defines its patient-\n * field registry once and reuses it across every patient surface.\n *\n * The card renders each field's `label`, `value`, and `icon` only — it is\n * flat (section headings are not shown in the body) and never inline-edits;\n * `sensitive` / `copyable` / `mono` / `editable` are honoured by\n * `PatientDetails`, not the card (so the PHI lock glyph does not appear here).\n *\n * Pass `onVisibleFieldsChange` alongside `sections` to make THIS placement\n * self-curating (a \"Customize fields\" cog appears — show/hide + drag-and-drop\n * reorder).\n */\n sections?: PatientFieldSection[];\n /**\n * Ordered visible field ids for THIS placement. The order is a\n * per-INSTANCE, per-CONTEXT preference the kit never persists — wire it to\n * whatever scope the consumer wants (e.g. a global per-user setting, or a\n * different config in the care-plan view vs the patient folder). The same\n * field vocabulary can therefore display differently in different parts of\n * the app. Omit (`undefined`) ⇒ show every field; an explicit empty array\n * `[]` ⇒ show none (a card that starts collapsed to name + identity chips and\n * reveals fields via the cog). Also applied to the legacy contact rows (ids\n * `email` / `phone` / `cityProvince` / `marketingConsent` / `aiConsent` /\n * `assignedTo`).\n */\n visibleFieldOrder?: string[];\n /**\n * Make this card's field set user-customizable. When provided alongside\n * `sections`, a \"Customize fields\" cog renders in the header (show/hide +\n * drag-and-drop / Alt+Arrow reorder), and this fires with the next ordered\n * visible set. The consumer owns persistence + its scope — editing here\n * writes only THIS context's preference, never a shared/global one.\n */\n onVisibleFieldsChange?: (orderedIds: string[]) => void;\n\n /* ----- Contact rows (legacy — prefer `sections`) ----- */\n\n /** @deprecated Pass via `sections`. Patient email — `mailto:` link when `emailEnabled`. */\n email?: string;\n /** Whether email contact is enabled — gates the `mailto:` link. */\n emailEnabled?: boolean;\n /** Phone number block. Compiled into a `tel:` link. */\n phone?: PatientSummaryCardPhone;\n /** City / province display string. */\n cityProvince?: string;\n\n /* ----- Consent ----- */\n\n /** Marketing-consent tri-state. */\n marketingConsent?: PatientSummaryCardMarketingConsent;\n /** AI-consent grant metadata. When present, an \"AI consent\" row renders. */\n aiConsent?: PatientSummaryCardAiConsent;\n\n /* ----- Status flags ----- */\n\n /** Counts / amounts surfaced as glyph badges. */\n flags?: PatientSummaryCardFlags;\n\n /* ----- Relations & assignment ----- */\n\n /** Family relations — rendered as `<Tag>` chips, optionally linked. */\n familyRelations?: PatientSummaryCardFamilyRelation[];\n /** Operator the patient is assigned to. */\n assignedTo?: PatientSummaryCardAssignee;\n\n /* ----- Formatting ----- */\n\n /** ISO-4217 currency code for the unpaid-amount chip. Defaults to `EUR`. */\n currency?: string;\n /** BCP-47 locale override. Defaults to the active i18next language. */\n locale?: string;\n\n /* ----- States ----- */\n\n /** Render the skeleton loading placeholder. */\n loading?: boolean;\n\n /* ----- Slots & callbacks ----- */\n\n /** Rendered at the inline-end of the heading row (e.g. an action menu). */\n actionSlot?: ReactNode;\n\n /**\n * Make an attention chip actionable. A handler turns that chip into a\n * button — \"2 unsigned documents\" opens the signing flow, the unpaid\n * balance opens invoicing. Without a handler the chip stays a read-only\n * badge, which is the default: most surfaces have nowhere to send the\n * reader.\n */\n onFlagActivate?: Partial<Record<PatientSummaryCardFlagId, () => void>>;\n /**\n * Explain a chip on hover / focus. The chip states WHAT (\"2 unsigned\n * documents\"); this states what the reader cannot see — how the signature\n * was requested, why the balance is outstanding.\n *\n * A string renders a `Tooltip`; a node renders a `HoverCard` with that node\n * as its content, for a host that wants the fuller card grammar (an eyebrow,\n * fact rows, a hint line). Either way the chip's own text stays the\n * accessible name and the surface only describes it.\n */\n flagHover?: Partial<Record<PatientSummaryCardFlagId, ReactNode>>;\n /**\n * Accessible name for the open button a hover CARD shows in its top-end\n * corner. The button appears only where the flag has BOTH a card and an\n * `onFlagActivate` handler — it mirrors the chip's own click so a pointer\n * that has travelled into the card can still act. Name the destination\n * (\"Open signing\"), not the gesture.\n *\n * Without a label there is no button: a card that merely describes should\n * not sprout an affordance the chip does not have.\n */\n flagOpenLabel?: Partial<Record<PatientSummaryCardFlagId, string>>;\n /**\n * Extra chips appended to the attention row, for signals the CARD cannot\n * model because they do not belong to the patient. An appointment panel\n * adds its own to-invoice and paid-online chips here; the card keeps its\n * patient-level flags and does not grow an appointment vocabulary.\n */\n extraChips?: ReactNode;\n\n /* ----- Inline editing (kit-owned controls, consumer-owned write) ----- */\n\n /**\n * Master switch — show the edit affordance on fields marked `editable` in\n * `sections`. The card edits through the SAME shared control as\n * `PatientDetails`, so a field offers the same affordance and the same\n * validation wherever it is shown.\n */\n editable?: boolean;\n /**\n * The single write channel. A rejected promise keeps the row in edit mode\n * and shows the message inline — the card never optimistically mutates the\n * value it was given.\n */\n onFieldSave?: (fieldId: string, value: unknown) => Promise<void>;\n /** Return a message to block the save and keep the row in edit mode. */\n validateField?: (fieldId: string, value: unknown) => string | null;\n /** Fires when the whole card / heading is activated. */\n onActivate?: () => void;\n\n /* ----- Styling ----- */\n\n /** `'elevated'` (default) wraps in `<Card>`; `'flat'` drops the chrome. */\n surface?: 'flat' | 'elevated';\n /** `'comfortable'` (default) reads as a header; `'compact'` for asides. */\n density?: 'comfortable' | 'compact';\n\n /* ----- a11y ----- */\n\n /** Override the default region aria-label. */\n 'aria-label'?: string;\n /** Agent-readiness consumer id, surfaced as `data-component-id`. */\n id?: string;\n}\n\n/* -------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------- */\n\n/** Strip everything except digits + leading `+` for `tel:` URLs. */\nfunction normalisePhone(raw: string): string {\n return raw.replace(/[^\\d+]/g, '');\n}\n\n/* -------------------------------------------------------------------- */\n/* Flag glyphs — the closed set of status indicators */\n/* -------------------------------------------------------------------- */\n\n/** The closed set of status-flag keys (icon + tonal variant defined below). */\ntype FlagKey = 'highlightedAnamnesis' | 'unsignedDocuments';\n\nconst FLAG_ICON: Record<FlagKey, LucideIcon> = {\n highlightedAnamnesis: MessageSquareWarning,\n unsignedDocuments: FileExclamationPoint,\n};\n\nconst FLAG_VARIANT: Record<FlagKey, 'warning' | 'error'> = {\n highlightedAnamnesis: 'warning',\n unsignedDocuments: 'error',\n};\n\n/** English fallbacks for the flag badge accessible names (count-interpolated). */\nconst FLAG_LABEL_DEFAULTS: Record<FlagKey, string> = {\n highlightedAnamnesis: '{{count}} highlighted anamnesis answers',\n unsignedDocuments: '{{count}} unsigned documents',\n};\n\n/** English fallbacks for the marketing-consent tri-state chip. */\nconst MARKETING_CONSENT_DEFAULTS: Record<\n PatientSummaryCardMarketingConsent,\n string\n> = {\n yes: 'Yes',\n no: 'No',\n not_specified: 'Not specified',\n};\n\n/* -------------------------------------------------------------------- */\n/* Component */\n/* -------------------------------------------------------------------- */\n\nexport const PatientSummaryCard = forwardRef<\n HTMLDivElement,\n PatientSummaryCardProps\n>(\n (\n {\n name,\n title,\n ageYears,\n dateOfBirth,\n gender,\n avatarUrl,\n patientUrl,\n sections,\n visibleFieldOrder,\n onVisibleFieldsChange,\n email,\n emailEnabled = false,\n phone,\n cityProvince,\n marketingConsent,\n aiConsent,\n flags,\n familyRelations,\n assignedTo,\n currency = 'EUR',\n locale,\n loading = false,\n actionSlot,\n onFlagActivate,\n flagHover,\n flagOpenLabel,\n extraChips,\n editable = false,\n onFieldSave,\n validateField,\n onActivate,\n surface = 'elevated',\n density = 'comfortable',\n 'aria-label': ariaLabel,\n id,\n className,\n ...rest\n },\n ref,\n ) => {\n // Pinned to `ui` as a guard for a host that inits i18next with its own\n // `defaultNS`: the flag badges pass a defaultValue, so a miss is silent.\n const { t, i18n } = useTranslation('ui');\n const headingId = useId();\n const activeLocale = locale ?? i18n.language ?? 'en';\n\n const unpaidAmountCents = flags?.unpaidAmountCents;\n const unsignedDocumentsCount = flags?.unsignedDocumentsCount ?? 0;\n const highlightedAnamnesisCount = flags?.highlightedAnamnesisCount ?? 0;\n const hasUnpaid = unpaidAmountCents != null && unpaidAmountCents > 0;\n\n // Imperative handle — structural snapshot only (counts/flags/ids),\n // never the patient name or any clinical content.\n const handle = useMemo<PatientSummaryCardHandle>(\n () => ({\n getSummary: () => ({\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsentGranted: aiConsent != null,\n }),\n }),\n [\n id,\n hasUnpaid,\n unsignedDocumentsCount,\n highlightedAnamnesisCount,\n aiConsent,\n ],\n );\n useAgentRegistration(patientSummaryCardAgent, handle, id);\n\n // Per-context field visibility. The cog (and live reordering) only engages\n // with the shared `sections` model AND an `onVisibleFieldsChange` handler;\n // legacy contact-prop cards stay read-only. The order is this placement's\n // own preference — never shared across surfaces.\n const customizable = !!sections && !!onVisibleFieldsChange;\n const fieldVisibility = usePatientFieldVisibility(sections ?? NO_SECTIONS, {\n value: visibleFieldOrder,\n onChange: onVisibleFieldsChange,\n });\n\n const resolvedAriaLabel =\n ariaLabel ??\n t('patientSummaryCard.regionLabel', { defaultValue: 'Patient overview' });\n\n // Heading text: optional honorific prefix + name.\n const TITLE_DEFAULTS: Record<'mr' | 'ms', string> = {\n mr: 'Mr.',\n ms: 'Ms.',\n };\n const honorific = title\n ? t(`patientSummaryCard.title.${title}`, {\n defaultValue: TITLE_DEFAULTS[title],\n })\n : undefined;\n // A translated PATTERN, not a hardcoded `${honorific} ${name}` join:\n // several of the 18 locales order or punctuate a name-with-title\n // differently (or drop it) — a locale can override the pattern\n // without touching this component.\n const headingText = honorific\n ? t('patientSummaryCard.nameWithHonorific', {\n honorific,\n name,\n defaultValue: '{{honorific}} {{name}}',\n })\n : name;\n\n // Identity line: the canonical sex / age / dob chips below the name — the\n // SAME chips the field model renders, so the header and the field rows\n // agree. Each chip is added only when its prop is present. (`dateOfBirth`\n // is a consumer-preformatted display string, so it goes through NeutralChip\n // directly rather than the date-parsing `dob` kind.)\n const identityChips: ReactNode[] = [];\n if (gender) {\n identityChips.push(<SexChip key=\"sex\" code={gender} />);\n }\n if (ageYears != null) {\n identityChips.push(<AgeChip key=\"age\" years={ageYears} />);\n }\n if (dateOfBirth) {\n identityChips.push(\n <NeutralChip key=\"dob\" icon={<CalendarDays />}>\n {dateOfBirth}\n </NeutralChip>,\n );\n }\n\n const isUrlSafe = !!patientUrl && isSafeEntityUrl(patientUrl);\n\n const avatarSize = density === 'comfortable' ? 'xl' : 'lg';\n const headingClass =\n density === 'comfortable' ? 'type-title-card' : 'type-title-item';\n const bodyGapClass =\n density === 'comfortable'\n ? 'ds:gap-[var(--spacing-md)]'\n : 'ds:gap-[var(--spacing-sm)]';\n\n /* ---------------------------------------------------------------- */\n /* Contact rows */\n /* ---------------------------------------------------------------- */\n\n const rows: Array<{\n key: string;\n icon: ReactElement;\n label: string;\n value: ReactNode;\n }> = [];\n\n if (email) {\n rows.push({\n key: 'email',\n icon: <Mail aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.email', { defaultValue: 'Email' }),\n value: emailEnabled ? (\n <Link\n href={`mailto:${email}`}\n intent=\"default\"\n onClick={onActivate}\n dir=\"ltr\"\n >\n {email}\n </Link>\n ) : (\n <span className=\"ds:text-[color:var(--muted-foreground)]\" dir=\"ltr\">\n {email}\n </span>\n ),\n });\n }\n\n if (phone) {\n rows.push({\n key: 'phone',\n icon: <Phone aria-hidden=\"true\" />,\n label:\n phone.label ??\n t('patientSummaryCard.label.phone', { defaultValue: 'Phone' }),\n value: (\n <span className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-2xs)]\">\n <Link\n href={`tel:${normalisePhone(phone.prefixAndNumber)}`}\n intent=\"default\"\n dir=\"ltr\"\n >\n {phone.prefixAndNumber}\n </Link>\n {phone.smsEnabled ? (\n <Badge variant=\"success\" size=\"sm\">\n {t('patientSummaryCard.value.smsEnabled', {\n defaultValue: 'SMS',\n })}\n </Badge>\n ) : null}\n </span>\n ),\n });\n }\n\n if (cityProvince) {\n rows.push({\n key: 'cityProvince',\n icon: <MapPin aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.cityProvince', {\n defaultValue: 'City / province',\n }),\n value: cityProvince,\n });\n }\n\n if (marketingConsent) {\n rows.push({\n key: 'marketingConsent',\n icon: <ShieldCheck aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.marketingConsent', {\n defaultValue: 'Marketing consent',\n }),\n value: (\n <Badge\n variant={\n marketingConsent === 'yes'\n ? 'success'\n : marketingConsent === 'no'\n ? 'error'\n : 'neutral'\n }\n size=\"sm\"\n withDot\n >\n {t(`patientSummaryCard.marketingConsent.${marketingConsent}`, {\n defaultValue: MARKETING_CONSENT_DEFAULTS[marketingConsent],\n })}\n </Badge>\n ),\n });\n }\n\n if (aiConsent) {\n rows.push({\n key: 'aiConsent',\n icon: <Astroid aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.aiConsent', {\n defaultValue: 'AI consent',\n }),\n value: aiConsent.grantedBy\n ? t('patientSummaryCard.value.aiConsentGrantedBy', {\n date: aiConsent.grantedAt,\n by: aiConsent.grantedBy,\n defaultValue: 'Granted {{date}} by {{by}}',\n })\n : t('patientSummaryCard.value.aiConsentGrantedAt', {\n date: aiConsent.grantedAt,\n defaultValue: 'Granted {{date}}',\n }),\n });\n }\n\n if (assignedTo) {\n rows.push({\n key: 'assignedTo',\n icon: <Users aria-hidden=\"true\" />,\n label: t('patientSummaryCard.label.assignedTo', {\n defaultValue: 'Assigned to',\n }),\n value: (\n <span className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <Avatar\n size=\"xs\"\n name={assignedTo.name}\n src={assignedTo.avatarUrl}\n />\n <span>{assignedTo.name}</span>\n </span>\n ),\n });\n }\n\n /* ---------------------------------------------------------------- */\n /* Attention-flag chips (VERBOSE — shown in the identity line) */\n /* */\n /* The unpaid balance + warning counts sit in the chip row under the */\n /* name, BEFORE the sex / age chips, each as a self-describing chip */\n /* (\"2 unsigned documents\") rather than a collapsed count badge in a */\n /* separate strip — the attention signals lead the patient's chips. */\n /* ---------------------------------------------------------------- */\n\n const flagBadges: Array<{ key: FlagKey; count: number }> = [];\n if (highlightedAnamnesisCount > 0) {\n flagBadges.push({\n key: 'highlightedAnamnesis',\n count: highlightedAnamnesisCount,\n });\n }\n if (unsignedDocumentsCount > 0) {\n flagBadges.push({\n key: 'unsignedDocuments',\n count: unsignedDocumentsCount,\n });\n }\n\n /* A chip becomes a BUTTON only when the host gave it somewhere to go.\n The chip's own text is already its accessible name, so the wrapper adds\n no label of its own and contributes no padding — the strip's rhythm is\n identical whether or not a chip is actionable. */\n /* A chip becomes a CONTROL when it has something to reveal or somewhere\n to go, and the trigger is always a real <button> — `asChild` on a bare\n <span> badge stamps `aria-haspopup` onto something a keyboard can never\n reach, which is both a dead end and an axe violation.\n\n The division of labour is the same on every chip: the chip opens its\n card (hover, or click / Enter for keyboard and touch), and the card's\n own top-end button performs the action. One gesture to learn, and no\n chip that acts differently from its neighbour. */\n const asAction = (id: PatientSummaryCardFlagId, chip: ReactNode) => {\n const onActivateFlag = onFlagActivate?.[id];\n const hover = flagHover?.[id];\n if (hover == null && !onActivateFlag) return chip;\n\n const triggerClasses =\n 'ds:inline-flex ds:cursor-pointer ds:rounded-[var(--radius-full)] ds:p-0 ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]';\n\n // No card: the chip itself is the action.\n if (hover == null) {\n return (\n <button\n key={id}\n type=\"button\"\n data-flag-action={id}\n onClick={onActivateFlag}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n }\n\n const trigger = (\n <button\n key={id}\n type=\"button\"\n data-flag-action={onActivateFlag ? id : undefined}\n data-flag-hover={id}\n className={triggerClasses}\n >\n {chip}\n </button>\n );\n\n // A string still renders a plain Tooltip, for a chip that needs naming\n // rather than a card.\n if (typeof hover === 'string') {\n return (\n <Tooltip key={id} label={hover} side=\"bottom\">\n {trigger}\n </Tooltip>\n );\n }\n\n return (\n <HoverCard key={id}>\n <HoverCard.Trigger asChild>{trigger}</HoverCard.Trigger>\n <HoverCard.Content\n side=\"bottom\"\n align=\"start\"\n size=\"sm\"\n headerAction={\n onActivateFlag && flagOpenLabel?.[id] ? (\n <IconButton\n icon={<ArrowUpRight />}\n /* Outline, not ghost: the card's own surface is already\n light, so a borderless glyph reads as decoration rather\n than a control. */\n intent=\"outline\"\n background=\"surface\"\n size=\"sm\"\n aria-label={flagOpenLabel[id] as string}\n onClick={onActivateFlag}\n />\n ) : undefined\n }\n >\n {hover}\n </HoverCard.Content>\n </HoverCard>\n );\n };\n\n const attentionChips: ReactNode[] = [];\n if (hasUnpaid) {\n attentionChips.push(\n asAction(\n 'unpaid',\n <TransactionChip\n key=\"unpaid\"\n state=\"debt\"\n amount={(unpaidAmountCents as number) / 100}\n currency={currency}\n locale={activeLocale}\n size=\"md\"\n showLabel\n />,\n ),\n );\n }\n flagBadges.forEach(({ key, count }) => {\n const FlagIcon = FLAG_ICON[key];\n // The Badge's visible text IS the count-interpolated label, so it's its\n // own accessible name — the leading glyph is decorative (aria-hidden).\n attentionChips.push(\n asAction(\n key,\n <Badge\n key={key}\n variant={FLAG_VARIANT[key]}\n size=\"md\"\n leading={<FlagIcon aria-hidden=\"true\" />}\n >\n {t(`patientSummaryCard.flag.${key}`, {\n count,\n defaultValue: FLAG_LABEL_DEFAULTS[key],\n })}\n </Badge>,\n ),\n );\n });\n if (extraChips) attentionChips.push(extraChips);\n\n /* ---------------------------------------------------------------- */\n /* Loading skeleton */\n /* ---------------------------------------------------------------- */\n\n const skeletonBody = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-md)]\">\n <Skeleton variant=\"circular\" size=\"lg\" />\n <div className=\"ds:flex ds:flex-1 ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <Skeleton variant=\"text\" width=\"60%\" />\n <Skeleton variant=\"text\" width=\"40%\" />\n </div>\n </div>\n <Skeleton variant=\"text\" lines={3} />\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Header */\n /* ---------------------------------------------------------------- */\n\n const heading = isUrlSafe ? (\n <Link\n href={patientUrl as string}\n intent=\"default\"\n weight=\"strong\"\n onClick={onActivate}\n className={`${headingClass} ds:no-underline`}\n >\n <span id={headingId}>{headingText}</span>\n </Link>\n ) : (\n <span\n id={headingId}\n className={`${headingClass} ds:text-[color:var(--foreground)]`}\n >\n {headingText}\n </span>\n );\n\n const header = (\n <div className=\"ds:flex ds:items-start ds:gap-[var(--spacing-md)]\">\n <Avatar\n size={avatarSize}\n name={name}\n src={avatarUrl}\n className=\"ds:shrink-0\"\n />\n <div className=\"ds:flex ds:min-w-0 ds:flex-1 ds:flex-col ds:gap-[var(--spacing-2xs)]\">\n {heading}\n {attentionChips.length > 0 || identityChips.length > 0 ? (\n <div className=\"ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-xs)]\">\n {/* Attention flags lead, then the sex / age / dob identity chips. */}\n {attentionChips}\n {identityChips}\n </div>\n ) : null}\n </div>\n {customizable || actionSlot ? (\n <div className=\"ds:ms-auto ds:flex ds:shrink-0 ds:items-center ds:gap-[var(--spacing-xs)]\">\n {customizable && sections ? (\n <FieldVisibilityCog\n sections={sections}\n visible={fieldVisibility.visible}\n onToggleField={fieldVisibility.toggleField}\n onToggleSection={fieldVisibility.toggleSection}\n onMoveFieldOnto={fieldVisibility.moveFieldOnto}\n onReset={fieldVisibility.reset}\n />\n ) : null}\n {actionSlot}\n </div>\n ) : null}\n </div>\n );\n\n /* ---------------------------------------------------------------- */\n /* Family relations */\n /* ---------------------------------------------------------------- */\n\n const familyBlock =\n familyRelations && familyRelations.length > 0 ? (\n <div className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-label ds:text-[color:var(--muted-foreground)]\">\n {t('patientSummaryCard.label.familyRelations', {\n defaultValue: 'Family relations',\n })}\n </span>\n <div className=\"ds:flex ds:flex-wrap ds:gap-[var(--spacing-2xs)]\">\n {familyRelations.map((rel, index) => {\n const safeUrl =\n !!rel.relatedPatient.url &&\n isSafeEntityUrl(rel.relatedPatient.url);\n const tagLabel = t('patientSummaryCard.value.familyRelation', {\n relation: rel.relation,\n name: rel.relatedPatient.name,\n defaultValue: '{{relation}}: {{name}}',\n });\n return safeUrl ? (\n <Link\n key={`${rel.relation}-${index}`}\n href={rel.relatedPatient.url as string}\n intent=\"default\"\n className=\"ds:no-underline\"\n >\n <Tag label={tagLabel} variant=\"neutral\" />\n </Link>\n ) : (\n <Tag\n key={`${rel.relation}-${index}`}\n label={tagLabel}\n variant=\"neutral\"\n />\n );\n })}\n </div>\n </div>\n ) : null;\n\n /* ---------------------------------------------------------------- */\n /* Body */\n /* ---------------------------------------------------------------- */\n\n // Field rows resolve through the SHARED model: when the consumer passes\n // `sections` (preferred), render those; otherwise wrap the legacy contact\n // rows as a single section. Either way `resolveVisibleFields` applies the\n // shared `visibleFieldOrder` preference, so the card and PatientDetails\n // always show the same fields, honouring the same per-user choice.\n const legacyFields: PatientField[] = rows.map((row) => ({\n id: row.key,\n label: row.label,\n value: row.value,\n icon: row.icon,\n }));\n const effectiveSections: PatientFieldSection[] = sections ?? [\n { id: 'contact', heading: '', fields: legacyFields },\n ];\n // With the shared `sections` model the order comes from the visibility hook\n // (so a cog reorder reflects live); legacy contact rows honour the raw\n // `visibleFieldOrder` prop.\n const order = sections ? fieldVisibility.visible : visibleFieldOrder;\n const visibleFields = resolveVisibleFields(\n effectiveSections,\n order,\n ).flatMap((resolved) => resolved.fields);\n\n const body = (\n <div className={`ds:flex ds:flex-col ${bodyGapClass}`}>\n {header}\n {visibleFields.length > 0 ? (\n // Container-queried so the fields flow into two columns when the\n // card is wide enough (the banner spans the full folder width), and\n // stay single-column in a narrow rail. The list's KeyValuePair\n // children already `col-span-3`; doubling the parent to six tracks\n // (`repeat(2, …)`) lets grid auto-flow place two fields per row while\n // each column keeps its own subgrid label/value alignment.\n // 672px, not the `@2xl` rem alias: container-query `rem` follows the\n // host root font-size, so a non-16px root moves the threshold.\n // Each label column stops at 20% of the card (every field has an\n // icon, so labels sit in the middle track of each group): a long\n // label wraps instead of squeezing its value, as KeyValueList's\n // single-column cap does at 40%.\n <div className=\"ds:@container/pfields\">\n <KeyValueList\n rowGap=\"sm\"\n className=\"ds:@[672px]/pfields:grid-cols-[repeat(2,auto_fit-content(20%)_minmax(0,1fr))]\"\n >\n {visibleFields.map((field) => (\n <KeyValuePair\n key={field.id}\n icon={field.icon ?? undefined}\n label={field.label}\n labelNode={<PatientFieldLabel field={field} />}\n // `group` is what reveals the edit pencil on hover / focus;\n // the cell itself carries no row markup.\n className=\"ds:group\"\n data-field-id={field.id}\n value={\n <PatientFieldValueCell\n field={field}\n editable={editable}\n onFieldSave={onFieldSave}\n validate={validateField}\n locale={locale}\n />\n }\n />\n ))}\n </KeyValueList>\n </div>\n ) : null}\n {familyBlock}\n </div>\n );\n\n const inner = loading ? skeletonBody : body;\n\n return (\n <div\n ref={ref}\n role=\"region\"\n // When the heading is rendered, the patient name (via\n // aria-labelledby) is the region's accessible name — the more\n // meaningful label than a generic \"Patient overview\". A consumer\n // aria-label still wins; the generic fallback only applies when\n // there is no heading to point at (loading state).\n aria-label={loading || ariaLabel ? resolvedAriaLabel : undefined}\n aria-labelledby={loading || ariaLabel ? undefined : headingId}\n aria-busy={loading || undefined}\n data-component=\"patient-summary-card\"\n data-component-id={id}\n data-density={density}\n id={id}\n className={rootVariants({ surface, density, className })}\n {...rest}\n >\n {surface === 'elevated' ? (\n <Card variant=\"elevated\">\n <Card.Body>{inner}</Card.Body>\n </Card>\n ) : (\n inner\n )}\n </div>\n );\n },\n);\n\nPatientSummaryCard.displayName = 'PatientSummaryCard';\n\n/** Variant unions re-exported for downstream typing. */\nexport type PatientSummaryCardSurface = NonNullable<\n VariantProps<typeof rootVariants>['surface']\n>;\nexport type PatientSummaryCardDensity = NonNullable<\n VariantProps<typeof rootVariants>['density']\n>;\n"],"names":["__iconNode","FileExclamationPoint","createLucideIcon","MessageSquareWarning","patientSummaryCardAgent","handle","NO_SECTIONS","rootVariants","cva","normalisePhone","raw","FLAG_ICON","FLAG_VARIANT","FLAG_LABEL_DEFAULTS","MARKETING_CONSENT_DEFAULTS","PatientSummaryCard","forwardRef","name","title","ageYears","dateOfBirth","gender","avatarUrl","patientUrl","sections","visibleFieldOrder","onVisibleFieldsChange","email","emailEnabled","phone","cityProvince","marketingConsent","aiConsent","flags","familyRelations","assignedTo","currency","locale","loading","actionSlot","onFlagActivate","flagHover","flagOpenLabel","extraChips","editable","onFieldSave","validateField","onActivate","surface","density","ariaLabel","id","className","rest","ref","i18n","useTranslation","headingId","useId","activeLocale","unpaidAmountCents","unsignedDocumentsCount","highlightedAnamnesisCount","hasUnpaid","useMemo","useAgentRegistration","customizable","fieldVisibility","usePatientFieldVisibility","resolvedAriaLabel","TITLE_DEFAULTS","honorific","headingText","identityChips","jsx","SexChip","AgeChip","NeutralChip","CalendarDays","isUrlSafe","isSafeEntityUrl","avatarSize","headingClass","bodyGapClass","rows","Mail","Link","Phone","jsxs","Badge","MapPin","ShieldCheck","Astroid","Users","Avatar","flagBadges","asAction","chip","onActivateFlag","hover","triggerClasses","trigger","Tooltip","HoverCard","IconButton","ArrowUpRight","attentionChips","TransactionChip","key","count","FlagIcon","skeletonBody","Skeleton","heading","header","FieldVisibilityCog","familyBlock","rel","index","safeUrl","tagLabel","Tag","legacyFields","row","effectiveSections","order","visibleFields","resolveVisibleFields","resolved","body","KeyValueList","field","KeyValuePair","PatientFieldLabel","PatientFieldValueCell","inner","Card"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
@@ -5,7 +5,7 @@ import { useTranslation as M } from "react-i18next";
|
|
|
5
5
|
import { B as O } from "./badge-BUk4RjTS.js";
|
|
6
6
|
import { C as D } from "./card-C85_Ndhb.js";
|
|
7
7
|
import { D as d } from "./description-list-BxzDN9o2.js";
|
|
8
|
-
import { K as Y, a as H } from "./key-value-pair-
|
|
8
|
+
import { K as Y, a as H } from "./key-value-pair-CB37UXsz.js";
|
|
9
9
|
import { T as j, A as ae } from "./transaction-chip-CohY6sTA.js";
|
|
10
10
|
import { u as W } from "./registry-DvAUVLHh.js";
|
|
11
11
|
import { H as te } from "./hash-CSQ9SChR.js";
|
|
@@ -439,4 +439,4 @@ export {
|
|
|
439
439
|
Ce as b,
|
|
440
440
|
me as p
|
|
441
441
|
};
|
|
442
|
-
//# sourceMappingURL=payment-request-card-
|
|
442
|
+
//# sourceMappingURL=payment-request-card-DPN5yklX.js.map
|