@eifi1/ui-kit 0.41.0 → 0.43.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 -7
- package/dist/admin/admin-area-labels.d.ts +59 -0
- package/dist/admin/admin-area-labels.js +35 -0
- package/dist/admin/admin-area-labels.js.map +1 -0
- package/dist/admin/admin-forbidden.d.ts +35 -0
- package/dist/admin/admin-forbidden.js +36 -0
- package/dist/admin/admin-forbidden.js.map +1 -0
- package/dist/admin/admin-overview.d.ts +110 -0
- package/dist/admin/admin-overview.js +92 -0
- package/dist/admin/admin-overview.js.map +1 -0
- package/dist/admin/admin-sections.d.ts +94 -0
- package/dist/admin/admin-sections.js +81 -0
- package/dist/admin/admin-sections.js.map +1 -0
- package/dist/admin/admin-tool-links.d.ts +48 -0
- package/dist/admin/admin-tool-links.js +31 -0
- package/dist/admin/admin-tool-links.js.map +1 -0
- package/dist/billing/billing-banner.d.ts +33 -2
- package/dist/billing/billing-banner.js +29 -3
- package/dist/billing/billing-banner.js.map +1 -1
- package/dist/billing/billing-labels.d.ts +36 -0
- package/dist/billing/billing-labels.js +10 -0
- package/dist/billing/billing-labels.js.map +1 -1
- package/dist/billing/billing-overview.d.ts +33 -0
- package/dist/billing/billing-overview.js +6 -0
- package/dist/billing/billing-overview.js.map +1 -1
- package/dist/billing/billing-standing.d.ts +8 -0
- package/dist/billing/billing-standing.js.map +1 -1
- package/dist/billing/cancel-request.d.ts +53 -0
- package/dist/billing/cancel-request.js +21 -0
- package/dist/billing/cancel-request.js.map +1 -0
- package/dist/billing/cancel-subscription.d.ts +46 -0
- package/dist/billing/cancel-subscription.js +57 -0
- package/dist/billing/cancel-subscription.js.map +1 -0
- package/dist/billing/plan-card.d.ts +45 -1
- package/dist/billing/plan-card.js +53 -2
- package/dist/billing/plan-card.js.map +1 -1
- package/dist/billing/plan-switch.d.ts +10 -1
- package/dist/billing/plan-switch.js +22 -13
- package/dist/billing/plan-switch.js.map +1 -1
- package/dist/billing/provider-page.d.ts +40 -0
- package/dist/billing/provider-page.js +33 -0
- package/dist/billing/provider-page.js.map +1 -0
- package/dist/billing/subscription-actions.d.ts +68 -4
- package/dist/billing/subscription-actions.js +65 -5
- package/dist/billing/subscription-actions.js.map +1 -1
- package/dist/components/account-chips.d.ts +50 -2
- package/dist/components/account-chips.js +33 -0
- package/dist/components/account-chips.js.map +1 -1
- package/dist/components/empty-state.d.ts +2 -1
- package/dist/components/empty-state.js.map +1 -1
- package/dist/eslint/index.js +1 -1
- package/dist/feedback/feedback-menu.d.ts +7 -4
- package/dist/feedback/feedback-menu.js +4 -2
- package/dist/feedback/feedback-menu.js.map +1 -1
- package/dist/hooks/use-search-param-state.js +4 -1
- package/dist/hooks/use-search-param-state.js.map +1 -1
- package/dist/i18n/defaults.js +7 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/german.js +113 -0
- package/dist/i18n/german.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +12 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/en.js +142 -1
- package/dist/i18n/locales/en.js.map +3 -3
- package/dist/i18n/locales/es.js +110 -0
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.js +109 -0
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.js +110 -0
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.js +110 -0
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.js +109 -0
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/i18n/review.js +34 -1
- package/dist/i18n/review.js.map +1 -1
- package/dist/index.d.ts +24 -2
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/search/global-search.d.ts +3 -0
- package/dist/search/global-search.js +3 -1
- package/dist/search/global-search.js.map +1 -1
- package/dist/settings/settings-catalogue.d.ts +9 -1
- package/dist/settings/settings-catalogue.js +1 -1
- package/dist/settings/settings-catalogue.js.map +1 -1
- package/dist/settings/settings-layout.d.ts +7 -1
- package/dist/settings/settings-layout.js +35 -27
- package/dist/settings/settings-layout.js.map +1 -1
- package/dist/shell/account-menu-language.d.ts +46 -0
- package/dist/shell/account-menu-language.js +64 -0
- package/dist/shell/account-menu-language.js.map +1 -0
- package/dist/shell/admin-menu.d.ts +69 -0
- package/dist/shell/admin-menu.js +64 -0
- package/dist/shell/admin-menu.js.map +1 -0
- package/dist/shell/app-shell.d.ts +10 -0
- package/dist/shell/app-shell.js +22 -4
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/dev-switchers.d.ts +53 -0
- package/dist/shell/dev-switchers.js +107 -0
- package/dist/shell/dev-switchers.js.map +1 -0
- package/dist/shell/sync-status-indicator.d.ts +86 -0
- package/dist/shell/sync-status-indicator.js +170 -0
- package/dist/shell/sync-status-indicator.js.map +1 -0
- package/dist/shell/top-bar-actions.d.ts +49 -0
- package/dist/shell/top-bar-actions.js +31 -0
- package/dist/shell/top-bar-actions.js.map +1 -0
- package/dist/shell/top-bar-parts-labels.d.ts +90 -0
- package/dist/shell/top-bar-parts-labels.js +51 -0
- package/dist/shell/top-bar-parts-labels.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +13 -1
- package/dist/shell/topbar-action-menu.js +5 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +16 -3
- package/dist/shell/topbar-controls.js +5 -1
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell/tour-menu.d.ts +67 -0
- package/dist/shell/tour-menu.js +87 -0
- package/dist/shell/tour-menu.js.map +1 -0
- package/dist/shell.d.ts +16 -0
- package/dist/shell.js +21 -0
- package/dist/shell.js.map +1 -1
- package/dist/tour/tour-catalogue-labels.d.ts +44 -0
- package/dist/tour/tour-catalogue-labels.js +32 -0
- package/dist/tour/tour-catalogue-labels.js.map +1 -0
- package/dist/tour/tour-catalogue.d.ts +68 -0
- package/dist/tour/tour-catalogue.js +189 -0
- package/dist/tour/tour-catalogue.js.map +1 -0
- package/dist/tour/tour-info.d.ts +112 -0
- package/dist/tour/tour-info.js +36 -0
- package/dist/tour/tour-info.js.map +1 -0
- package/dist/tour/use-tour-progress.d.ts +61 -0
- package/dist/tour/use-tour-progress.js +116 -0
- package/dist/tour/use-tour-progress.js.map +1 -0
- package/dist/tour/use-tour-url-sync.d.ts +58 -0
- package/dist/tour/use-tour-url-sync.js +110 -0
- package/dist/tour/use-tour-url-sync.js.map +1 -0
- package/dist/tour.d.ts +8 -0
- package/dist/tour.js +18 -0
- package/dist/tour.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/admin-area-labels.ts +91 -0
- package/src/admin/admin-forbidden.tsx +75 -0
- package/src/admin/admin-overview.tsx +217 -0
- package/src/admin/admin-sections.tsx +198 -0
- package/src/admin/admin-tool-links.tsx +84 -0
- package/src/billing/billing-banner.tsx +57 -6
- package/src/billing/billing-labels.ts +59 -0
- package/src/billing/billing-overview.ts +37 -0
- package/src/billing/billing-standing.ts +8 -0
- package/src/billing/cancel-request.ts +75 -0
- package/src/billing/cancel-subscription.tsx +102 -0
- package/src/billing/plan-card.tsx +97 -1
- package/src/billing/plan-switch.tsx +16 -0
- package/src/billing/provider-page.ts +75 -0
- package/src/billing/subscription-actions.tsx +155 -20
- package/src/components/account-chips.tsx +89 -2
- package/src/components/empty-state.tsx +2 -1
- package/src/feedback/feedback-menu.tsx +8 -3
- package/src/hooks/use-search-param-state.ts +6 -1
- package/src/i18n/defaults.ts +6 -0
- package/src/i18n/german.ts +127 -0
- package/src/i18n/kit-labels.tsx +12 -0
- package/src/i18n/locales/en.ts +32 -0
- package/src/i18n/locales/es.ts +121 -0
- package/src/i18n/locales/fr.ts +121 -0
- package/src/i18n/locales/hu.ts +119 -0
- package/src/i18n/locales/it.ts +122 -0
- package/src/i18n/locales/zh.ts +114 -0
- package/src/i18n/review.ts +33 -0
- package/src/index.ts +38 -2
- package/src/search/global-search.tsx +5 -0
- package/src/settings/settings-catalogue.ts +10 -2
- package/src/settings/settings-layout.tsx +58 -34
- package/src/shell/account-menu-language.tsx +116 -0
- package/src/shell/admin-menu.tsx +146 -0
- package/src/shell/app-shell.tsx +44 -3
- package/src/shell/dev-switchers.tsx +179 -0
- package/src/shell/sync-status-indicator.tsx +301 -0
- package/src/shell/top-bar-actions.tsx +79 -0
- package/src/shell/top-bar-parts-labels.ts +142 -0
- package/src/shell/topbar-action-menu.tsx +15 -2
- package/src/shell/topbar-controls.tsx +20 -3
- package/src/shell/tour-menu.tsx +179 -0
- package/src/shell.ts +27 -0
- package/src/tour/tour-catalogue-labels.ts +75 -0
- package/src/tour/tour-catalogue.tsx +316 -0
- package/src/tour/tour-info.ts +144 -0
- package/src/tour/use-tour-progress.ts +198 -0
- package/src/tour/use-tour-url-sync.ts +221 -0
- package/src/tour.ts +11 -0
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\";\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.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.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\";\nexport { RowActions, rowActionsColumn, DEFAULT_ROW_ACTIONS_LABELS } from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\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.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, planRelation } from \"./billing/plan-card\";\nexport type { BillingPlan, PlanRelation, PlanCardProps, PlanPickerProps, PlanChoice } 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// 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} 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\";\nexport { TimeZoneSelect, timeZoneOptions, deviceTimeZone } from \"./notifications/time-zone-select\";\nexport type { TimeZoneSelectProps } from \"./notifications/time-zone-select\";\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\";\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.\nexport {\n useFeedbackNotificationTypes,\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\";\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\";\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.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\";\nexport { RowActions, rowActionsColumn, DEFAULT_ROW_ACTIONS_LABELS } from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\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} from \"./admin/admin-overview\";\nexport { AdminToolLinks } from \"./admin/admin-tool-links\";\nexport type { AdminToolLink, AdminToolLinksProps } from \"./admin/admin-tool-links\";\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} 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\";\nexport { TimeZoneSelect, timeZoneOptions, deviceTimeZone } from \"./notifications/time-zone-select\";\nexport type { TimeZoneSelectProps } from \"./notifications/time-zone-select\";\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\";\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.\nexport {\n useFeedbackNotificationTypes,\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":[]}
|
|
@@ -161,6 +161,9 @@ export interface GlobalSearchProps {
|
|
|
161
161
|
labels?: LabelOverride<GlobalSearchLabels>;
|
|
162
162
|
/** Passed through to the palette (`empty`, `loading`, `error`, `hint`, …). */
|
|
163
163
|
paletteLabels?: Partial<CommandPaletteLabels>;
|
|
164
|
+
/** 0.43: `data-*` attributes go on the kit's trigger button (`trigger="button"`) — a
|
|
165
|
+
* tour's anchor (`data-tour="search"`), a test hook. A function trigger is the app's. */
|
|
166
|
+
[key: `data-${string}`]: string | number | boolean | undefined;
|
|
164
167
|
}
|
|
165
168
|
/**
|
|
166
169
|
* The app-wide ⌘K search, whole: the top-bar trigger, the shortcut, and a
|
|
@@ -70,7 +70,8 @@ function GlobalSearchImpl({
|
|
|
70
70
|
triggerName = "plain",
|
|
71
71
|
density,
|
|
72
72
|
labels,
|
|
73
|
-
paletteLabels
|
|
73
|
+
paletteLabels,
|
|
74
|
+
...attributes
|
|
74
75
|
}) {
|
|
75
76
|
const l = useKitLabels("globalSearch", DEFAULT_GLOBAL_SEARCH_LABELS, labels);
|
|
76
77
|
const pl = useKitLabels("commandPalette", DEFAULT_COMMAND_PALETTE_LABELS, paletteLabels);
|
|
@@ -278,6 +279,7 @@ function GlobalSearchImpl({
|
|
|
278
279
|
children: /* @__PURE__ */ jsx(
|
|
279
280
|
"button",
|
|
280
281
|
{
|
|
282
|
+
...Object.fromEntries(Object.entries(attributes).filter(([k]) => k.startsWith("data-"))),
|
|
281
283
|
type: "button",
|
|
282
284
|
onClick: openSearch,
|
|
283
285
|
"aria-label": triggerLabel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/search/global-search.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { useHref, useInRouterContext, useNavigate } from \"react-router\";\nimport { AlertCircle, Loader2, Search } from \"lucide-react\";\nimport { Tooltip } from \"../components/tooltip\";\nimport { TOPBAR_TRIGGER_CLASS } from \"../shell/topbar-controls\";\nimport { cn } from \"../lib/cn\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\n// Types only from ./command-palette, gone from the built module: the palette loads late.\nimport type { CommandItem, CommandPaletteDensity, CommandPaletteLabels } from \"./command-palette\";\nimport { DEFAULT_COMMAND_PALETTE_LABELS } from \"./command-palette-labels\";\nimport { useCommandKey } from \"./use-command-key\";\nimport { createSearchIndex } from \"./search-index\";\nimport type { SearchEntry, SearchIndexOptions } from \"./search-index\";\nimport { DEFAULT_GLOBAL_SEARCH_LABELS } from \"./global-search-labels\";\n\n/**\n * The palette, loaded when the search is first opened rather than with the top bar\n * (0.34, MOD-1 of the refactor audit 2026-10): ~5.5 kB gzip of keksdose's and kastlan's\n * entry chunks, for a dialog drawn only once somebody searches. A LITERAL relative\n * `import()`, as the catalogue loaders are (i18n/languages.ts), so the library build keeps\n * the module its own and an app's bundler splits it off.\n */\nconst LazyCommandPalette = lazy(() =>\n import(\"./command-palette\").then((module) => ({ default: module.CommandPalette })),\n);\n\nexport interface GlobalSearchLabels {\n /** The trigger's accessible name, and the dialog's. */\n trigger: string;\n /** The field's placeholder — says WHAT can be found, which \"Search…\" does not. */\n placeholder: string;\n /** The trigger's tooltip, given the shortcut as the platform writes it (\"⌘K\",\n * \"Ctrl K\"). A function so a language can put the keys where its grammar wants. */\n shortcut: (keys: string) => string;\n /** Heading of the suggestions shown for an empty query. */\n suggestions: string;\n /** Heading for entries that name no `group`. */\n results: string;\n}\n\n// Defined in ./global-search-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_GLOBAL_SEARCH_LABELS };\n\n/**\n * A place results come from that is not the static index — a server search, a\n * local-first store too large to hand over whole. Each source is its own group, with its\n * own debounce, its own \"Searching…\" line and its own failure: the static groups never\n * wait for it, and one source failing never takes another's results with it.\n */\nexport interface GlobalSearchSource {\n /** Stable key — the effect that runs the source is keyed by it, not by identity. */\n id: string;\n /** The group its results are shown under (an entry's own `group` is ignored) — unless\n * `groups` is set, where it is only the home of entries that name no declared group.\n * If every entry names a declared group, it is never shown: a catch-all heading such\n * as \"Other\" is the honest value, so a stray type would still surface, labelled. */\n group: string;\n /**\n * Split ONE request into several groups — kastlan's record search answers with\n * properties, units, contacts, leases and invoices at once, and one source per group\n * meant a dedupe layer so the network still saw one request. Each entry is then shown\n * under the group its own `group` names: a declared `key` (shown by its `label`) or a\n * plain string (key and heading at once). The groups appear in THIS order whatever the\n * answer's order, each kept to `limit` rows; an entry naming no declared group falls\n * under `group`. While the request runs, or when it fails, the source shows one status\n * line under its first group, not one per group. Unset: one group, as before.\n */\n groups?: readonly (string | GlobalSearchSourceGroup)[];\n /** Called with the trimmed query. Its results are shown AS GIVEN — the source ranked\n * them — and never re-filtered by the index's matcher. `signal` aborts when the query\n * moves on or the palette closes; a stale answer is dropped either way. */\n search: (query: string, signal: AbortSignal) => Promise<readonly SearchEntry[]> | readonly SearchEntry[];\n /** Shortest query it is asked for. Default 2 — one letter matches half a database. */\n minChars?: number;\n /** Quiet period after the last keystroke before it is asked. Default 200ms. */\n debounceMs?: number;\n /** Rows kept — per group, when `groups` is set. Default: `indexOptions.groupLimit` (8). */\n limit?: number;\n /** Mask every row of this source for session replay, hints (amounts) included. An\n * entry's own `redact` still wins. */\n redact?: boolean;\n /** Told when `search` throws or rejects (not when it is aborted). The group then\n * shows the palette's `error` line instead of rows. */\n onError?: (error: unknown) => void;\n}\n\n/** One of a multi-group source's groups: the `key` its entries name in `group`, and the\n * heading shown — so a server's type (\"unit\") need not be translated per entry. */\nexport interface GlobalSearchSourceGroup {\n key: string;\n label: string;\n}\n\n/** What a custom trigger gets: everything the default button uses. */\nexport interface GlobalSearchTriggerProps {\n open: () => void;\n /** Resolved `trigger` label — the accessible name. */\n label: string;\n /** Resolved `shortcut(keys)` — the tooltip. */\n tooltip: string;\n /** \"⌘K\" on Apple platforms, \"Ctrl K\" elsewhere. */\n keys: string;\n /** For the trigger's `aria-keyshortcuts`. */\n ariaKeyShortcuts: string;\n}\n\n/** A suggestion for the empty query: an entry, the `id` of one in `entries`, or a query\n * to type into the field. */\nexport type GlobalSearchSuggestion = SearchEntry | string | { query: string };\n\nexport interface GlobalSearchProps {\n /**\n * The static index: pages, actions, settings rows — already filtered by the app (by\n * role, by privacy mode). Matched and ranked by {@link createSearchIndex}.\n *\n * Changing it re-runs the open search by itself. Nothing has to be stable: the index is\n * rebuilt only when the entries' TEXT changes (ids, titles, keywords, …), so a list\n * rebuilt on every render — `data = []` while a query is pending, icons as fresh JSX —\n * neither re-indexes nor loops, and the icons and handlers used are always the latest.\n */\n entries?: readonly SearchEntry[];\n /** The async sources, each streamed into its own group — or several (`groups`). */\n sources?: readonly GlobalSearchSource[];\n /** What the empty query shows, under the `suggestions` heading. */\n suggestions?: readonly GlobalSearchSuggestion[];\n /**\n * Show each suggested ENTRY under its own `group` instead of all of them under the\n * one `suggestions` heading — keksdose's empty palette listed \"Pages\" and \"Actions\"\n * apart, and one \"Try\" heading over both lost the difference. An entry with no\n * `group` and a query suggestion (`{ query }`) stay under `suggestions`. `groupOrder`\n * orders these groups as it orders the results'. Off by default.\n */\n suggestionsKeepGroups?: boolean;\n /** Groups listed here come first, in this order; the rest follow in ranking order. */\n groupOrder?: readonly string[];\n /** Ranking and capping — `groupLimit` (default 8) applies to every group. */\n indexOptions?: SearchIndexOptions;\n /**\n * How an entry's `href` is followed on a plain click or ↵. Default: react-router's\n * `navigate` when the search is rendered inside a router, else a full page load.\n */\n navigate?: (href: string) => void;\n /**\n * The browser URL of an `href`, for the row's real link (middle-/⌘-click opens a tab).\n * Default inside a router: the router's own (`#/page` under a hash router, the\n * basename prefixed under a browser router); outside one, the href itself.\n */\n hrefFor?: (href: string) => string;\n /** Register ⌘K / Ctrl K. Default true; turn it off for a second, scoped search on a\n * page that already has the app-wide one. */\n shortcut?: boolean;\n /** Controlled open state — so a button anywhere can open it. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Controlled query, as on `CommandPalette` (keksdose binds it to the URL's `q`). */\n query?: string;\n onQueryChange?: (query: string) => void;\n searchOn?: \"input\" | \"submit\";\n /** Mask every row for session replay (see `CommandPalette`). A source's or an entry's\n * own `redact` wins. */\n redactLabels?: boolean;\n fullScreenOnPhone?: boolean;\n /** `\"button\"` (default): the top-bar icon button. `\"none\"`: no trigger — the shortcut\n * or a controlled `open` opens it. A function renders a trigger of your own. */\n trigger?: \"button\" | \"none\" | ((props: GlobalSearchTriggerProps) => ReactNode);\n /** Hide the default trigger below `sm` (kastlan's phone top bar has no room). */\n hideTriggerOnPhone?: boolean;\n /** Class for the default trigger button, merged over `TOPBAR_TRIGGER_CLASS`. */\n triggerClassName?: string;\n /**\n * The default trigger's magnifier, in px. Default 16 (`size-4`), as it always was;\n * 20 matches the kit's other top-bar triggers (`TopbarIconButton` draws `size-5`) and\n * keksdose's top bar, which reached into the button with `[&_svg]:size-5` for it.\n */\n triggerIconSize?: number;\n /**\n * Whether the trigger's accessible name includes the shortcut: `\"plain\"` (default)\n * names it \"Search\"; `\"withShortcut\"` names it by `labels.shortcut(keys)` —\n * \"Search (⌘K)\" on Apple platforms, \"Search (Ctrl K)\" elsewhere — the same text its\n * tooltip shows, so a speech-control user (\"click Search\") and a sighted keyboard user\n * meet the shortcut in the name itself (keksdose C25). `aria-keyshortcuts` is set\n * either way. Also reaches a custom trigger as `triggerProps.label`.\n */\n triggerName?: \"plain\" | \"withShortcut\";\n /** The palette's row height — `CommandPalette`'s `density`. Default `\"compact\"`. */\n density?: CommandPaletteDensity;\n labels?: LabelOverride<GlobalSearchLabels>;\n /** Passed through to the palette (`empty`, `loading`, `error`, `hint`, …). */\n paletteLabels?: Partial<CommandPaletteLabels>;\n}\n\nfunction isApplePlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n return /mac|iphone|ipad|ipod/i.test(nav.userAgentData?.platform || nav.platform || nav.userAgent);\n}\n\nconst pageLoad = (href: string) => window.location.assign(href);\nconst identity = (href: string) => href;\n\n/** The entries' text, which is all the index reads — see `entries`. */\nfunction signature(entries: readonly SearchEntry[]): string {\n return entries\n .map((e) =>\n [e.id, e.title, (e.keywords ?? []).join(\"\\u0003\"), e.description, e.group, e.hint, e.href, e.weight, e.redact].join(\n \"\\u0001\",\n ),\n )\n .join(\"\\u0002\");\n}\n\n/** Focus the open palette's field again — after a suggestion typed itself into it, the\n * row that was clicked (and held focus) is gone. */\nfunction refocusField() {\n requestAnimationFrame(() => {\n const fields = document.querySelectorAll<HTMLInputElement>('[role=\"dialog\"][aria-modal=\"true\"] input[role=\"combobox\"]');\n fields[fields.length - 1]?.focus();\n });\n}\n\ninterface SourceResult {\n query: string;\n status: \"loading\" | \"done\" | \"error\";\n entries: readonly SearchEntry[];\n}\n\n/**\n * The app-wide ⌘K search, whole: the top-bar trigger, the shortcut, and a\n * {@link CommandPalette} fed from a ranked index ({@link createSearchIndex}) and any\n * number of async sources.\n *\n * Every consumer had built this out of `CommandPalette` by hand, and each copy had the\n * same holes — a substring match, no ranking, no typo tolerance, results in declaration\n * order, one monolithic provider in which the static groups waited on the slowest\n * request. This is that wrapper once:\n *\n * <GlobalSearch\n * entries={pages} // { id, title, keywords, group, href, icon }\n * sources={[{ id: \"tx\", group: \"Transactions\", search: (q, signal) => api.search(q, { signal }) }]}\n * suggestions={[\"page-budget\", \"action-new-account\"]}\n * />\n *\n * Inside a react-router tree it navigates with the router and builds its links with it;\n * outside one, pass `navigate` (or accept full page loads).\n *\n * Since 0.34 the palette's module loads on the first open (MOD-1), so the dialog appears a\n * moment after the trigger or ⌘K: a test finds it with `await screen.findBy…`.\n */\nexport function GlobalSearch(props: GlobalSearchProps) {\n // Two components rather than a conditional hook: `useNavigate` throws outside a\n // router, and whether we are in one does not change over a component's life.\n const inRouter = useInRouterContext();\n if (inRouter && (!props.navigate || !props.hrefFor)) return <RoutedGlobalSearch {...props} />;\n return <GlobalSearchImpl {...props} navigate={props.navigate ?? pageLoad} hrefFor={props.hrefFor ?? identity} />;\n}\n\nfunction RoutedGlobalSearch(props: GlobalSearchProps) {\n const routerNavigate = useNavigate();\n // The router's href for \"/\" is its base (\"#/\" under a hash router, \"/app/\" under a\n // basename); every href is that base plus the path.\n const base = useHref(\"/\").replace(/\\/$/, \"\");\n const navigate = useCallback((href: string) => void routerNavigate(href), [routerNavigate]);\n const hrefFor = useCallback((href: string) => (href.startsWith(\"/\") ? base + href : href), [base]);\n return <GlobalSearchImpl {...props} navigate={props.navigate ?? navigate} hrefFor={props.hrefFor ?? hrefFor} />;\n}\n\nfunction GlobalSearchImpl({\n entries,\n sources,\n suggestions,\n suggestionsKeepGroups = false,\n groupOrder,\n indexOptions,\n navigate,\n hrefFor,\n shortcut = true,\n open: openProp,\n onOpenChange,\n query: queryProp,\n onQueryChange,\n searchOn,\n redactLabels = false,\n fullScreenOnPhone,\n trigger = \"button\",\n hideTriggerOnPhone = false,\n triggerClassName,\n triggerIconSize,\n triggerName = \"plain\",\n density,\n labels,\n paletteLabels,\n}: GlobalSearchProps & { navigate: (href: string) => void; hrefFor: (href: string) => string }) {\n const l = useKitLabels(\"globalSearch\", DEFAULT_GLOBAL_SEARCH_LABELS, labels);\n const pl = useKitLabels(\"commandPalette\", DEFAULT_COMMAND_PALETTE_LABELS, paletteLabels);\n const [ownOpen, setOwnOpen] = useState(false);\n const open = openProp ?? ownOpen;\n const [ownQuery, setOwnQuery] = useState(\"\");\n const queryControlled = queryProp !== undefined;\n const query = queryControlled ? queryProp : ownQuery;\n const q = query.trim();\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (openProp === undefined) setOwnOpen(next);\n onOpenChange?.(next);\n },\n [openProp, onOpenChange],\n );\n const setQuery = useCallback(\n (next: string) => {\n if (!queryControlled) setOwnQuery(next);\n onQueryChange?.(next);\n },\n [queryControlled, onQueryChange],\n );\n\n // Each open starts blank — unless the owner controls the query (a URL `q`). Adjusted\n // during render, React's pattern for state that follows a prop, so a controlled `open`\n // gets the same reset as the trigger does.\n const [wasOpen, setWasOpen] = useState(open);\n if (wasOpen !== open) {\n setWasOpen(open);\n if (open && !queryControlled) setOwnQuery(\"\");\n }\n\n // The palette mounts on the first open — its module loads then — and stays mounted\n // after, closed, as it always was (MOD-1): a closed palette keeps the last results, and\n // a reopen over an owner-held query shows them at once, where a palette mounted anew\n // would say \"No results\" through its debounce first.\n const [paletteMounted, setPaletteMounted] = useState(open);\n if (open && !paletteMounted) setPaletteMounted(true);\n\n const openSearch = useCallback(() => setOpen(true), [setOpen]);\n const noop = useCallback(() => {}, []);\n useCommandKey(shortcut ? openSearch : noop);\n\n /* ── the static index ─────────────────────────────────────────────────── */\n\n // Everything below is keyed by CONTENT, never by the identity of what the app passed:\n // inline arrays and `data = []` defaults are the norm, and an identity key would\n // re-index and re-search on every render of the app. Handlers, which can close over\n // anything, are read from refs at the moment a row is chosen — never stale.\n const list = entries ?? EMPTY;\n const sig = signature(list);\n const optionsKey = JSON.stringify(indexOptions ?? {});\n const groupLimit = indexOptions?.groupLimit ?? 8;\n // `sig` and `optionsKey` stand for `list` and `indexOptions`: same text, same index.\n /* eslint-disable react-hooks/exhaustive-deps */\n const index = useMemo(() => createSearchIndex(list, indexOptions), [sig, optionsKey]);\n const byId = useMemo(() => new Map(list.map((e) => [e.id, e])), [sig]);\n\n const sourceKey = (sources ?? [])\n .map((s) =>\n [\n s.id,\n s.group,\n (s.groups ?? []).map((g) => (typeof g === \"string\" ? g : `${g.key}\\u0003${g.label}`)).join(\"\\u0004\"),\n s.minChars ?? 2,\n s.debounceMs ?? 200,\n s.limit,\n s.redact,\n ].join(\"\\u0001\"),\n )\n .join(\"\\u0002\");\n const sourceList = useMemo(() => sources ?? [], [sourceKey]);\n\n const suggestionsKey = (suggestions ?? [])\n .map((s) => (typeof s === \"string\" ? `i:${s}` : \"query\" in s ? `q:${s.query}` : `e:${signature([s])}`))\n .join(\"\\u0002\");\n const suggestionList = useMemo(() => suggestions ?? [], [suggestionsKey]);\n\n const groupOrderKey = (groupOrder ?? []).join(\"\\u0002\");\n const order = useMemo(() => groupOrder ?? [], [groupOrderKey]);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n // The live objects, for the moment a row is chosen or a source is asked.\n const live = useRef({ entries: list, sources: sources ?? [], suggestions: suggestions ?? [], navigate });\n useLayoutEffect(() => {\n live.current = { entries: list, sources: sources ?? [], suggestions: suggestions ?? [], navigate };\n });\n\n /* ── the async sources ────────────────────────────────────────────────── */\n\n const [sourceResults, setSourceResults] = useState<Record<string, SourceResult>>({});\n useEffect(() => {\n const controllers: AbortController[] = [];\n const timers: ReturnType<typeof setTimeout>[] = [];\n const asked = open ? live.current.sources.filter((s) => q.length >= (s.minChars ?? 2)) : [];\n for (const source of asked) {\n const id = source.id;\n const controller = new AbortController();\n controllers.push(controller);\n timers.push(\n setTimeout(async () => {\n const settle = (result: SourceResult) => {\n if (!controller.signal.aborted) setSourceResults((prev) => ({ ...prev, [id]: result }));\n };\n try {\n const found = await source.search(q, controller.signal);\n settle({ query: q, status: \"done\", entries: found });\n } catch (error) {\n if (controller.signal.aborted) return;\n source.onError?.(error);\n settle({ query: q, status: \"error\", entries: [] });\n }\n }, source.debounceMs ?? 200),\n );\n }\n return () => {\n timers.forEach(clearTimeout);\n controllers.forEach((c) => c.abort());\n };\n }, [open, q, sourceKey]);\n\n /* ── rows ─────────────────────────────────────────────────────────────── */\n\n const toItem = useCallback(\n (prefix: string, entry: SearchEntry, group: string, redact = redactLabels): CommandItem => ({\n id: `${prefix}${entry.id}`,\n label: entry.title,\n hint: entry.hint,\n group,\n icon: entry.icon,\n redact: entry.redact ?? redact,\n href: entry.href !== undefined ? hrefFor(entry.href) : undefined,\n onSelect: () => {\n // The entry as the app has it NOW — its handler may close over newer state\n // than the one this row was built from.\n const current = live.current.entries.find((e) => e.id === entry.id) ?? entry;\n if (current.onSelect) current.onSelect();\n else if (current.href !== undefined) live.current.navigate(current.href);\n },\n }),\n [hrefFor, redactLabels],\n );\n\n // `toItem` only BUILDS `onSelect` closures here; `live` is read when a row is chosen,\n // which the compiler lint cannot tell from a read during render.\n /* eslint-disable react-hooks/refs */\n const items = useMemo((): CommandItem[] => {\n const ordered = (out: CommandItem[]) => {\n if (!order.length) return out;\n const rank = (group: string) => {\n const i = order.indexOf(group);\n return i === -1 ? order.length : i;\n };\n // Stable: within a rank, groups keep the order their best hit gave them.\n return out\n .map((item, i) => ({ item, i }))\n .sort((a, b) => rank(a.item.group) - rank(b.item.group) || a.i - b.i)\n .map(({ item }) => item);\n };\n\n if (!q) {\n const out: CommandItem[] = [];\n const groupOf = (entry: SearchEntry) =>\n suggestionsKeepGroups ? (entry.group ?? l.suggestions) : l.suggestions;\n suggestionList.forEach((s, i) => {\n if (typeof s === \"string\") {\n const entry = byId.get(s);\n if (entry) out.push(toItem(\"try:\", entry, groupOf(entry)));\n } else if (\"query\" in s) {\n out.push({\n id: `try:q${i}`,\n label: s.query,\n group: l.suggestions,\n icon: <Search className=\"size-4\" />,\n onSelect: () => {\n // The palette closes before it runs a row; a query suggestion keeps it\n // open and types itself in instead.\n setOpen(true);\n setQuery(s.query);\n refocusField();\n },\n });\n } else out.push(toItem(\"try:\", s, groupOf(s)));\n });\n // One heading has nothing to order; kept groups are ordered like results.\n return suggestionsKeepGroups ? ordered(out) : out;\n }\n\n const out = index.search(q).map((hit) => toItem(\"s:\", hit.entry, hit.entry.group ?? l.results));\n for (const source of sourceList) {\n if (q.length < (source.minChars ?? 2)) continue;\n const result = sourceResults[source.id];\n const declared = (source.groups ?? []).map((g) => (typeof g === \"string\" ? { key: g, label: g } : g));\n const status = (label: string, icon: ReactNode): CommandItem => ({\n id: `src:${source.id}:status`,\n label,\n // One line for the one request, under the group that will head its answer.\n group: declared[0]?.label ?? source.group,\n icon,\n kind: \"status\",\n onSelect: noop,\n });\n // Anything but an answer to THIS query is still loading — including the previous\n // query's rows, which would otherwise sit under the new query as if they matched.\n if (!result || result.query !== q) {\n out.push(status(pl.loading, <Loader2 className=\"size-3.5 animate-spin\" />));\n } else if (result.status === \"error\") {\n out.push(status(pl.error ?? DEFAULT_COMMAND_PALETTE_LABELS.error!, <AlertCircle className=\"size-3.5\" />));\n } else if (!declared.length) {\n for (const entry of result.entries.slice(0, source.limit ?? groupLimit)) {\n out.push(toItem(`src:${source.id}:`, entry, source.group, source.redact ?? redactLabels));\n }\n } else {\n // Bucket by the entry's own group, then emit in the DECLARED order — the answer's\n // order must not reshuffle the headings between keystrokes. Within a group the\n // source's ranking stands. The group key is in the row id: two record types may\n // share an id (\"1\"), and the palette keys rows by it.\n const buckets = new Map<string, { label: string; entries: SearchEntry[] }>();\n for (const g of declared) buckets.set(g.key, { label: g.label, entries: [] });\n const rest: SearchEntry[] = [];\n for (const entry of result.entries) {\n const bucket = entry.group === undefined ? undefined : buckets.get(entry.group);\n (bucket ? bucket.entries : rest).push(entry);\n }\n const limit = source.limit ?? groupLimit;\n const emit = (key: string, label: string, list: SearchEntry[]) => {\n for (const entry of list.slice(0, limit)) {\n out.push(toItem(`src:${source.id}:${key}:`, entry, label, source.redact ?? redactLabels));\n }\n };\n for (const [key, { label, entries: list }] of buckets) emit(key, label, list);\n emit(\"~\", source.group, rest);\n }\n }\n\n return ordered(out);\n }, [q, suggestionList, suggestionsKeepGroups, byId, index, sourceList, sourceResults, order, groupLimit, toItem, l.suggestions, l.results, pl.loading, pl.error, setOpen, setQuery, noop, redactLabels]);\n /* eslint-enable react-hooks/refs */\n\n // The palette re-runs its provider on a `revision` change, never on the provider's\n // identity — and `items` is everything the provider answers with.\n const provider = useCallback(() => items, [items]);\n\n const resolvedPaletteLabels = useMemo(\n () => ({ dialog: l.trigger, placeholder: l.placeholder, ...paletteLabels }),\n [l.trigger, l.placeholder, paletteLabels],\n );\n\n const apple = useMemo(() => isApplePlatform(), []);\n const keys = apple ? \"⌘K\" : \"Ctrl K\";\n const triggerLabel = triggerName === \"withShortcut\" ? l.shortcut(keys) : l.trigger;\n const triggerProps: GlobalSearchTriggerProps = {\n open: openSearch,\n label: triggerLabel,\n tooltip: l.shortcut(keys),\n keys,\n ariaKeyShortcuts: \"Meta+K Control+K\",\n };\n\n return (\n <>\n {typeof trigger === \"function\"\n ? trigger(triggerProps)\n : trigger === \"button\" && (\n <Tooltip\n label={triggerProps.tooltip}\n side=\"bottom\"\n portal\n className={hideTriggerOnPhone ? \"hidden sm:block\" : undefined}\n >\n <button\n type=\"button\"\n onClick={openSearch}\n aria-label={triggerLabel}\n aria-keyshortcuts={triggerProps.ariaKeyShortcuts}\n aria-haspopup=\"dialog\"\n className={cn(TOPBAR_TRIGGER_CLASS, triggerClassName)}\n >\n <Search\n className={triggerIconSize === undefined ? \"size-4\" : undefined}\n style={triggerIconSize === undefined ? undefined : { width: triggerIconSize, height: triggerIconSize }}\n />\n </button>\n </Tooltip>\n )}\n {/* Nothing is drawn while the palette's module is on its way (a few milliseconds,\n once per page load). A failed load is a chunk-load error for the app's error\n boundary, as a lazy route's is. */}\n {paletteMounted && (\n <Suspense fallback={null}>\n <LazyCommandPalette\n open={open}\n onClose={() => setOpen(false)}\n search={provider}\n revision={items}\n query={query}\n onQueryChange={setQuery}\n searchOn={searchOn}\n redactLabels={redactLabels}\n fullScreenOnPhone={fullScreenOnPhone}\n density={density}\n labels={resolvedPaletteLabels}\n />\n </Suspense>\n )}\n </>\n );\n}\n\nconst EMPTY: readonly SearchEntry[] = [];\n"],"mappings":"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","names":["out","list"]}
|
|
1
|
+
{"version":3,"sources":["../../src/search/global-search.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { useHref, useInRouterContext, useNavigate } from \"react-router\";\nimport { AlertCircle, Loader2, Search } from \"lucide-react\";\nimport { Tooltip } from \"../components/tooltip\";\nimport { TOPBAR_TRIGGER_CLASS } from \"../shell/topbar-controls\";\nimport { cn } from \"../lib/cn\";\nimport { useKitLabels, type LabelOverride } from \"../i18n/kit-labels\";\n// Types only from ./command-palette, gone from the built module: the palette loads late.\nimport type { CommandItem, CommandPaletteDensity, CommandPaletteLabels } from \"./command-palette\";\nimport { DEFAULT_COMMAND_PALETTE_LABELS } from \"./command-palette-labels\";\nimport { useCommandKey } from \"./use-command-key\";\nimport { createSearchIndex } from \"./search-index\";\nimport type { SearchEntry, SearchIndexOptions } from \"./search-index\";\nimport { DEFAULT_GLOBAL_SEARCH_LABELS } from \"./global-search-labels\";\n\n/**\n * The palette, loaded when the search is first opened rather than with the top bar\n * (0.34, MOD-1 of the refactor audit 2026-10): ~5.5 kB gzip of keksdose's and kastlan's\n * entry chunks, for a dialog drawn only once somebody searches. A LITERAL relative\n * `import()`, as the catalogue loaders are (i18n/languages.ts), so the library build keeps\n * the module its own and an app's bundler splits it off.\n */\nconst LazyCommandPalette = lazy(() =>\n import(\"./command-palette\").then((module) => ({ default: module.CommandPalette })),\n);\n\nexport interface GlobalSearchLabels {\n /** The trigger's accessible name, and the dialog's. */\n trigger: string;\n /** The field's placeholder — says WHAT can be found, which \"Search…\" does not. */\n placeholder: string;\n /** The trigger's tooltip, given the shortcut as the platform writes it (\"⌘K\",\n * \"Ctrl K\"). A function so a language can put the keys where its grammar wants. */\n shortcut: (keys: string) => string;\n /** Heading of the suggestions shown for an empty query. */\n suggestions: string;\n /** Heading for entries that name no `group`. */\n results: string;\n}\n\n// Defined in ./global-search-labels, which holds no component code (0.34, KS U8).\nexport { DEFAULT_GLOBAL_SEARCH_LABELS };\n\n/**\n * A place results come from that is not the static index — a server search, a\n * local-first store too large to hand over whole. Each source is its own group, with its\n * own debounce, its own \"Searching…\" line and its own failure: the static groups never\n * wait for it, and one source failing never takes another's results with it.\n */\nexport interface GlobalSearchSource {\n /** Stable key — the effect that runs the source is keyed by it, not by identity. */\n id: string;\n /** The group its results are shown under (an entry's own `group` is ignored) — unless\n * `groups` is set, where it is only the home of entries that name no declared group.\n * If every entry names a declared group, it is never shown: a catch-all heading such\n * as \"Other\" is the honest value, so a stray type would still surface, labelled. */\n group: string;\n /**\n * Split ONE request into several groups — kastlan's record search answers with\n * properties, units, contacts, leases and invoices at once, and one source per group\n * meant a dedupe layer so the network still saw one request. Each entry is then shown\n * under the group its own `group` names: a declared `key` (shown by its `label`) or a\n * plain string (key and heading at once). The groups appear in THIS order whatever the\n * answer's order, each kept to `limit` rows; an entry naming no declared group falls\n * under `group`. While the request runs, or when it fails, the source shows one status\n * line under its first group, not one per group. Unset: one group, as before.\n */\n groups?: readonly (string | GlobalSearchSourceGroup)[];\n /** Called with the trimmed query. Its results are shown AS GIVEN — the source ranked\n * them — and never re-filtered by the index's matcher. `signal` aborts when the query\n * moves on or the palette closes; a stale answer is dropped either way. */\n search: (query: string, signal: AbortSignal) => Promise<readonly SearchEntry[]> | readonly SearchEntry[];\n /** Shortest query it is asked for. Default 2 — one letter matches half a database. */\n minChars?: number;\n /** Quiet period after the last keystroke before it is asked. Default 200ms. */\n debounceMs?: number;\n /** Rows kept — per group, when `groups` is set. Default: `indexOptions.groupLimit` (8). */\n limit?: number;\n /** Mask every row of this source for session replay, hints (amounts) included. An\n * entry's own `redact` still wins. */\n redact?: boolean;\n /** Told when `search` throws or rejects (not when it is aborted). The group then\n * shows the palette's `error` line instead of rows. */\n onError?: (error: unknown) => void;\n}\n\n/** One of a multi-group source's groups: the `key` its entries name in `group`, and the\n * heading shown — so a server's type (\"unit\") need not be translated per entry. */\nexport interface GlobalSearchSourceGroup {\n key: string;\n label: string;\n}\n\n/** What a custom trigger gets: everything the default button uses. */\nexport interface GlobalSearchTriggerProps {\n open: () => void;\n /** Resolved `trigger` label — the accessible name. */\n label: string;\n /** Resolved `shortcut(keys)` — the tooltip. */\n tooltip: string;\n /** \"⌘K\" on Apple platforms, \"Ctrl K\" elsewhere. */\n keys: string;\n /** For the trigger's `aria-keyshortcuts`. */\n ariaKeyShortcuts: string;\n}\n\n/** A suggestion for the empty query: an entry, the `id` of one in `entries`, or a query\n * to type into the field. */\nexport type GlobalSearchSuggestion = SearchEntry | string | { query: string };\n\nexport interface GlobalSearchProps {\n /**\n * The static index: pages, actions, settings rows — already filtered by the app (by\n * role, by privacy mode). Matched and ranked by {@link createSearchIndex}.\n *\n * Changing it re-runs the open search by itself. Nothing has to be stable: the index is\n * rebuilt only when the entries' TEXT changes (ids, titles, keywords, …), so a list\n * rebuilt on every render — `data = []` while a query is pending, icons as fresh JSX —\n * neither re-indexes nor loops, and the icons and handlers used are always the latest.\n */\n entries?: readonly SearchEntry[];\n /** The async sources, each streamed into its own group — or several (`groups`). */\n sources?: readonly GlobalSearchSource[];\n /** What the empty query shows, under the `suggestions` heading. */\n suggestions?: readonly GlobalSearchSuggestion[];\n /**\n * Show each suggested ENTRY under its own `group` instead of all of them under the\n * one `suggestions` heading — keksdose's empty palette listed \"Pages\" and \"Actions\"\n * apart, and one \"Try\" heading over both lost the difference. An entry with no\n * `group` and a query suggestion (`{ query }`) stay under `suggestions`. `groupOrder`\n * orders these groups as it orders the results'. Off by default.\n */\n suggestionsKeepGroups?: boolean;\n /** Groups listed here come first, in this order; the rest follow in ranking order. */\n groupOrder?: readonly string[];\n /** Ranking and capping — `groupLimit` (default 8) applies to every group. */\n indexOptions?: SearchIndexOptions;\n /**\n * How an entry's `href` is followed on a plain click or ↵. Default: react-router's\n * `navigate` when the search is rendered inside a router, else a full page load.\n */\n navigate?: (href: string) => void;\n /**\n * The browser URL of an `href`, for the row's real link (middle-/⌘-click opens a tab).\n * Default inside a router: the router's own (`#/page` under a hash router, the\n * basename prefixed under a browser router); outside one, the href itself.\n */\n hrefFor?: (href: string) => string;\n /** Register ⌘K / Ctrl K. Default true; turn it off for a second, scoped search on a\n * page that already has the app-wide one. */\n shortcut?: boolean;\n /** Controlled open state — so a button anywhere can open it. */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** Controlled query, as on `CommandPalette` (keksdose binds it to the URL's `q`). */\n query?: string;\n onQueryChange?: (query: string) => void;\n searchOn?: \"input\" | \"submit\";\n /** Mask every row for session replay (see `CommandPalette`). A source's or an entry's\n * own `redact` wins. */\n redactLabels?: boolean;\n fullScreenOnPhone?: boolean;\n /** `\"button\"` (default): the top-bar icon button. `\"none\"`: no trigger — the shortcut\n * or a controlled `open` opens it. A function renders a trigger of your own. */\n trigger?: \"button\" | \"none\" | ((props: GlobalSearchTriggerProps) => ReactNode);\n /** Hide the default trigger below `sm` (kastlan's phone top bar has no room). */\n hideTriggerOnPhone?: boolean;\n /** Class for the default trigger button, merged over `TOPBAR_TRIGGER_CLASS`. */\n triggerClassName?: string;\n /**\n * The default trigger's magnifier, in px. Default 16 (`size-4`), as it always was;\n * 20 matches the kit's other top-bar triggers (`TopbarIconButton` draws `size-5`) and\n * keksdose's top bar, which reached into the button with `[&_svg]:size-5` for it.\n */\n triggerIconSize?: number;\n /**\n * Whether the trigger's accessible name includes the shortcut: `\"plain\"` (default)\n * names it \"Search\"; `\"withShortcut\"` names it by `labels.shortcut(keys)` —\n * \"Search (⌘K)\" on Apple platforms, \"Search (Ctrl K)\" elsewhere — the same text its\n * tooltip shows, so a speech-control user (\"click Search\") and a sighted keyboard user\n * meet the shortcut in the name itself (keksdose C25). `aria-keyshortcuts` is set\n * either way. Also reaches a custom trigger as `triggerProps.label`.\n */\n triggerName?: \"plain\" | \"withShortcut\";\n /** The palette's row height — `CommandPalette`'s `density`. Default `\"compact\"`. */\n density?: CommandPaletteDensity;\n labels?: LabelOverride<GlobalSearchLabels>;\n /** Passed through to the palette (`empty`, `loading`, `error`, `hint`, …). */\n paletteLabels?: Partial<CommandPaletteLabels>;\n /** 0.43: `data-*` attributes go on the kit's trigger button (`trigger=\"button\"`) — a\n * tour's anchor (`data-tour=\"search\"`), a test hook. A function trigger is the app's. */\n [key: `data-${string}`]: string | number | boolean | undefined;\n}\n\nfunction isApplePlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n return /mac|iphone|ipad|ipod/i.test(nav.userAgentData?.platform || nav.platform || nav.userAgent);\n}\n\nconst pageLoad = (href: string) => window.location.assign(href);\nconst identity = (href: string) => href;\n\n/** The entries' text, which is all the index reads — see `entries`. */\nfunction signature(entries: readonly SearchEntry[]): string {\n return entries\n .map((e) =>\n [e.id, e.title, (e.keywords ?? []).join(\"\\u0003\"), e.description, e.group, e.hint, e.href, e.weight, e.redact].join(\n \"\\u0001\",\n ),\n )\n .join(\"\\u0002\");\n}\n\n/** Focus the open palette's field again — after a suggestion typed itself into it, the\n * row that was clicked (and held focus) is gone. */\nfunction refocusField() {\n requestAnimationFrame(() => {\n const fields = document.querySelectorAll<HTMLInputElement>('[role=\"dialog\"][aria-modal=\"true\"] input[role=\"combobox\"]');\n fields[fields.length - 1]?.focus();\n });\n}\n\ninterface SourceResult {\n query: string;\n status: \"loading\" | \"done\" | \"error\";\n entries: readonly SearchEntry[];\n}\n\n/**\n * The app-wide ⌘K search, whole: the top-bar trigger, the shortcut, and a\n * {@link CommandPalette} fed from a ranked index ({@link createSearchIndex}) and any\n * number of async sources.\n *\n * Every consumer had built this out of `CommandPalette` by hand, and each copy had the\n * same holes — a substring match, no ranking, no typo tolerance, results in declaration\n * order, one monolithic provider in which the static groups waited on the slowest\n * request. This is that wrapper once:\n *\n * <GlobalSearch\n * entries={pages} // { id, title, keywords, group, href, icon }\n * sources={[{ id: \"tx\", group: \"Transactions\", search: (q, signal) => api.search(q, { signal }) }]}\n * suggestions={[\"page-budget\", \"action-new-account\"]}\n * />\n *\n * Inside a react-router tree it navigates with the router and builds its links with it;\n * outside one, pass `navigate` (or accept full page loads).\n *\n * Since 0.34 the palette's module loads on the first open (MOD-1), so the dialog appears a\n * moment after the trigger or ⌘K: a test finds it with `await screen.findBy…`.\n */\nexport function GlobalSearch(props: GlobalSearchProps) {\n // Two components rather than a conditional hook: `useNavigate` throws outside a\n // router, and whether we are in one does not change over a component's life.\n const inRouter = useInRouterContext();\n if (inRouter && (!props.navigate || !props.hrefFor)) return <RoutedGlobalSearch {...props} />;\n return <GlobalSearchImpl {...props} navigate={props.navigate ?? pageLoad} hrefFor={props.hrefFor ?? identity} />;\n}\n\nfunction RoutedGlobalSearch(props: GlobalSearchProps) {\n const routerNavigate = useNavigate();\n // The router's href for \"/\" is its base (\"#/\" under a hash router, \"/app/\" under a\n // basename); every href is that base plus the path.\n const base = useHref(\"/\").replace(/\\/$/, \"\");\n const navigate = useCallback((href: string) => void routerNavigate(href), [routerNavigate]);\n const hrefFor = useCallback((href: string) => (href.startsWith(\"/\") ? base + href : href), [base]);\n return <GlobalSearchImpl {...props} navigate={props.navigate ?? navigate} hrefFor={props.hrefFor ?? hrefFor} />;\n}\n\nfunction GlobalSearchImpl({\n entries,\n sources,\n suggestions,\n suggestionsKeepGroups = false,\n groupOrder,\n indexOptions,\n navigate,\n hrefFor,\n shortcut = true,\n open: openProp,\n onOpenChange,\n query: queryProp,\n onQueryChange,\n searchOn,\n redactLabels = false,\n fullScreenOnPhone,\n trigger = \"button\",\n hideTriggerOnPhone = false,\n triggerClassName,\n triggerIconSize,\n triggerName = \"plain\",\n density,\n labels,\n paletteLabels,\n ...attributes\n}: GlobalSearchProps & { navigate: (href: string) => void; hrefFor: (href: string) => string }) {\n const l = useKitLabels(\"globalSearch\", DEFAULT_GLOBAL_SEARCH_LABELS, labels);\n const pl = useKitLabels(\"commandPalette\", DEFAULT_COMMAND_PALETTE_LABELS, paletteLabels);\n const [ownOpen, setOwnOpen] = useState(false);\n const open = openProp ?? ownOpen;\n const [ownQuery, setOwnQuery] = useState(\"\");\n const queryControlled = queryProp !== undefined;\n const query = queryControlled ? queryProp : ownQuery;\n const q = query.trim();\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (openProp === undefined) setOwnOpen(next);\n onOpenChange?.(next);\n },\n [openProp, onOpenChange],\n );\n const setQuery = useCallback(\n (next: string) => {\n if (!queryControlled) setOwnQuery(next);\n onQueryChange?.(next);\n },\n [queryControlled, onQueryChange],\n );\n\n // Each open starts blank — unless the owner controls the query (a URL `q`). Adjusted\n // during render, React's pattern for state that follows a prop, so a controlled `open`\n // gets the same reset as the trigger does.\n const [wasOpen, setWasOpen] = useState(open);\n if (wasOpen !== open) {\n setWasOpen(open);\n if (open && !queryControlled) setOwnQuery(\"\");\n }\n\n // The palette mounts on the first open — its module loads then — and stays mounted\n // after, closed, as it always was (MOD-1): a closed palette keeps the last results, and\n // a reopen over an owner-held query shows them at once, where a palette mounted anew\n // would say \"No results\" through its debounce first.\n const [paletteMounted, setPaletteMounted] = useState(open);\n if (open && !paletteMounted) setPaletteMounted(true);\n\n const openSearch = useCallback(() => setOpen(true), [setOpen]);\n const noop = useCallback(() => {}, []);\n useCommandKey(shortcut ? openSearch : noop);\n\n /* ── the static index ─────────────────────────────────────────────────── */\n\n // Everything below is keyed by CONTENT, never by the identity of what the app passed:\n // inline arrays and `data = []` defaults are the norm, and an identity key would\n // re-index and re-search on every render of the app. Handlers, which can close over\n // anything, are read from refs at the moment a row is chosen — never stale.\n const list = entries ?? EMPTY;\n const sig = signature(list);\n const optionsKey = JSON.stringify(indexOptions ?? {});\n const groupLimit = indexOptions?.groupLimit ?? 8;\n // `sig` and `optionsKey` stand for `list` and `indexOptions`: same text, same index.\n /* eslint-disable react-hooks/exhaustive-deps */\n const index = useMemo(() => createSearchIndex(list, indexOptions), [sig, optionsKey]);\n const byId = useMemo(() => new Map(list.map((e) => [e.id, e])), [sig]);\n\n const sourceKey = (sources ?? [])\n .map((s) =>\n [\n s.id,\n s.group,\n (s.groups ?? []).map((g) => (typeof g === \"string\" ? g : `${g.key}\\u0003${g.label}`)).join(\"\\u0004\"),\n s.minChars ?? 2,\n s.debounceMs ?? 200,\n s.limit,\n s.redact,\n ].join(\"\\u0001\"),\n )\n .join(\"\\u0002\");\n const sourceList = useMemo(() => sources ?? [], [sourceKey]);\n\n const suggestionsKey = (suggestions ?? [])\n .map((s) => (typeof s === \"string\" ? `i:${s}` : \"query\" in s ? `q:${s.query}` : `e:${signature([s])}`))\n .join(\"\\u0002\");\n const suggestionList = useMemo(() => suggestions ?? [], [suggestionsKey]);\n\n const groupOrderKey = (groupOrder ?? []).join(\"\\u0002\");\n const order = useMemo(() => groupOrder ?? [], [groupOrderKey]);\n /* eslint-enable react-hooks/exhaustive-deps */\n\n // The live objects, for the moment a row is chosen or a source is asked.\n const live = useRef({ entries: list, sources: sources ?? [], suggestions: suggestions ?? [], navigate });\n useLayoutEffect(() => {\n live.current = { entries: list, sources: sources ?? [], suggestions: suggestions ?? [], navigate };\n });\n\n /* ── the async sources ────────────────────────────────────────────────── */\n\n const [sourceResults, setSourceResults] = useState<Record<string, SourceResult>>({});\n useEffect(() => {\n const controllers: AbortController[] = [];\n const timers: ReturnType<typeof setTimeout>[] = [];\n const asked = open ? live.current.sources.filter((s) => q.length >= (s.minChars ?? 2)) : [];\n for (const source of asked) {\n const id = source.id;\n const controller = new AbortController();\n controllers.push(controller);\n timers.push(\n setTimeout(async () => {\n const settle = (result: SourceResult) => {\n if (!controller.signal.aborted) setSourceResults((prev) => ({ ...prev, [id]: result }));\n };\n try {\n const found = await source.search(q, controller.signal);\n settle({ query: q, status: \"done\", entries: found });\n } catch (error) {\n if (controller.signal.aborted) return;\n source.onError?.(error);\n settle({ query: q, status: \"error\", entries: [] });\n }\n }, source.debounceMs ?? 200),\n );\n }\n return () => {\n timers.forEach(clearTimeout);\n controllers.forEach((c) => c.abort());\n };\n }, [open, q, sourceKey]);\n\n /* ── rows ─────────────────────────────────────────────────────────────── */\n\n const toItem = useCallback(\n (prefix: string, entry: SearchEntry, group: string, redact = redactLabels): CommandItem => ({\n id: `${prefix}${entry.id}`,\n label: entry.title,\n hint: entry.hint,\n group,\n icon: entry.icon,\n redact: entry.redact ?? redact,\n href: entry.href !== undefined ? hrefFor(entry.href) : undefined,\n onSelect: () => {\n // The entry as the app has it NOW — its handler may close over newer state\n // than the one this row was built from.\n const current = live.current.entries.find((e) => e.id === entry.id) ?? entry;\n if (current.onSelect) current.onSelect();\n else if (current.href !== undefined) live.current.navigate(current.href);\n },\n }),\n [hrefFor, redactLabels],\n );\n\n // `toItem` only BUILDS `onSelect` closures here; `live` is read when a row is chosen,\n // which the compiler lint cannot tell from a read during render.\n /* eslint-disable react-hooks/refs */\n const items = useMemo((): CommandItem[] => {\n const ordered = (out: CommandItem[]) => {\n if (!order.length) return out;\n const rank = (group: string) => {\n const i = order.indexOf(group);\n return i === -1 ? order.length : i;\n };\n // Stable: within a rank, groups keep the order their best hit gave them.\n return out\n .map((item, i) => ({ item, i }))\n .sort((a, b) => rank(a.item.group) - rank(b.item.group) || a.i - b.i)\n .map(({ item }) => item);\n };\n\n if (!q) {\n const out: CommandItem[] = [];\n const groupOf = (entry: SearchEntry) =>\n suggestionsKeepGroups ? (entry.group ?? l.suggestions) : l.suggestions;\n suggestionList.forEach((s, i) => {\n if (typeof s === \"string\") {\n const entry = byId.get(s);\n if (entry) out.push(toItem(\"try:\", entry, groupOf(entry)));\n } else if (\"query\" in s) {\n out.push({\n id: `try:q${i}`,\n label: s.query,\n group: l.suggestions,\n icon: <Search className=\"size-4\" />,\n onSelect: () => {\n // The palette closes before it runs a row; a query suggestion keeps it\n // open and types itself in instead.\n setOpen(true);\n setQuery(s.query);\n refocusField();\n },\n });\n } else out.push(toItem(\"try:\", s, groupOf(s)));\n });\n // One heading has nothing to order; kept groups are ordered like results.\n return suggestionsKeepGroups ? ordered(out) : out;\n }\n\n const out = index.search(q).map((hit) => toItem(\"s:\", hit.entry, hit.entry.group ?? l.results));\n for (const source of sourceList) {\n if (q.length < (source.minChars ?? 2)) continue;\n const result = sourceResults[source.id];\n const declared = (source.groups ?? []).map((g) => (typeof g === \"string\" ? { key: g, label: g } : g));\n const status = (label: string, icon: ReactNode): CommandItem => ({\n id: `src:${source.id}:status`,\n label,\n // One line for the one request, under the group that will head its answer.\n group: declared[0]?.label ?? source.group,\n icon,\n kind: \"status\",\n onSelect: noop,\n });\n // Anything but an answer to THIS query is still loading — including the previous\n // query's rows, which would otherwise sit under the new query as if they matched.\n if (!result || result.query !== q) {\n out.push(status(pl.loading, <Loader2 className=\"size-3.5 animate-spin\" />));\n } else if (result.status === \"error\") {\n out.push(status(pl.error ?? DEFAULT_COMMAND_PALETTE_LABELS.error!, <AlertCircle className=\"size-3.5\" />));\n } else if (!declared.length) {\n for (const entry of result.entries.slice(0, source.limit ?? groupLimit)) {\n out.push(toItem(`src:${source.id}:`, entry, source.group, source.redact ?? redactLabels));\n }\n } else {\n // Bucket by the entry's own group, then emit in the DECLARED order — the answer's\n // order must not reshuffle the headings between keystrokes. Within a group the\n // source's ranking stands. The group key is in the row id: two record types may\n // share an id (\"1\"), and the palette keys rows by it.\n const buckets = new Map<string, { label: string; entries: SearchEntry[] }>();\n for (const g of declared) buckets.set(g.key, { label: g.label, entries: [] });\n const rest: SearchEntry[] = [];\n for (const entry of result.entries) {\n const bucket = entry.group === undefined ? undefined : buckets.get(entry.group);\n (bucket ? bucket.entries : rest).push(entry);\n }\n const limit = source.limit ?? groupLimit;\n const emit = (key: string, label: string, list: SearchEntry[]) => {\n for (const entry of list.slice(0, limit)) {\n out.push(toItem(`src:${source.id}:${key}:`, entry, label, source.redact ?? redactLabels));\n }\n };\n for (const [key, { label, entries: list }] of buckets) emit(key, label, list);\n emit(\"~\", source.group, rest);\n }\n }\n\n return ordered(out);\n }, [q, suggestionList, suggestionsKeepGroups, byId, index, sourceList, sourceResults, order, groupLimit, toItem, l.suggestions, l.results, pl.loading, pl.error, setOpen, setQuery, noop, redactLabels]);\n /* eslint-enable react-hooks/refs */\n\n // The palette re-runs its provider on a `revision` change, never on the provider's\n // identity — and `items` is everything the provider answers with.\n const provider = useCallback(() => items, [items]);\n\n const resolvedPaletteLabels = useMemo(\n () => ({ dialog: l.trigger, placeholder: l.placeholder, ...paletteLabels }),\n [l.trigger, l.placeholder, paletteLabels],\n );\n\n const apple = useMemo(() => isApplePlatform(), []);\n const keys = apple ? \"⌘K\" : \"Ctrl K\";\n const triggerLabel = triggerName === \"withShortcut\" ? l.shortcut(keys) : l.trigger;\n const triggerProps: GlobalSearchTriggerProps = {\n open: openSearch,\n label: triggerLabel,\n tooltip: l.shortcut(keys),\n keys,\n ariaKeyShortcuts: \"Meta+K Control+K\",\n };\n\n return (\n <>\n {typeof trigger === \"function\"\n ? trigger(triggerProps)\n : trigger === \"button\" && (\n <Tooltip\n label={triggerProps.tooltip}\n side=\"bottom\"\n portal\n className={hideTriggerOnPhone ? \"hidden sm:block\" : undefined}\n >\n <button\n {...Object.fromEntries(Object.entries(attributes).filter(([k]) => k.startsWith(\"data-\")))}\n type=\"button\"\n onClick={openSearch}\n aria-label={triggerLabel}\n aria-keyshortcuts={triggerProps.ariaKeyShortcuts}\n aria-haspopup=\"dialog\"\n className={cn(TOPBAR_TRIGGER_CLASS, triggerClassName)}\n >\n <Search\n className={triggerIconSize === undefined ? \"size-4\" : undefined}\n style={triggerIconSize === undefined ? undefined : { width: triggerIconSize, height: triggerIconSize }}\n />\n </button>\n </Tooltip>\n )}\n {/* Nothing is drawn while the palette's module is on its way (a few milliseconds,\n once per page load). A failed load is a chunk-load error for the app's error\n boundary, as a lazy route's is. */}\n {paletteMounted && (\n <Suspense fallback={null}>\n <LazyCommandPalette\n open={open}\n onClose={() => setOpen(false)}\n search={provider}\n revision={items}\n query={query}\n onQueryChange={setQuery}\n searchOn={searchOn}\n redactLabels={redactLabels}\n fullScreenOnPhone={fullScreenOnPhone}\n density={density}\n labels={resolvedPaletteLabels}\n />\n </Suspense>\n )}\n </>\n );\n}\n\nconst EMPTY: readonly SearchEntry[] = [];\n"],"mappings":"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","names":["out","list"]}
|
|
@@ -27,6 +27,13 @@ export interface SettingsGroup<G extends string = string> {
|
|
|
27
27
|
* kastlan's `/admin/billing` while billing is off. Default: visible.
|
|
28
28
|
*/
|
|
29
29
|
visible?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 0.43: the group shows with no visible entry — a page of its own rather than of setting
|
|
32
|
+
* cards (the admin area's Overview, whose tiles are no settings; `adminSections` sets
|
|
33
|
+
* it). `visible: false` still hides it. Default: a group shows only with an entry once
|
|
34
|
+
* `entries` are given (§4.1).
|
|
35
|
+
*/
|
|
36
|
+
standalone?: boolean;
|
|
30
37
|
}
|
|
31
38
|
/** One setting, and the card that holds it (§4.1). */
|
|
32
39
|
export interface SettingsEntry<G extends string = string> {
|
|
@@ -53,7 +60,8 @@ export interface SettingsEntry<G extends string = string> {
|
|
|
53
60
|
/**
|
|
54
61
|
* The groups that show, in their order: not `visible: false`, and — when `entries` is
|
|
55
62
|
* given — holding at least one visible entry (§4.1: Kurvenschmiede's notifications group
|
|
56
|
-
* stays hidden until it has a card). Without `entries` only the
|
|
63
|
+
* stays hidden until it has a card) or `standalone` (0.43). Without `entries` only the
|
|
64
|
+
* groups' own flag counts.
|
|
57
65
|
*/
|
|
58
66
|
export declare function visibleSettingsGroups<G extends string>(groups: readonly SettingsGroup<G>[], entries?: readonly SettingsEntry<G>[]): SettingsGroup<G>[];
|
|
59
67
|
/** The visible entries of the visible groups — what search may find. */
|
|
@@ -3,7 +3,7 @@ function visibleSettingsGroups(groups, entries) {
|
|
|
3
3
|
if (!entries) return groups.filter((g) => g.visible !== false);
|
|
4
4
|
const filled = /* @__PURE__ */ new Set();
|
|
5
5
|
for (const e of entries) if (e.visible !== false) filled.add(e.group);
|
|
6
|
-
return groups.filter((g) => g.visible !== false && filled.has(g.id));
|
|
6
|
+
return groups.filter((g) => g.visible !== false && (g.standalone === true || filled.has(g.id)));
|
|
7
7
|
}
|
|
8
8
|
function visibleSettingsEntries(groups, entries) {
|
|
9
9
|
const shown = new Set(visibleSettingsGroups(groups, entries).map((g) => g.id));
|