@eifi1/ui-kit 0.40.1 → 0.41.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 (38) hide show
  1. package/dist/components/nav-pills.d.ts +2 -2
  2. package/dist/components/nav-pills.js.map +1 -1
  3. package/dist/components/tabs.d.ts +4 -32
  4. package/dist/components/tabs.js +30 -66
  5. package/dist/components/tabs.js.map +1 -1
  6. package/dist/components/translation-review-parts.d.ts +2 -2
  7. package/dist/components/translation-review-parts.js.map +1 -1
  8. package/dist/eslint/index.js +1 -1
  9. package/dist/feedback/feedback-menu-labels.js +0 -2
  10. package/dist/feedback/feedback-menu-labels.js.map +1 -1
  11. package/dist/feedback/feedback-menu.d.ts +0 -6
  12. package/dist/feedback/feedback-menu.js.map +1 -1
  13. package/dist/i18n/german.js +0 -2
  14. package/dist/i18n/german.js.map +1 -1
  15. package/dist/i18n/locales/en.js +0 -2
  16. package/dist/i18n/locales/en.js.map +2 -2
  17. package/dist/i18n/locales/es.js +0 -2
  18. package/dist/i18n/locales/es.js.map +1 -1
  19. package/dist/i18n/locales/fr.js +0 -2
  20. package/dist/i18n/locales/fr.js.map +1 -1
  21. package/dist/i18n/locales/hu.js +0 -2
  22. package/dist/i18n/locales/hu.js.map +1 -1
  23. package/dist/i18n/locales/it.js +0 -2
  24. package/dist/i18n/locales/it.js.map +1 -1
  25. package/dist/i18n/locales/zh.js +0 -2
  26. package/dist/i18n/locales/zh.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/nav-pills.tsx +2 -2
  29. package/src/components/tabs.tsx +19 -110
  30. package/src/components/translation-review-parts.tsx +2 -2
  31. package/src/feedback/feedback-menu-labels.ts +0 -2
  32. package/src/feedback/feedback-menu.tsx +0 -6
  33. package/src/i18n/german.ts +0 -2
  34. package/src/i18n/locales/es.ts +0 -2
  35. package/src/i18n/locales/fr.ts +0 -2
  36. package/src/i18n/locales/hu.ts +0 -2
  37. package/src/i18n/locales/it.ts +0 -2
  38. package/src/i18n/locales/zh.ts +0 -2
@@ -77,34 +77,6 @@ export interface TabsProps<T extends string>
77
77
  active: T;
78
78
  onChange: (id: T) => void;
79
79
  className?: string;
80
- /** Let the strip WRAP onto as many rows as it needs below `md`, instead of
81
- * scrolling sideways — for a strip carrying more tabs than fit on a phone row.
82
- * Keksdose live #262: ten reports on a 406px screen showed about three, and the
83
- * round-2 answer (a <select> below `md`) cost a tap to open and a tap to choose.
84
- * *"I would rather keep the tabs but have multirow tabs depending on the screen
85
- * size, I will not loose the function to see all reports at once and navigate by
86
- * single click rather by double click."*
87
- *
88
- * The active MARKER has to change with the layout, which is why this cannot be
89
- * done from a call site with a `className`: the default marker is a `border-b-2`
90
- * underline riding the container's own bottom rule, and a tab sitting in a row
91
- * that does not touch that rule cannot wear it — every row but the last would
92
- * show a stray line floating mid-strip, and `-mb-px` would pull each chip a
93
- * pixel into the row beneath it. A wrapped strip marks the active tab with a
94
- * filled brand chip instead, which is also the only thing findable at a glance
95
- * among ten same-weight labels on three rows.
96
- *
97
- * From `md` up NOTHING changes: same single-line underline strip, same paddings,
98
- * same colours as every other strip in the app.
99
- *
100
- * Opt-in on purpose. The three-tab strips (invoices, statements, bank imports)
101
- * already fit a phone row, and turning those into chips would be an unrequested
102
- * redesign of three other pages.
103
- *
104
- * @deprecated 0.40 — use the scrolling strip with `overflowCue`; removed in 0.41. No
105
- * consumer is left (keksdose went back to one scrolling row, live #410); the caret
106
- * says a phone's row goes on. */
107
- wrap?: boolean;
108
80
  /**
109
81
  * The caret beside a SCROLLING strip below `md` (0.40, kk run 79 gap 1): a › while
110
82
  * tabs lie past the strip's end — a tap scrolls it on by three quarters of its width —
@@ -117,7 +89,7 @@ export interface TabsProps<T extends string>
117
89
  * turns round rather than two that come and go, so the strip's width never changes
118
90
  * under the thumb. Out of the tab order — the keyboard walks the strip with the arrow
119
91
  * keys, which bring the focused tab into view. From `md` up nothing changes. Ignored on
120
- * a `wrap` strip and a vertical one (a side nav is a column, not a row). Names:
92
+ * a vertical strip (a side nav is a column, not a row). Names:
121
93
  * `tabs.more` / `tabs.backToFirst`.
122
94
  */
