@eifi1/ui-kit 0.28.0 → 0.29.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 (166) hide show
  1. package/README.md +22 -4
  2. package/dist/auth/accept-invitation.d.ts +90 -0
  3. package/dist/auth/accept-invitation.js +117 -0
  4. package/dist/auth/accept-invitation.js.map +1 -0
  5. package/dist/auth/auth-errors.d.ts +60 -0
  6. package/dist/auth/auth-errors.js +32 -0
  7. package/dist/auth/auth-errors.js.map +1 -0
  8. package/dist/auth/complete-name-dialog.d.ts +71 -0
  9. package/dist/auth/complete-name-dialog.js +168 -0
  10. package/dist/auth/complete-name-dialog.js.map +1 -0
  11. package/dist/auth/email-tag.d.ts +60 -0
  12. package/dist/auth/email-tag.js +23 -0
  13. package/dist/auth/email-tag.js.map +1 -0
  14. package/dist/auth/forgot-password-form.d.ts +79 -0
  15. package/dist/auth/forgot-password-form.js +120 -0
  16. package/dist/auth/forgot-password-form.js.map +1 -0
  17. package/dist/auth/form-rules.d.ts +27 -0
  18. package/dist/auth/form-rules.js +23 -0
  19. package/dist/auth/form-rules.js.map +1 -0
  20. package/dist/auth/new-password-fields.d.ts +38 -0
  21. package/dist/auth/new-password-fields.js +54 -0
  22. package/dist/auth/new-password-fields.js.map +1 -0
  23. package/dist/auth/not-found-page.d.ts +57 -0
  24. package/dist/auth/not-found-page.js +40 -0
  25. package/dist/auth/not-found-page.js.map +1 -0
  26. package/dist/auth/register-form.d.ts +86 -0
  27. package/dist/auth/register-form.js +268 -0
  28. package/dist/auth/register-form.js.map +1 -0
  29. package/dist/auth/reset-password-form.d.ts +124 -0
  30. package/dist/auth/reset-password-form.js +164 -0
  31. package/dist/auth/reset-password-form.js.map +1 -0
  32. package/dist/auth/sign-in-form.d.ts +243 -0
  33. package/dist/auth/sign-in-form.js +345 -0
  34. package/dist/auth/sign-in-form.js.map +1 -0
  35. package/dist/auth/status-parts.d.ts +78 -0
  36. package/dist/auth/status-parts.js +83 -0
  37. package/dist/auth/status-parts.js.map +1 -0
  38. package/dist/auth/verify-email.d.ts +121 -0
  39. package/dist/auth/verify-email.js +207 -0
  40. package/dist/auth/verify-email.js.map +1 -0
  41. package/dist/chart.d.ts +17 -2
  42. package/dist/components/amount-input.d.ts +18 -2
  43. package/dist/components/button-group.d.ts +18 -2
  44. package/dist/components/calculator.d.ts +18 -2
  45. package/dist/components/confirm-dialog.d.ts +18 -2
  46. package/dist/components/copy-button.d.ts +18 -2
  47. package/dist/components/danger-confirm.d.ts +18 -2
  48. package/dist/components/facing-pair.d.ts +18 -2
  49. package/dist/components/file-button.d.ts +18 -2
  50. package/dist/components/file-dropzone.d.ts +18 -2
  51. package/dist/components/form-actions.d.ts +18 -2
  52. package/dist/components/iban-input.d.ts +18 -2
  53. package/dist/components/language-select.d.ts +18 -9
  54. package/dist/components/legal-page.d.ts +26 -4
  55. package/dist/components/legal-page.js +24 -5
  56. package/dist/components/legal-page.js.map +1 -1
  57. package/dist/components/legal.d.ts +18 -2
  58. package/dist/components/legal.js +49 -5
  59. package/dist/components/legal.js.map +1 -1
  60. package/dist/components/money-field.d.ts +18 -2
  61. package/dist/components/number-field.d.ts +18 -2
  62. package/dist/components/number-input.d.ts +18 -2
  63. package/dist/components/numpad-sheet.d.ts +18 -2
  64. package/dist/components/phone-input.d.ts +18 -2
  65. package/dist/components/series-chart.d.ts +18 -2
  66. package/dist/components/settings-fields.d.ts +15 -2
  67. package/dist/components/share-card.d.ts +18 -2
  68. package/dist/components/text-link.d.ts +18 -2
  69. package/dist/components/time-input.d.ts +18 -2
  70. package/dist/components/ui.d.ts +17 -1
  71. package/dist/components/user-avatar.d.ts +16 -2
  72. package/dist/components/user-avatar.js +7 -3
  73. package/dist/components/user-avatar.js.map +1 -1
  74. package/dist/feedback/feedback-attachment.d.ts +18 -2
  75. package/dist/feedback/feedback-context.d.ts +18 -2
  76. package/dist/feedback/feedback-crash.d.ts +18 -2
  77. package/dist/feedback/feedback-dialog.d.ts +18 -2
  78. package/dist/feedback/feedback-inbox.d.ts +18 -2
  79. package/dist/feedback/feedback-labels.d.ts +18 -2
  80. package/dist/feedback/feedback-menu.d.ts +18 -2
  81. package/dist/feedback/feedback-record.d.ts +18 -2
  82. package/dist/feedback/feedback-row-detail.d.ts +18 -2
  83. package/dist/feedback/feedback-status-undo.d.ts +18 -2
  84. package/dist/feedback/feedback-submit.d.ts +18 -2
  85. package/dist/feedback/feedback-swipe.d.ts +18 -2
  86. package/dist/feedback/feedback-table.d.ts +18 -2
  87. package/dist/feedback/feedback-thread.d.ts +18 -2
  88. package/dist/feedback.d.ts +18 -2
  89. package/dist/hooks/use-file-drop.d.ts +18 -2
  90. package/dist/i18n/defaults.d.ts +18 -2
  91. package/dist/i18n/defaults.js +18 -0
  92. package/dist/i18n/defaults.js.map +1 -1
  93. package/dist/i18n/german.d.ts +18 -2
  94. package/dist/i18n/german.js +145 -0
  95. package/dist/i18n/german.js.map +1 -1
  96. package/dist/i18n/kit-labels.d.ts +18 -2
  97. package/dist/i18n/kit-labels.js.map +1 -1
  98. package/dist/i18n/languages.d.ts +13 -201
  99. package/dist/i18n/locales/de-CH.d.ts +18 -2
  100. package/dist/i18n/locales/en.d.ts +18 -2
  101. package/dist/i18n/locales/es.d.ts +18 -2
  102. package/dist/i18n/locales/es.js +147 -3
  103. package/dist/i18n/locales/es.js.map +1 -1
  104. package/dist/i18n/locales/fr.d.ts +18 -2
  105. package/dist/i18n/locales/fr.js +147 -0
  106. package/dist/i18n/locales/fr.js.map +1 -1
  107. package/dist/i18n/locales/hu.d.ts +18 -2
  108. package/dist/i18n/locales/hu.js +149 -3
  109. package/dist/i18n/locales/hu.js.map +1 -1
  110. package/dist/i18n/locales/it.d.ts +18 -2
  111. package/dist/i18n/locales/it.js +146 -1
  112. package/dist/i18n/locales/it.js.map +1 -1
  113. package/dist/i18n/locales/zh.d.ts +18 -2
  114. package/dist/i18n/locales/zh.js +146 -1
  115. package/dist/i18n/locales/zh.js.map +1 -1
  116. package/dist/i18n/review.d.ts +18 -2
  117. package/dist/i18n/review.js +17 -7
  118. package/dist/i18n/review.js.map +1 -1
  119. package/dist/index.d.ts +13 -2
  120. package/dist/index.js +49 -1
  121. package/dist/index.js.map +1 -1
  122. package/dist/lib/person-name.d.ts +69 -0
  123. package/dist/lib/person-name.js +65 -0
  124. package/dist/lib/person-name.js.map +1 -0
  125. package/dist/{kit-labels-SBN0biPl.d.ts → register-form-V1OeNlMr.d.ts} +423 -6
  126. package/dist/rhf/fields.d.ts +18 -2
  127. package/dist/rhf/form.d.ts +18 -2
  128. package/dist/rhf.d.ts +18 -2
  129. package/dist/shell/app-shell.d.ts +18 -2
  130. package/dist/shell/company-switcher.d.ts +59 -0
  131. package/dist/shell/company-switcher.js +85 -0
  132. package/dist/shell/company-switcher.js.map +1 -0
  133. package/dist/shell/top-bar-brand.d.ts +18 -2
  134. package/dist/shell/topbar-action-menu.d.ts +1 -0
  135. package/dist/shell.d.ts +12 -2
  136. package/dist/wizard/stepper-nav.d.ts +18 -2
  137. package/dist/wizard.d.ts +18 -2
  138. package/package.json +1 -1
  139. package/src/auth/accept-invitation.tsx +227 -0
  140. package/src/auth/auth-errors.ts +105 -0
  141. package/src/auth/complete-name-dialog.tsx +253 -0
  142. package/src/auth/email-tag.ts +75 -0
  143. package/src/auth/forgot-password-form.tsx +213 -0
  144. package/src/auth/form-rules.ts +40 -0
  145. package/src/auth/new-password-fields.tsx +85 -0
  146. package/src/auth/not-found-page.tsx +98 -0
  147. package/src/auth/register-form.tsx +459 -0
  148. package/src/auth/reset-password-form.tsx +337 -0
  149. package/src/auth/sign-in-form.tsx +687 -0
  150. package/src/auth/status-parts.tsx +138 -0
  151. package/src/auth/verify-email.tsx +358 -0
  152. package/src/components/legal-page.tsx +35 -0
  153. package/src/components/legal.tsx +93 -7
  154. package/src/components/user-avatar.tsx +22 -4
  155. package/src/i18n/defaults.ts +18 -0
  156. package/src/i18n/german.ts +153 -0
  157. package/src/i18n/kit-labels.tsx +27 -0
  158. package/src/i18n/locales/es.ts +156 -3
  159. package/src/i18n/locales/fr.ts +157 -0
  160. package/src/i18n/locales/hu.ts +159 -3
  161. package/src/i18n/locales/it.ts +154 -1
  162. package/src/i18n/locales/zh.ts +149 -1
  163. package/src/i18n/review.ts +15 -6
  164. package/src/index.ts +63 -1
  165. package/src/lib/person-name.ts +157 -0
  166. package/src/shell/company-switcher.tsx +140 -0
