@eifi1/ui-kit 0.24.0 → 0.25.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 (148) hide show
  1. package/README.md +6 -6
  2. package/dist/chart.d.ts +2 -2
  3. package/dist/components/account-chips.d.ts +1 -1
  4. package/dist/components/amount-input.d.ts +2 -2
  5. package/dist/components/button-group.d.ts +2 -2
  6. package/dist/components/calculator.d.ts +2 -2
  7. package/dist/components/column-mapper.d.ts +28 -9
  8. package/dist/components/column-mapper.js +63 -77
  9. package/dist/components/column-mapper.js.map +1 -1
  10. package/dist/components/confirm-dialog.d.ts +2 -2
  11. package/dist/components/copy-button.d.ts +2 -2
  12. package/dist/components/danger-confirm.d.ts +2 -2
  13. package/dist/components/data-table-cells.d.ts +1 -1
  14. package/dist/components/data-table-filter-popover.d.ts +1 -1
  15. package/dist/components/data-table-filters.d.ts +1 -1
  16. package/dist/components/data-table-labels.d.ts +1 -1
  17. package/dist/components/data-table-pagination.d.ts +1 -1
  18. package/dist/components/data-table-pagination.js +6 -1
  19. package/dist/components/data-table-pagination.js.map +1 -1
  20. package/dist/components/data-table.d.ts +1 -1
  21. package/dist/components/data-table.js +7 -1
  22. package/dist/components/data-table.js.map +1 -1
  23. package/dist/components/facing-pair.d.ts +2 -2
  24. package/dist/components/file-button.d.ts +2 -2
  25. package/dist/components/file-dropzone.d.ts +2 -2
  26. package/dist/components/form-actions.d.ts +2 -2
  27. package/dist/components/iban-input.d.ts +2 -2
  28. package/dist/components/language-select.d.ts +2 -2
  29. package/dist/components/money-field.d.ts +2 -2
  30. package/dist/components/number-field.d.ts +2 -2
  31. package/dist/components/number-input.d.ts +2 -2
  32. package/dist/components/numpad-sheet.d.ts +2 -2
  33. package/dist/components/phone-input.d.ts +2 -2
  34. package/dist/components/series-chart.d.ts +2 -2
  35. package/dist/components/settings-fields.d.ts +2 -2
  36. package/dist/components/share-card.d.ts +2 -2
  37. package/dist/components/swipeable-row.js +1 -1
  38. package/dist/components/swipeable-row.js.map +1 -1
  39. package/dist/components/table.d.ts +35 -1
  40. package/dist/components/table.js +4 -0
  41. package/dist/components/table.js.map +1 -1
  42. package/dist/components/text-link.d.ts +2 -2
  43. package/dist/components/time-input.d.ts +2 -2
  44. package/dist/components/tooltip.d.ts +103 -14
  45. package/dist/components/tooltip.js +194 -57
  46. package/dist/components/tooltip.js.map +1 -1
  47. package/dist/components/translation-review-editor.d.ts +9 -1
  48. package/dist/components/translation-review-editor.js +11 -1
  49. package/dist/components/translation-review-editor.js.map +1 -1
  50. package/dist/components/translation-review-labels.d.ts +10 -0
  51. package/dist/components/translation-review-labels.js +5 -1
  52. package/dist/components/translation-review-labels.js.map +1 -1
  53. package/dist/components/translation-review.d.ts +109 -8
  54. package/dist/components/translation-review.js +315 -91
  55. package/dist/components/translation-review.js.map +1 -1
  56. package/dist/components/ui.d.ts +2 -2
  57. package/dist/components/ui.js +55 -18
  58. package/dist/components/ui.js.map +1 -1
  59. package/dist/components/use-table-state.d.ts +1 -1
  60. package/dist/{data-table-labels-B7OdnM0S.d.ts → data-table-labels-Cdn1QS2k.d.ts} +21 -1
  61. package/dist/data-table.d.ts +1 -1
  62. package/dist/feedback/feedback-attachment.d.ts +2 -2
  63. package/dist/feedback/feedback-dialog.d.ts +2 -2
  64. package/dist/feedback/feedback-dialog.js +6 -1
  65. package/dist/feedback/feedback-dialog.js.map +1 -1
  66. package/dist/feedback/feedback-inbox.d.ts +2 -2
  67. package/dist/feedback/feedback-inbox.js +2 -0
  68. package/dist/feedback/feedback-inbox.js.map +1 -1
  69. package/dist/feedback/feedback-thread.d.ts +2 -2
  70. package/dist/{feedback-DOwPu-Il.d.ts → feedback-BXKH-ToU.d.ts} +32 -3
  71. package/dist/feedback.d.ts +2 -2
  72. package/dist/hooks/use-body-scroll-lock.js +16 -0
  73. package/dist/hooks/use-body-scroll-lock.js.map +1 -1
  74. package/dist/hooks/use-file-drop.d.ts +2 -2
  75. package/dist/hooks/use-search-param-state.d.ts +58 -3
  76. package/dist/hooks/use-search-param-state.js +100 -35
  77. package/dist/hooks/use-search-param-state.js.map +1 -1
  78. package/dist/i18n/defaults.d.ts +2 -2
  79. package/dist/i18n/german.d.ts +2 -2
  80. package/dist/i18n/german.js +8 -1
  81. package/dist/i18n/german.js.map +1 -1
  82. package/dist/i18n/kit-labels.d.ts +2 -2
  83. package/dist/i18n/languages.d.ts +2 -2
  84. package/dist/i18n/locales/de-CH.d.ts +2 -2
  85. package/dist/i18n/locales/en.d.ts +2 -2
  86. package/dist/i18n/locales/en.js +5 -1
  87. package/dist/i18n/locales/en.js.map +1 -1
  88. package/dist/i18n/locales/es.d.ts +2 -2
  89. package/dist/i18n/locales/es.js +7 -1
  90. package/dist/i18n/locales/es.js.map +1 -1
  91. package/dist/i18n/locales/fr.d.ts +2 -2
  92. package/dist/i18n/locales/fr.js +6 -1
  93. package/dist/i18n/locales/fr.js.map +1 -1
  94. package/dist/i18n/locales/hu.d.ts +2 -2
  95. package/dist/i18n/locales/hu.js +9 -1
  96. package/dist/i18n/locales/hu.js.map +1 -1
  97. package/dist/i18n/locales/it.d.ts +2 -2
  98. package/dist/i18n/locales/it.js +6 -1
  99. package/dist/i18n/locales/it.js.map +1 -1
  100. package/dist/i18n/locales/zh.d.ts +2 -2
  101. package/dist/i18n/locales/zh.js +6 -1
  102. package/dist/i18n/locales/zh.js.map +1 -1
  103. package/dist/i18n/review.d.ts +2 -2
  104. package/dist/i18n/review.js +11 -0
  105. package/dist/i18n/review.js.map +1 -1
  106. package/dist/index.d.ts +6 -6
  107. package/dist/index.js +9 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/lib/strip-fade.d.ts +84 -5
  110. package/dist/lib/strip-fade.js +109 -11
  111. package/dist/lib/strip-fade.js.map +1 -1
  112. package/dist/lib/translation-review.d.ts +45 -1
  113. package/dist/lib/translation-review.js +38 -1
  114. package/dist/lib/translation-review.js.map +1 -1
  115. package/dist/rhf/fields.d.ts +2 -2
  116. package/dist/rhf/form.d.ts +2 -2
  117. package/dist/rhf.d.ts +2 -2
  118. package/dist/shell/app-shell.d.ts +2 -2
  119. package/dist/shell/top-bar-brand.d.ts +2 -2
  120. package/dist/shell.d.ts +2 -2
  121. package/dist/wizard/stepper-nav.d.ts +2 -2
  122. package/dist/wizard.d.ts +2 -2
  123. package/package.json +2 -2
  124. package/src/components/column-mapper.tsx +120 -113
  125. package/src/components/data-table-pagination.tsx +10 -1
  126. package/src/components/data-table.tsx +34 -1
  127. package/src/components/swipeable-row.tsx +1 -1
  128. package/src/components/table.tsx +39 -0
  129. package/src/components/tooltip.tsx +487 -104
  130. package/src/components/translation-review-editor.tsx +21 -1
  131. package/src/components/translation-review-labels.ts +17 -0
  132. package/src/components/translation-review.tsx +497 -109
  133. package/src/components/ui.tsx +104 -4
  134. package/src/feedback/feedback-dialog.tsx +21 -0
  135. package/src/feedback/feedback-inbox.tsx +19 -2
  136. package/src/hooks/use-body-scroll-lock.ts +25 -0
  137. package/src/hooks/use-search-param-state.ts +268 -41
  138. package/src/i18n/german.ts +10 -0
  139. package/src/i18n/locales/en.ts +7 -0
  140. package/src/i18n/locales/es.ts +9 -0
  141. package/src/i18n/locales/fr.ts +9 -0
  142. package/src/i18n/locales/hu.ts +11 -0
  143. package/src/i18n/locales/it.ts +9 -0
  144. package/src/i18n/locales/zh.ts +8 -0
  145. package/src/i18n/review.ts +11 -0
  146. package/src/index.ts +12 -0
  147. package/src/lib/strip-fade.ts +220 -15
  148. package/src/lib/translation-review.ts +85 -0
