@alfadocs/ui-kit-debug 0.77.0 → 0.79.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/{alia-sidebar-w6B0TEx7.js → alia-sidebar-DzNz1gDf.js} +2 -2
- package/dist/_chunks/{alia-sidebar-w6B0TEx7.js.map → alia-sidebar-DzNz1gDf.js.map} +1 -1
- package/dist/_chunks/calendar-4dXTvsCz.js +1136 -0
- package/dist/_chunks/calendar-4dXTvsCz.js.map +1 -0
- package/dist/_chunks/calendar-event-card-C6qGtywL.js +257 -0
- package/dist/_chunks/calendar-event-card-C6qGtywL.js.map +1 -0
- package/dist/_chunks/{chat-input-BTCDqUDX.js → chat-input-QpHxBEnN.js} +32 -31
- package/dist/_chunks/chat-input-QpHxBEnN.js.map +1 -0
- package/dist/_chunks/document-preview-nwfulDEs.js +290 -0
- package/dist/_chunks/document-preview-nwfulDEs.js.map +1 -0
- package/dist/_chunks/{fiscal-code-input-DWA6C8x8.js → fiscal-code-input-QP9gkyDE.js} +2 -2
- package/dist/_chunks/fiscal-code-input-QP9gkyDE.js.map +1 -0
- package/dist/_chunks/{patient-details-zy76MRh7.js → patient-details-COvYWp2e.js} +2 -2
- package/dist/_chunks/{patient-details-zy76MRh7.js.map → patient-details-COvYWp2e.js.map} +1 -1
- package/dist/_chunks/signature-request-CEOrCDyk.js +341 -0
- package/dist/_chunks/signature-request-CEOrCDyk.js.map +1 -0
- package/dist/agent-catalog.json +1 -1
- package/dist/components/_shared/contrast-warning.d.ts +46 -0
- package/dist/components/_shared/contrast-warning.d.ts.map +1 -0
- package/dist/components/calendar/calendar.d.ts +284 -7
- package/dist/components/calendar/calendar.d.ts.map +1 -1
- package/dist/components/calendar/index.d.ts +1 -1
- package/dist/components/calendar/index.d.ts.map +1 -1
- package/dist/components/calendar/index.js +1 -1
- package/dist/components/calendar-event-card/calendar-event-card.d.ts +103 -0
- package/dist/components/calendar-event-card/calendar-event-card.d.ts.map +1 -0
- package/dist/components/calendar-event-card/index.d.ts +3 -0
- package/dist/components/calendar-event-card/index.d.ts.map +1 -0
- package/dist/components/calendar-event-card/index.js +5 -0
- package/dist/components/calendar-event-card/index.js.map +1 -0
- package/dist/components/chat-input/chat-input.d.ts.map +1 -1
- package/dist/components/chat-input/index.js +1 -1
- package/dist/components/document-preview/document-preview.d.ts +10 -0
- package/dist/components/document-preview/document-preview.d.ts.map +1 -1
- package/dist/components/document-preview/index.js +1 -1
- package/dist/components/fiscal-code-input/index.js +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/patient-details/index.js +1 -1
- package/dist/i18n/locales/ar.d.ts +6 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +6 -0
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +6 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +6 -0
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +6 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +6 -0
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +6 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +6 -0
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +6 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +6 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +6 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +6 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +6 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +6 -0
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +6 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +6 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +6 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +6 -0
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +6 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +6 -0
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +6 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +6 -0
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +6 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +6 -0
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +6 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +6 -0
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +6 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +6 -0
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +6 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +6 -0
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +6 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +6 -0
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +6 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +6 -0
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +6 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +6 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +252 -250
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.json +6 -0
- package/dist/locales/de.json +6 -0
- package/dist/locales/el.json +6 -0
- package/dist/locales/en.json +6 -0
- package/dist/locales/es.json +6 -0
- package/dist/locales/fr.json +6 -0
- package/dist/locales/hi.json +6 -0
- package/dist/locales/it.json +6 -0
- package/dist/locales/ja.json +6 -0
- package/dist/locales/nl.json +6 -0
- package/dist/locales/pl.json +6 -0
- package/dist/locales/pt.json +6 -0
- package/dist/locales/ro.json +6 -0
- package/dist/locales/ru.json +6 -0
- package/dist/locales/sq.json +6 -0
- package/dist/locales/sv.json +6 -0
- package/dist/locales/tr.json +6 -0
- package/dist/locales/zh.json +6 -0
- package/dist/patterns/alia-assistant/index.js +1 -1
- package/dist/patterns/signature-request/index.js +1 -1
- package/dist/patterns/signature-request/signature-request.d.ts +7 -0
- package/dist/patterns/signature-request/signature-request.d.ts.map +1 -1
- package/dist/tokens.css +9 -5
- package/package.json +5 -1
- package/dist/_chunks/calendar-DeAlFPsF.js +0 -1050
- package/dist/_chunks/calendar-DeAlFPsF.js.map +0 -1
- package/dist/_chunks/chat-input-BTCDqUDX.js.map +0 -1
- package/dist/_chunks/document-preview-CvHnHf6T.js +0 -243
- package/dist/_chunks/document-preview-CvHnHf6T.js.map +0 -1
- package/dist/_chunks/fiscal-code-input-DWA6C8x8.js.map +0 -1
- package/dist/_chunks/signature-request-C-mskXwi.js +0 -318
- package/dist/_chunks/signature-request-C-mskXwi.js.map +0 -1
- package/dist/components/calendar/contrast-warning.d.ts +0 -20
- package/dist/components/calendar/contrast-warning.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-event-card-C6qGtywL.js","sources":["../../node_modules/lucide-react/dist/esm/icons/ban.mjs","../../node_modules/lucide-react/dist/esm/icons/euro.mjs","../../node_modules/lucide-react/dist/esm/icons/thumbs-up.mjs","../../node_modules/lucide-react/dist/esm/icons/zap.mjs","../../src/components/_shared/contrast-warning.ts","../../src/components/calendar-event-card/calendar-event-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 [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M4.929 4.929 19.07 19.071\", key: \"196cmz\" }]\n];\nconst Ban = createLucideIcon(\"ban\", __iconNode);\n\nexport { __iconNode, Ban as default };\n//# sourceMappingURL=ban.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 [\"path\", { d: \"M4 10h12\", key: \"1y6xl8\" }],\n [\"path\", { d: \"M4 14h9\", key: \"1loblj\" }],\n [\n \"path\",\n {\n d: \"M19 6a7.7 7.7 0 0 0-5.2-2A7.9 7.9 0 0 0 6 12c0 4.4 3.5 8 7.8 8 2 0 3.8-.8 5.2-2\",\n key: \"1j6lzo\"\n }\n ]\n];\nconst Euro = createLucideIcon(\"euro\", __iconNode);\n\nexport { __iconNode, Euro as default };\n//# sourceMappingURL=euro.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: \"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\",\n key: \"emmmcr\"\n }\n ],\n [\"path\", { d: \"M7 10v12\", key: \"1qc93n\" }]\n];\nconst ThumbsUp = createLucideIcon(\"thumbs-up\", __iconNode);\n\nexport { __iconNode, ThumbsUp as default };\n//# sourceMappingURL=thumbs-up.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: \"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\",\n key: \"1xq2db\"\n }\n ]\n];\nconst Zap = createLucideIcon(\"zap\", __iconNode);\n\nexport { __iconNode, Zap as default };\n//# sourceMappingURL=zap.mjs.map\n","/* ------------------------------------------------------------------ */\n/* Shared contrast guardrail — Calendar + CalendarEventCard */\n/* */\n/* The consuming app supplies runtime hex pairs at several surfaces: */\n/* - event.backgroundColor / event.textColor (+ event.borderColor) */\n/* - modeBannerColor / modeBannerTextColor */\n/* - resource.color / resource.shortTitleTextColor */\n/* */\n/* When the text half of the pair is also a hex (i.e. both halves come */\n/* from the caller), we can validate them synchronously and warn the */\n/* consuming-app developer during DEV if the pair fails WCAG AA normal */\n/* text (4.5:1). When only the background half is supplied, */\n/* `resolveInk` derives a provably AA-safe black/white ink for it. */\n/* Every helper is a no-op in production builds. */\n/* ------------------------------------------------------------------ */\n\n/* Module-level dedup set — keyed on the (bg, fg, context) tuple so the\n same bad pair moving around the calendar only warns once per session.\n Exposed via `resetContrastWarnings()` for test isolation. */\nconst warnedTuples = new Set<string>();\n\n/** Reset the dedup set — intended for use between tests. */\nexport function resetContrastWarnings(): void {\n warnedTuples.clear();\n}\n\n/**\n * Parse a 3-char or 6-char `#RRGGBB` hex string into a linear sRGB\n * triple in the [0,1] range. Returns `null` for any input the caller\n * can't parse (malformed prefix, bad length, non-hex characters) —\n * the helper stays silent in that case rather than emitting noise.\n */\nfunction parseHex(hex: string): [number, number, number] | null {\n if (typeof hex !== 'string') return null;\n const trimmed = hex.trim();\n if (!trimmed.startsWith('#')) return null;\n const body = trimmed.slice(1);\n let r: number;\n let g: number;\n let b: number;\n if (body.length === 3) {\n if (!/^[0-9a-f]{3}$/i.test(body)) return null;\n r = parseInt(body[0] + body[0], 16);\n g = parseInt(body[1] + body[1], 16);\n b = parseInt(body[2] + body[2], 16);\n } else if (body.length === 6) {\n if (!/^[0-9a-f]{6}$/i.test(body)) return null;\n r = parseInt(body.slice(0, 2), 16);\n g = parseInt(body.slice(2, 4), 16);\n b = parseInt(body.slice(4, 6), 16);\n } else {\n return null;\n }\n return [r / 255, g / 255, b / 255];\n}\n\n/**\n * WCAG 2.1 relative luminance. Each channel is gamma-corrected then\n * weighted against the CIE photopic sensitivity of the human eye.\n * https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n */\nfunction relativeLuminance([r, g, b]: [number, number, number]): number {\n const lin = (c: number): number =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);\n}\n\n/**\n * WCAG 2.1 contrast ratio. Always returns a value in [1, 21]; the\n * relative-luminance lighter-over-darker convention is applied here.\n */\nfunction contrastRatio(\n bg: [number, number, number],\n fg: [number, number, number],\n): number {\n const l1 = relativeLuminance(bg);\n const l2 = relativeLuminance(fg);\n const lighter = Math.max(l1, l2);\n const darker = Math.min(l1, l2);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * DEV-only WCAG AA guardrail for caller-supplied hex pairs.\n *\n * - No-op when `import.meta.env.DEV` is false.\n * - No-op when either half of the pair is missing (the \"fg missing →\n * inherits DS token\" case is a docs concern; the DS token isn't a\n * hex at runtime so we can't check it here).\n * - No-op when either hex can't be parsed (silent — not the helper's\n * concern to police malformed input).\n * - Deduplicated by `(bgHex, fgHex, contextLabel)` tuple so moving a\n * ratio-bad event around the calendar doesn't spam the console.\n *\n * @param bgHex - Caller-supplied background hex (e.g. `'#c2185b'`)\n * @param fgHex - Caller-supplied foreground hex (e.g. `'#ffffff'`)\n * @param contextLabel - Short description for the warning (e.g. `'event e1'`).\n */\nexport function warnLowContrast(\n bgHex: string | undefined,\n fgHex: string | undefined,\n contextLabel: string,\n): void {\n if (!import.meta.env.DEV) return;\n if (!bgHex || !fgHex) return;\n\n const bg = parseHex(bgHex);\n const fg = parseHex(fgHex);\n if (!bg || !fg) return;\n\n const ratio = contrastRatio(bg, fg);\n if (ratio >= 4.5) return;\n\n const key = `${bgHex}|${fgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n /* `bg` parsed successfully above, so `resolveInk(bgHex)` is guaranteed\n to produce a compliant ink — the omit-textColor hint is always valid\n at this point. */\n console.warn(\n `[Calendar] Low contrast on ${contextLabel}: ${bgHex} / ${fgHex} (ratio ${ratio.toFixed(\n 2,\n )}, target 4.5). Pass a matching textColor/fgHex, pick a higher-contrast background, or omit textColor to let the kit choose a compliant ink.`,\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Ink derivation — bg-only caller colours */\n/* ------------------------------------------------------------------ */\n\nexport type EventInk = 'on-light' | 'on-dark';\n\n/**\n * Pick the ink for an arbitrary opaque bg hex. Returns `null` when the\n * input can't be parsed (`#rgb` / `#rrggbb` only).\n *\n * The threshold 0.1791 is the relative luminance at which\n * `contrast(bg, #fff) === contrast(bg, #000)`; the better of the two\n * always yields ≥ 4.58:1 (the minimum, at a mid-grey ≈ `#757575`) —\n * provably WCAG AA-safe for any opaque background.\n */\nexport function resolveInk(bgHex: string): EventInk | null {\n const bg = parseHex(bgHex);\n if (!bg) return null;\n // threshold where contrast(bg, #fff) === contrast(bg, #000)\n return relativeLuminance(bg) > 0.1791 ? 'on-light' : 'on-dark';\n}\n\n/**\n * DEV-only, one-shot warning for a caller `backgroundColor` the kit can't\n * parse (`rgb(…)`, keywords, malformed hex). The browser can still paint\n * it, but the text falls back to the token default and contrast can't be\n * verified. Deduplicated by `(bgHex, contextLabel)`.\n */\nexport function warnUnparseableBackground(\n bgHex: string,\n contextLabel: string,\n): void {\n if (!import.meta.env.DEV) return;\n if (parseHex(bgHex)) return;\n\n const key = `unparseable|${bgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n console.warn(\n `[Calendar] Unparseable backgroundColor on ${contextLabel}: \"${bgHex}\". ` +\n `Expected #rgb or #rrggbb — contrast cannot be verified and the text ` +\n `colour falls back to the token default.`,\n );\n}\n\n/**\n * DEV-only, one-shot warning for a near-white `backgroundColor`\n * (relative luminance > 0.9) supplied without a `borderColor` — the\n * event may be invisible against the calendar grid. The kit warns, it\n * does not repaint (delineation is decorative under WCAG 1.4.11 and the\n * consumer owns the picker colour). Deduplicated by `(bgHex, contextLabel)`.\n */\nexport function warnLowDelineation(bgHex: string, contextLabel: string): void {\n if (!import.meta.env.DEV) return;\n\n const bg = parseHex(bgHex);\n if (!bg) return;\n if (relativeLuminance(bg) <= 0.9) return;\n\n const key = `delineation|${bgHex}|${contextLabel}`;\n if (warnedTuples.has(key)) return;\n warnedTuples.add(key);\n\n console.warn(\n `[Calendar] Light backgroundColor without borderColor on ${contextLabel}: ` +\n `${bgHex} may be invisible against the grid — pass a borderColor ` +\n `(the platform convention sends a light-grey border for white backgrounds).`,\n );\n}\n","/* ------------------------------------------------------------------ */\n/* CalendarEventCard — the single painted surface of a calendar event. */\n/* */\n/* Colour model (platform parity): the caller's picker hex */\n/* (backgroundColor / textColor / borderColor) is the ONLY thing that */\n/* paints the card. `status` never paints the surface — it selects an */\n/* icon, an optional decorative accent bar, and (for `cancelled`) a */\n/* line-through. When no picker colour is supplied the surface falls */\n/* back to the theme's --primary / --primary-foreground pair. */\n/* */\n/* Non-interactive by design: inside FullCalendar the outer harness */\n/* anchor owns click/drag/focus; standalone consumers wrap the card in */\n/* their own button/link. No onClick in the contract. */\n/* ------------------------------------------------------------------ */\n\nimport { forwardRef } from 'react';\nimport type { CSSProperties, HTMLAttributes } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cva } from 'class-variance-authority';\nimport {\n ThumbsUp,\n Clock,\n Stethoscope,\n Check,\n Ban,\n Zap,\n Globe,\n AlertTriangle,\n HeartPulse,\n Euro,\n Video,\n type LucideIcon,\n} from 'lucide-react';\n// Type-only import — erased at build, no runtime cycle with calendar.tsx's\n// runtime import of this card. Do NOT convert to a value import.\nimport type { CalendarEventStatus } from '../calendar/calendar';\nimport {\n warnLowContrast,\n resolveInk,\n warnUnparseableBackground,\n warnLowDelineation,\n} from '../_shared/contrast-warning';\n\n/* ------------------------------------------------------------------ */\n/* Status lookups */\n/* ------------------------------------------------------------------ */\n\nconst STATUS_ICON: Record<CalendarEventStatus, LucideIcon> = {\n confirmed: ThumbsUp,\n waiting: Clock,\n in_care: Stethoscope,\n done: Check,\n cancelled: Ban,\n absent: Zap,\n};\n\n/* Status → i18n key lookup. Kept as a literal object (not a template)\n so static-analysis extractors can find every key. Keys already exist\n in all 18 locale bundles — do not add new ones here. */\nconst STATUS_LABEL_KEYS: Record<CalendarEventStatus, string> = {\n confirmed: 'calendar.status.confirmed',\n waiting: 'calendar.status.waiting',\n in_care: 'calendar.status.inCare',\n done: 'calendar.status.done',\n cancelled: 'calendar.status.cancelled',\n absent: 'calendar.status.absent',\n};\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst calendarEventCardVariants = cva(\n [\n // layout — verbatim from the Calendar's former eventCardVariants base,\n // plus ds:relative for the accent bar's positioning context\n 'ds:relative ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]',\n 'ds:w-full ds:h-full',\n 'ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:text-[length:var(--font-size-sm)]',\n 'ds:font-[var(--font-weight-medium)]',\n 'ds:overflow-hidden',\n // kept verbatim from the former base (inert on a non-focusable div\n // inside FC; harmless)\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n // SINGLE PAINTED SURFACE — always present, never conditional. One\n // declaration per paint channel; value chain = \"caller custom prop,\n // else token\". This structurally eliminates the CVA-vs-override\n // specificity race (the old double-paint bug) — stylesheet order\n // becomes irrelevant.\n 'ds:[background-color:var(--calendar-event-bg,var(--primary))]',\n 'ds:[color:var(--calendar-event-text,var(--primary-foreground))]',\n 'ds:border ds:[border-color:var(--calendar-event-border,transparent)]',\n ].join(' '),\n {\n variants: {\n // Do not add colour classes to this axis — status is icon + accent\n // + aria only; a unit test asserts identical computed background\n // across all six statuses.\n status: {\n none: '',\n confirmed: '',\n waiting: '',\n in_care: '',\n done: '',\n cancelled: 'ds:line-through',\n absent: '',\n },\n bookedOnline: {\n // class name kept as a stable inert DOM hook; the stripe paint\n // lives here (moved from fullcalendar-theme.css) so it works in\n // the card's own stories, outside .fc-theme-alfadocs.\n // currentcolor = resolved ink, so stripes stay visible over any\n // picker colour.\n true: 'event-booked-online ds:bg-[image:repeating-linear-gradient(45deg,transparent,transparent_4px,color-mix(in_srgb,currentcolor_10%,transparent)_4px,color-mix(in_srgb,currentcolor_10%,transparent)_8px)]',\n false: '',\n },\n },\n defaultVariants: { status: 'none', bookedOnline: false },\n },\n);\n\n/* Status accent — a SEPARATE absolutely-positioned decorative element,\n not a border, so it can never collide with the caller's borderColor on\n the inline-start edge. The 3px width literal is the same\n decorative-geometry category as the former done-variant border-s-[3px]. */\nconst statusAccentVariants = cva(\n 'ds:absolute ds:inset-y-0 ds:start-0 ds:w-[3px]',\n {\n variants: {\n status: {\n confirmed: 'ds:[background-color:var(--success)]',\n waiting: 'ds:[background-color:var(--info)]',\n in_care: 'ds:[background-color:var(--primary)]',\n done: 'ds:[background-color:var(--success)]',\n cancelled: 'ds:[background-color:var(--destructive)]',\n absent: 'ds:[background-color:var(--warning)]',\n },\n },\n },\n);\n\n/* ------------------------------------------------------------------ */\n/* Props */\n/* ------------------------------------------------------------------ */\n\n/**\n * The single painted surface of a calendar event.\n *\n * Colour model (platform parity): the caller's picker hex\n * (`backgroundColor` / `textColor` / `borderColor`) is the ONLY thing that\n * paints the card. `status` never paints the surface — it selects an icon,\n * an optional decorative accent bar, and (for `cancelled`) a line-through.\n *\n * Non-interactive by design: inside FullCalendar the outer harness anchor\n * owns click/drag/focus; standalone consumers wrap the card in their own\n * button/link. No onClick in the contract.\n */\nexport interface CalendarEventCardProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title'\n> {\n /**\n * Primary line. Pass the ALREADY-MASKED title when privacy applies — the\n * card never receives a name it must not render, so it cannot leak it\n * (visually or via the composed aria-label).\n */\n title: string;\n /**\n * Secondary description line, normal weight, truncated. Note: the\n * Calendar's privacy mode does NOT mask the suffix (current behaviour,\n * preserved deliberately).\n */\n suffix?: string;\n /**\n * Pre-formatted, localised time range (e.g. \"09:00 – 09:45\"). The\n * Calendar adapter computes it via Intl.DateTimeFormat.formatRange.\n * Included in the composed aria-label whenever present (even when the\n * visual time line is suppressed via showTime/allDay — matches today's\n * Calendar behaviour byte-for-byte).\n */\n rangeText?: string;\n /**\n * Gates the VISUAL time line only (aria keeps rangeText). Mirrors\n * CalendarProps.showTime. @default true\n */\n showTime?: boolean;\n /**\n * All-day events suppress the visual time line (aria keeps rangeText).\n * @default false\n */\n allDay?: boolean;\n\n /**\n * Lifecycle state (6-state, matches the platform DoctorAppointment\n * lifecycle) → status icon + optional accent bar + line-through for\n * `cancelled` + localised label in the aria-label. NEVER paints the\n * card surface.\n */\n status?: CalendarEventStatus;\n /**\n * Render the 3px inline-start accent bar in the status's semantic token\n * colour. Purely decorative (aria-hidden) — the icon and aria-label carry\n * status regardless. The platform (colour = picker, status = icons only)\n * passes false via CalendarProps.eventStatusAccent. @default true\n */\n statusAccent?: boolean;\n\n /**\n * Runtime hex (#rgb or #rrggbb) from the consumer's colour picker — THE\n * painted surface. Injected as `--calendar-event-bg` via the sanctioned\n * inline custom-property pattern (23-constraints §inline-style exception).\n */\n backgroundColor?: string;\n /**\n * Runtime hex paired with backgroundColor. When omitted while\n * backgroundColor is set, the card auto-derives black/white ink by\n * luminance (provably WCAG AA ≥ 4.58:1 for any opaque colour).\n */\n textColor?: string;\n /**\n * Runtime hex border for delineating light surfaces. The platform sends\n * '#cccccc' when backgroundColor is '#ffffff' and omits it otherwise.\n * Falls back to transparent; border-width is constant (1px always\n * rendered), so toggling never shifts layout and event boundaries\n * survive forced-colors / Windows High Contrast for free.\n */\n borderColor?: string;\n\n /* Indicator icons — names identical to CalendarEvent fields (1:1 map). */\n /** Globe icon + diagonal stripe overlay. */\n isBookedOnline?: boolean;\n /** AlertTriangle icon. */\n hasUnassignedPatient?: boolean;\n /** HeartPulse icon. */\n hasHighlightedAnamnesis?: boolean;\n /** Euro icon. */\n hasBillableAmount?: boolean;\n /** Video icon. */\n isTelehealth?: boolean;\n\n /**\n * Resource title (chair/operator) woven into the composed aria-label\n * only — never rendered visually. The Calendar adapter resolves\n * resourceId → title before passing it.\n */\n resourceLabel?: string;\n /**\n * Stable event id → emitted as `data-event-id` (Calendar.focusEvent\n * targets it) and used as the contrast-warning dedup context.\n */\n eventId?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Component */\n/* ------------------------------------------------------------------ */\n\nexport const CalendarEventCard = forwardRef<\n HTMLDivElement,\n CalendarEventCardProps\n>(\n (\n {\n title,\n suffix,\n rangeText,\n showTime = true,\n allDay = false,\n status,\n statusAccent = true,\n backgroundColor,\n textColor,\n borderColor,\n isBookedOnline = false,\n hasUnassignedPatient,\n hasHighlightedAnamnesis,\n hasBillableAmount,\n isTelehealth,\n resourceLabel,\n eventId,\n className,\n style,\n 'aria-label': ariaLabelProp,\n ...rest\n },\n ref,\n ) => {\n const { t } = useTranslation();\n\n const StatusIcon = status ? STATUS_ICON[status] : null;\n const statusLabel = status ? t(STATUS_LABEL_KEYS[status]) : undefined;\n\n /* Accessible name — exactly the Calendar's historical composition.\n An explicit consumer-supplied aria-label wins. rangeText is always\n included when present, even when the visual time line is hidden. */\n const ariaLabel =\n ariaLabelProp ??\n [title, rangeText, resourceLabel, statusLabel].filter(Boolean).join(', ');\n\n /* Ink derivation — only when the caller paints the surface without\n pairing a text colour. */\n const ink =\n !textColor && backgroundColor ? resolveInk(backgroundColor) : null;\n\n /* DEV-only guardrails — every helper no-ops in production and dedupes\n per session, so calling during render is safe. */\n const warnContext = eventId ? `event ${eventId}` : 'calendar-event-card';\n warnLowContrast(backgroundColor, textColor, warnContext);\n if (backgroundColor && !textColor) {\n // no-ops when the hex is parseable (i.e. when resolveInk succeeded)\n warnUnparseableBackground(backgroundColor, warnContext);\n }\n if (backgroundColor && !borderColor) {\n // no-ops unless the background is near-white (luminance > 0.9)\n warnLowDelineation(backgroundColor, warnContext);\n }\n\n /* Per-event colour override: the consuming app passes runtime hex from\n its colour picker. 23-constraints permits inline `style` only as a\n CSS custom-property setter for runtime values that can't be\n enumerated at build time — the consuming background-color / color /\n border-color declarations live in the CVA base as Tailwind arbitrary\n values with token fallbacks. */\n const colourOverrides: CSSProperties | undefined =\n backgroundColor || textColor || borderColor\n ? ({\n ...(backgroundColor\n ? { '--calendar-event-bg': backgroundColor }\n : {}),\n ...(textColor\n ? { '--calendar-event-text': textColor }\n : ink === 'on-light'\n ? { '--calendar-event-text': 'var(--event-ink-on-light)' }\n : ink === 'on-dark'\n ? { '--calendar-event-text': 'var(--event-ink-on-dark)' }\n : {}),\n ...(borderColor ? { '--calendar-event-border': borderColor } : {}),\n } as CSSProperties)\n : undefined;\n\n const mergedStyle: CSSProperties | undefined =\n style || colourOverrides ? { ...style, ...colourOverrides } : undefined;\n\n return (\n <div\n ref={ref}\n {...rest}\n className={calendarEventCardVariants({\n status: status ?? 'none',\n bookedOnline: isBookedOnline,\n className,\n })}\n // eslint-disable-next-line react/forbid-dom-props -- caller-supplied event bg/text/border hex injected via CSS variables (23-constraints §inline-style exception)\n style={mergedStyle}\n aria-label={ariaLabel}\n data-component=\"calendar-event-card\"\n data-event-id={eventId}\n data-status={status ?? 'none'}\n data-contrast={textColor ? 'custom' : (ink ?? 'default')}\n >\n {status && statusAccent ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"status-accent\"\n className={statusAccentVariants({ status })}\n />\n ) : null}\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:self-end\">\n {/* All icons render in currentcolor — they inherit the resolved\n ink, so the ≥ 4.5:1 text guarantee makes every icon exceed the\n 3:1 graphics minimum (WCAG 1.4.11) on any picker surface.\n Never tint icons with status colours. */}\n {StatusIcon ? <StatusIcon size={14} aria-hidden=\"true\" /> : null}\n {isBookedOnline ? <Globe size={12} aria-hidden=\"true\" /> : null}\n {hasUnassignedPatient ? (\n <AlertTriangle size={12} aria-hidden=\"true\" />\n ) : null}\n {hasHighlightedAnamnesis ? (\n <HeartPulse size={12} aria-hidden=\"true\" />\n ) : null}\n {hasBillableAmount ? <Euro size={12} aria-hidden=\"true\" /> : null}\n {isTelehealth ? <Video size={12} aria-hidden=\"true\" /> : null}\n </div>\n {showTime && !allDay && rangeText ? (\n // No opacity here — composing 70% over saturated bgs drops\n // effective contrast below WCAG AA. The smaller font-size-xs vs\n // the title's font-weight-semibold provides sufficient visual\n // hierarchy.\n <span className=\"ds:text-[length:var(--font-size-xs)]\">\n {rangeText}\n </span>\n ) : null}\n <span className=\"ds:font-[var(--font-weight-semibold)] ds:truncate ds:text-start\">\n {title}\n </span>\n {suffix ? (\n <span className=\"ds:truncate ds:text-start ds:text-[length:var(--font-size-xs)]\">\n {suffix}\n </span>\n ) : null}\n </div>\n );\n },\n);\nCalendarEventCard.displayName = 'CalendarEventCard';\n"],"names":["__iconNode","Ban","createLucideIcon","Euro","ThumbsUp","Zap","parseHex","hex","trimmed","body","r","g","b","relativeLuminance","lin","c","warnLowContrast","bgHex","fgHex","contextLabel","resolveInk","bg","STATUS_ICON","Clock","Stethoscope","Check","STATUS_LABEL_KEYS","calendarEventCardVariants","cva","statusAccentVariants","CalendarEventCard","forwardRef","title","suffix","rangeText","showTime","allDay","status","statusAccent","backgroundColor","textColor","borderColor","isBookedOnline","hasUnassignedPatient","hasHighlightedAnamnesis","hasBillableAmount","isTelehealth","resourceLabel","eventId","className","style","ariaLabelProp","rest","ref","t","useTranslation","StatusIcon","statusLabel","ariaLabel","ink","colourOverrides","mergedStyle","jsxs","jsx","Globe","AlertTriangle","HeartPulse","Video"],"mappings":"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","x_google_ignoreList":[0,1,2,3]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs as v, jsx as i, Fragment as ge } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef as ve, useId as ye, useRef as
|
|
2
|
+
import { forwardRef as ve, useId as ye, useRef as w, useCallback as W, useImperativeHandle as be, useMemo as xe } from "react";
|
|
3
3
|
import { c as Ie } from "./index-D2ZczOXr.js";
|
|
4
4
|
import { useTranslation as ke } from "react-i18next";
|
|
5
5
|
import { I as q } from "./icon-button-C_kbcd7I.js";
|
|
@@ -132,9 +132,9 @@ function Me(t, n) {
|
|
|
132
132
|
if (typeof Intl < "u" && typeof Intl.Segmenter == "function")
|
|
133
133
|
try {
|
|
134
134
|
const l = new Intl.Segmenter(n, { granularity: "grapheme" });
|
|
135
|
-
let
|
|
136
|
-
for (const y of l.segment(t))
|
|
137
|
-
return
|
|
135
|
+
let r = 0;
|
|
136
|
+
for (const y of l.segment(t)) r += 1;
|
|
137
|
+
return r;
|
|
138
138
|
} catch {
|
|
139
139
|
}
|
|
140
140
|
return Array.from(t).length;
|
|
@@ -149,15 +149,15 @@ function Fe(t, n, l) {
|
|
|
149
149
|
return d.length === t.length ? t : d;
|
|
150
150
|
} catch {
|
|
151
151
|
}
|
|
152
|
-
const
|
|
153
|
-
return
|
|
152
|
+
const r = Array.from(t);
|
|
153
|
+
return r.length <= n ? t : r.slice(0, n).join("");
|
|
154
154
|
}
|
|
155
155
|
const Ke = ve(
|
|
156
156
|
({
|
|
157
157
|
size: t = "md",
|
|
158
158
|
value: n,
|
|
159
159
|
defaultValue: l,
|
|
160
|
-
maxLength:
|
|
160
|
+
maxLength: r,
|
|
161
161
|
submitOnEnter: y = !1,
|
|
162
162
|
minRows: o = 1,
|
|
163
163
|
maxRows: d = 8,
|
|
@@ -169,22 +169,22 @@ const Ke = ve(
|
|
|
169
169
|
label: T,
|
|
170
170
|
placeholder: U,
|
|
171
171
|
className: Y,
|
|
172
|
-
onChange:
|
|
173
|
-
onKeyDown:
|
|
174
|
-
onCompositionStart:
|
|
175
|
-
onCompositionEnd:
|
|
176
|
-
id:
|
|
172
|
+
onChange: C,
|
|
173
|
+
onKeyDown: N,
|
|
174
|
+
onCompositionStart: V,
|
|
175
|
+
onCompositionEnd: j,
|
|
176
|
+
id: z,
|
|
177
177
|
...J
|
|
178
178
|
}, L) => {
|
|
179
|
-
const { t: c, i18n: E } = ke(), O = ye(), p =
|
|
180
|
-
|
|
179
|
+
const { t: c, i18n: E } = ke(), O = ye(), p = w(!1), M = w(null), I = w(null), Q = W((e) => {
|
|
180
|
+
I.current = e;
|
|
181
181
|
}, []), [X, m] = we({
|
|
182
182
|
value: n === void 0 ? void 0 : String(n),
|
|
183
183
|
defaultValue: String(l ?? "")
|
|
184
|
-
}), a = X ?? "", H = Me(a, E.language), f = typeof
|
|
185
|
-
const e =
|
|
184
|
+
}), a = X ?? "", H = Me(a, E.language), f = typeof r == "number" && r > 0, Z = f ? Math.max(0, r - H) : 0, D = f && H > r * 0.9, h = f && H >= r, F = W(() => {
|
|
185
|
+
const e = I.current;
|
|
186
186
|
if (!e) return;
|
|
187
|
-
const
|
|
187
|
+
const s = window.getComputedStyle(e), k = parseFloat(s.lineHeight) || 24, de = parseFloat(s.paddingTop) || 0, ue = parseFloat(s.paddingBottom) || 0, pe = parseFloat(s.borderTopWidth) || 0, me = parseFloat(s.borderBottomWidth) || 0, _ = de + ue + pe + me, fe = k * o + _, $ = k * d + _;
|
|
188
188
|
e.style.height = "auto";
|
|
189
189
|
const he = Math.max(fe, Math.min(e.scrollHeight, $));
|
|
190
190
|
e.style.height = `${he}px`, e.style.overflowY = e.scrollHeight > $ ? "auto" : "hidden";
|
|
@@ -193,15 +193,16 @@ const Ke = ve(
|
|
|
193
193
|
F();
|
|
194
194
|
}, [F, a]);
|
|
195
195
|
const ee = (e) => {
|
|
196
|
-
let
|
|
197
|
-
f && !p.current && (
|
|
196
|
+
let s = e.target.value;
|
|
197
|
+
f && !p.current && (s = Fe(s, r, E.language)), m(s), !p.current && (C == null || C(e));
|
|
198
198
|
}, te = (e) => {
|
|
199
|
-
p.current = !0,
|
|
199
|
+
p.current = !0, V == null || V(e);
|
|
200
200
|
}, se = (e) => {
|
|
201
|
-
p.current = !1,
|
|
201
|
+
p.current = !1, j == null || j(e);
|
|
202
202
|
}, re = (e) => e.nativeEvent.isComposing || e.keyCode === 229 || p.current, S = () => {
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
var s;
|
|
204
|
+
!a.trim() || x || h || (u == null || u(a), m(""), (s = I.current) == null || s.focus());
|
|
205
|
+
}, K = w(null);
|
|
205
206
|
be(L, () => K.current, []);
|
|
206
207
|
const ne = xe(
|
|
207
208
|
() => ({
|
|
@@ -218,7 +219,7 @@ const Ke = ve(
|
|
|
218
219
|
},
|
|
219
220
|
focus: () => {
|
|
220
221
|
var e;
|
|
221
|
-
(e =
|
|
222
|
+
(e = I.current) == null || e.focus();
|
|
222
223
|
}
|
|
223
224
|
}),
|
|
224
225
|
// `submit` is a local closure that always sees the latest currentValue
|
|
@@ -227,24 +228,24 @@ const Ke = ve(
|
|
|
227
228
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
228
229
|
[a, m]
|
|
229
230
|
);
|
|
230
|
-
Ne(Te, ne,
|
|
231
|
+
Ne(Te, ne, z);
|
|
231
232
|
const ae = (e) => {
|
|
232
|
-
if (
|
|
233
|
-
const
|
|
234
|
-
(
|
|
233
|
+
if (N == null || N(e), !e.defaultPrevented && !re(e) && e.key === "Enter") {
|
|
234
|
+
const s = e.metaKey || e.ctrlKey, k = y && !e.shiftKey;
|
|
235
|
+
(s || k) && (e.preventDefault(), S());
|
|
235
236
|
}
|
|
236
237
|
}, ie = () => {
|
|
237
238
|
var e;
|
|
238
239
|
(e = M.current) == null || e.click();
|
|
239
240
|
}, oe = (e) => {
|
|
240
241
|
e.target.files && e.target.files.length > 0 && (b == null || b(e.target.files)), e.target.value = "";
|
|
241
|
-
}, g =
|
|
242
|
+
}, g = z ?? O, R = `${g}-label`, B = f ? `${g}-counter` : void 0, P = `${g}-hint`, ce = U ?? c("chat.input.placeholder"), le = T ?? c("chat.prompt");
|
|
242
243
|
return /* @__PURE__ */ v(
|
|
243
244
|
"div",
|
|
244
245
|
{
|
|
245
246
|
ref: K,
|
|
246
247
|
"data-component": "chat-input",
|
|
247
|
-
"data-component-id":
|
|
248
|
+
"data-component-id": z,
|
|
248
249
|
className: Ee({ size: t, className: Y }),
|
|
249
250
|
children: [
|
|
250
251
|
/* @__PURE__ */ i(
|
|
@@ -365,4 +366,4 @@ export {
|
|
|
365
366
|
Se as P,
|
|
366
367
|
Te as c
|
|
367
368
|
};
|
|
368
|
-
//# sourceMappingURL=chat-input-
|
|
369
|
+
//# sourceMappingURL=chat-input-QpHxBEnN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-input-QpHxBEnN.js","sources":["../../node_modules/lucide-react/dist/esm/icons/paperclip.mjs","../../src/components/chat-input/chat-input.agent.ts","../../src/components/chat-input/chat-input.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: \"m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551\",\n key: \"1miecu\"\n }\n ]\n];\nconst Paperclip = createLucideIcon(\"paperclip\", __iconNode);\n\nexport { __iconNode, Paperclip as default };\n//# sourceMappingURL=paperclip.mjs.map\n","/* -------------------------------------------------------------------- */\n/* Agent adapter — ChatInput. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ChatInputHandle } from './chat-input';\n\nexport const chatInputAgent: AgentAdapter<ChatInputHandle> = {\n id: 'chat-input',\n capabilities: ['edit_inline', 'submit'],\n state: {\n value: {\n type: 'string',\n descriptionKey: 'ui.agent.chatInput.state.value',\n description: 'Current text in the composer.',\n read: (handle) => handle.getValue(),\n },\n isEmpty: {\n type: 'boolean',\n descriptionKey: 'ui.agent.chatInput.state.isEmpty',\n description: 'True when the composer has no text.',\n read: (handle) => handle.isEmpty(),\n },\n },\n actions: {\n set_value: {\n safety: 'write',\n argsType: '{ value: string }',\n argsSchema: {\n type: 'object',\n properties: {\n value: {\n type: 'string',\n description: 'New composer text, replacing the current value.',\n },\n },\n required: ['value'],\n },\n idempotent: true,\n descriptionKey: 'ui.agent.chatInput.actions.setValue',\n description: 'Replace the composer text.',\n invoke: (handle, args: { value: string }) => {\n handle.setValue(args.value);\n },\n },\n clear: {\n // Discards whatever the user has typed — irreversible from this UI.\n safety: 'destructive',\n idempotent: true,\n descriptionKey: 'ui.agent.chatInput.actions.clear',\n description: 'Clear the composer. Irreversible from the same UI.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n submit: {\n safety: 'write',\n // Hands the composer text to the host `onSubmit` callback, which sends\n // the message to a backend / model — an external side effect.\n openWorld: true,\n descriptionKey: 'ui.agent.chatInput.actions.submit',\n description: 'Submit the current composer state via onSubmit.',\n invoke: (handle) => {\n handle.submit();\n },\n },\n focus: {\n safety: 'read',\n descriptionKey: 'ui.agent.chatInput.actions.focus',\n description: 'Move keyboard focus into the textarea.',\n invoke: (handle) => {\n handle.focus();\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'chat-input',\n description: 'Marks the ChatInput wrapper.',\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 useCallback,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n type ChangeEvent,\n type CompositionEvent,\n type KeyboardEvent,\n type ReactNode,\n type TextareaHTMLAttributes,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { AlertCircle, Paperclip, Send } from 'lucide-react';\nimport { IconButton } from '../button';\nimport { useControllableState } from '../../hooks/use-controllable-state';\nimport { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { chatInputAgent } from './chat-input.agent';\n\nconst rootVariants = cva(\n [\n 'ds:flex ds:flex-col ds:gap-[var(--spacing-xs)] ds:w-full',\n // Uses the kit's shared input-chrome tokens — `--input` for fill,\n // `--shadow-input` for the halo. Border stays at 1px (`--border`,\n // softened to `grey-700` in light) so the focus-within override and\n // forced-colors fallback both still paint a visible edge.\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-border',\n 'ds:bg-input ds:shadow-[var(--shadow-input)]',\n 'ds:focus-within:border-[color:var(--primary)]',\n 'ds:transition-[border-color,box-shadow] ds:duration-[var(--animation-duration)]',\n 'ds:motion-reduce:transition-none',\n 'ds:forced-colors:border-[CanvasText]',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'ds:text-[length:var(--font-size-sm)]',\n md: 'ds:text-[length:var(--font-size-base)]',\n lg: 'ds:text-[length:var(--font-size-lg)]',\n },\n },\n defaultVariants: { size: 'md' },\n },\n);\n\ntype NativeTextareaProps = Omit<\n TextareaHTMLAttributes<HTMLTextAreaElement>,\n 'size' | 'onSubmit' | 'children'\n>;\n\n/** Curated imperative handle for agent / external automation. */\nexport interface ChatInputHandle {\n getValue: () => string;\n isEmpty: () => boolean;\n setValue: (value: string) => void;\n clear: () => void;\n submit: () => void;\n focus: () => void;\n}\n\nexport interface ChatInputProps\n extends NativeTextareaProps, VariantProps<typeof rootVariants> {\n /** Invoked when the user submits (Cmd/Ctrl+Enter, or send button). */\n onSubmit?: (text: string) => void;\n /** Maximum allowed characters (grapheme clusters via Intl.Segmenter when available). */\n maxLength?: number;\n /** When true, plain Enter submits and Shift+Enter inserts a newline.\n * Default false (Enter inserts newline; Cmd/Ctrl+Enter submits). */\n submitOnEnter?: boolean;\n /** Minimum visible rows. Default 1. */\n minRows?: number;\n /** Maximum visible rows before the field scrolls. Default 8. */\n maxRows?: number;\n /** Optional attachment handler — when provided, renders the attachment button. */\n onAttach?: (files: FileList) => void;\n /** `accept` forwarded to the hidden file input. */\n accept?: string;\n /** Controls whether the textarea is disabled and submit is blocked. */\n disabled?: boolean;\n /** Optional slot placed between the textarea and the send button. */\n toolbar?: ReactNode;\n /** Visible label above the textarea. When omitted, a visually-hidden label is used. */\n label?: string;\n}\n\nfunction graphemeCount(value: string, locale: string): number {\n if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {\n try {\n const seg = new Intl.Segmenter(locale, { granularity: 'grapheme' });\n let n = 0;\n for (const _s of seg.segment(value)) n += 1;\n return n;\n } catch {\n /* fall through to Array.from */\n }\n }\n return Array.from(value).length;\n}\n\n/** Truncate `value` to at most `max` graphemes. Returns the original\n * string when it already fits so callers can compare references. */\nfunction truncateToGraphemes(\n value: string,\n max: number,\n locale: string,\n): string {\n if (typeof Intl !== 'undefined' && typeof Intl.Segmenter === 'function') {\n try {\n const seg = new Intl.Segmenter(locale, { granularity: 'grapheme' });\n const parts: string[] = [];\n for (const s of seg.segment(value)) {\n parts.push(s.segment);\n if (parts.length >= max) break;\n }\n const joined = parts.join('');\n return joined.length === value.length ? value : joined;\n } catch {\n /* fall through to code-point split */\n }\n }\n const cps = Array.from(value);\n return cps.length <= max ? value : cps.slice(0, max).join('');\n}\n\nexport const ChatInput = forwardRef<HTMLDivElement, ChatInputProps>(\n (\n {\n size = 'md',\n value,\n defaultValue,\n maxLength,\n submitOnEnter = false,\n minRows = 1,\n maxRows = 8,\n onSubmit,\n onAttach,\n accept,\n disabled,\n toolbar,\n label,\n placeholder,\n className,\n onChange,\n onKeyDown,\n onCompositionStart,\n onCompositionEnd,\n id,\n ...rest\n },\n ref,\n ) => {\n const { t, i18n } = useTranslation();\n const textareaId = useId();\n const composingRef = useRef(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const innerRef = useRef<HTMLTextAreaElement | null>(null);\n\n const setRefs = useCallback((node: HTMLTextAreaElement | null) => {\n innerRef.current = node;\n }, []);\n\n const [currentValueRaw, setChatValue] = useControllableState<string>({\n value: value === undefined ? undefined : String(value),\n defaultValue: String(defaultValue ?? ''),\n });\n const currentValue = currentValueRaw ?? '';\n\n const count = graphemeCount(currentValue, i18n.language);\n const hasMaxLength = typeof maxLength === 'number' && maxLength > 0;\n const remaining = hasMaxLength ? Math.max(0, maxLength - count) : 0;\n const showCounter = hasMaxLength && count > (maxLength as number) * 0.9;\n const atLimit = hasMaxLength && count >= maxLength;\n\n /* Auto-grow — compute height from scrollHeight, clamped to [minRows, maxRows].\n Imperative `.style` write is permitted per 23-constraints\n §Runtime-computed dimensions (textarea scrollHeight measurement). */\n const resize = useCallback(() => {\n const el = innerRef.current;\n if (!el) return;\n const styles = window.getComputedStyle(el);\n const lineHeight = parseFloat(styles.lineHeight) || 24;\n const padTop = parseFloat(styles.paddingTop) || 0;\n const padBot = parseFloat(styles.paddingBottom) || 0;\n const borderTop = parseFloat(styles.borderTopWidth) || 0;\n const borderBot = parseFloat(styles.borderBottomWidth) || 0;\n const chrome = padTop + padBot + borderTop + borderBot;\n const minH = lineHeight * minRows + chrome;\n const maxH = lineHeight * maxRows + chrome;\n el.style.height = 'auto';\n const next = Math.max(minH, Math.min(el.scrollHeight, maxH));\n el.style.height = `${next}px`;\n el.style.overflowY = el.scrollHeight > maxH ? 'auto' : 'hidden';\n }, [minRows, maxRows]);\n\n useIsomorphicLayoutEffect(() => {\n resize();\n }, [resize, currentValue]);\n\n const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {\n let next = e.target.value;\n // Enforce a grapheme cap so emoji like 👨👩👧 (1 grapheme, 11 UTF-16\n // units) stay aligned with the visible counter. Skip during IME\n // composition so the in-progress text is preserved verbatim.\n if (hasMaxLength && !composingRef.current) {\n next = truncateToGraphemes(next, maxLength as number, i18n.language);\n }\n setChatValue(next);\n if (composingRef.current) return;\n onChange?.(e);\n };\n\n const handleCompositionStart = (\n e: CompositionEvent<HTMLTextAreaElement>,\n ) => {\n composingRef.current = true;\n onCompositionStart?.(e);\n };\n const handleCompositionEnd = (e: CompositionEvent<HTMLTextAreaElement>) => {\n composingRef.current = false;\n onCompositionEnd?.(e);\n };\n\n const isIMEKey = (e: KeyboardEvent<HTMLTextAreaElement>) =>\n e.nativeEvent.isComposing || e.keyCode === 229 || composingRef.current;\n\n const submit = () => {\n const text = currentValue.trim();\n if (!text || disabled || atLimit) return;\n onSubmit?.(currentValue);\n setChatValue('');\n // Keep focus in the composer after a send. Activating the Send *button*\n // (click, or keyboard Enter/Space) otherwise strands focus: clearing the\n // value re-disables the button on the next render, so focus falls to\n // <body> and a keyboard user must re-traverse back to the textarea.\n // Refocusing leaves the composer ready for the next message — a no-op for\n // the Enter-to-send path, where focus is already in the textarea.\n innerRef.current?.focus();\n };\n\n const rootRef = useRef<HTMLDivElement>(null);\n useImperativeHandle(ref, () => rootRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<ChatInputHandle>(\n () => ({\n getValue: () => currentValue,\n isEmpty: () => !currentValue.trim(),\n setValue: (next: string) => {\n setChatValue(next);\n },\n clear: () => {\n setChatValue('');\n },\n submit: () => {\n submit();\n },\n focus: () => {\n innerRef.current?.focus();\n },\n }),\n // `submit` is a local closure that always sees the latest currentValue\n // via React's render cycle — depend on currentValue so the handle\n // picks up new values across renders.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [currentValue, setChatValue],\n );\n useAgentRegistration(chatInputAgent, agentHandle, id);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n onKeyDown?.(e);\n if (e.defaultPrevented) return;\n if (isIMEKey(e)) return;\n\n if (e.key === 'Enter') {\n const explicitSubmit = e.metaKey || e.ctrlKey;\n const plainEnterSubmits = submitOnEnter && !e.shiftKey;\n if (explicitSubmit || plainEnterSubmits) {\n e.preventDefault();\n submit();\n }\n }\n };\n\n const handleAttach = () => {\n fileInputRef.current?.click();\n };\n\n const handleFilePick = (e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onAttach?.(e.target.files);\n }\n // Reset so picking the same file twice still fires change.\n e.target.value = '';\n };\n\n const effectiveId = id ?? textareaId;\n const labelId = `${effectiveId}-label`;\n const counterId = hasMaxLength ? `${effectiveId}-counter` : undefined;\n const hintId = `${effectiveId}-hint`;\n\n const resolvedPlaceholder = placeholder ?? t('chat.input.placeholder');\n const resolvedLabel = label ?? t('chat.prompt');\n\n return (\n <div\n ref={rootRef}\n data-component=\"chat-input\"\n data-component-id={id}\n className={rootVariants({ size, className })}\n >\n <label\n id={labelId}\n htmlFor={effectiveId}\n className={\n label\n ? 'type-label ds:ps-[var(--spacing-sm)] ds:pt-[var(--spacing-sm)]'\n : 'ds:sr-only'\n }\n >\n {resolvedLabel}\n </label>\n <textarea\n ref={setRefs}\n id={effectiveId}\n value={currentValue}\n disabled={disabled}\n rows={minRows}\n placeholder={resolvedPlaceholder}\n aria-labelledby={labelId}\n aria-describedby={\n [counterId, hintId].filter(Boolean).join(' ') || undefined\n }\n aria-invalid={atLimit || undefined}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n className={[\n 'ds:w-full ds:resize-none ds:bg-transparent',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:pt-[var(--spacing-sm)] ds:pb-[var(--spacing-xs)]',\n 'ds:placeholder:text-[color:var(--muted-foreground)]',\n 'ds:leading-[var(--line-height-base)]',\n 'ds:disabled:opacity-50 ds:disabled:cursor-not-allowed',\n // Tokenised focus ring on the textarea itself — the 1px border\n // shift on the wrapper alone fails the 3px accessible-theme\n // requirement. See a11y-critical-fixes.mdx.\n 'ds:outline-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[color:var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' ')}\n {...rest}\n />\n <div className=\"ds:flex ds:items-center ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-xs)] ds:pe-[var(--spacing-xs)] ds:pb-[var(--spacing-xs)]\">\n {onAttach ? (\n <>\n <input\n ref={fileInputRef}\n type=\"file\"\n className=\"ds:sr-only\"\n multiple\n accept={accept}\n onChange={handleFilePick}\n aria-label={t('chat.input.attach')}\n tabIndex={-1}\n />\n <IconButton\n icon={<Paperclip />}\n aria-label={t('chat.input.attach')}\n intent=\"ghost\"\n size=\"sm\"\n onClick={handleAttach}\n disabled={disabled}\n />\n </>\n ) : null}\n {toolbar}\n <div className=\"ds:ms-auto ds:inline-flex ds:items-center ds:gap-[var(--spacing-sm)]\">\n {showCounter ? (\n <span\n id={counterId}\n aria-live=\"polite\"\n className={[\n 'ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]',\n 'type-meta ds:tabular-nums',\n atLimit\n ? 'ds:text-[color:var(--destructive)]'\n : 'ds:text-[color:var(--muted-foreground)]',\n ].join(' ')}\n >\n {atLimit ? (\n // Icon pairs with --destructive colour so the at-limit\n // state is not conveyed by hue alone (WCAG 1.4.1).\n <AlertCircle aria-hidden=\"true\" className=\"ds:size-3.5\" />\n ) : null}\n {t('chat.input.remaining', { count: remaining })}\n </span>\n ) : null}\n <span id={hintId} className=\"ds:sr-only\">\n {t('chat.input.sendHint')}\n </span>\n <IconButton\n icon={<Send />}\n aria-label={t('chat.send')}\n intent=\"primary\"\n size=\"sm\"\n disabled={disabled || !currentValue.trim() || atLimit}\n onClick={submit}\n aria-keyshortcuts=\"Meta+Enter Control+Enter\"\n />\n </div>\n </div>\n </div>\n );\n },\n);\n\nChatInput.displayName = 'ChatInput';\n"],"names":["__iconNode","Paperclip","createLucideIcon","chatInputAgent","handle","args","rootVariants","cva","graphemeCount","value","locale","seg","n","_s","truncateToGraphemes","max","parts","s","joined","cps","ChatInput","forwardRef","size","defaultValue","maxLength","submitOnEnter","minRows","maxRows","onSubmit","onAttach","accept","disabled","toolbar","label","placeholder","className","onChange","onKeyDown","onCompositionStart","onCompositionEnd","id","rest","ref","t","i18n","useTranslation","textareaId","useId","composingRef","useRef","fileInputRef","innerRef","setRefs","useCallback","node","currentValueRaw","setChatValue","useControllableState","currentValue","count","hasMaxLength","remaining","showCounter","atLimit","resize","el","styles","lineHeight","padTop","padBot","borderTop","borderBot","chrome","minH","maxH","next","useIsomorphicLayoutEffect","handleChange","handleCompositionStart","handleCompositionEnd","isIMEKey","submit","_a","rootRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration","handleKeyDown","explicitSubmit","plainEnterSubmits","handleAttach","handleFilePick","effectiveId","labelId","counterId","hintId","resolvedPlaceholder","resolvedLabel","jsxs","jsx","Fragment","IconButton","AlertCircle","Send"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { jsxs as m, Fragment as W, jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as j, useMemo as I, useState as q, useImperativeHandle as E, Fragment as H } from "react";
|
|
3
|
+
import { c as $ } from "./index-D2ZczOXr.js";
|
|
4
|
+
import { useTranslation as U } from "react-i18next";
|
|
5
|
+
import { B as b } from "./badge-DCOqV9mI.js";
|
|
6
|
+
import { C as B } from "./card-DPmk26CL.js";
|
|
7
|
+
import { E as G } from "./empty-state-CrLsi0XI.js";
|
|
8
|
+
import { P as Y } from "./panel-header-D313n_9-.js";
|
|
9
|
+
import { P as J } from "./pdf-viewer-DF3VMaPo.js";
|
|
10
|
+
import { T as O, b as Q, c as X, a as Z } from "./tabs-CVTukWRD.js";
|
|
11
|
+
import { u as ee } from "./registry-DvAUVLHh.js";
|
|
12
|
+
import { F as ie, a as te } from "./file-Cwe9VC1A.js";
|
|
13
|
+
import { F as se } from "./file-text-5yv6r2ls.js";
|
|
14
|
+
import { c as ne } from "./createLucideIcon-DhHxpK9K.js";
|
|
15
|
+
/**
|
|
16
|
+
* @license lucide-react v1.22.0 - ISC
|
|
17
|
+
*
|
|
18
|
+
* This source code is licensed under the ISC license.
|
|
19
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
20
|
+
*/
|
|
21
|
+
const ae = [
|
|
22
|
+
["path", { d: "M15 2h-4a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V8", key: "14sh0y" }],
|
|
23
|
+
[
|
|
24
|
+
"path",
|
|
25
|
+
{
|
|
26
|
+
d: "M16.706 2.706A2.4 2.4 0 0 0 15 2v5a1 1 0 0 0 1 1h5a2.4 2.4 0 0 0-.706-1.706z",
|
|
27
|
+
key: "1970lx"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
["path", { d: "M5 7a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h8a2 2 0 0 0 1.732-1", key: "l4dndm" }]
|
|
31
|
+
], re = ne("files", ae), de = {
|
|
32
|
+
id: "document-preview",
|
|
33
|
+
capabilities: [],
|
|
34
|
+
state: {
|
|
35
|
+
kind: {
|
|
36
|
+
type: "'pdf' | 'image' | 'metadata' | 'empty'",
|
|
37
|
+
descriptionKey: "ui.agent.documentPreview.state.kind",
|
|
38
|
+
description: "Which render branch is active: pdf, image, metadata (no inline preview), or empty (no document). Structural — never the document name.",
|
|
39
|
+
read: (a) => a.getKind()
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
actions: {
|
|
43
|
+
get_name: {
|
|
44
|
+
// phi (not read): resolves the document display name, which can identify
|
|
45
|
+
// patients. PRS §26 — phi outranks read so the host gates it behind
|
|
46
|
+
// stricter confirm + audit. The always-on kind slot stays name-free.
|
|
47
|
+
safety: "phi",
|
|
48
|
+
returns: "string | undefined",
|
|
49
|
+
returnsSchema: { type: ["string", "null"] },
|
|
50
|
+
idempotent: !0,
|
|
51
|
+
descriptionKey: "ui.agent.documentPreview.actions.getName",
|
|
52
|
+
description: "Read the display name of the previewed document. May identify a patient (PHI).",
|
|
53
|
+
invoke: (a) => a.getName()
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
domHooks: {
|
|
57
|
+
root: {
|
|
58
|
+
attr: "data-component",
|
|
59
|
+
value: "document-preview",
|
|
60
|
+
description: "Marks the DocumentPreview region."
|
|
61
|
+
},
|
|
62
|
+
instanceId: {
|
|
63
|
+
attr: "data-component-id",
|
|
64
|
+
sourceProp: "id",
|
|
65
|
+
description: "Sourced from the id prop."
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}, le = $(
|
|
69
|
+
[
|
|
70
|
+
"ds:flex ds:h-full ds:min-h-0 ds:min-w-0 ds:flex-col ds:overflow-auto",
|
|
71
|
+
"ds:focus-visible:outline-[length:var(--focus-ring-width)]",
|
|
72
|
+
"ds:focus-visible:outline-solid",
|
|
73
|
+
"ds:focus-visible:outline-ring"
|
|
74
|
+
].join(" ")
|
|
75
|
+
), oe = {
|
|
76
|
+
signed: "success",
|
|
77
|
+
pending: "warning"
|
|
78
|
+
};
|
|
79
|
+
function z(a, r, u) {
|
|
80
|
+
if (!a) return "empty";
|
|
81
|
+
const l = r ?? "";
|
|
82
|
+
return l === "application/pdf" && u ? "pdf" : l.startsWith("image/") && u ? "image" : "metadata";
|
|
83
|
+
}
|
|
84
|
+
function N(a) {
|
|
85
|
+
const r = a ?? "";
|
|
86
|
+
return r.startsWith("image/") ? ie : r === "application/pdf" || r.startsWith("text/") || r.includes("word") ? se : te;
|
|
87
|
+
}
|
|
88
|
+
const ce = [
|
|
89
|
+
"documentPreview.units.bytes",
|
|
90
|
+
"documentPreview.units.kilobytes",
|
|
91
|
+
"documentPreview.units.megabytes",
|
|
92
|
+
"documentPreview.units.gigabytes"
|
|
93
|
+
], S = ["B", "KB", "MB", "GB"];
|
|
94
|
+
function me(a, r, u) {
|
|
95
|
+
let l = a, o = 0;
|
|
96
|
+
for (; l >= 1024 && o < S.length - 1; )
|
|
97
|
+
l /= 1024, o++;
|
|
98
|
+
return `${new Intl.NumberFormat(r, {
|
|
99
|
+
maximumFractionDigits: o === 0 ? 0 : 1
|
|
100
|
+
}).format(l)} ${u(ce[o], S[o])}`;
|
|
101
|
+
}
|
|
102
|
+
const ue = j(({ id: a, name: r, mimeType: u, src: l, metadata: o, documents: h, className: F }, M) => {
|
|
103
|
+
const { t: s, i18n: T } = U(), c = I(() => h && h.length > 0 ? h : r ? [{ id: a ?? r, name: r, mimeType: u, src: l, metadata: o }] : [], [h, a, r, u, l, o]), P = c.length > 1, [R, C] = q(void 0), n = c.find((t) => t.id === R) ?? c[0], x = I(
|
|
104
|
+
() => ({
|
|
105
|
+
getKind: () => n ? z(n.name, n.mimeType, n.src) : "empty",
|
|
106
|
+
getName: () => n == null ? void 0 : n.name
|
|
107
|
+
}),
|
|
108
|
+
[n]
|
|
109
|
+
);
|
|
110
|
+
E(M, () => x, [x]), ee(de, x, a);
|
|
111
|
+
const A = (t) => {
|
|
112
|
+
const w = z(t.name, t.mimeType, t.src), e = t.metadata, _ = N(t.mimeType);
|
|
113
|
+
let y;
|
|
114
|
+
w === "pdf" && t.src ? y = /* @__PURE__ */ i(
|
|
115
|
+
J,
|
|
116
|
+
{
|
|
117
|
+
src: t.src,
|
|
118
|
+
toolbarVariant: "minimal",
|
|
119
|
+
ariaLabel: t.name,
|
|
120
|
+
className: "ds:h-full ds:w-full"
|
|
121
|
+
}
|
|
122
|
+
) : w === "image" && t.src ? y = /* @__PURE__ */ i(
|
|
123
|
+
"img",
|
|
124
|
+
{
|
|
125
|
+
src: t.src,
|
|
126
|
+
alt: s("documentPreview.imageAlt", "Preview of {{name}}", {
|
|
127
|
+
name: t.name
|
|
128
|
+
}),
|
|
129
|
+
className: "ds:max-h-full ds:max-w-full ds:object-contain"
|
|
130
|
+
}
|
|
131
|
+
) : y = /* @__PURE__ */ m("span", { className: "ds:flex ds:flex-col ds:items-center ds:gap-[var(--spacing-sm)] ds:text-muted-foreground", children: [
|
|
132
|
+
/* @__PURE__ */ i(_, { "aria-hidden": "true", className: "ds:size-10" }),
|
|
133
|
+
/* @__PURE__ */ i("span", { className: "type-body-sm", children: s("documentPreview.noPreview", "No preview available.") })
|
|
134
|
+
] });
|
|
135
|
+
const p = e == null ? void 0 : e.signatureStatus, k = !!(e != null && e.documentType) || !!(e != null && e.clinical) || p !== void 0 && p !== "none", f = (v) => new Intl.DateTimeFormat(T.language, { dateStyle: "medium" }).format(
|
|
136
|
+
new Date(v)
|
|
137
|
+
), d = [];
|
|
138
|
+
e != null && e.createdBy && d.push({
|
|
139
|
+
key: "createdBy",
|
|
140
|
+
label: s("documentPreview.fields.createdBy", "Created by"),
|
|
141
|
+
value: e.createdBy
|
|
142
|
+
}), e != null && e.createdAt && d.push({
|
|
143
|
+
key: "created",
|
|
144
|
+
label: s("documentPreview.fields.created", "Created"),
|
|
145
|
+
value: f(e.createdAt)
|
|
146
|
+
}), e != null && e.updatedAt && d.push({
|
|
147
|
+
key: "modified",
|
|
148
|
+
label: s("documentPreview.fields.modified", "Modified"),
|
|
149
|
+
value: f(e.updatedAt)
|
|
150
|
+
}), e != null && e.signatureRequestedAt && d.push({
|
|
151
|
+
key: "signatureRequested",
|
|
152
|
+
label: s(
|
|
153
|
+
"documentPreview.fields.signatureRequested",
|
|
154
|
+
"Signature requested"
|
|
155
|
+
),
|
|
156
|
+
value: f(e.signatureRequestedAt)
|
|
157
|
+
}), e != null && e.signedAt && d.push({
|
|
158
|
+
key: "signed",
|
|
159
|
+
label: s("documentPreview.fields.signed", "Signed"),
|
|
160
|
+
value: f(e.signedAt)
|
|
161
|
+
}), e != null && e.sharedAt && d.push({
|
|
162
|
+
key: "sharedWithPatient",
|
|
163
|
+
label: s(
|
|
164
|
+
"documentPreview.fields.sharedWithPatient",
|
|
165
|
+
"Shared with patient"
|
|
166
|
+
),
|
|
167
|
+
value: f(e.sharedAt)
|
|
168
|
+
}), (e == null ? void 0 : e.size) !== void 0 && d.push({
|
|
169
|
+
key: "size",
|
|
170
|
+
label: s("documentPreview.fields.size", "Size"),
|
|
171
|
+
value: me(e.size, T.language, s)
|
|
172
|
+
}), e != null && e.expiresAt && d.push({
|
|
173
|
+
key: "expires",
|
|
174
|
+
label: s("documentPreview.fields.expires", "Expires"),
|
|
175
|
+
value: f(e.expiresAt)
|
|
176
|
+
});
|
|
177
|
+
const V = k || d.length > 0;
|
|
178
|
+
return /* @__PURE__ */ i("div", { className: "ds:p-[var(--spacing-md)]", children: /* @__PURE__ */ m(
|
|
179
|
+
B,
|
|
180
|
+
{
|
|
181
|
+
variant: "elevated",
|
|
182
|
+
className: "ds:flex ds:flex-col ds:overflow-hidden",
|
|
183
|
+
children: [
|
|
184
|
+
/* @__PURE__ */ i("div", { className: "ds:flex ds:aspect-[4/3] ds:min-h-0 ds:items-center ds:justify-center ds:overflow-hidden ds:border-b ds:border-[color:var(--card-border)] ds:bg-muted", children: y }),
|
|
185
|
+
V && /* @__PURE__ */ m(B.Body, { className: "ds:flex ds:flex-col ds:gap-[var(--spacing-sm)]", children: [
|
|
186
|
+
/* @__PURE__ */ i("h3", { className: "type-eyebrow ds:m-0 ds:text-muted-foreground", children: s("documentPreview.detailsTitle", "Details") }),
|
|
187
|
+
k && /* @__PURE__ */ m("span", { className: "ds:flex ds:flex-wrap ds:items-center ds:gap-[var(--spacing-sm)]", children: [
|
|
188
|
+
(e == null ? void 0 : e.documentType) && /* @__PURE__ */ i(b, { variant: "neutral", size: "sm", children: e.documentType }),
|
|
189
|
+
(e == null ? void 0 : e.clinical) && /* @__PURE__ */ i(b, { variant: "info", size: "sm", children: s("documentPreview.clinical", "Clinical") }),
|
|
190
|
+
p && p !== "none" && /* @__PURE__ */ i(
|
|
191
|
+
b,
|
|
192
|
+
{
|
|
193
|
+
variant: oe[p],
|
|
194
|
+
size: "sm",
|
|
195
|
+
withDot: !0,
|
|
196
|
+
children: s(`documentPreview.signature.${p}`, p)
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
] }),
|
|
200
|
+
d.length > 0 && /* @__PURE__ */ i("dl", { className: "ds:grid ds:grid-cols-[auto_1fr] ds:gap-x-[var(--spacing-md)] ds:gap-y-[var(--spacing-xs)] type-body-sm", children: d.map((v) => /* @__PURE__ */ m(H, { children: [
|
|
201
|
+
/* @__PURE__ */ i("dt", { className: "ds:text-muted-foreground", children: v.label }),
|
|
202
|
+
/* @__PURE__ */ i("dd", { className: "ds:m-0", children: v.value })
|
|
203
|
+
] }, v.key)) })
|
|
204
|
+
] })
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
) });
|
|
208
|
+
}, D = N(n == null ? void 0 : n.mimeType), K = P ? /* @__PURE__ */ i(re, { "aria-hidden": "true" }) : /* @__PURE__ */ i(D, { "aria-hidden": "true" }), L = P ? /* @__PURE__ */ m(W, { children: [
|
|
209
|
+
s("documentPreview.multiTitle", "Documents"),
|
|
210
|
+
/* @__PURE__ */ i(b, { variant: "neutral", size: "sm", children: c.length })
|
|
211
|
+
] }) : n == null ? void 0 : n.name;
|
|
212
|
+
let g;
|
|
213
|
+
return c.length === 0 ? g = /* @__PURE__ */ i(
|
|
214
|
+
G,
|
|
215
|
+
{
|
|
216
|
+
variant: "first-use",
|
|
217
|
+
size: "sm",
|
|
218
|
+
title: s("documentPreview.emptyTitle", "No document selected"),
|
|
219
|
+
description: s(
|
|
220
|
+
"documentPreview.emptyDescription",
|
|
221
|
+
"Select a document to preview it here."
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
) : P ? g = /* @__PURE__ */ m(
|
|
225
|
+
O,
|
|
226
|
+
{
|
|
227
|
+
value: (n == null ? void 0 : n.id) ?? "",
|
|
228
|
+
onValueChange: C,
|
|
229
|
+
variant: "underlined",
|
|
230
|
+
size: "sm",
|
|
231
|
+
className: "ds:min-h-0 ds:flex-1 ds:pt-[var(--spacing-sm)]",
|
|
232
|
+
children: [
|
|
233
|
+
/* @__PURE__ */ i(
|
|
234
|
+
Q,
|
|
235
|
+
{
|
|
236
|
+
"aria-label": s("documentPreview.tabsLabel", "Selected documents"),
|
|
237
|
+
className: "ds:gap-[var(--spacing-sm)]",
|
|
238
|
+
children: c.map((t) => {
|
|
239
|
+
const w = N(t.mimeType);
|
|
240
|
+
return /* @__PURE__ */ i(
|
|
241
|
+
X,
|
|
242
|
+
{
|
|
243
|
+
value: t.id,
|
|
244
|
+
icon: /* @__PURE__ */ i(
|
|
245
|
+
w,
|
|
246
|
+
{
|
|
247
|
+
"aria-hidden": "true",
|
|
248
|
+
className: "ds:size-4 ds:text-[color:var(--accent)]"
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
className: "ds:[min-inline-size:0]",
|
|
252
|
+
children: /* @__PURE__ */ i("span", { className: "ds:block ds:truncate ds:[min-inline-size:0]", children: t.name })
|
|
253
|
+
},
|
|
254
|
+
t.id
|
|
255
|
+
);
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
),
|
|
259
|
+
c.map((t) => /* @__PURE__ */ i(
|
|
260
|
+
Z,
|
|
261
|
+
{
|
|
262
|
+
value: t.id,
|
|
263
|
+
className: "ds:min-h-0 ds:flex-1",
|
|
264
|
+
children: A(t)
|
|
265
|
+
},
|
|
266
|
+
t.id
|
|
267
|
+
))
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
) : g = A(n), /* @__PURE__ */ m(
|
|
271
|
+
"section",
|
|
272
|
+
{
|
|
273
|
+
"data-component": "document-preview",
|
|
274
|
+
"data-component-id": a,
|
|
275
|
+
tabIndex: 0,
|
|
276
|
+
"aria-label": s("documentPreview.regionLabel", "Document preview"),
|
|
277
|
+
className: le({ className: F }),
|
|
278
|
+
children: [
|
|
279
|
+
c.length > 0 && /* @__PURE__ */ i(Y, { sticky: !0, icon: K, title: L }),
|
|
280
|
+
g
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
});
|
|
285
|
+
ue.displayName = "DocumentPreview";
|
|
286
|
+
export {
|
|
287
|
+
ue as D,
|
|
288
|
+
de as d
|
|
289
|
+
};
|
|
290
|
+
//# sourceMappingURL=document-preview-nwfulDEs.js.map
|