@@ -0,0 +1,140 @@
1
+ import { useState } from "react";
2
+ import type { ReactNode } from "react";
3
+ import { Building2 } from "lucide-react";
4
+ import { cn } from "../lib/cn";
5
+ import { useKitLabels } from "../i18n/kit-labels";
6
+ import { useAnnounce } from "../hooks/use-announce";
7
+ import { Spinner } from "../components/ui";
8
+ import { OptionSwitcherMenu } from "./option-switcher-menu";
9
+ import { TOPBAR_TRIGGER_CLASS } from "./topbar-controls";
10
+
11
+ /** Every string the switcher renders or speaks — the `companySwitcher` namespace. A
12
+ * different context (keksdose's budgets) renames them all. */
13
+ export interface CompanySwitcherLabels {
14
+ /** The trigger's and the menu's accessible name. */
15
+ switchCompany: string;
16
+ /** The small heading over the list. */
17
+ heading: string;
18
+ /** The trigger's tooltip (and description), given the current company's name. */
19
+ current: (name: string) => string;
20
+ /** Read after the current company's name in the list, where the eye sees a check. */
21
+ currentMark: string;
22
+ /** Said while a switch is running. */
23
+ switching: string;
24
+ }
25
+
26
+ export const DEFAULT_COMPANY_SWITCHER_LABELS: CompanySwitcherLabels = {
27
+ switchCompany: "Switch company",
28
+ heading: "Companies",
29
+ current: (name) => `Company: ${name}`,
30
+ currentMark: "(current)",
31
+ switching: "Switching company…",
32
+ };
33
+
34
+ /** One company the user belongs to — kastlan's `/auth/me` `companies[]` (§5.3). */
35
+ export interface CompanySwitcherCompany<Id extends string | number = string | number> {
36
+ /** kastlan's ids are numbers; a string works the same. */
37
+ id: Id;
38
+ name: string;
39
+ }
40
+
41
+ export interface CompanySwitcherProps<Id extends string | number> {
42
+ /** Every company the user belongs to. With fewer than two there is nothing to
43
+ * switch, and nothing renders. */
44
+ companies: readonly CompanySwitcherCompany<Id>[];
45
+ /** The company the session is in — `/auth/me`'s `current_company_id`. */
46
+ currentId: Id;
47
+ /**
48
+ * Another company was picked: `POST /auth/switch-company {company_id}`, store the
49
+ * fresh tokens, reload what is company-scoped. While the promise runs the switcher is
50
+ * disabled, so a second pick cannot race the first; a rejection frees it (the app
51
+ * says why). Picking the current company does nothing.
52
+ */
53
+ onSwitch: (id: Id) => Promise<unknown> | void;
54
+ /** The trigger's glyph. Default a building; keksdose's budgets would pass a wallet. */
55
+ icon?: ReactNode;
56
+ labels?: Partial<CompanySwitcherLabels>;
57
+ }
58
+
59
+ /**
60
+ * The company switcher in the top bar (docs/auth-harmonization.md §5.3, §8): a kastlan
61
+ * user may belong to several companies, and the access token carries the current one,
62
+ * so switching is a request for new tokens — `onSwitch`, the app's. Built on
63
+ * {@link OptionSwitcherMenu}, like `RoleSwitcher`: the icon trigger, the current company
64
+ * in its tooltip, the list with a check on the current one.
65
+ *
66
+ * **Only for more than one company** — a user in one company has nothing to switch, and
67
+ * the top bar stays as it was. **Disabled while a switch runs**: the trigger is swapped
68
+ * for a disabled one with a spinner (`aria-busy`), and "Switching company…" is said, so
69
+ * a second pick cannot race the first. The kit never sends the request.
70
+ *
71
+ * A generic context switcher: the labels rename it ("Switch budget", "Budgets"), `icon`
72
+ * replaces the building, and `id` may be a number (kastlan's) or a string.
73
+ */
74
+ export function CompanySwitcher<Id extends string | number>({
75
+ companies,
76
+ currentId,
77
+ onSwitch,
78
+ icon,
79
+ labels: labelsProp,
80
+ }: CompanySwitcherProps<Id>) {
81
+ const labels = useKitLabels("companySwitcher", DEFAULT_COMPANY_SWITCHER_LABELS, labelsProp);
82
+ const [pending, setPending] = useState(false);
83
+ const { announce, regionProps } = useAnnounce();
84
+ if (companies.length < 2) return null;
85
+
86
+ const current = companies.find((c) => c.id === currentId);
87
+ const select = (value: string) => {
88
+ if (pending) return;
89
+ const picked = companies.find((c) => String(c.id) === value);
90
+ if (!picked || picked.id === currentId) return;
91
+ const result = onSwitch(picked.id);
92
+ if (typeof (result as PromiseLike<unknown> | undefined)?.then !== "function") return;
93
+ setPending(true);
94
+ announce(labels.switching);
95
+ (result as PromiseLike<unknown>).then(
96
+ () => setPending(false),
97
+ () => setPending(false),
98
+ );
99
+ };
100
+
101
+ return (
102
+ <>
103
+ {pending ? (
104
+ <button
105
+ type="button"
106
+ disabled
107
+ aria-busy="true"
108
+ aria-label={labels.switchCompany}
109
+ className={cn(TOPBAR_TRIGGER_CLASS, "cursor-wait opacity-60 hover:bg-transparent")}
110
+ >
111
+ <Spinner label={null} />
112
+ </button>
113
+ ) : (
114
+ <OptionSwitcherMenu<string>
115
+ ariaLabel={labels.switchCompany}
116
+ title={current ? labels.current(current.name) : undefined}
117
+ heading={labels.heading}
118
+ icon={icon ?? <Building2 className="size-5" />}
119
+ options={companies.map((c) => ({
120
+ value: String(c.id),
121
+ label:
122
+ c.id === currentId ? (
123
+ // `relative`: the sr-only mark needs a local containing block.
124
+ <span className="relative">
125
+ {c.name}
126
+ <span className="sr-only"> {labels.currentMark}</span>
127
+ </span>
128
+ ) : (
129
+ c.name
130
+ ),
131
+ }))}
132
+ value={String(currentId)}
133
+ onSelect={select}
134
+ />
135
+ )}
136
+ {/* Outside both triggers, so it survives the swap and is read when it changes. */}
137
+ <span {...regionProps} />
138
+ </>
139
+ );
140
+ }