@eifi1/ui-kit 0.53.0 → 0.54.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.
Files changed (131) hide show
  1. package/README.md +9 -9
  2. package/dist/account/delete-account-setting.d.ts +3 -2
  3. package/dist/account/delete-account-setting.js.map +1 -1
  4. package/dist/auth/auth-errors.d.ts +36 -0
  5. package/dist/auth/auth-errors.js +20 -0
  6. package/dist/auth/auth-errors.js.map +1 -1
  7. package/dist/components/amount-input.d.ts +2 -1
  8. package/dist/components/amount-input.js.map +1 -1
  9. package/dist/components/calendar-heatmap.js +4 -2
  10. package/dist/components/calendar-heatmap.js.map +1 -1
  11. package/dist/components/currency-option-list.d.ts +2 -1
  12. package/dist/components/currency-option-list.js +10 -3
  13. package/dist/components/currency-option-list.js.map +1 -1
  14. package/dist/components/currency-select.d.ts +3 -1
  15. package/dist/components/currency-select.js.map +1 -1
  16. package/dist/components/danger-confirm.d.ts +22 -1
  17. package/dist/components/danger-confirm.js +50 -28
  18. package/dist/components/danger-confirm.js.map +1 -1
  19. package/dist/components/data-table-filter-popover.d.ts +2 -1
  20. package/dist/components/data-table-filter-popover.js +3 -2
  21. package/dist/components/data-table-filter-popover.js.map +1 -1
  22. package/dist/components/data-table-filters.d.ts +33 -3
  23. package/dist/components/data-table-filters.js +6 -4
  24. package/dist/components/data-table-filters.js.map +1 -1
  25. package/dist/components/dialog-frame.d.ts +3 -1
  26. package/dist/components/dialog-frame.js +6 -2
  27. package/dist/components/dialog-frame.js.map +1 -1
  28. package/dist/components/mini-calendar.js +3 -2
  29. package/dist/components/mini-calendar.js.map +1 -1
  30. package/dist/components/modal.d.ts +27 -0
  31. package/dist/components/modal.js +5 -3
  32. package/dist/components/modal.js.map +1 -1
  33. package/dist/components/number-input.js.map +1 -1
  34. package/dist/components/stat-tile.d.ts +21 -2
  35. package/dist/components/stat-tile.js +4 -2
  36. package/dist/components/stat-tile.js.map +1 -1
  37. package/dist/currencies.d.ts +16 -2
  38. package/dist/currencies.js +2 -1
  39. package/dist/currencies.js.map +1 -1
  40. package/dist/eslint/index.js +1 -1
  41. package/dist/feedback/feedback-context-labels.js +2 -1
  42. package/dist/feedback/feedback-context-labels.js.map +1 -1
  43. package/dist/feedback/feedback-context.d.ts +19 -3
  44. package/dist/feedback/feedback-context.js +12 -1
  45. package/dist/feedback/feedback-context.js.map +1 -1
  46. package/dist/feedback/feedback-diagnostics.d.ts +17 -0
  47. package/dist/feedback/feedback-diagnostics.js +27 -0
  48. package/dist/feedback/feedback-diagnostics.js.map +1 -0
  49. package/dist/feedback/feedback-dialog.d.ts +10 -0
  50. package/dist/feedback/feedback-dialog.js +6 -4
  51. package/dist/feedback/feedback-dialog.js.map +1 -1
  52. package/dist/feedback/feedback-record.d.ts +5 -0
  53. package/dist/feedback/feedback-record.js.map +1 -1
  54. package/dist/feedback/feedback-row-detail-labels.js +1 -0
  55. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  56. package/dist/feedback/feedback-row-detail.d.ts +3 -0
  57. package/dist/feedback/feedback-row-detail.js +3 -0
  58. package/dist/feedback/feedback-row-detail.js.map +1 -1
  59. package/dist/feedback/feedback-submit-dialog.d.ts +5 -1
  60. package/dist/feedback/feedback-submit-dialog.js +15 -3
  61. package/dist/feedback/feedback-submit-dialog.js.map +1 -1
  62. package/dist/feedback/feedback-submit.d.ts +30 -2
  63. package/dist/feedback/feedback-submit.js +5 -2
  64. package/dist/feedback/feedback-submit.js.map +1 -1
  65. package/dist/hooks/use-hotkey.js +11 -1
  66. package/dist/hooks/use-hotkey.js.map +1 -1
  67. package/dist/i18n/german.js +3 -1
  68. package/dist/i18n/german.js.map +1 -1
  69. package/dist/i18n/locales/en.js +3 -1
  70. package/dist/i18n/locales/en.js.map +2 -2
  71. package/dist/i18n/locales/es.js +3 -1
  72. package/dist/i18n/locales/es.js.map +1 -1
  73. package/dist/i18n/locales/fr.js +3 -1
  74. package/dist/i18n/locales/fr.js.map +1 -1
  75. package/dist/i18n/locales/hu.js +3 -1
  76. package/dist/i18n/locales/hu.js.map +1 -1
  77. package/dist/i18n/locales/it.js +3 -1
  78. package/dist/i18n/locales/it.js.map +1 -1
  79. package/dist/i18n/locales/zh.js +3 -1
  80. package/dist/i18n/locales/zh.js.map +1 -1
  81. package/dist/index.d.ts +3 -3
  82. package/dist/index.js +6 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/lib/dates.d.ts +7 -1
  85. package/dist/lib/dates.js +8 -1
  86. package/dist/lib/dates.js.map +1 -1
  87. package/dist/lib/format.d.ts +37 -2
  88. package/dist/lib/format.js +25 -1
  89. package/dist/lib/format.js.map +1 -1
  90. package/dist/lib/intl-cache.d.ts +4 -2
  91. package/dist/lib/intl-cache.js.map +1 -1
  92. package/dist/lib/translation-review.d.ts +26 -0
  93. package/dist/lib/translation-review.js +14 -0
  94. package/dist/lib/translation-review.js.map +1 -1
  95. package/package.json +1 -1
  96. package/src/account/delete-account-setting.tsx +3 -2
  97. package/src/auth/auth-errors.ts +69 -0
  98. package/src/components/amount-input.tsx +2 -1
  99. package/src/components/calendar-heatmap.tsx +8 -2
  100. package/src/components/currency-option-list.tsx +12 -4
  101. package/src/components/currency-select.tsx +3 -1
  102. package/src/components/danger-confirm.tsx +80 -27
  103. package/src/components/data-table-filter-popover.tsx +19 -11
  104. package/src/components/data-table-filters.ts +36 -8
  105. package/src/components/dialog-frame.tsx +12 -4
  106. package/src/components/mini-calendar.tsx +5 -2
  107. package/src/components/modal.tsx +36 -7
  108. package/src/components/number-input.tsx +4 -3
  109. package/src/components/stat-tile.tsx +32 -3
  110. package/src/currencies.ts +23 -3
  111. package/src/feedback/feedback-context-labels.ts +1 -0
  112. package/src/feedback/feedback-context.tsx +34 -2
  113. package/src/feedback/feedback-diagnostics.tsx +41 -0
  114. package/src/feedback/feedback-dialog.tsx +16 -4
  115. package/src/feedback/feedback-record.ts +5 -0
  116. package/src/feedback/feedback-row-detail-labels.ts +1 -0
  117. package/src/feedback/feedback-row-detail.tsx +13 -0
  118. package/src/feedback/feedback-submit-dialog.tsx +15 -2
  119. package/src/feedback/feedback-submit.tsx +36 -3
  120. package/src/hooks/use-hotkey.ts +24 -1
  121. package/src/i18n/german.ts +2 -0
  122. package/src/i18n/locales/es.ts +2 -0
  123. package/src/i18n/locales/fr.ts +2 -0
  124. package/src/i18n/locales/hu.ts +2 -0
  125. package/src/i18n/locales/it.ts +2 -0
  126. package/src/i18n/locales/zh.ts +2 -0
  127. package/src/index.ts +14 -2
  128. package/src/lib/dates.ts +24 -2
  129. package/src/lib/format.ts +66 -3
  130. package/src/lib/intl-cache.ts +4 -2
  131. package/src/lib/translation-review.ts +52 -0