123
95
  overflowCue?: boolean;
@@ -203,8 +175,8 @@ export interface TabsProps<T extends string>
203
175
  * `onRemove`, `onAdd` — means exactly what it means on the horizontal strip; the
204
176
  * badge moves to the row's end.
205
177
  *
206
- * **On a phone (`usePhoneLayout()`) it becomes the horizontal strip**, `wrap` and
207
- * all, rather than staying a column. A side nav only works beside its content; on
178
+ * **On a phone (`usePhoneLayout()`) it becomes the horizontal strip**, rather than
179
+ * staying a column. A side nav only works beside its content; on
208
180
  * a phone it has to go ABOVE it, and eight full-width rows there push the panel
209
181
  * the user picked below the fold on every visit — the two keksdose pages both
210
182
  * collapsed theirs into a scrolling row by hand for exactly that reason. The
@@ -220,14 +192,6 @@ export interface TabsProps<T extends string>
220
192
  ref?: Ref<HTMLDivElement>;
221
193
  }
222
194
 
223
- // The two shapes are written out as whole strings rather than as one base plus a
224
- // pile of `md:` overrides. The unwrapped pair is character-for-character what the
225
- // three strips that do not opt in get, so those cannot drift; the wrapped pair is
226
- // authored from scratch, so no unprefixed utility has to be beaten by its own `md:`
227
- // twin through tailwind-merge. The only ordering this relies on is Tailwind's own:
228
- // unprefixed utilities are emitted first, then `md:` — so from 768px up the wrapped
229
- // strip resolves to exactly the paint of the default one. Both themes come free now
230
- // that the colours are tokens: there is no `md:dark:` tier left to keep in step.
231
195
  const TABLIST_CLASSES =
232
196
  "flex gap-1 overflow-x-auto overflow-y-hidden border-b border-subtle";
233
197
  // The side nav. A column of full-width rows with the open one FILLED rather than
@@ -242,9 +206,6 @@ const TAB_VERTICAL_ACTIVE_CLASSES = "bg-active text-primary";
242
206
  const TAB_VERTICAL_INACTIVE_CLASSES =
243
207
  "text-muted hover:bg-hover hover:text-primary";
244
208
 
245
- const TABLIST_WRAP_CLASSES =
246
- "flex flex-wrap gap-1.5 md:flex-nowrap md:gap-1 md:overflow-x-auto md:overflow-y-hidden md:border-b md:border-subtle";
247
-
248
209
  // `max-w-full`: no tab outgrows its strip. A sheet's `detail` line ("Spurstangenkraft
249
210
  // links · … · 31 Punkte") made one tab 448px wide in a 390px strip, and a tab wider
250
211
  // than the strip cannot be scrolled into view — its end was simply off screen
@@ -256,31 +217,13 @@ const TAB_ACTIVE_CLASSES = "border-[var(--text-primary)] text-primary";
256
217
  const TAB_INACTIVE_CLASSES =
257
218
  "border-transparent text-muted hover:text-secondary hover:border-strong";
258
219
 
259
- // Below `md`, a chip: `py-2` on `text-xs` is exactly 32px tall, and ten German
260
- // report labels then land in three rows on a 406px screen (four at `text-sm`). The
261
- // active fill is the app's own selected pair, `--brand` / `--brand-contrast`: the
262
- // palette store writes both halves of it together for every preset and both themes,
263
- // so the contrast holds everywhere (5.1:1 at its worst preset) without a hard-coded
264
- // colour. Inactive chips take the raised card surface with full-strength body text —
265
- // all ten have to stay readable; it is the FILL, not the text weight, that says
266
- // which one is open.
267
- const TAB_WRAP_CLASSES =
268
- FOCUS_RING_WIDTH +
269
- " max-w-full whitespace-nowrap rounded-md px-2.5 py-2 text-xs font-medium transition-colors focus:outline-none focus-visible:ring-strong md:rounded-none md:border-b-2 md:-mb-px md:bg-transparent md:px-3 md:py-2 md:text-sm";
270
- const TAB_WRAP_ACTIVE_CLASSES =
271
- "bg-brand text-brand-contrast md:border-[var(--text-primary)] md:text-primary";
272
- const TAB_WRAP_INACTIVE_CLASSES =
273
- "bg-surface text-primary md:border-transparent md:text-muted md:hover:border-strong md:hover:text-secondary";
274
-
275
220
  // The add/remove chrome. The × reserves its gutter on every removable tab (see