@@ -27,6 +27,30 @@ import 'lucide-react';
27
27
  * write to the server's batch limit is the app's; the panel sends one call per action.
28
28
  */
29
29
  type MaybePromise = void | Promise<unknown>;
30
+ /** What asked for a write — see {@link TranslationReviewSaveInfo}. */
31
+ type TranslationReviewOrigin = "editor" | "row" | "swipe" | "group" | "selection" | "undo";
32
+ /**
33
+ * The second argument of `onSave` and `onClear` (0.25): where the write came from, and
34
+ * whether the panel answers it with a toast of its own.
35
+ *
36
+ * WHY THE APP IS TOLD. keksdose and kastlan toast "Saved" from their mutation on every
37
+ * save. With {@link TranslationReviewPanelProps.undo} on, an approval is answered by the
38
+ * kit's Undo toast instead — and a reviewer swiping through a list then read two toasts
39
+ * per card. The app skips its own where `toasted` is true:
40
+ *
41
+ * onSave={(writes, { toasted }) => save.mutateAsync({ items: writes.map(toApiWrite), quiet: toasted })}
42
+ *
43
+ * An app that ignores the argument keeps working; it only says "Saved" twice.
44
+ */
45
+ interface TranslationReviewSaveInfo {
46
+ /** The open editor, a row's approve button, a swipe on a phone card, a group's
47
+ * "Approve unreviewed", the selection's bulk bar, or an Undo pressed on the toast. */
48
+ origin: TranslationReviewOrigin;
49
+ /** The panel shows its own toast for this write (an approval's Undo toast). */
50
+ toasted: boolean;
51
+ }
52
+ /** How {@link TranslationReviewPanelProps.groupBy} names a row's group. */
53
+ type TranslationReviewGroupBy = "namespace" | "source" | ((row: TranslationRow) => string);
30
54
  interface TranslationReviewPanelProps {
31
55
  /** One locale's rows, from `translationRows`. */
32
56
  rows: readonly TranslationRow[];
@@ -35,10 +59,12 @@ interface TranslationReviewPanelProps {
35
59
  /** The reference language's own name — the reference column's header. */
36
60
  referenceLabel: string;
37
61
  /** Store verdicts: one for an editor or a row's approve button, many for a bulk
38
- * approve. Left out (or `readOnly`): nothing can be changed. */
39
- onSave?: (writes: TranslationReviewWrite[]) => MaybePromise;
40
- /** Clear verdicts — back to unreviewed. Left out: no reset. */
41
- onClear?: (keys: TranslationReviewKey[]) => MaybePromise;
62
+ * approve. Left out (or `readOnly`): nothing can be changed. The second argument
63
+ * says where the write came from ({@link TranslationReviewSaveInfo}). */
64
+ onSave?: (writes: TranslationReviewWrite[], info: TranslationReviewSaveInfo) => MaybePromise;
65
+ /** Clear verdicts — back to unreviewed. Left out: no reset, and an approval of a row
66
+ * that had no verdict cannot be undone. */
67
+ onClear?: (keys: TranslationReviewKey[], info: TranslationReviewSaveInfo) => MaybePromise;
42
68
  /** A locale the viewer may read but not review: the rows and their verdicts, no
43
69
  * actions, and a line saying so. */
44
70
  readOnly?: boolean;
@@ -58,9 +84,13 @@ interface TranslationReviewPanelProps {
58
84
  sourceLabels?: Readonly<Record<string, string>>;
59
85
  /**
60
86
  * Controlled filters — for an app that keeps them in the URL (keksdose's `?status=`,
61
- * `?area=`, `?q=`). Whatever is left out is the panel's own. Pair with `onFilterChange`.
87
+ * `?ns=`, `?q=`). Whatever is left out is the panel's own. Pair with `onFilterChange`.
62
88
  */
63
89
  filter?: Partial<TranslationReviewFilter>;
90
+ /** Every filter, on every change — write them in ONE update: `useSearchParamsState`'s
91
+ * setter takes this object as it is (`filter={filter} onFilterChange={setFilter}`).
92
+ * Single `useSearchParamState` setters compose since 0.25; before, four in a row
93
+ * clobbered each other (keksdose live #378). */
64
94
  onFilterChange?: (filter: TranslationReviewFilter) => void;
65
95
  /** The progress bar over the filters. Default true. */
66
96
  progress?: boolean;
@@ -72,6 +102,70 @@ interface TranslationReviewPanelProps {
72
102
  formatDate?: (iso: string) => string;
73
103
  /** Turns a callback's rejection into words. Default {@link TranslationReviewLabels.failed}. */
74
104
  formatError?: (error: unknown) => ReactNode;
105
+ /**
106
+ * Swipe the phone cards (0.25, keksdose live #377 — Marcel reviewing on a phone): toward
107
+ * the reading END to approve, toward the START for "Needs a change", which OPENS the
108
+ * editor with the cursor in the wording rather than sending the string back blind — a
109
+ * verdict without a note or a better wording tells whoever fixes it nothing. In a
110
+ * right-to-left page the two sides mirror with the reading direction.
111
+ *
112
+ * DataTable's swipe sides (`mobileSwipeActions`) on {@link SwipeableRow}: the same
113
+ * gesture, the same feedback, and the same keyboard path — every swipe is also a real
114
+ * button, read out and reachable by Tab, so the gesture is a shortcut and never the only
115
+ * way. A row has no swipe while the editor under it is open, while its own write is out,
116
+ * under a {@link WriteLockProvider} lock, in a `readOnly` locale, and toward "Approve"
117
+ * where there is nothing to approve (a missing string, an approved one). A reviewer
118
+ * limited to `areas` never sees a row outside them, so never swipes one.
119
+ *
120
+ * Off by default, so no existing page gains a gesture on the bump. Phones only; the
121
+ * desktop table keeps its approve button.
122
+ */
123
+ swipe?: boolean;
124
+ /**
125
+ * Answer every approval with the kit's Undo toast (`toast.undo`): a row's button, a
126
+ * swipe, the editor's Approve, a group's and the selection's bulk approve. Undo stores
127
+ * again what the rows said before ({@link reviewUndo}) — or clears them, for rows that
128
+ * had no verdict, which needs `onClear` (without it the toast reports and offers
129
+ * nothing). A batch has ONE Undo.
130
+ *
131
+ * Default: on with `swipe` or `groupBy` — the two ways to approve in one movement or many
132
+ * rows at once bring their way back — and off otherwise, so an existing page does not
133
+ * gain a toast on the bump. Needs the app's `<Toaster>`. Tell the app's own "Saved"
134
+ * toast apart with the `toasted` flag ({@link TranslationReviewSaveInfo}).
135
+ */
136
+ undo?: boolean;
137
+ /**
138
+ * Group the strings under a header per area (0.25, keksdose live #377: *"grouping to the
139
+ * translation review entries for faster reviewing"*): `"namespace"` — the row's
140
+ * `namespace`, which `translationRows` derives from the key (`budget`, `kit.dataTable`
141
+ * with keksdose's `namespaceOf`) — `"source"`, or a function of the row.
142
+ *
143
+ * Each group is a section with a heading ({@link groupHeadingAs}): its name, "n
144
+ * unreviewed / total", and "Approve unreviewed (n)", which approves the group's rows
145
+ * nobody has given a verdict ({@link unreviewedRows}) under the same rules as one
146
+ * approval — write lock, `readOnly`, one write at a time — with one Undo for the batch.
147
+ * A batch larger than `pageSize` asks first, inside the opened group: more than a page
148
+ * is more than the reviewer can have had on screen.
149
+ *
150
+ * WHAT IT MEANS FOR THE FILTERS, THE SORT AND THE PAGES. The filters narrow the rows
151
+ * first, then the rows are grouped: a header counts what the filters show in it (so
152
+ * "Approve unreviewed" never takes a row the reviewer filtered away), and an area with
153
+ * nothing left is not shown. Groups stand in the order their first string has in the
154
+ * reference; a column sort orders the rows INSIDE every group alike. Each group pages
155
+ * on its own, `pageSize` rows at a time — a header then always stands over its own
156
+ * rows, and paging one area does not move another — rather than one pager cutting
157
+ * through the headers. `storageKey` keeps persisting the ungrouped table only.
158
+ *
159
+ * Groups fold (each on its own, remembered while the panel lives). On a phone they
160
+ * start folded when there are several — the headers are then the area list, and the
161
+ * reviewer opens the one to work through; on a wide screen they start open.
162
+ */
163
+ groupBy?: TranslationReviewGroupBy;
164
+ /** A group's name. Default: `sourceLabels` for `groupBy="source"`, else the key. */
165
+ groupLabel?: (group: string) => string;
166
+ /** The level of the group headings. Default `h2`: the panel is a page's body, under
167
+ * the page's `h1`. */
168
+ groupHeadingAs?: "h2" | "h3" | "h4";
75
169
  className?: string;
76
170
  labels?: Partial<TranslationReviewLabels>;
77
171
  }
@@ -87,8 +181,15 @@ interface TranslationReviewPanelProps {
87
181
  * Bulk approve takes the selected rows that are not approved yet and have a text:
88
182
  * approving an absent string says nothing, and re-approving one says it again. On a
89
183
  * phone the table has no checkboxes, so "Select all shown" selects what the filters
90
- * show — filter to `Unreviewed` in one area, read, select, approve.
184
+ * show — filter to `Unreviewed` in one area, read, select, approve. With `groupBy`, a
185
+ * group's own "Approve unreviewed" is the shorter way, and with `swipe` a card is approved
186
+ * by a swipe.
187
+ *
188
+ * The panel's writes go out ONE AT A TIME, in the order they were asked for: two writes on
189
+ * one locale's verdicts can answer out of order, and an Undo must not overtake the
190
+ * approval it takes back. A swipe on the next card while one is out is queued rather than
191
+ * refused — a reviewer swiping down a list is faster than the server.
91
192
  */
92
- declare function TranslationReviewPanel({ rows: rowsProp, localeLabel, referenceLabel, onSave, onClear, readOnly, areas, areaLabels, inArea, sourceLabels, filter: filterProp, onFilterChange, progress, pageSize, storageKey, formatDate, formatError, className, labels: labelsProp, }: TranslationReviewPanelProps): react.JSX.Element;
193
+ declare function TranslationReviewPanel({ rows: rowsProp, localeLabel, referenceLabel, onSave, onClear, readOnly, areas, areaLabels, inArea, sourceLabels, filter: filterProp, onFilterChange, progress, pageSize, storageKey, formatDate, formatError, swipe, undo: undoProp, groupBy, groupLabel, groupHeadingAs, className, labels: labelsProp, }: TranslationReviewPanelProps): react.JSX.Element;
93
194
 
94
- export { TranslationReviewLabels, TranslationReviewPanel, type TranslationReviewPanelProps };
195
+ export { type TranslationReviewGroupBy, TranslationReviewLabels, type TranslationReviewOrigin, TranslationReviewPanel, type TranslationReviewPanelProps, type TranslationReviewSaveInfo };