package/dist/index.d.ts CHANGED
@@ -15,7 +15,7 @@ export { createSessionRefresh, attachSessionRefresh, isTransientRefreshFailure,
15
15
  export type { SessionRefresh, SessionRefreshOptions, SessionRenewal, SessionRefreshOutcome, } from "./lib/session-refresh.js";
16
16
  export { formatPersonName, personInitials } from "./lib/person-name.js";
17
17
  export type { PersonName } from "./lib/person-name.js";
18
- export { REVIEW_STATUSES, fromApiReview, toApiWrite, flattenStrings, keyNamespace, placeholderTokens, placeholderMismatch, reviewStatus, keyInArea, keyInAreas, reviewAreaOf, translationRows, summariseRows, DEFAULT_TRANSLATION_REVIEW_FILTER, filterTranslationRows, reviewWrite, mergeReviews, dropReviews, translationCorrections, groupTranslationRows, unreviewedRows, reviewUndo, TRANSLATION_REVIEW_SWIPE_ACTIONS, DEFAULT_TRANSLATION_REVIEW_SWIPE, translationReviewSwipePlan, } from "./lib/translation-review.js";
18
+ export { REVIEW_STATUSES, fromApiReview, toApiWrite, flattenStrings, keyNamespace, placeholderTokens, placeholderMismatch, reviewStatus, keyInArea, keyInAreas, reviewAreaOf, translationRows, summariseRows, DEFAULT_TRANSLATION_REVIEW_FILTER, filterTranslationRows, reviewWrite, mergeReviews, dropReviews, saveReviewsInChunks, clearReviewsInChunks, translationCorrections, groupTranslationRows, unreviewedRows, reviewUndo, TRANSLATION_REVIEW_SWIPE_ACTIONS, DEFAULT_TRANSLATION_REVIEW_SWIPE, translationReviewSwipePlan, } from "./lib/translation-review.js";
19
19
  export type { TranslationVerdict, TranslationReview, TranslationReviewWrite, TranslationReviewKey, ReviewStatus, TranslationRow, ApiTranslationReview, ApiTranslationReviewsResponse, ApiTranslationReviewWrite, TranslationRowsInput, TranslationSummary, TranslationReviewFilter, TranslationCorrection, TranslationRowGroup, TranslationReviewUndo, TranslationReviewSwipeAction, TranslationReviewSwipeBinding, } from "./lib/translation-review.js";
20
20
  export { COUNTRY_CODES, countryName } from "./lib/countries.js";
21
21
  export { IBAN_LENGTHS, compactIban, formatIban, ibanCheckDigits, ibanProblem, isValidIban, isQrIban } from "./lib/iban.js";
@@ -244,7 +244,7 @@ export type { RegisterFormProps, RegisterLabels, RegisterValues } from "./auth/r
244
244
  export { CompleteNameDialog, DEFAULT_COMPLETE_NAME_LABELS } from "./auth/complete-name-dialog.js";
245
245
  export type { CompleteNameDialogProps, CompleteNameLabels, CompleteNameValues } from "./auth/complete-name-dialog.js";
246
246
  export { taggedEmail } from "./auth/email-tag.js";
247
- export { isAuthError, authErrorCode, isBillingError } from "./auth/auth-errors.js";
247
+ export { isAuthError, authErrorCode, isBillingError, billingRefusalText } from "./auth/auth-errors.js";
248
248
  export type { AuthErrorCode } from "./auth/auth-errors.js";
249
249
  export { ForgotPasswordForm, DEFAULT_FORGOT_PASSWORD_LABELS } from "./auth/forgot-password-form.js";
250
250
  export type { ForgotPasswordFormProps, ForgotPasswordLabels } from "./auth/forgot-password-form.js";
@@ -258,7 +258,7 @@ export { AcceptInvitation, DEFAULT_ACCEPT_INVITATION_LABELS } from "./auth/accep
258
258
  export type { AcceptInvitationProps, AcceptInvitationLabels, AcceptInvitationResult, AcceptInvitationFailure, } from "./auth/accept-invitation.js";
259
259
  export type { AuthHeadingLevel } from "./auth/status-parts.js";
260
260
  export { isRateLimited, retryAfterSeconds } from "./auth/auth-errors.js";
261
- export type { AccountErrorCode, BillingErrorCode, DemoErrorCode, KitErrorCode } from "./auth/auth-errors.js";
261
+ export type { AccountErrorCode, BillingErrorCode, BillingRefusalTextOptions, DemoErrorCode, KitErrorCode, } from "./auth/auth-errors.js";
262
262
  export * from "./account/account-settings.js";
263
263
  export * from "./account/passkeys-setting.js";
264
264
  export { EmailChangeSetting, DEFAULT_EMAIL_CHANGE_LABELS } from "./account/email-change-setting.js";
package/dist/index.js CHANGED
@@ -43,6 +43,8 @@ import {
43
43
  reviewWrite,
44
44
  mergeReviews,
45
45
  dropReviews,
46
+ saveReviewsInChunks,
47
+ clearReviewsInChunks,
46
48
  translationCorrections,
47
49
  groupTranslationRows,
48
50
  unreviewedRows,
@@ -327,7 +329,7 @@ import { SignInForm, DEFAULT_SIGN_IN_LABELS } from "./auth/sign-in-form.js";
327
329
  import { RegisterForm, DEFAULT_REGISTER_LABELS } from "./auth/register-form.js";
328
330
  import { CompleteNameDialog, DEFAULT_COMPLETE_NAME_LABELS } from "./auth/complete-name-dialog.js";
329
331
  import { taggedEmail } from "./auth/email-tag.js";
330
- import { isAuthError, authErrorCode, isBillingError } from "./auth/auth-errors.js";
332
+ import { isAuthError, authErrorCode, isBillingError, billingRefusalText } from "./auth/auth-errors.js";
331
333
  import { ForgotPasswordForm, DEFAULT_FORGOT_PASSWORD_LABELS } from "./auth/forgot-password-form.js";
332
334
  import { ResetPasswordForm, DEFAULT_RESET_PASSWORD_LABELS } from "./auth/reset-password-form.js";
333
335
  import { VerifyEmailStatus, EmailVerificationBanner, DEFAULT_VERIFY_EMAIL_LABELS } from "./auth/verify-email.js";
@@ -646,10 +648,12 @@ export {
646
648
  billingCurrencyFor,
647
649
  billingDaysLeft,
648
650
  billingLockAt,
651
+ billingRefusalText,
649
652
  breakpointQuery,
650
653
  buttonClasses,
651
654
  checkoutFingerprint,
652
655
  checkoutReturnUrl,
656
+ clearReviewsInChunks,
653
657
  cn,
654
658
  combineWriteLocks,
655
659
  compactIban,
@@ -750,6 +754,7 @@ export {
750
754
  roleOfColumn,
751
755
  rowActionsColumn,
752
756
  saveBlob,
757
+ saveReviewsInChunks,
753
758
  searchWords,
754
759
  seoCopyProblems,
755
760
  serverWake,
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). 0.52 (DUP-8,\n// refactor audit 2026-10-30): the remove, the sessionStorage pair and a JSON pair with a\n// shape check — 16 files in the apps wrap storage by hand, a few of them with no guard.\nexport {\n readStored,\n writeStored,\n removeStored,\n readSessionStored,\n writeSessionStored,\n readStoredJson,\n writeStoredJson,\n} from \"./lib/safe-storage\";\n// 0.52 (DUP-8): `prefers-reduced-motion`, asked at the moment of the motion (KS copied it).\nexport { prefersReducedMotion } from \"./lib/reduced-motion\";\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// The local-calendar ISO date helpers are the \"@eifi1/ui-kit/dates\" entry, standalone: none\n// of its names is in this barrel (public-surface.test.ts, STANDALONE).\n// One fold and one ranking for every list's search box (DUP-5), for an app's own lists;\n// and the pickers' every-word match (0.51.5), for an async `loadOptions` that filters itself.\nexport { foldForSearch, rankMatch, searchWords, matchesSearch } 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 {\n ServerWakeStage,\n ServerWakeFilter,\n ServerWakeOptions,\n ServerWakeRequest,\n ServerWakeWatcher,\n ServerWakeAxiosConfig,\n AxiosLikeInstance,\n} 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 {\n createSessionRefresh,\n attachSessionRefresh,\n isTransientRefreshFailure,\n isSignedOutStep,\n} from \"./lib/session-refresh\";\nexport type {\n SessionRefresh,\n SessionRefreshOptions,\n SessionRenewal,\n SessionRefreshOutcome,\n} 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 and phone helpers that\n// CountrySelect, IbanInput and PhoneInput are built on.\nexport { COUNTRY_CODES, countryName } from \"./lib/countries\";\nexport { IBAN_LENGTHS, compactIban, formatIban, ibanCheckDigits, ibanProblem, isValidIban, isQrIban } from \"./lib/iban\";\nexport type { IbanKind, IbanProblem } from \"./lib/iban\";\nexport { PHONE_DIAL_CODES, PHONE_COUNTRIES, parsePhone, formatNationalPhone, formatPhone, isE164 } 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.52 (DUP-8): DataTable's press-and-hold, which keksdose wrote first and still keeps.\nexport { useLongPress } from \"./hooks/use-long-press\";\nexport type { LongPressOptions, LongPressResult } from \"./hooks/use-long-press\";\n// 0.28: keksdose's noindex marker, for the legal and auth pages of every app.\nexport { useNoIndex } from \"./hooks/use-noindex\";\n// 0.49 KIT-9: the window's title from page, section and app, in the provider's format.\nexport { useDocumentTitle } from \"./hooks/use-document-title\";\n// 0.53: the 55 names no app reads left the entry points (deprecated in 0.52, refactor audit\n// 2026-10-30, API-4, decision 4) — here 0.49 KIT-1b's `asciiMinusInNumbers`, the copy\n// handler's rule, among them. Their modules keep the ones the kit itself uses.\nexport { DEFAULT_DOCUMENT_TITLE_FORMAT, formatDocumentTitle } from \"./lib/document-title\";\nexport type { DocumentTitleParts } from \"./lib/document-title\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// 0.25: several keys, one navigation (keksdose live #378 — four setters in a row clobbered).\nexport { useSearchParamsState } from \"./hooks/use-search-param-state\";\nexport type { SearchParamField, SearchParamFields, SearchParamsUpdate } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n// Row windowing for a long list (0.7.0, lenkbank's measured grid is built on it).\nexport { useWindowedRows, WINDOWED_ROW_INDEX } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// 0.32.0 (docs/text-size-harmonization.md): the breakpoints, and the hooks components read\n// the behaviours at Large from (§4, §10.7–10.9).\nexport {\n useBreakpoint,\n usePhoneLayout,\n breakpointQuery,\n BREAKPOINT_REM,\n remPx,\n useRemPx,\n} 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\";\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// 0.49.0 (KIT-8): five domain-free status kinds and their tones — Chip/StatusDot `status`.\nexport { statusTone, STATUS_KINDS } from \"./lib/status-tone\";\nexport type { StatusKind, StatusTone } from \"./lib/status-tone\";\n// ChipInput's own module since MOD-9: it renders Chip, so chip.tsx re-exports only its types.\nexport * from \"./components/chip-input\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\n// Named, not `*`: `heatmapLevel` is CalendarHeatmap's own since 0.53 (API-4).\nexport {\n CalendarHeatmap,\n DEFAULT_CALENDAR_HEATMAP_LABELS,\n heatmapWindowEnd,\n type CalendarHeatmapLabels,\n type CalendarHeatmapDatum,\n type CalendarHeatmapDay,\n type CalendarHeatmapProps,\n} 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 {\n WriteLockProvider,\n useWriteLock,\n writeLockFor,\n COMMIT_EXCEPT_BILLING,\n DEFAULT_WRITE_LOCK_LABELS,\n} from \"./components/write-lock\";\n// 0.46 (kastlan K4): the offline lock's scope and its source (the kind, `OFFLINE_LOCK`, left\n// the surface in 0.53: it is the string \"offline\").\nexport { COMMIT_EXCEPT_OFFLINE, useOfflineWriteLock } from \"./components/write-lock\";\nexport type {\n WriteLock,\n WriteLockLabels,\n WriteLockProviderProps,\n WriteLockKind,\n WriteLockHold,\n CommitScope,\n} from \"./components/write-lock\";\n// 0.18: the parts both apps' admin rosters repeat (Kurvenschmiede 6).\nexport {\n RoleChip,\n AccountStateChip,\n DateMark,\n dateColumn,\n DEFAULT_ACCOUNT_STATE_LABELS,\n ACCOUNT_STATE_TONES,\n} from \"./components/account-chips\";\nexport type {\n RoleChipProps,\n RoleDefinition,\n RoleVocabulary,\n AccountState,\n AccountStateLabels,\n AccountStateChipProps,\n DateMarkProps,\n DateColumnOptions,\n} 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 {\n ShareCardProps,\n ShareDialogProps,\n SharePanelProps,\n ShareCardLabels,\n ShareRole,\n ShareGrantee,\n SharePendingGrant,\n ShareCandidate,\n ShareAddRequest,\n} from \"./components/share-card\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.48 (keksdose dev #628): the table/list loading preset, one status label.\nexport { TableSkeleton } from \"./components/table-skeleton\";\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\n// Named, not `*`: `splitFileName` is ImageGrid's own since 0.53 (API-4).\nexport {\n ImageGrid,\n DEFAULT_IMAGE_GRID_LABELS,\n type ImageGridLabels,\n type ImageGridProps,\n} 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 { toast, Toaster, DEFAULT_TOAST_LABELS } 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 LegalInfoPageKey,\n LegalTextSectionLabels,\n LegalOperatorSectionLabels,\n LegalFramedSectionLabels,\n LegalDisclaimerSectionLabels,\n} from \"./components/legal\";\nexport { LegalPage, LegalKitSection, LegalAcceptCheckbox, LEGAL_SKELETON } from \"./components/legal-page\";\nexport type {\n LegalPageProps,\n LegalKitSectionProps,\n LegalKitSectionKey,\n LegalAcceptCheckboxProps,\n LegalSkeletonEntry,\n LegalSkeletonPage,\n LegalSectionOwner,\n LegalDisclaimerVariant,\n} from \"./components/legal-page\";\n// 0.32.0 (docs/text-size-harmonization.md): the appearance settings' words, and a row's\n// actions, one of the behaviours at Large (§4, §10.7–10.9).\nexport { DEFAULT_APPEARANCE_LABELS, useAppearanceLabels } from \"./components/appearance-labels\";\nexport type { AppearanceLabels } from \"./components/appearance-labels\";\n// 0.46 (keksdose's date format, lifted): the preference, its resolver and renderer, the\n// provider's formatter for it, and the settings field.\nexport {\n DATE_FORMAT_PREFERENCES,\n isDateFormatPreference,\n resolveDateFormat,\n formatDateWithPreference,\n // 0.52 (refactor audit 2026-10-30, DUP-2): a timestamp, the preference's date and the language's clock.\n formatDateTimeWithPreference,\n dateFormatSample,\n dateFormatterFor,\n} from \"./lib/date-format\";\nexport type { DateFormatPreference, DateFormatOptions, ResolvedDateFormat } from \"./lib/date-format\";\nexport { DateFormatSetting } from \"./components/date-format-setting\";\nexport type { DateFormatSettingProps } from \"./components/date-format-setting\";\nexport {\n RowActions,\n rowActionsColumn,\n DEFAULT_ROW_ACTIONS_LABELS,\n // 0.47.0 (keksdose N17): a hand-built table's actions heading and cell.\n RowActionsHead,\n ROW_ACTIONS_CELL_CLASS,\n} from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\n RowActionsHeadProps,\n RowActionTone,\n // 0.49 KIT-12: a danger action's confirmation words.\n RowActionConfirm,\n} from \"./components/row-actions\";\n// 0.22.0: the inputs round (kastlan's, keksdose's and Kurvenschmiede's audits).\nexport * from \"./components/checkbox-group\";\nexport * from \"./components/one-time-code-input\";\nexport * from \"./components/language-select\";\nexport * from \"./components/tile-radio\";\nexport * from \"./components/inline-edit-field\";\nexport * from \"./components/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 {\n SessionsSettingProps,\n SessionsLabels,\n SessionItem,\n SessionId,\n SessionsAction,\n} 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 useUserRosterColumns,\n UserIdentityCell,\n UserRowActions,\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 } from \"./admin/admin-overview\";\nexport type {\n AdminAttention,\n AdminAttentionTile,\n AdminExtraTile,\n AdminOverviewProps,\n AttentionTileProps,\n // 0.46 (Kurvenschmiede 1): the feedback tiles with the kit's words.\n AdminFeedbackTile,\n AdminFeedbackTileKey,\n AdminOwnTile,\n} from \"./admin/admin-overview\";\nexport { AdminToolLinks } from \"./admin/admin-tool-links\";\nexport type { AdminToolLink, AdminToolLinksProps } from \"./admin/admin-tool-links\";\n// 0.45.0 (docs/admin-harmonization.md §9.2.4): \"Send a test mail to me\".\nexport { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR } from \"./admin/mail-test-card\";\nexport type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from \"./admin/mail-test-card\";\n// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).\nexport { usePlanColumn, PlanChangeConfirm, usePlanChangeResult, DEFAULT_PLAN_CHANGE_LABELS } 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 {\n BillingInterval,\n BillingCurrency,\n PlanIntervalPrices,\n PlanPrices,\n PlanPriceAnswer,\n} from \"./billing/plan-price\";\nexport { PlanCard, PlanPicker, GrantWarningConfirm } from \"./billing/plan-card\";\nexport type {\n BillingPlan,\n PlanRelation,\n PlanCardProps,\n PlanPickerProps,\n PlanChoice,\n GrantWarningConfirmProps,\n} 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, 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 { 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 } from \"./settings/use-account-appearance\";\nexport type {\n AppearanceSource,\n AccountAppearanceFields,\n DeviceAppearance,\n AccountAppearancePatch,\n ResolvedAccountAppearance,\n UseAccountAppearanceOptions,\n AccountAppearance,\n} from \"./settings/use-account-appearance\";\n\n// ── notifications ────────────────────────────────────────────────────────────\n// 0.36.0 (docs/notifications-harmonization.md §4.2): the notification cards — the types\n// the server answers (the kit keeps no list of its own), quiet hours with the zone picker,\n// this device's push on its hook, the device list — and the signed-out unsubscribe page.\n// Each card takes the app's request functions; the kit makes no request itself.\nexport { DEFAULT_NOTIFICATIONS_LABELS } from \"./notifications/notifications-labels\";\nexport type { NotificationsLabels, NotificationRegionLabels } from \"./notifications/notifications-labels\";\nexport type {\n DigestCadence,\n NotificationSwitches,\n NotificationTypesValue,\n NotificationTypeEntry,\n NotificationTypeGroup,\n NotificationSettingsPatch,\n PushDeviceItem,\n NotificationChannel,\n} from \"./notifications/notification-types\";\nexport { NotificationTypesSetting } from \"./notifications/notification-types-setting\";\nexport type { NotificationTypesSettingProps } from \"./notifications/notification-types-setting\";\nexport { QuietHoursSetting } from \"./notifications/quiet-hours-setting\";\nexport type { QuietHoursSettingProps } from \"./notifications/quiet-hours-setting\";\n// 0.46 (docs/notifications-harmonization.md §10.1, §10.3): the inbox list, the bell and\n// the device-zone report (the account's zone is automatic only, amended 2026-10-20).\nexport { NotificationInbox, INBOX_BADGE_INTERVAL } from \"./notifications/notification-inbox\";\nexport type {\n NotificationInboxAction,\n NotificationInboxItem,\n NotificationInboxProps,\n} from \"./notifications/notification-inbox\";\nexport { NotificationBell } from \"./notifications/notification-bell\";\nexport type { NotificationBellProps } from \"./notifications/notification-bell\";\n// `deviceTimeZone` lives beside the report since 0.46.1 (keksdose N6; sign-up needs it).\nexport { useDeviceZoneReport, deviceTimeZone } from \"./notifications/device-zone-report\";\nexport type { DeviceZoneReportOptions } from \"./notifications/device-zone-report\";\nexport {\n usePushDevice,\n PUSH_SUBSCRIPTION_CHANGED,\n notifyPushSubscriptionChanged,\n pushSupported,\n PushDeviceError,\n // 0.52 (§10.6, refactor audit 2026-10-30 FLW-2): an explicit sign-out releases this device's push.\n releaseThisDevicePush,\n} from \"./notifications/use-push-device\";\nexport type {\n PushDevice,\n UsePushDeviceOptions,\n PushSubscriptionInput,\n PushPermission,\n PushDeviceErrorCode,\n} from \"./notifications/use-push-device\";\n// 0.46 (NT:1028): the service worker re-registers a rotated subscription. A worker imports\n// them from `@eifi1/ui-kit/push-worker` (§10.6 rule 5); the barrel keeps them too.\nexport {\n handlePushSubscriptionChange,\n resubscribeAfterChange,\n pushSubscriptionInput,\n} from \"./notifications/push-worker\";\nexport type {\n PushReplaceInput,\n PushSubscriptionChangeOptions,\n PushSubscriptionChangeEventLike,\n PushResubscribeOutcome,\n PushWorkerScope,\n} from \"./notifications/push-worker\";\nexport { PushDeviceSetting } from \"./notifications/push-device-setting\";\nexport type { PushDeviceSettingProps, PushDeviceAction } from \"./notifications/push-device-setting\";\nexport { PushDevicesSetting } from \"./notifications/push-devices-setting\";\nexport type { PushDevicesSettingProps } from \"./notifications/push-devices-setting\";\nexport { UnsubscribePanel, unsubscribeTokenType } from \"./notifications/unsubscribe-panel\";\nexport type { UnsubscribePanelProps } from \"./notifications/unsubscribe-panel\";\n// 0.38.0 (docs/feedback-harmonization.md §9.11): the two feedback types' setting words.\n// 0.46.1 (keksdose N9): `useFeedbackNotificationTypesLabels`, the words resolved, for `adminGroup`.\nexport {\n useFeedbackNotificationTypes,\n useFeedbackNotificationTypesLabels,\n DEFAULT_FEEDBACK_NOTIFICATION_TYPES_LABELS,\n} from \"./notifications/feedback-notification-types\";\nexport type {\n FeedbackNotificationTypeId,\n FeedbackNotificationTypesLabels,\n} from \"./notifications/feedback-notification-types\";\n\n// ── landing ──────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the public landing page. Its router-aware parts — the header and the resume (RootEntry,\n// RedirectIfAuthed, the last-visited page) — come with `./shell` above.\nexport { DEFAULT_LANDING_LABELS, useLandingLabels } from \"./landing/landing-labels\";\nexport type { LandingLabels } from \"./landing/landing-labels\";\nexport { accessAction, useAccessAction } from \"./landing/access\";\nexport type { AccessChoice, AccessLink, AccessLabels } from \"./landing/access\";\nexport { LandingActions } from \"./landing/landing-actions\";\nexport type { LandingActionsProps, LandingSession } from \"./landing/landing-actions\";\nexport { Hero, FeatureRows, FeatureRow, TrustStrip, CtaBand, PublicFooter } from \"./landing/landing-sections\";\nexport type {\n HeroProps,\n FeatureRowsProps,\n FeatureRowProps,\n TrustItem,\n TrustStripProps,\n CtaBandProps,\n PublicFooterProps,\n} from \"./landing/landing-sections\";\nexport { usePageSeo, seoCopyProblems, metaContent } from \"./landing/page-seo\";\nexport type { PageSeo, SeoCopy, SeoCopyLimits, SeoCopyProblem, SeoCopyProblemCode } from \"./landing/page-seo\";\n// 0.51.0 (Marcel 2026-10-26): the frame of a public page that is not the landing or a legal page.\nexport { PublicPage } from \"./landing/public-page\";\nexport type { PublicPageProps } from \"./landing/public-page\";\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 } 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). 0.52 (DUP-8,\n// refactor audit 2026-10-30): the remove, the sessionStorage pair and a JSON pair with a\n// shape check — 16 files in the apps wrap storage by hand, a few of them with no guard.\nexport {\n readStored,\n writeStored,\n removeStored,\n readSessionStored,\n writeSessionStored,\n readStoredJson,\n writeStoredJson,\n} from \"./lib/safe-storage\";\n// 0.52 (DUP-8): `prefers-reduced-motion`, asked at the moment of the motion (KS copied it).\nexport { prefersReducedMotion } from \"./lib/reduced-motion\";\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// The local-calendar ISO date helpers are the \"@eifi1/ui-kit/dates\" entry, standalone: none\n// of its names is in this barrel (public-surface.test.ts, STANDALONE).\n// One fold and one ranking for every list's search box (DUP-5), for an app's own lists;\n// and the pickers' every-word match (0.51.5), for an async `loadOptions` that filters itself.\nexport { foldForSearch, rankMatch, searchWords, matchesSearch } 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 {\n ServerWakeStage,\n ServerWakeFilter,\n ServerWakeOptions,\n ServerWakeRequest,\n ServerWakeWatcher,\n ServerWakeAxiosConfig,\n AxiosLikeInstance,\n} 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 {\n createSessionRefresh,\n attachSessionRefresh,\n isTransientRefreshFailure,\n isSignedOutStep,\n} from \"./lib/session-refresh\";\nexport type {\n SessionRefresh,\n SessionRefreshOptions,\n SessionRenewal,\n SessionRefreshOutcome,\n} 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 // 0.54: a save or a reset of any size under server-kit's cap of 2000 (kastlan reuse\n // audit 2026-11-02, proposal 5).\n saveReviewsInChunks,\n clearReviewsInChunks,\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 and phone helpers that\n// CountrySelect, IbanInput and PhoneInput are built on.\nexport { COUNTRY_CODES, countryName } from \"./lib/countries\";\nexport { IBAN_LENGTHS, compactIban, formatIban, ibanCheckDigits, ibanProblem, isValidIban, isQrIban } from \"./lib/iban\";\nexport type { IbanKind, IbanProblem } from \"./lib/iban\";\nexport { PHONE_DIAL_CODES, PHONE_COUNTRIES, parsePhone, formatNationalPhone, formatPhone, isE164 } 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.52 (DUP-8): DataTable's press-and-hold, which keksdose wrote first and still keeps.\nexport { useLongPress } from \"./hooks/use-long-press\";\nexport type { LongPressOptions, LongPressResult } from \"./hooks/use-long-press\";\n// 0.28: keksdose's noindex marker, for the legal and auth pages of every app.\nexport { useNoIndex } from \"./hooks/use-noindex\";\n// 0.49 KIT-9: the window's title from page, section and app, in the provider's format.\nexport { useDocumentTitle } from \"./hooks/use-document-title\";\n// 0.53: the 55 names no app reads left the entry points (deprecated in 0.52, refactor audit\n// 2026-10-30, API-4, decision 4) — here 0.49 KIT-1b's `asciiMinusInNumbers`, the copy\n// handler's rule, among them. Their modules keep the ones the kit itself uses.\nexport { DEFAULT_DOCUMENT_TITLE_FORMAT, formatDocumentTitle } from \"./lib/document-title\";\nexport type { DocumentTitleParts } from \"./lib/document-title\";\nexport type { SwipeStage, RowSwipeOptions, RowSwipeReturn } from \"./hooks/use-row-swipe\";\n// Any element as a file drop target, screened like FileButton (kastlan).\nexport { useFileDrop, dragHasFiles } from \"./hooks/use-file-drop\";\nexport type { UseFileDropOptions, UseFileDropReturn, FileDropProps } from \"./hooks/use-file-drop\";\n// kastlan's search boxes each carried a hand-rolled copy, two without the cleanup.\nexport { useDebounce, useDebouncedCallback } from \"./hooks/use-debounce\";\nexport type { DebouncedCallbackOptions, DebouncedFunction } from \"./hooks/use-debounce\";\n// One search param as state, the active tab in `?tab=`, and a dialog's open state in the\n// URL (Modal's `urlParam`) — kastlan's and keksdose's use-search-param-state, in the kit.\nexport { useSearchParamState, useTabParam, useDialogParam } from \"./hooks/use-search-param-state\";\nexport type { SearchParamStateOptions, DialogParam } from \"./hooks/use-search-param-state\";\n// 0.25: several keys, one navigation (keksdose live #378 — four setters in a row clobbered).\nexport { useSearchParamsState } from \"./hooks/use-search-param-state\";\nexport type { SearchParamField, SearchParamFields, SearchParamsUpdate } from \"./hooks/use-search-param-state\";\n// Copy that reports whether it worked — keksdose's copy buttons said \"Copied\" when it had not.\nexport { useCopyToClipboard, copyToClipboard } from \"./hooks/use-copy-to-clipboard\";\nexport type { CopyState, UseCopyToClipboardOptions, UseCopyToClipboardReturn } from \"./hooks/use-copy-to-clipboard\";\n// Keyboard shortcuts (\"Mod+K\", \"Ctrl+Shift+F\") that leave typing in fields alone.\nexport { useHotkey, parseHotkey, matchesHotkey } from \"./hooks/use-hotkey\";\nexport type { Hotkey, ParsedHotkey, UseHotkeyOptions } from \"./hooks/use-hotkey\";\n// A protected file as an object URL, fetched with the app's own auth (kastlan's AuthedImage).\nexport { useAuthedSrc } from \"./hooks/use-authed-src\";\nexport type { AuthedFetcher, AuthedSrcStatus, UseAuthedSrcOptions, UseAuthedSrcResult } from \"./hooks/use-authed-src\";\n// Row windowing for a long list (0.7.0, lenkbank's measured grid is built on it).\nexport { useWindowedRows, WINDOWED_ROW_INDEX } from \"./hooks/use-windowed-rows\";\nexport type { WindowedRows } from \"./hooks/use-windowed-rows\";\n// 0.32.0 (docs/text-size-harmonization.md): the breakpoints, and the hooks components read\n// the behaviours at Large from (§4, §10.7–10.9).\nexport {\n useBreakpoint,\n usePhoneLayout,\n breakpointQuery,\n BREAKPOINT_REM,\n remPx,\n useRemPx,\n} 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\";\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// 0.49.0 (KIT-8): five domain-free status kinds and their tones — Chip/StatusDot `status`.\nexport { statusTone, STATUS_KINDS } from \"./lib/status-tone\";\nexport type { StatusKind, StatusTone } from \"./lib/status-tone\";\n// ChipInput's own module since MOD-9: it renders Chip, so chip.tsx re-exports only its types.\nexport * from \"./components/chip-input\";\nexport * from \"./components/wizard-stepper\";\nexport * from \"./components/hover-menu\";\nexport * from \"./components/modal\";\nexport * from \"./components/full-bleed-dialog\";\nexport * from \"./components/grouped-picker\";\nexport * from \"./components/file-dropzone\";\nexport * from \"./components/mini-calendar\";\n// Named, not `*`: `heatmapLevel` is CalendarHeatmap's own since 0.53 (API-4).\nexport {\n CalendarHeatmap,\n DEFAULT_CALENDAR_HEATMAP_LABELS,\n heatmapWindowEnd,\n type CalendarHeatmapLabels,\n type CalendarHeatmapDatum,\n type CalendarHeatmapDay,\n type CalendarHeatmapProps,\n} 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 {\n WriteLockProvider,\n useWriteLock,\n writeLockFor,\n COMMIT_EXCEPT_BILLING,\n DEFAULT_WRITE_LOCK_LABELS,\n} from \"./components/write-lock\";\n// 0.46 (kastlan K4): the offline lock's scope and its source (the kind, `OFFLINE_LOCK`, left\n// the surface in 0.53: it is the string \"offline\").\nexport { COMMIT_EXCEPT_OFFLINE, useOfflineWriteLock } from \"./components/write-lock\";\nexport type {\n WriteLock,\n WriteLockLabels,\n WriteLockProviderProps,\n WriteLockKind,\n WriteLockHold,\n CommitScope,\n} from \"./components/write-lock\";\n// 0.18: the parts both apps' admin rosters repeat (Kurvenschmiede 6).\nexport {\n RoleChip,\n AccountStateChip,\n DateMark,\n dateColumn,\n DEFAULT_ACCOUNT_STATE_LABELS,\n ACCOUNT_STATE_TONES,\n} from \"./components/account-chips\";\nexport type {\n RoleChipProps,\n RoleDefinition,\n RoleVocabulary,\n AccountState,\n AccountStateLabels,\n AccountStateChipProps,\n DateMarkProps,\n DateColumnOptions,\n} 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 {\n ShareCardProps,\n ShareDialogProps,\n SharePanelProps,\n ShareCardLabels,\n ShareRole,\n ShareGrantee,\n SharePendingGrant,\n ShareCandidate,\n ShareAddRequest,\n} from \"./components/share-card\";\nexport * from \"./components/line-items\";\nexport * from \"./components/progress-bar\";\n// Named: skeleton.tsx also holds SKELETON_CLASS, the look StatTile shares — internal.\nexport { Skeleton } from \"./components/skeleton\";\nexport type { SkeletonProps, SkeletonShape } from \"./components/skeleton\";\n// 0.48 (keksdose dev #628): the table/list loading preset, one status label.\nexport { TableSkeleton } from \"./components/table-skeleton\";\nexport type { TableSkeletonProps } from \"./components/table-skeleton\";\n// 0.12.0: a centred spinner with words, signed figures and deltas, a render-error fallback.\nexport * from \"./components/loading-state\";\nexport * from \"./components/signed-amount\";\nexport * from \"./components/error-boundary\";\nexport * from \"./components/copy-button\";\nexport { AuthedImage, DEFAULT_AUTHED_IMAGE_LABELS } from \"./components/authed-image\";\nexport type { AuthedImageProps, AuthedImageLabels } from \"./components/authed-image\";\n// Named, not `*`: `splitFileName` is ImageGrid's own since 0.53 (API-4).\nexport {\n ImageGrid,\n DEFAULT_IMAGE_GRID_LABELS,\n type ImageGridLabels,\n type ImageGridProps,\n} 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 { toast, Toaster, DEFAULT_TOAST_LABELS } 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 LegalInfoPageKey,\n LegalTextSectionLabels,\n LegalOperatorSectionLabels,\n LegalFramedSectionLabels,\n LegalDisclaimerSectionLabels,\n} from \"./components/legal\";\nexport { LegalPage, LegalKitSection, LegalAcceptCheckbox, LEGAL_SKELETON } from \"./components/legal-page\";\nexport type {\n LegalPageProps,\n LegalKitSectionProps,\n LegalKitSectionKey,\n LegalAcceptCheckboxProps,\n LegalSkeletonEntry,\n LegalSkeletonPage,\n LegalSectionOwner,\n LegalDisclaimerVariant,\n} from \"./components/legal-page\";\n// 0.32.0 (docs/text-size-harmonization.md): the appearance settings' words, and a row's\n// actions, one of the behaviours at Large (§4, §10.7–10.9).\nexport { DEFAULT_APPEARANCE_LABELS, useAppearanceLabels } from \"./components/appearance-labels\";\nexport type { AppearanceLabels } from \"./components/appearance-labels\";\n// 0.46 (keksdose's date format, lifted): the preference, its resolver and renderer, the\n// provider's formatter for it, and the settings field.\nexport {\n DATE_FORMAT_PREFERENCES,\n isDateFormatPreference,\n resolveDateFormat,\n formatDateWithPreference,\n // 0.52 (refactor audit 2026-10-30, DUP-2): a timestamp, the preference's date and the language's clock.\n formatDateTimeWithPreference,\n dateFormatSample,\n dateFormatterFor,\n} from \"./lib/date-format\";\nexport type { DateFormatPreference, DateFormatOptions, ResolvedDateFormat } from \"./lib/date-format\";\nexport { DateFormatSetting } from \"./components/date-format-setting\";\nexport type { DateFormatSettingProps } from \"./components/date-format-setting\";\nexport {\n RowActions,\n rowActionsColumn,\n DEFAULT_ROW_ACTIONS_LABELS,\n // 0.47.0 (keksdose N17): a hand-built table's actions heading and cell.\n RowActionsHead,\n ROW_ACTIONS_CELL_CLASS,\n} from \"./components/row-actions\";\nexport type {\n RowAction,\n RowActionList,\n RowActionsLabels,\n RowActionsProps,\n RowActionsCollapse,\n RowActionsSize,\n RowActionsColumnOptions,\n RowActionsHeadProps,\n RowActionTone,\n // 0.49 KIT-12: a danger action's confirmation words.\n RowActionConfirm,\n} from \"./components/row-actions\";\n// 0.22.0: the inputs round (kastlan's, keksdose's and Kurvenschmiede's audits).\nexport * from \"./components/checkbox-group\";\nexport * from \"./components/one-time-code-input\";\nexport * from \"./components/language-select\";\nexport * from \"./components/tile-radio\";\nexport * from \"./components/inline-edit-field\";\nexport * from \"./components/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\";\n// 0.54 (kastlan reuse audit 2026-11-02, proposal 4): `billingRefusalText`, a billing\n// refusal's words, which every app mapped from the code by hand.\nexport { isAuthError, authErrorCode, isBillingError, billingRefusalText } 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 {\n AccountErrorCode,\n BillingErrorCode,\n BillingRefusalTextOptions,\n DemoErrorCode,\n KitErrorCode,\n} 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 {\n SessionsSettingProps,\n SessionsLabels,\n SessionItem,\n SessionId,\n SessionsAction,\n} 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 useUserRosterColumns,\n UserIdentityCell,\n UserRowActions,\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 } from \"./admin/admin-overview\";\nexport type {\n AdminAttention,\n AdminAttentionTile,\n AdminExtraTile,\n AdminOverviewProps,\n AttentionTileProps,\n // 0.46 (Kurvenschmiede 1): the feedback tiles with the kit's words.\n AdminFeedbackTile,\n AdminFeedbackTileKey,\n AdminOwnTile,\n} from \"./admin/admin-overview\";\nexport { AdminToolLinks } from \"./admin/admin-tool-links\";\nexport type { AdminToolLink, AdminToolLinksProps } from \"./admin/admin-tool-links\";\n// 0.45.0 (docs/admin-harmonization.md §9.2.4): \"Send a test mail to me\".\nexport { MailTestCard, DEFAULT_MAIL_TEST_CARD_LABELS, MAIL_TEST_ANCHOR } from \"./admin/mail-test-card\";\nexport type { MailTestCardProps, MailTestCardLabels, MailTestAnswer } from \"./admin/mail-test-card\";\n// 0.33.0: the operator's plan parts (docs/billing-harmonization.md §14.12).\nexport { usePlanColumn, PlanChangeConfirm, usePlanChangeResult, DEFAULT_PLAN_CHANGE_LABELS } 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 {\n BillingInterval,\n BillingCurrency,\n PlanIntervalPrices,\n PlanPrices,\n PlanPriceAnswer,\n} from \"./billing/plan-price\";\nexport { PlanCard, PlanPicker, GrantWarningConfirm } from \"./billing/plan-card\";\nexport type {\n BillingPlan,\n PlanRelation,\n PlanCardProps,\n PlanPickerProps,\n PlanChoice,\n GrantWarningConfirmProps,\n} 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, 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 { 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 } from \"./settings/use-account-appearance\";\nexport type {\n AppearanceSource,\n AccountAppearanceFields,\n DeviceAppearance,\n AccountAppearancePatch,\n ResolvedAccountAppearance,\n UseAccountAppearanceOptions,\n AccountAppearance,\n} from \"./settings/use-account-appearance\";\n\n// ── notifications ────────────────────────────────────────────────────────────\n// 0.36.0 (docs/notifications-harmonization.md §4.2): the notification cards — the types\n// the server answers (the kit keeps no list of its own), quiet hours with the zone picker,\n// this device's push on its hook, the device list — and the signed-out unsubscribe page.\n// Each card takes the app's request functions; the kit makes no request itself.\nexport { DEFAULT_NOTIFICATIONS_LABELS } from \"./notifications/notifications-labels\";\nexport type { NotificationsLabels, NotificationRegionLabels } from \"./notifications/notifications-labels\";\nexport type {\n DigestCadence,\n NotificationSwitches,\n NotificationTypesValue,\n NotificationTypeEntry,\n NotificationTypeGroup,\n NotificationSettingsPatch,\n PushDeviceItem,\n NotificationChannel,\n} from \"./notifications/notification-types\";\nexport { NotificationTypesSetting } from \"./notifications/notification-types-setting\";\nexport type { NotificationTypesSettingProps } from \"./notifications/notification-types-setting\";\nexport { QuietHoursSetting } from \"./notifications/quiet-hours-setting\";\nexport type { QuietHoursSettingProps } from \"./notifications/quiet-hours-setting\";\n// 0.46 (docs/notifications-harmonization.md §10.1, §10.3): the inbox list, the bell and\n// the device-zone report (the account's zone is automatic only, amended 2026-10-20).\nexport { NotificationInbox, INBOX_BADGE_INTERVAL } from \"./notifications/notification-inbox\";\nexport type {\n NotificationInboxAction,\n NotificationInboxItem,\n NotificationInboxProps,\n} from \"./notifications/notification-inbox\";\nexport { NotificationBell } from \"./notifications/notification-bell\";\nexport type { NotificationBellProps } from \"./notifications/notification-bell\";\n// `deviceTimeZone` lives beside the report since 0.46.1 (keksdose N6; sign-up needs it).\nexport { useDeviceZoneReport, deviceTimeZone } from \"./notifications/device-zone-report\";\nexport type { DeviceZoneReportOptions } from \"./notifications/device-zone-report\";\nexport {\n usePushDevice,\n PUSH_SUBSCRIPTION_CHANGED,\n notifyPushSubscriptionChanged,\n pushSupported,\n PushDeviceError,\n // 0.52 (§10.6, refactor audit 2026-10-30 FLW-2): an explicit sign-out releases this device's push.\n releaseThisDevicePush,\n} from \"./notifications/use-push-device\";\nexport type {\n PushDevice,\n UsePushDeviceOptions,\n PushSubscriptionInput,\n PushPermission,\n PushDeviceErrorCode,\n} from \"./notifications/use-push-device\";\n// 0.46 (NT:1028): the service worker re-registers a rotated subscription. A worker imports\n// them from `@eifi1/ui-kit/push-worker` (§10.6 rule 5); the barrel keeps them too.\nexport {\n handlePushSubscriptionChange,\n resubscribeAfterChange,\n pushSubscriptionInput,\n} from \"./notifications/push-worker\";\nexport type {\n PushReplaceInput,\n PushSubscriptionChangeOptions,\n PushSubscriptionChangeEventLike,\n PushResubscribeOutcome,\n PushWorkerScope,\n} from \"./notifications/push-worker\";\nexport { PushDeviceSetting } from \"./notifications/push-device-setting\";\nexport type { PushDeviceSettingProps, PushDeviceAction } from \"./notifications/push-device-setting\";\nexport { PushDevicesSetting } from \"./notifications/push-devices-setting\";\nexport type { PushDevicesSettingProps } from \"./notifications/push-devices-setting\";\nexport { UnsubscribePanel, unsubscribeTokenType } from \"./notifications/unsubscribe-panel\";\nexport type { UnsubscribePanelProps } from \"./notifications/unsubscribe-panel\";\n// 0.38.0 (docs/feedback-harmonization.md §9.11): the two feedback types' setting words.\n// 0.46.1 (keksdose N9): `useFeedbackNotificationTypesLabels`, the words resolved, for `adminGroup`.\nexport {\n useFeedbackNotificationTypes,\n useFeedbackNotificationTypesLabels,\n DEFAULT_FEEDBACK_NOTIFICATION_TYPES_LABELS,\n} from \"./notifications/feedback-notification-types\";\nexport type {\n FeedbackNotificationTypeId,\n FeedbackNotificationTypesLabels,\n} from \"./notifications/feedback-notification-types\";\n\n// ── landing ──────────────────────────────────────────────────────────────────\n// 0.31.0 (docs/landing-demo-harmonization.md): the public landing page. Its router-aware parts — the header and the resume (RootEntry,\n// RedirectIfAuthed, the last-visited page) — come with `./shell` above.\nexport { DEFAULT_LANDING_LABELS, useLandingLabels } from \"./landing/landing-labels\";\nexport type { LandingLabels } from \"./landing/landing-labels\";\nexport { accessAction, useAccessAction } from \"./landing/access\";\nexport type { AccessChoice, AccessLink, AccessLabels } from \"./landing/access\";\nexport { LandingActions } from \"./landing/landing-actions\";\nexport type { LandingActionsProps, LandingSession } from \"./landing/landing-actions\";\nexport { Hero, FeatureRows, FeatureRow, TrustStrip, CtaBand, PublicFooter } from \"./landing/landing-sections\";\nexport type {\n HeroProps,\n FeatureRowsProps,\n FeatureRowProps,\n TrustItem,\n TrustStripProps,\n CtaBandProps,\n PublicFooterProps,\n} from \"./landing/landing-sections\";\nexport { usePageSeo, seoCopyProblems, metaContent } from \"./landing/page-seo\";\nexport type { PageSeo, SeoCopy, SeoCopyLimits, SeoCopyProblem, SeoCopyProblemCode } from \"./landing/page-seo\";\n// 0.51.0 (Marcel 2026-10-26): the frame of a public page that is not the landing or a legal page.\nexport { PublicPage } from \"./landing/public-page\";\nexport type { PublicPageProps } from \"./landing/public-page\";\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 } 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":[]}
@@ -60,7 +60,13 @@ export declare function parseIsoDate(s: string): Date | null;
60
60
  * unparseable). Defaults to the locale's short numeric date; pass `options` to
61
61
  * override (e.g. `{ dateStyle: "medium" }`). `locale` may be `undefined` since 0.34 —
62
62
  * the runtime's default, as `Intl` reads it and as every other kit formatter takes it
63
- * (DUP-11: DatePicker re-wrapped this function only to pass none). */
63
+ * (DUP-11: DatePicker re-wrapped this function only to pass none).
64
+ *
65
+ * Through the kit's formatter cache since 0.54 (keksdose audit follow-up, 2026-11-01):
66
+ * `toLocaleDateString` builds a formatter per call, and this one runs for the date
67
+ * pickers' trigger on every render and for an app's date column once per row. The output
68
+ * is `toLocaleDateString`'s: the same options, with the date it adds when they name none
69
+ * (`asDateOptions`). */
64
70
  export declare function formatIsoDate(iso: string, locale: string | undefined, options?: Intl.DateTimeFormatOptions): string;
65
71
  /** A "YYYY-MM-DD" string shifted by `days` (negative shifts back), or the input
66
72
  * unchanged when it isn't a parseable date.
package/dist/lib/dates.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { dateFormatter } from "./intl-cache.js";
2
3
  function pad(n) {
3
4
  return String(n).padStart(2, "0");
4
5
  }
@@ -60,9 +61,15 @@ function parseIsoDate(s) {
60
61
  if (dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) return null;
61
62
  return dt;
62
63
  }
64
+ const DATE_FIELDS = ["weekday", "year", "month", "day", "dateStyle"];
65
+ const NUMERIC_DATE = { year: "numeric", month: "numeric", day: "numeric" };
66
+ function asDateOptions(options) {
67
+ if (!options) return NUMERIC_DATE;
68
+ return DATE_FIELDS.some((field) => options[field] !== void 0) ? options : { ...options, ...NUMERIC_DATE };
69
+ }
63
70
  function formatIsoDate(iso, locale, options) {
64
71
  const d = parseIsoDate(iso);
65
- return d ? d.toLocaleDateString(locale, options) : "";
72
+ return d ? dateFormatter(locale, asDateOptions(options)).format(d) : "";
66
73
  }
67
74
  function addDaysIso(iso, days) {
68
75
  const d = parseIsoDate(iso);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/dates.ts"],"sourcesContent":["/**\n * ISO date helpers, collected from copies that were scattered across the pages.\n *\n * **Every \"what day is it\" helper here reads the LOCAL calendar** — one family, not\n * two. It used to be two: these all built a local Date and then read it back through\n * `toISOString()`, which is UTC, so east of Greenwich they all returned YESTERDAY\n * between local midnight and the UTC rollover. The old module note called that\n * deliberate and warned against changing it. It was not defensible, and dev#471 is\n * what it cost:\n *\n * > *\"Just entered a tx now from scheduled. But it still shows as upcoming. Is there\n * > a problem with timezones? It is currently 1 o clock middle european summer time.\"*\n *\n * There was: at 01:00 CEST `todayIso()` answered with the 14th, the row the scheduler\n * had just booked was dated the 15th, and `isUpcoming` compares the two strings — so a\n * transaction entered a second ago read as one still to come. The same slip moved\n * `startOfMonthIso()` onto the last day of the PREVIOUS month for an hour every first\n * of the month, which is a report range nobody would have questioned.\n *\n * A calendar day only means anything to the human reading it, and every caller here —\n * the register's today, the date-range presets, the budget cursor, a new\n * transaction's default date — is asking that question. There is no caller for whom\n * \"the UTC day\" is the right answer; the server compares plain dates with no zone at\n * all, so sending it the user's local day is also what it wants.\n */\n\n/** Zero-pad a number to two digits (\"3\" -> \"03\"). */\nexport function pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** Today as \"YYYY-MM-DD\" on the LOCAL calendar (see the module note). */\nexport function todayIso(): string {\n return toLocalIso(new Date());\n}\n\n/** A Date as a local-time \"YYYY-MM-DD\" string. */\nexport function toLocalIso(d: Date): string {\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n}\n\n/** A Date as a local-time \"YYYY-MM\" month key. */\nexport function monthKey(d: Date): string {\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;\n}\n\n// ---------- Date-range presets + calendar helpers ----------\n// Local-calendar like todayIso (see the module note); used by the data-table date\n// filter and its MiniCalendar. Each one mutates a local Date and must therefore READ\n// it back locally — going out through toISOString() is what shifted every one of\n// these by a day near midnight (dev#471).\n\n/** Today shifted by `days`, as \"YYYY-MM-DD\". */\nexport function shiftIso(days: number): string {\n const d = new Date();\n d.setDate(d.getDate() + days);\n return toLocalIso(d);\n}\n\n/** First day (Monday) of the current week, as \"YYYY-MM-DD\". */\nexport function startOfWeekIso(): string {\n const d = new Date();\n const day = d.getDay();\n const diff = (day + 6) % 7; // monday = 0\n d.setDate(d.getDate() - diff);\n return toLocalIso(d);\n}\n\n/** First day of the month `offsetMonths` from now, as \"YYYY-MM-DD\". */\nexport function startOfMonthIso(offsetMonths = 0): string {\n const d = new Date();\n d.setDate(1);\n d.setMonth(d.getMonth() + offsetMonths);\n return toLocalIso(d);\n}\n\n/** Last day of the month `offsetMonths` from now, as \"YYYY-MM-DD\". */\nexport function endOfMonthIso(offsetMonths = 0): string {\n const d = new Date();\n d.setDate(1);\n d.setMonth(d.getMonth() + offsetMonths + 1);\n d.setDate(0);\n return toLocalIso(d);\n}\n\n/** First day of the year `offsetYears` from now, as \"YYYY-MM-DD\". */\nexport function startOfYearIso(offsetYears = 0): string {\n const d = new Date();\n d.setMonth(0);\n d.setDate(1);\n d.setFullYear(d.getFullYear() + offsetYears);\n return toLocalIso(d);\n}\n\n/** Last day of the year `offsetYears` from now, as \"YYYY-MM-DD\". */\nexport function endOfYearIso(offsetYears = 0): string {\n const d = new Date();\n d.setMonth(11);\n d.setDate(31);\n d.setFullYear(d.getFullYear() + offsetYears);\n return toLocalIso(d);\n}\n\n/** Parse a \"YYYY-MM-DD\" string to a local-midnight Date, or null if malformed —\n * where \"malformed\" includes a date that does not exist.\n *\n * The falsy check alone was not enough. `new Date(y, m - 1, d)` ROLLS OVER out-of-range\n * components rather than refusing them, so \"2026-13-45\" came back as 2027-02-14 and\n * \"2026-02-30\" as 2026-03-02: a valid-looking Date for a day that never happened. No\n * caller could tell — {@link formatIsoDate} blanks only on `null`, so the invented\n * date formatted and displayed exactly like a real one.\n *\n * The round-trip is the check: build the Date, then read the components back off it.\n * A value that rolled over cannot answer with the numbers it was given. That is the\n * same shape {@link sameYmd} already expresses, applied to a Date and its source. */\nexport function parseIsoDate(s: string): Date | null {\n if (!s) return null;\n const [y, m, d] = s.split(\"-\").map(Number);\n if (!y || !m || !d) return null;\n if (!Number.isInteger(y) || !Number.isInteger(m) || !Number.isInteger(d)) return null;\n const dt = new Date(y, m - 1, d);\n if (Number.isNaN(dt.getTime())) return null;\n if (dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) return null;\n return dt;\n}\n\n/** Format a \"YYYY-MM-DD\" string for display in `locale` (empty string when\n * unparseable). Defaults to the locale's short numeric date; pass `options` to\n * override (e.g. `{ dateStyle: \"medium\" }`). `locale` may be `undefined` since 0.34 —\n * the runtime's default, as `Intl` reads it and as every other kit formatter takes it\n * (DUP-11: DatePicker re-wrapped this function only to pass none). */\nexport function formatIsoDate(iso: string, locale: string | undefined, options?: Intl.DateTimeFormatOptions): string {\n const d = parseIsoDate(iso);\n return d ? d.toLocaleDateString(locale, options) : \"\";\n}\n\n/** A \"YYYY-MM-DD\" string shifted by `days` (negative shifts back), or the input\n * unchanged when it isn't a parseable date.\n *\n * Local-time throughout — {@link parseIsoDate} builds a local-midnight Date and\n * {@link toLocalIso} reads local components back, so this never slides a day the way\n * a `toISOString()` round-trip does west of UTC. */\nexport function addDaysIso(iso: string, days: number): string {\n const d = parseIsoDate(iso);\n if (!d) return iso;\n d.setDate(d.getDate() + days);\n return toLocalIso(d);\n}\n\n/**\n * `d` moved by whole months, keeping the day of the month where the target has one.\n * `setMonth` alone ROLLS OVER — 31 January + 1 month is 3 March — which would skip\n * February entirely for anyone paging through the year with PageDown. Returns a new\n * Date; `d` is not touched.\n */\nexport function addMonthsClamped(d: Date, months: number): Date {\n const day = d.getDate();\n const out = new Date(d.getFullYear(), d.getMonth() + months, 1);\n const lastOfTarget = new Date(out.getFullYear(), out.getMonth() + 1, 0).getDate();\n out.setDate(Math.min(day, lastOfTarget));\n return out;\n}\n\n/**\n * The first day of the week in `locale`, as a `Date#getDay` index (0 = Sunday).\n *\n * `Intl.Locale#getWeekInfo()` is the standard spelling; V8 shipped it first as the\n * `weekInfo` accessor, and Firefox has neither yet — hence both reads and a Monday\n * fallback, which is ISO 8601. Its `firstDay` counts 1 = Monday … 7 = Sunday, so `% 7`\n * maps it onto `getDay`. `undefined` asks for the runtime's default locale.\n */\nexport function localeWeekStart(locale: string | undefined): 0 | 1 | 2 | 3 | 4 | 5 | 6 {\n try {\n const tag = locale ?? new Intl.DateTimeFormat().resolvedOptions().locale;\n const loc = new Intl.Locale(tag) as Intl.Locale & {\n getWeekInfo?: () => { firstDay: number };\n weekInfo?: { firstDay: number };\n };\n const firstDay = (loc.getWeekInfo?.() ?? loc.weekInfo)?.firstDay;\n if (typeof firstDay === \"number\") return (firstDay % 7) as 0 | 1 | 2 | 3 | 4 | 5 | 6;\n } catch {\n // A malformed tag throws from `Intl.Locale`; a calendar still has to render.\n }\n return 1;\n}\n\n/** Whether two Dates fall on the same local calendar day. */\nexport function sameYmd(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nexport interface DateRangePreset {\n key: string;\n from: string;\n to: string;\n}\n\n/**\n * The named ranges offered by the data-table date filter (local-calendar, like\n * {@link todayIso} — see the module note). `key` maps to the consumer's\n * `table.preset_*` labels.\n */\nexport function dateRangePresets(): DateRangePreset[] {\n const mondayOffset = (new Date().getDay() + 6) % 7; // monday = 0\n return [\n { key: \"today\", from: todayIso(), to: todayIso() },\n { key: \"yesterday\", from: shiftIso(-1), to: shiftIso(-1) },\n { key: \"this_week\", from: startOfWeekIso(), to: todayIso() },\n { key: \"last_week\", from: shiftIso(-7 - mondayOffset), to: shiftIso(-1 - mondayOffset) },\n { key: \"last_7_days\", from: shiftIso(-6), to: todayIso() },\n { key: \"last_30_days\", from: shiftIso(-29), to: todayIso() },\n { key: \"this_month\", from: startOfMonthIso(0), to: todayIso() },\n { key: \"last_month\", from: startOfMonthIso(-1), to: endOfMonthIso(-1) },\n { key: \"last_3_months\", from: shiftIso(-90), to: todayIso() },\n { key: \"ytd\", from: startOfYearIso(0), to: todayIso() },\n { key: \"last_year\", from: startOfYearIso(-1), to: endOfYearIso(-1) },\n ];\n}\n\n/** The last `n` WHOLE calendar months before the current one, as an inclusive\n * `{ from, to }` — on 15 May, `n = 3` is 1 February … 30 April. Local-calendar, like\n * everything here; `now` is for tests and for a host with its own clock. */\nexport function lastFullMonthsRange(n: number, now: Date = new Date()): { from: string; to: string } {\n const from = new Date(now.getFullYear(), now.getMonth() - n, 1);\n // Day 0 of the current month is the last day of the previous one.\n const to = new Date(now.getFullYear(), now.getMonth(), 0);\n return { from: toLocalIso(from), to: toLocalIso(to) };\n}\n\n/** The last `n` WHOLE calendar years before the current one — in 2026, `n = 2` is\n * 1 January 2024 … 31 December 2025. */\nexport function lastFullYearsRange(n: number, now: Date = new Date()): { from: string; to: string } {\n const year = now.getFullYear();\n return { from: `${year - n}-01-01`, to: `${year - 1}-12-31` };\n}\n\nexport interface CalendarMonthPresetOptions {\n /** How many whole months each month preset spans. Default `[3, 6]`. */\n months?: readonly number[];\n /** How many whole years each year preset spans. Default `[2]`. */\n years?: readonly number[];\n /** The day to count back from. Default: now, on the local calendar. */\n now?: Date;\n}\n\n/**\n * Month-ALIGNED presets, beside the rolling-day ones of {@link dateRangePresets}.\n *\n * kastlan's accounting reports are closed by the month: \"the last three months\" there\n * means February, March and April, never \"the 90 days up to this morning\", which\n * starts mid-month and ends with a day that is still being booked. `last_3_months`\n * above is the rolling kind and stays that way for the data table's filter, so these\n * are separate keys rather than a changed meaning under an old one.\n *\n * Keys are `last_<n>_full_months` and `last_<n>_full_years`; the host labels them (the\n * same arrangement as `dateRangePresets`' keys and its `table.preset_*` strings). With\n * `DateRangePicker`, pass the key as the preset's `id` so the choice keeps its\n * identity while the dates are recomputed on every render.\n */\nexport function calendarMonthPresets(options: CalendarMonthPresetOptions = {}): DateRangePreset[] {\n const { months = [3, 6], years = [2], now = new Date() } = options;\n return [\n ...months.map((n) => ({ key: `last_${n}_full_months`, ...lastFullMonthsRange(n, now) })),\n ...years.map((n) => ({ key: `last_${n}_full_years`, ...lastFullYearsRange(n, now) })),\n ];\n}\n"],"mappings":";AA2BO,SAAS,IAAI,GAAmB;AACrC,SAAO,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAClC;AAGO,SAAS,WAAmB;AACjC,SAAO,WAAW,oBAAI,KAAK,CAAC;AAC9B;AAGO,SAAS,WAAW,GAAiB;AAC1C,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxE;AAGO,SAAS,SAAS,GAAiB;AACxC,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI,EAAE,SAAS,IAAI,CAAC,CAAC;AACpD;AASO,SAAS,SAAS,MAAsB;AAC7C,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI;AAC5B,SAAO,WAAW,CAAC;AACrB;AAGO,SAAS,iBAAyB;AACvC,QAAM,IAAI,oBAAI,KAAK;AACnB,QAAM,MAAM,EAAE,OAAO;AACrB,QAAM,QAAQ,MAAM,KAAK;AACzB,IAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI;AAC5B,SAAO,WAAW,CAAC;AACrB;AAGO,SAAS,gBAAgB,eAAe,GAAW;AACxD,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,QAAQ,CAAC;AACX,IAAE,SAAS,EAAE,SAAS,IAAI,YAAY;AACtC,SAAO,WAAW,CAAC;AACrB;AAGO,SAAS,cAAc,eAAe,GAAW;AACtD,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,QAAQ,CAAC;AACX,IAAE,SAAS,EAAE,SAAS,IAAI,eAAe,CAAC;AAC1C,IAAE,QAAQ,CAAC;AACX,SAAO,WAAW,CAAC;AACrB;AAGO,SAAS,eAAe,cAAc,GAAW;AACtD,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,SAAS,CAAC;AACZ,IAAE,QAAQ,CAAC;AACX,IAAE,YAAY,EAAE,YAAY,IAAI,WAAW;AAC3C,SAAO,WAAW,CAAC;AACrB;AAGO,SAAS,aAAa,cAAc,GAAW;AACpD,QAAM,IAAI,oBAAI,KAAK;AACnB,IAAE,SAAS,EAAE;AACb,IAAE,QAAQ,EAAE;AACZ,IAAE,YAAY,EAAE,YAAY,IAAI,WAAW;AAC3C,SAAO,WAAW,CAAC;AACrB;AAcO,SAAS,aAAa,GAAwB;AACnD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM;AACzC,MAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAG,QAAO;AAC3B,MAAI,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,EAAG,QAAO;AACjF,QAAM,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC;AAC/B,MAAI,OAAO,MAAM,GAAG,QAAQ,CAAC,EAAG,QAAO;AACvC,MAAI,GAAG,YAAY,MAAM,KAAK,GAAG,SAAS,MAAM,IAAI,KAAK,GAAG,QAAQ,MAAM,EAAG,QAAO;AACpF,SAAO;AACT;AAOO,SAAS,cAAc,KAAa,QAA4B,SAA8C;AACnH,QAAM,IAAI,aAAa,GAAG;AAC1B,SAAO,IAAI,EAAE,mBAAmB,QAAQ,OAAO,IAAI;AACrD;AAQO,SAAS,WAAW,KAAa,MAAsB;AAC5D,QAAM,IAAI,aAAa,GAAG;AAC1B,MAAI,CAAC,EAAG,QAAO;AACf,IAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI;AAC5B,SAAO,WAAW,CAAC;AACrB;AAQO,SAAS,iBAAiB,GAAS,QAAsB;AAC9D,QAAM,MAAM,EAAE,QAAQ;AACtB,QAAM,MAAM,IAAI,KAAK,EAAE,YAAY,GAAG,EAAE,SAAS,IAAI,QAAQ,CAAC;AAC9D,QAAM,eAAe,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC,EAAE,QAAQ;AAChF,MAAI,QAAQ,KAAK,IAAI,KAAK,YAAY,CAAC;AACvC,SAAO;AACT;AAUO,SAAS,gBAAgB,QAAuD;AACrF,MAAI;AACF,UAAM,MAAM,UAAU,IAAI,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAClE,UAAM,MAAM,IAAI,KAAK,OAAO,GAAG;AAI/B,UAAM,YAAY,IAAI,cAAc,KAAK,IAAI,WAAW;AACxD,QAAI,OAAO,aAAa,SAAU,QAAQ,WAAW;AAAA,EACvD,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGO,SAAS,QAAQ,GAAS,GAAkB;AACjD,SAAO,EAAE,YAAY,MAAM,EAAE,YAAY,KAAK,EAAE,SAAS,MAAM,EAAE,SAAS,KAAK,EAAE,QAAQ,MAAM,EAAE,QAAQ;AAC3G;AAaO,SAAS,mBAAsC;AACpD,QAAM,iBAAgB,oBAAI,KAAK,GAAE,OAAO,IAAI,KAAK;AACjD,SAAO;AAAA,IACL,EAAE,KAAK,SAAS,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE;AAAA,IACjD,EAAE,KAAK,aAAa,MAAM,SAAS,EAAE,GAAG,IAAI,SAAS,EAAE,EAAE;AAAA,IACzD,EAAE,KAAK,aAAa,MAAM,eAAe,GAAG,IAAI,SAAS,EAAE;AAAA,IAC3D,EAAE,KAAK,aAAa,MAAM,SAAS,KAAK,YAAY,GAAG,IAAI,SAAS,KAAK,YAAY,EAAE;AAAA,IACvF,EAAE,KAAK,eAAe,MAAM,SAAS,EAAE,GAAG,IAAI,SAAS,EAAE;AAAA,IACzD,EAAE,KAAK,gBAAgB,MAAM,SAAS,GAAG,GAAG,IAAI,SAAS,EAAE;AAAA,IAC3D,EAAE,KAAK,cAAc,MAAM,gBAAgB,CAAC,GAAG,IAAI,SAAS,EAAE;AAAA,IAC9D,EAAE,KAAK,cAAc,MAAM,gBAAgB,EAAE,GAAG,IAAI,cAAc,EAAE,EAAE;AAAA,IACtE,EAAE,KAAK,iBAAiB,MAAM,SAAS,GAAG,GAAG,IAAI,SAAS,EAAE;AAAA,IAC5D,EAAE,KAAK,OAAO,MAAM,eAAe,CAAC,GAAG,IAAI,SAAS,EAAE;AAAA,IACtD,EAAE,KAAK,aAAa,MAAM,eAAe,EAAE,GAAG,IAAI,aAAa,EAAE,EAAE;AAAA,EACrE;AACF;AAKO,SAAS,oBAAoB,GAAW,MAAY,oBAAI,KAAK,GAAiC;AACnG,QAAM,OAAO,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC;AAE9D,QAAM,KAAK,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,CAAC;AACxD,SAAO,EAAE,MAAM,WAAW,IAAI,GAAG,IAAI,WAAW,EAAE,EAAE;AACtD;AAIO,SAAS,mBAAmB,GAAW,MAAY,oBAAI,KAAK,GAAiC;AAClG,QAAM,OAAO,IAAI,YAAY;AAC7B,SAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,OAAO,CAAC,SAAS;AAC9D;AAyBO,SAAS,qBAAqB,UAAsC,CAAC,GAAsB;AAChG,QAAM,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,MAAM,oBAAI,KAAK,EAAE,IAAI;AAC3D,SAAO;AAAA,IACL,GAAG,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,gBAAgB,GAAG,oBAAoB,GAAG,GAAG,EAAE,EAAE;AAAA,IACvF,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,eAAe,GAAG,mBAAmB,GAAG,GAAG,EAAE,EAAE;AAAA,EACtF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/dates.ts"],"sourcesContent":["/**\n * ISO date helpers, collected from copies that were scattered across the pages.\n *\n * **Every \"what day is it\" helper here reads the LOCAL calendar** — one family, not\n * two. It used to be two: these all built a local Date and then read it back through\n * `toISOString()`, which is UTC, so east of Greenwich they all returned YESTERDAY\n * between local midnight and the UTC rollover. The old module note called that\n * deliberate and warned against changing it. It was not defensible, and dev#471 is\n * what it cost:\n *\n * > *\"Just entered a tx now from scheduled. But it still shows as upcoming. Is there\n * > a problem with timezones? It is currently 1 o clock middle european summer time.\"*\n *\n * There was: at 01:00 CEST `todayIso()` answered with the 14th, the row the scheduler\n * had just booked was dated the 15th, and `isUpcoming` compares the two strings — so a\n * transaction entered a second ago read as one still to come. The same slip moved\n * `startOfMonthIso()` onto the last day of the PREVIOUS month for an hour every first\n * of the month, which is a report range nobody would have questioned.\n *\n * A calendar day only means anything to the human reading it, and every caller here —\n * the register's today, the date-range presets, the budget cursor, a new\n * transaction's default date — is asking that question. There is no caller for whom\n * \"the UTC day\" is the right answer; the server compares plain dates with no zone at\n * all, so sending it the user's local day is also what it wants.\n */\n\n// Imports nothing else: `@eifi1/ui-kit/dates` reaches no package (packaging-contract).\nimport { dateFormatter } from \"./intl-cache\";\n\n/** Zero-pad a number to two digits (\"3\" -> \"03\"). */\nexport function pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** Today as \"YYYY-MM-DD\" on the LOCAL calendar (see the module note). */\nexport function todayIso(): string {\n return toLocalIso(new Date());\n}\n\n/** A Date as a local-time \"YYYY-MM-DD\" string. */\nexport function toLocalIso(d: Date): string {\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n}\n\n/** A Date as a local-time \"YYYY-MM\" month key. */\nexport function monthKey(d: Date): string {\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}`;\n}\n\n// ---------- Date-range presets + calendar helpers ----------\n// Local-calendar like todayIso (see the module note); used by the data-table date\n// filter and its MiniCalendar. Each one mutates a local Date and must therefore READ\n// it back locally — going out through toISOString() is what shifted every one of\n// these by a day near midnight (dev#471).\n\n/** Today shifted by `days`, as \"YYYY-MM-DD\". */\nexport function shiftIso(days: number): string {\n const d = new Date();\n d.setDate(d.getDate() + days);\n return toLocalIso(d);\n}\n\n/** First day (Monday) of the current week, as \"YYYY-MM-DD\". */\nexport function startOfWeekIso(): string {\n const d = new Date();\n const day = d.getDay();\n const diff = (day + 6) % 7; // monday = 0\n d.setDate(d.getDate() - diff);\n return toLocalIso(d);\n}\n\n/** First day of the month `offsetMonths` from now, as \"YYYY-MM-DD\". */\nexport function startOfMonthIso(offsetMonths = 0): string {\n const d = new Date();\n d.setDate(1);\n d.setMonth(d.getMonth() + offsetMonths);\n return toLocalIso(d);\n}\n\n/** Last day of the month `offsetMonths` from now, as \"YYYY-MM-DD\". */\nexport function endOfMonthIso(offsetMonths = 0): string {\n const d = new Date();\n d.setDate(1);\n d.setMonth(d.getMonth() + offsetMonths + 1);\n d.setDate(0);\n return toLocalIso(d);\n}\n\n/** First day of the year `offsetYears` from now, as \"YYYY-MM-DD\". */\nexport function startOfYearIso(offsetYears = 0): string {\n const d = new Date();\n d.setMonth(0);\n d.setDate(1);\n d.setFullYear(d.getFullYear() + offsetYears);\n return toLocalIso(d);\n}\n\n/** Last day of the year `offsetYears` from now, as \"YYYY-MM-DD\". */\nexport function endOfYearIso(offsetYears = 0): string {\n const d = new Date();\n d.setMonth(11);\n d.setDate(31);\n d.setFullYear(d.getFullYear() + offsetYears);\n return toLocalIso(d);\n}\n\n/** Parse a \"YYYY-MM-DD\" string to a local-midnight Date, or null if malformed —\n * where \"malformed\" includes a date that does not exist.\n *\n * The falsy check alone was not enough. `new Date(y, m - 1, d)` ROLLS OVER out-of-range\n * components rather than refusing them, so \"2026-13-45\" came back as 2027-02-14 and\n * \"2026-02-30\" as 2026-03-02: a valid-looking Date for a day that never happened. No\n * caller could tell — {@link formatIsoDate} blanks only on `null`, so the invented\n * date formatted and displayed exactly like a real one.\n *\n * The round-trip is the check: build the Date, then read the components back off it.\n * A value that rolled over cannot answer with the numbers it was given. That is the\n * same shape {@link sameYmd} already expresses, applied to a Date and its source. */\nexport function parseIsoDate(s: string): Date | null {\n if (!s) return null;\n const [y, m, d] = s.split(\"-\").map(Number);\n if (!y || !m || !d) return null;\n if (!Number.isInteger(y) || !Number.isInteger(m) || !Number.isInteger(d)) return null;\n const dt = new Date(y, m - 1, d);\n if (Number.isNaN(dt.getTime())) return null;\n if (dt.getFullYear() !== y || dt.getMonth() !== m - 1 || dt.getDate() !== d) return null;\n return dt;\n}\n\n/** The fields that make an option set a DATE for `toLocaleDateString` (ECMA-402's\n * ToDateTimeOptions, required \"date\"): with none of them it adds year, month and day. */\nconst DATE_FIELDS = [\"weekday\", \"year\", \"month\", \"day\", \"dateStyle\"] as const;\nconst NUMERIC_DATE: Intl.DateTimeFormatOptions = { year: \"numeric\", month: \"numeric\", day: \"numeric\" };\n\n/** `options` as `toLocaleDateString` reads them: with a date in them, whatever else they\n * ask for. `{ hour: \"numeric\" }` alone is a date and an hour there, never the hour alone\n * that `Intl.DateTimeFormat` would print for it. */\nfunction asDateOptions(options: Intl.DateTimeFormatOptions | undefined): Intl.DateTimeFormatOptions {\n if (!options) return NUMERIC_DATE;\n return DATE_FIELDS.some((field) => options[field] !== undefined) ? options : { ...options, ...NUMERIC_DATE };\n}\n\n/** Format a \"YYYY-MM-DD\" string for display in `locale` (empty string when\n * unparseable). Defaults to the locale's short numeric date; pass `options` to\n * override (e.g. `{ dateStyle: \"medium\" }`). `locale` may be `undefined` since 0.34 —\n * the runtime's default, as `Intl` reads it and as every other kit formatter takes it\n * (DUP-11: DatePicker re-wrapped this function only to pass none).\n *\n * Through the kit's formatter cache since 0.54 (keksdose audit follow-up, 2026-11-01):\n * `toLocaleDateString` builds a formatter per call, and this one runs for the date\n * pickers' trigger on every render and for an app's date column once per row. The output\n * is `toLocaleDateString`'s: the same options, with the date it adds when they name none\n * (`asDateOptions`). */\nexport function formatIsoDate(iso: string, locale: string | undefined, options?: Intl.DateTimeFormatOptions): string {\n const d = parseIsoDate(iso);\n return d ? dateFormatter(locale, asDateOptions(options)).format(d) : \"\";\n}\n\n/** A \"YYYY-MM-DD\" string shifted by `days` (negative shifts back), or the input\n * unchanged when it isn't a parseable date.\n *\n * Local-time throughout — {@link parseIsoDate} builds a local-midnight Date and\n * {@link toLocalIso} reads local components back, so this never slides a day the way\n * a `toISOString()` round-trip does west of UTC. */\nexport function addDaysIso(iso: string, days: number): string {\n const d = parseIsoDate(iso);\n if (!d) return iso;\n d.setDate(d.getDate() + days);\n return toLocalIso(d);\n}\n\n/**\n * `d` moved by whole months, keeping the day of the month where the target has one.\n * `setMonth` alone ROLLS OVER — 31 January + 1 month is 3 March — which would skip\n * February entirely for anyone paging through the year with PageDown. Returns a new\n * Date; `d` is not touched.\n */\nexport function addMonthsClamped(d: Date, months: number): Date {\n const day = d.getDate();\n const out = new Date(d.getFullYear(), d.getMonth() + months, 1);\n const lastOfTarget = new Date(out.getFullYear(), out.getMonth() + 1, 0).getDate();\n out.setDate(Math.min(day, lastOfTarget));\n return out;\n}\n\n/**\n * The first day of the week in `locale`, as a `Date#getDay` index (0 = Sunday).\n *\n * `Intl.Locale#getWeekInfo()` is the standard spelling; V8 shipped it first as the\n * `weekInfo` accessor, and Firefox has neither yet — hence both reads and a Monday\n * fallback, which is ISO 8601. Its `firstDay` counts 1 = Monday … 7 = Sunday, so `% 7`\n * maps it onto `getDay`. `undefined` asks for the runtime's default locale.\n */\nexport function localeWeekStart(locale: string | undefined): 0 | 1 | 2 | 3 | 4 | 5 | 6 {\n try {\n const tag = locale ?? new Intl.DateTimeFormat().resolvedOptions().locale;\n const loc = new Intl.Locale(tag) as Intl.Locale & {\n getWeekInfo?: () => { firstDay: number };\n weekInfo?: { firstDay: number };\n };\n const firstDay = (loc.getWeekInfo?.() ?? loc.weekInfo)?.firstDay;\n if (typeof firstDay === \"number\") return (firstDay % 7) as 0 | 1 | 2 | 3 | 4 | 5 | 6;\n } catch {\n // A malformed tag throws from `Intl.Locale`; a calendar still has to render.\n }\n return 1;\n}\n\n/** Whether two Dates fall on the same local calendar day. */\nexport function sameYmd(a: Date, b: Date): boolean {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\nexport interface DateRangePreset {\n key: string;\n from: string;\n to: string;\n}\n\n/**\n * The named ranges offered by the data-table date filter (local-calendar, like\n * {@link todayIso} — see the module note). `key` maps to the consumer's\n * `table.preset_*` labels.\n */\nexport function dateRangePresets(): DateRangePreset[] {\n const mondayOffset = (new Date().getDay() + 6) % 7; // monday = 0\n return [\n { key: \"today\", from: todayIso(), to: todayIso() },\n { key: \"yesterday\", from: shiftIso(-1), to: shiftIso(-1) },\n { key: \"this_week\", from: startOfWeekIso(), to: todayIso() },\n { key: \"last_week\", from: shiftIso(-7 - mondayOffset), to: shiftIso(-1 - mondayOffset) },\n { key: \"last_7_days\", from: shiftIso(-6), to: todayIso() },\n { key: \"last_30_days\", from: shiftIso(-29), to: todayIso() },\n { key: \"this_month\", from: startOfMonthIso(0), to: todayIso() },\n { key: \"last_month\", from: startOfMonthIso(-1), to: endOfMonthIso(-1) },\n { key: \"last_3_months\", from: shiftIso(-90), to: todayIso() },\n { key: \"ytd\", from: startOfYearIso(0), to: todayIso() },\n { key: \"last_year\", from: startOfYearIso(-1), to: endOfYearIso(-1) },\n ];\n}\n\n/** The last `n` WHOLE calendar months before the current one, as an inclusive\n * `{ from, to }` — on 15 May, `n = 3` is 1 February … 30 April. Local-calendar, like\n * everything here; `now` is for tests and for a host with its own clock. */\nexport function lastFullMonthsRange(n: number, now: Date = new Date()): { from: string; to: string } {\n const from = new Date(now.getFullYear(), now.getMonth() - n, 1);\n // Day 0 of the current month is the last day of the previous one.\n const to = new Date(now.getFullYear(), now.getMonth(), 0);\n return { from: toLocalIso(from), to: toLocalIso(to) };\n}\n\n/** The last `n` WHOLE calendar years before the current one — in 2026, `n = 2` is\n * 1 January 2024 … 31 December 2025. */\nexport function lastFullYearsRange(n: number, now: Date = new Date()): { from: string; to: string } {\n const year = now.getFullYear();\n return { from: `${year - n}-01-01`, to: `${year - 1}-12-31` };\n}\n\nexport interface CalendarMonthPresetOptions {\n /** How many whole months each month preset spans. Default `[3, 6]`. */\n months?: readonly number[];\n /** How many whole years each year preset spans. Default `[2]`. */\n years?: readonly number[];\n /** The day to count back from. Default: now, on the local calendar. */\n now?: Date;\n}\n\n/**\n * Month-ALIGNED presets, beside the rolling-day ones of {@link dateRangePresets}.\n *\n * kastlan's accounting reports are closed by the month: \"the last three months\" there\n * means February, March and April, never \"the 90 days up to this morning\", which\n * starts mid-month and ends with a day that is still being booked. `last_3_months`\n * above is the rolling kind and stays that way for the data table's filter, so these\n * are separate keys rather than a changed meaning under an old one.\n *\n * Keys are `last_<n>_full_months` and `last_<n>_full_years`; the host labels them (the\n * same arrangement as `dateRangePresets`' keys and its `table.preset_*` strings). With\n * `DateRangePicker`, pass the key as the preset's `id` so the choice keeps its\n * identity while the dates are recomputed on every render.\n */\nexport function calendarMonthPresets(options: CalendarMonthPresetOptions = {}): DateRangePreset[] {\n const { months = [3, 6], years = [2], now = new Date() } = options;\n return [\n ...months.map((n) => ({ key: `last_${n}_full_months`, ...lastFullMonthsRange(n, now) })),\n ...years.map((n) => ({ key: `last_${n}_full_years`, ...lastFullYearsRange(n, now) })),\n ];\n}\n"],"mappings":"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","names":[]}