@eifi1/ui-kit 0.48.2 → 0.49.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/README.md +26 -12
- package/dist/admin/admin-action-confirm.js +1 -1
- package/dist/admin/admin-action-confirm.js.map +1 -1
- package/dist/admin/invitations-panel.js +5 -1
- package/dist/admin/invitations-panel.js.map +1 -1
- package/dist/admin/user-roster.d.ts +11 -5
- package/dist/admin/user-roster.js +15 -4
- package/dist/admin/user-roster.js.map +1 -1
- package/dist/auth/accept-invitation.js +2 -2
- package/dist/auth/accept-invitation.js.map +1 -1
- package/dist/auth/not-found-page.js +1 -1
- package/dist/auth/not-found-page.js.map +1 -1
- package/dist/auth/reset-password-form.js +2 -2
- package/dist/auth/reset-password-form.js.map +1 -1
- package/dist/auth/verify-email.js +2 -2
- package/dist/auth/verify-email.js.map +1 -1
- package/dist/billing/plan-card.js +2 -2
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/components/breadcrumbs.d.ts +19 -1
- package/dist/components/breadcrumbs.js +11 -4
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/button-look.d.ts +37 -7
- package/dist/components/button-look.js +33 -6
- package/dist/components/button-look.js.map +1 -1
- package/dist/components/button.d.ts +4 -1
- package/dist/components/button.js +2 -2
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar-heatmap.js +2 -1
- package/dist/components/calendar-heatmap.js.map +1 -1
- package/dist/components/chart-edge.d.ts +10 -0
- package/dist/components/chart-edge.js +57 -0
- package/dist/components/chart-edge.js.map +1 -0
- package/dist/components/chart.js +2 -1
- package/dist/components/chart.js.map +1 -1
- package/dist/components/chip.d.ts +8 -1
- package/dist/components/chip.js +4 -1
- package/dist/components/chip.js.map +1 -1
- package/dist/components/confirm-context.d.ts +5 -0
- package/dist/components/confirm-context.js +7 -0
- package/dist/components/confirm-context.js.map +1 -0
- package/dist/components/confirm-dialog.js +3 -3
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/danger-confirm.d.ts +2 -2
- package/dist/components/danger-confirm.js +1 -1
- package/dist/components/danger-confirm.js.map +1 -1
- package/dist/components/data-table-fit.js +21 -3
- package/dist/components/data-table-fit.js.map +1 -1
- package/dist/components/data-table-mobile.d.ts +48 -2
- package/dist/components/data-table-mobile.js +87 -10
- package/dist/components/data-table-mobile.js.map +1 -1
- package/dist/components/data-table-row-actions.d.ts +2 -1
- package/dist/components/data-table-row-actions.js +7 -0
- package/dist/components/data-table-row-actions.js.map +1 -1
- package/dist/components/data-table-row.d.ts +1 -1
- package/dist/components/data-table-row.js.map +1 -1
- package/dist/components/data-table.d.ts +34 -1
- package/dist/components/data-table.js +34 -9
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/error-boundary.js +2 -2
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/floating-panel.d.ts +36 -13
- package/dist/components/floating-panel.js +27 -7
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +1 -1
- package/dist/components/form-actions.js +1 -1
- package/dist/components/form-actions.js.map +1 -1
- package/dist/components/icon-button.d.ts +11 -0
- package/dist/components/icon-button.js +7 -5
- package/dist/components/icon-button.js.map +1 -1
- package/dist/components/nav-pills.d.ts +8 -1
- package/dist/components/nav-pills.js +61 -38
- package/dist/components/nav-pills.js.map +1 -1
- package/dist/components/page-header-context.d.ts +8 -0
- package/dist/components/page-header-context.js +7 -0
- package/dist/components/page-header-context.js.map +1 -0
- package/dist/components/page-header.d.ts +14 -2
- package/dist/components/page-header.js +10 -1
- package/dist/components/page-header.js.map +1 -1
- package/dist/components/pie-chart.js +2 -1
- package/dist/components/pie-chart.js.map +1 -1
- package/dist/components/progress-bar.js +5 -4
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/reauth-dialog.js +1 -1
- package/dist/components/reauth-dialog.js.map +1 -1
- package/dist/components/row-actions-labels.js +3 -1
- package/dist/components/row-actions-labels.js.map +1 -1
- package/dist/components/row-actions.d.ts +43 -9
- package/dist/components/row-actions.js +78 -15
- package/dist/components/row-actions.js.map +1 -1
- package/dist/components/section-nav.d.ts +37 -0
- package/dist/components/section-nav.js +33 -0
- package/dist/components/section-nav.js.map +1 -0
- package/dist/components/series-chart.js +8 -3
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/share-card.js +1 -1
- package/dist/components/share-card.js.map +1 -1
- package/dist/components/signature-pad.js +1 -1
- package/dist/components/signature-pad.js.map +1 -1
- package/dist/components/sparkline.js +2 -1
- package/dist/components/sparkline.js.map +1 -1
- package/dist/components/stat-tile.js +14 -7
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/status-dot.d.ts +5 -1
- package/dist/components/status-dot.js +4 -1
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/tooltip.js +1 -1
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/translation-review-editor.js +2 -2
- package/dist/components/translation-review-editor.js.map +1 -1
- package/dist/components/translation-review.js +2 -2
- package/dist/components/translation-review.js.map +1 -1
- package/dist/components/treemap.d.ts +5 -2
- package/dist/components/treemap.js +26 -6
- package/dist/components/treemap.js.map +1 -1
- package/dist/components/use-table-state.js +37 -6
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/demo/demo-banner.js +1 -1
- package/dist/demo/demo-banner.js.map +1 -1
- package/dist/demo/demo-ended.js +1 -1
- package/dist/demo/demo-ended.js.map +1 -1
- package/dist/demo/demo-start.js +1 -1
- package/dist/demo/demo-start.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/feedback/feedback-inbox.js +1 -1
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/hooks/use-dismiss.d.ts +9 -1
- package/dist/hooks/use-dismiss.js +25 -5
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-document-title.d.ts +14 -0
- package/dist/hooks/use-document-title.js +22 -0
- package/dist/hooks/use-document-title.js.map +1 -0
- package/dist/i18n/german.js +6 -2
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +31 -1
- package/dist/i18n/kit-labels.js +43 -2
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +6 -2
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/es.js +6 -2
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +6 -2
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +6 -2
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +6 -2
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +6 -2
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +2 -0
- package/dist/i18n/review.js.map +1 -1
- package/dist/i18n/shared-labels.js +1 -0
- package/dist/i18n/shared-labels.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/landing/landing-actions.js +2 -2
- package/dist/landing/landing-actions.js.map +1 -1
- package/dist/landing/public-header.js +2 -2
- package/dist/landing/public-header.js.map +1 -1
- package/dist/lib/clipboard-minus.d.ts +27 -0
- package/dist/lib/clipboard-minus.js +63 -0
- package/dist/lib/clipboard-minus.js.map +1 -0
- package/dist/lib/document-title.d.ts +17 -0
- package/dist/lib/document-title.js +29 -0
- package/dist/lib/document-title.js.map +1 -0
- package/dist/lib/float-clearance.js +8 -2
- package/dist/lib/float-clearance.js.map +1 -1
- package/dist/lib/format.d.ts +35 -10
- package/dist/lib/format.js +55 -11
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/minus.d.ts +22 -0
- package/dist/lib/minus.js +14 -0
- package/dist/lib/minus.js.map +1 -0
- package/dist/lib/status-tone.d.ts +30 -0
- package/dist/lib/status-tone.js +17 -0
- package/dist/lib/status-tone.js.map +1 -0
- package/dist/settings/settings-layout.js +3 -2
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +1 -1
- package/dist/shell/account-menu-language.js +9 -1
- package/dist/shell/account-menu-language.js.map +1 -1
- package/dist/shell/app-shell-labels.js +2 -1
- package/dist/shell/app-shell-labels.js.map +1 -1
- package/dist/shell/app-shell.d.ts +58 -16
- package/dist/shell/app-shell.js +151 -43
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/language-code.d.ts +3 -0
- package/dist/shell/language-code.js +8 -0
- package/dist/shell/language-code.js.map +1 -0
- package/dist/shell/topbar-controls.d.ts +14 -6
- package/dist/shell/topbar-controls.js +14 -17
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/testing/css-variables.generated.d.ts +1 -1
- package/dist/testing/css-variables.generated.js +1 -1
- package/dist/testing/css-variables.generated.js.map +1 -1
- package/dist/theme/chart-palette.d.ts +82 -15
- package/dist/theme/chart-palette.js +51 -24
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/palette-presets.d.ts +9 -0
- package/dist/theme/palette-presets.js +77 -62
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/tour/tour.js +1 -1
- package/dist/tour/tour.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +1 -1
- package/dist/wizard/stepper-nav.js +3 -3
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/admin-action-confirm.tsx +1 -1
- package/src/admin/invitations-panel.tsx +7 -3
- package/src/admin/user-roster.tsx +23 -6
- package/src/auth/accept-invitation.tsx +3 -3
- package/src/auth/not-found-page.tsx +1 -1
- package/src/auth/reset-password-form.tsx +3 -3
- package/src/auth/verify-email.tsx +3 -3
- package/src/billing/plan-card.tsx +2 -2
- package/src/components/breadcrumbs.tsx +32 -4
- package/src/components/button-look.ts +86 -15
- package/src/components/button.tsx +6 -3
- package/src/components/calendar-heatmap.tsx +2 -1
- package/src/components/chart-edge.ts +73 -0
- package/src/components/chart.tsx +3 -1
- package/src/components/chip.tsx +10 -1
- package/src/components/confirm-context.ts +7 -0
- package/src/components/confirm-dialog.tsx +3 -3
- package/src/components/danger-confirm.tsx +3 -3
- package/src/components/data-table-fit.ts +41 -6
- package/src/components/data-table-mobile.tsx +162 -11
- package/src/components/data-table-row-actions.tsx +9 -1
- package/src/components/data-table-row.tsx +2 -0
- package/src/components/data-table.tsx +82 -18
- package/src/components/error-boundary.tsx +2 -2
- package/src/components/floating-panel.tsx +67 -16
- package/src/components/form-actions.tsx +2 -2
- package/src/components/icon-button.tsx +21 -8
- package/src/components/nav-pills.tsx +29 -2
- package/src/components/page-header-context.ts +8 -0
- package/src/components/page-header.tsx +34 -2
- package/src/components/pie-chart.tsx +2 -1
- package/src/components/progress-bar.tsx +6 -3
- package/src/components/reauth-dialog.tsx +1 -1
- package/src/components/row-actions-labels.ts +2 -0
- package/src/components/row-actions.tsx +154 -33
- package/src/components/section-nav.tsx +65 -0
- package/src/components/series-chart.tsx +12 -3
- package/src/components/share-card.tsx +1 -1
- package/src/components/signature-pad.tsx +1 -1
- package/src/components/sparkline.tsx +2 -1
- package/src/components/stat-tile.tsx +19 -7
- package/src/components/status-dot.tsx +7 -1
- package/src/components/tooltip.tsx +3 -1
- package/src/components/translation-review-editor.tsx +2 -2
- package/src/components/translation-review.tsx +2 -2
- package/src/components/treemap.tsx +34 -8
- package/src/components/use-table-state.ts +63 -8
- package/src/data-table.ts +3 -3
- package/src/demo/demo-banner.tsx +1 -1
- package/src/demo/demo-ended.tsx +1 -1
- package/src/demo/demo-start.tsx +1 -1
- package/src/feedback/feedback-inbox.tsx +1 -1
- package/src/hooks/use-dismiss.ts +43 -4
- package/src/hooks/use-document-title.ts +31 -0
- package/src/i18n/german.ts +4 -0
- package/src/i18n/kit-labels.tsx +76 -1
- package/src/i18n/locales/es.ts +4 -0
- package/src/i18n/locales/fr.ts +4 -0
- package/src/i18n/locales/hu.ts +4 -0
- package/src/i18n/locales/it.ts +4 -0
- package/src/i18n/locales/zh.ts +4 -0
- package/src/i18n/review.ts +2 -0
- package/src/i18n/shared-labels.ts +1 -0
- package/src/index.ts +13 -0
- package/src/landing/landing-actions.tsx +2 -2
- package/src/landing/public-header.tsx +2 -2
- package/src/lib/clipboard-minus.ts +94 -0
- package/src/lib/document-title.ts +41 -0
- package/src/lib/float-clearance.ts +19 -3
- package/src/lib/format.ts +115 -30
- package/src/lib/minus.ts +40 -0
- package/src/lib/status-tone.ts +43 -0
- package/src/settings/settings-layout.tsx +3 -2
- package/src/shell/account-menu-language.tsx +14 -2
- package/src/shell/app-shell-labels.ts +1 -0
- package/src/shell/app-shell.tsx +291 -68
- package/src/shell/language-code.ts +5 -0
- package/src/shell/topbar-controls.tsx +35 -15
- package/src/testing/css-variables.generated.ts +6 -6
- package/src/theme/chart-palette.ts +102 -20
- package/src/theme/palette-presets.ts +121 -84
- package/src/tour/tour.tsx +1 -1
- package/src/wizard/stepper-nav.tsx +4 -4
- package/tokens.css +28 -18
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n//\n// Grouped by folder. A subpath entry (chart, data-table, shell, feedback, wizard, tour,\n// search) is re-exported whole — `export * from \"./chart\"` — instead of its list typed out a\n// second time here: the two copies had drifted (refactor audit 2026-10, MOD-5). A name that\n// arrives twice that way is the same binding from the same module, which ESM does not count\n// as a clash.\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Intl number / money / percent / date / relative-time formatting, and `useKitFormat()`\n// for the same bound to the provider's locale (kastlan's formatters.ts, English \"5m ago\").\nexport * from \"./lib/format\";\n// localStorage that never throws (Safari private mode, blocked site data).\nexport { readStored, writeStored } from \"./lib/safe-storage\";\n// Save a fetched Blob as a download, and read the name a Content-Disposition asks for\n// (`filename*` first) — 0.34, KS U5; the kit's own three downloads use them.\nexport { saveBlob, filenameFromDisposition } from \"./lib/download\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n// One fold and one ranking for every list's search box (DUP-5), for an app's own lists.\nexport { foldForSearch, rankMatch } from \"./lib/text-match\";\nexport type { MatchRank } from \"./lib/text-match\";\n// 0.12.0: the QR encoder QrCode draws with — no dependency, see lib/qr-encode.ts.\nexport { encodeQr } from \"./lib/qr-encode\";\nexport type { QrEncodeOptions, QrErrorCorrection, QrMatrix } from \"./lib/qr-encode\";\n// 0.18: the cold-start notice keksdose built (#199), for every app: the framework-free\n// watchdog over the app's requests (the corner notice is components/server-wake).\nexport { createServerWake, serverWake, watchReadsAnd, attachServerWake, wrapFetch } from \"./lib/server-wake\";\nexport type { ServerWakeStage, ServerWakeFilter, ServerWakeOptions, ServerWakeRequest, ServerWakeWatcher, ServerWakeAxiosConfig, AxiosLikeInstance } from \"./lib/server-wake\";\n// 0.34 (docs/auth-harmonization.md §11, round 0.34 C7): renewing a session — one refresh\n// per tab, a definitive failure ends the session once, a transient one keeps it.\nexport { createSessionRefresh, attachSessionRefresh, isTransientRefreshFailure, isSignedOutStep } from \"./lib/session-refresh\";\nexport type { SessionRefresh, SessionRefreshOptions, SessionRenewal, SessionRefreshOutcome } from \"./lib/session-refresh\";\n// 0.29.0 (docs/auth-harmonization.md): the person-name order of each language.\nexport { formatPersonName, personInitials } from \"./lib/person-name\";\nexport type { PersonName } from \"./lib/person-name\";\n// Translation review (0.19): one contract for kastlan's and keksdose's review pages — the\n// pure rows/status/placeholder logic here, the presentational page parts under components.\nexport {\n REVIEW_STATUSES,\n fromApiReview,\n toApiWrite,\n flattenStrings,\n keyNamespace,\n placeholderTokens,\n placeholderMismatch,\n reviewStatus,\n keyInArea,\n keyInAreas,\n // 0.28: the area a key is grouped under — `kit.legal.*` in `legal` (legal round §7.5).\n reviewAreaOf,\n translationRows,\n summariseRows,\n DEFAULT_TRANSLATION_REVIEW_FILTER,\n filterTranslationRows,\n reviewWrite,\n mergeReviews,\n dropReviews,\n translationCorrections,\n // 0.25: grouping and the approvals' Undo (keksdose live #377).\n groupTranslationRows,\n unreviewedRows,\n reviewUndo,\n // 0.26: swipe bindings for an app's Settings → Interaction (keksdose #377 rework).\n TRANSLATION_REVIEW_SWIPE_ACTIONS,\n DEFAULT_TRANSLATION_REVIEW_SWIPE,\n translationReviewSwipePlan,\n} from \"./lib/translation-review\";\nexport type {\n TranslationVerdict,\n TranslationReview,\n TranslationReviewWrite,\n TranslationReviewKey,\n ReviewStatus,\n TranslationRow,\n ApiTranslationReview,\n ApiTranslationReviewsResponse,\n ApiTranslationReviewWrite,\n TranslationRowsInput,\n TranslationSummary,\n TranslationReviewFilter,\n TranslationCorrection,\n TranslationRowGroup,\n TranslationReviewUndo,\n TranslationReviewSwipeAction,\n TranslationReviewSwipeBinding,\n} from \"./lib/translation-review\";\n// 0.22.0, the inputs round: the country list and the IBAN, ISIN and phone helpers that\n// CountrySelect, IbanInput and PhoneInput are built on.\nexport { COUNTRY_CODES, countryName } from \"./lib/countries\";\nexport {\n IBAN_LENGTHS,\n compactIban,\n formatIban,\n ibanCheckDigits,\n ibanProblem,\n isValidIban,\n isQrIban,\n} from \"./lib/iban\";\nexport type { IbanKind, IbanProblem } from \"./lib/iban\";\nexport { formatIsin, isinCheckDigit, isValidIsin } from \"./lib/isin\";\nexport {\n PHONE_DIAL_CODES,\n PHONE_COUNTRIES,\n parsePhone,\n formatNationalPhone,\n formatPhone,\n isE164,\n} from \"./lib/phone\";\nexport type { PhoneCountryCode, PhoneCountry, ParsedPhone } from \"./lib/phone\";\n// 0.23.0: ColumnMapper's pure half (Kurvenschmiede's columns input, keksdose's import map).\nexport {\n assignColumnRole,\n guessMapping,\n missingRoles,\n readMappedTable,\n readTextFile,\n roleOfColumn,\n} from \"./lib/column-mapping\";\nexport type { ColumnMapperResult, ColumnMapping, ColumnRole } from \"./lib/column-mapping\";\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport {\n useAnchoredPanel,\n anchoredPanelPlacement,\n useVisualViewport,\n readKeyboardInset,\n} from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n KeyboardInsetOptions,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\n// Focus containment for an overlay, and a live region for a change that moves no focus.\n// Both were extracted from the two components that already did them correctly (Modal and\n// CommandPalette) so the rest of the kit stops being the exception.\nexport { useFocusTrap } from \"./hooks/use-focus-trap\";\nexport type { FocusTrapOptions } from \"./hooks/use-focus-trap\";\nexport { useAnnounce } from \"./hooks/use-announce\";\nexport type { UseAnnounceReturn, UseAnnounceOptions, AnnounceRegionProps } from \"./hooks/use-announce\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\n// 0.28: keksdose's noindex marker, for the legal and auth pages of every app.\nexport { useNoIndex } from \"./hooks/use-noindex\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// 0.25: several keys, one navigation (keksdose live #378 — four setters in a row clobbered).\nexport { useSearchParamsState } from \"./hooks/use-search-param-state\";\nexport type { SearchParamField, SearchParamFields, SearchParamsUpdate } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n// Row windowing for a long list (0.7.0, lenkbank's measured grid is built on it).\nexport { useWindowedRows, WINDOWED_ROW_INDEX } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// 0.32.0 (docs/text-size-harmonization.md): the breakpoints, and the hooks components read\n// the behaviours at Large from (§4, §10.7–10.9).\nexport { useBreakpoint, usePhoneLayout, breakpointQuery, BREAKPOINT_REM, remPx, useRemPx } from \"./hooks/use-breakpoint\";\nexport type { Breakpoint, BreakpointVariant, RemLength } from \"./hooks/use-breakpoint\";\nexport { useLargeText, useCoarsePointer, useInlineFacts } from \"./hooks/use-large-text\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\n// The chart palette (theme/chart-palette) comes with the chart kit, `./chart` below.\n// Colour maths (sRGB ↔ OKLCH, WCAG contrast, CVD simulation) and the palette deriver\n// that builds a whole, contrast-solved palette from one brand colour plus any colours\n// pinned by hand. `auditPalette` / `auditChartRamp` measure a palette rather than\n// trusting a comment about it.\nexport * from \"./theme/color\";\nexport * from \"./theme/palette-derive\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n// 0.32.0: text size and contrast (docs/text-size-harmonization.md).\nexport * from \"./theme/text-size\";\nexport * from \"./theme/contrast\";\n\n// ── i18n: one label tree, one optional provider ──────────────────────────────\n// `UiKitLabels` names every string the kit renders; `<UiKitProvider labels locale>`\n// hands a translation to every component below it. Precedence: a component's own\n// prop > the provider > the English default. See src/i18n/kit-labels.tsx.\nexport * from \"./i18n/kit-labels\";\nexport * from \"./i18n/defaults\";\n// The kit's words as `key → text` rows for an app's translation review (keksdose).\nexport { kitLabelStrings } from \"./i18n/review\";\nexport type { KitLabelStringsOptions } from \"./i18n/review\";\n// The seven languages, how an app resolves one, and the kit catalogue loader for it.\nexport * from \"./i18n/languages\";\n// CLDR plural categories for an app's i18next catalogue, filled from `_other`; and the\n// forms of an app's word a kit part picks from by count (0.33.1, `PlanColumnUsage.label`).\nexport { withAllPlurals } from \"./i18n/plurals\";\nexport type { PluralForms } from \"./i18n/plurals\";\n\n// ── components ───────────────────────────────────────────────────────────────\n// The kit's core controls, one module each since 0.34 (MOD-2, refactor audit 2026-10):\n// Button, IconButton, the field base, Input, Select, Textarea, Card, Spinner, EmptyState\n// and Tabs. Named, not `*`, for `button-look` and `field-base`: they also hold parts the\n// controls share, which are internal. The others are public whole.\nexport * from \"./components/button\";\nexport {\n buttonClasses,\n TOUCH_TARGET_LARGE,\n type ButtonClassesOptions,\n type ButtonSize,\n type ButtonTone,\n type ButtonVariant,\n} from \"./components/button-look\";\nexport * from \"./components/icon-button\";\nexport {\n FIELD_TOUCH_TEXT,\n FIELD_BASE,\n FIELD_WRITABLE_LOOK,\n FIELD_FLOATING_PAD,\n FIELD_INVALID,\n FLOATING_INPUT_CLASS,\n FIELD_DISPLAY,\n FIELD_TRIGGER,\n FieldChevron,\n FLOATING_LABEL_CLASS,\n FloatingField,\n Label,\n DEFAULT_PASSWORD_REVEAL_LABELS,\n DEFAULT_CHARACTER_COUNT_LABELS,\n type FieldChevronProps,\n type FloatingFieldProps,\n type LabelProps,\n type PasswordRevealLabels,\n type CharacterCountLabels,\n} from \"./components/field-base\";\nexport * from \"./components/input\";\nexport * from \"./components/select\";\nexport * from \"./components/textarea\";\nexport * from \"./components/card\";\nexport * from \"./components/spinner\";\nexport * from \"./components/empty-state\";\nexport * from \"./components/tabs\";\n// The static label lives in field-parts since 0.23 (it is what the field anatomy there\n// draws, and field-parts must not import the controls).\nexport { FieldLabel, FLOATING_LABEL_STATIC, FieldHint } from \"./components/field-parts\";\nexport type { FieldLabelProps, FieldHintProps } from \"./components/field-parts\";\n// The kit's focus frame (§5), in its own module so the parts the controls import\n// (field-parts, the choice controls) can draw it too.\nexport { FOCUS_RING, FOCUS_RING_WIDTH } from \"./components/focus-ring\";\n// No fact only in a tooltip (§4): the reason line and the compact region live in\n// field-parts, where the self-saving controls (Switch, Checkbox) reach them too.\nexport {\n CompactControls,\n DisabledReasonLine,\n DISABLED_REASON_LINE_CLASS,\n useDisabledReasonLine,\n} from \"./components/field-parts\";\nexport type { DisabledReasonDisplay } from \"./components/field-parts\";\n// The label-ABOVE field group (label, hint, error, required), inside wizards or out.\nexport * from \"./components/field\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\n// 0.34 (keksdose K3): paragraph-long help behind a \"?\", opened on a tap — FieldHint's\n// sibling for help rather than a fact (docs/text-size-harmonization.md §10.23).\nexport { HelpPopover } from \"./components/help-popover\";\nexport type { HelpPopoverProps } from \"./components/help-popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipePaint, SwipeTone, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\n// 0.35: each currency's flag-icons country. `CURRENCIES` and it are also the pure-data\n// entry \"@eifi1/ui-kit/currencies\", which imports nothing, for an app's build in Node.\nexport { CURRENCY_COUNTRIES } from \"./currencies\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/money-field\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\n// Sync state for a database-backed field: the engine (`useFieldSync`) and the\n// affordance (`FieldSyncIndicator`), kept separate because the state is useful\n// without the dot — a form can gate its submit on any field being `pending`.\nexport * from \"./components/field-sync\";\nexport * from \"./components/month-picker\";\nexport * from \"./components/checkbox\";\nexport * from \"./components/switch\";\nexport * from \"./components/slider\";\nexport * from \"./components/time-input\";\nexport * from \"./components/number-field\";\nexport * from \"./components/sparkline\";\nexport * from \"./components/stat-tile\";\nexport * from \"./components/signature-pad\";\nexport * from \"./components/password-strength\";\nexport * from \"./components/page-contents\";\nexport * from \"./components/disclosure\";\nexport * from \"./components/dialog-frame\";\n// Named, not `*`: danger-confirm also holds the password field and pending hook that\n// ReauthDialog shares with it, which are kit-internal.\nexport {\n DangerConfirm,\n DEFAULT_DANGER_CONFIRM_LABELS,\n typedMatches,\n // 0.22.0: the typed-confirmation field on its own (keksdose K7) and the current-password\n // field kastlan wants for sign-in and re-authentication (kastlan 1).\n TypedConfirmField,\n CurrentPasswordInput,\n} from \"./components/danger-confirm\";\nexport type {\n DangerConfirmLabels,\n DangerConfirmProps,\n TypedMatch,\n DangerConsequence,\n TypedConfirmFieldProps,\n TypedConfirmFieldLabels,\n CurrentPasswordInputProps,\n CurrentPasswordInputLabels,\n // 0.23.0: onConfirm's second argument — the guards' values (keksdose G4b).\n DangerConfirmValues,\n} from \"./components/danger-confirm\";\n// 0.18: re-authentication before a sensitive action (Kurvenschmiede 4).\nexport { ReauthDialog, DEFAULT_REAUTH_DIALOG_LABELS } from \"./components/reauth-dialog\";\nexport type { ReauthDialogProps, ReauthDialogLabels } from \"./components/reauth-dialog\";\n// `useConfirm()` — the promise-based replacement for `window.confirm`, one host per app.\nexport * from \"./components/confirm-dialog\";\n// A non-modal corner panel and its round trigger (keksdose's assistant launcher).\nexport * from \"./components/floating-panel\";\n// The count / clear / actions bar a selection brings up (keksdose's three copies).\nexport * from \"./components/bulk-action-bar\";\nexport * from \"./components/swatch-picker\";\nexport * from \"./components/icon-picker\";\nexport * from \"./components/choice-card\";\nexport * from \"./components/autocomplete\";\nexport * from \"./components/measured-grid\";\n// Named, not `export *`: file-button.tsx also re-exports the screening helpers the\n// dropzone shares (hooks/use-file-picker since 0.34, MOD-8), which are internal.\nexport { FileButton, useFilePicker, matchesAccept, DEFAULT_FILE_PICKER_LABELS } from \"./components/file-button\";\nexport type {\n FileButtonProps,\n UseFilePickerOptions,\n UseFilePickerReturn,\n FilePickerLabels,\n FileRejection,\n FileRejectionReason,\n FileScreenOptions,\n} from \"./components/file-button\";\n// The chart kit, whole, from its subpath (`@eifi1/ui-kit/chart`, which names its parts):\n// the chart shell and its palette, the treemap, the series chart with its zoom, legend,\n// labels and facing-pair axes, the height every chart takes, and the pie chart.\nexport * from \"./chart\";\n// 0.12.0: the QR code TwoFactorSetting draws its otpauth URI with (encoder in\n// lib/qr-encode.ts — no dependency, see there).\nexport * from \"./components/qr-code\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\n// A wrapping set of links/buttons marked `aria-current` — Tabs-like looks, not tabs.\nexport * from \"./components/nav-pills\";\n// A pill carrying one VALUE — inert, a link, or a toggle, depending on which prop it is\n// given — and the list field built from it. Distinct from Button on purpose: a row of\n// buttons reads as \"choose an action\", a row of chips as \"here are the things\".\nexport * from \"./components/chip\";\n// ChipInput's own module since MOD-9: it renders Chip, so chip.tsx re-exports only its types.\nexport * from \"./components/chip-input\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/calendar-heatmap\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/tree-view\";\n// 0.8.0 layout and feedback primitives the apps hand-rolled or took from shadcn/Radix.\nexport * from \"./components/description-list\";\n// The Save / Cancel row forms and dialogs end in, and the editable line-item repeater\n// (journal lines, lease components, invoice positions). 0.12.0.\nexport * from \"./components/form-actions\";\n// 0.18: lock every opted-in commit under one provider, the reason in its tooltip\n// (Kurvenschmiede 2). `useCommitReason` stays internal.\n// 0.33: a lock says its source, and a control can be exempt from one\n// (docs/billing-harmonization.md §12.36): the kinds, the holds, `CommitScope`,\n// `COMMIT_EXCEPT_BILLING` and the pure `writeLockFor`.\nexport { WriteLockProvider, useWriteLock, writeLockFor, COMMIT_EXCEPT_BILLING, DEFAULT_WRITE_LOCK_LABELS } from \"./components/write-lock\";\n// 0.46 (kastlan K4): the offline lock kind, its scope and its source.\nexport { OFFLINE_LOCK, COMMIT_EXCEPT_OFFLINE, useOfflineWriteLock } from \"./components/write-lock\";\nexport type { WriteLock, WriteLockLabels, WriteLockProviderProps, WriteLockKind, WriteLockHold, CommitScope } from \"./components/write-lock\";\n// 0.18: the parts both apps' admin rosters repeat (Kurvenschmiede 6).\nexport { RoleChip, AccountStateChip, DateMark, dateColumn, DEFAULT_ACCOUNT_STATE_LABELS, ACCOUNT_STATE_TONES } from \"./components/account-chips\";\nexport type { RoleChipProps, RoleDefinition, RoleVocabulary, AccountState, AccountStateLabels, AccountStateChipProps, DateMarkProps, DateColumnOptions } from \"./components/account-chips\";\n// 0.42 (docs/admin-harmonization.md §2.1): the role in the account menu's header, a link\n// to the role's tool (`RoleDefinition.href`).\nexport { AccountRoleChip } from \"./components/account-chips\";\nexport type { AccountRoleChipProps } from \"./components/account-chips\";\n// 0.18: the cold-start notice keksdose built (#199), for every app: the corner notice\n// that explains the wait (its framework-free watchdog is lib/server-wake).\nexport { ServerWakeNotice, useServerWakeStage, DEFAULT_SERVER_WAKE_LABELS } from \"./components/server-wake\";\nexport type { ServerWakeLabels, ServerWakeNoticeProps } from \"./components/server-wake\";\n// 0.18: sharing — grantees, roles, pending grants, candidates (Kurvenschmiede 1).\nexport { ShareCard, ShareDialog, SharePanel, DEFAULT_SHARE_CARD_LABELS } from \"./components/share-card\";\nexport type { ShareCardProps, ShareDialogProps, SharePanelProps, ShareCardLabels, ShareRole, ShareGrantee, SharePendingGrant, ShareCandidate, ShareAddRequest } from \"./components/share-card\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.48 (keksdose dev #628): the table/list loading preset, one status label.\nexport { TableSkeleton } from \"./components/table-skeleton\";\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\nexport * from \"./components/image-grid\";\nexport * from \"./components/lightbox\";\nexport * from \"./components/button-group\";\nexport * from \"./components/table\";\nexport * from \"./components/separator\";\n// Named: scroll-area.tsx also holds the overflow hook and scrollbar class Table shares.\nexport { ScrollArea } from \"./components/scroll-area\";\nexport type { ScrollAreaProps } from \"./components/scroll-area\";\n// 0.10.0 rows, menu rows, text primitives and page chrome the apps drew by hand.\nexport * from \"./components/list\";\nexport * from \"./components/menu-item\";\nexport * from \"./components/text\";\nexport * from \"./components/status-dot\";\nexport * from \"./components/page-header\";\nexport * from \"./components/breadcrumbs\";\n// The one inline link (kastlan's EntityLink / CellLink / legal and source links), through\n// `<UiKitProvider linkComponent>`. Named: the file also holds the kit's internal link picker.\nexport { TextLink } from \"./components/text-link\";\nexport type {\n TextLinkProps,\n TextLinkRenderProps,\n TextLinkTone,\n TextLinkUnderline,\n TextLinkCurrent,\n} from \"./components/text-link\";\n// The toast layer over sonner (an OPTIONAL peer, loaded lazily): `toast` mirrors sonner's\n// API so apps migrate by swapping the import; `<Toaster>` carries the placement, theme,\n// tones and z-index both apps had wired by hand.\nexport {\n toast,\n Toaster,\n DEFAULT_TOAST_LABELS,\n TOAST_ACTION_DURATION,\n TOASTER_OFFSET_TOP,\n TOASTER_OFFSET_BOTTOM,\n} from \"./components/toast\";\nexport type {\n ToastId,\n ToastAction,\n ToastOptions,\n ToastPromiseOptions,\n ToastUndoOptions,\n ToastRedoOptions,\n ToastLabels,\n ToastPosition,\n ToastSwipeDirection,\n ToasterOffset,\n ToasterProps,\n} from \"./components/toast\";\n// Translation review (0.19): the presentational page parts (the pure logic is\n// lib/translation-review).\nexport {\n TranslationReviewPanel,\n TranslationReviewEditor,\n ReviewStatusChip,\n TranslationProgress,\n TranslationLocaleTabs,\n TranslationExportButton,\n REVIEW_STATUS_TONES,\n DEFAULT_TRANSLATION_REVIEW_LABELS,\n} from \"./components/translation-review\";\nexport type {\n TranslationReviewPanelProps,\n TranslationReviewEditorProps,\n ReviewStatusChipProps,\n TranslationProgressProps,\n TranslationLocaleTab,\n TranslationLocaleTabsProps,\n TranslationExportButtonProps,\n TranslationReviewLabels,\n TranslationReviewSaveInfo,\n TranslationReviewOrigin,\n TranslationReviewGroupBy,\n} from \"./components/translation-review\";\n// The legal pages' shell (0.19, H10): Imprint, Privacy Policy, Terms in every app.\n// 0.28 (docs/legal-harmonization.md): the shared wording, the page frame, the kit's\n// sections, the public footer and the terms checkbox.\nexport {\n LegalLayout,\n LegalSection,\n LegalLinks,\n LegalFooter,\n DEFAULT_LEGAL_LABELS,\n LEGAL_HREFS,\n legalOperatorText,\n useLegalLabels,\n} from \"./components/legal\";\nexport type {\n LegalLabels,\n LegalLink,\n LegalLinksProps,\n LegalSectionProps,\n LegalLayoutProps,\n LegalFooterProps,\n LegalOperator,\n LegalOperatorText,\n LegalPageKey,\n LegalTextSectionLabels,\n LegalOperatorSectionLabels,\n LegalFramedSectionLabels,\n LegalDisclaimerSectionLabels,\n} from \"./components/legal\";\nexport { LegalPage, LegalKitSection, LegalAcceptCheckbox, LEGAL_SKELETON } from \"./components/legal-page\";\nexport type {\n LegalPageProps,\n LegalKitSectionProps,\n LegalKitSectionKey,\n LegalAcceptCheckboxProps,\n LegalSkeletonEntry,\n LegalSkeletonPage,\n LegalSectionOwner,\n LegalDisclaimerVariant,\n} from \"./components/legal-page\";\n// 0.32.0 (docs/text-size-harmonization.md): the appearance settings' words, and a row's\n// actions, one of the behaviours at Large (§4, §10.7–10.9).\nexport { DEFAULT_APPEARANCE_LABELS, useAppearanceLabels } from \"./components/appearance-labels\";\nexport type { AppearanceLabels } from \"./components/appearance-labels\";\n// 0.46 (keksdose's date format, lifted): the preference, its resolver and renderer, the\n// provider's formatter for it, and the settings field.\nexport {\n DATE_FORMAT_PREFERENCES,\n isDateFormatPreference,\n resolveDateFormat,\n formatDateWithPreference,\n dateFormatSample,\n dateFormatterFor,\n} from \"./lib/date-format\";\nexport type { DateFormatPreference, DateFormatOptions, ResolvedDateFormat } from \"./lib/date-format\";\nexport { DateFormatSetting } from \"./components/date-format-setting\";\nexport type { DateFormatSettingProps } from \"./components/date-format-setting\";\nexport {\n RowActions,\n rowActionsColumn,\n DEFAULT_ROW_ACTIONS_LABELS,\n // 0.47.0 (keksdose N17): a hand-built table's actions heading and cell.\n RowActionsHead,\n ROW_ACTIONS_CELL_CLASS,\n ROW_ACTIONS_HEAD_CLASS,\n} from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\n RowActionsHeadProps,\n RowActionTone,\n} from \"./components/row-actions\";\n// 0.22.0: the inputs round (kastlan's, keksdose's and Kurvenschmiede's audits).\nexport * from \"./components/checkbox-group\";\nexport * from \"./components/one-time-code-input\";\nexport * from \"./components/language-select\";\nexport * from \"./components/tile-radio\";\nexport * from \"./components/inline-edit-field\";\nexport * from \"./components/sign-chip\";\nexport * from \"./components/country-select\";\nexport * from \"./components/iban-input\";\nexport * from \"./components/phone-input\";\n// 0.23.0, the apps' 0.22 adoption round: the label strip over custom content (keksdose G8).\nexport * from \"./components/field-strip\";\n// Paste or drop a table, give each column a role (Kurvenschmiede's columns input,\n// keksdose's import map step). The lexer itself stays in `@eifi1/ui-kit/table-text`.\nexport * from \"./components/column-mapper\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\n// Whole, from its subpath (`@eifi1/ui-kit/data-table`, which names its parts): DataTable,\n// its sort, filters, pagination and cells, and a server table's state held by its owner,\n// URL-synced.\nexport * from \"./data-table\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\n// Whole, from `@eifi1/ui-kit/shell`: the top bar and its controls, AppShell, the switchers\n// and AuthLayout, and (0.31.0) the router-aware parts of settings and landing —\n// SettingsLayout with its route, focus, section, context, heading and catalogue;\n// PublicHeader, RootEntry, RedirectIfAuthed and the last-visited page.\nexport * from \"./shell\";\n// 0.29.0 (docs/auth-harmonization.md): kastlan's company switcher.\nexport { CompanySwitcher, DEFAULT_COMPANY_SWITCHER_LABELS } from \"./shell/company-switcher\";\nexport type { CompanySwitcherProps, CompanySwitcherLabels, CompanySwitcherCompany } from \"./shell/company-switcher\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it. Whole, from `@eifi1/ui-kit/feedback`, which also has 0.27.0's\n// harmonization (docs/feedback-harmonization.md): the record, menu, table, detail and\n// crash reporter.\nexport * from \"./feedback\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// `wizard-field` was removed here rather than kept as stock: it held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app — a\n// field group nothing was built from, which this comment used to advertise. A design\n// system may carry stock; untested stock nothing has ever rendered is not stock, it is\n// a liability with an export. The react-hook-form bridge to the Next gate\n// (`useRhfWizardStep`) is NOT here either: it left the barrel in 0.4.x so the barrel\n// imports no react-hook-form, and came back in 0.11 under `@eifi1/ui-kit/rhf`\n// (src/rhf.ts), where the optional peer is that subpath's alone.\n// Whole, from `@eifi1/ui-kit/wizard`.\nexport * from \"./wizard\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\n// The palette, its pure matcher and the ⌘K search on it. The list fold every search box\n// shares is lib/text-match, above.\nexport * from \"./search\";\n\n// ── auth ─────────────────────────────────────────────────────────────────────\n// 0.29.0 (docs/auth-harmonization.md): sign-in, sign-up and the signed-out pages — forms\n// that take callbacks and never send a request themselves. The person-name order of each\n// language is lib/person-name, kastlan's company switcher is in the shell section.\nexport { SignInForm, DEFAULT_SIGN_IN_LABELS } from \"./auth/sign-in-form\";\nexport type {\n SignInFormProps,\n SignInLabels,\n SignInAnswer,\n SignInStep,\n SignInAction,\n SignInCredentials,\n SignInCodeValues,\n SignInNewPasswordValues,\n} from \"./auth/sign-in-form\";\nexport { RegisterForm, DEFAULT_REGISTER_LABELS } from \"./auth/register-form\";\nexport type { RegisterFormProps, RegisterLabels, RegisterValues } from \"./auth/register-form\";\nexport { CompleteNameDialog, DEFAULT_COMPLETE_NAME_LABELS } from \"./auth/complete-name-dialog\";\nexport type { CompleteNameDialogProps, CompleteNameLabels, CompleteNameValues } from \"./auth/complete-name-dialog\";\nexport { taggedEmail } from \"./auth/email-tag\";\nexport { isAuthError, authErrorCode, isBillingError } from \"./auth/auth-errors\";\nexport type { AuthErrorCode } from \"./auth/auth-errors\";\nexport { ForgotPasswordForm, DEFAULT_FORGOT_PASSWORD_LABELS } from \"./auth/forgot-password-form\";\nexport type { ForgotPasswordFormProps, ForgotPasswordLabels } from \"./auth/forgot-password-form\";\nexport { ResetPasswordForm, DEFAULT_RESET_PASSWORD_LABELS } from \"./auth/reset-password-form\";\nexport type {\n ResetPasswordFormProps,\n ResetPasswordLabels,\n ResetPasswordCheck,\n ResetPasswordValues,\n ResetPasswordResult,\n} from \"./auth/reset-password-form\";\nexport { VerifyEmailStatus, EmailVerificationBanner, DEFAULT_VERIFY_EMAIL_LABELS } from \"./auth/verify-email\";\nexport type {\n VerifyEmailStatusProps,\n EmailVerificationBannerProps,\n VerifyEmailLabels,\n VerifyEmailFailure,\n} from \"./auth/verify-email\";\nexport { NotFoundPage, DEFAULT_NOT_FOUND_LABELS } from \"./auth/not-found-page\";\nexport type { NotFoundPageProps, NotFoundLabels } from \"./auth/not-found-page\";\nexport { AcceptInvitation, DEFAULT_ACCEPT_INVITATION_LABELS } from \"./auth/accept-invitation\";\nexport type {\n AcceptInvitationProps,\n AcceptInvitationLabels,\n AcceptInvitationResult,\n AcceptInvitationFailure,\n} from \"./auth/accept-invitation\";\nexport type { AuthHeadingLevel } from \"./auth/status-parts\";\n// 0.30.0: a rate limit and its wait, and the codes the account, billing and demo calls\n// answer with.\nexport { isRateLimited, retryAfterSeconds } from \"./auth/auth-errors\";\nexport type { AccountErrorCode, BillingErrorCode, DemoErrorCode, KitErrorCode } from \"./auth/auth-errors\";\n\n// ── account ──────────────────────────────────────────────────────────────────\n// In account/ since 0.34, beside the other account cards (MOD-8, refactor audit 2026-10):\n// the profile, password and two-factor cards, and (0.12.0) the fourth account section,\n// the passkeys.\nexport * from \"./account/account-settings\";\nexport * from \"./account/passkeys-setting\";\n// 0.30.0 (docs/user-admin-harmonization.md): the account's own settings — email change,\n// sessions, deletion, export. Callbacks only; the confirmation level is the server's.\nexport { EmailChangeSetting, DEFAULT_EMAIL_CHANGE_LABELS } from \"./account/email-change-setting\";\nexport type {\n EmailChangeSettingProps,\n EmailChangeLabels,\n EmailChangeValues,\n EmailChangeAction,\n} from \"./account/email-change-setting\";\nexport { SessionsSetting, DEFAULT_SESSIONS_LABELS } from \"./account/sessions-setting\";\nexport type { SessionsSettingProps, SessionsLabels, SessionItem, SessionId, SessionsAction } from \"./account/sessions-setting\";\nexport { DeleteAccountSetting, DEFAULT_DELETE_ACCOUNT_LABELS } from \"./account/delete-account-setting\";\nexport type {\n DeleteAccountSettingProps,\n DeleteAccountLabels,\n DeleteAccountValues,\n DeletionMode,\n DeleteAccountConsequence,\n} from \"./account/delete-account-setting\";\nexport { DataExportSetting, DEFAULT_DATA_EXPORT_LABELS } from \"./account/data-export-setting\";\nexport type { DataExportSettingProps, DataExportLabels, DataExportFile } from \"./account/data-export-setting\";\n\n// ── admin ────────────────────────────────────────────────────────────────────\n// 0.30.0 (docs/user-admin-harmonization.md): the admin user list and its actions, and the\n// invitations panel. Callbacks only; the confirmation level is the server's.\nexport {\n userRosterColumns,\n useUserRosterColumns,\n UserIdentityCell,\n UserRowActions,\n adminUserStates,\n userRosterSort,\n USER_ROSTER_SORT_KEYS,\n DEFAULT_USER_ROSTER_LABELS,\n} from \"./admin/user-roster\";\nexport type {\n UserRosterRow,\n AdminUserStateFields,\n RosterState,\n UserRosterSortKey,\n UserRosterLabels,\n UserIdentityCellProps,\n UserRowAction,\n UserRowActionList,\n UserRowActionsProps,\n RoleEditing,\n UserRosterColumnsOptions,\n} from \"./admin/user-roster\";\nexport { RoleSelect, RolesEditor, DEFAULT_ROLE_SELECT_LABELS } from \"./admin/role-select\";\nexport type { RoleSelectProps, RolesEditorProps, RoleSelectLabels, RoleLock, RoleLockCode } from \"./admin/role-select\";\nexport { ReviewerScopeEditor, DEFAULT_REVIEWER_SCOPE_LABELS } from \"./admin/reviewer-scope-editor\";\nexport type {\n ReviewerScope,\n ReviewerScopeArea,\n ReviewerScopeLanguage,\n ReviewerScopeLabels,\n ReviewerScopeEditorProps,\n} from \"./admin/reviewer-scope-editor\";\nexport { AdminActionConfirm, DEFAULT_ADMIN_ACTION_LABELS } from \"./admin/admin-action-confirm\";\nexport type {\n AdminConfirmLevel,\n AdminActionConfirmValues,\n AdminActionTarget,\n AdminActionLabels,\n AdminActionConfirmProps,\n} from \"./admin/admin-action-confirm\";\nexport { AdminActionLog, ADMIN_ACTION_KINDS, DEFAULT_ADMIN_ACTION_LOG_LABELS } from \"./admin/admin-action-log\";\nexport type {\n AdminActionKind,\n AdminActionLogEntry,\n AdminActionLogLabels,\n AdminActionLogPaging,\n AdminActionLogProps,\n // 0.34 (docs/user-admin-harmonization.md §11): a log target that is not a person, and\n // the app's noun for its groups.\n AdminGroupTarget,\n AdminOtherTarget,\n AdminGroupNoun,\n} from \"./admin/admin-action-log\";\nexport { TransferOwnershipDialog, DEFAULT_TRANSFER_OWNERSHIP_LABELS } from \"./admin/transfer-ownership-dialog\";\nexport type {\n TransferCandidate,\n TransferUnavailable,\n TransferValues,\n TransferOwnershipLabels,\n TransferOwnershipDialogProps,\n} from \"./admin/transfer-ownership-dialog\";\nexport { InvitationsPanel, DEFAULT_INVITATIONS_LABELS } from \"./admin/invitations-panel\";\nexport type {\n InvitationStatus,\n InvitationRow,\n InvitationDraft,\n InvitationSentAnswer,\n InvitationScope,\n InvitationsLabels,\n InvitationsPanelProps,\n} from \"./admin/invitations-panel\";\nexport type { AdminPerson } from \"./admin/admin-parts\";\n// 0.42.0 (docs/admin-harmonization.md §3.1): the admin area's template — its words, the\n// shared sections and the catalogue helper, the 403 page, the overview and its tiles fed\n// by `GET /admin/attention`, and the Tools list. The menu row is `./shell`'s.\nexport { DEFAULT_ADMIN_AREA_LABELS, useAdminAreaLabels } from \"./admin/admin-area-labels\";\nexport type { AdminAreaLabels, AdminTileLabels, AdminSharedSection } from \"./admin/admin-area-labels\";\nexport { ADMIN_SECTIONS, adminSections } from \"./admin/admin-sections\";\nexport type { AdminSectionDefinition, AdminOwnSection, AdminSectionsOptions } from \"./admin/admin-sections\";\n// 0.43.0 (keksdose): the section order as ids, and the narrowed `leaveOut`.\nexport { adminSectionOrder } from \"./admin/admin-sections\";\nexport type { AdminSectionPlace, AdminSectionOrderOptions, AdminKeptSection } from \"./admin/admin-sections\";\nexport { AdminForbidden } from \"./admin/admin-forbidden\";\nexport type { AdminForbiddenProps } from \"./admin/admin-forbidden\";\nexport { AdminOverview, AttentionTile, adminWaitingCount, DEFAULT_ADMIN_ATTENTION_HREFS } from \"./admin/admin-overview\";\nexport type {\n AdminAttention,\n AdminAttentionTile,\n AdminExtraTile,\n AdminOverviewProps,\n AttentionTileProps,\n // 0.46 (Kurvenschmiede 1): the feedback tiles with the kit's words.\n AdminFeedbackTile,\n AdminFeedbackTileKey,\n AdminOwnTile,\n} from \"./admin/admin-overview\";\nexport { AdminToolLinks } from \"./admin/admin-tool-links\";\nexport type { AdminToolLink, AdminToolLinksProps } from \"./admin/admin-tool-links\";\n// 0.45.0 (docs/admin-harmonization.md §9.2.4): \"Send a test mail to me\".\nexport { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR, maskMailAddress } from \"./admin/mail-test-card\";\nexport type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from \"./admin/mail-test-card\";\n// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).\nexport {\n planColumn,\n usePlanColumn,\n PlanChangeConfirm,\n usePlanChangeResult,\n DEFAULT_PLAN_CHANGE_LABELS,\n} from \"./admin/plan-change\";\nexport type {\n PlanChangeLabels,\n PlanColumnOptions,\n PlanColumnUsage,\n PlanChange,\n PlanChangeConfirmProps,\n PlanChangeOutcome,\n PlanChangeTone,\n PlanChangeLine,\n PlanChangeResultOptions,\n} from \"./admin/plan-change\";\n\n// ── billing ──────────────────────────────────────────────────────────────────\n// 0.32.0: plans, standing, banners, the limit notice (docs/billing-harmonization.md §7).\nexport { DEFAULT_BILLING_LABELS, useBillingLabels, SUBSCRIPTION_STATUSES } from \"./billing/billing-labels\";\nexport type { BillingLabels, SubscriptionStatus } from \"./billing/billing-labels\";\nexport { BILLING_INTERVALS, planPrice, minorToMajor, formatPlanPrice, billingCurrencyFor } from \"./billing/plan-price\";\nexport type { BillingInterval, BillingCurrency, PlanIntervalPrices, PlanPrices, PlanPriceAnswer } from \"./billing/plan-price\";\nexport { PlanCard, PlanPicker, GrantWarningConfirm, planRelation } from \"./billing/plan-card\";\nexport type { BillingPlan, PlanRelation, PlanCardProps, PlanPickerProps, PlanChoice, GrantWarningConfirmProps } from \"./billing/plan-card\";\nexport { SubscriptionStatusChip, SUBSCRIPTION_STATUS_TONES } from \"./billing/subscription-status-chip\";\nexport type { SubscriptionStatusChipProps } from \"./billing/subscription-status-chip\";\nexport { BillingBanner } from \"./billing/billing-banner\";\nexport type { BillingBannerProps, BillingBannerKind } from \"./billing/billing-banner\";\nexport { PlanLimitNotice, planLimitMailto } from \"./billing/plan-limit-notice\";\nexport type { PlanLimitNoticeProps } from \"./billing/plan-limit-notice\";\nexport { isPlanLimit } from \"./billing/plan-limit\";\nexport type { PlanLimitRefusal } from \"./billing/plan-limit\";\n// 0.33.0: sources name their kind, the combined lock holds them all, and billing's is one\n// hook (docs/billing-harmonization.md §12.36).\nexport { combineWriteLocks, useBillingLockReason, useBillingWriteLock } from \"./billing/billing-lock\";\nexport type { WriteLockSource, CombinedWriteLock, BillingLockReasonOptions } from \"./billing/billing-lock\";\nexport { billingLockAt, isBillingReadOnly, billingDaysLeft } from \"./billing/billing-standing\";\nexport type { BillingStanding } from \"./billing/billing-standing\";\nexport { SubscriptionActions } from \"./billing/subscription-actions\";\nexport type { SubscriptionActionsProps } from \"./billing/subscription-actions\";\n// 0.33.0, billing's round 0.33 (docs/billing-harmonization.md §14):\n// the way back from a checkout and its \"processing\", router-agnostic (§14.4).\nexport {\n CHECKOUT_RETURN_PARAM,\n CHECKOUT_RETURN_VALUE,\n isCheckoutReturn,\n withoutCheckoutReturn,\n checkoutReturnUrl,\n} from \"./billing/checkout-return\";\nexport { checkoutFingerprint, checkoutLanded, noteCheckoutStarted, useCheckoutProcessing } from \"./billing/checkout-processing\";\nexport type { CheckoutOverview, CheckoutProcessingOptions } from \"./billing/checkout-processing\";\n// The link to the pay page and Paddle's locale (§14.4); the page itself ships as dist/pay/.\nexport { PAY_PAGE_LANG_PARAM, paddleLocale, payPageUrl } from \"./billing/pay-page\";\nexport type { PaddleEnvironment } from \"./billing/pay-page\";\n// 0.39 (§15.2.6): the apps every pay page serves, by their `billing_app` tag.\nexport { PAY_PAGE_APPS } from \"./billing/pay-page\";\nexport type { PayPageApp } from \"./billing/pay-page\";\n// The API's shapes the parts read, server-kit 0.7's (§4, §14.5), and the plan limit as\n// a toast (§14.11).\nexport type { BillingOverview, SubscriptionSource, PortalTarget, PortalRequest } from \"./billing/billing-overview\";\nexport { usePlanLimitToast } from \"./billing/plan-limit-toast\";\nexport type { PlanLimitToastOptions } from \"./billing/plan-limit-toast\";\n// 0.39 (§15.2.10): the payer's plan switch, its shapes, and what the payer pays.\nexport { PlanSwitchConfirm } from \"./billing/plan-switch\";\nexport type { PlanSwitchConfirmProps, PlanSwitchSide } from \"./billing/plan-switch\";\nexport type { PaidPrice, PlanSwitchRequest, PlanSwitchPreview } from \"./billing/billing-overview\";\n// 0.42 (§16): the portal for the buyer only, the in-app cancel, the permanent-grant warning.\nexport { isPermanentGrant } from \"./billing/billing-overview\";\nexport type { BillingPortalAccess } from \"./billing/billing-overview\";\nexport { CancelSubscriptionConfirm } from \"./billing/cancel-subscription\";\nexport type { CancelSubscriptionConfirmProps } from \"./billing/cancel-subscription\";\n// 0.43 (§17): the provider's portal in a new tab; the in-app cancel's follow-up.\nexport { openProviderPage } from \"./billing/provider-page\";\nexport type { OpenProviderPageOptions, ProviderPageWay } from \"./billing/provider-page\";\nexport { useCancelRequest } from \"./billing/cancel-request\";\nexport type { CancelRequest, CancelRequested, CancelRequestView } from \"./billing/cancel-request\";\n// The operator's plan parts (§14.12) are admin/plan-change, in the admin section.\n\n// ── settings ─────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/settings-harmonization.md): the settings page and the admin page on one\n// shell. The router-aware layout with its\n// route and focus hooks, and the router-free section, context, heading level and catalogue,\n// come with `./shell` above (also `@eifi1/ui-kit/shell`).\nexport { DEFAULT_SETTINGS_LABELS, useSettingsLabels } from \"./settings/settings-labels\";\nexport type { SettingsLabels, SettingsGroupLabels, SettingsCoreGroup } from \"./settings/settings-labels\";\n// 0.36.0 (§11): \"Reset this device's settings\" — the registry the kit's stores, provider\n// and shell join on their own and an app adds its own device keys to, and the card, the\n// appearance group's last.\nexport { registerDeviceSetting, deviceSettings, resetDeviceSettings } from \"./lib/device-settings\";\nexport type { DeviceSetting, DeviceSettingKind } from \"./lib/device-settings\";\nexport { DeviceResetSetting, DEVICE_RESET_ANCHOR, DEFAULT_DEVICE_RESET_LABELS } from \"./settings/device-reset-setting\";\nexport type { DeviceResetSettingProps, DeviceResetLabels } from \"./settings/device-reset-setting\";\n// The language follows the account (§6.2); since 0.32 so do the text size and the\n// contrast (useAccountAppearance below, docs/text-size-harmonization.md §6).\nexport { useAccountLanguage, resolveAccountLanguage, matchOfferedLanguage } from \"./settings/use-account-language\";\nexport type {\n UseAccountLanguageOptions,\n AccountLanguage,\n AccountLanguageSource,\n ResolveAccountLanguageInput,\n ResolvedAccountLanguage,\n} from \"./settings/use-account-language\";\nexport { useAccountAppearance, resolveAccountAppearance } from \"./settings/use-account-appearance\";\nexport type {\n AppearanceSource,\n AccountAppearanceFields,\n DeviceAppearance,\n AccountAppearancePatch,\n ResolvedAccountAppearance,\n UseAccountAppearanceOptions,\n AccountAppearance,\n} from \"./settings/use-account-appearance\";\n\n// ── notifications ────────────────────────────────────────────────────────────\n// 0.36.0 (docs/notifications-harmonization.md §4.2): the notification cards — the types\n// the server answers (the kit keeps no list of its own), quiet hours with the zone picker,\n// this device's push on its hook, the device list — and the signed-out unsubscribe page.\n// Each card takes the app's request functions; the kit makes no request itself.\nexport { DEFAULT_NOTIFICATIONS_LABELS } from \"./notifications/notifications-labels\";\nexport type { NotificationsLabels, NotificationRegionLabels } from \"./notifications/notifications-labels\";\nexport type {\n DigestCadence,\n NotificationSwitches,\n NotificationTypesValue,\n NotificationTypeEntry,\n NotificationTypeGroup,\n NotificationSettingsPatch,\n PushDeviceItem,\n NotificationChannel,\n} from \"./notifications/notification-types\";\nexport { NotificationTypesSetting } from \"./notifications/notification-types-setting\";\nexport type { NotificationTypesSettingProps } from \"./notifications/notification-types-setting\";\nexport { QuietHoursSetting } from \"./notifications/quiet-hours-setting\";\nexport type { QuietHoursSettingProps } from \"./notifications/quiet-hours-setting\";\n// 0.46 (docs/notifications-harmonization.md §10.1, §10.3): the inbox list, the bell and\n// the device-zone report (the account's zone is automatic only, amended 2026-10-20).\nexport { NotificationInbox, INBOX_BADGE_INTERVAL } from \"./notifications/notification-inbox\";\nexport type {\n NotificationInboxAction,\n NotificationInboxItem,\n NotificationInboxProps,\n} from \"./notifications/notification-inbox\";\nexport { NotificationBell } from \"./notifications/notification-bell\";\nexport type { NotificationBellProps } from \"./notifications/notification-bell\";\n// `deviceTimeZone` lives beside the report since 0.46.1 (keksdose N6; sign-up needs it).\nexport { useDeviceZoneReport, deviceTimeZone } from \"./notifications/device-zone-report\";\nexport type { DeviceZoneReportOptions } from \"./notifications/device-zone-report\";\nexport {\n usePushDevice,\n PUSH_SUBSCRIPTION_CHANGED,\n notifyPushSubscriptionChanged,\n pushSupported,\n PushDeviceError,\n} from \"./notifications/use-push-device\";\nexport type {\n PushDevice,\n UsePushDeviceOptions,\n PushSubscriptionInput,\n PushPermission,\n PushDeviceErrorCode,\n} from \"./notifications/use-push-device\";\n// 0.46 (NT:1028): the service worker re-registers a rotated subscription. A worker imports\n// them from `@eifi1/ui-kit/push-worker` (§10.6 rule 5); the barrel keeps them too.\nexport {\n handlePushSubscriptionChange,\n resubscribeAfterChange,\n pushSubscriptionInput,\n} from \"./notifications/push-worker\";\nexport type {\n PushReplaceInput,\n PushSubscriptionChangeOptions,\n PushSubscriptionChangeEventLike,\n PushResubscribeOutcome,\n PushWorkerScope,\n} from \"./notifications/push-worker\";\nexport { PushDeviceSetting } from \"./notifications/push-device-setting\";\nexport type { PushDeviceSettingProps, PushDeviceAction } from \"./notifications/push-device-setting\";\nexport { PushDevicesSetting, describeUserAgent } from \"./notifications/push-devices-setting\";\nexport type { PushDevicesSettingProps } from \"./notifications/push-devices-setting\";\nexport { UnsubscribePanel, unsubscribeTokenType } from \"./notifications/unsubscribe-panel\";\nexport type { UnsubscribePanelProps } from \"./notifications/unsubscribe-panel\";\n// 0.38.0 (docs/feedback-harmonization.md §9.11): the two feedback types' setting words.\n// 0.46.1 (keksdose N9): `useFeedbackNotificationTypesLabels`, the words resolved, for `adminGroup`.\nexport {\n useFeedbackNotificationTypes,\n useFeedbackNotificationTypesLabels,\n DEFAULT_FEEDBACK_NOTIFICATION_TYPES_LABELS,\n} from \"./notifications/feedback-notification-types\";\nexport type {\n FeedbackNotificationTypeId,\n FeedbackNotificationTypesLabels,\n} from \"./notifications/feedback-notification-types\";\n\n// ── landing ──────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the public landing page. Its router-aware parts — the header and the resume (RootEntry,\n// RedirectIfAuthed, the last-visited page) — come with `./shell` above.\nexport { DEFAULT_LANDING_LABELS, useLandingLabels } from \"./landing/landing-labels\";\nexport type { LandingLabels } from \"./landing/landing-labels\";\nexport { accessAction, useAccessAction } from \"./landing/access\";\nexport type { AccessChoice, AccessLink, AccessLabels } from \"./landing/access\";\nexport { LandingActions } from \"./landing/landing-actions\";\nexport type { LandingActionsProps, LandingSession } from \"./landing/landing-actions\";\nexport { Hero, FeatureRows, FeatureRow, TrustStrip, CtaBand, PublicFooter } from \"./landing/landing-sections\";\nexport type {\n HeroProps,\n FeatureRowsProps,\n FeatureRowProps,\n TrustItem,\n TrustStripProps,\n CtaBandProps,\n PublicFooterProps,\n} from \"./landing/landing-sections\";\nexport { usePageSeo, seoCopyProblems, metaContent } from \"./landing/page-seo\";\nexport type { SeoCopy, SeoCopyLimits, SeoCopyProblem, SeoCopyProblemCode } from \"./landing/page-seo\";\n\n// ── demo ─────────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the demo's start, banner, countdown and end.\nexport { DEFAULT_DEMO_LABELS, useDemoLabels } from \"./demo/demo-labels\";\nexport type { DemoLabels } from \"./demo/demo-labels\";\nexport { isDemoSession } from \"./demo/demo-session\";\nexport type { DemoModel, DemoSessionUser } from \"./demo/demo-session\";\nexport { useDemoCountdown, demoCountdown, DEMO_WARNING_MINUTES, DEMO_MINUTES_ONLY } from \"./demo/demo-countdown\";\nexport type { DemoCountdown, DemoCountdownOptions, DemoExpiry } from \"./demo/demo-countdown\";\nexport { DemoStart } from \"./demo/demo-start\";\nexport type { DemoStartProps } from \"./demo/demo-start\";\nexport { DemoBanner } from \"./demo/demo-banner\";\nexport type { DemoBannerProps } from \"./demo/demo-banner\";\nexport { DemoEnded } from \"./demo/demo-ended\";\nexport type { DemoEndedProps } from \"./demo/demo-ended\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// @eifi1/ui-kit — shared design-system barrel.\n//\n// Domain-free UI + theme surface shared across apps (lead app: Keksdose). Consumers import\n// components/theme from \"@eifi1/ui-kit\" and the token stylesheet from \"@eifi1/ui-kit/tokens.css\".\n//\n// Grouped by folder. A subpath entry (chart, data-table, shell, feedback, wizard, tour,\n// search) is re-exported whole — `export * from \"./chart\"` — instead of its list typed out a\n// second time here: the two copies had drifted (refactor audit 2026-10, MOD-5). A name that\n// arrives twice that way is the same binding from the same module, which ESM does not count\n// as a clash.\n\n// ── lib ────────────────────────────────────────────────────────────────────\nexport * from \"./lib/calc\";\nexport { cn } from \"./lib/cn\";\nexport { logger, setStoreLog } from \"./lib/logger\";\n// Intl number / money / percent / date / relative-time formatting, and `useKitFormat()`\n// for the same bound to the provider's locale (kastlan's formatters.ts, English \"5m ago\").\nexport * from \"./lib/format\";\n// localStorage that never throws (Safari private mode, blocked site data).\nexport { readStored, writeStored } from \"./lib/safe-storage\";\n// Save a fetched Blob as a download, and read the name a Content-Disposition asks for\n// (`filename*` first) — 0.34, KS U5; the kit's own three downloads use them.\nexport { saveBlob, filenameFromDisposition } from \"./lib/download\";\n// Date helpers are also available via the \"@eifi1/ui-kit/dates\" subpath.\n// One fold and one ranking for every list's search box (DUP-5), for an app's own lists.\nexport { foldForSearch, rankMatch } from \"./lib/text-match\";\nexport type { MatchRank } from \"./lib/text-match\";\n// 0.12.0: the QR encoder QrCode draws with — no dependency, see lib/qr-encode.ts.\nexport { encodeQr } from \"./lib/qr-encode\";\nexport type { QrEncodeOptions, QrErrorCorrection, QrMatrix } from \"./lib/qr-encode\";\n// 0.18: the cold-start notice keksdose built (#199), for every app: the framework-free\n// watchdog over the app's requests (the corner notice is components/server-wake).\nexport { createServerWake, serverWake, watchReadsAnd, attachServerWake, wrapFetch } from \"./lib/server-wake\";\nexport type { ServerWakeStage, ServerWakeFilter, ServerWakeOptions, ServerWakeRequest, ServerWakeWatcher, ServerWakeAxiosConfig, AxiosLikeInstance } from \"./lib/server-wake\";\n// 0.34 (docs/auth-harmonization.md §11, round 0.34 C7): renewing a session — one refresh\n// per tab, a definitive failure ends the session once, a transient one keeps it.\nexport { createSessionRefresh, attachSessionRefresh, isTransientRefreshFailure, isSignedOutStep } from \"./lib/session-refresh\";\nexport type { SessionRefresh, SessionRefreshOptions, SessionRenewal, SessionRefreshOutcome } from \"./lib/session-refresh\";\n// 0.29.0 (docs/auth-harmonization.md): the person-name order of each language.\nexport { formatPersonName, personInitials } from \"./lib/person-name\";\nexport type { PersonName } from \"./lib/person-name\";\n// Translation review (0.19): one contract for kastlan's and keksdose's review pages — the\n// pure rows/status/placeholder logic here, the presentational page parts under components.\nexport {\n REVIEW_STATUSES,\n fromApiReview,\n toApiWrite,\n flattenStrings,\n keyNamespace,\n placeholderTokens,\n placeholderMismatch,\n reviewStatus,\n keyInArea,\n keyInAreas,\n // 0.28: the area a key is grouped under — `kit.legal.*` in `legal` (legal round §7.5).\n reviewAreaOf,\n translationRows,\n summariseRows,\n DEFAULT_TRANSLATION_REVIEW_FILTER,\n filterTranslationRows,\n reviewWrite,\n mergeReviews,\n dropReviews,\n translationCorrections,\n // 0.25: grouping and the approvals' Undo (keksdose live #377).\n groupTranslationRows,\n unreviewedRows,\n reviewUndo,\n // 0.26: swipe bindings for an app's Settings → Interaction (keksdose #377 rework).\n TRANSLATION_REVIEW_SWIPE_ACTIONS,\n DEFAULT_TRANSLATION_REVIEW_SWIPE,\n translationReviewSwipePlan,\n} from \"./lib/translation-review\";\nexport type {\n TranslationVerdict,\n TranslationReview,\n TranslationReviewWrite,\n TranslationReviewKey,\n ReviewStatus,\n TranslationRow,\n ApiTranslationReview,\n ApiTranslationReviewsResponse,\n ApiTranslationReviewWrite,\n TranslationRowsInput,\n TranslationSummary,\n TranslationReviewFilter,\n TranslationCorrection,\n TranslationRowGroup,\n TranslationReviewUndo,\n TranslationReviewSwipeAction,\n TranslationReviewSwipeBinding,\n} from \"./lib/translation-review\";\n// 0.22.0, the inputs round: the country list and the IBAN, ISIN and phone helpers that\n// CountrySelect, IbanInput and PhoneInput are built on.\nexport { COUNTRY_CODES, countryName } from \"./lib/countries\";\nexport {\n IBAN_LENGTHS,\n compactIban,\n formatIban,\n ibanCheckDigits,\n ibanProblem,\n isValidIban,\n isQrIban,\n} from \"./lib/iban\";\nexport type { IbanKind, IbanProblem } from \"./lib/iban\";\nexport { formatIsin, isinCheckDigit, isValidIsin } from \"./lib/isin\";\nexport {\n PHONE_DIAL_CODES,\n PHONE_COUNTRIES,\n parsePhone,\n formatNationalPhone,\n formatPhone,\n isE164,\n} from \"./lib/phone\";\nexport type { PhoneCountryCode, PhoneCountry, ParsedPhone } from \"./lib/phone\";\n// 0.23.0: ColumnMapper's pure half (Kurvenschmiede's columns input, keksdose's import map).\nexport {\n assignColumnRole,\n guessMapping,\n missingRoles,\n readMappedTable,\n readTextFile,\n roleOfColumn,\n} from \"./lib/column-mapping\";\nexport type { ColumnMapperResult, ColumnMapping, ColumnRole } from \"./lib/column-mapping\";\n\n// ── hooks ────────────────────────────────────────────────────────────────────\nexport { useMediaQuery } from \"./hooks/use-media-query\";\nexport { useBodyScrollLock } from \"./hooks/use-body-scroll-lock\";\nexport { useAnchoredRect } from \"./hooks/use-anchored-rect\";\nexport type { AnchorRect } from \"./hooks/use-anchored-rect\";\nexport {\n useAnchoredPanel,\n anchoredPanelPlacement,\n useVisualViewport,\n readKeyboardInset,\n} from \"./hooks/use-anchored-panel\";\nexport type {\n AnchoredPanel,\n AnchoredPanelOptions,\n ViewportBox,\n KeyboardInsetOptions,\n} from \"./hooks/use-anchored-panel\";\nexport { useEscapeKey, useOutsideClick } from \"./hooks/use-dismiss\";\n// Focus containment for an overlay, and a live region for a change that moves no focus.\n// Both were extracted from the two components that already did them correctly (Modal and\n// CommandPalette) so the rest of the kit stops being the exception.\nexport { useFocusTrap } from \"./hooks/use-focus-trap\";\nexport type { FocusTrapOptions } from \"./hooks/use-focus-trap\";\nexport { useAnnounce } from \"./hooks/use-announce\";\nexport type { UseAnnounceReturn, UseAnnounceOptions, AnnounceRegionProps } from \"./hooks/use-announce\";\nexport { useOverlayHistory } from \"./hooks/use-overlay-history\";\nexport { useCloseTransition, OVERLAY_EXIT_MS } from \"./hooks/use-close-transition\";\nexport { useRowSwipe } from \"./hooks/use-row-swipe\";\n// 0.28: keksdose's noindex marker, for the legal and auth pages of every app.\nexport { useNoIndex } from \"./hooks/use-noindex\";\n// 0.49 KIT-9: the window's title from page, section and app, in the provider's format.\nexport { useDocumentTitle } from \"./hooks/use-document-title\";\n// 0.49 KIT-1b: U+2212 before a number as \"-\", the copy handler's rule, for an app's text.\nexport { asciiMinusInNumbers } from \"./lib/clipboard-minus\";\nexport { DEFAULT_DOCUMENT_TITLE_FORMAT, formatDocumentTitle } from \"./lib/document-title\";\nexport type { DocumentTitleParts } from \"./lib/document-title\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// 0.25: several keys, one navigation (keksdose live #378 — four setters in a row clobbered).\nexport { useSearchParamsState } from \"./hooks/use-search-param-state\";\nexport type { SearchParamField, SearchParamFields, SearchParamsUpdate } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n// Row windowing for a long list (0.7.0, lenkbank's measured grid is built on it).\nexport { useWindowedRows, WINDOWED_ROW_INDEX } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// 0.32.0 (docs/text-size-harmonization.md): the breakpoints, and the hooks components read\n// the behaviours at Large from (§4, §10.7–10.9).\nexport { useBreakpoint, usePhoneLayout, breakpointQuery, BREAKPOINT_REM, remPx, useRemPx } from \"./hooks/use-breakpoint\";\nexport type { Breakpoint, BreakpointVariant, RemLength } from \"./hooks/use-breakpoint\";\nexport { useLargeText, useCoarsePointer, useInlineFacts } from \"./hooks/use-large-text\";\n\n// ── theme / palettes ─────────────────────────────────────────────────────────\n// The chart palette (theme/chart-palette) comes with the chart kit, `./chart` below.\n// Colour maths (sRGB ↔ OKLCH, WCAG contrast, CVD simulation) and the palette deriver\n// that builds a whole, contrast-solved palette from one brand colour plus any colours\n// pinned by hand. `auditPalette` / `auditChartRamp` measure a palette rather than\n// trusting a comment about it.\nexport * from \"./theme/color\";\nexport * from \"./theme/palette-derive\";\nexport * from \"./theme/palette-presets\";\nexport * from \"./theme/theme-store\";\nexport * from \"./theme/palette-store\";\n// 0.32.0: text size and contrast (docs/text-size-harmonization.md).\nexport * from \"./theme/text-size\";\nexport * from \"./theme/contrast\";\n\n// ── i18n: one label tree, one optional provider ──────────────────────────────\n// `UiKitLabels` names every string the kit renders; `<UiKitProvider labels locale>`\n// hands a translation to every component below it. Precedence: a component's own\n// prop > the provider > the English default. See src/i18n/kit-labels.tsx.\nexport * from \"./i18n/kit-labels\";\nexport * from \"./i18n/defaults\";\n// The kit's words as `key → text` rows for an app's translation review (keksdose).\nexport { kitLabelStrings } from \"./i18n/review\";\nexport type { KitLabelStringsOptions } from \"./i18n/review\";\n// The seven languages, how an app resolves one, and the kit catalogue loader for it.\nexport * from \"./i18n/languages\";\n// CLDR plural categories for an app's i18next catalogue, filled from `_other`; and the\n// forms of an app's word a kit part picks from by count (0.33.1, `PlanColumnUsage.label`).\nexport { withAllPlurals } from \"./i18n/plurals\";\nexport type { PluralForms } from \"./i18n/plurals\";\n\n// ── components ───────────────────────────────────────────────────────────────\n// The kit's core controls, one module each since 0.34 (MOD-2, refactor audit 2026-10):\n// Button, IconButton, the field base, Input, Select, Textarea, Card, Spinner, EmptyState\n// and Tabs. Named, not `*`, for `button-look` and `field-base`: they also hold parts the\n// controls share, which are internal. The others are public whole.\nexport * from \"./components/button\";\nexport {\n buttonClasses,\n TOUCH_TARGET_LARGE,\n type ButtonClassesOptions,\n type ButtonSize,\n type ButtonTone,\n type ButtonVariant,\n} from \"./components/button-look\";\nexport * from \"./components/icon-button\";\nexport {\n FIELD_TOUCH_TEXT,\n FIELD_BASE,\n FIELD_WRITABLE_LOOK,\n FIELD_FLOATING_PAD,\n FIELD_INVALID,\n FLOATING_INPUT_CLASS,\n FIELD_DISPLAY,\n FIELD_TRIGGER,\n FieldChevron,\n FLOATING_LABEL_CLASS,\n FloatingField,\n Label,\n DEFAULT_PASSWORD_REVEAL_LABELS,\n DEFAULT_CHARACTER_COUNT_LABELS,\n type FieldChevronProps,\n type FloatingFieldProps,\n type LabelProps,\n type PasswordRevealLabels,\n type CharacterCountLabels,\n} from \"./components/field-base\";\nexport * from \"./components/input\";\nexport * from \"./components/select\";\nexport * from \"./components/textarea\";\nexport * from \"./components/card\";\nexport * from \"./components/spinner\";\nexport * from \"./components/empty-state\";\nexport * from \"./components/tabs\";\n// The static label lives in field-parts since 0.23 (it is what the field anatomy there\n// draws, and field-parts must not import the controls).\nexport { FieldLabel, FLOATING_LABEL_STATIC, FieldHint } from \"./components/field-parts\";\nexport type { FieldLabelProps, FieldHintProps } from \"./components/field-parts\";\n// The kit's focus frame (§5), in its own module so the parts the controls import\n// (field-parts, the choice controls) can draw it too.\nexport { FOCUS_RING, FOCUS_RING_WIDTH } from \"./components/focus-ring\";\n// No fact only in a tooltip (§4): the reason line and the compact region live in\n// field-parts, where the self-saving controls (Switch, Checkbox) reach them too.\nexport {\n CompactControls,\n DisabledReasonLine,\n DISABLED_REASON_LINE_CLASS,\n useDisabledReasonLine,\n} from \"./components/field-parts\";\nexport type { DisabledReasonDisplay } from \"./components/field-parts\";\n// The label-ABOVE field group (label, hint, error, required), inside wizards or out.\nexport * from \"./components/field\";\nexport * from \"./components/search-field\";\nexport * from \"./components/dropdown\";\nexport * from \"./components/popover\";\n// 0.34 (keksdose K3): paragraph-long help behind a \"?\", opened on a tap — FieldHint's\n// sibling for help rather than a fact (docs/text-size-harmonization.md §10.23).\nexport { HelpPopover } from \"./components/help-popover\";\nexport type { HelpPopoverProps } from \"./components/help-popover\";\nexport { SwipeableRow } from \"./components/swipeable-row\";\nexport type { SwipeAction, SwipePaint, SwipeTone, SwipeableRowProps } from \"./components/swipeable-row\";\nexport * from \"./components/calculator\";\nexport * from \"./components/numpad-sheet\";\nexport * from \"./components/number-input\";\nexport * from \"./components/currency-select\";\n// 0.35: each currency's flag-icons country. `CURRENCIES` and it are also the pure-data\n// entry \"@eifi1/ui-kit/currencies\", which imports nothing, for an app's build in Node.\nexport { CURRENCY_COUNTRIES } from \"./currencies\";\nexport * from \"./components/amount-input\";\nexport * from \"./components/money-field\";\nexport * from \"./components/combobox\";\nexport * from \"./components/picker-sheet\";\nexport * from \"./components/entity-combobox\";\nexport * from \"./components/multi-entity-combobox\";\nexport * from \"./components/multi-select\";\nexport * from \"./components/tooltip\";\nexport * from \"./components/user-avatar\";\nexport * from \"./components/settings-fields\";\n// Sync state for a database-backed field: the engine (`useFieldSync`) and the\n// affordance (`FieldSyncIndicator`), kept separate because the state is useful\n// without the dot — a form can gate its submit on any field being `pending`.\nexport * from \"./components/field-sync\";\nexport * from \"./components/month-picker\";\nexport * from \"./components/checkbox\";\nexport * from \"./components/switch\";\nexport * from \"./components/slider\";\nexport * from \"./components/time-input\";\nexport * from \"./components/number-field\";\nexport * from \"./components/sparkline\";\nexport * from \"./components/stat-tile\";\nexport * from \"./components/signature-pad\";\nexport * from \"./components/password-strength\";\nexport * from \"./components/page-contents\";\nexport * from \"./components/disclosure\";\nexport * from \"./components/dialog-frame\";\n// Named, not `*`: danger-confirm also holds the password field and pending hook that\n// ReauthDialog shares with it, which are kit-internal.\nexport {\n DangerConfirm,\n DEFAULT_DANGER_CONFIRM_LABELS,\n typedMatches,\n // 0.22.0: the typed-confirmation field on its own (keksdose K7) and the current-password\n // field kastlan wants for sign-in and re-authentication (kastlan 1).\n TypedConfirmField,\n CurrentPasswordInput,\n} from \"./components/danger-confirm\";\nexport type {\n DangerConfirmLabels,\n DangerConfirmProps,\n TypedMatch,\n DangerConsequence,\n TypedConfirmFieldProps,\n TypedConfirmFieldLabels,\n CurrentPasswordInputProps,\n CurrentPasswordInputLabels,\n // 0.23.0: onConfirm's second argument — the guards' values (keksdose G4b).\n DangerConfirmValues,\n} from \"./components/danger-confirm\";\n// 0.18: re-authentication before a sensitive action (Kurvenschmiede 4).\nexport { ReauthDialog, DEFAULT_REAUTH_DIALOG_LABELS } from \"./components/reauth-dialog\";\nexport type { ReauthDialogProps, ReauthDialogLabels } from \"./components/reauth-dialog\";\n// `useConfirm()` — the promise-based replacement for `window.confirm`, one host per app.\nexport * from \"./components/confirm-dialog\";\n// A non-modal corner panel and its round trigger (keksdose's assistant launcher).\nexport * from \"./components/floating-panel\";\n// The count / clear / actions bar a selection brings up (keksdose's three copies).\nexport * from \"./components/bulk-action-bar\";\nexport * from \"./components/swatch-picker\";\nexport * from \"./components/icon-picker\";\nexport * from \"./components/choice-card\";\nexport * from \"./components/autocomplete\";\nexport * from \"./components/measured-grid\";\n// Named, not `export *`: file-button.tsx also re-exports the screening helpers the\n// dropzone shares (hooks/use-file-picker since 0.34, MOD-8), which are internal.\nexport { FileButton, useFilePicker, matchesAccept, DEFAULT_FILE_PICKER_LABELS } from \"./components/file-button\";\nexport type {\n FileButtonProps,\n UseFilePickerOptions,\n UseFilePickerReturn,\n FilePickerLabels,\n FileRejection,\n FileRejectionReason,\n FileScreenOptions,\n} from \"./components/file-button\";\n// The chart kit, whole, from its subpath (`@eifi1/ui-kit/chart`, which names its parts):\n// the chart shell and its palette, the treemap, the series chart with its zoom, legend,\n// labels and facing-pair axes, the height every chart takes, and the pie chart.\nexport * from \"./chart\";\n// 0.12.0: the QR code TwoFactorSetting draws its otpauth URI with (encoder in\n// lib/qr-encode.ts — no dependency, see there).\nexport * from \"./components/qr-code\";\nexport * from \"./components/alert-banner\";\nexport * from \"./components/toggle-group\";\n// A wrapping set of links/buttons marked `aria-current` — Tabs-like looks, not tabs.\nexport * from \"./components/nav-pills\";\n// 0.49.0 (KIT-6): a section's pages on the phone, one scrolling row of pills.\nexport * from \"./components/section-nav\";\n// A pill carrying one VALUE — inert, a link, or a toggle, depending on which prop it is\n// given — and the list field built from it. Distinct from Button on purpose: a row of\n// buttons reads as \"choose an action\", a row of chips as \"here are the things\".\nexport * from \"./components/chip\";\n// 0.49.0 (KIT-8): five domain-free status kinds and their tones — Chip/StatusDot `status`.\nexport { statusTone, STATUS_KINDS } from \"./lib/status-tone\";\nexport type { StatusKind, StatusTone } from \"./lib/status-tone\";\n// ChipInput's own module since MOD-9: it renders Chip, so chip.tsx re-exports only its types.\nexport * from \"./components/chip-input\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\nexport * from \"./components/calendar-heatmap\";\nexport * from \"./components/date-picker\";\nexport * from \"./components/tree-view\";\n// 0.8.0 layout and feedback primitives the apps hand-rolled or took from shadcn/Radix.\nexport * from \"./components/description-list\";\n// The Save / Cancel row forms and dialogs end in, and the editable line-item repeater\n// (journal lines, lease components, invoice positions). 0.12.0.\nexport * from \"./components/form-actions\";\n// 0.18: lock every opted-in commit under one provider, the reason in its tooltip\n// (Kurvenschmiede 2). `useCommitReason` stays internal.\n// 0.33: a lock says its source, and a control can be exempt from one\n// (docs/billing-harmonization.md §12.36): the kinds, the holds, `CommitScope`,\n// `COMMIT_EXCEPT_BILLING` and the pure `writeLockFor`.\nexport { WriteLockProvider, useWriteLock, writeLockFor, COMMIT_EXCEPT_BILLING, DEFAULT_WRITE_LOCK_LABELS } from \"./components/write-lock\";\n// 0.46 (kastlan K4): the offline lock kind, its scope and its source.\nexport { OFFLINE_LOCK, COMMIT_EXCEPT_OFFLINE, useOfflineWriteLock } from \"./components/write-lock\";\nexport type { WriteLock, WriteLockLabels, WriteLockProviderProps, WriteLockKind, WriteLockHold, CommitScope } from \"./components/write-lock\";\n// 0.18: the parts both apps' admin rosters repeat (Kurvenschmiede 6).\nexport { RoleChip, AccountStateChip, DateMark, dateColumn, DEFAULT_ACCOUNT_STATE_LABELS, ACCOUNT_STATE_TONES } from \"./components/account-chips\";\nexport type { RoleChipProps, RoleDefinition, RoleVocabulary, AccountState, AccountStateLabels, AccountStateChipProps, DateMarkProps, DateColumnOptions } from \"./components/account-chips\";\n// 0.42 (docs/admin-harmonization.md §2.1): the role in the account menu's header, a link\n// to the role's tool (`RoleDefinition.href`).\nexport { AccountRoleChip } from \"./components/account-chips\";\nexport type { AccountRoleChipProps } from \"./components/account-chips\";\n// 0.18: the cold-start notice keksdose built (#199), for every app: the corner notice\n// that explains the wait (its framework-free watchdog is lib/server-wake).\nexport { ServerWakeNotice, useServerWakeStage, DEFAULT_SERVER_WAKE_LABELS } from \"./components/server-wake\";\nexport type { ServerWakeLabels, ServerWakeNoticeProps } from \"./components/server-wake\";\n// 0.18: sharing — grantees, roles, pending grants, candidates (Kurvenschmiede 1).\nexport { ShareCard, ShareDialog, SharePanel, DEFAULT_SHARE_CARD_LABELS } from \"./components/share-card\";\nexport type { ShareCardProps, ShareDialogProps, SharePanelProps, ShareCardLabels, ShareRole, ShareGrantee, SharePendingGrant, ShareCandidate, ShareAddRequest } from \"./components/share-card\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.48 (keksdose dev #628): the table/list loading preset, one status label.\nexport { TableSkeleton } from \"./components/table-skeleton\";\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\nexport * from \"./components/image-grid\";\nexport * from \"./components/lightbox\";\nexport * from \"./components/button-group\";\nexport * from \"./components/table\";\nexport * from \"./components/separator\";\n// Named: scroll-area.tsx also holds the overflow hook and scrollbar class Table shares.\nexport { ScrollArea } from \"./components/scroll-area\";\nexport type { ScrollAreaProps } from \"./components/scroll-area\";\n// 0.10.0 rows, menu rows, text primitives and page chrome the apps drew by hand.\nexport * from \"./components/list\";\nexport * from \"./components/menu-item\";\nexport * from \"./components/text\";\nexport * from \"./components/status-dot\";\nexport * from \"./components/page-header\";\nexport * from \"./components/breadcrumbs\";\n// The one inline link (kastlan's EntityLink / CellLink / legal and source links), through\n// `<UiKitProvider linkComponent>`. Named: the file also holds the kit's internal link picker.\nexport { TextLink } from \"./components/text-link\";\nexport type {\n TextLinkProps,\n TextLinkRenderProps,\n TextLinkTone,\n TextLinkUnderline,\n TextLinkCurrent,\n} from \"./components/text-link\";\n// The toast layer over sonner (an OPTIONAL peer, loaded lazily): `toast` mirrors sonner's\n// API so apps migrate by swapping the import; `<Toaster>` carries the placement, theme,\n// tones and z-index both apps had wired by hand.\nexport {\n toast,\n Toaster,\n DEFAULT_TOAST_LABELS,\n TOAST_ACTION_DURATION,\n TOASTER_OFFSET_TOP,\n TOASTER_OFFSET_BOTTOM,\n} from \"./components/toast\";\nexport type {\n ToastId,\n ToastAction,\n ToastOptions,\n ToastPromiseOptions,\n ToastUndoOptions,\n ToastRedoOptions,\n ToastLabels,\n ToastPosition,\n ToastSwipeDirection,\n ToasterOffset,\n ToasterProps,\n} from \"./components/toast\";\n// Translation review (0.19): the presentational page parts (the pure logic is\n// lib/translation-review).\nexport {\n TranslationReviewPanel,\n TranslationReviewEditor,\n ReviewStatusChip,\n TranslationProgress,\n TranslationLocaleTabs,\n TranslationExportButton,\n REVIEW_STATUS_TONES,\n DEFAULT_TRANSLATION_REVIEW_LABELS,\n} from \"./components/translation-review\";\nexport type {\n TranslationReviewPanelProps,\n TranslationReviewEditorProps,\n ReviewStatusChipProps,\n TranslationProgressProps,\n TranslationLocaleTab,\n TranslationLocaleTabsProps,\n TranslationExportButtonProps,\n TranslationReviewLabels,\n TranslationReviewSaveInfo,\n TranslationReviewOrigin,\n TranslationReviewGroupBy,\n} from \"./components/translation-review\";\n// The legal pages' shell (0.19, H10): Imprint, Privacy Policy, Terms in every app.\n// 0.28 (docs/legal-harmonization.md): the shared wording, the page frame, the kit's\n// sections, the public footer and the terms checkbox.\nexport {\n LegalLayout,\n LegalSection,\n LegalLinks,\n LegalFooter,\n DEFAULT_LEGAL_LABELS,\n LEGAL_HREFS,\n legalOperatorText,\n useLegalLabels,\n} from \"./components/legal\";\nexport type {\n LegalLabels,\n LegalLink,\n LegalLinksProps,\n LegalSectionProps,\n LegalLayoutProps,\n LegalFooterProps,\n LegalOperator,\n LegalOperatorText,\n LegalPageKey,\n LegalTextSectionLabels,\n LegalOperatorSectionLabels,\n LegalFramedSectionLabels,\n LegalDisclaimerSectionLabels,\n} from \"./components/legal\";\nexport { LegalPage, LegalKitSection, LegalAcceptCheckbox, LEGAL_SKELETON } from \"./components/legal-page\";\nexport type {\n LegalPageProps,\n LegalKitSectionProps,\n LegalKitSectionKey,\n LegalAcceptCheckboxProps,\n LegalSkeletonEntry,\n LegalSkeletonPage,\n LegalSectionOwner,\n LegalDisclaimerVariant,\n} from \"./components/legal-page\";\n// 0.32.0 (docs/text-size-harmonization.md): the appearance settings' words, and a row's\n// actions, one of the behaviours at Large (§4, §10.7–10.9).\nexport { DEFAULT_APPEARANCE_LABELS, useAppearanceLabels } from \"./components/appearance-labels\";\nexport type { AppearanceLabels } from \"./components/appearance-labels\";\n// 0.46 (keksdose's date format, lifted): the preference, its resolver and renderer, the\n// provider's formatter for it, and the settings field.\nexport {\n DATE_FORMAT_PREFERENCES,\n isDateFormatPreference,\n resolveDateFormat,\n formatDateWithPreference,\n dateFormatSample,\n dateFormatterFor,\n} from \"./lib/date-format\";\nexport type { DateFormatPreference, DateFormatOptions, ResolvedDateFormat } from \"./lib/date-format\";\nexport { DateFormatSetting } from \"./components/date-format-setting\";\nexport type { DateFormatSettingProps } from \"./components/date-format-setting\";\nexport {\n RowActions,\n rowActionsColumn,\n DEFAULT_ROW_ACTIONS_LABELS,\n // 0.47.0 (keksdose N17): a hand-built table's actions heading and cell.\n RowActionsHead,\n ROW_ACTIONS_CELL_CLASS,\n ROW_ACTIONS_HEAD_CLASS,\n} from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\n RowActionsHeadProps,\n RowActionTone,\n // 0.49 KIT-12: a danger action's confirmation words.\n RowActionConfirm,\n} from \"./components/row-actions\";\n// 0.22.0: the inputs round (kastlan's, keksdose's and Kurvenschmiede's audits).\nexport * from \"./components/checkbox-group\";\nexport * from \"./components/one-time-code-input\";\nexport * from \"./components/language-select\";\nexport * from \"./components/tile-radio\";\nexport * from \"./components/inline-edit-field\";\nexport * from \"./components/sign-chip\";\nexport * from \"./components/country-select\";\nexport * from \"./components/iban-input\";\nexport * from \"./components/phone-input\";\n// 0.23.0, the apps' 0.22 adoption round: the label strip over custom content (keksdose G8).\nexport * from \"./components/field-strip\";\n// Paste or drop a table, give each column a role (Kurvenschmiede's columns input,\n// keksdose's import map step). The lexer itself stays in `@eifi1/ui-kit/table-text`.\nexport * from \"./components/column-mapper\";\n\n// ── data-table suite ─────────────────────────────────────────────────────────\n// Whole, from its subpath (`@eifi1/ui-kit/data-table`, which names its parts): DataTable,\n// its sort, filters, pagination and cells, and a server table's state held by its owner,\n// URL-synced.\nexport * from \"./data-table\";\n\n// ── shell (composable app chrome) ────────────────────────────────────────────\n// Whole, from `@eifi1/ui-kit/shell`: the top bar and its controls, AppShell, the switchers\n// and AuthLayout, and (0.31.0) the router-aware parts of settings and landing —\n// SettingsLayout with its route, focus, section, context, heading and catalogue;\n// PublicHeader, RootEntry, RedirectIfAuthed and the last-visited page.\nexport * from \"./shell\";\n// 0.29.0 (docs/auth-harmonization.md): kastlan's company switcher.\nexport { CompanySwitcher, DEFAULT_COMPANY_SWITCHER_LABELS } from \"./shell/company-switcher\";\nexport type { CompanySwitcherProps, CompanySwitcherLabels, CompanySwitcherCompany } from \"./shell/company-switcher\";\n\n// ── feedback ─────────────────────────────────────────────────────────────────\n// The form somebody files a report with, and the parts an inbox is built from:\n// the status vocabulary both apps share value for value, the policy about what a\n// row may move to from where it stands, and the look of a status control, a\n// category badge and an opened report. The app still wires its own API, columns\n// and strings — see the note at the top of `feedback-inbox.tsx` for what is\n// deliberately left to it. Whole, from `@eifi1/ui-kit/feedback`, which also has 0.27.0's\n// harmonization (docs/feedback-harmonization.md): the record, menu, table, detail and\n// crash reporter.\nexport * from \"./feedback\";\n\n// ── multi-step wizard ────────────────────────────────────────────────────────\n// The engine (step machine, validators, collected data), the chrome around it\n// (indicator + nav bar + cancel confirm) and the review step it ends on.\n// `components/wizard-stepper` next door is a different, much smaller thing: a bare\n// step indicator for a two-step import flow, with no engine.\n//\n// `wizard-field` was removed here rather than kept as stock: it held a\n// `WizardField`/`WizardSelectField` pair that had never been rendered in any app — a\n// field group nothing was built from, which this comment used to advertise. A design\n// system may carry stock; untested stock nothing has ever rendered is not stock, it is\n// a liability with an export. The react-hook-form bridge to the Next gate\n// (`useRhfWizardStep`) is NOT here either: it left the barrel in 0.4.x so the barrel\n// imports no react-hook-form, and came back in 0.11 under `@eifi1/ui-kit/rhf`\n// (src/rhf.ts), where the optional peer is that subpath's alone.\n// Whole, from `@eifi1/ui-kit/wizard`.\nexport * from \"./wizard\";\n\n// ── guided tours ─────────────────────────────────────────────────────────────\nexport * from \"./tour\";\n\n// ── command palette / global search ──────────────────────────────────────────\n// The palette, its pure matcher and the ⌘K search on it. The list fold every search box\n// shares is lib/text-match, above.\nexport * from \"./search\";\n\n// ── auth ─────────────────────────────────────────────────────────────────────\n// 0.29.0 (docs/auth-harmonization.md): sign-in, sign-up and the signed-out pages — forms\n// that take callbacks and never send a request themselves. The person-name order of each\n// language is lib/person-name, kastlan's company switcher is in the shell section.\nexport { SignInForm, DEFAULT_SIGN_IN_LABELS } from \"./auth/sign-in-form\";\nexport type {\n SignInFormProps,\n SignInLabels,\n SignInAnswer,\n SignInStep,\n SignInAction,\n SignInCredentials,\n SignInCodeValues,\n SignInNewPasswordValues,\n} from \"./auth/sign-in-form\";\nexport { RegisterForm, DEFAULT_REGISTER_LABELS } from \"./auth/register-form\";\nexport type { RegisterFormProps, RegisterLabels, RegisterValues } from \"./auth/register-form\";\nexport { CompleteNameDialog, DEFAULT_COMPLETE_NAME_LABELS } from \"./auth/complete-name-dialog\";\nexport type { CompleteNameDialogProps, CompleteNameLabels, CompleteNameValues } from \"./auth/complete-name-dialog\";\nexport { taggedEmail } from \"./auth/email-tag\";\nexport { isAuthError, authErrorCode, isBillingError } from \"./auth/auth-errors\";\nexport type { AuthErrorCode } from \"./auth/auth-errors\";\nexport { ForgotPasswordForm, DEFAULT_FORGOT_PASSWORD_LABELS } from \"./auth/forgot-password-form\";\nexport type { ForgotPasswordFormProps, ForgotPasswordLabels } from \"./auth/forgot-password-form\";\nexport { ResetPasswordForm, DEFAULT_RESET_PASSWORD_LABELS } from \"./auth/reset-password-form\";\nexport type {\n ResetPasswordFormProps,\n ResetPasswordLabels,\n ResetPasswordCheck,\n ResetPasswordValues,\n ResetPasswordResult,\n} from \"./auth/reset-password-form\";\nexport { VerifyEmailStatus, EmailVerificationBanner, DEFAULT_VERIFY_EMAIL_LABELS } from \"./auth/verify-email\";\nexport type {\n VerifyEmailStatusProps,\n EmailVerificationBannerProps,\n VerifyEmailLabels,\n VerifyEmailFailure,\n} from \"./auth/verify-email\";\nexport { NotFoundPage, DEFAULT_NOT_FOUND_LABELS } from \"./auth/not-found-page\";\nexport type { NotFoundPageProps, NotFoundLabels } from \"./auth/not-found-page\";\nexport { AcceptInvitation, DEFAULT_ACCEPT_INVITATION_LABELS } from \"./auth/accept-invitation\";\nexport type {\n AcceptInvitationProps,\n AcceptInvitationLabels,\n AcceptInvitationResult,\n AcceptInvitationFailure,\n} from \"./auth/accept-invitation\";\nexport type { AuthHeadingLevel } from \"./auth/status-parts\";\n// 0.30.0: a rate limit and its wait, and the codes the account, billing and demo calls\n// answer with.\nexport { isRateLimited, retryAfterSeconds } from \"./auth/auth-errors\";\nexport type { AccountErrorCode, BillingErrorCode, DemoErrorCode, KitErrorCode } from \"./auth/auth-errors\";\n\n// ── account ──────────────────────────────────────────────────────────────────\n// In account/ since 0.34, beside the other account cards (MOD-8, refactor audit 2026-10):\n// the profile, password and two-factor cards, and (0.12.0) the fourth account section,\n// the passkeys.\nexport * from \"./account/account-settings\";\nexport * from \"./account/passkeys-setting\";\n// 0.30.0 (docs/user-admin-harmonization.md): the account's own settings — email change,\n// sessions, deletion, export. Callbacks only; the confirmation level is the server's.\nexport { EmailChangeSetting, DEFAULT_EMAIL_CHANGE_LABELS } from \"./account/email-change-setting\";\nexport type {\n EmailChangeSettingProps,\n EmailChangeLabels,\n EmailChangeValues,\n EmailChangeAction,\n} from \"./account/email-change-setting\";\nexport { SessionsSetting, DEFAULT_SESSIONS_LABELS } from \"./account/sessions-setting\";\nexport type { SessionsSettingProps, SessionsLabels, SessionItem, SessionId, SessionsAction } from \"./account/sessions-setting\";\nexport { DeleteAccountSetting, DEFAULT_DELETE_ACCOUNT_LABELS } from \"./account/delete-account-setting\";\nexport type {\n DeleteAccountSettingProps,\n DeleteAccountLabels,\n DeleteAccountValues,\n DeletionMode,\n DeleteAccountConsequence,\n} from \"./account/delete-account-setting\";\nexport { DataExportSetting, DEFAULT_DATA_EXPORT_LABELS } from \"./account/data-export-setting\";\nexport type { DataExportSettingProps, DataExportLabels, DataExportFile } from \"./account/data-export-setting\";\n\n// ── admin ────────────────────────────────────────────────────────────────────\n// 0.30.0 (docs/user-admin-harmonization.md): the admin user list and its actions, and the\n// invitations panel. Callbacks only; the confirmation level is the server's.\nexport {\n userRosterColumns,\n useUserRosterColumns,\n UserIdentityCell,\n UserRowActions,\n adminUserStates,\n userRosterSort,\n USER_ROSTER_SORT_KEYS,\n DEFAULT_USER_ROSTER_LABELS,\n} from \"./admin/user-roster\";\nexport type {\n UserRosterRow,\n AdminUserStateFields,\n RosterState,\n UserRosterSortKey,\n UserRosterLabels,\n UserIdentityCellProps,\n UserRowAction,\n UserRowActionList,\n UserRowActionsProps,\n RoleEditing,\n UserRosterColumnsOptions,\n} from \"./admin/user-roster\";\nexport { RoleSelect, RolesEditor, DEFAULT_ROLE_SELECT_LABELS } from \"./admin/role-select\";\nexport type { RoleSelectProps, RolesEditorProps, RoleSelectLabels, RoleLock, RoleLockCode } from \"./admin/role-select\";\nexport { ReviewerScopeEditor, DEFAULT_REVIEWER_SCOPE_LABELS } from \"./admin/reviewer-scope-editor\";\nexport type {\n ReviewerScope,\n ReviewerScopeArea,\n ReviewerScopeLanguage,\n ReviewerScopeLabels,\n ReviewerScopeEditorProps,\n} from \"./admin/reviewer-scope-editor\";\nexport { AdminActionConfirm, DEFAULT_ADMIN_ACTION_LABELS } from \"./admin/admin-action-confirm\";\nexport type {\n AdminConfirmLevel,\n AdminActionConfirmValues,\n AdminActionTarget,\n AdminActionLabels,\n AdminActionConfirmProps,\n} from \"./admin/admin-action-confirm\";\nexport { AdminActionLog, ADMIN_ACTION_KINDS, DEFAULT_ADMIN_ACTION_LOG_LABELS } from \"./admin/admin-action-log\";\nexport type {\n AdminActionKind,\n AdminActionLogEntry,\n AdminActionLogLabels,\n AdminActionLogPaging,\n AdminActionLogProps,\n // 0.34 (docs/user-admin-harmonization.md §11): a log target that is not a person, and\n // the app's noun for its groups.\n AdminGroupTarget,\n AdminOtherTarget,\n AdminGroupNoun,\n} from \"./admin/admin-action-log\";\nexport { TransferOwnershipDialog, DEFAULT_TRANSFER_OWNERSHIP_LABELS } from \"./admin/transfer-ownership-dialog\";\nexport type {\n TransferCandidate,\n TransferUnavailable,\n TransferValues,\n TransferOwnershipLabels,\n TransferOwnershipDialogProps,\n} from \"./admin/transfer-ownership-dialog\";\nexport { InvitationsPanel, DEFAULT_INVITATIONS_LABELS } from \"./admin/invitations-panel\";\nexport type {\n InvitationStatus,\n InvitationRow,\n InvitationDraft,\n InvitationSentAnswer,\n InvitationScope,\n InvitationsLabels,\n InvitationsPanelProps,\n} from \"./admin/invitations-panel\";\nexport type { AdminPerson } from \"./admin/admin-parts\";\n// 0.42.0 (docs/admin-harmonization.md §3.1): the admin area's template — its words, the\n// shared sections and the catalogue helper, the 403 page, the overview and its tiles fed\n// by `GET /admin/attention`, and the Tools list. The menu row is `./shell`'s.\nexport { DEFAULT_ADMIN_AREA_LABELS, useAdminAreaLabels } from \"./admin/admin-area-labels\";\nexport type { AdminAreaLabels, AdminTileLabels, AdminSharedSection } from \"./admin/admin-area-labels\";\nexport { ADMIN_SECTIONS, adminSections } from \"./admin/admin-sections\";\nexport type { AdminSectionDefinition, AdminOwnSection, AdminSectionsOptions } from \"./admin/admin-sections\";\n// 0.43.0 (keksdose): the section order as ids, and the narrowed `leaveOut`.\nexport { adminSectionOrder } from \"./admin/admin-sections\";\nexport type { AdminSectionPlace, AdminSectionOrderOptions, AdminKeptSection } from \"./admin/admin-sections\";\nexport { AdminForbidden } from \"./admin/admin-forbidden\";\nexport type { AdminForbiddenProps } from \"./admin/admin-forbidden\";\nexport { AdminOverview, AttentionTile, adminWaitingCount, DEFAULT_ADMIN_ATTENTION_HREFS } from \"./admin/admin-overview\";\nexport type {\n AdminAttention,\n AdminAttentionTile,\n AdminExtraTile,\n AdminOverviewProps,\n AttentionTileProps,\n // 0.46 (Kurvenschmiede 1): the feedback tiles with the kit's words.\n AdminFeedbackTile,\n AdminFeedbackTileKey,\n AdminOwnTile,\n} from \"./admin/admin-overview\";\nexport { AdminToolLinks } from \"./admin/admin-tool-links\";\nexport type { AdminToolLink, AdminToolLinksProps } from \"./admin/admin-tool-links\";\n// 0.45.0 (docs/admin-harmonization.md §9.2.4): \"Send a test mail to me\".\nexport { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR, maskMailAddress } from \"./admin/mail-test-card\";\nexport type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from \"./admin/mail-test-card\";\n// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).\nexport {\n planColumn,\n usePlanColumn,\n PlanChangeConfirm,\n usePlanChangeResult,\n DEFAULT_PLAN_CHANGE_LABELS,\n} from \"./admin/plan-change\";\nexport type {\n PlanChangeLabels,\n PlanColumnOptions,\n PlanColumnUsage,\n PlanChange,\n PlanChangeConfirmProps,\n PlanChangeOutcome,\n PlanChangeTone,\n PlanChangeLine,\n PlanChangeResultOptions,\n} from \"./admin/plan-change\";\n\n// ── billing ──────────────────────────────────────────────────────────────────\n// 0.32.0: plans, standing, banners, the limit notice (docs/billing-harmonization.md §7).\nexport { DEFAULT_BILLING_LABELS, useBillingLabels, SUBSCRIPTION_STATUSES } from \"./billing/billing-labels\";\nexport type { BillingLabels, SubscriptionStatus } from \"./billing/billing-labels\";\nexport { BILLING_INTERVALS, planPrice, minorToMajor, formatPlanPrice, billingCurrencyFor } from \"./billing/plan-price\";\nexport type { BillingInterval, BillingCurrency, PlanIntervalPrices, PlanPrices, PlanPriceAnswer } from \"./billing/plan-price\";\nexport { PlanCard, PlanPicker, GrantWarningConfirm, planRelation } from \"./billing/plan-card\";\nexport type { BillingPlan, PlanRelation, PlanCardProps, PlanPickerProps, PlanChoice, GrantWarningConfirmProps } from \"./billing/plan-card\";\nexport { SubscriptionStatusChip, SUBSCRIPTION_STATUS_TONES } from \"./billing/subscription-status-chip\";\nexport type { SubscriptionStatusChipProps } from \"./billing/subscription-status-chip\";\nexport { BillingBanner } from \"./billing/billing-banner\";\nexport type { BillingBannerProps, BillingBannerKind } from \"./billing/billing-banner\";\nexport { PlanLimitNotice, planLimitMailto } from \"./billing/plan-limit-notice\";\nexport type { PlanLimitNoticeProps } from \"./billing/plan-limit-notice\";\nexport { isPlanLimit } from \"./billing/plan-limit\";\nexport type { PlanLimitRefusal } from \"./billing/plan-limit\";\n// 0.33.0: sources name their kind, the combined lock holds them all, and billing's is one\n// hook (docs/billing-harmonization.md §12.36).\nexport { combineWriteLocks, useBillingLockReason, useBillingWriteLock } from \"./billing/billing-lock\";\nexport type { WriteLockSource, CombinedWriteLock, BillingLockReasonOptions } from \"./billing/billing-lock\";\nexport { billingLockAt, isBillingReadOnly, billingDaysLeft } from \"./billing/billing-standing\";\nexport type { BillingStanding } from \"./billing/billing-standing\";\nexport { SubscriptionActions } from \"./billing/subscription-actions\";\nexport type { SubscriptionActionsProps } from \"./billing/subscription-actions\";\n// 0.33.0, billing's round 0.33 (docs/billing-harmonization.md §14):\n// the way back from a checkout and its \"processing\", router-agnostic (§14.4).\nexport {\n CHECKOUT_RETURN_PARAM,\n CHECKOUT_RETURN_VALUE,\n isCheckoutReturn,\n withoutCheckoutReturn,\n checkoutReturnUrl,\n} from \"./billing/checkout-return\";\nexport { checkoutFingerprint, checkoutLanded, noteCheckoutStarted, useCheckoutProcessing } from \"./billing/checkout-processing\";\nexport type { CheckoutOverview, CheckoutProcessingOptions } from \"./billing/checkout-processing\";\n// The link to the pay page and Paddle's locale (§14.4); the page itself ships as dist/pay/.\nexport { PAY_PAGE_LANG_PARAM, paddleLocale, payPageUrl } from \"./billing/pay-page\";\nexport type { PaddleEnvironment } from \"./billing/pay-page\";\n// 0.39 (§15.2.6): the apps every pay page serves, by their `billing_app` tag.\nexport { PAY_PAGE_APPS } from \"./billing/pay-page\";\nexport type { PayPageApp } from \"./billing/pay-page\";\n// The API's shapes the parts read, server-kit 0.7's (§4, §14.5), and the plan limit as\n// a toast (§14.11).\nexport type { BillingOverview, SubscriptionSource, PortalTarget, PortalRequest } from \"./billing/billing-overview\";\nexport { usePlanLimitToast } from \"./billing/plan-limit-toast\";\nexport type { PlanLimitToastOptions } from \"./billing/plan-limit-toast\";\n// 0.39 (§15.2.10): the payer's plan switch, its shapes, and what the payer pays.\nexport { PlanSwitchConfirm } from \"./billing/plan-switch\";\nexport type { PlanSwitchConfirmProps, PlanSwitchSide } from \"./billing/plan-switch\";\nexport type { PaidPrice, PlanSwitchRequest, PlanSwitchPreview } from \"./billing/billing-overview\";\n// 0.42 (§16): the portal for the buyer only, the in-app cancel, the permanent-grant warning.\nexport { isPermanentGrant } from \"./billing/billing-overview\";\nexport type { BillingPortalAccess } from \"./billing/billing-overview\";\nexport { CancelSubscriptionConfirm } from \"./billing/cancel-subscription\";\nexport type { CancelSubscriptionConfirmProps } from \"./billing/cancel-subscription\";\n// 0.43 (§17): the provider's portal in a new tab; the in-app cancel's follow-up.\nexport { openProviderPage } from \"./billing/provider-page\";\nexport type { OpenProviderPageOptions, ProviderPageWay } from \"./billing/provider-page\";\nexport { useCancelRequest } from \"./billing/cancel-request\";\nexport type { CancelRequest, CancelRequested, CancelRequestView } from \"./billing/cancel-request\";\n// The operator's plan parts (§14.12) are admin/plan-change, in the admin section.\n\n// ── settings ─────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/settings-harmonization.md): the settings page and the admin page on one\n// shell. The router-aware layout with its\n// route and focus hooks, and the router-free section, context, heading level and catalogue,\n// come with `./shell` above (also `@eifi1/ui-kit/shell`).\nexport { DEFAULT_SETTINGS_LABELS, useSettingsLabels } from \"./settings/settings-labels\";\nexport type { SettingsLabels, SettingsGroupLabels, SettingsCoreGroup } from \"./settings/settings-labels\";\n// 0.36.0 (§11): \"Reset this device's settings\" — the registry the kit's stores, provider\n// and shell join on their own and an app adds its own device keys to, and the card, the\n// appearance group's last.\nexport { registerDeviceSetting, deviceSettings, resetDeviceSettings } from \"./lib/device-settings\";\nexport type { DeviceSetting, DeviceSettingKind } from \"./lib/device-settings\";\nexport { DeviceResetSetting, DEVICE_RESET_ANCHOR, DEFAULT_DEVICE_RESET_LABELS } from \"./settings/device-reset-setting\";\nexport type { DeviceResetSettingProps, DeviceResetLabels } from \"./settings/device-reset-setting\";\n// The language follows the account (§6.2); since 0.32 so do the text size and the\n// contrast (useAccountAppearance below, docs/text-size-harmonization.md §6).\nexport { useAccountLanguage, resolveAccountLanguage, matchOfferedLanguage } from \"./settings/use-account-language\";\nexport type {\n UseAccountLanguageOptions,\n AccountLanguage,\n AccountLanguageSource,\n ResolveAccountLanguageInput,\n ResolvedAccountLanguage,\n} from \"./settings/use-account-language\";\nexport { useAccountAppearance, resolveAccountAppearance } from \"./settings/use-account-appearance\";\nexport type {\n AppearanceSource,\n AccountAppearanceFields,\n DeviceAppearance,\n AccountAppearancePatch,\n ResolvedAccountAppearance,\n UseAccountAppearanceOptions,\n AccountAppearance,\n} from \"./settings/use-account-appearance\";\n\n// ── notifications ────────────────────────────────────────────────────────────\n// 0.36.0 (docs/notifications-harmonization.md §4.2): the notification cards — the types\n// the server answers (the kit keeps no list of its own), quiet hours with the zone picker,\n// this device's push on its hook, the device list — and the signed-out unsubscribe page.\n// Each card takes the app's request functions; the kit makes no request itself.\nexport { DEFAULT_NOTIFICATIONS_LABELS } from \"./notifications/notifications-labels\";\nexport type { NotificationsLabels, NotificationRegionLabels } from \"./notifications/notifications-labels\";\nexport type {\n DigestCadence,\n NotificationSwitches,\n NotificationTypesValue,\n NotificationTypeEntry,\n NotificationTypeGroup,\n NotificationSettingsPatch,\n PushDeviceItem,\n NotificationChannel,\n} from \"./notifications/notification-types\";\nexport { NotificationTypesSetting } from \"./notifications/notification-types-setting\";\nexport type { NotificationTypesSettingProps } from \"./notifications/notification-types-setting\";\nexport { QuietHoursSetting } from \"./notifications/quiet-hours-setting\";\nexport type { QuietHoursSettingProps } from \"./notifications/quiet-hours-setting\";\n// 0.46 (docs/notifications-harmonization.md §10.1, §10.3): the inbox list, the bell and\n// the device-zone report (the account's zone is automatic only, amended 2026-10-20).\nexport { NotificationInbox, INBOX_BADGE_INTERVAL } from \"./notifications/notification-inbox\";\nexport type {\n NotificationInboxAction,\n NotificationInboxItem,\n NotificationInboxProps,\n} from \"./notifications/notification-inbox\";\nexport { NotificationBell } from \"./notifications/notification-bell\";\nexport type { NotificationBellProps } from \"./notifications/notification-bell\";\n// `deviceTimeZone` lives beside the report since 0.46.1 (keksdose N6; sign-up needs it).\nexport { useDeviceZoneReport, deviceTimeZone } from \"./notifications/device-zone-report\";\nexport type { DeviceZoneReportOptions } from \"./notifications/device-zone-report\";\nexport {\n usePushDevice,\n PUSH_SUBSCRIPTION_CHANGED,\n notifyPushSubscriptionChanged,\n pushSupported,\n PushDeviceError,\n} from \"./notifications/use-push-device\";\nexport type {\n PushDevice,\n UsePushDeviceOptions,\n PushSubscriptionInput,\n PushPermission,\n PushDeviceErrorCode,\n} from \"./notifications/use-push-device\";\n// 0.46 (NT:1028): the service worker re-registers a rotated subscription. A worker imports\n// them from `@eifi1/ui-kit/push-worker` (§10.6 rule 5); the barrel keeps them too.\nexport {\n handlePushSubscriptionChange,\n resubscribeAfterChange,\n pushSubscriptionInput,\n} from \"./notifications/push-worker\";\nexport type {\n PushReplaceInput,\n PushSubscriptionChangeOptions,\n PushSubscriptionChangeEventLike,\n PushResubscribeOutcome,\n PushWorkerScope,\n} from \"./notifications/push-worker\";\nexport { PushDeviceSetting } from \"./notifications/push-device-setting\";\nexport type { PushDeviceSettingProps, PushDeviceAction } from \"./notifications/push-device-setting\";\nexport { PushDevicesSetting, describeUserAgent } from \"./notifications/push-devices-setting\";\nexport type { PushDevicesSettingProps } from \"./notifications/push-devices-setting\";\nexport { UnsubscribePanel, unsubscribeTokenType } from \"./notifications/unsubscribe-panel\";\nexport type { UnsubscribePanelProps } from \"./notifications/unsubscribe-panel\";\n// 0.38.0 (docs/feedback-harmonization.md §9.11): the two feedback types' setting words.\n// 0.46.1 (keksdose N9): `useFeedbackNotificationTypesLabels`, the words resolved, for `adminGroup`.\nexport {\n useFeedbackNotificationTypes,\n useFeedbackNotificationTypesLabels,\n DEFAULT_FEEDBACK_NOTIFICATION_TYPES_LABELS,\n} from \"./notifications/feedback-notification-types\";\nexport type {\n FeedbackNotificationTypeId,\n FeedbackNotificationTypesLabels,\n} from \"./notifications/feedback-notification-types\";\n\n// ── landing ──────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the public landing page. Its router-aware parts — the header and the resume (RootEntry,\n// RedirectIfAuthed, the last-visited page) — come with `./shell` above.\nexport { DEFAULT_LANDING_LABELS, useLandingLabels } from \"./landing/landing-labels\";\nexport type { LandingLabels } from \"./landing/landing-labels\";\nexport { accessAction, useAccessAction } from \"./landing/access\";\nexport type { AccessChoice, AccessLink, AccessLabels } from \"./landing/access\";\nexport { LandingActions } from \"./landing/landing-actions\";\nexport type { LandingActionsProps, LandingSession } from \"./landing/landing-actions\";\nexport { Hero, FeatureRows, FeatureRow, TrustStrip, CtaBand, PublicFooter } from \"./landing/landing-sections\";\nexport type {\n HeroProps,\n FeatureRowsProps,\n FeatureRowProps,\n TrustItem,\n TrustStripProps,\n CtaBandProps,\n PublicFooterProps,\n} from \"./landing/landing-sections\";\nexport { usePageSeo, seoCopyProblems, metaContent } from \"./landing/page-seo\";\nexport type { SeoCopy, SeoCopyLimits, SeoCopyProblem, SeoCopyProblemCode } from \"./landing/page-seo\";\n\n// ── demo ─────────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the demo's start, banner, countdown and end.\nexport { DEFAULT_DEMO_LABELS, useDemoLabels } from \"./demo/demo-labels\";\nexport type { DemoLabels } from \"./demo/demo-labels\";\nexport { isDemoSession } from \"./demo/demo-session\";\nexport type { DemoModel, DemoSessionUser } from \"./demo/demo-session\";\nexport { useDemoCountdown, demoCountdown, DEMO_WARNING_MINUTES, DEMO_MINUTES_ONLY } from \"./demo/demo-countdown\";\nexport type { DemoCountdown, DemoCountdownOptions, DemoExpiry } from \"./demo/demo-countdown\";\nexport { DemoStart } from \"./demo/demo-start\";\nexport type { DemoStartProps } from \"./demo/demo-start\";\nexport { DemoBanner } from \"./demo/demo-banner\";\nexport type { DemoBannerProps } from \"./demo/demo-banner\";\nexport { DemoEnded } from \"./demo/demo-ended\";\nexport type { DemoEndedProps } from \"./demo/demo-ended\";\n"],"mappings":"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","names":[]}
|
|
@@ -26,8 +26,8 @@ function LandingActions({
|
|
|
26
26
|
...rest,
|
|
27
27
|
"data-slot": "landing-actions",
|
|
28
28
|
className: cn("flex flex-col gap-3 sm:flex-row", align === "center" && "sm:justify-center", className),
|
|
29
|
-
children: session === "user" ? /* @__PURE__ */ jsx(Button, { href: openAppHref, variant: "
|
|
30
|
-
/* @__PURE__ */ jsx(Button, { href: accessLink.href, variant: "
|
|
29
|
+
children: session === "user" ? /* @__PURE__ */ jsx(Button, { href: openAppHref, variant: "accent", size: buttonSize, className: extra, children: labels.openApp }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
30
|
+
/* @__PURE__ */ jsx(Button, { href: accessLink.href, variant: "accent", size: buttonSize, className: extra, children: accessLink.label }),
|
|
31
31
|
demoHref !== null && /* @__PURE__ */ jsx(Button, { href: demoHref, variant: "secondary", size: buttonSize, className: extra, children: session === "demo" ? labels.continueDemo : labels.tryDemo })
|
|
32
32
|
] })
|
|
33
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/landing/landing-actions.tsx"],"sourcesContent":["import type { ComponentPropsWithRef } from \"react\";\n\nimport { cn } from \"../lib/cn\";\nimport { Button } from \"../components/button\";\nimport type { ButtonSize } from \"../components/button-look\";\nimport { useAccessAction } from \"./access\";\nimport type { AccessChoice } from \"./access\";\nimport { useLandingLabels } from \"./landing-labels\";\nimport type { LandingLabels } from \"./landing-labels\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\n\n/**\n * Who is looking at a public page (docs/landing-demo-harmonization.md §3.1, §4.1):\n * nobody signed in, a demo session, or a real account. The app derives it from its auth\n * state — a demo is `isDemoSession(me)`.\n */\nexport type LandingSession = \"none\" | \"demo\" | \"user\";\n\n/** keksdose's hero buttons: wider than the kit's `md` (px-5 py-2.5), the page's\n * largest actions. */\nconst LARGE = \"px-5 py-2.5\";\n\nexport interface LandingActionsProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\"> {\n session: LandingSession;\n access: AccessChoice;\n /** \"Try the demo\" without a session, \"Continue the demo\" with a demo one. Default\n * `/demo`, which starts a demo — or, for a live one, continues it (§3.1). `null`\n * (0.31.1): the app has no demo yet, and the action is left out — \"Request access\"\n * stands alone (Kurvenschmiede's 0.31 adoption). */\n demoHref?: string | null;\n /** \"Open app\" for a real session: the resume target. Default `/`, which resumes\n * through `RootEntry`. */\n openAppHref?: string;\n /** `large` (default): the hero's and the CTA band's size. Or a kit `ButtonSize`. */\n size?: ButtonSize | \"large\";\n /** `start` (default) under the hero's copy; `center` in the CTA band. */\n align?: \"start\" | \"center\";\n labels?: LabelOverride<LandingLabels>;\n}\n\n/**\n * The landing's action pair for the visitor's state (§4.1), shared by {@link Hero} and\n * {@link CtaBand}:\n *\n * | session | actions |\n * |---|---|\n * | none | **Request access** (primary), Try the demo |\n * | demo | **Request access** (primary), Continue the demo |\n * | user | **Open app** (primary), alone |\n *\n * keksdose showed a signed-in visitor (who reached the landing by its brand link,\n * `/welcome`) the register/demo pair, which `RedirectIfAuthed` then silently bounced\n * back into the app; one \"Open app\" says where it goes. \"Request access\" is the mail of\n * {@link accessAction}, or \"Get started\" once the app opens registration.\n *\n * Stacked full-width on a phone, a row from `sm` up — keksdose's layout.\n */\nexport function LandingActions({\n session,\n access,\n demoHref = \"/demo\",\n openAppHref = \"/\",\n size = \"large\",\n align = \"start\",\n labels: labelsProp,\n className,\n ...rest\n}: LandingActionsProps) {\n const labels = useLandingLabels(labelsProp);\n const accessLink = useAccessAction(access, labelsProp);\n const buttonSize: ButtonSize = size === \"large\" ? \"md\" : size;\n const extra = size === \"large\" ? LARGE : undefined;\n return (\n <div\n {...rest}\n data-slot=\"landing-actions\"\n className={cn(\"flex flex-col gap-3 sm:flex-row\", align === \"center\" && \"sm:justify-center\", className)}\n >\n {session === \"user\" ? (\n <Button href={openAppHref} variant=\"
|
|
1
|
+
{"version":3,"sources":["../../src/landing/landing-actions.tsx"],"sourcesContent":["import type { ComponentPropsWithRef } from \"react\";\n\nimport { cn } from \"../lib/cn\";\nimport { Button } from \"../components/button\";\nimport type { ButtonSize } from \"../components/button-look\";\nimport { useAccessAction } from \"./access\";\nimport type { AccessChoice } from \"./access\";\nimport { useLandingLabels } from \"./landing-labels\";\nimport type { LandingLabels } from \"./landing-labels\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\n\n/**\n * Who is looking at a public page (docs/landing-demo-harmonization.md §3.1, §4.1):\n * nobody signed in, a demo session, or a real account. The app derives it from its auth\n * state — a demo is `isDemoSession(me)`.\n */\nexport type LandingSession = \"none\" | \"demo\" | \"user\";\n\n/** keksdose's hero buttons: wider than the kit's `md` (px-5 py-2.5), the page's\n * largest actions. */\nconst LARGE = \"px-5 py-2.5\";\n\nexport interface LandingActionsProps extends Omit<ComponentPropsWithRef<\"div\">, \"children\"> {\n session: LandingSession;\n access: AccessChoice;\n /** \"Try the demo\" without a session, \"Continue the demo\" with a demo one. Default\n * `/demo`, which starts a demo — or, for a live one, continues it (§3.1). `null`\n * (0.31.1): the app has no demo yet, and the action is left out — \"Request access\"\n * stands alone (Kurvenschmiede's 0.31 adoption). */\n demoHref?: string | null;\n /** \"Open app\" for a real session: the resume target. Default `/`, which resumes\n * through `RootEntry`. */\n openAppHref?: string;\n /** `large` (default): the hero's and the CTA band's size. Or a kit `ButtonSize`. */\n size?: ButtonSize | \"large\";\n /** `start` (default) under the hero's copy; `center` in the CTA band. */\n align?: \"start\" | \"center\";\n labels?: LabelOverride<LandingLabels>;\n}\n\n/**\n * The landing's action pair for the visitor's state (§4.1), shared by {@link Hero} and\n * {@link CtaBand}:\n *\n * | session | actions |\n * |---|---|\n * | none | **Request access** (primary), Try the demo |\n * | demo | **Request access** (primary), Continue the demo |\n * | user | **Open app** (primary), alone |\n *\n * keksdose showed a signed-in visitor (who reached the landing by its brand link,\n * `/welcome`) the register/demo pair, which `RedirectIfAuthed` then silently bounced\n * back into the app; one \"Open app\" says where it goes. \"Request access\" is the mail of\n * {@link accessAction}, or \"Get started\" once the app opens registration.\n *\n * Stacked full-width on a phone, a row from `sm` up — keksdose's layout.\n */\nexport function LandingActions({\n session,\n access,\n demoHref = \"/demo\",\n openAppHref = \"/\",\n size = \"large\",\n align = \"start\",\n labels: labelsProp,\n className,\n ...rest\n}: LandingActionsProps) {\n const labels = useLandingLabels(labelsProp);\n const accessLink = useAccessAction(access, labelsProp);\n const buttonSize: ButtonSize = size === \"large\" ? \"md\" : size;\n const extra = size === \"large\" ? LARGE : undefined;\n return (\n <div\n {...rest}\n data-slot=\"landing-actions\"\n className={cn(\"flex flex-col gap-3 sm:flex-row\", align === \"center\" && \"sm:justify-center\", className)}\n >\n {session === \"user\" ? (\n <Button href={openAppHref} variant=\"accent\" size={buttonSize} className={extra}>\n {labels.openApp}\n </Button>\n ) : (\n <>\n <Button href={accessLink.href} variant=\"accent\" size={buttonSize} className={extra}>\n {accessLink.label}\n </Button>\n {demoHref !== null && (\n <Button href={demoHref} variant=\"secondary\" size={buttonSize} className={extra}>\n {session === \"demo\" ? labels.continueDemo : labels.tryDemo}\n </Button>\n )}\n </>\n )}\n </div>\n );\n}\n"],"mappings":";AA+EQ,SAIA,UAJA,KAIA,YAJA;AA7ER,SAAS,UAAU;AACnB,SAAS,cAAc;AAEvB,SAAS,uBAAuB;AAEhC,SAAS,wBAAwB;AAajC,MAAM,QAAQ;AAqCP,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,cAAc;AAAA,EACd,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAAwB;AACtB,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,aAAa,gBAAgB,QAAQ,UAAU;AACrD,QAAM,aAAyB,SAAS,UAAU,OAAO;AACzD,QAAM,QAAQ,SAAS,UAAU,QAAQ;AACzC,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,aAAU;AAAA,MACV,WAAW,GAAG,mCAAmC,UAAU,YAAY,qBAAqB,SAAS;AAAA,MAEpG,sBAAY,SACX,oBAAC,UAAO,MAAM,aAAa,SAAQ,UAAS,MAAM,YAAY,WAAW,OACtE,iBAAO,SACV,IAEA,iCACE;AAAA,4BAAC,UAAO,MAAM,WAAW,MAAM,SAAQ,UAAS,MAAM,YAAY,WAAW,OAC1E,qBAAW,OACd;AAAA,QACC,aAAa,QACZ,oBAAC,UAAO,MAAM,UAAU,SAAQ,aAAY,MAAM,YAAY,WAAW,OACtE,sBAAY,SAAS,OAAO,eAAe,OAAO,SACrD;AAAA,SAEJ;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -25,9 +25,9 @@ function PublicHeader({
|
|
|
25
25
|
const phone = usePhoneLayout();
|
|
26
26
|
const size = phone ? "sm" : "md";
|
|
27
27
|
const home = homeHref ?? (session === "none" ? "/" : "/welcome");
|
|
28
|
-
const actions = session === "user" ? /* @__PURE__ */ jsx(Button, { href: openAppHref, variant: "
|
|
28
|
+
const actions = session === "user" ? /* @__PURE__ */ jsx(Button, { href: openAppHref, variant: "accent", size, children: labels.openApp }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
29
29
|
session === "demo" ? /* @__PURE__ */ jsx(Button, { href: demoHref, variant: "secondary", size, children: labels.continueDemo }) : /* @__PURE__ */ jsx(Button, { href: signInHref, variant: "secondary", size, className: "max-sm:hidden", children: labels.signIn }),
|
|
30
|
-
/* @__PURE__ */ jsx(Button, { href: accessLink.href, variant: "
|
|
30
|
+
/* @__PURE__ */ jsx(Button, { href: accessLink.href, variant: "accent", size, children: accessLink.label })
|
|
31
31
|
] });
|
|
32
32
|
return /* @__PURE__ */ jsx(
|
|
33
33
|
TopBar,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/landing/public-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nimport { Button } from \"../components/button\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport { TopBar } from \"../shell/top-bar\";\nimport type { TopBarProps } from \"../shell/top-bar\";\nimport { TopBarBrand } from \"../shell/top-bar-brand\";\nimport { useAccessAction } from \"./access\";\nimport type { AccessChoice } from \"./access\";\nimport { useLandingLabels } from \"./landing-labels\";\nimport type { LandingLabels } from \"./landing-labels\";\nimport type { LandingSession } from \"./landing-actions\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\n\n/** The header's brand: what `TopBarBrand` draws. */\nexport interface PublicHeaderBrand {\n /** The brand mark — an SVG or an `<img alt=\"\">`. */\n logo: ReactNode;\n /** The product name beside it, and the link's accessible name. */\n name: ReactNode;\n /** See `TopBarBrand`. Default `sm`: the logo alone on a phone. */\n collapseBelow?: \"sm\" | \"md\" | false;\n}\n\nexport interface PublicHeaderProps extends Omit<TopBarProps, \"brand\" | \"actions\" | \"children\"> {\n brand: PublicHeaderBrand;\n /** Where the brand links. Default `/` without a session and `/welcome` with one —\n * `/` would resume into the app, `/welcome` is always the landing (§3.1). */\n homeHref?: string;\n session: LandingSession;\n access: AccessChoice;\n /** \"Sign in\". Default `/login`. */\n signInHref?: string;\n /** \"Open app\" for a real session — the resume target. Default `/`, which resumes\n * through `RootEntry`. */\n openAppHref?: string;\n /** \"Continue the demo\" for a demo session. Default `/demo`, which continues a live\n * demo (§3.1). */\n demoHref?: string;\n /** The app's `LanguageMenu`, before the actions. */\n languageMenu?: ReactNode;\n /** The app's `ThemeToggle`, before the language menu. */\n themeToggle?: ReactNode;\n labels?: LabelOverride<LandingLabels>;\n}\n\n/**\n * The header of every public page (docs/landing-demo-harmonization.md §4.1): the\n * landing, the auth pages, the legal pages and the 404 — keksdose's `LandingHeader`, on\n * the kit's `TopBar` and `TopBarBrand`, with its hard-coded teal turned into `--brand`.\n *\n * | session | actions |\n * |---|---|\n * | none | Sign in (secondary, hidden below `sm`), **Request access** (primary) |\n * | demo | Continue the demo (secondary), **Request access** (primary) |\n * | user | **Open app** (primary) |\n *\n * A demo session is not \"signed in\" here: it is still offered access, which is the point\n * of the demo (§5.6). In the phone layout (`usePhoneLayout()`) the actions take the kit's `sm` size, so\n * the brand mark, the two controls and two actions fit 390px; \"Sign in\" gives way below\n * `sm` as in keksdose — the sign-in page is one tap away from \"Request access\" anyway.\n */\nexport function PublicHeader({\n brand,\n homeHref,\n session,\n access,\n signInHref = \"/login\",\n openAppHref = \"/\",\n demoHref = \"/demo\",\n languageMenu,\n themeToggle,\n labels: labelsProp,\n className,\n ...rest\n}: PublicHeaderProps) {\n const labels = useLandingLabels(labelsProp);\n const accessLink = useAccessAction(access, labelsProp);\n const phone = usePhoneLayout();\n const size = phone ? \"sm\" : \"md\";\n const home = homeHref ?? (session === \"none\" ? \"/\" : \"/welcome\");\n\n const actions =\n session === \"user\" ? (\n <Button href={openAppHref} variant=\"
|
|
1
|
+
{"version":3,"sources":["../../src/landing/public-header.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\n\nimport { Button } from \"../components/button\";\nimport { usePhoneLayout } from \"../hooks/use-breakpoint\";\nimport { TopBar } from \"../shell/top-bar\";\nimport type { TopBarProps } from \"../shell/top-bar\";\nimport { TopBarBrand } from \"../shell/top-bar-brand\";\nimport { useAccessAction } from \"./access\";\nimport type { AccessChoice } from \"./access\";\nimport { useLandingLabels } from \"./landing-labels\";\nimport type { LandingLabels } from \"./landing-labels\";\nimport type { LandingSession } from \"./landing-actions\";\nimport type { LabelOverride } from \"../i18n/kit-labels\";\n\n/** The header's brand: what `TopBarBrand` draws. */\nexport interface PublicHeaderBrand {\n /** The brand mark — an SVG or an `<img alt=\"\">`. */\n logo: ReactNode;\n /** The product name beside it, and the link's accessible name. */\n name: ReactNode;\n /** See `TopBarBrand`. Default `sm`: the logo alone on a phone. */\n collapseBelow?: \"sm\" | \"md\" | false;\n}\n\nexport interface PublicHeaderProps extends Omit<TopBarProps, \"brand\" | \"actions\" | \"children\"> {\n brand: PublicHeaderBrand;\n /** Where the brand links. Default `/` without a session and `/welcome` with one —\n * `/` would resume into the app, `/welcome` is always the landing (§3.1). */\n homeHref?: string;\n session: LandingSession;\n access: AccessChoice;\n /** \"Sign in\". Default `/login`. */\n signInHref?: string;\n /** \"Open app\" for a real session — the resume target. Default `/`, which resumes\n * through `RootEntry`. */\n openAppHref?: string;\n /** \"Continue the demo\" for a demo session. Default `/demo`, which continues a live\n * demo (§3.1). */\n demoHref?: string;\n /** The app's `LanguageMenu`, before the actions. */\n languageMenu?: ReactNode;\n /** The app's `ThemeToggle`, before the language menu. */\n themeToggle?: ReactNode;\n labels?: LabelOverride<LandingLabels>;\n}\n\n/**\n * The header of every public page (docs/landing-demo-harmonization.md §4.1): the\n * landing, the auth pages, the legal pages and the 404 — keksdose's `LandingHeader`, on\n * the kit's `TopBar` and `TopBarBrand`, with its hard-coded teal turned into `--brand`.\n *\n * | session | actions |\n * |---|---|\n * | none | Sign in (secondary, hidden below `sm`), **Request access** (primary) |\n * | demo | Continue the demo (secondary), **Request access** (primary) |\n * | user | **Open app** (primary) |\n *\n * A demo session is not \"signed in\" here: it is still offered access, which is the point\n * of the demo (§5.6). In the phone layout (`usePhoneLayout()`) the actions take the kit's `sm` size, so\n * the brand mark, the two controls and two actions fit 390px; \"Sign in\" gives way below\n * `sm` as in keksdose — the sign-in page is one tap away from \"Request access\" anyway.\n */\nexport function PublicHeader({\n brand,\n homeHref,\n session,\n access,\n signInHref = \"/login\",\n openAppHref = \"/\",\n demoHref = \"/demo\",\n languageMenu,\n themeToggle,\n labels: labelsProp,\n className,\n ...rest\n}: PublicHeaderProps) {\n const labels = useLandingLabels(labelsProp);\n const accessLink = useAccessAction(access, labelsProp);\n const phone = usePhoneLayout();\n const size = phone ? \"sm\" : \"md\";\n const home = homeHref ?? (session === \"none\" ? \"/\" : \"/welcome\");\n\n const actions =\n session === \"user\" ? (\n <Button href={openAppHref} variant=\"accent\" size={size}>\n {labels.openApp}\n </Button>\n ) : (\n <>\n {session === \"demo\" ? (\n <Button href={demoHref} variant=\"secondary\" size={size}>\n {labels.continueDemo}\n </Button>\n ) : (\n <Button href={signInHref} variant=\"secondary\" size={size} className=\"max-sm:hidden\">\n {labels.signIn}\n </Button>\n )}\n <Button href={accessLink.href} variant=\"accent\" size={size}>\n {accessLink.label}\n </Button>\n </>\n );\n\n return (\n <TopBar\n {...rest}\n className={className}\n brand={<TopBarBrand logo={brand.logo} name={brand.name} to={home} collapseBelow={brand.collapseBelow} />}\n actions={\n <>\n {themeToggle}\n {languageMenu}\n <span data-slot=\"public-header-actions\" className=\"ms-1 flex items-center gap-1.5 sm:gap-2\">\n {actions}\n </span>\n </>\n }\n />\n );\n}\n"],"mappings":";AAoFM,SAIA,UAJA,KAIA,YAJA;AAlFN,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,cAAc;AAEvB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAEhC,SAAS,wBAAwB;AAqD1B,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,cAAc;AAAA,EACd,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,SAAS,iBAAiB,UAAU;AAC1C,QAAM,aAAa,gBAAgB,QAAQ,UAAU;AACrD,QAAM,QAAQ,eAAe;AAC7B,QAAM,OAAO,QAAQ,OAAO;AAC5B,QAAM,OAAO,aAAa,YAAY,SAAS,MAAM;AAErD,QAAM,UACJ,YAAY,SACV,oBAAC,UAAO,MAAM,aAAa,SAAQ,UAAS,MACzC,iBAAO,SACV,IAEA,iCACG;AAAA,gBAAY,SACX,oBAAC,UAAO,MAAM,UAAU,SAAQ,aAAY,MACzC,iBAAO,cACV,IAEA,oBAAC,UAAO,MAAM,YAAY,SAAQ,aAAY,MAAY,WAAU,iBACjE,iBAAO,QACV;AAAA,IAEF,oBAAC,UAAO,MAAM,WAAW,MAAM,SAAQ,UAAS,MAC7C,qBAAW,OACd;AAAA,KACF;AAGJ,SACE;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,OAAO,oBAAC,eAAY,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI,MAAM,eAAe,MAAM,eAAe;AAAA,MACtG,SACE,iCACG;AAAA;AAAA,QACA;AAAA,QACD,oBAAC,UAAK,aAAU,yBAAwB,WAAU,2CAC/C,mBACH;AAAA,SACF;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The copy handler for the one minus sign (0.49 KIT-1b, Marcel's follow-up to KIT-1).
|
|
3
|
+
*
|
|
4
|
+
* The kit prints a negative with U+2212 (lib/minus.ts). A spreadsheet does not read that
|
|
5
|
+
* as a number: a figure copied out of a kit table and pasted into Excel landed as text.
|
|
6
|
+
* So while a selection inside the page is copied, every U+2212 standing directly before a
|
|
7
|
+
* number — optionally after a currency code or symbol and spaces: "−CHF 1,250.50",
|
|
8
|
+
* "−€2,000", "−12%" — becomes the ASCII "-" in the clipboard, in `text/plain` AND in
|
|
9
|
+
* `text/html` (Excel pastes the HTML flavour, as cells). The page keeps "−".
|
|
10
|
+
*
|
|
11
|
+
* A copy with no such minus is left to the browser untouched, and so is any copy out of an
|
|
12
|
+
* input, a textarea or an editable element: what the person typed is theirs.
|
|
13
|
+
*
|
|
14
|
+
* Installed once per document by `UiKitProvider` (`copyAsciiMinus`, default `true`) —
|
|
15
|
+
* the one part every app mounts, the signed-out pages included.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `text` with each U+2212 that stands before a number (in the sense above) as the ASCII
|
|
19
|
+
* hyphen-minus, every other character as it was — for text an app hands a machine that
|
|
20
|
+
* did not come from a formatter's `minus: "ascii"`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function asciiMinusInNumbers(text: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Listen for copies on `doc` until the returned function is called. Counted: nested
|
|
25
|
+
* providers install it once, and the last one to go removes it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function installClipboardMinus(doc?: Document): () => void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const MINUS_BEFORE_NUMBER = /\u2212(?=(?:[A-Z]{3}|\p{Sc})?[\s\u00a0\u202f]*\d)/gu;
|
|
3
|
+
function asciiMinusInNumbers(text) {
|
|
4
|
+
return text.replace(MINUS_BEFORE_NUMBER, "-");
|
|
5
|
+
}
|
|
6
|
+
function hasMinusBeforeNumber(text) {
|
|
7
|
+
MINUS_BEFORE_NUMBER.lastIndex = 0;
|
|
8
|
+
const found = MINUS_BEFORE_NUMBER.test(text);
|
|
9
|
+
MINUS_BEFORE_NUMBER.lastIndex = 0;
|
|
10
|
+
return found;
|
|
11
|
+
}
|
|
12
|
+
function isEditable(node) {
|
|
13
|
+
const el = node instanceof Element ? node : node?.parentElement;
|
|
14
|
+
if (!el) return false;
|
|
15
|
+
if (el.closest("input, textarea, select")) return true;
|
|
16
|
+
return el.isContentEditable === true || el.closest('[contenteditable=""], [contenteditable="true"]') !== null;
|
|
17
|
+
}
|
|
18
|
+
function wrapTableParts(container) {
|
|
19
|
+
const first = container.firstElementChild?.tagName;
|
|
20
|
+
const html = container.innerHTML;
|
|
21
|
+
if (first === "TD" || first === "TH") return `<table><tbody><tr>${html}</tr></tbody></table>`;
|
|
22
|
+
if (first === "TR") return `<table><tbody>${html}</tbody></table>`;
|
|
23
|
+
if (first === "TBODY" || first === "THEAD" || first === "TFOOT") return `<table>${html}</table>`;
|
|
24
|
+
return html;
|
|
25
|
+
}
|
|
26
|
+
function onCopy(event) {
|
|
27
|
+
if (event.defaultPrevented || !event.clipboardData) return;
|
|
28
|
+
const doc = event.target?.ownerDocument ?? document;
|
|
29
|
+
if (isEditable(event.target) || isEditable(doc.activeElement)) return;
|
|
30
|
+
const selection = doc.getSelection();
|
|
31
|
+
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;
|
|
32
|
+
if (isEditable(selection.anchorNode) || isEditable(selection.focusNode)) return;
|
|
33
|
+
const text = selection.toString();
|
|
34
|
+
if (!hasMinusBeforeNumber(text)) return;
|
|
35
|
+
const container = doc.createElement("div");
|
|
36
|
+
for (let i = 0; i < selection.rangeCount; i++) container.appendChild(selection.getRangeAt(i).cloneContents());
|
|
37
|
+
const walker = doc.createTreeWalker(container, NodeFilter.SHOW_TEXT);
|
|
38
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
39
|
+
node.nodeValue = asciiMinusInNumbers(node.nodeValue ?? "");
|
|
40
|
+
}
|
|
41
|
+
event.clipboardData.setData("text/plain", asciiMinusInNumbers(text));
|
|
42
|
+
event.clipboardData.setData("text/html", wrapTableParts(container));
|
|
43
|
+
event.preventDefault();
|
|
44
|
+
}
|
|
45
|
+
const installs = /* @__PURE__ */ new WeakMap();
|
|
46
|
+
function installClipboardMinus(doc = document) {
|
|
47
|
+
const count = installs.get(doc) ?? 0;
|
|
48
|
+
if (count === 0) doc.addEventListener("copy", onCopy);
|
|
49
|
+
installs.set(doc, count + 1);
|
|
50
|
+
let done = false;
|
|
51
|
+
return () => {
|
|
52
|
+
if (done) return;
|
|
53
|
+
done = true;
|
|
54
|
+
const left = (installs.get(doc) ?? 1) - 1;
|
|
55
|
+
installs.set(doc, left);
|
|
56
|
+
if (left === 0) doc.removeEventListener("copy", onCopy);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
asciiMinusInNumbers,
|
|
61
|
+
installClipboardMinus
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=clipboard-minus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/clipboard-minus.ts"],"sourcesContent":["/**\n * The copy handler for the one minus sign (0.49 KIT-1b, Marcel's follow-up to KIT-1).\n *\n * The kit prints a negative with U+2212 (lib/minus.ts). A spreadsheet does not read that\n * as a number: a figure copied out of a kit table and pasted into Excel landed as text.\n * So while a selection inside the page is copied, every U+2212 standing directly before a\n * number — optionally after a currency code or symbol and spaces: \"−CHF 1,250.50\",\n * \"−€2,000\", \"−12%\" — becomes the ASCII \"-\" in the clipboard, in `text/plain` AND in\n * `text/html` (Excel pastes the HTML flavour, as cells). The page keeps \"−\".\n *\n * A copy with no such minus is left to the browser untouched, and so is any copy out of an\n * input, a textarea or an editable element: what the person typed is theirs.\n *\n * Installed once per document by `UiKitProvider` (`copyAsciiMinus`, default `true`) —\n * the one part every app mounts, the signed-out pages included.\n */\n\n/** U+2212, then (optionally) a currency code or symbol, then spaces, then a digit. */\nconst MINUS_BEFORE_NUMBER = /\\u2212(?=(?:[A-Z]{3}|\\p{Sc})?[\\s\\u00a0\\u202f]*\\d)/gu;\n\n/**\n * `text` with each U+2212 that stands before a number (in the sense above) as the ASCII\n * hyphen-minus, every other character as it was — for text an app hands a machine that\n * did not come from a formatter's `minus: \"ascii\"`.\n */\nexport function asciiMinusInNumbers(text: string): string {\n return text.replace(MINUS_BEFORE_NUMBER, \"-\");\n}\n\nfunction hasMinusBeforeNumber(text: string): boolean {\n MINUS_BEFORE_NUMBER.lastIndex = 0;\n const found = MINUS_BEFORE_NUMBER.test(text);\n MINUS_BEFORE_NUMBER.lastIndex = 0;\n return found;\n}\n\n/** An input, a textarea or an editable element: a copy there is the person's own text. */\nfunction isEditable(node: Node | null | undefined): boolean {\n const el = node instanceof Element ? node : node?.parentElement;\n if (!el) return false;\n if (el.closest(\"input, textarea, select\")) return true;\n return (el as HTMLElement).isContentEditable === true || el.closest('[contenteditable=\"\"], [contenteditable=\"true\"]') !== null;\n}\n\n/** Table parts copied alone are wrapped back into a table, which Excel reads as cells. */\nfunction wrapTableParts(container: HTMLElement): string {\n const first = container.firstElementChild?.tagName;\n const html = container.innerHTML;\n if (first === \"TD\" || first === \"TH\") return `<table><tbody><tr>${html}</tr></tbody></table>`;\n if (first === \"TR\") return `<table><tbody>${html}</tbody></table>`;\n if (first === \"TBODY\" || first === \"THEAD\" || first === \"TFOOT\") return `<table>${html}</table>`;\n return html;\n}\n\nfunction onCopy(event: ClipboardEvent): void {\n if (event.defaultPrevented || !event.clipboardData) return;\n const doc = (event.target as Node | null)?.ownerDocument ?? document;\n if (isEditable(event.target as Node | null) || isEditable(doc.activeElement)) return;\n const selection = doc.getSelection();\n if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;\n if (isEditable(selection.anchorNode) || isEditable(selection.focusNode)) return;\n const text = selection.toString();\n if (!hasMinusBeforeNumber(text)) return;\n\n const container = doc.createElement(\"div\");\n for (let i = 0; i < selection.rangeCount; i++) container.appendChild(selection.getRangeAt(i).cloneContents());\n const walker = doc.createTreeWalker(container, NodeFilter.SHOW_TEXT);\n for (let node = walker.nextNode(); node; node = walker.nextNode()) {\n node.nodeValue = asciiMinusInNumbers(node.nodeValue ?? \"\");\n }\n event.clipboardData.setData(\"text/plain\", asciiMinusInNumbers(text));\n event.clipboardData.setData(\"text/html\", wrapTableParts(container));\n event.preventDefault();\n}\n\nconst installs = new WeakMap<Document, number>();\n\n/**\n * Listen for copies on `doc` until the returned function is called. Counted: nested\n * providers install it once, and the last one to go removes it.\n */\nexport function installClipboardMinus(doc: Document = document): () => void {\n const count = installs.get(doc) ?? 0;\n if (count === 0) doc.addEventListener(\"copy\", onCopy);\n installs.set(doc, count + 1);\n let done = false;\n return () => {\n if (done) return;\n done = true;\n const left = (installs.get(doc) ?? 1) - 1;\n installs.set(doc, left);\n if (left === 0) doc.removeEventListener(\"copy\", onCopy);\n };\n}\n"],"mappings":";AAkBA,MAAM,sBAAsB;AAOrB,SAAS,oBAAoB,MAAsB;AACxD,SAAO,KAAK,QAAQ,qBAAqB,GAAG;AAC9C;AAEA,SAAS,qBAAqB,MAAuB;AACnD,sBAAoB,YAAY;AAChC,QAAM,QAAQ,oBAAoB,KAAK,IAAI;AAC3C,sBAAoB,YAAY;AAChC,SAAO;AACT;AAGA,SAAS,WAAW,MAAwC;AAC1D,QAAM,KAAK,gBAAgB,UAAU,OAAO,MAAM;AAClD,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI,GAAG,QAAQ,yBAAyB,EAAG,QAAO;AAClD,SAAQ,GAAmB,sBAAsB,QAAQ,GAAG,QAAQ,gDAAgD,MAAM;AAC5H;AAGA,SAAS,eAAe,WAAgC;AACtD,QAAM,QAAQ,UAAU,mBAAmB;AAC3C,QAAM,OAAO,UAAU;AACvB,MAAI,UAAU,QAAQ,UAAU,KAAM,QAAO,qBAAqB,IAAI;AACtE,MAAI,UAAU,KAAM,QAAO,iBAAiB,IAAI;AAChD,MAAI,UAAU,WAAW,UAAU,WAAW,UAAU,QAAS,QAAO,UAAU,IAAI;AACtF,SAAO;AACT;AAEA,SAAS,OAAO,OAA6B;AAC3C,MAAI,MAAM,oBAAoB,CAAC,MAAM,cAAe;AACpD,QAAM,MAAO,MAAM,QAAwB,iBAAiB;AAC5D,MAAI,WAAW,MAAM,MAAqB,KAAK,WAAW,IAAI,aAAa,EAAG;AAC9E,QAAM,YAAY,IAAI,aAAa;AACnC,MAAI,CAAC,aAAa,UAAU,eAAe,KAAK,UAAU,YAAa;AACvE,MAAI,WAAW,UAAU,UAAU,KAAK,WAAW,UAAU,SAAS,EAAG;AACzE,QAAM,OAAO,UAAU,SAAS;AAChC,MAAI,CAAC,qBAAqB,IAAI,EAAG;AAEjC,QAAM,YAAY,IAAI,cAAc,KAAK;AACzC,WAAS,IAAI,GAAG,IAAI,UAAU,YAAY,IAAK,WAAU,YAAY,UAAU,WAAW,CAAC,EAAE,cAAc,CAAC;AAC5G,QAAM,SAAS,IAAI,iBAAiB,WAAW,WAAW,SAAS;AACnE,WAAS,OAAO,OAAO,SAAS,GAAG,MAAM,OAAO,OAAO,SAAS,GAAG;AACjE,SAAK,YAAY,oBAAoB,KAAK,aAAa,EAAE;AAAA,EAC3D;AACA,QAAM,cAAc,QAAQ,cAAc,oBAAoB,IAAI,CAAC;AACnE,QAAM,cAAc,QAAQ,aAAa,eAAe,SAAS,CAAC;AAClE,QAAM,eAAe;AACvB;AAEA,MAAM,WAAW,oBAAI,QAA0B;AAMxC,SAAS,sBAAsB,MAAgB,UAAsB;AAC1E,QAAM,QAAQ,SAAS,IAAI,GAAG,KAAK;AACnC,MAAI,UAAU,EAAG,KAAI,iBAAiB,QAAQ,MAAM;AACpD,WAAS,IAAI,KAAK,QAAQ,CAAC;AAC3B,MAAI,OAAO;AACX,SAAO,MAAM;AACX,QAAI,KAAM;AACV,WAAO;AACP,UAAM,QAAQ,SAAS,IAAI,GAAG,KAAK,KAAK;AACxC,aAAS,IAAI,KAAK,IAAI;AACtB,QAAI,SAAS,EAAG,KAAI,oBAAoB,QAAQ,MAAM;AAAA,EACxD;AACF;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The window's title from its parts (0.49 KIT-9): `{page}`, `{section}` and `{app}` in a
|
|
3
|
+
* format, by default "{page} · {section} · {app}" — "Invoices · Finance · Kastlan".
|
|
4
|
+
*
|
|
5
|
+
* A part that is missing (undefined, null, empty or blank) is dropped WITH the separator
|
|
6
|
+
* before it, so "Invoices · Kastlan" never reads "Invoices · · Kastlan". The text between
|
|
7
|
+
* two parts is the separator; text before the first part and after the last is kept as
|
|
8
|
+
* written ("[{page} – {app}]" → "[KS]"). No part at all gives "".
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_DOCUMENT_TITLE_FORMAT = "{page} \u00B7 {section} \u00B7 {app}";
|
|
11
|
+
/** The parts {@link formatDocumentTitle} fills in. */
|
|
12
|
+
export interface DocumentTitleParts {
|
|
13
|
+
page?: string | null;
|
|
14
|
+
section?: string | null;
|
|
15
|
+
app?: string | null;
|
|
16
|
+
}
|
|
17
|
+
export declare function formatDocumentTitle(format: string, parts: DocumentTitleParts): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
const DEFAULT_DOCUMENT_TITLE_FORMAT = "{page} \xB7 {section} \xB7 {app}";
|
|
3
|
+
const PLACEHOLDER = /\{(page|section|app)\}/g;
|
|
4
|
+
function formatDocumentTitle(format, parts) {
|
|
5
|
+
let prefix = "";
|
|
6
|
+
let out = "";
|
|
7
|
+
let pending = "";
|
|
8
|
+
let last = 0;
|
|
9
|
+
let seen = false;
|
|
10
|
+
for (const m of format.matchAll(PLACEHOLDER)) {
|
|
11
|
+
const literal = format.slice(last, m.index);
|
|
12
|
+
last = m.index + m[0].length;
|
|
13
|
+
if (!seen) prefix = literal;
|
|
14
|
+
else pending = out === "" ? "" : literal || pending;
|
|
15
|
+
seen = true;
|
|
16
|
+
const value = parts[m[1]]?.trim();
|
|
17
|
+
if (!value) continue;
|
|
18
|
+
out += (out === "" ? "" : pending) + value;
|
|
19
|
+
pending = "";
|
|
20
|
+
}
|
|
21
|
+
if (!seen) return format;
|
|
22
|
+
if (out === "") return "";
|
|
23
|
+
return prefix + out + format.slice(last);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
DEFAULT_DOCUMENT_TITLE_FORMAT,
|
|
27
|
+
formatDocumentTitle
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=document-title.js.map
|