276
- // `onRemove`); `md:pe-8` is spelled out because the wrapped chip's `md:px-3` would
277
- // otherwise hand the gutter back from 768px up.
278
- const TAB_REMOVABLE_CLASSES = "pe-8 md:pe-8";
221
+ // `onRemove`).
222
+ const TAB_REMOVABLE_CLASSES = "pe-8";
279
223
  const TAB_EMPTY_CLASSES = "-mx-1.5 rounded border border-dashed border-strong px-1.5";
280
224
  const TAB_ADD_CLASSES =
281
225
  FOCUS_RING_WIDTH +
282
226
  " inline-flex items-center gap-1 whitespace-nowrap rounded-md px-3 py-2 text-sm font-medium text-muted transition-colors hover:text-primary focus:outline-none focus-visible:ring-strong disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4";
283
- const TAB_ADD_WRAP_CLASSES = "px-2.5 text-xs md:px-3 md:text-sm";
284
227
  // `relative`: the phone's visually hidden label needs a positioned ancestor (see the
285
228
  // sr-only rule in CONTRIBUTING); `max-md:px-2` squares the lone "+".
286
229
  const TAB_ADD_PHONE_CLASSES = "relative max-md:px-2";
@@ -290,7 +233,6 @@ export function Tabs<T extends string>({
290
233
  active,
291
234
  onChange,
292
235
  className,
293
- wrap = false,
294
236
  overflowCue = false,
295
237
  panelId,
296
238
  onRemove,
@@ -312,7 +254,7 @@ export function Tabs<T extends string>({
312
254
  const setStrip = useMemo(() => mergeRefs(stripRef, ref), [ref]);
313
255
  const fade = useStripFade(stripRef);
314
256
  // See `overflowCue`. `start` alone means the strip is scrolled to its end.
315
- const cue = overflowCue && !wrap && !vertical && fade.overflow !== undefined;
257
+ const cue = overflowCue && !vertical && fade.overflow !== undefined;
316
258
  const cueAtEnd = fade.overflow === "start";
317
259
  const onCue = () => {
318
260
  const strip = stripRef.current;
@@ -394,9 +336,7 @@ export function Tabs<T extends string>({
394
336
  strip.querySelectorAll<HTMLElement>('[role="tab"]')[index]?.focus();
395
337
  }, [tabs, active]);
396
338
 
397
- // Arrow keys walk the strip in DOM order (ARIA tabs pattern), which is what keeps
398
- // a WRAPPED strip navigable: the rows flow in DOM order too, so Right off the end
399
- // of row one lands on the first chip of row two rather than nowhere. Home/End jump
339
+ // Arrow keys walk the strip in DOM order (ARIA tabs pattern). Home/End jump
400
340
  // to the ends. Focus only — activation stays on click/Enter/Space, because a tab
401
341
  // here can be a real route and moving focus must not navigate.
402
342
  //
@@ -465,8 +405,8 @@ export function Tabs<T extends string>({
465
405
  // With an add button the strip gains an outer box, and `className` goes there
466
406
  // — it is the box a caller's margin or width is meant for.
467
407
  className={cn(
468
- vertical ? TABLIST_VERTICAL_CLASSES : wrap ? TABLIST_WRAP_CLASSES : TABLIST_CLASSES,
469
- onAdd ? "min-w-0" : overflowCue && !wrap && !vertical ? "min-w-0 flex-1" : className,
408
+ vertical ? TABLIST_VERTICAL_CLASSES : TABLIST_CLASSES,
409
+ onAdd ? "min-w-0" : overflowCue && !vertical ? "min-w-0 flex-1" : className,
470
410
  )}
471
411
  >
472
412
  {tabs.map((tab) => {
@@ -502,14 +442,8 @@ export function Tabs<T extends string>({
502
442
  removable && "pe-8",
503
443
  )
504
444
  : cn(
505
- wrap ? TAB_WRAP_CLASSES : TAB_CLASSES,
506
- wrap
507
- ? isActive
508
- ? TAB_WRAP_ACTIVE_CLASSES
509
- : TAB_WRAP_INACTIVE_CLASSES
510
- : isActive
511
- ? TAB_ACTIVE_CLASSES
512
- : TAB_INACTIVE_CLASSES,
445
+ TAB_CLASSES,
446
+ isActive ? TAB_ACTIVE_CLASSES : TAB_INACTIVE_CLASSES,
513
447
  removable && TAB_REMOVABLE_CLASSES,
514
448
  ),
515
449
  };
@@ -537,16 +471,7 @@ export function Tabs<T extends string>({
537
471
  {/* A separator for the NAME only — whitespace between flex items is
538
472
  not drawn, and without it the two lines ran together into one
539
473
  word for a screen reader ("80 km/hloop 2"). */}{" "}
540
- <span
541
- className={cn(
542
- "max-w-full truncate-until-large text-caption font-normal leading-tight text-muted",
543
- // On a wrapped strip's filled chip (below `md`) the muted grey
544
- // was dark text on the brand fill — "loop 2" all but vanished
545
- // under the one label that most needed reading. It takes the
546
- // chip's own ink instead, as the label and the × already do.
547
- wrap && isActive && !vertical && "text-brand-contrast md:text-muted",
548
- )}
549
- >
474
+ <span className="max-w-full truncate-until-large text-caption font-normal leading-tight text-muted">
550
475
  {tab.detail}
551
476
  </span>
552
477
  </span>
@@ -620,12 +545,7 @@ export function Tabs<T extends string>({
620
545
  type="button"
621
546
  disabled={busy}
622
547
  onClick={() => requestRemove(tab.id)}
623
- className={cn(
624
- "absolute inset-y-0 end-1 my-auto",
625
- // On a wrapped strip's filled chip the quiet grey would vanish into
626
- // the brand fill below `md`.
627
- wrap && "text-brand-contrast md:text-placeholder",
628
- )}
548
+ className="absolute inset-y-0 end-1 my-auto"
629
549
  >
630
550
  <X />
631
551
  </IconButton>
@@ -654,7 +574,7 @@ export function Tabs<T extends string>({
654
574
  {text.remove(nameOf(activeTab))}
655
575
  </button>
656
576
  ) : null;
657
- if (!onAdd && overflowCue && !wrap && !vertical) {
577
+ if (!onAdd && overflowCue && !vertical) {
658
578
  // The caret needs a row to sit in beside the strip, and `className` goes there — it
659
579
  // is the box a caller's margin or width is meant for, as with an add button. The box
660
580
  // is there whether or not the strip overflows right now, so a resize never moves
@@ -692,37 +612,26 @@ export function Tabs<T extends string>({
692
612
  );
693
613
  }
694
614
  return (
695
- <div
696
- className={cn(
697
- wrap ? "flex flex-wrap items-end gap-1.5 md:flex-nowrap md:gap-0" : "flex items-end",
698
- className,
699
- )}
700
- >
615
+ <div className={cn("flex items-end", className)}>
701
616
  {tablist}
702
617
  {removeButton}
703
618
  {cueButton}
704
619
  {/* Outside the tablist: an action, not a tab — and a tablist may own only
705
620
  tabs. The rule under the strip carries on beneath it. */}
706
621
  <div
707
- className={cn(
708
- "flex flex-1 items-center",
709
- wrap
710
- ? "md:self-stretch md:border-b md:border-subtle"
711
- : "self-stretch border-b border-subtle",
712
- )}
622
+ className="flex flex-1 items-center self-stretch border-b border-subtle"
713
623
  >
714
624
  <button
715
625
  type="button"
716
626
  onClick={onAdd}
717
627
  disabled={busy}
718
- className={cn(TAB_ADD_CLASSES, wrap ? TAB_ADD_WRAP_CLASSES : TAB_ADD_PHONE_CLASSES)}
628
+ className={cn(TAB_ADD_CLASSES, TAB_ADD_PHONE_CLASSES)}
719
629
  >
720
630
  <Plus aria-hidden />
721
631
  {/* Below md a scrolling strip keeps the room for tabs: the label is visually
722
632
  hidden and the "+" carries it as its name. Beside "+ Add loop" a 390px strip
723
- showed the open tab and a sliver of the next (showcase audit). A wrapping
724
- strip has its own row there, so it keeps the label. */}
725
- <span className={wrap ? undefined : "max-md:sr-only"}>{addLabel ?? text.add}</span>
633
+ showed the open tab and a sliver of the next (showcase audit). */}
634
+ <span className="max-md:sr-only">{addLabel ?? text.add}</span>
726
635
  </button>
727
636
  </div>
728
637
  </div>
@@ -170,8 +170,8 @@ export interface TranslationLocaleTabsProps {
170
170
 
171
171
  /**
172
172
  * One tab per locale with its approved/total, one scrolling row on a phone with the
173
- * strip's caret saying it goes on (`overflowCue`; `wrap` is deprecated in 0.40). Nothing for a single
174
- * locale: a strip with one tab is a heading that looks clickable.
173
+ * strip's caret saying it goes on (`overflowCue`). Nothing for a single locale:
174
+ * a strip with one tab is a heading that looks clickable.
175
175
  */
176
176
  export function TranslationLocaleTabs({ locales, active, onChange, className, labels: labelsProp }: TranslationLocaleTabsProps) {
177
177
  const labels = useKitLabels("translationReview", DEFAULT_TRANSLATION_REVIEW_LABELS, labelsProp);
@@ -7,8 +7,6 @@ import type { FeedbackMenuLabels } from "./feedback-menu";
7
7
  export const DEFAULT_FEEDBACK_MENU_LABELS: FeedbackMenuLabels = {
8
8
  trigger: "Send feedback",
9
9
  myFeedback: "My feedback",
10
- viewFeedback: "View feedback",
11
- allFeedback: "All feedback",
12
10
  discussion: "Feedback discussion",
13
11
  inbox: "Feedback inbox",
14
12
  };
@@ -28,12 +28,6 @@ export interface FeedbackMenuLabels {
28
28
  /** 0.40: the admin's link to the triage list, {@link FeedbackMenuProps.inboxHref}
29
29
  * ("View feedback" before). de-CH "Feedback-Eingang". */
30
30
  inbox: string;
31
- /** @deprecated 0.40 — use {@link inbox}; removed in 0.41. Unused: the inbox row reads
32
- * `inbox` (feedback §10.6). */
33
- viewFeedback?: string;
34
- /** @deprecated 0.40 — use {@link discussion}; removed in 0.41. Unused: the public row
35
- * reads `discussion` (feedback §10.6). */
36
- allFeedback?: string;
37
31
  }
38
32
 
39
33
  // Defined in ./feedback-menu-labels, which holds no component code (0.34, KS U8).
@@ -121,8 +121,6 @@ export function germanLabels(numberLocale: string): UiKitLabels {
121
121
  feedbackMenu: {
122
122
  trigger: "Feedback senden",
123
123
  myFeedback: "Mein Feedback",
124
- viewFeedback: "Feedback ansehen",
125
- allFeedback: "Alle Rückmeldungen",
126
124
  discussion: "Feedback-Diskussion",
127
125
  inbox: "Feedback-Eingang",
128
126
  },
@@ -112,8 +112,6 @@ export function uiKitLabelsEs(numberLocale = "es-ES"): UiKitLabels {
112
112
  feedbackMenu: {
113
113
  trigger: "Enviar comentarios",
114
114
  myFeedback: "Mis comentarios",
115
- viewFeedback: "Ver comentarios",
116
- allFeedback: "Todos los comentarios",
117
115
  discussion: "Debate de comentarios",
118
116
  inbox: "Comentarios recibidos",
119
117
  },
@@ -110,8 +110,6 @@ export function uiKitLabelsFr(numberLocale = "fr-FR"): UiKitLabels {
110
110
  feedbackMenu: {
111
111
  trigger: "Envoyer un retour",
112
112
  myFeedback: "Mes retours",
113
- viewFeedback: "Voir les retours",
114
- allFeedback: "Tous les retours",
115
113
  discussion: "Discussion des retours",
116
114
  inbox: "Retours reçus",
117
115
  },
@@ -109,8 +109,6 @@ export function uiKitLabelsHu(numberLocale = "hu-HU"): UiKitLabels {
109
109
  feedbackMenu: {
110
110
  trigger: "Visszajelzés küldése",
111
111
  myFeedback: "Visszajelzéseim",
112
- viewFeedback: "Visszajelzések megtekintése",
113
- allFeedback: "Összes visszajelzés",
114
112
  discussion: "Visszajelzések megvitatása",
115
113
  inbox: "Beérkezett visszajelzések",
116
114
  },
@@ -112,8 +112,6 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
112
112
  feedbackMenu: {
113
113
  trigger: "Invia feedback",
114
114
  myFeedback: "I miei feedback",
115
- viewFeedback: "Visualizza feedback",
116
- allFeedback: "Tutti i feedback",
117
115
  discussion: "Discussione sui feedback",
118
116
  inbox: "Feedback ricevuti",
119
117
  },
@@ -102,8 +102,6 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
102
102
  feedbackMenu: {
103
103
  trigger: "发送反馈",
104
104
  myFeedback: "我的反馈",
105
- viewFeedback: "查看反馈",
106
- allFeedback: "全部反馈",
107
105
  discussion: "反馈讨论",
108
106
  inbox: "反馈收件箱",
109
107
  },