@alfadocs/ui-kit-debug 0.41.2 → 0.42.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/address-autocomplete-CSjMrBvu.js +358 -0
- package/dist/_chunks/address-autocomplete-CSjMrBvu.js.map +1 -0
- package/dist/_chunks/{alia-sidebar-DXsYPinm.js → alia-sidebar-BpX4z_af.js} +2 -2
- package/dist/_chunks/{alia-sidebar-DXsYPinm.js.map → alia-sidebar-BpX4z_af.js.map} +1 -1
- package/dist/_chunks/{bmi-calculator-DnEr513I.js → bmi-calculator-D4juUcyF.js} +57 -51
- package/dist/_chunks/bmi-calculator-D4juUcyF.js.map +1 -0
- package/dist/_chunks/{breadcrumb-CLlhx7qo.js → breadcrumb-OTbaY70e.js} +4 -4
- package/dist/_chunks/{breadcrumb-CLlhx7qo.js.map → breadcrumb-OTbaY70e.js.map} +1 -1
- package/dist/_chunks/cycle-calculator-DsZbyzX6.js +191 -0
- package/dist/_chunks/cycle-calculator-DsZbyzX6.js.map +1 -0
- package/dist/_chunks/{document-scanner-CqS_klIr.js → document-scanner-BqLsGs4Y.js} +7 -7
- package/dist/_chunks/{document-scanner-CqS_klIr.js.map → document-scanner-BqLsGs4Y.js.map} +1 -1
- package/dist/_chunks/{dropdown-menu-BC5ZdOMo.js → dropdown-menu-CUEXqKis.js} +2 -2
- package/dist/_chunks/{dropdown-menu-BC5ZdOMo.js.map → dropdown-menu-CUEXqKis.js.map} +1 -1
- package/dist/_chunks/{due-date-calculator-CUspKSTw.js → due-date-calculator-s_CBgaFs.js} +53 -40
- package/dist/_chunks/due-date-calculator-s_CBgaFs.js.map +1 -0
- package/dist/_chunks/{editable-currency-cell-renderer-DgkCIIcO.js → editable-currency-cell-renderer-BhUkRiPZ.js} +2 -2
- package/dist/_chunks/{editable-currency-cell-renderer-DgkCIIcO.js.map → editable-currency-cell-renderer-BhUkRiPZ.js.map} +1 -1
- package/dist/_chunks/{freemium-paywall-BAk3a6er.js → freemium-paywall-BLXESpH4.js} +2 -2
- package/dist/_chunks/{freemium-paywall-BAk3a6er.js.map → freemium-paywall-BLXESpH4.js.map} +1 -1
- package/dist/_chunks/{gestational-age-calculator-CsQ05qDy.js → gestational-age-calculator-CWOG3bkI.js} +56 -43
- package/dist/_chunks/gestational-age-calculator-CWOG3bkI.js.map +1 -0
- package/dist/_chunks/{header-settings-CBLwUK6t.js → header-settings-Bx0Biimh.js} +2 -2
- package/dist/_chunks/{header-settings-CBLwUK6t.js.map → header-settings-Bx0Biimh.js.map} +1 -1
- package/dist/_chunks/index.modern-D2LGACWg.js +1529 -0
- package/dist/_chunks/index.modern-D2LGACWg.js.map +1 -0
- package/dist/_chunks/insert-result-DtQQeSSf.js +227 -0
- package/dist/_chunks/insert-result-DtQQeSSf.js.map +1 -0
- package/dist/_chunks/{kbd-Cglkd7CY.js → kbd-D855ZXIW.js} +2 -2
- package/dist/_chunks/{kbd-Cglkd7CY.js.map → kbd-D855ZXIW.js.map} +1 -1
- package/dist/_chunks/map-view-Tb5VfK9Y.js +333 -0
- package/dist/_chunks/map-view-Tb5VfK9Y.js.map +1 -0
- package/dist/_chunks/marketplace-app-shell-kVAVycz_.js +391 -0
- package/dist/_chunks/marketplace-app-shell-kVAVycz_.js.map +1 -0
- package/dist/_chunks/{patient-search-CBq62kmL.js → patient-search-DPe2ZYEL.js} +2 -2
- package/dist/_chunks/{patient-search-CBq62kmL.js.map → patient-search-DPe2ZYEL.js.map} +1 -1
- package/dist/_chunks/{patient-shell-DF81lALv.js → patient-shell-lDX3wwu6.js} +2 -2
- package/dist/_chunks/{patient-shell-DF81lALv.js.map → patient-shell-lDX3wwu6.js.map} +1 -1
- package/dist/_chunks/{payment-form-Dy3WIIsC.js → payment-form-BzVsG6Ks.js} +5 -5
- package/dist/_chunks/{payment-form-Dy3WIIsC.js.map → payment-form-BzVsG6Ks.js.map} +1 -1
- package/dist/_chunks/{pdf-viewer-Cy6Ul3hZ.js → pdf-viewer-B6MC6VTx.js} +139 -126
- package/dist/_chunks/pdf-viewer-B6MC6VTx.js.map +1 -0
- package/dist/_chunks/{practice-results-C0d4IL5E.js → practice-results-CrLpEiiW.js} +4 -4
- package/dist/_chunks/{practice-results-C0d4IL5E.js.map → practice-results-CrLpEiiW.js.map} +1 -1
- package/dist/_chunks/pregnancy-weight-gain-B7kBK-ZR.js +223 -0
- package/dist/_chunks/pregnancy-weight-gain-B7kBK-ZR.js.map +1 -0
- package/dist/_chunks/{public-header.agent-B2dDg2_d.js → public-header.agent-BY6FH71R.js} +2 -2
- package/dist/_chunks/{public-header.agent-B2dDg2_d.js.map → public-header.agent-BY6FH71R.js.map} +1 -1
- package/dist/_chunks/radio-group-CLjK-SlK.js +167 -0
- package/dist/_chunks/radio-group-CLjK-SlK.js.map +1 -0
- package/dist/_chunks/{rich-text-editor-DLbg2852.js → rich-text-editor-DhGIBd4a.js} +10 -10
- package/dist/_chunks/{rich-text-editor-DLbg2852.js.map → rich-text-editor-DhGIBd4a.js.map} +1 -1
- package/dist/_chunks/{sheet-BV-yuLE2.js → sheet-xbzu4YiY.js} +7 -7
- package/dist/_chunks/{sheet-BV-yuLE2.js.map → sheet-xbzu4YiY.js.map} +1 -1
- package/dist/_chunks/{sign-document-CpLDZ6Db.js → sign-document-QHfcNKFj.js} +5 -5
- package/dist/_chunks/{sign-document-CpLDZ6Db.js.map → sign-document-QHfcNKFj.js.map} +1 -1
- package/dist/_chunks/{signature-capture-DoiBd6i3.js → signature-capture-CpMBhqQ9.js} +6 -6
- package/dist/_chunks/{signature-capture-DoiBd6i3.js.map → signature-capture-CpMBhqQ9.js.map} +1 -1
- package/dist/_chunks/tab-bar-C4II-7ej.js +86 -0
- package/dist/_chunks/tab-bar-C4II-7ej.js.map +1 -0
- package/dist/_chunks/{theme-toggle-DpC28kt5.js → theme-toggle-ClATnY4Q.js} +2 -2
- package/dist/_chunks/{theme-toggle-DpC28kt5.js.map → theme-toggle-ClATnY4Q.js.map} +1 -1
- package/dist/_chunks/{toast.agent-WHHfw5VX.js → toast.agent-B0MCsvdZ.js} +2 -2
- package/dist/_chunks/{toast.agent-WHHfw5VX.js.map → toast.agent-B0MCsvdZ.js.map} +1 -1
- package/dist/_chunks/{unit-converter-EUwO6QYq.js → unit-converter-D1UrEUxa.js} +46 -40
- package/dist/_chunks/unit-converter-D1UrEUxa.js.map +1 -0
- package/dist/_chunks/{workflow-map-C3gB0FvB.js → workflow-map-BFNpzTiw.js} +2 -2
- package/dist/_chunks/{workflow-map-C3gB0FvB.js.map → workflow-map-BFNpzTiw.js.map} +1 -1
- package/dist/agent-catalog.json +1 -1
- package/dist/brand/product-lockup/product-lockup.d.ts +16 -0
- package/dist/brand/product-lockup/product-lockup.d.ts.map +1 -1
- package/dist/components/_shared/insert-result.d.ts +21 -4
- package/dist/components/_shared/insert-result.d.ts.map +1 -1
- package/dist/components/address-autocomplete/address-autocomplete.d.ts +77 -0
- package/dist/components/address-autocomplete/address-autocomplete.d.ts.map +1 -0
- package/dist/components/address-autocomplete/index.d.ts +4 -0
- package/dist/components/address-autocomplete/index.d.ts.map +1 -0
- package/dist/components/address-autocomplete/index.js +6 -0
- package/dist/components/address-autocomplete/index.js.map +1 -0
- package/dist/components/address-autocomplete/parse-address.d.ts +52 -0
- package/dist/components/address-autocomplete/parse-address.d.ts.map +1 -0
- package/dist/components/bmi-calculator/bmi-calculator.d.ts +11 -1
- package/dist/components/bmi-calculator/bmi-calculator.d.ts.map +1 -1
- package/dist/components/bmi-calculator/index.js +1 -1
- package/dist/components/breadcrumb/index.js +1 -1
- package/dist/components/cycle-calculator/cycle-calculator.d.ts +12 -2
- package/dist/components/cycle-calculator/cycle-calculator.d.ts.map +1 -1
- package/dist/components/cycle-calculator/index.js +1 -1
- package/dist/components/data-table/index.js +1 -1
- package/dist/components/document-scanner/index.js +1 -1
- package/dist/components/dropdown-menu/index.js +1 -1
- package/dist/components/due-date-calculator/due-date-calculator.d.ts +11 -1
- package/dist/components/due-date-calculator/due-date-calculator.d.ts.map +1 -1
- package/dist/components/due-date-calculator/index.js +1 -1
- package/dist/components/freemium-paywall/index.js +1 -1
- package/dist/components/gestational-age-calculator/gestational-age-calculator.d.ts +12 -2
- package/dist/components/gestational-age-calculator/gestational-age-calculator.d.ts.map +1 -1
- package/dist/components/gestational-age-calculator/index.js +1 -1
- package/dist/components/header-settings/index.js +1 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/kbd/index.js +1 -1
- package/dist/components/map-view/index.js +1 -1
- package/dist/components/matrix-rain/matrix-rain.d.ts +1 -1
- package/dist/components/patient-search/index.js +1 -1
- package/dist/components/payment-form/index.js +1 -1
- package/dist/components/pdf-viewer/index.js +1 -1
- package/dist/components/pdf-viewer/pdf-viewer.d.ts.map +1 -1
- package/dist/components/practice-results/index.js +1 -1
- package/dist/components/pregnancy-weight-gain/index.js +1 -1
- package/dist/components/pregnancy-weight-gain/pregnancy-weight-gain.d.ts +12 -2
- package/dist/components/pregnancy-weight-gain/pregnancy-weight-gain.d.ts.map +1 -1
- package/dist/components/public-header/index.js +1 -1
- package/dist/components/radio-group/index.js +1 -1
- package/dist/components/radio-group/radio-group.d.ts.map +1 -1
- package/dist/components/rich-text-editor/index.js +1 -1
- package/dist/components/sheet/index.js +1 -1
- package/dist/components/sheet/sheet.d.ts.map +1 -1
- package/dist/components/sign-document/index.js +1 -1
- package/dist/components/signature-capture/index.js +1 -1
- package/dist/components/tab-bar/index.d.ts +3 -0
- package/dist/components/tab-bar/index.d.ts.map +1 -0
- package/dist/components/tab-bar/index.js +5 -0
- package/dist/components/tab-bar/index.js.map +1 -0
- package/dist/components/tab-bar/tab-bar.d.ts +61 -0
- package/dist/components/tab-bar/tab-bar.d.ts.map +1 -0
- package/dist/components/theme-toggle/index.js +1 -1
- package/dist/components/toast/index.js +1 -1
- package/dist/components/unit-converter/index.js +1 -1
- package/dist/components/unit-converter/unit-converter.d.ts +11 -1
- package/dist/components/unit-converter/unit-converter.d.ts.map +1 -1
- package/dist/components/workflow/index.js +1 -1
- package/dist/i18n/locales/ar.d.ts +17 -0
- package/dist/i18n/locales/ar.d.ts.map +1 -1
- package/dist/i18n/locales/ar.js +18 -1
- package/dist/i18n/locales/ar.js.map +1 -1
- package/dist/i18n/locales/de.d.ts +17 -0
- package/dist/i18n/locales/de.d.ts.map +1 -1
- package/dist/i18n/locales/de.js +18 -1
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/el.d.ts +17 -0
- package/dist/i18n/locales/el.d.ts.map +1 -1
- package/dist/i18n/locales/el.js +18 -1
- package/dist/i18n/locales/el.js.map +1 -1
- package/dist/i18n/locales/en.d.ts +17 -0
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/en.js +18 -1
- package/dist/i18n/locales/en.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +17 -0
- package/dist/i18n/locales/es.d.ts.map +1 -1
- package/dist/i18n/locales/es.js +18 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +17 -0
- package/dist/i18n/locales/fr.d.ts.map +1 -1
- package/dist/i18n/locales/fr.js +18 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hi.d.ts +17 -0
- package/dist/i18n/locales/hi.d.ts.map +1 -1
- package/dist/i18n/locales/hi.js +18 -1
- package/dist/i18n/locales/hi.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +17 -0
- package/dist/i18n/locales/it.d.ts.map +1 -1
- package/dist/i18n/locales/it.js +18 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/ja.d.ts +17 -0
- package/dist/i18n/locales/ja.d.ts.map +1 -1
- package/dist/i18n/locales/ja.js +18 -1
- package/dist/i18n/locales/ja.js.map +1 -1
- package/dist/i18n/locales/nl.d.ts +17 -0
- package/dist/i18n/locales/nl.d.ts.map +1 -1
- package/dist/i18n/locales/nl.js +18 -1
- package/dist/i18n/locales/nl.js.map +1 -1
- package/dist/i18n/locales/pl.d.ts +17 -0
- package/dist/i18n/locales/pl.d.ts.map +1 -1
- package/dist/i18n/locales/pl.js +18 -1
- package/dist/i18n/locales/pl.js.map +1 -1
- package/dist/i18n/locales/pt.d.ts +17 -0
- package/dist/i18n/locales/pt.d.ts.map +1 -1
- package/dist/i18n/locales/pt.js +18 -1
- package/dist/i18n/locales/pt.js.map +1 -1
- package/dist/i18n/locales/ro.d.ts +17 -0
- package/dist/i18n/locales/ro.d.ts.map +1 -1
- package/dist/i18n/locales/ro.js +18 -1
- package/dist/i18n/locales/ro.js.map +1 -1
- package/dist/i18n/locales/ru.d.ts +17 -0
- package/dist/i18n/locales/ru.d.ts.map +1 -1
- package/dist/i18n/locales/ru.js +18 -1
- package/dist/i18n/locales/ru.js.map +1 -1
- package/dist/i18n/locales/sq.d.ts +17 -0
- package/dist/i18n/locales/sq.d.ts.map +1 -1
- package/dist/i18n/locales/sq.js +18 -1
- package/dist/i18n/locales/sq.js.map +1 -1
- package/dist/i18n/locales/sv.d.ts +17 -0
- package/dist/i18n/locales/sv.d.ts.map +1 -1
- package/dist/i18n/locales/sv.js +18 -1
- package/dist/i18n/locales/sv.js.map +1 -1
- package/dist/i18n/locales/tr.d.ts +17 -0
- package/dist/i18n/locales/tr.d.ts.map +1 -1
- package/dist/i18n/locales/tr.js +18 -1
- package/dist/i18n/locales/tr.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +17 -0
- package/dist/i18n/locales/zh.d.ts.map +1 -1
- package/dist/i18n/locales/zh.js +18 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.js +604 -599
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.json +18 -1
- package/dist/locales/de.json +18 -1
- package/dist/locales/el.json +18 -1
- package/dist/locales/en.json +18 -1
- package/dist/locales/es.json +18 -1
- package/dist/locales/fr.json +18 -1
- package/dist/locales/hi.json +18 -1
- package/dist/locales/it.json +18 -1
- package/dist/locales/ja.json +18 -1
- package/dist/locales/nl.json +18 -1
- package/dist/locales/pl.json +18 -1
- package/dist/locales/pt.json +18 -1
- package/dist/locales/ro.json +18 -1
- package/dist/locales/ru.json +18 -1
- package/dist/locales/sq.json +18 -1
- package/dist/locales/sv.json +18 -1
- package/dist/locales/tr.json +18 -1
- package/dist/locales/zh.json +18 -1
- package/dist/patterns/alia-assistant/index.js +1 -1
- package/dist/patterns/marketplace-app-shell/index.js +1 -1
- package/dist/patterns/marketplace-app-shell/marketplace-app-shell.d.ts +30 -3
- package/dist/patterns/marketplace-app-shell/marketplace-app-shell.d.ts.map +1 -1
- package/dist/patterns/patient-shell/index.js +1 -1
- package/dist/tokens.css +1 -1
- package/package.json +16 -1
- package/dist/_chunks/bmi-calculator-DnEr513I.js.map +0 -1
- package/dist/_chunks/cycle-calculator-B5Uj9QeT.js +0 -185
- package/dist/_chunks/cycle-calculator-B5Uj9QeT.js.map +0 -1
- package/dist/_chunks/due-date-calculator-CUspKSTw.js.map +0 -1
- package/dist/_chunks/gestational-age-calculator-CsQ05qDy.js.map +0 -1
- package/dist/_chunks/insert-result-yJ0QavoN.js +0 -133
- package/dist/_chunks/insert-result-yJ0QavoN.js.map +0 -1
- package/dist/_chunks/map-view-qJLybrmN.js +0 -1850
- package/dist/_chunks/map-view-qJLybrmN.js.map +0 -1
- package/dist/_chunks/marketplace-app-shell-BlxVizU4.js +0 -296
- package/dist/_chunks/marketplace-app-shell-BlxVizU4.js.map +0 -1
- package/dist/_chunks/pdf-viewer-Cy6Ul3hZ.js.map +0 -1
- package/dist/_chunks/pregnancy-weight-gain-BCdi-JSv.js +0 -209
- package/dist/_chunks/pregnancy-weight-gain-BCdi-JSv.js.map +0 -1
- package/dist/_chunks/radio-group-BcF92GEF.js +0 -152
- package/dist/_chunks/radio-group-BcF92GEF.js.map +0 -1
- package/dist/_chunks/unit-converter-EUwO6QYq.js.map +0 -1
package/dist/_chunks/{signature-capture-DoiBd6i3.js.map → signature-capture-CpMBhqQ9.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature-capture-DoiBd6i3.js","sources":["../../src/components/signature-capture/signature-capture.agent.ts","../../src/components/signature-capture/signature-capture.tsx"],"sourcesContent":["import type { AgentAdapter } from '../../agent/types';\nimport type { SignatureCaptureHandle } from './signature-capture';\n\nexport const signatureCaptureAgent: AgentAdapter<SignatureCaptureHandle> = {\n id: 'signature-capture',\n capabilities: ['edit_inline', 'submit'],\n state: {\n isEmpty: {\n type: 'boolean',\n description: 'True when no signature has been drawn or typed.',\n read: (handle) => handle.isEmpty(),\n },\n },\n actions: {\n clear: {\n safety: 'destructive',\n description: 'Erase the current signature. Loses unsaved input.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n undo: {\n safety: 'write',\n description: 'Undo the last stroke.',\n invoke: (handle) => {\n handle.undo();\n },\n },\n confirm: {\n safety: 'write',\n description: 'Commit the signature and return its serialised payload.',\n invoke: (handle) => handle.confirm(),\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'signature-capture' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* SignatureCapture — thin React wrapper over signature_pad. */\n/* */\n/* - Library: `signature_pad` (08-third-party §Signature Pad). We */\n/* instantiate one pad per mounted canvas and expose imperative */\n/* clear / undo / isEmpty / confirm verbs to the consumer. */\n/* - Colors: `penColor` / `backgroundColor` default to */\n/* `--foreground` / `--background` via `getComputedStyle()`. Theme */\n/* switches are observed via a MutationObserver on `<html class>` */\n/* so the ink recolours when the theme flips. */\n/* - DPR scaling: canvas attribute `width/height = cssSize * DPR`; the */\n/* 2D context is scaled by the same factor. A `ResizeObserver` */\n/* replays strokes via `fromData()` on re-scale so nothing is lost. */\n/* - Typed fallback: keyboard-only path renders a text input styled in */\n/* italic `var(--font-sans)` (per 23-constraints §10 — serif is */\n/* marketing only). On confirm we render the string to an offscreen */\n/* canvas for the PNG/SVG export. */\n/* - Confirm payload: `{ png, svg, widthMm, heightMm, capturedAt, */\n/* sha256, strokes? }`. `sha256` is the SubtleCrypto digest of the */\n/* PNG bytes — tamper-evident for audit trails. */\n/* - Security: no `fetch` / `XMLHttpRequest` / `localStorage` / */\n/* `sessionStorage` in this file — the consumer owns persistence. */\n/* */\n/* TODO: */\n/* - 3× DPI re-render for print: currently `toDataURL('image/png')` */\n/* exports the live canvas (already at DPR). A proper 300-DPI */\n/* pipeline would create an offscreen canvas at `cssSize × 3` and */\n/* replay strokes via `fromData()` — deferred pending the print */\n/* bridge landing. */\n/* - Typed-fallback canvas font can't read CSS variables directly */\n/* (Canvas2D resolves fonts at paint time and won't expand */\n/* `var(--font-size-2xl)`); we use a fixed `32px italic` + the */\n/* user's font stack, which is visually close but not */\n/* theme-reactive. Will migrate once the typography tokens expose */\n/* a resolved `font` shorthand. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\nimport SignaturePad from 'signature_pad';\nimport type { PointGroup } from 'signature_pad';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { signatureCaptureAgent } from './signature-capture.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface SignatureConfirmPayload {\n /** Data URL of the captured signature rendered as PNG. */\n png: string;\n /** SVG string trimmed to the stroke bounding box. */\n svg: string;\n /** Physical width in millimetres, derived from CSS px. */\n widthMm: number;\n /** Physical height in millimetres, derived from CSS px. */\n heightMm: number;\n /** ISO-8601 UTC timestamp for when `confirm()` resolved. */\n capturedAt: string;\n /** Hex-encoded SHA-256 digest of the PNG bytes. */\n sha256: string;\n /** Raw stroke data from `signature_pad.toData()` — optional for replays. */\n strokes?: PointGroup[];\n}\n\nexport interface SignatureCaptureProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Called with the export payload when the user confirms the signature. */\n onConfirm?: (payload: SignatureConfirmPayload) => void;\n /** Called after the pad is cleared (explicit user action). */\n onClear?: () => void;\n /** Called when the user starts drawing a new stroke. */\n onStart?: () => void;\n /** CSS width of the pad. Default 400. */\n width?: number | string;\n /** CSS height of the pad. Default 200. */\n height?: number | string;\n /** Pen colour override — defaults to `var(--foreground)`. */\n penColor?: string;\n /** Background override — defaults to `var(--background)`. */\n backgroundColor?: string;\n /** Show the typed-name fallback toggle. Default `true`. */\n allowTypedFallback?: boolean;\n /** Disable the entire component. */\n disabled?: boolean;\n /** Accessible label for the pad region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface SignatureCaptureHandle {\n clear: () => void;\n undo: () => void;\n isEmpty: () => boolean;\n confirm: () => Promise<SignatureConfirmPayload | null>;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n [\n 'ds:signature-capture-alfadocs ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:[.theme-accessible_&]:border-2',\n 'ds:p-[var(--spacing-sm)]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst padFrameVariants = cva(\n [\n 'ds:relative ds:block',\n 'ds:inline-size-[var(--signature-width)]',\n 'ds:block-size-[var(--signature-height)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)]',\n 'ds:overflow-hidden',\n 'ds:touch-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\nconst canvasVariants = cva(\n [\n 'ds:block',\n 'ds:inline-size-full',\n 'ds:block-size-full',\n 'ds:touch-none',\n 'ds:select-none',\n ].join(' '),\n);\n\nconst toolbarVariants = cva(\n ['ds:flex ds:items-stretch ds:flex-wrap ds:gap-[var(--spacing-sm)]'].join(\n ' ',\n ),\n);\n\n// Toolbar actions are sized for thumbs: they grow to fill the pad width\n// (`flex-1`), sit above the 44/48px floor, and use base-size text so they read\n// clearly on a phone.\nconst actionButtonVariants = cva(\n [\n 'ds:inline-flex ds:flex-1 ds:items-center ds:justify-center',\n 'ds:min-block-size-[var(--min-target-size)]',\n 'ds:min-inline-size-[var(--min-target-size)]',\n 'ds:gap-[var(--spacing-xs)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-transparent ds:text-[var(--foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--muted)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst confirmButtonVariants = cva(\n [\n 'ds:inline-flex ds:flex-1 ds:items-center ds:justify-center',\n 'ds:min-block-size-[var(--min-target-size)]',\n 'ds:min-inline-size-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--primary-hover)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst typedInputVariants = cva(\n [\n 'ds:block ds:inline-size-full',\n 'ds:min-block-size-[var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:font-[family-name:var(--font-sans)]',\n 'ds:italic',\n 'ds:tracking-[0.1em]',\n 'ds:text-[length:var(--font-size-lg)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\nconst typedPreviewVariants = cva(\n [\n 'ds:flex ds:items-center ds:justify-center',\n 'ds:inline-size-[var(--signature-width)]',\n 'ds:block-size-[var(--signature-height)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--card-border)]',\n 'ds:[.theme-accessible_&]:border-2',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:font-[family-name:var(--font-sans)]',\n 'ds:italic',\n 'ds:tracking-[0.1em]',\n 'ds:text-[length:var(--font-size-2xl)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\ntype SignatureState = 'empty' | 'drawing' | 'captured' | 'cleared';\n\n/**\n * Resolve a CSS custom property against `document.documentElement`. We\n * can't pass `var(--foreground)` to signature_pad directly — the lib\n * stamps the string straight into `ctx.strokeStyle`, which only accepts\n * concrete colour values. Looking the variable up at runtime keeps the\n * component in tokens-only compliance.\n */\nfunction resolveCssVar(name: string): string {\n if (typeof document === 'undefined') return '';\n const value = getComputedStyle(document.documentElement)\n .getPropertyValue(name)\n .trim();\n return value;\n}\n\nfunction toCssSize(v: number | string | undefined, fallback: string): string {\n if (typeof v === 'number') return `${v}px`;\n if (typeof v === 'string' && v.length > 0) return v;\n return fallback;\n}\n\n/**\n * Parse a pixel value, returning `null` for non-pixel strings (e.g.\n * \"100%\", \"50vw\") so the caller can fall back to the measured rect.\n * parseFloat(\"100%\") would silently return 100 — a 100mm-wide export\n * masquerading as 26mm. Allow only digits, dot, minus, whitespace, \"px\".\n */\nfunction parsePxValue(v: string): number | null {\n if (typeof v === 'string' && /[^0-9.\\s\\-px]/i.test(v)) return null;\n const n = parseFloat(v);\n if (!Number.isFinite(n)) return null;\n return n;\n}\n\n/** Hex-encode a Uint8Array. */\nfunction toHex(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i += 1) {\n const b = bytes[i];\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n\n/** Decode a base64 string into bytes without `atob` polyfills. */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === 'function') {\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n // Fallback — node-style Buffer, gated behind a runtime check.\n const g = globalThis as {\n Buffer?: { from: (s: string, enc: string) => Uint8Array };\n };\n if (g.Buffer) return g.Buffer.from(b64, 'base64');\n return new Uint8Array();\n}\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n const g = globalThis as { crypto?: Crypto };\n if (g.crypto?.subtle) {\n // Copy the bytes into a fresh ArrayBuffer so the slice is always an\n // ArrayBuffer (never a SharedArrayBuffer) — SubtleCrypto's BufferSource\n // narrowing doesn't accept the latter.\n const copy = new Uint8Array(bytes.byteLength);\n copy.set(bytes);\n const digest = await g.crypto.subtle.digest('SHA-256', copy.buffer);\n return toHex(new Uint8Array(digest));\n }\n // No subtle crypto — return empty so callers can still use the rest\n // of the payload. Test env is expected to stub crypto.subtle.\n return '';\n}\n\n/**\n * Render the typed fallback string onto an offscreen canvas and return\n * it. Used by the confirm path when the user has typed their name\n * instead of drawing. Size is fixed at `32px italic` because Canvas2D\n * resolves fonts eagerly and can't expand `var(--font-size-*)`.\n */\nfunction renderTypedSignatureToCanvas(\n text: string,\n cssWidth: number,\n cssHeight: number,\n penColor: string,\n backgroundColor: string,\n): HTMLCanvasElement {\n const dpr = Math.max(\n 1,\n typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n );\n const canvas = document.createElement('canvas');\n canvas.width = Math.floor(cssWidth * dpr);\n canvas.height = Math.floor(cssHeight * dpr);\n const ctx = canvas.getContext('2d');\n if (!ctx) return canvas;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n // Fill background with the token-resolved colour.\n ctx.fillStyle = backgroundColor || 'transparent';\n ctx.fillRect(0, 0, cssWidth, cssHeight);\n // Draw the typed signature centred.\n ctx.fillStyle = penColor || 'currentColor';\n ctx.font = '32px italic sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, cssWidth / 2, cssHeight / 2, cssWidth - 16);\n return canvas;\n}\n\n/* ------------------------------------------------------------------ */\n/* SignatureCapture */\n/* ------------------------------------------------------------------ */\n\nexport const SignatureCapture = forwardRef<\n SignatureCaptureHandle,\n SignatureCaptureProps\n>(\n (\n {\n id,\n onConfirm,\n onClear,\n onStart,\n width = 400,\n height = 200,\n penColor,\n backgroundColor,\n allowTypedFallback = true,\n disabled = false,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const rawId = useId();\n const idSafe = useMemo(\n () => `sig-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n const liveRegionId = `${idSafe}-live`;\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n const padFrameRef = useRef<HTMLDivElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const typedPreviewRef = useRef<HTMLDivElement>(null);\n const signaturePadRef = useRef<SignaturePad | null>(null);\n\n const [mode, setMode] = useState<'draw' | 'typed'>('draw');\n const [typedValue, setTypedValue] = useState('');\n // Tracks whether the pad has any ink — gates the Confirm button.\n // signature_pad's isEmpty() is a sync ref read and won't trigger\n // re-renders; this state mirrors it so React sees the change.\n const [padHasInk, setPadHasInk] = useState(false);\n // Retained state — consumers may subscribe to the pad's lifecycle via\n // `onConfirm`/`onClear`/`onStart`; we still track the machine internally\n // so the live region + confirm button stay coherent.\n const signatureStateRef = useRef<SignatureState>('empty');\n const [announcement, setAnnouncement] = useState<string>('');\n const [resolvedPen, setResolvedPen] = useState<string>('');\n const [resolvedBg, setResolvedBg] = useState<string>('');\n\n // Stable callback refs so we can wire signature_pad once without\n // re-instantiating on every render.\n const onStartRef = useRef<SignatureCaptureProps['onStart']>(onStart);\n const onClearRef = useRef<SignatureCaptureProps['onClear']>(onClear);\n const onConfirmRef = useRef<SignatureCaptureProps['onConfirm']>(onConfirm);\n useEffect(() => {\n onStartRef.current = onStart;\n onClearRef.current = onClear;\n onConfirmRef.current = onConfirm;\n }, [onStart, onClear, onConfirm]);\n\n /* ---- Announce helper ---------------------------------------- */\n const announce = useCallback(\n (next: SignatureState) => {\n signatureStateRef.current = next;\n setAnnouncement(t(`signature.state.${next}`));\n },\n [t],\n );\n\n /* ---- Resolve tokens ----------------------------------------- */\n useEffect(() => {\n if (typeof document === 'undefined') return undefined;\n function resolveAll(): void {\n const pen = penColor ?? resolveCssVar('--foreground');\n const bg = backgroundColor ?? resolveCssVar('--background');\n // Fall back to `currentColor` / `transparent` — keyword literals\n // are token-neutral and honour the surrounding theme even when\n // the CSS variable is briefly unavailable (SSR, initial paint).\n setResolvedPen(pen || 'currentColor');\n setResolvedBg(bg || 'transparent');\n }\n resolveAll();\n // Watch for theme-class changes on <html>.\n const mo = new MutationObserver(() => {\n resolveAll();\n });\n mo.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n });\n return () => mo.disconnect();\n }, [penColor, backgroundColor]);\n\n /* ---- Apply colour changes to an existing pad ---------------- */\n useEffect(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n if (resolvedPen) pad.penColor = resolvedPen;\n if (resolvedBg) pad.backgroundColor = resolvedBg;\n }, [resolvedPen, resolvedBg]);\n\n /* ---- Instantiate signature_pad ------------------------------ */\n useEffect(() => {\n if (mode !== 'draw') return undefined;\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n\n const pad = new SignaturePad(canvas, {\n penColor: resolvedPen || 'currentColor',\n backgroundColor: resolvedBg || 'transparent',\n minWidth: 0.5,\n maxWidth: 2.5,\n velocityFilterWeight: 0.7,\n });\n signaturePadRef.current = pad;\n\n const handleBegin = (): void => {\n setPadHasInk(true);\n announce('drawing');\n onStartRef.current?.();\n };\n const handleEnd = (): void => {\n // Keep state as 'drawing' — transition to 'captured' on confirm.\n };\n pad.addEventListener('beginStroke', handleBegin);\n pad.addEventListener('endStroke', handleEnd);\n\n // Initial DPR scale + announcement.\n scaleCanvas(canvas);\n announce('empty');\n\n return () => {\n pad.removeEventListener('beginStroke', handleBegin);\n pad.removeEventListener('endStroke', handleEnd);\n // Clear strokes from memory; 08-third-party §Signature Pad.\n pad.clear();\n pad.off();\n signaturePadRef.current = null;\n };\n // We intentionally re-create the pad only when switching between\n // typed and draw modes. Color updates flow through the effect above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode]);\n\n /* ---- Disabled state ----------------------------------------- */\n useEffect(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n if (disabled) pad.off();\n else pad.on();\n }, [disabled, mode]);\n\n /* ---- DPR + ResizeObserver ----------------------------------- */\n // Hard-cap backing-store dimensions to bound memory. 4096 px × 4096 px at\n // 4 bytes per pixel is ~67 MB — generous for any realistic signature, but\n // well under the multi-GB allocation a careless or malicious prop could\n // request on a high-DPR display. See security-hardening.mdx.\n const MAX_CANVAS_PX = 4096;\n const scaleCanvas = useCallback(\n (canvas: HTMLCanvasElement) => {\n const rect = canvas.getBoundingClientRect();\n const dpr = Math.max(\n 1,\n typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n );\n const rawWidth = Math.max(1, Math.floor(rect.width * dpr));\n const rawHeight = Math.max(1, Math.floor(rect.height * dpr));\n const targetWidth = Math.min(rawWidth, MAX_CANVAS_PX);\n const targetHeight = Math.min(rawHeight, MAX_CANVAS_PX);\n if (\n import.meta.env.DEV &&\n (rawWidth !== targetWidth || rawHeight !== targetHeight)\n ) {\n // Silent in production; a consumer shipping 10k × 10k probably wants\n // the nudge.\n console.warn(\n `[SignatureCapture] clamped canvas backing store from ${rawWidth}x${rawHeight} to ${targetWidth}x${targetHeight} (cap = ${MAX_CANVAS_PX}px).`,\n );\n }\n if (canvas.width === targetWidth && canvas.height === targetHeight)\n return;\n\n const pad = signaturePadRef.current;\n const prior = pad ? pad.toData() : null;\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) ctx.scale(dpr, dpr);\n if (pad) {\n if (resolvedBg) pad.backgroundColor = resolvedBg;\n if (resolvedPen) pad.penColor = resolvedPen;\n pad.clear();\n if (prior && prior.length > 0) {\n pad.fromData(prior);\n }\n }\n },\n [resolvedBg, resolvedPen],\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n if (typeof ResizeObserver === 'undefined') {\n scaleCanvas(canvas);\n return undefined;\n }\n const ro = new ResizeObserver(() => {\n scaleCanvas(canvas);\n });\n ro.observe(canvas);\n return () => ro.disconnect();\n }, [scaleCanvas]);\n\n /* ---- Imperative handle -------------------------------------- */\n const clear = useCallback(() => {\n const pad = signaturePadRef.current;\n if (pad) pad.clear();\n setTypedValue('');\n setPadHasInk(false);\n announce('cleared');\n onClearRef.current?.();\n }, [announce]);\n\n const undo = useCallback(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n const data = pad.toData();\n if (!data || data.length === 0) return;\n data.pop();\n pad.fromData(data);\n if (data.length === 0) {\n setPadHasInk(false);\n announce('empty');\n }\n }, [announce]);\n\n const isEmpty = useCallback((): boolean => {\n if (mode === 'typed') return typedValue.trim().length === 0;\n const pad = signaturePadRef.current;\n return pad ? pad.isEmpty() : true;\n }, [mode, typedValue]);\n\n const confirm =\n useCallback(async (): Promise<SignatureConfirmPayload | null> => {\n // parsePxValue returns null for \"100%\" / \"50vw\" etc. — fall back\n // to the live rendered rect so widthMm reflects reality, not a\n // mis-parsed parseFloat(\"100%\") = 100.\n const widthParsed = parsePxValue(\n typeof width === 'number' ? `${width}` : String(width),\n );\n const heightParsed = parsePxValue(\n typeof height === 'number' ? `${height}` : String(height),\n );\n const measureEl =\n mode === 'draw'\n ? (canvasRef.current ?? padFrameRef.current ?? wrapperRef.current)\n : (typedPreviewRef.current ?? wrapperRef.current);\n const measuredRect = measureEl?.getBoundingClientRect();\n const cssWidth =\n widthParsed ?? (measuredRect ? measuredRect.width : 400);\n const cssHeight =\n heightParsed ?? (measuredRect ? measuredRect.height : 200);\n\n let pngDataUrl = '';\n let svgString = '';\n let strokes: PointGroup[] | undefined;\n\n if (mode === 'draw') {\n const pad = signaturePadRef.current;\n if (!pad || pad.isEmpty()) return null;\n pngDataUrl = pad.toDataURL('image/png');\n svgString = pad.toSVG();\n strokes = pad.toData();\n } else {\n const value = typedValue.trim();\n if (value.length === 0) return null;\n const offscreen = renderTypedSignatureToCanvas(\n value,\n cssWidth,\n cssHeight,\n resolvedPen || 'currentColor',\n resolvedBg || 'transparent',\n );\n pngDataUrl = offscreen.toDataURL('image/png');\n // Inline SVG — we can't call toSVG() because signature_pad isn't\n // driving the canvas. Build a minimal SVG with the rendered text.\n const safeText = value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n svgString =\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${cssWidth} ${cssHeight}\" width=\"${cssWidth}\" height=\"${cssHeight}\">` +\n `<text x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"sans-serif\" font-style=\"italic\" font-size=\"32\" fill=\"${resolvedPen || 'currentColor'}\" letter-spacing=\"3\">${safeText}</text>` +\n `</svg>`;\n }\n\n // 96 CSS px = 25.4 mm (per W3C CSS absolute length definition).\n const widthMm = (cssWidth * 25.4) / 96;\n const heightMm = (cssHeight * 25.4) / 96;\n const capturedAt = new Date().toISOString();\n\n // Compute SHA-256 of the PNG bytes.\n let sha256 = '';\n if (pngDataUrl) {\n const commaIx = pngDataUrl.indexOf(',');\n const b64 = commaIx >= 0 ? pngDataUrl.slice(commaIx + 1) : '';\n const bytes = base64ToBytes(b64);\n sha256 = await sha256Hex(bytes);\n }\n\n const payload: SignatureConfirmPayload = {\n png: pngDataUrl,\n svg: svgString,\n widthMm,\n heightMm,\n capturedAt,\n sha256,\n strokes,\n };\n\n announce('captured');\n onConfirmRef.current?.(payload);\n return payload;\n }, [mode, typedValue, width, height, resolvedPen, resolvedBg, announce]);\n\n const agentHandle = useMemo<SignatureCaptureHandle>(\n () => ({\n clear,\n undo,\n isEmpty,\n confirm,\n }),\n [clear, undo, isEmpty, confirm],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n useAgentRegistration(signatureCaptureAgent, agentHandle, id);\n\n /* ---- Derived UI state --------------------------------------- */\n // Gate Confirm on React state, not the signature_pad ref — its\n // isEmpty() doesn't trigger re-renders, leaving the button stale.\n const hasContent =\n mode === 'typed' ? typedValue.trim().length > 0 : padHasInk;\n const confirmDisabled = disabled || !hasContent;\n // Inline style — permitted per 23-constraints §Runtime-computed\n // dimensions (CSS custom property setter for dynamic width/height\n // from consumer props; the width rule lives in Tailwind arbitrary\n // values that read --signature-width / --signature-height).\n const sizeStyle: CSSProperties = {\n ['--signature-width' as unknown as keyof CSSProperties]: toCssSize(\n width,\n 'var(--signature-default-width)',\n ),\n ['--signature-height' as unknown as keyof CSSProperties]: toCssSize(\n height,\n 'var(--signature-default-height)',\n ),\n } as CSSProperties;\n\n /* ---- Render -------------------------------------------------- */\n return (\n <div\n ref={wrapperRef}\n role=\"group\"\n aria-label={ariaLabel ?? t('signature.padLabel')}\n aria-disabled={disabled || undefined}\n className={[wrapperVariants(), className].filter(Boolean).join(' ')}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed pad dimensions\n style={sizeStyle}\n data-component=\"signature-capture\"\n data-component-id={id}\n >\n {mode === 'draw' ? (\n <div ref={padFrameRef} className={padFrameVariants()}>\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={t('signature.padLabel')}\n className={canvasVariants()}\n data-testid=\"signature-canvas\"\n />\n </div>\n ) : (\n <label className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-body-sm ds:text-[var(--muted-foreground)]\">\n {t('signature.typedFallback.label')}\n </span>\n <input\n type=\"text\"\n value={typedValue}\n onChange={(e) => {\n setTypedValue(e.target.value);\n if (e.target.value.length > 0) announce('drawing');\n else announce('empty');\n }}\n placeholder={t('signature.typedFallback.placeholder')}\n aria-label={t('signature.typedFallback.label')}\n disabled={disabled}\n className={typedInputVariants()}\n data-testid=\"signature-typed-input\"\n />\n {typedValue ? (\n <div\n ref={typedPreviewRef}\n className={typedPreviewVariants()}\n aria-hidden=\"true\"\n >\n {typedValue}\n </div>\n ) : null}\n </label>\n )}\n\n {/* Live region — state transitions (empty, drawing, captured, cleared) */}\n <div\n id={liveRegionId}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n data-testid=\"signature-live\"\n >\n {announcement}\n </div>\n\n <div\n className={toolbarVariants()}\n role=\"group\"\n aria-label={t('signature.padLabel')}\n >\n <button\n type=\"button\"\n onClick={() => {\n if (disabled) return;\n clear();\n }}\n aria-disabled={disabled || undefined}\n className={actionButtonVariants()}\n >\n {t('signature.clear')}\n </button>\n {allowTypedFallback ? (\n <button\n type=\"button\"\n onClick={() => {\n if (disabled) return;\n setTypedValue('');\n setMode((m) => (m === 'draw' ? 'typed' : 'draw'));\n announce('cleared');\n }}\n aria-disabled={disabled || undefined}\n className={actionButtonVariants()}\n aria-pressed={mode === 'typed'}\n >\n {mode === 'draw'\n ? t('signature.typedFallback.toggle')\n : t('signature.typedFallback.toggleDraw')}\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => {\n if (confirmDisabled) return;\n void confirm();\n }}\n aria-disabled={confirmDisabled || undefined}\n aria-describedby={liveRegionId}\n className={confirmButtonVariants()}\n data-testid=\"signature-confirm\"\n >\n {t('signature.confirm')}\n </button>\n </div>\n </div>\n );\n },\n);\n\nSignatureCapture.displayName = 'SignatureCapture';\n\nexport {\n wrapperVariants as signatureWrapperVariants,\n actionButtonVariants as signatureActionButtonVariants,\n confirmButtonVariants as signatureConfirmButtonVariants,\n};\n"],"names":["signatureCaptureAgent","handle","wrapperVariants","cva","padFrameVariants","canvasVariants","toolbarVariants","actionButtonVariants","confirmButtonVariants","typedInputVariants","typedPreviewVariants","resolveCssVar","name","toCssSize","v","fallback","parsePxValue","toHex","bytes","out","i","b","base64ToBytes","b64","bin","g","sha256Hex","_a","copy","digest","renderTypedSignatureToCanvas","text","cssWidth","cssHeight","penColor","backgroundColor","dpr","canvas","ctx","SignatureCapture","forwardRef","id","onConfirm","onClear","onStart","width","height","allowTypedFallback","disabled","ariaLabel","className","ref","t","useTranslation","rawId","useId","liveRegionId","useMemo","wrapperRef","useRef","padFrameRef","canvasRef","typedPreviewRef","signaturePadRef","mode","setMode","useState","typedValue","setTypedValue","padHasInk","setPadHasInk","signatureStateRef","announcement","setAnnouncement","resolvedPen","setResolvedPen","resolvedBg","setResolvedBg","onStartRef","onClearRef","onConfirmRef","useEffect","announce","useCallback","next","resolveAll","pen","bg","mo","pad","SignaturePad","handleBegin","handleEnd","scaleCanvas","MAX_CANVAS_PX","rect","rawWidth","rawHeight","targetWidth","targetHeight","prior","ro","clear","undo","data","isEmpty","confirm","widthParsed","heightParsed","measureEl","measuredRect","pngDataUrl","svgString","strokes","value","safeText","widthMm","heightMm","capturedAt","sha256","commaIx","payload","agentHandle","useImperativeHandle","useAgentRegistration","hasContent","confirmDisabled","sizeStyle","jsxs","jsx","m"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"signature-capture-CpMBhqQ9.js","sources":["../../src/components/signature-capture/signature-capture.agent.ts","../../src/components/signature-capture/signature-capture.tsx"],"sourcesContent":["import type { AgentAdapter } from '../../agent/types';\nimport type { SignatureCaptureHandle } from './signature-capture';\n\nexport const signatureCaptureAgent: AgentAdapter<SignatureCaptureHandle> = {\n id: 'signature-capture',\n capabilities: ['edit_inline', 'submit'],\n state: {\n isEmpty: {\n type: 'boolean',\n description: 'True when no signature has been drawn or typed.',\n read: (handle) => handle.isEmpty(),\n },\n },\n actions: {\n clear: {\n safety: 'destructive',\n description: 'Erase the current signature. Loses unsaved input.',\n invoke: (handle) => {\n handle.clear();\n },\n },\n undo: {\n safety: 'write',\n description: 'Undo the last stroke.',\n invoke: (handle) => {\n handle.undo();\n },\n },\n confirm: {\n safety: 'write',\n description: 'Commit the signature and return its serialised payload.',\n invoke: (handle) => handle.confirm(),\n },\n },\n domHooks: {\n root: { attr: 'data-component', value: 'signature-capture' },\n instanceId: {\n attr: 'data-component-id',\n sourceProp: 'id',\n description: 'Sourced from the id prop.',\n },\n },\n};\n","/* ------------------------------------------------------------------ */\n/* SignatureCapture — thin React wrapper over signature_pad. */\n/* */\n/* - Library: `signature_pad` (08-third-party §Signature Pad). We */\n/* instantiate one pad per mounted canvas and expose imperative */\n/* clear / undo / isEmpty / confirm verbs to the consumer. */\n/* - Colors: `penColor` / `backgroundColor` default to */\n/* `--foreground` / `--background` via `getComputedStyle()`. Theme */\n/* switches are observed via a MutationObserver on `<html class>` */\n/* so the ink recolours when the theme flips. */\n/* - DPR scaling: canvas attribute `width/height = cssSize * DPR`; the */\n/* 2D context is scaled by the same factor. A `ResizeObserver` */\n/* replays strokes via `fromData()` on re-scale so nothing is lost. */\n/* - Typed fallback: keyboard-only path renders a text input styled in */\n/* italic `var(--font-sans)` (per 23-constraints §10 — serif is */\n/* marketing only). On confirm we render the string to an offscreen */\n/* canvas for the PNG/SVG export. */\n/* - Confirm payload: `{ png, svg, widthMm, heightMm, capturedAt, */\n/* sha256, strokes? }`. `sha256` is the SubtleCrypto digest of the */\n/* PNG bytes — tamper-evident for audit trails. */\n/* - Security: no `fetch` / `XMLHttpRequest` / `localStorage` / */\n/* `sessionStorage` in this file — the consumer owns persistence. */\n/* */\n/* TODO: */\n/* - 3× DPI re-render for print: currently `toDataURL('image/png')` */\n/* exports the live canvas (already at DPR). A proper 300-DPI */\n/* pipeline would create an offscreen canvas at `cssSize × 3` and */\n/* replay strokes via `fromData()` — deferred pending the print */\n/* bridge landing. */\n/* - Typed-fallback canvas font can't read CSS variables directly */\n/* (Canvas2D resolves fonts at paint time and won't expand */\n/* `var(--font-size-2xl)`); we use a fixed `32px italic` + the */\n/* user's font stack, which is visually close but not */\n/* theme-reactive. Will migrate once the typography tokens expose */\n/* a resolved `font` shorthand. */\n/* ------------------------------------------------------------------ */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\nimport SignaturePad from 'signature_pad';\nimport type { PointGroup } from 'signature_pad';\nimport { cva } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { signatureCaptureAgent } from './signature-capture.agent';\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport interface SignatureConfirmPayload {\n /** Data URL of the captured signature rendered as PNG. */\n png: string;\n /** SVG string trimmed to the stroke bounding box. */\n svg: string;\n /** Physical width in millimetres, derived from CSS px. */\n widthMm: number;\n /** Physical height in millimetres, derived from CSS px. */\n heightMm: number;\n /** ISO-8601 UTC timestamp for when `confirm()` resolved. */\n capturedAt: string;\n /** Hex-encoded SHA-256 digest of the PNG bytes. */\n sha256: string;\n /** Raw stroke data from `signature_pad.toData()` — optional for replays. */\n strokes?: PointGroup[];\n}\n\nexport interface SignatureCaptureProps {\n /** Opaque instance id — emitted as `data-component-id` for the agent registry. */\n id?: string;\n /** Called with the export payload when the user confirms the signature. */\n onConfirm?: (payload: SignatureConfirmPayload) => void;\n /** Called after the pad is cleared (explicit user action). */\n onClear?: () => void;\n /** Called when the user starts drawing a new stroke. */\n onStart?: () => void;\n /** CSS width of the pad. Default 400. */\n width?: number | string;\n /** CSS height of the pad. Default 200. */\n height?: number | string;\n /** Pen colour override — defaults to `var(--foreground)`. */\n penColor?: string;\n /** Background override — defaults to `var(--background)`. */\n backgroundColor?: string;\n /** Show the typed-name fallback toggle. Default `true`. */\n allowTypedFallback?: boolean;\n /** Disable the entire component. */\n disabled?: boolean;\n /** Accessible label for the pad region. */\n ariaLabel?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n}\n\nexport interface SignatureCaptureHandle {\n clear: () => void;\n undo: () => void;\n isEmpty: () => boolean;\n confirm: () => Promise<SignatureConfirmPayload | null>;\n}\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva(\n [\n 'ds:signature-capture-alfadocs ds:flex ds:flex-col',\n 'ds:gap-[var(--spacing-sm)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:rounded-[var(--radius-md)] ds:border ds:border-[color:var(--card-border)]',\n 'ds:shadow-[var(--shadow-card)]',\n 'ds:[.theme-accessible_&]:border-2',\n 'ds:p-[var(--spacing-sm)]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst padFrameVariants = cva(\n [\n 'ds:relative ds:block',\n 'ds:inline-size-[var(--signature-width)]',\n 'ds:block-size-[var(--signature-height)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)]',\n 'ds:overflow-hidden',\n 'ds:touch-none',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\nconst canvasVariants = cva(\n [\n 'ds:block',\n 'ds:inline-size-full',\n 'ds:block-size-full',\n 'ds:touch-none',\n 'ds:select-none',\n ].join(' '),\n);\n\nconst toolbarVariants = cva(\n ['ds:flex ds:items-stretch ds:flex-wrap ds:gap-[var(--spacing-sm)]'].join(\n ' ',\n ),\n);\n\n// Toolbar actions are sized for thumbs: they grow to fill the pad width\n// (`flex-1`), sit above the 44/48px floor, and use base-size text so they read\n// clearly on a phone.\nconst actionButtonVariants = cva(\n [\n 'ds:inline-flex ds:flex-1 ds:items-center ds:justify-center',\n 'ds:[min-block-size:var(--min-target-size)]',\n 'ds:[min-inline-size:var(--min-target-size)]',\n 'ds:gap-[var(--spacing-xs)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-transparent ds:text-[var(--foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--muted)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst confirmButtonVariants = cva(\n [\n 'ds:inline-flex ds:flex-1 ds:items-center ds:justify-center',\n 'ds:[min-block-size:var(--min-target-size)]',\n 'ds:[min-inline-size:var(--min-target-size)]',\n 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n 'ds:pt-[var(--spacing-md)] ds:pb-[var(--spacing-md)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:bg-[var(--primary)] ds:text-[var(--primary-foreground)]',\n 'ds:text-[length:var(--font-size-base)] ds:font-medium',\n 'ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none',\n 'ds:hover:bg-[var(--primary-hover)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n 'ds:aria-disabled:opacity-[var(--opacity-50)] ds:aria-disabled:cursor-not-allowed',\n ].join(' '),\n);\n\nconst typedInputVariants = cva(\n [\n 'ds:block ds:inline-size-full',\n 'ds:[min-block-size:var(--min-target-size)]',\n 'ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--border)]',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:font-[family-name:var(--font-sans)]',\n 'ds:italic',\n 'ds:tracking-[0.1em]',\n 'ds:text-[length:var(--font-size-lg)]',\n 'ds:focus-visible:outline-[length:var(--focus-ring-width)]',\n 'ds:focus-visible:outline-solid',\n 'ds:focus-visible:outline-[var(--ring)]',\n 'ds:forced-colors:focus-visible:outline-[CanvasText]',\n ].join(' '),\n);\n\nconst typedPreviewVariants = cva(\n [\n 'ds:flex ds:items-center ds:justify-center',\n 'ds:inline-size-[var(--signature-width)]',\n 'ds:block-size-[var(--signature-height)]',\n 'ds:rounded-[var(--radius-sm)]',\n 'ds:border ds:border-[color:var(--card-border)]',\n 'ds:[.theme-accessible_&]:border-2',\n 'ds:bg-[var(--background)] ds:text-[var(--foreground)]',\n 'ds:font-[family-name:var(--font-sans)]',\n 'ds:italic',\n 'ds:tracking-[0.1em]',\n 'ds:text-[length:var(--font-size-2xl)]',\n 'ds:p-[var(--spacing-md)]',\n ].join(' '),\n);\n\n/* ------------------------------------------------------------------ */\n/* Helpers */\n/* ------------------------------------------------------------------ */\n\ntype SignatureState = 'empty' | 'drawing' | 'captured' | 'cleared';\n\n/**\n * Resolve a CSS custom property against `document.documentElement`. We\n * can't pass `var(--foreground)` to signature_pad directly — the lib\n * stamps the string straight into `ctx.strokeStyle`, which only accepts\n * concrete colour values. Looking the variable up at runtime keeps the\n * component in tokens-only compliance.\n */\nfunction resolveCssVar(name: string): string {\n if (typeof document === 'undefined') return '';\n const value = getComputedStyle(document.documentElement)\n .getPropertyValue(name)\n .trim();\n return value;\n}\n\nfunction toCssSize(v: number | string | undefined, fallback: string): string {\n if (typeof v === 'number') return `${v}px`;\n if (typeof v === 'string' && v.length > 0) return v;\n return fallback;\n}\n\n/**\n * Parse a pixel value, returning `null` for non-pixel strings (e.g.\n * \"100%\", \"50vw\") so the caller can fall back to the measured rect.\n * parseFloat(\"100%\") would silently return 100 — a 100mm-wide export\n * masquerading as 26mm. Allow only digits, dot, minus, whitespace, \"px\".\n */\nfunction parsePxValue(v: string): number | null {\n if (typeof v === 'string' && /[^0-9.\\s\\-px]/i.test(v)) return null;\n const n = parseFloat(v);\n if (!Number.isFinite(n)) return null;\n return n;\n}\n\n/** Hex-encode a Uint8Array. */\nfunction toHex(bytes: Uint8Array): string {\n let out = '';\n for (let i = 0; i < bytes.length; i += 1) {\n const b = bytes[i];\n out += b.toString(16).padStart(2, '0');\n }\n return out;\n}\n\n/** Decode a base64 string into bytes without `atob` polyfills. */\nfunction base64ToBytes(b64: string): Uint8Array {\n if (typeof atob === 'function') {\n const bin = atob(b64);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) bytes[i] = bin.charCodeAt(i);\n return bytes;\n }\n // Fallback — node-style Buffer, gated behind a runtime check.\n const g = globalThis as {\n Buffer?: { from: (s: string, enc: string) => Uint8Array };\n };\n if (g.Buffer) return g.Buffer.from(b64, 'base64');\n return new Uint8Array();\n}\n\nasync function sha256Hex(bytes: Uint8Array): Promise<string> {\n const g = globalThis as { crypto?: Crypto };\n if (g.crypto?.subtle) {\n // Copy the bytes into a fresh ArrayBuffer so the slice is always an\n // ArrayBuffer (never a SharedArrayBuffer) — SubtleCrypto's BufferSource\n // narrowing doesn't accept the latter.\n const copy = new Uint8Array(bytes.byteLength);\n copy.set(bytes);\n const digest = await g.crypto.subtle.digest('SHA-256', copy.buffer);\n return toHex(new Uint8Array(digest));\n }\n // No subtle crypto — return empty so callers can still use the rest\n // of the payload. Test env is expected to stub crypto.subtle.\n return '';\n}\n\n/**\n * Render the typed fallback string onto an offscreen canvas and return\n * it. Used by the confirm path when the user has typed their name\n * instead of drawing. Size is fixed at `32px italic` because Canvas2D\n * resolves fonts eagerly and can't expand `var(--font-size-*)`.\n */\nfunction renderTypedSignatureToCanvas(\n text: string,\n cssWidth: number,\n cssHeight: number,\n penColor: string,\n backgroundColor: string,\n): HTMLCanvasElement {\n const dpr = Math.max(\n 1,\n typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n );\n const canvas = document.createElement('canvas');\n canvas.width = Math.floor(cssWidth * dpr);\n canvas.height = Math.floor(cssHeight * dpr);\n const ctx = canvas.getContext('2d');\n if (!ctx) return canvas;\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n // Fill background with the token-resolved colour.\n ctx.fillStyle = backgroundColor || 'transparent';\n ctx.fillRect(0, 0, cssWidth, cssHeight);\n // Draw the typed signature centred.\n ctx.fillStyle = penColor || 'currentColor';\n ctx.font = '32px italic sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(text, cssWidth / 2, cssHeight / 2, cssWidth - 16);\n return canvas;\n}\n\n/* ------------------------------------------------------------------ */\n/* SignatureCapture */\n/* ------------------------------------------------------------------ */\n\nexport const SignatureCapture = forwardRef<\n SignatureCaptureHandle,\n SignatureCaptureProps\n>(\n (\n {\n id,\n onConfirm,\n onClear,\n onStart,\n width = 400,\n height = 200,\n penColor,\n backgroundColor,\n allowTypedFallback = true,\n disabled = false,\n ariaLabel,\n className,\n },\n ref,\n ) => {\n const { t } = useTranslation();\n const rawId = useId();\n const idSafe = useMemo(\n () => `sig-${rawId.replace(/[^a-zA-Z0-9-_]/g, '')}`,\n [rawId],\n );\n const liveRegionId = `${idSafe}-live`;\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n const padFrameRef = useRef<HTMLDivElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const typedPreviewRef = useRef<HTMLDivElement>(null);\n const signaturePadRef = useRef<SignaturePad | null>(null);\n\n const [mode, setMode] = useState<'draw' | 'typed'>('draw');\n const [typedValue, setTypedValue] = useState('');\n // Tracks whether the pad has any ink — gates the Confirm button.\n // signature_pad's isEmpty() is a sync ref read and won't trigger\n // re-renders; this state mirrors it so React sees the change.\n const [padHasInk, setPadHasInk] = useState(false);\n // Retained state — consumers may subscribe to the pad's lifecycle via\n // `onConfirm`/`onClear`/`onStart`; we still track the machine internally\n // so the live region + confirm button stay coherent.\n const signatureStateRef = useRef<SignatureState>('empty');\n const [announcement, setAnnouncement] = useState<string>('');\n const [resolvedPen, setResolvedPen] = useState<string>('');\n const [resolvedBg, setResolvedBg] = useState<string>('');\n\n // Stable callback refs so we can wire signature_pad once without\n // re-instantiating on every render.\n const onStartRef = useRef<SignatureCaptureProps['onStart']>(onStart);\n const onClearRef = useRef<SignatureCaptureProps['onClear']>(onClear);\n const onConfirmRef = useRef<SignatureCaptureProps['onConfirm']>(onConfirm);\n useEffect(() => {\n onStartRef.current = onStart;\n onClearRef.current = onClear;\n onConfirmRef.current = onConfirm;\n }, [onStart, onClear, onConfirm]);\n\n /* ---- Announce helper ---------------------------------------- */\n const announce = useCallback(\n (next: SignatureState) => {\n signatureStateRef.current = next;\n setAnnouncement(t(`signature.state.${next}`));\n },\n [t],\n );\n\n /* ---- Resolve tokens ----------------------------------------- */\n useEffect(() => {\n if (typeof document === 'undefined') return undefined;\n function resolveAll(): void {\n const pen = penColor ?? resolveCssVar('--foreground');\n const bg = backgroundColor ?? resolveCssVar('--background');\n // Fall back to `currentColor` / `transparent` — keyword literals\n // are token-neutral and honour the surrounding theme even when\n // the CSS variable is briefly unavailable (SSR, initial paint).\n setResolvedPen(pen || 'currentColor');\n setResolvedBg(bg || 'transparent');\n }\n resolveAll();\n // Watch for theme-class changes on <html>.\n const mo = new MutationObserver(() => {\n resolveAll();\n });\n mo.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n });\n return () => mo.disconnect();\n }, [penColor, backgroundColor]);\n\n /* ---- Apply colour changes to an existing pad ---------------- */\n useEffect(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n if (resolvedPen) pad.penColor = resolvedPen;\n if (resolvedBg) pad.backgroundColor = resolvedBg;\n }, [resolvedPen, resolvedBg]);\n\n /* ---- Instantiate signature_pad ------------------------------ */\n useEffect(() => {\n if (mode !== 'draw') return undefined;\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n\n const pad = new SignaturePad(canvas, {\n penColor: resolvedPen || 'currentColor',\n backgroundColor: resolvedBg || 'transparent',\n minWidth: 0.5,\n maxWidth: 2.5,\n velocityFilterWeight: 0.7,\n });\n signaturePadRef.current = pad;\n\n const handleBegin = (): void => {\n setPadHasInk(true);\n announce('drawing');\n onStartRef.current?.();\n };\n const handleEnd = (): void => {\n // Keep state as 'drawing' — transition to 'captured' on confirm.\n };\n pad.addEventListener('beginStroke', handleBegin);\n pad.addEventListener('endStroke', handleEnd);\n\n // Initial DPR scale + announcement.\n scaleCanvas(canvas);\n announce('empty');\n\n return () => {\n pad.removeEventListener('beginStroke', handleBegin);\n pad.removeEventListener('endStroke', handleEnd);\n // Clear strokes from memory; 08-third-party §Signature Pad.\n pad.clear();\n pad.off();\n signaturePadRef.current = null;\n };\n // We intentionally re-create the pad only when switching between\n // typed and draw modes. Color updates flow through the effect above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mode]);\n\n /* ---- Disabled state ----------------------------------------- */\n useEffect(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n if (disabled) pad.off();\n else pad.on();\n }, [disabled, mode]);\n\n /* ---- DPR + ResizeObserver ----------------------------------- */\n // Hard-cap backing-store dimensions to bound memory. 4096 px × 4096 px at\n // 4 bytes per pixel is ~67 MB — generous for any realistic signature, but\n // well under the multi-GB allocation a careless or malicious prop could\n // request on a high-DPR display. See security-hardening.mdx.\n const MAX_CANVAS_PX = 4096;\n const scaleCanvas = useCallback(\n (canvas: HTMLCanvasElement) => {\n const rect = canvas.getBoundingClientRect();\n const dpr = Math.max(\n 1,\n typeof window !== 'undefined' ? window.devicePixelRatio : 1,\n );\n const rawWidth = Math.max(1, Math.floor(rect.width * dpr));\n const rawHeight = Math.max(1, Math.floor(rect.height * dpr));\n const targetWidth = Math.min(rawWidth, MAX_CANVAS_PX);\n const targetHeight = Math.min(rawHeight, MAX_CANVAS_PX);\n if (\n import.meta.env.DEV &&\n (rawWidth !== targetWidth || rawHeight !== targetHeight)\n ) {\n // Silent in production; a consumer shipping 10k × 10k probably wants\n // the nudge.\n console.warn(\n `[SignatureCapture] clamped canvas backing store from ${rawWidth}x${rawHeight} to ${targetWidth}x${targetHeight} (cap = ${MAX_CANVAS_PX}px).`,\n );\n }\n if (canvas.width === targetWidth && canvas.height === targetHeight)\n return;\n\n const pad = signaturePadRef.current;\n const prior = pad ? pad.toData() : null;\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n const ctx = canvas.getContext('2d');\n if (ctx) ctx.scale(dpr, dpr);\n if (pad) {\n if (resolvedBg) pad.backgroundColor = resolvedBg;\n if (resolvedPen) pad.penColor = resolvedPen;\n pad.clear();\n if (prior && prior.length > 0) {\n pad.fromData(prior);\n }\n }\n },\n [resolvedBg, resolvedPen],\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n if (typeof ResizeObserver === 'undefined') {\n scaleCanvas(canvas);\n return undefined;\n }\n const ro = new ResizeObserver(() => {\n scaleCanvas(canvas);\n });\n ro.observe(canvas);\n return () => ro.disconnect();\n }, [scaleCanvas]);\n\n /* ---- Imperative handle -------------------------------------- */\n const clear = useCallback(() => {\n const pad = signaturePadRef.current;\n if (pad) pad.clear();\n setTypedValue('');\n setPadHasInk(false);\n announce('cleared');\n onClearRef.current?.();\n }, [announce]);\n\n const undo = useCallback(() => {\n const pad = signaturePadRef.current;\n if (!pad) return;\n const data = pad.toData();\n if (!data || data.length === 0) return;\n data.pop();\n pad.fromData(data);\n if (data.length === 0) {\n setPadHasInk(false);\n announce('empty');\n }\n }, [announce]);\n\n const isEmpty = useCallback((): boolean => {\n if (mode === 'typed') return typedValue.trim().length === 0;\n const pad = signaturePadRef.current;\n return pad ? pad.isEmpty() : true;\n }, [mode, typedValue]);\n\n const confirm =\n useCallback(async (): Promise<SignatureConfirmPayload | null> => {\n // parsePxValue returns null for \"100%\" / \"50vw\" etc. — fall back\n // to the live rendered rect so widthMm reflects reality, not a\n // mis-parsed parseFloat(\"100%\") = 100.\n const widthParsed = parsePxValue(\n typeof width === 'number' ? `${width}` : String(width),\n );\n const heightParsed = parsePxValue(\n typeof height === 'number' ? `${height}` : String(height),\n );\n const measureEl =\n mode === 'draw'\n ? (canvasRef.current ?? padFrameRef.current ?? wrapperRef.current)\n : (typedPreviewRef.current ?? wrapperRef.current);\n const measuredRect = measureEl?.getBoundingClientRect();\n const cssWidth =\n widthParsed ?? (measuredRect ? measuredRect.width : 400);\n const cssHeight =\n heightParsed ?? (measuredRect ? measuredRect.height : 200);\n\n let pngDataUrl = '';\n let svgString = '';\n let strokes: PointGroup[] | undefined;\n\n if (mode === 'draw') {\n const pad = signaturePadRef.current;\n if (!pad || pad.isEmpty()) return null;\n pngDataUrl = pad.toDataURL('image/png');\n svgString = pad.toSVG();\n strokes = pad.toData();\n } else {\n const value = typedValue.trim();\n if (value.length === 0) return null;\n const offscreen = renderTypedSignatureToCanvas(\n value,\n cssWidth,\n cssHeight,\n resolvedPen || 'currentColor',\n resolvedBg || 'transparent',\n );\n pngDataUrl = offscreen.toDataURL('image/png');\n // Inline SVG — we can't call toSVG() because signature_pad isn't\n // driving the canvas. Build a minimal SVG with the rendered text.\n const safeText = value\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n svgString =\n `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 ${cssWidth} ${cssHeight}\" width=\"${cssWidth}\" height=\"${cssHeight}\">` +\n `<text x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"sans-serif\" font-style=\"italic\" font-size=\"32\" fill=\"${resolvedPen || 'currentColor'}\" letter-spacing=\"3\">${safeText}</text>` +\n `</svg>`;\n }\n\n // 96 CSS px = 25.4 mm (per W3C CSS absolute length definition).\n const widthMm = (cssWidth * 25.4) / 96;\n const heightMm = (cssHeight * 25.4) / 96;\n const capturedAt = new Date().toISOString();\n\n // Compute SHA-256 of the PNG bytes.\n let sha256 = '';\n if (pngDataUrl) {\n const commaIx = pngDataUrl.indexOf(',');\n const b64 = commaIx >= 0 ? pngDataUrl.slice(commaIx + 1) : '';\n const bytes = base64ToBytes(b64);\n sha256 = await sha256Hex(bytes);\n }\n\n const payload: SignatureConfirmPayload = {\n png: pngDataUrl,\n svg: svgString,\n widthMm,\n heightMm,\n capturedAt,\n sha256,\n strokes,\n };\n\n announce('captured');\n onConfirmRef.current?.(payload);\n return payload;\n }, [mode, typedValue, width, height, resolvedPen, resolvedBg, announce]);\n\n const agentHandle = useMemo<SignatureCaptureHandle>(\n () => ({\n clear,\n undo,\n isEmpty,\n confirm,\n }),\n [clear, undo, isEmpty, confirm],\n );\n useImperativeHandle(ref, () => agentHandle, [agentHandle]);\n useAgentRegistration(signatureCaptureAgent, agentHandle, id);\n\n /* ---- Derived UI state --------------------------------------- */\n // Gate Confirm on React state, not the signature_pad ref — its\n // isEmpty() doesn't trigger re-renders, leaving the button stale.\n const hasContent =\n mode === 'typed' ? typedValue.trim().length > 0 : padHasInk;\n const confirmDisabled = disabled || !hasContent;\n // Inline style — permitted per 23-constraints §Runtime-computed\n // dimensions (CSS custom property setter for dynamic width/height\n // from consumer props; the width rule lives in Tailwind arbitrary\n // values that read --signature-width / --signature-height).\n const sizeStyle: CSSProperties = {\n ['--signature-width' as unknown as keyof CSSProperties]: toCssSize(\n width,\n 'var(--signature-default-width)',\n ),\n ['--signature-height' as unknown as keyof CSSProperties]: toCssSize(\n height,\n 'var(--signature-default-height)',\n ),\n } as CSSProperties;\n\n /* ---- Render -------------------------------------------------- */\n return (\n <div\n ref={wrapperRef}\n role=\"group\"\n aria-label={ariaLabel ?? t('signature.padLabel')}\n aria-disabled={disabled || undefined}\n className={[wrapperVariants(), className].filter(Boolean).join(' ')}\n // eslint-disable-next-line react/forbid-dom-props -- runtime-computed pad dimensions\n style={sizeStyle}\n data-component=\"signature-capture\"\n data-component-id={id}\n >\n {mode === 'draw' ? (\n <div ref={padFrameRef} className={padFrameVariants()}>\n <canvas\n ref={canvasRef}\n role=\"img\"\n aria-label={t('signature.padLabel')}\n className={canvasVariants()}\n data-testid=\"signature-canvas\"\n />\n </div>\n ) : (\n <label className=\"ds:flex ds:flex-col ds:gap-[var(--spacing-xs)]\">\n <span className=\"type-body-sm ds:text-[var(--muted-foreground)]\">\n {t('signature.typedFallback.label')}\n </span>\n <input\n type=\"text\"\n value={typedValue}\n onChange={(e) => {\n setTypedValue(e.target.value);\n if (e.target.value.length > 0) announce('drawing');\n else announce('empty');\n }}\n placeholder={t('signature.typedFallback.placeholder')}\n aria-label={t('signature.typedFallback.label')}\n disabled={disabled}\n className={typedInputVariants()}\n data-testid=\"signature-typed-input\"\n />\n {typedValue ? (\n <div\n ref={typedPreviewRef}\n className={typedPreviewVariants()}\n aria-hidden=\"true\"\n >\n {typedValue}\n </div>\n ) : null}\n </label>\n )}\n\n {/* Live region — state transitions (empty, drawing, captured, cleared) */}\n <div\n id={liveRegionId}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"ds:sr-only\"\n data-testid=\"signature-live\"\n >\n {announcement}\n </div>\n\n <div\n className={toolbarVariants()}\n role=\"group\"\n aria-label={t('signature.padLabel')}\n >\n <button\n type=\"button\"\n onClick={() => {\n if (disabled) return;\n clear();\n }}\n aria-disabled={disabled || undefined}\n className={actionButtonVariants()}\n >\n {t('signature.clear')}\n </button>\n {allowTypedFallback ? (\n <button\n type=\"button\"\n onClick={() => {\n if (disabled) return;\n setTypedValue('');\n setMode((m) => (m === 'draw' ? 'typed' : 'draw'));\n announce('cleared');\n }}\n aria-disabled={disabled || undefined}\n className={actionButtonVariants()}\n aria-pressed={mode === 'typed'}\n >\n {mode === 'draw'\n ? t('signature.typedFallback.toggle')\n : t('signature.typedFallback.toggleDraw')}\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={() => {\n if (confirmDisabled) return;\n void confirm();\n }}\n aria-disabled={confirmDisabled || undefined}\n aria-describedby={liveRegionId}\n className={confirmButtonVariants()}\n data-testid=\"signature-confirm\"\n >\n {t('signature.confirm')}\n </button>\n </div>\n </div>\n );\n },\n);\n\nSignatureCapture.displayName = 'SignatureCapture';\n\nexport {\n wrapperVariants as signatureWrapperVariants,\n actionButtonVariants as signatureActionButtonVariants,\n confirmButtonVariants as signatureConfirmButtonVariants,\n};\n"],"names":["signatureCaptureAgent","handle","wrapperVariants","cva","padFrameVariants","canvasVariants","toolbarVariants","actionButtonVariants","confirmButtonVariants","typedInputVariants","typedPreviewVariants","resolveCssVar","name","toCssSize","v","fallback","parsePxValue","toHex","bytes","out","i","b","base64ToBytes","b64","bin","g","sha256Hex","_a","copy","digest","renderTypedSignatureToCanvas","text","cssWidth","cssHeight","penColor","backgroundColor","dpr","canvas","ctx","SignatureCapture","forwardRef","id","onConfirm","onClear","onStart","width","height","allowTypedFallback","disabled","ariaLabel","className","ref","t","useTranslation","rawId","useId","liveRegionId","useMemo","wrapperRef","useRef","padFrameRef","canvasRef","typedPreviewRef","signaturePadRef","mode","setMode","useState","typedValue","setTypedValue","padHasInk","setPadHasInk","signatureStateRef","announcement","setAnnouncement","resolvedPen","setResolvedPen","resolvedBg","setResolvedBg","onStartRef","onClearRef","onConfirmRef","useEffect","announce","useCallback","next","resolveAll","pen","bg","mo","pad","SignaturePad","handleBegin","handleEnd","scaleCanvas","MAX_CANVAS_PX","rect","rawWidth","rawHeight","targetWidth","targetHeight","prior","ro","clear","undo","data","isEmpty","confirm","widthParsed","heightParsed","measureEl","measuredRect","pngDataUrl","svgString","strokes","value","safeText","widthMm","heightMm","capturedAt","sha256","commaIx","payload","agentHandle","useImperativeHandle","useAgentRegistration","hasContent","confirmDisabled","sizeStyle","jsxs","jsx","m"],"mappings":";;;;;;AAGO,MAAMA,KAA8D;AAAA,EACzE,IAAI;AAAA,EACJ,cAAc,CAAC,eAAe,QAAQ;AAAA,EACtC,OAAO;AAAA,IACL,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM,CAACC,MAAWA,EAAO,QAAA;AAAA,IAAQ;AAAA,EACnC;AAAA,EAEF,SAAS;AAAA,IACP,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,QAAQ,CAACA,MAAW;AAClB,QAAAA,EAAO,MAAA;AAAA,MACT;AAAA,IAAA;AAAA,IAEF,MAAM;AAAA,MACJ,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,QAAQ,CAACA,MAAW;AAClB,QAAAA,EAAO,KAAA;AAAA,MACT;AAAA,IAAA;AAAA,IAEF,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,QAAQ,CAACA,MAAWA,EAAO,QAAA;AAAA,IAAQ;AAAA,EACrC;AAAA,EAEF,UAAU;AAAA,IACR,MAAM,EAAE,MAAM,kBAAkB,OAAO,oBAAA;AAAA,IACvC,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ,GCwEMC,KAAkBC;AAAA,EACtB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMC,KAAmBD;AAAA,EACvB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEME,KAAiBF;AAAA,EACrB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMG,KAAkBH;AAAA,EACtB,CAAC,kEAAkE,EAAE;AAAA,IACnE;AAAA,EAAA;AAEJ,GAKMI,KAAuBJ;AAAA,EAC3B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMK,KAAwBL;AAAA,EAC5B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMM,KAAqBN;AAAA,EACzB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ,GAEMO,KAAuBP;AAAA,EAC3B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,EACA,KAAK,GAAG;AACZ;AAeA,SAASQ,GAAcC,GAAsB;AAC3C,SAAI,OAAO,WAAa,MAAoB,KAC9B,iBAAiB,SAAS,eAAe,EACpD,iBAAiBA,CAAI,EACrB,KAAA;AAEL;AAEA,SAASC,GAAUC,GAAgCC,GAA0B;AAC3E,SAAI,OAAOD,KAAM,WAAiB,GAAGA,CAAC,OAClC,OAAOA,KAAM,YAAYA,EAAE,SAAS,IAAUA,IAC3CC;AACT;AAQA,SAASC,GAAaF,GAA0B;AAC9C,MAAI,OAAOA,KAAM,YAAY,iBAAiB,KAAKA,CAAC,EAAG,QAAO;AAC9D,QAAM,IAAI,WAAWA,CAAC;AACtB,SAAK,OAAO,SAAS,CAAC,IACf,IADyB;AAElC;AAGA,SAASG,GAAMC,GAA2B;AACxC,MAAIC,IAAM;AACV,WAASC,IAAI,GAAGA,IAAIF,EAAM,QAAQE,KAAK,GAAG;AACxC,UAAMC,IAAIH,EAAME,CAAC;AACjB,IAAAD,KAAOE,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EACvC;AACA,SAAOF;AACT;AAGA,SAASG,GAAcC,GAAyB;AAC9C,MAAI,OAAO,QAAS,YAAY;AAC9B,UAAMC,IAAM,KAAKD,CAAG,GACdL,IAAQ,IAAI,WAAWM,EAAI,MAAM;AACvC,aAASJ,IAAI,GAAGA,IAAII,EAAI,QAAQJ,KAAK,EAAG,CAAAF,EAAME,CAAC,IAAII,EAAI,WAAWJ,CAAC;AACnE,WAAOF;AAAA,EACT;AAEA,QAAMO,IAAI;AAGV,SAAIA,EAAE,SAAeA,EAAE,OAAO,KAAKF,GAAK,QAAQ,IACzC,IAAI,WAAA;AACb;AAEA,eAAeG,GAAUR,GAAoC;;AAC3D,QAAMO,IAAI;AACV,OAAIE,IAAAF,EAAE,WAAF,QAAAE,EAAU,QAAQ;AAIpB,UAAMC,IAAO,IAAI,WAAWV,EAAM,UAAU;AAC5C,IAAAU,EAAK,IAAIV,CAAK;AACd,UAAMW,IAAS,MAAMJ,EAAE,OAAO,OAAO,OAAO,WAAWG,EAAK,MAAM;AAClE,WAAOX,GAAM,IAAI,WAAWY,CAAM,CAAC;AAAA,EACrC;AAGA,SAAO;AACT;AAQA,SAASC,GACPC,GACAC,GACAC,GACAC,GACAC,GACmB;AACnB,QAAMC,IAAM,KAAK;AAAA,IACf;AAAA,IACA,OAAO,SAAW,MAAc,OAAO,mBAAmB;AAAA,EAAA,GAEtDC,IAAS,SAAS,cAAc,QAAQ;AAC9C,EAAAA,EAAO,QAAQ,KAAK,MAAML,IAAWI,CAAG,GACxCC,EAAO,SAAS,KAAK,MAAMJ,IAAYG,CAAG;AAC1C,QAAME,IAAMD,EAAO,WAAW,IAAI;AAClC,SAAKC,MACLA,EAAI,aAAaF,GAAK,GAAG,GAAGA,GAAK,GAAG,CAAC,GAErCE,EAAI,YAAYH,GAChBG,EAAI,SAAS,GAAG,GAAGN,GAAUC,CAAS,GAEtCK,EAAI,YAAYJ,GAChBI,EAAI,OAAO,0BACXA,EAAI,YAAY,UAChBA,EAAI,eAAe,UACnBA,EAAI,SAASP,GAAMC,IAAW,GAAGC,IAAY,GAAGD,IAAW,EAAE,IACtDK;AACT;AAMO,MAAME,KAAmBC;AAAA,EAI9B,CACE;AAAA,IACE,IAAAC;AAAA,IACA,WAAAC;AAAA,IACA,SAAAC;AAAA,IACA,SAAAC;AAAA,IACA,OAAAC,IAAQ;AAAA,IACR,QAAAC,IAAS;AAAA,IACT,UAAAZ;AAAA,IACA,iBAAAC;AAAA,IACA,oBAAAY,KAAqB;AAAA,IACrB,UAAAC,IAAW;AAAA,IACX,WAAAC;AAAA,IACA,WAAAC;AAAA,EAAA,GAEFC,OACG;AACH,UAAM,EAAE,GAAAC,EAAA,IAAMC,GAAA,GACRC,IAAQC,GAAA,GAKRC,IAAe,GAJNC;AAAA,MACb,MAAM,OAAOH,EAAM,QAAQ,mBAAmB,EAAE,CAAC;AAAA,MACjD,CAACA,CAAK;AAAA,IAAA,CAEsB,SAExBI,IAAaC,EAAuB,IAAI,GACxCC,IAAcD,EAAuB,IAAI,GACzCE,IAAYF,EAA0B,IAAI,GAC1CG,IAAkBH,EAAuB,IAAI,GAC7CI,IAAkBJ,EAA4B,IAAI,GAElD,CAACK,GAAMC,EAAO,IAAIC,EAA2B,MAAM,GACnD,CAACC,GAAYC,CAAa,IAAIF,EAAS,EAAE,GAIzC,CAACG,IAAWC,CAAY,IAAIJ,EAAS,EAAK,GAI1CK,KAAoBZ,EAAuB,OAAO,GAClD,CAACa,IAAcC,EAAe,IAAIP,EAAiB,EAAE,GACrD,CAACQ,GAAaC,EAAc,IAAIT,EAAiB,EAAE,GACnD,CAACU,GAAYC,EAAa,IAAIX,EAAiB,EAAE,GAIjDY,IAAanB,EAAyCf,CAAO,GAC7DmC,IAAapB,EAAyChB,CAAO,GAC7DqC,IAAerB,EAA2CjB,CAAS;AACzE,IAAAuC,EAAU,MAAM;AACd,MAAAH,EAAW,UAAUlC,GACrBmC,EAAW,UAAUpC,GACrBqC,EAAa,UAAUtC;AAAA,IACzB,GAAG,CAACE,GAASD,GAASD,CAAS,CAAC;AAGhC,UAAMwC,IAAWC;AAAA,MACf,CAACC,MAAyB;AACxB,QAAAb,GAAkB,UAAUa,GAC5BX,GAAgBrB,EAAE,mBAAmBgC,CAAI,EAAE,CAAC;AAAA,MAC9C;AAAA,MACA,CAAChC,CAAC;AAAA,IAAA;AAIJ,IAAA6B,EAAU,MAAM;AACd,UAAI,OAAO,WAAa,IAAa;AACrC,eAASI,IAAmB;AAC1B,cAAMC,IAAMpD,KAAYvB,GAAc,cAAc,GAC9C4E,IAAKpD,KAAmBxB,GAAc,cAAc;AAI1D,QAAAgE,GAAeW,KAAO,cAAc,GACpCT,GAAcU,KAAM,aAAa;AAAA,MACnC;AACA,MAAAF,EAAA;AAEA,YAAMG,IAAK,IAAI,iBAAiB,MAAM;AACpC,QAAAH,EAAA;AAAA,MACF,CAAC;AACD,aAAAG,EAAG,QAAQ,SAAS,iBAAiB;AAAA,QACnC,YAAY;AAAA,QACZ,iBAAiB,CAAC,OAAO;AAAA,MAAA,CAC1B,GACM,MAAMA,EAAG,WAAA;AAAA,IAClB,GAAG,CAACtD,GAAUC,CAAe,CAAC,GAG9B8C,EAAU,MAAM;AACd,YAAMQ,IAAM1B,EAAgB;AAC5B,MAAK0B,MACDf,QAAiB,WAAWA,IAC5BE,QAAgB,kBAAkBA;AAAA,IACxC,GAAG,CAACF,GAAaE,CAAU,CAAC,GAG5BK,EAAU,MAAM;AACd,UAAIjB,MAAS,OAAQ;AACrB,YAAM3B,IAASwB,EAAU;AACzB,UAAI,CAACxB,EAAQ;AAEb,YAAMoD,IAAM,IAAIC,GAAarD,GAAQ;AAAA,QACnC,UAAUqC,KAAe;AAAA,QACzB,iBAAiBE,KAAc;AAAA,QAC/B,UAAU;AAAA,QACV,UAAU;AAAA,QACV,sBAAsB;AAAA,MAAA,CACvB;AACD,MAAAb,EAAgB,UAAU0B;AAE1B,YAAME,IAAc,MAAY;;AAC9B,QAAArB,EAAa,EAAI,GACjBY,EAAS,SAAS,IAClBvD,IAAAmD,EAAW,YAAX,QAAAnD,EAAA,KAAAmD;AAAA,MACF,GACMc,IAAY,MAAY;AAAA,MAE9B;AACA,aAAAH,EAAI,iBAAiB,eAAeE,CAAW,GAC/CF,EAAI,iBAAiB,aAAaG,CAAS,GAG3CC,EAAYxD,CAAM,GAClB6C,EAAS,OAAO,GAET,MAAM;AACX,QAAAO,EAAI,oBAAoB,eAAeE,CAAW,GAClDF,EAAI,oBAAoB,aAAaG,CAAS,GAE9CH,EAAI,MAAA,GACJA,EAAI,IAAA,GACJ1B,EAAgB,UAAU;AAAA,MAC5B;AAAA,IAIF,GAAG,CAACC,CAAI,CAAC,GAGTiB,EAAU,MAAM;AACd,YAAMQ,IAAM1B,EAAgB;AAC5B,MAAK0B,MACDzC,MAAc,IAAA,MACT,GAAA;AAAA,IACX,GAAG,CAACA,GAAUgB,CAAI,CAAC;AAOnB,UAAM8B,IAAgB,MAChBD,IAAcV;AAAA,MAClB,CAAC9C,MAA8B;AAC7B,cAAM0D,IAAO1D,EAAO,sBAAA,GACdD,IAAM,KAAK;AAAA,UACf;AAAA,UACA,OAAO,SAAW,MAAc,OAAO,mBAAmB;AAAA,QAAA,GAEtD4D,IAAW,KAAK,IAAI,GAAG,KAAK,MAAMD,EAAK,QAAQ3D,CAAG,CAAC,GACnD6D,IAAY,KAAK,IAAI,GAAG,KAAK,MAAMF,EAAK,SAAS3D,CAAG,CAAC,GACrD8D,IAAc,KAAK,IAAIF,GAAUF,CAAa,GAC9CK,IAAe,KAAK,IAAIF,GAAWH,CAAa;AAWtD,YAAIzD,EAAO,UAAU6D,KAAe7D,EAAO,WAAW8D;AACpD;AAEF,cAAMV,IAAM1B,EAAgB,SACtBqC,IAAQX,IAAMA,EAAI,OAAA,IAAW;AACnC,QAAApD,EAAO,QAAQ6D,GACf7D,EAAO,SAAS8D;AAChB,cAAM7D,IAAMD,EAAO,WAAW,IAAI;AAClC,QAAIC,KAAKA,EAAI,MAAMF,GAAKA,CAAG,GACvBqD,MACEb,QAAgB,kBAAkBA,IAClCF,QAAiB,WAAWA,IAChCe,EAAI,MAAA,GACAW,KAASA,EAAM,SAAS,KAC1BX,EAAI,SAASW,CAAK;AAAA,MAGxB;AAAA,MACA,CAACxB,GAAYF,CAAW;AAAA,IAAA;AAG1B,IAAAO,EAAU,MAAM;AACd,YAAM5C,IAASwB,EAAU;AACzB,UAAI,CAACxB,EAAQ;AACb,UAAI,OAAO,iBAAmB,KAAa;AACzC,QAAAwD,EAAYxD,CAAM;AAClB;AAAA,MACF;AACA,YAAMgE,IAAK,IAAI,eAAe,MAAM;AAClC,QAAAR,EAAYxD,CAAM;AAAA,MACpB,CAAC;AACD,aAAAgE,EAAG,QAAQhE,CAAM,GACV,MAAMgE,EAAG,WAAA;AAAA,IAClB,GAAG,CAACR,CAAW,CAAC;AAGhB,UAAMS,IAAQnB,EAAY,MAAM;;AAC9B,YAAMM,IAAM1B,EAAgB;AAC5B,MAAI0B,OAAS,MAAA,GACbrB,EAAc,EAAE,GAChBE,EAAa,EAAK,GAClBY,EAAS,SAAS,IAClBvD,IAAAoD,EAAW,YAAX,QAAApD,EAAA,KAAAoD;AAAA,IACF,GAAG,CAACG,CAAQ,CAAC,GAEPqB,IAAOpB,EAAY,MAAM;AAC7B,YAAMM,IAAM1B,EAAgB;AAC5B,UAAI,CAAC0B,EAAK;AACV,YAAMe,IAAOf,EAAI,OAAA;AACjB,MAAI,CAACe,KAAQA,EAAK,WAAW,MAC7BA,EAAK,IAAA,GACLf,EAAI,SAASe,CAAI,GACbA,EAAK,WAAW,MAClBlC,EAAa,EAAK,GAClBY,EAAS,OAAO;AAAA,IAEpB,GAAG,CAACA,CAAQ,CAAC,GAEPuB,IAAUtB,EAAY,MAAe;AACzC,UAAInB,MAAS,QAAS,QAAOG,EAAW,KAAA,EAAO,WAAW;AAC1D,YAAMsB,IAAM1B,EAAgB;AAC5B,aAAO0B,IAAMA,EAAI,QAAA,IAAY;AAAA,IAC/B,GAAG,CAACzB,GAAMG,CAAU,CAAC,GAEfuC,IACJvB,EAAY,YAAqD;;AAI/D,YAAMwB,IAAc3F;AAAA,QAClB,OAAO6B,KAAU,WAAW,GAAGA,CAAK,KAAK,OAAOA,CAAK;AAAA,MAAA,GAEjD+D,IAAe5F;AAAA,QACnB,OAAO8B,KAAW,WAAW,GAAGA,CAAM,KAAK,OAAOA,CAAM;AAAA,MAAA,GAEpD+D,IACJ7C,MAAS,SACJH,EAAU,WAAWD,EAAY,WAAWF,EAAW,UACvDI,EAAgB,WAAWJ,EAAW,SACvCoD,IAAeD,KAAA,gBAAAA,EAAW,yBAC1B7E,IACJ2E,MAAgBG,IAAeA,EAAa,QAAQ,MAChD7E,IACJ2E,MAAiBE,IAAeA,EAAa,SAAS;AAExD,UAAIC,IAAa,IACbC,IAAY,IACZC;AAEJ,UAAIjD,MAAS,QAAQ;AACnB,cAAMyB,IAAM1B,EAAgB;AAC5B,YAAI,CAAC0B,KAAOA,EAAI,QAAA,EAAW,QAAO;AAClC,QAAAsB,IAAatB,EAAI,UAAU,WAAW,GACtCuB,IAAYvB,EAAI,MAAA,GAChBwB,IAAUxB,EAAI,OAAA;AAAA,MAChB,OAAO;AACL,cAAMyB,IAAQ/C,EAAW,KAAA;AACzB,YAAI+C,EAAM,WAAW,EAAG,QAAO;AAQ/B,QAAAH,IAPkBjF;AAAA,UAChBoF;AAAA,UACAlF;AAAA,UACAC;AAAA,UACAyC,KAAe;AAAA,UACfE,KAAc;AAAA,QAAA,EAEO,UAAU,WAAW;AAG5C,cAAMuC,IAAWD,EACd,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AACxB,QAAAF,IACE,wDAAwDhF,CAAQ,IAAIC,CAAS,YAAYD,CAAQ,aAAaC,CAAS,6IACoByC,KAAe,cAAc,wBAAwByC,CAAQ;AAAA,MAE5M;AAGA,YAAMC,IAAWpF,IAAW,OAAQ,IAC9BqF,KAAYpF,IAAY,OAAQ,IAChCqF,MAAa,oBAAI,KAAA,GAAO,YAAA;AAG9B,UAAIC,KAAS;AACb,UAAIR,GAAY;AACd,cAAMS,IAAUT,EAAW,QAAQ,GAAG,GAChCxF,KAAMiG,KAAW,IAAIT,EAAW,MAAMS,IAAU,CAAC,IAAI,IACrDtG,IAAQI,GAAcC,EAAG;AAC/B,QAAAgG,KAAS,MAAM7F,GAAUR,CAAK;AAAA,MAChC;AAEA,YAAMuG,KAAmC;AAAA,QACvC,KAAKV;AAAA,QACL,KAAKC;AAAA,QACL,SAAAI;AAAA,QACA,UAAAC;AAAA,QACA,YAAAC;AAAA,QACA,QAAAC;AAAA,QACA,SAAAN;AAAA,MAAA;AAGF,aAAA/B,EAAS,UAAU,IACnBvD,KAAAqD,EAAa,YAAb,QAAArD,GAAA,KAAAqD,GAAuByC,KAChBA;AAAA,IACT,GAAG,CAACzD,GAAMG,GAAYtB,GAAOC,GAAQ4B,GAAaE,GAAYM,CAAQ,CAAC,GAEnEwC,IAAcjE;AAAA,MAClB,OAAO;AAAA,QACL,OAAA6C;AAAA,QACA,MAAAC;AAAA,QACA,SAAAE;AAAA,QACA,SAAAC;AAAA,MAAA;AAAA,MAEF,CAACJ,GAAOC,GAAME,GAASC,CAAO;AAAA,IAAA;AAEhC,IAAAiB,GAAoBxE,IAAK,MAAMuE,GAAa,CAACA,CAAW,CAAC,GACzDE,GAAqB5H,IAAuB0H,GAAajF,CAAE;AAK3D,UAAMoF,KACJ7D,MAAS,UAAUG,EAAW,OAAO,SAAS,IAAIE,IAC9CyD,IAAkB9E,KAAY,CAAC6E,IAK/BE,KAA2B;AAAA,MAC9B,qBAAwDlH;AAAA,QACvDgC;AAAA,QACA;AAAA,MAAA;AAAA,MAED,sBAAyDhC;AAAA,QACxDiC;AAAA,QACA;AAAA,MAAA;AAAA,IACF;AAIF,WACE,gBAAAkF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKtE;AAAA,QACL,MAAK;AAAA,QACL,cAAYT,MAAaG,EAAE,oBAAoB;AAAA,QAC/C,iBAAeJ,KAAY;AAAA,QAC3B,WAAW,CAAC9C,GAAA,GAAmBgD,EAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,QAElE,OAAO6E;AAAA,QACP,kBAAe;AAAA,QACf,qBAAmBtF;AAAA,QAElB,UAAA;AAAA,UAAAuB,MAAS,SACR,gBAAAiE,EAAC,OAAA,EAAI,KAAKrE,GAAa,WAAWxD,MAChC,UAAA,gBAAA6H;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,KAAKpE;AAAA,cACL,MAAK;AAAA,cACL,cAAYT,EAAE,oBAAoB;AAAA,cAClC,WAAW/C,GAAA;AAAA,cACX,eAAY;AAAA,YAAA;AAAA,UAAA,EACd,CACF,IAEA,gBAAA2H,EAAC,SAAA,EAAM,WAAU,kDACf,UAAA;AAAA,YAAA,gBAAAC,EAAC,QAAA,EAAK,WAAU,kDACb,UAAA7E,EAAE,+BAA+B,GACpC;AAAA,YACA,gBAAA6E;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAO9D;AAAA,gBACP,UAAU,CAAC,MAAM;AACf,kBAAAC,EAAc,EAAE,OAAO,KAAK,GACxB,EAAE,OAAO,MAAM,SAAS,MAAY,SAAS,MACnC,OAAO;AAAA,gBACvB;AAAA,gBACA,aAAahB,EAAE,qCAAqC;AAAA,gBACpD,cAAYA,EAAE,+BAA+B;AAAA,gBAC7C,UAAAJ;AAAA,gBACA,WAAWvC,GAAA;AAAA,gBACX,eAAY;AAAA,cAAA;AAAA,YAAA;AAAA,YAEb0D,IACC,gBAAA8D;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAKnE;AAAA,gBACL,WAAWpD,GAAA;AAAA,gBACX,eAAY;AAAA,gBAEX,UAAAyD;AAAA,cAAA;AAAA,YAAA,IAED;AAAA,UAAA,GACN;AAAA,UAIF,gBAAA8D;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,IAAIzE;AAAA,cACJ,aAAU;AAAA,cACV,eAAY;AAAA,cACZ,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,UAGH,gBAAAwD;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW1H,GAAA;AAAA,cACX,MAAK;AAAA,cACL,cAAY8C,EAAE,oBAAoB;AAAA,cAElC,UAAA;AAAA,gBAAA,gBAAA6E;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM;AACb,sBAAIjF,KACJsD,EAAA;AAAA,oBACF;AAAA,oBACA,iBAAetD,KAAY;AAAA,oBAC3B,WAAWzC,GAAA;AAAA,oBAEV,YAAE,iBAAiB;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAErBwC,KACC,gBAAAkF;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM;AACb,sBAAIjF,MACJoB,EAAc,EAAE,GAChBH,GAAQ,CAACiE,MAAOA,MAAM,SAAS,UAAU,MAAO,GAChDhD,EAAS,SAAS;AAAA,oBACpB;AAAA,oBACA,iBAAelC,KAAY;AAAA,oBAC3B,WAAWzC,GAAA;AAAA,oBACX,gBAAcyD,MAAS;AAAA,oBAEtB,UACGZ,QADM,SACJ,mCACA,oCADgC;AAAA,kBACI;AAAA,gBAAA,IAE1C;AAAA,gBACJ,gBAAA6E;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM;AACb,sBAAIH,KACCpB,EAAA;AAAA,oBACP;AAAA,oBACA,iBAAeoB,KAAmB;AAAA,oBAClC,oBAAkBtE;AAAA,oBAClB,WAAWhD,GAAA;AAAA,oBACX,eAAY;AAAA,oBAEX,YAAE,mBAAmB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACxB;AAAA,YAAA;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACF;AAEA+B,GAAiB,cAAc;"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as a, jsxs as c, Fragment as g } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as m } from "react";
|
|
3
|
+
import { c as d } from "./index-D2ZczOXr.js";
|
|
4
|
+
import { B as b } from "./badge-zsf5i5bH.js";
|
|
5
|
+
function h(r) {
|
|
6
|
+
return r > 99 ? "99+" : String(r);
|
|
7
|
+
}
|
|
8
|
+
const x = d("ds:shrink-0", {
|
|
9
|
+
variants: {
|
|
10
|
+
position: {
|
|
11
|
+
top: "ds:pt-[var(--spacing-md)]",
|
|
12
|
+
bottom: "ds:pb-[var(--spacing-md)]"
|
|
13
|
+
},
|
|
14
|
+
fill: {
|
|
15
|
+
false: "ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]",
|
|
16
|
+
true: ""
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: { position: "top", fill: !1 }
|
|
20
|
+
}), w = "ds:flex ds:[justify-content:safe_center] ds:overflow-x-auto ds:rounded-[var(--radius-lg)] ds:border ds:border-[color:var(--card-border)] ds:bg-[var(--card)]/80 ds:backdrop-blur-md ds:shadow-[var(--shadow-md)] ds:py-[var(--spacing-xs)]", C = d(
|
|
21
|
+
"ds:flex ds:items-stretch ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]",
|
|
22
|
+
{
|
|
23
|
+
variants: {
|
|
24
|
+
fill: { false: "ds:shrink-0", true: "ds:w-full" }
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: { fill: !1 }
|
|
27
|
+
}
|
|
28
|
+
), p = d(
|
|
29
|
+
"ds:group ds:flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)] ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:whitespace-nowrap ds:cursor-pointer ds:appearance-none ds:border-0 ds:bg-transparent ds:text-[length:var(--font-size-sm)] ds:font-[var(--font-weight-regular)] ds:text-[color:var(--foreground)] ds:no-underline ds:hover:bg-[var(--muted)]/20 ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)] ds:forced-colors:focus-visible:outline-[CanvasText]",
|
|
30
|
+
{
|
|
31
|
+
variants: {
|
|
32
|
+
fill: {
|
|
33
|
+
// Responsive: label under the icon below `sm`, beside it at `sm`+.
|
|
34
|
+
false: "ds:flex-col ds:sm:flex-row ds:sm:gap-[var(--spacing-sm)]",
|
|
35
|
+
// Fill the bar, always icon-over-label. No `min-w-0`, so a tab never
|
|
36
|
+
// shrinks below its label (labels never overlap); if the full set can't
|
|
37
|
+
// fit, the pill scrolls instead.
|
|
38
|
+
true: "ds:flex-1 ds:basis-0 ds:flex-col"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
defaultVariants: { fill: !1 }
|
|
42
|
+
}
|
|
43
|
+
), N = "ds:inline-flex ds:items-center ds:text-[color:var(--accent)] ds:[&>svg]:size-4", y = "ds:group-aria-[current=page]:underline ds:group-aria-[current=page]:decoration-2 ds:group-aria-[current=page]:decoration-[color:var(--accent)] ds:group-aria-[current=page]:underline-offset-[var(--spacing-xs)]", V = m(
|
|
44
|
+
({ items: r, ariaLabel: u, onSelect: n, fill: e = !1, position: f = "top", className: i }, v) => /* @__PURE__ */ a(
|
|
45
|
+
"div",
|
|
46
|
+
{
|
|
47
|
+
ref: v,
|
|
48
|
+
"data-component": "tab-bar",
|
|
49
|
+
className: `${x({ position: f, fill: e })}${i ? ` ${i}` : ""}`,
|
|
50
|
+
children: /* @__PURE__ */ a("div", { className: w, children: /* @__PURE__ */ a("nav", { "aria-label": u, className: C({ fill: e }), children: r.map((s) => {
|
|
51
|
+
const o = typeof s.badgeCount == "number" && s.badgeCount > 0 ? s.badgeCount : void 0, t = s.isActive ? "page" : void 0, l = /* @__PURE__ */ c(g, { children: [
|
|
52
|
+
s.icon ? /* @__PURE__ */ a("span", { "aria-hidden": "true", className: N, children: s.icon }) : null,
|
|
53
|
+
/* @__PURE__ */ c("span", { className: "ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]", children: [
|
|
54
|
+
/* @__PURE__ */ a("span", { className: y, children: s.label }),
|
|
55
|
+
o !== void 0 ? /* @__PURE__ */ a(b, { variant: "neutral", children: h(o) }) : null
|
|
56
|
+
] })
|
|
57
|
+
] });
|
|
58
|
+
return s.href ? /* @__PURE__ */ a(
|
|
59
|
+
"a",
|
|
60
|
+
{
|
|
61
|
+
href: s.href,
|
|
62
|
+
"aria-current": t,
|
|
63
|
+
className: p({ fill: e }),
|
|
64
|
+
children: l
|
|
65
|
+
},
|
|
66
|
+
s.id
|
|
67
|
+
) : /* @__PURE__ */ a(
|
|
68
|
+
"button",
|
|
69
|
+
{
|
|
70
|
+
type: "button",
|
|
71
|
+
"aria-current": t,
|
|
72
|
+
className: p({ fill: e }),
|
|
73
|
+
onClick: () => n == null ? void 0 : n(s.id),
|
|
74
|
+
children: l
|
|
75
|
+
},
|
|
76
|
+
s.id
|
|
77
|
+
);
|
|
78
|
+
}) }) })
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
V.displayName = "TabBar";
|
|
83
|
+
export {
|
|
84
|
+
V as T
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=tab-bar-C4II-7ej.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-bar-C4II-7ej.js","sources":["../../src/components/tab-bar/tab-bar.tsx"],"sourcesContent":["/**\n * TabBar — a floating-pill bar of page-level navigation tabs.\n *\n * Each tab is an icon + label (+ optional count badge); the active tab is\n * marked with `aria-current=\"page\"` and an `--accent` underline. The bar is a\n * glassy `--card` pill that floats on whatever canvas the consumer provides\n * (the strip area itself is transparent, so it blends with the surrounding\n * surface).\n *\n * Two layouts:\n * - default (`fill` off): content-width tabs that **centre** when they fit and\n * scroll from the inline-start (`safe center`) when they overflow, with a\n * gutter preserved at both ends. The label stacks under the icon below `sm`.\n * Use this when the tab set is open-ended (e.g. a marketplace app's routes).\n * - `fill`: equal-width tabs that fill the bar and always stack the label under\n * the icon — a fixed, always-visible set that fits any column width without\n * scrolling (e.g. a patient portal's four sections).\n *\n * Tabs render as links when given an `href` (real navigation) or as buttons\n * otherwise (in-app view switching via `onSelect`). Use it as a header (top,\n * default) for section navigation; `position=\"bottom\"` floats it from the\n * bottom edge for a footer.\n */\nimport { forwardRef, type ReactNode } from 'react';\nimport { cva } from 'class-variance-authority';\n\nimport { Badge } from '../badge';\n\nexport interface TabBarItem {\n /** Stable id; also the value handed to `onSelect` for button tabs. */\n id: string;\n /** Pre-translated label — consumers localise their own nav copy. */\n label: string;\n /** Optional leading icon (a lucide-react element or equivalent), tinted with `--accent`. */\n icon?: ReactNode;\n /** Optional unseen-item count rendered as a pill badge. */\n badgeCount?: number;\n /** Mark the tab as the current page (`aria-current='page'` + accent underline). */\n isActive?: boolean;\n /** When set, the tab renders as a link to this href; otherwise it's a button. */\n href?: string;\n}\n\nexport interface TabBarProps {\n /** The tabs, in order. */\n items: TabBarItem[];\n /** Accessible name for the `<nav>` landmark. */\n ariaLabel: string;\n /** Fires with the tab `id` when a button tab (one without `href`) is chosen. */\n onSelect?: (id: string) => void;\n /**\n * Equal-width tabs that fill the bar and always stack the label under the\n * icon (for a fixed, always-visible set). Off (default) = content-width tabs\n * that centre when they fit and scroll when they overflow.\n */\n fill?: boolean;\n /**\n * Float side. `'top'` (default) gutters from the top edge for a header;\n * `'bottom'` gutters from the bottom edge for a footer.\n */\n position?: 'top' | 'bottom';\n /** Extra classes merged onto the outer strip (e.g. sticky/fixed positioning). */\n className?: string;\n}\n\nfunction formatBadgeCount(count: number): string {\n return count > 99 ? '99+' : String(count);\n}\n\n/* Transparent strip area — provides the floating gutter on the active side. The\n default layout also insets the pill horizontally so it reads as a floating\n strip; `fill` drops that inset so the pill spans the full width and aligns\n with the consumer's content (e.g. a portal's cards). */\nconst stripVariants = cva('ds:shrink-0', {\n variants: {\n position: {\n top: 'ds:pt-[var(--spacing-md)]',\n bottom: 'ds:pb-[var(--spacing-md)]',\n },\n fill: {\n false: 'ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n true: '',\n },\n },\n defaultVariants: { position: 'top', fill: false },\n});\n\n/* The pill is the flex scroll container. `safe center` centres the tabs when\n they fit but falls back to start-alignment the moment they overflow, so the\n row stays fully scrollable end to end with nothing clipped. */\nconst pillClasses =\n 'ds:flex ds:[justify-content:safe_center] ds:overflow-x-auto ds:rounded-[var(--radius-lg)] ds:border ds:border-[color:var(--card-border)] ds:bg-[var(--card)]/80 ds:backdrop-blur-md ds:shadow-[var(--shadow-md)] ds:py-[var(--spacing-xs)]';\n\n/* The nav's inline padding is the start/end gutter — it scrolls WITH the tabs,\n so the gutter survives a full scroll. Content width (`shrink-0`) by default so\n it overflows and scrolls; `w-full` in fill mode so the tabs spread to fit. */\nconst navVariants = cva(\n 'ds:flex ds:items-stretch ds:gap-[var(--spacing-xs)] ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)]',\n {\n variants: {\n fill: { false: 'ds:shrink-0', true: 'ds:w-full' },\n },\n defaultVariants: { fill: false },\n },\n);\n\n/* Each tab is a centred flex box so the icon + label sit centred on both axes.\n Regular weight; the active state is carried by the accent underline + accent\n icon, not a heavier weight. */\nconst tabVariants = cva(\n 'ds:group ds:flex ds:items-center ds:justify-center ds:gap-[var(--spacing-xs)] ds:min-h-[var(--min-target-size)] ds:rounded-[var(--radius-sm)] ds:ps-[var(--spacing-sm)] ds:pe-[var(--spacing-sm)] ds:py-[var(--spacing-xs)] ds:whitespace-nowrap ds:cursor-pointer ds:appearance-none ds:border-0 ds:bg-transparent ds:text-[length:var(--font-size-sm)] ds:font-[var(--font-weight-regular)] ds:text-[color:var(--foreground)] ds:no-underline ds:hover:bg-[var(--muted)]/20 ds:transition-colors ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none ds:focus-visible:outline-[length:var(--focus-ring-width)] ds:focus-visible:outline-solid ds:focus-visible:outline-[var(--ring)] ds:focus-visible:outline-offset-[length:var(--focus-ring-offset)] ds:forced-colors:focus-visible:outline-[CanvasText]',\n {\n variants: {\n fill: {\n // Responsive: label under the icon below `sm`, beside it at `sm`+.\n false: 'ds:flex-col ds:sm:flex-row ds:sm:gap-[var(--spacing-sm)]',\n // Fill the bar, always icon-over-label. No `min-w-0`, so a tab never\n // shrinks below its label (labels never overlap); if the full set can't\n // fit, the pill scrolls instead.\n true: 'ds:flex-1 ds:basis-0 ds:flex-col',\n },\n },\n defaultVariants: { fill: false },\n },\n);\n\nconst iconClasses =\n 'ds:inline-flex ds:items-center ds:text-[color:var(--accent)] ds:[&>svg]:size-4';\n\n/* The accent underline rides the label text itself (not the whole tab), so it\n never reaches the icon or badge and never has to propagate through flex. */\nconst labelClasses =\n 'ds:group-aria-[current=page]:underline ds:group-aria-[current=page]:decoration-2 ds:group-aria-[current=page]:decoration-[color:var(--accent)] ds:group-aria-[current=page]:underline-offset-[var(--spacing-xs)]';\n\nexport const TabBar = forwardRef<HTMLDivElement, TabBarProps>(\n (\n { items, ariaLabel, onSelect, fill = false, position = 'top', className },\n ref,\n ) => {\n return (\n <div\n ref={ref}\n data-component=\"tab-bar\"\n className={`${stripVariants({ position, fill })}${className ? ` ${className}` : ''}`}\n >\n <div className={pillClasses}>\n <nav aria-label={ariaLabel} className={navVariants({ fill })}>\n {items.map((item) => {\n const badge =\n typeof item.badgeCount === 'number' && item.badgeCount > 0\n ? item.badgeCount\n : undefined;\n const ariaCurrent = item.isActive ? 'page' : undefined;\n const inner = (\n <>\n {item.icon ? (\n <span aria-hidden=\"true\" className={iconClasses}>\n {item.icon}\n </span>\n ) : null}\n {/* Label + badge stay paired; they sit under the icon when the\n tab stacks to a column. */}\n <span className=\"ds:inline-flex ds:items-center ds:gap-[var(--spacing-xs)]\">\n <span className={labelClasses}>{item.label}</span>\n {badge !== undefined ? (\n <Badge variant=\"neutral\">{formatBadgeCount(badge)}</Badge>\n ) : null}\n </span>\n </>\n );\n return item.href ? (\n <a\n key={item.id}\n href={item.href}\n aria-current={ariaCurrent}\n className={tabVariants({ fill })}\n >\n {inner}\n </a>\n ) : (\n <button\n key={item.id}\n type=\"button\"\n aria-current={ariaCurrent}\n className={tabVariants({ fill })}\n onClick={() => onSelect?.(item.id)}\n >\n {inner}\n </button>\n );\n })}\n </nav>\n </div>\n </div>\n );\n },\n);\nTabBar.displayName = 'TabBar';\n"],"names":["formatBadgeCount","count","stripVariants","cva","pillClasses","navVariants","tabVariants","iconClasses","labelClasses","TabBar","forwardRef","items","ariaLabel","onSelect","fill","position","className","ref","jsx","item","badge","ariaCurrent","inner","jsxs","Fragment","Badge"],"mappings":";;;;AAiEA,SAASA,EAAiBC,GAAuB;AAC/C,SAAOA,IAAQ,KAAK,QAAQ,OAAOA,CAAK;AAC1C;AAMA,MAAMC,IAAgBC,EAAI,eAAe;AAAA,EACvC,UAAU;AAAA,IACR,UAAU;AAAA,MACR,KAAK;AAAA,MACL,QAAQ;AAAA,IAAA;AAAA,IAEV,MAAM;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IAAA;AAAA,EACR;AAAA,EAEF,iBAAiB,EAAE,UAAU,OAAO,MAAM,GAAA;AAC5C,CAAC,GAKKC,IACJ,8OAKIC,IAAcF;AAAA,EAClB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM,EAAE,OAAO,eAAe,MAAM,YAAA;AAAA,IAAY;AAAA,IAElD,iBAAiB,EAAE,MAAM,GAAA;AAAA,EAAM;AAEnC,GAKMG,IAAcH;AAAA,EAClB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA;AAAA,QAEJ,OAAO;AAAA;AAAA;AAAA;AAAA,QAIP,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB,EAAE,MAAM,GAAA;AAAA,EAAM;AAEnC,GAEMI,IACJ,kFAIIC,IACJ,oNAEWC,IAASC;AAAA,EACpB,CACE,EAAE,OAAAC,GAAO,WAAAC,GAAW,UAAAC,GAAU,MAAAC,IAAO,IAAO,UAAAC,IAAW,OAAO,WAAAC,EAAA,GAC9DC,MAGE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,kBAAe;AAAA,MACf,WAAW,GAAGf,EAAc,EAAE,UAAAa,GAAU,MAAAD,EAAA,CAAM,CAAC,GAAGE,IAAY,IAAIA,CAAS,KAAK,EAAE;AAAA,MAElF,4BAAC,OAAA,EAAI,WAAWZ,GACd,UAAA,gBAAAc,EAAC,SAAI,cAAYN,GAAW,WAAWP,EAAY,EAAE,MAAAS,EAAA,CAAM,GACxD,UAAAH,EAAM,IAAI,CAACQ,MAAS;AACnB,cAAMC,IACJ,OAAOD,EAAK,cAAe,YAAYA,EAAK,aAAa,IACrDA,EAAK,aACL,QACAE,IAAcF,EAAK,WAAW,SAAS,QACvCG,IACJ,gBAAAC,EAAAC,GAAA,EACG,UAAA;AAAA,UAAAL,EAAK,yBACH,QAAA,EAAK,eAAY,QAAO,WAAWZ,GACjC,UAAAY,EAAK,KAAA,CACR,IACE;AAAA,UAGJ,gBAAAI,EAAC,QAAA,EAAK,WAAU,6DACd,UAAA;AAAA,YAAA,gBAAAL,EAAC,QAAA,EAAK,WAAWV,GAAe,UAAAW,EAAK,OAAM;AAAA,YAC1CC,MAAU,SACT,gBAAAF,EAACO,GAAA,EAAM,SAAQ,WAAW,UAAAzB,EAAiBoB,CAAK,EAAA,CAAE,IAChD;AAAA,UAAA,EAAA,CACN;AAAA,QAAA,GACF;AAEF,eAAOD,EAAK,OACV,gBAAAD;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,MAAMC,EAAK;AAAA,YACX,gBAAcE;AAAA,YACd,WAAWf,EAAY,EAAE,MAAAQ,GAAM;AAAA,YAE9B,UAAAQ;AAAA,UAAA;AAAA,UALIH,EAAK;AAAA,QAAA,IAQZ,gBAAAD;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,MAAK;AAAA,YACL,gBAAcG;AAAA,YACd,WAAWf,EAAY,EAAE,MAAAQ,GAAM;AAAA,YAC/B,SAAS,MAAMD,KAAA,gBAAAA,EAAWM,EAAK;AAAA,YAE9B,UAAAG;AAAA,UAAA;AAAA,UANIH,EAAK;AAAA,QAAA;AAAA,MAShB,CAAC,GACH,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAIR;AACAV,EAAO,cAAc;"}
|
|
@@ -5,7 +5,7 @@ import { useTranslation as g } from "react-i18next";
|
|
|
5
5
|
import { I as y } from "./icon-button-CKEOrN37.js";
|
|
6
6
|
import { I as K } from "./icon-button-group-C48khLE0.js";
|
|
7
7
|
import { S as x } from "./switch-BJ6HD3Mn.js";
|
|
8
|
-
import { D as o } from "./dropdown-menu-
|
|
8
|
+
import { D as o } from "./dropdown-menu-CUEXqKis.js";
|
|
9
9
|
import { u as z } from "./use-theme-C2dHKUAN.js";
|
|
10
10
|
import { u as D } from "./registry-nPAVE19X.js";
|
|
11
11
|
import { M as v, S as C } from "./sun-BuXE0xUS.js";
|
|
@@ -352,4 +352,4 @@ export {
|
|
|
352
352
|
O as T,
|
|
353
353
|
H as t
|
|
354
354
|
};
|
|
355
|
-
//# sourceMappingURL=theme-toggle-
|
|
355
|
+
//# sourceMappingURL=theme-toggle-ClATnY4Q.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-toggle-DpC28kt5.js","sources":["../../src/components/theme-toggle/theme-toggle.agent.ts","../../src/components/theme-toggle/theme-toggle.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ThemeToggle. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ThemeToggleHandle } from './theme-toggle';\n\nexport const themeToggleAgent: AgentAdapter<ThemeToggleHandle> = {\n id: 'theme-toggle',\n capabilities: ['view_change'],\n state: {\n currentTheme: {\n type: 'ThemePreference',\n descriptionKey: 'ui.agent.themeToggle.state.currentTheme',\n description: 'Active theme preference: light, dark, or system.',\n read: (handle) => handle.getCurrentTheme(),\n },\n currentAccessibility: {\n type: 'AccessibilityPreference',\n descriptionKey: 'ui.agent.themeToggle.state.currentAccessibility',\n description: 'Active accessibility preference: default or accessible.',\n read: (handle) => handle.getCurrentAccessibility(),\n },\n },\n actions: {\n set_theme: {\n safety: 'write',\n argsType: '{ theme: \"light\" | \"dark\" | \"system\" }',\n descriptionKey: 'ui.agent.themeToggle.actions.setTheme',\n description: 'Switch the theme preference.',\n invoke: (handle, args: { theme: 'light' | 'dark' | 'system' }) => {\n handle.setTheme(args.theme);\n },\n },\n set_accessibility: {\n safety: 'write',\n argsType: '{ accessibility: \"default\" | \"accessible\" }',\n descriptionKey: 'ui.agent.themeToggle.actions.setAccessibility',\n description: 'Switch the accessibility preference.',\n invoke: (handle, args: { accessibility: 'default' | 'accessible' }) => {\n handle.setAccessibility(args.accessibility);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'theme-toggle',\n description: 'Marks the ThemeToggle 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 useImperativeHandle,\n useMemo,\n useRef,\n type HTMLAttributes,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Monitor, Moon, Sun } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { IconButtonGroup } from '../icon-button-group/icon-button-group';\nimport { Switch } from '../switch/switch';\nimport { DropdownMenu } from '../dropdown-menu/dropdown-menu';\nimport {\n useTheme,\n type AccessibilityPreference,\n type ThemePreference,\n type UseThemeReturn,\n} from '../../hooks';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { themeToggleAgent } from './theme-toggle.agent';\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva('ds:inline-flex ds:items-center', {\n variants: {\n variant: {\n menu: '',\n compact: '',\n split: 'ds:gap-[var(--spacing-md)]',\n },\n },\n defaultVariants: { variant: 'menu' },\n});\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type ThemeToggleVariant = 'menu' | 'compact' | 'split';\n\ninterface ThemeToggleBaseProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>,\n VariantProps<typeof wrapperVariants> {\n /**\n * Visual form factor.\n * - `menu` (default) — single trigger that opens a dropdown with both\n * Appearance and Accessibility controls. Best for headers / nav rails.\n * - `compact` — segmented Appearance control only. Use when accessibility\n * lives on a separate settings surface.\n * - `split` — segmented Appearance control plus an inline Accessibility\n * switch. Best for full-width settings panels.\n */\n variant?: ThemeToggleVariant;\n /** Hide the accessibility control. Ignored on `compact`, which never renders it. */\n showAccessibility?: boolean;\n /**\n * Controlled escape hatch — when omitted the component reads/writes\n * `useTheme()` directly so it can drop into any header with no wiring.\n * Pass all four to opt into controlled mode.\n */\n theme?: ThemePreference;\n accessibility?: AccessibilityPreference;\n onThemeChange?: (next: ThemePreference) => void;\n onAccessibilityChange?: (next: AccessibilityPreference) => void;\n}\n\nexport type ThemeToggleProps = ThemeToggleBaseProps;\n\n/** Curated imperative handle for agent / external automation. */\nexport interface ThemeToggleHandle {\n getCurrentTheme: () => ThemePreference;\n getCurrentAccessibility: () => AccessibilityPreference;\n setTheme: (next: ThemePreference) => void;\n setAccessibility: (next: AccessibilityPreference) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook adapter */\n/* ------------------------------------------------------------------ */\n\n/**\n * Resolves controlled props against the store. When the consumer passes\n * `theme` / `onThemeChange` (etc.) we honour those; otherwise we fall\n * through to the singleton `useTheme()` hook so a bare `<ThemeToggle />`\n * works with zero wiring.\n */\nfunction useResolvedTheme(props: ThemeToggleBaseProps): UseThemeReturn {\n const {\n theme: themeProp,\n accessibility: accessibilityProp,\n onThemeChange,\n onAccessibilityChange,\n } = props;\n const store = useTheme();\n const theme = themeProp ?? store.theme;\n const accessibility = accessibilityProp ?? store.accessibility;\n\n const storeSetTheme = store.setTheme;\n const storeSetAccessibility = store.setAccessibility;\n\n const setTheme = useCallback(\n (next: ThemePreference) => {\n if (onThemeChange) {\n onThemeChange(next);\n return;\n }\n storeSetTheme(next);\n },\n [onThemeChange, storeSetTheme],\n );\n\n const setAccessibility = useCallback(\n (next: AccessibilityPreference) => {\n if (onAccessibilityChange) {\n onAccessibilityChange(next);\n return;\n }\n storeSetAccessibility(next);\n },\n [onAccessibilityChange, storeSetAccessibility],\n );\n\n return {\n theme,\n accessibility,\n resolvedTheme: store.resolvedTheme,\n setTheme,\n setAccessibility,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Sub-pieces */\n/* ------------------------------------------------------------------ */\n\ninterface AppearanceSegmentProps {\n value: ThemePreference;\n onValueChange: (next: ThemePreference) => void;\n ariaLabel: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nfunction AppearanceSegment({\n value,\n onValueChange,\n ariaLabel,\n size = 'md',\n}: AppearanceSegmentProps) {\n const { t } = useTranslation();\n return (\n <IconButtonGroup\n aria-label={ariaLabel}\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size={size}\n value={value}\n onValueChange={(next) => onValueChange(next as ThemePreference)}\n >\n <IconButton\n icon={<Sun aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.light')}\n value=\"light\"\n />\n <IconButton\n icon={<Moon aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.dark')}\n value=\"dark\"\n />\n <IconButton\n icon={<Monitor aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.system')}\n value=\"system\"\n />\n </IconButtonGroup>\n );\n}\n\ninterface AccessibilitySwitchProps {\n value: AccessibilityPreference;\n onValueChange: (next: AccessibilityPreference) => void;\n size?: 'sm' | 'md' | 'lg';\n}\n\nfunction AccessibilitySwitch({\n value,\n onValueChange,\n size = 'md',\n}: AccessibilitySwitchProps) {\n const { t } = useTranslation();\n // 'system' is treated as \"off\" visually — the OS preference flows through\n // automatically. Flipping the switch on creates an explicit override.\n const checked = value === 'accessible';\n return (\n <Switch\n label={t('navigation.themeToggle.accessibility.label')}\n labelSide=\"start\"\n size={size}\n checked={checked}\n onCheckedChange={(next) => onValueChange(next ? 'accessible' : 'default')}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Variants */\n/* ------------------------------------------------------------------ */\n\ninterface VariantRenderProps {\n state: UseThemeReturn;\n className?: string;\n rest: HTMLAttributes<HTMLDivElement>;\n forwardedRef: React.Ref<HTMLDivElement>;\n showAccessibility: boolean;\n}\n\nfunction MenuVariant({\n state,\n className,\n rest,\n forwardedRef,\n showAccessibility,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n const triggerIcon =\n state.resolvedTheme === 'dark' ||\n state.resolvedTheme === 'dark-accessible' ? (\n <Moon aria-hidden />\n ) : (\n <Sun aria-hidden />\n );\n\n const accessibleChecked = state.accessibility === 'accessible';\n\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'menu', className })}\n {...rest}\n >\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <IconButton\n icon={triggerIcon}\n aria-label={t('navigation.themeToggle.trigger')}\n />\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content align=\"end\" sideOffset={8}>\n <DropdownMenu.Label>\n {t('navigation.themeToggle.appearance.label')}\n </DropdownMenu.Label>\n <DropdownMenu.RadioGroup\n value={state.theme}\n onValueChange={(next) => state.setTheme(next as ThemePreference)}\n >\n <DropdownMenu.RadioItem value=\"light\">\n <Sun aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.light')}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"dark\">\n <Moon aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.dark')}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"system\">\n <Monitor aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.system')}\n </DropdownMenu.RadioItem>\n </DropdownMenu.RadioGroup>\n {showAccessibility ? (\n <>\n <DropdownMenu.Separator />\n {/* CheckboxItem keeps the accessibility toggle inside the\n Radix menu collection so ArrowDown reaches it and Space\n activates it; `onSelect={preventDefault}` prevents the\n menu from closing on toggle. */}\n <DropdownMenu.CheckboxItem\n checked={accessibleChecked}\n onCheckedChange={(next) =>\n state.setAccessibility(next ? 'accessible' : 'default')\n }\n onSelect={(event) => event.preventDefault()}\n >\n {t('navigation.themeToggle.accessibility.label')}\n </DropdownMenu.CheckboxItem>\n </>\n ) : null}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n </div>\n );\n}\n\nfunction CompactVariant({\n state,\n className,\n rest,\n forwardedRef,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'compact', className })}\n {...rest}\n >\n <AppearanceSegment\n value={state.theme}\n onValueChange={state.setTheme}\n ariaLabel={t('navigation.themeToggle.appearance.label')}\n />\n </div>\n );\n}\n\nfunction SplitVariant({\n state,\n className,\n rest,\n forwardedRef,\n showAccessibility,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'split', className })}\n {...rest}\n >\n <AppearanceSegment\n value={state.theme}\n onValueChange={state.setTheme}\n ariaLabel={t('navigation.themeToggle.appearance.label')}\n />\n {showAccessibility ? (\n <AccessibilitySwitch\n value={state.accessibility}\n onValueChange={state.setAccessibility}\n />\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ThemeToggle */\n/* ------------------------------------------------------------------ */\n\nexport const ThemeToggle = forwardRef<HTMLDivElement, ThemeToggleProps>(\n (props, ref) => {\n const {\n variant = 'menu',\n showAccessibility = true,\n className,\n id,\n // Strip controlled props from the spread — they are read by the\n // adapter, not by the DOM element.\n theme: _theme,\n accessibility: _accessibility,\n onThemeChange: _onThemeChange,\n onAccessibilityChange: _onAccessibilityChange,\n ...rest\n } = props as ThemeToggleProps & { id?: string };\n\n const state = useResolvedTheme(props);\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // Internal variant wrappers attach refs to <div> elements; we forward that\n // DOM node as the public ref (Pattern B). The agent handle is registered\n // separately via useAgentRegistration.\n const forwardedRef = useRef<HTMLDivElement | null>(null);\n useImperativeHandle(ref, () => forwardedRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<ThemeToggleHandle>(\n () => ({\n getCurrentTheme: () => stateRef.current.theme,\n getCurrentAccessibility: () => stateRef.current.accessibility,\n setTheme: (next) => stateRef.current.setTheme(next),\n setAccessibility: (next) => stateRef.current.setAccessibility(next),\n }),\n [],\n );\n useAgentRegistration(themeToggleAgent, agentHandle, id);\n\n if (variant === 'compact') {\n return (\n <CompactVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n }\n if (variant === 'split') {\n return (\n <SplitVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n }\n return (\n <MenuVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n },\n);\n\nThemeToggle.displayName = 'ThemeToggle';\n"],"names":["themeToggleAgent","handle","args","wrapperVariants","cva","useResolvedTheme","props","themeProp","accessibilityProp","onThemeChange","onAccessibilityChange","store","useTheme","theme","accessibility","storeSetTheme","storeSetAccessibility","setTheme","useCallback","next","setAccessibility","AppearanceSegment","value","onValueChange","ariaLabel","size","t","useTranslation","jsxs","IconButtonGroup","jsx","IconButton","Sun","Moon","Monitor","AccessibilitySwitch","checked","Switch","MenuVariant","state","className","rest","forwardedRef","showAccessibility","triggerIcon","accessibleChecked","DropdownMenu","Fragment","event","CompactVariant","SplitVariant","ThemeToggle","forwardRef","ref","variant","id","_theme","_accessibility","_onThemeChange","_onAccessibilityChange","stateRef","useRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"theme-toggle-ClATnY4Q.js","sources":["../../src/components/theme-toggle/theme-toggle.agent.ts","../../src/components/theme-toggle/theme-toggle.tsx"],"sourcesContent":["/* -------------------------------------------------------------------- */\n/* Agent adapter — ThemeToggle. */\n/* -------------------------------------------------------------------- */\n\nimport type { AgentAdapter } from '../../agent/types';\nimport type { ThemeToggleHandle } from './theme-toggle';\n\nexport const themeToggleAgent: AgentAdapter<ThemeToggleHandle> = {\n id: 'theme-toggle',\n capabilities: ['view_change'],\n state: {\n currentTheme: {\n type: 'ThemePreference',\n descriptionKey: 'ui.agent.themeToggle.state.currentTheme',\n description: 'Active theme preference: light, dark, or system.',\n read: (handle) => handle.getCurrentTheme(),\n },\n currentAccessibility: {\n type: 'AccessibilityPreference',\n descriptionKey: 'ui.agent.themeToggle.state.currentAccessibility',\n description: 'Active accessibility preference: default or accessible.',\n read: (handle) => handle.getCurrentAccessibility(),\n },\n },\n actions: {\n set_theme: {\n safety: 'write',\n argsType: '{ theme: \"light\" | \"dark\" | \"system\" }',\n descriptionKey: 'ui.agent.themeToggle.actions.setTheme',\n description: 'Switch the theme preference.',\n invoke: (handle, args: { theme: 'light' | 'dark' | 'system' }) => {\n handle.setTheme(args.theme);\n },\n },\n set_accessibility: {\n safety: 'write',\n argsType: '{ accessibility: \"default\" | \"accessible\" }',\n descriptionKey: 'ui.agent.themeToggle.actions.setAccessibility',\n description: 'Switch the accessibility preference.',\n invoke: (handle, args: { accessibility: 'default' | 'accessible' }) => {\n handle.setAccessibility(args.accessibility);\n },\n },\n },\n domHooks: {\n root: {\n attr: 'data-component',\n value: 'theme-toggle',\n description: 'Marks the ThemeToggle 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 useImperativeHandle,\n useMemo,\n useRef,\n type HTMLAttributes,\n} from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { useTranslation } from 'react-i18next';\nimport { Monitor, Moon, Sun } from 'lucide-react';\nimport { IconButton } from '../button/icon-button';\nimport { IconButtonGroup } from '../icon-button-group/icon-button-group';\nimport { Switch } from '../switch/switch';\nimport { DropdownMenu } from '../dropdown-menu/dropdown-menu';\nimport {\n useTheme,\n type AccessibilityPreference,\n type ThemePreference,\n type UseThemeReturn,\n} from '../../hooks';\nimport { useAgentRegistration } from '../../agent/registry';\nimport { themeToggleAgent } from './theme-toggle.agent';\n\n/* ------------------------------------------------------------------ */\n/* CVA */\n/* ------------------------------------------------------------------ */\n\nconst wrapperVariants = cva('ds:inline-flex ds:items-center', {\n variants: {\n variant: {\n menu: '',\n compact: '',\n split: 'ds:gap-[var(--spacing-md)]',\n },\n },\n defaultVariants: { variant: 'menu' },\n});\n\n/* ------------------------------------------------------------------ */\n/* Public types */\n/* ------------------------------------------------------------------ */\n\nexport type ThemeToggleVariant = 'menu' | 'compact' | 'split';\n\ninterface ThemeToggleBaseProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, 'onChange'>,\n VariantProps<typeof wrapperVariants> {\n /**\n * Visual form factor.\n * - `menu` (default) — single trigger that opens a dropdown with both\n * Appearance and Accessibility controls. Best for headers / nav rails.\n * - `compact` — segmented Appearance control only. Use when accessibility\n * lives on a separate settings surface.\n * - `split` — segmented Appearance control plus an inline Accessibility\n * switch. Best for full-width settings panels.\n */\n variant?: ThemeToggleVariant;\n /** Hide the accessibility control. Ignored on `compact`, which never renders it. */\n showAccessibility?: boolean;\n /**\n * Controlled escape hatch — when omitted the component reads/writes\n * `useTheme()` directly so it can drop into any header with no wiring.\n * Pass all four to opt into controlled mode.\n */\n theme?: ThemePreference;\n accessibility?: AccessibilityPreference;\n onThemeChange?: (next: ThemePreference) => void;\n onAccessibilityChange?: (next: AccessibilityPreference) => void;\n}\n\nexport type ThemeToggleProps = ThemeToggleBaseProps;\n\n/** Curated imperative handle for agent / external automation. */\nexport interface ThemeToggleHandle {\n getCurrentTheme: () => ThemePreference;\n getCurrentAccessibility: () => AccessibilityPreference;\n setTheme: (next: ThemePreference) => void;\n setAccessibility: (next: AccessibilityPreference) => void;\n}\n\n/* ------------------------------------------------------------------ */\n/* Hook adapter */\n/* ------------------------------------------------------------------ */\n\n/**\n * Resolves controlled props against the store. When the consumer passes\n * `theme` / `onThemeChange` (etc.) we honour those; otherwise we fall\n * through to the singleton `useTheme()` hook so a bare `<ThemeToggle />`\n * works with zero wiring.\n */\nfunction useResolvedTheme(props: ThemeToggleBaseProps): UseThemeReturn {\n const {\n theme: themeProp,\n accessibility: accessibilityProp,\n onThemeChange,\n onAccessibilityChange,\n } = props;\n const store = useTheme();\n const theme = themeProp ?? store.theme;\n const accessibility = accessibilityProp ?? store.accessibility;\n\n const storeSetTheme = store.setTheme;\n const storeSetAccessibility = store.setAccessibility;\n\n const setTheme = useCallback(\n (next: ThemePreference) => {\n if (onThemeChange) {\n onThemeChange(next);\n return;\n }\n storeSetTheme(next);\n },\n [onThemeChange, storeSetTheme],\n );\n\n const setAccessibility = useCallback(\n (next: AccessibilityPreference) => {\n if (onAccessibilityChange) {\n onAccessibilityChange(next);\n return;\n }\n storeSetAccessibility(next);\n },\n [onAccessibilityChange, storeSetAccessibility],\n );\n\n return {\n theme,\n accessibility,\n resolvedTheme: store.resolvedTheme,\n setTheme,\n setAccessibility,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Sub-pieces */\n/* ------------------------------------------------------------------ */\n\ninterface AppearanceSegmentProps {\n value: ThemePreference;\n onValueChange: (next: ThemePreference) => void;\n ariaLabel: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\nfunction AppearanceSegment({\n value,\n onValueChange,\n ariaLabel,\n size = 'md',\n}: AppearanceSegmentProps) {\n const { t } = useTranslation();\n return (\n <IconButtonGroup\n aria-label={ariaLabel}\n role=\"radiogroup\"\n mode=\"toggle-single\"\n size={size}\n value={value}\n onValueChange={(next) => onValueChange(next as ThemePreference)}\n >\n <IconButton\n icon={<Sun aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.light')}\n value=\"light\"\n />\n <IconButton\n icon={<Moon aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.dark')}\n value=\"dark\"\n />\n <IconButton\n icon={<Monitor aria-hidden />}\n aria-label={t('navigation.themeToggle.appearance.system')}\n value=\"system\"\n />\n </IconButtonGroup>\n );\n}\n\ninterface AccessibilitySwitchProps {\n value: AccessibilityPreference;\n onValueChange: (next: AccessibilityPreference) => void;\n size?: 'sm' | 'md' | 'lg';\n}\n\nfunction AccessibilitySwitch({\n value,\n onValueChange,\n size = 'md',\n}: AccessibilitySwitchProps) {\n const { t } = useTranslation();\n // 'system' is treated as \"off\" visually — the OS preference flows through\n // automatically. Flipping the switch on creates an explicit override.\n const checked = value === 'accessible';\n return (\n <Switch\n label={t('navigation.themeToggle.accessibility.label')}\n labelSide=\"start\"\n size={size}\n checked={checked}\n onCheckedChange={(next) => onValueChange(next ? 'accessible' : 'default')}\n />\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* Variants */\n/* ------------------------------------------------------------------ */\n\ninterface VariantRenderProps {\n state: UseThemeReturn;\n className?: string;\n rest: HTMLAttributes<HTMLDivElement>;\n forwardedRef: React.Ref<HTMLDivElement>;\n showAccessibility: boolean;\n}\n\nfunction MenuVariant({\n state,\n className,\n rest,\n forwardedRef,\n showAccessibility,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n const triggerIcon =\n state.resolvedTheme === 'dark' ||\n state.resolvedTheme === 'dark-accessible' ? (\n <Moon aria-hidden />\n ) : (\n <Sun aria-hidden />\n );\n\n const accessibleChecked = state.accessibility === 'accessible';\n\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'menu', className })}\n {...rest}\n >\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <IconButton\n icon={triggerIcon}\n aria-label={t('navigation.themeToggle.trigger')}\n />\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content align=\"end\" sideOffset={8}>\n <DropdownMenu.Label>\n {t('navigation.themeToggle.appearance.label')}\n </DropdownMenu.Label>\n <DropdownMenu.RadioGroup\n value={state.theme}\n onValueChange={(next) => state.setTheme(next as ThemePreference)}\n >\n <DropdownMenu.RadioItem value=\"light\">\n <Sun aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.light')}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"dark\">\n <Moon aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.dark')}\n </DropdownMenu.RadioItem>\n <DropdownMenu.RadioItem value=\"system\">\n <Monitor aria-hidden className=\"ds:size-4\" />\n {t('navigation.themeToggle.appearance.system')}\n </DropdownMenu.RadioItem>\n </DropdownMenu.RadioGroup>\n {showAccessibility ? (\n <>\n <DropdownMenu.Separator />\n {/* CheckboxItem keeps the accessibility toggle inside the\n Radix menu collection so ArrowDown reaches it and Space\n activates it; `onSelect={preventDefault}` prevents the\n menu from closing on toggle. */}\n <DropdownMenu.CheckboxItem\n checked={accessibleChecked}\n onCheckedChange={(next) =>\n state.setAccessibility(next ? 'accessible' : 'default')\n }\n onSelect={(event) => event.preventDefault()}\n >\n {t('navigation.themeToggle.accessibility.label')}\n </DropdownMenu.CheckboxItem>\n </>\n ) : null}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n </div>\n );\n}\n\nfunction CompactVariant({\n state,\n className,\n rest,\n forwardedRef,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'compact', className })}\n {...rest}\n >\n <AppearanceSegment\n value={state.theme}\n onValueChange={state.setTheme}\n ariaLabel={t('navigation.themeToggle.appearance.label')}\n />\n </div>\n );\n}\n\nfunction SplitVariant({\n state,\n className,\n rest,\n forwardedRef,\n showAccessibility,\n}: VariantRenderProps) {\n const { t } = useTranslation();\n return (\n <div\n ref={forwardedRef}\n data-component=\"theme-toggle\"\n data-component-id={rest.id}\n className={wrapperVariants({ variant: 'split', className })}\n {...rest}\n >\n <AppearanceSegment\n value={state.theme}\n onValueChange={state.setTheme}\n ariaLabel={t('navigation.themeToggle.appearance.label')}\n />\n {showAccessibility ? (\n <AccessibilitySwitch\n value={state.accessibility}\n onValueChange={state.setAccessibility}\n />\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ThemeToggle */\n/* ------------------------------------------------------------------ */\n\nexport const ThemeToggle = forwardRef<HTMLDivElement, ThemeToggleProps>(\n (props, ref) => {\n const {\n variant = 'menu',\n showAccessibility = true,\n className,\n id,\n // Strip controlled props from the spread — they are read by the\n // adapter, not by the DOM element.\n theme: _theme,\n accessibility: _accessibility,\n onThemeChange: _onThemeChange,\n onAccessibilityChange: _onAccessibilityChange,\n ...rest\n } = props as ThemeToggleProps & { id?: string };\n\n const state = useResolvedTheme(props);\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // Internal variant wrappers attach refs to <div> elements; we forward that\n // DOM node as the public ref (Pattern B). The agent handle is registered\n // separately via useAgentRegistration.\n const forwardedRef = useRef<HTMLDivElement | null>(null);\n useImperativeHandle(ref, () => forwardedRef.current as HTMLDivElement, []);\n\n const agentHandle = useMemo<ThemeToggleHandle>(\n () => ({\n getCurrentTheme: () => stateRef.current.theme,\n getCurrentAccessibility: () => stateRef.current.accessibility,\n setTheme: (next) => stateRef.current.setTheme(next),\n setAccessibility: (next) => stateRef.current.setAccessibility(next),\n }),\n [],\n );\n useAgentRegistration(themeToggleAgent, agentHandle, id);\n\n if (variant === 'compact') {\n return (\n <CompactVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n }\n if (variant === 'split') {\n return (\n <SplitVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n }\n return (\n <MenuVariant\n state={state}\n className={className}\n rest={rest}\n forwardedRef={forwardedRef}\n showAccessibility={showAccessibility}\n />\n );\n },\n);\n\nThemeToggle.displayName = 'ThemeToggle';\n"],"names":["themeToggleAgent","handle","args","wrapperVariants","cva","useResolvedTheme","props","themeProp","accessibilityProp","onThemeChange","onAccessibilityChange","store","useTheme","theme","accessibility","storeSetTheme","storeSetAccessibility","setTheme","useCallback","next","setAccessibility","AppearanceSegment","value","onValueChange","ariaLabel","size","t","useTranslation","jsxs","IconButtonGroup","jsx","IconButton","Sun","Moon","Monitor","AccessibilitySwitch","checked","Switch","MenuVariant","state","className","rest","forwardedRef","showAccessibility","triggerIcon","accessibleChecked","DropdownMenu","Fragment","event","CompactVariant","SplitVariant","ThemeToggle","forwardRef","ref","variant","id","_theme","_accessibility","_onThemeChange","_onAccessibilityChange","stateRef","useRef","useImperativeHandle","agentHandle","useMemo","useAgentRegistration"],"mappings":"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"}
|
|
@@ -838,7 +838,7 @@ function Oe({
|
|
|
838
838
|
"ds:forced-colors:border ds:forced-colors:border-[CanvasText]",
|
|
839
839
|
"ds:rounded-[var(--radius-md)]",
|
|
840
840
|
"ds:ps-[var(--spacing-md)] ds:pe-[var(--spacing-md)] ds:py-[var(--spacing-sm)]",
|
|
841
|
-
"[max-inline-size:360px] max-sm:[max-inline-size:88dvw]",
|
|
841
|
+
"ds:[max-inline-size:360px] ds:max-sm:[max-inline-size:88dvw]",
|
|
842
842
|
"break-words",
|
|
843
843
|
"ds:z-[var(--z-toast)]",
|
|
844
844
|
"ds:duration-[var(--animation-duration)] ds:motion-reduce:transition-none"
|
|
@@ -985,4 +985,4 @@ export {
|
|
|
985
985
|
Ze as e,
|
|
986
986
|
aa as t
|
|
987
987
|
};
|
|
988
|
-
//# sourceMappingURL=toast.agent-
|
|
988
|
+
//# sourceMappingURL=toast.agent-B0MCsvdZ.js.map
|