@eifi1/ui-kit 0.25.1 → 0.27.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 (174) hide show
  1. package/README.md +16 -5
  2. package/dist/chart.d.ts +13 -9
  3. package/dist/components/account-chips.d.ts +1 -1
  4. package/dist/components/amount-input.d.ts +13 -9
  5. package/dist/components/button-group.d.ts +13 -9
  6. package/dist/components/calculator.d.ts +13 -9
  7. package/dist/components/confirm-dialog.d.ts +13 -9
  8. package/dist/components/copy-button.d.ts +10 -6
  9. package/dist/components/danger-confirm.d.ts +13 -9
  10. package/dist/components/data-table-cells.d.ts +1 -1
  11. package/dist/components/data-table-filter-popover.d.ts +1 -1
  12. package/dist/components/data-table-filters.d.ts +1 -1
  13. package/dist/components/data-table-labels.d.ts +1 -1
  14. package/dist/components/data-table-pagination.d.ts +1 -1
  15. package/dist/components/data-table.d.ts +1 -1
  16. package/dist/components/data-table.js +3 -2
  17. package/dist/components/data-table.js.map +1 -1
  18. package/dist/components/facing-pair.d.ts +13 -9
  19. package/dist/components/file-button.d.ts +13 -9
  20. package/dist/components/file-dropzone.d.ts +13 -9
  21. package/dist/components/form-actions.d.ts +13 -9
  22. package/dist/components/iban-input.d.ts +13 -9
  23. package/dist/components/language-select.d.ts +13 -9
  24. package/dist/components/money-field.d.ts +13 -9
  25. package/dist/components/number-field.d.ts +13 -9
  26. package/dist/components/number-input.d.ts +13 -9
  27. package/dist/components/numpad-sheet.d.ts +13 -9
  28. package/dist/components/phone-input.d.ts +13 -9
  29. package/dist/components/series-chart.d.ts +13 -9
  30. package/dist/components/settings-fields.d.ts +13 -9
  31. package/dist/components/share-card.d.ts +13 -9
  32. package/dist/components/swipeable-row.d.ts +5 -1
  33. package/dist/components/swipeable-row.js.map +1 -1
  34. package/dist/components/text-link.d.ts +13 -9
  35. package/dist/components/time-input.d.ts +13 -9
  36. package/dist/components/translation-review-labels.d.ts +4 -0
  37. package/dist/components/translation-review-labels.js +2 -1
  38. package/dist/components/translation-review-labels.js.map +1 -1
  39. package/dist/components/translation-review.d.ts +27 -3
  40. package/dist/components/translation-review.js +50 -21
  41. package/dist/components/translation-review.js.map +1 -1
  42. package/dist/components/ui.d.ts +10 -6
  43. package/dist/components/use-table-state.d.ts +1 -1
  44. package/dist/{data-table-labels-Cdn1QS2k.d.ts → data-table-labels-DUELeXpa.d.ts} +5 -0
  45. package/dist/data-table.d.ts +1 -1
  46. package/dist/feedback/feedback-attachment.d.ts +13 -9
  47. package/dist/feedback/feedback-attachment.js +3 -3
  48. package/dist/feedback/feedback-attachment.js.map +1 -1
  49. package/dist/feedback/feedback-capture.d.ts +71 -0
  50. package/dist/feedback/feedback-capture.js +194 -0
  51. package/dist/feedback/feedback-capture.js.map +1 -0
  52. package/dist/feedback/feedback-context.d.ts +71 -0
  53. package/dist/feedback/feedback-context.js +96 -0
  54. package/dist/feedback/feedback-context.js.map +1 -0
  55. package/dist/feedback/feedback-crash.d.ts +276 -0
  56. package/dist/feedback/feedback-crash.js +225 -0
  57. package/dist/feedback/feedback-crash.js.map +1 -0
  58. package/dist/feedback/feedback-dialog.d.ts +13 -9
  59. package/dist/feedback/feedback-dialog.js +5 -3
  60. package/dist/feedback/feedback-dialog.js.map +1 -1
  61. package/dist/feedback/feedback-inbox.d.ts +13 -9
  62. package/dist/feedback/feedback-inbox.js +89 -49
  63. package/dist/feedback/feedback-inbox.js.map +1 -1
  64. package/dist/feedback/feedback-labels.d.ts +71 -0
  65. package/dist/feedback/feedback-labels.js +48 -0
  66. package/dist/feedback/feedback-labels.js.map +1 -0
  67. package/dist/feedback/feedback-menu.d.ts +71 -0
  68. package/dist/feedback/feedback-menu.js +61 -0
  69. package/dist/feedback/feedback-menu.js.map +1 -0
  70. package/dist/feedback/feedback-record.d.ts +71 -0
  71. package/dist/feedback/feedback-record.js +104 -0
  72. package/dist/feedback/feedback-record.js.map +1 -0
  73. package/dist/feedback/feedback-row-detail.d.ts +71 -0
  74. package/dist/feedback/feedback-row-detail.js +437 -0
  75. package/dist/feedback/feedback-row-detail.js.map +1 -0
  76. package/dist/feedback/feedback-status-undo.d.ts +71 -0
  77. package/dist/feedback/feedback-status-undo.js +40 -0
  78. package/dist/feedback/feedback-status-undo.js.map +1 -0
  79. package/dist/feedback/feedback-submit.d.ts +182 -0
  80. package/dist/feedback/feedback-submit.js +101 -0
  81. package/dist/feedback/feedback-submit.js.map +1 -0
  82. package/dist/feedback/feedback-swipe.d.ts +152 -0
  83. package/dist/feedback/feedback-swipe.js +73 -0
  84. package/dist/feedback/feedback-swipe.js.map +1 -0
  85. package/dist/feedback/feedback-table.d.ts +71 -0
  86. package/dist/feedback/feedback-table.js +357 -0
  87. package/dist/feedback/feedback-table.js.map +1 -0
  88. package/dist/feedback/feedback-thread.d.ts +13 -9
  89. package/dist/feedback.d.ts +17 -9
  90. package/dist/feedback.js +11 -0
  91. package/dist/feedback.js.map +1 -1
  92. package/dist/hooks/use-file-drop.d.ts +13 -9
  93. package/dist/i18n/defaults.d.ts +13 -9
  94. package/dist/i18n/defaults.js +16 -0
  95. package/dist/i18n/defaults.js.map +1 -1
  96. package/dist/i18n/german.d.ts +13 -9
  97. package/dist/i18n/german.js +92 -5
  98. package/dist/i18n/german.js.map +1 -1
  99. package/dist/i18n/kit-labels.d.ts +7 -3
  100. package/dist/i18n/kit-labels.js.map +1 -1
  101. package/dist/i18n/languages.d.ts +13 -9
  102. package/dist/i18n/locales/de-CH.d.ts +13 -9
  103. package/dist/i18n/locales/en.d.ts +13 -9
  104. package/dist/i18n/locales/en.js +11 -1
  105. package/dist/i18n/locales/en.js.map +1 -1
  106. package/dist/i18n/locales/es.d.ts +13 -9
  107. package/dist/i18n/locales/es.js +90 -5
  108. package/dist/i18n/locales/es.js.map +1 -1
  109. package/dist/i18n/locales/fr.d.ts +13 -9
  110. package/dist/i18n/locales/fr.js +90 -5
  111. package/dist/i18n/locales/fr.js.map +1 -1
  112. package/dist/i18n/locales/hu.d.ts +13 -9
  113. package/dist/i18n/locales/hu.js +91 -5
  114. package/dist/i18n/locales/hu.js.map +1 -1
  115. package/dist/i18n/locales/it.d.ts +13 -9
  116. package/dist/i18n/locales/it.js +90 -5
  117. package/dist/i18n/locales/it.js.map +1 -1
  118. package/dist/i18n/locales/zh.d.ts +13 -9
  119. package/dist/i18n/locales/zh.js +90 -5
  120. package/dist/i18n/locales/zh.js.map +1 -1
  121. package/dist/i18n/review.d.ts +16 -11
  122. package/dist/i18n/review.js +12 -0
  123. package/dist/i18n/review.js.map +1 -1
  124. package/dist/i18n/swiss.js +3 -1
  125. package/dist/i18n/swiss.js.map +1 -1
  126. package/dist/index.d.ts +7 -3
  127. package/dist/index.js +18 -1
  128. package/dist/index.js.map +1 -1
  129. package/dist/{feedback-BXKH-ToU.d.ts → kit-labels-DQg82eHB.d.ts} +1275 -25
  130. package/dist/lib/translation-review.d.ts +76 -1
  131. package/dist/lib/translation-review.js +30 -0
  132. package/dist/lib/translation-review.js.map +1 -1
  133. package/dist/rhf/fields.d.ts +13 -9
  134. package/dist/rhf/form.d.ts +13 -9
  135. package/dist/rhf.d.ts +13 -9
  136. package/dist/shell/app-shell.d.ts +13 -9
  137. package/dist/shell/top-bar-brand.d.ts +13 -9
  138. package/dist/shell.d.ts +11 -11
  139. package/dist/wizard/stepper-nav.d.ts +13 -9
  140. package/dist/wizard.d.ts +13 -9
  141. package/package.json +6 -1
  142. package/src/components/data-table.tsx +14 -2
  143. package/src/components/swipeable-row.tsx +5 -1
  144. package/src/components/translation-review-labels.ts +5 -0
  145. package/src/components/translation-review.tsx +102 -35
  146. package/src/feedback/feedback-attachment.tsx +19 -3
  147. package/src/feedback/feedback-capture.ts +285 -0
  148. package/src/feedback/feedback-context.tsx +217 -0
  149. package/src/feedback/feedback-crash.ts +547 -0
  150. package/src/feedback/feedback-dialog.tsx +29 -6
  151. package/src/feedback/feedback-inbox.tsx +131 -27
  152. package/src/feedback/feedback-labels.ts +127 -0
  153. package/src/feedback/feedback-menu.tsx +132 -0
  154. package/src/feedback/feedback-record.ts +345 -0
  155. package/src/feedback/feedback-row-detail.tsx +825 -0
  156. package/src/feedback/feedback-status-undo.ts +111 -0
  157. package/src/feedback/feedback-submit.tsx +224 -0
  158. package/src/feedback/feedback-swipe.tsx +170 -0
  159. package/src/feedback/feedback-table.tsx +757 -0
  160. package/src/feedback.ts +13 -0
  161. package/src/i18n/defaults.ts +16 -0
  162. package/src/i18n/german.ts +99 -5
  163. package/src/i18n/kit-labels.tsx +20 -0
  164. package/src/i18n/locales/en.ts +16 -1
  165. package/src/i18n/locales/es.ts +97 -5
  166. package/src/i18n/locales/fr.ts +96 -5
  167. package/src/i18n/locales/hu.ts +95 -5
  168. package/src/i18n/locales/it.ts +98 -5
  169. package/src/i18n/locales/zh.ts +91 -5
  170. package/src/i18n/review.ts +15 -2
  171. package/src/i18n/swiss.ts +5 -1
  172. package/src/index.ts +19 -0
  173. package/src/lib/translation-review.ts +109 -0
  174. package/tokens.css +8 -0
@@ -17,14 +17,18 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
17
17
 
18
18
  return {
19
19
  feedbackAttachment: {
20
- attachmentAdd: "Allega immagine",
20
+ attachmentAdd: "Aggiungi allegato",
21
21
  attachmentCapture: "Cattura schermata",
22
- attachmentPaste: "…oppure incolli uno screenshot dagli appunti.",
22
+ attachmentPaste:
23
+ "…oppure incolli uno screenshot direttamente dagli appunti, così può mostrare solo un dettaglio invece dell’intera pagina.",
23
24
  attachmentRemove: "Rimuovi allegato",
24
25
  attachmentList: "Allegati",
25
26
  attachmentScreenshot: "Screenshot",
26
27
  attachmentRemoveFile: (name) => `Rimuovi ${name}`,
27
- attachmentLimit: (max) => `Massimo ${n(max)} ${max === 1 ? "allegato" : "allegati"}: ne rimuova uno per aggiungerne un altro.`,
28
+ attachmentLimit: (max) =>
29
+ max === 1
30
+ ? `Massimo ${n(max)} allegato: lo rimuova per aggiungerne un altro.`
31
+ : `Massimo ${n(max)} allegati: ne rimuova uno per aggiungerne un altro.`,
28
32
  attachmentUploading: "Caricamento…",
29
33
  attachmentUploadFailed: (name) => `Impossibile caricare «${name}»`,
30
34
  },
@@ -34,8 +38,8 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
34
38
  subject: "Oggetto",
35
39
  body: "Cosa è successo?",
36
40
  bodyOptional: "Cosa è successo? (facoltativo)",
37
- attachment: "Screenshot",
38
- submitHint: "Ctrl/⌘ + Invio per inviare",
41
+ attachment: "Allegato",
42
+ submitHint: (apple) => (apple ? "⌘ Invio per inviare" : "Ctrl+Invio per inviare"),
39
43
  cancel: "Annulla",
40
44
  save: "Invia",
41
45
  },
@@ -54,6 +58,94 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
54
58
  sendHint: (modifier) => `${modifier} + Invio per inviare`,
55
59
  sendHintEnter: "Invio per inviare, Maiusc + Invio per andare a capo",
56
60
  },
61
+ // 0.27.0. "Feedback" stays, as `feedbackDialog`; "rielaborazione" for rework.
62
+ feedbackStatus: {
63
+ OPEN: "Aperto",
64
+ IN_PROGRESS: "In corso",
65
+ IN_EVALUATION: "In valutazione",
66
+ NEEDS_LIVE_TEST: "Da testare in produzione",
67
+ POSTPONED: "Rimandato",
68
+ DONE: "Completato",
69
+ WONT_DO: "Non verrà fatto",
70
+ },
71
+ feedbackCategory: {
72
+ CRASH: "Arresto anomalo",
73
+ BUG: "Errore",
74
+ IDEA: "Idea",
75
+ QUESTION: "Domanda",
76
+ OTHER: "Altro",
77
+ },
78
+ feedbackToast: {
79
+ submitted: "Grazie per il feedback!",
80
+ submitFailed: "Impossibile inviare il feedback",
81
+ attachmentUnsupported: "Sono consentiti solo immagini, PDF o file di testo",
82
+ attachmentTooLarge: "Il file supera i 10 MB",
83
+ attachmentTooMany: (count) =>
84
+ count === 1
85
+ ? "C’è posto solo per 1 allegato: gli altri sono stati esclusi."
86
+ : `C’è posto solo per ${n(count)} allegati: gli altri sono stati esclusi.`,
87
+ captureFailed: "Impossibile catturare lo screenshot",
88
+ updateFailed: "Non è stato possibile salvare la modifica.",
89
+ statusChanged: (status, title) => `Impostato su «${status}»: ${title}`,
90
+ statusUndo: "Annulla",
91
+ statusRestored: (status, title) => `Tornato a «${status}»: ${title}`,
92
+ },
93
+ feedbackMenu: {
94
+ trigger: "Invia feedback",
95
+ myFeedback: "I miei feedback",
96
+ viewFeedback: "Visualizza feedback",
97
+ },
98
+ feedbackContext: {
99
+ user: "Utente",
100
+ attachUrl: "Allega l’URL della pagina corrente",
101
+ },
102
+ feedbackPage: {
103
+ title: "Feedback",
104
+ myTitle: "I miei feedback",
105
+ columnId: "#",
106
+ columnDate: "Data",
107
+ columnCategory: "Categoria",
108
+ columnSubject: "Oggetto",
109
+ columnUser: "Utente",
110
+ columnEmail: "Email",
111
+ columnUrl: "URL",
112
+ columnStatus: "Stato",
113
+ columnResolved: "Risolto il",
114
+ openPage: "Apri pagina",
115
+ empty: "Nessuno",
116
+ deletedUser: "<utente eliminato>",
117
+ // An id, not a count: printed as it is, like the "#" column.
118
+ userFallback: (id) => `utente #${id}`,
119
+ environment: (environment) => String(environment ?? "").toUpperCase(),
120
+ reworkChip: (count) => (count === 1 ? "Rielaborazione" : `Rielaborazione ×${n(count)}`),
121
+ awaitingFilter: "Solo ciò che attende Lei",
122
+ phoneActions: "Azioni sul feedback",
123
+ },
124
+ feedbackDetail: {
125
+ body: "Descrizione",
126
+ edit: "Modifica",
127
+ editDescription: "Modifica descrizione",
128
+ save: "Salva",
129
+ cancel: "Annulla",
130
+ url: "URL",
131
+ copyUrl: "Copia URL",
132
+ attachment: "Allegato",
133
+ download: (name) => `Scarica ${name}`,
134
+ downloadFailed: "Non è stato possibile scaricare l’allegato.",
135
+ outcome: "Esito",
136
+ resolvedAt: (date) => `Risolto il ${date}`,
137
+ outcomeAdd: "Aggiungi esito",
138
+ outcomeUpdate: "Aggiorna",
139
+ outcomePlaceholder: "Cosa è stato fatto o deciso, oppure perché non verrà affrontato.",
140
+ rework: "Rielaborazione",
141
+ openPage: "Apri pagina",
142
+ reworkTitle: "Rimanda in rielaborazione",
143
+ reworkSend: "Richiedi rielaborazione",
144
+ reworkPlaceholder: "Cosa va ancora perfezionato? Eventuali nuovi vincoli o cambi di direzione.",
145
+ reworkUploadFailed:
146
+ "Non è stato possibile caricare il file. La richiesta di rielaborazione non è stata inviata.",
147
+ status: "Stato",
148
+ },
57
149
  accountSettings: {
58
150
  profile: {
59
151
  title: "Profilo",
@@ -774,6 +866,7 @@ export function uiKitLabelsIt(numberLocale = "it-IT"): UiKitLabels {
774
866
  exportCorrections: (count) => `Esporta le correzioni (${n(count)})`,
775
867
  failed: "Non ha funzionato. Riprovi.",
776
868
  approvedToast: (count) => (count === 1 ? "Testo approvato" : `${n(count)} testi approvati`),
869
+ clearedToast: (count) => (count === 1 ? "Testo segnato come non rivisto" : `${n(count)} testi segnati come non rivisti`),
777
870
  groupCount: (unreviewed, total) =>
778
871
  `${n(unreviewed)} ${plural(unreviewed, "non rivisto", "non rivisti")} / ${n(total)}`,
779
872
  approveGroup: (count) => `Approva i non rivisti (${n(count)})`,
@@ -16,14 +16,15 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
16
16
 
17
17
  return {
18
18
  feedbackAttachment: {
19
- attachmentAdd: "附加图片",
19
+ attachmentAdd: "添加附件",
20
20
  attachmentCapture: "截取屏幕",
21
- attachmentPaste: "……或从剪贴板粘贴截图。",
21
+ attachmentPaste: "……或直接从剪贴板粘贴截图,这样只需展示局部,而不必截取整个页面。",
22
22
  attachmentRemove: "移除附件",
23
23
  attachmentList: "附件",
24
24
  attachmentScreenshot: "截图",
25
25
  attachmentRemoveFile: (name) => `移除 ${name}`,
26
- attachmentLimit: (max) => `最多 ${n(max)} 个附件,请先移除一个再添加。`,
26
+ attachmentLimit: (max) =>
27
+ max === 1 ? `最多 ${n(max)} 个附件,请先将其移除再添加。` : `最多 ${n(max)} 个附件,请先移除一个再添加。`,
27
28
  attachmentUploading: "正在上传…",
28
29
  attachmentUploadFailed: (name) => `无法上传“${name}”`,
29
30
  },
@@ -33,8 +34,8 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
33
34
  subject: "主题",
34
35
  body: "发生了什么?",
35
36
  bodyOptional: "发生了什么?(可选)",
36
- attachment: "截图",
37
- submitHint: "Ctrl/⌘ + Enter 发送",
37
+ attachment: "附件",
38
+ submitHint: (apple) => (apple ? "⌘ Enter 发送" : "Ctrl+Enter 发送"),
38
39
  cancel: "取消",
39
40
  save: "发送",
40
41
  },
@@ -53,6 +54,90 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
53
54
  sendHint: (modifier) => `${modifier} + Enter 发送`,
54
55
  sendHintEnter: "Enter 发送,Shift + Enter 换行",
55
56
  },
57
+ // 0.27.0. 反馈 for feedback, as `feedbackDialog`; 返工 for rework.
58
+ feedbackStatus: {
59
+ OPEN: "待处理",
60
+ IN_PROGRESS: "处理中",
61
+ IN_EVALUATION: "评估中",
62
+ NEEDS_LIVE_TEST: "待线上测试",
63
+ POSTPONED: "已推迟",
64
+ DONE: "已完成",
65
+ WONT_DO: "不予处理",
66
+ },
67
+ feedbackCategory: {
68
+ CRASH: "崩溃",
69
+ BUG: "错误",
70
+ IDEA: "建议",
71
+ QUESTION: "疑问",
72
+ OTHER: "其他",
73
+ },
74
+ feedbackToast: {
75
+ submitted: "感谢您的反馈!",
76
+ submitFailed: "无法提交反馈",
77
+ attachmentUnsupported: "仅允许图片、PDF 或文本文件",
78
+ attachmentTooLarge: "文件超过 10 MB",
79
+ attachmentTooMany: (count) => `只能容纳 ${n(count)} 个附件,其余的已略去。`,
80
+ captureFailed: "无法截取屏幕",
81
+ updateFailed: "无法保存更改。",
82
+ statusChanged: (status, title) => `已设为“${status}”:${title}`,
83
+ statusUndo: "撤销",
84
+ statusRestored: (status, title) => `已恢复为“${status}”:${title}`,
85
+ },
86
+ feedbackMenu: {
87
+ trigger: "发送反馈",
88
+ myFeedback: "我的反馈",
89
+ viewFeedback: "查看反馈",
90
+ },
91
+ feedbackContext: {
92
+ user: "用户",
93
+ attachUrl: "附加当前页面 URL",
94
+ },
95
+ feedbackPage: {
96
+ title: "反馈",
97
+ myTitle: "我的反馈",
98
+ columnId: "#",
99
+ columnDate: "日期",
100
+ columnCategory: "类别",
101
+ columnSubject: "主题",
102
+ columnUser: "用户",
103
+ columnEmail: "电子邮箱",
104
+ columnUrl: "URL",
105
+ columnStatus: "状态",
106
+ columnResolved: "解决日期",
107
+ openPage: "打开页面",
108
+ empty: "无",
109
+ deletedUser: "<已删除的用户>",
110
+ // An id, not a count: printed as it is, like the "#" column.
111
+ userFallback: (id) => `用户 #${id}`,
112
+ environment: (environment) => String(environment ?? "").toUpperCase(),
113
+ reworkChip: (count) => (count === 1 ? "返工" : `返工 ×${n(count)}`),
114
+ awaitingFilter: "仅显示待您处理的",
115
+ phoneActions: "反馈操作",
116
+ },
117
+ feedbackDetail: {
118
+ body: "描述",
119
+ edit: "编辑",
120
+ editDescription: "编辑描述",
121
+ save: "保存",
122
+ cancel: "取消",
123
+ url: "URL",
124
+ copyUrl: "复制 URL",
125
+ attachment: "附件",
126
+ download: (name) => `下载 ${name}`,
127
+ downloadFailed: "无法下载附件。",
128
+ outcome: "处理结果",
129
+ resolvedAt: (date) => `解决日期:${date}`,
130
+ outcomeAdd: "添加处理结果",
131
+ outcomeUpdate: "更新",
132
+ outcomePlaceholder: "做了什么、作出了什么决定,或为什么不予处理。",
133
+ rework: "返工",
134
+ openPage: "打开页面",
135
+ reworkTitle: "退回返工",
136
+ reworkSend: "提交返工",
137
+ reworkPlaceholder: "还有哪些需要完善?如有新的限制或方向调整,请一并说明。",
138
+ reworkUploadFailed: "无法上传文件,返工请求未发送。",
139
+ status: "状态",
140
+ },
56
141
  accountSettings: {
57
142
  profile: {
58
143
  title: "个人资料",
@@ -749,6 +834,7 @@ export function uiKitLabelsZh(numberLocale = "zh-CN"): UiKitLabels {
749
834
  exportCorrections: (count) => `导出更正(${n(count)})`,
750
835
  failed: "操作未成功,请重试。",
751
836
  approvedToast: (count) => (count === 1 ? "文本已通过" : `已通过 ${n(count)} 条文本`),
837
+ clearedToast: (count) => (count === 1 ? "文本已标记为未审校" : `已将 ${n(count)} 条文本标记为未审校`),
752
838
  groupCount: (unreviewed, total) => `未审校 ${n(unreviewed)} / ${n(total)}`,
753
839
  approveGroup: (count) => `通过未审校项(${n(count)})`,
754
840
  confirmGroup: (count, group) =>
@@ -6,8 +6,9 @@ import type { UiKitLabels } from "./kit-labels";
6
6
  * keksdose reviews its own locale bundles on its /translations page — one verdict per
7
7
  * locale and key, stored with the text the reviewer saw, so a later change re-opens it.
8
8
  * The kit's words appear on the same screens but live in TypeScript, not in the app's
9
- * bundles, and 94 of them are functions (`(count) => "3 results"`), which a bundle
10
- * flattener skips. This turns a label tree into rows that page can join on.
9
+ * bundles, and 138 of them are functions (`(count) => "3 results"`; 0.27.0, every one
10
+ * listed in {@link KIT_LABEL_SAMPLES}), which a bundle flattener skips. This turns a
11
+ * label tree into rows that page can join on.
11
12
  *
12
13
  * - A string label is one row under its dot path: `common.close`. An array of words
13
14
  * (weekday names) is one row per entry: `miniCalendar.weekdays.0`.
@@ -150,6 +151,17 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
150
151
  "feedbackAttachment.attachmentLimit": one,
151
152
  "feedbackAttachment.attachmentUploadFailed": [["{{name}}"]],
152
153
  "feedbackComposer.sendHint": [["{{modifier}}"]],
154
+ "feedbackDialog.submitHint": [[true], [false]],
155
+ "feedbackToast.attachmentTooMany": one,
156
+ "feedbackToast.statusChanged": [["{{status}}", "{{title}}"]],
157
+ "feedbackToast.statusRestored": [["{{status}}", "{{title}}"]],
158
+ "feedbackPage.userFallback": [[42]],
159
+ // A real value, not a placeholder: the chip upper-cases what it is given, and
160
+ // "{{ENVIRONMENT}}" would read as a placeholder of that name.
161
+ "feedbackPage.environment": [["dev"]],
162
+ "feedbackPage.reworkChip": one,
163
+ "feedbackDetail.download": [["{{name}}"]],
164
+ "feedbackDetail.resolvedAt": [["{{date}}"]],
153
165
  "accountSettings.passkeys.renameItem": [["{{name}}"]],
154
166
  "accountSettings.passkeys.renameField": [["{{name}}"]],
155
167
  "accountSettings.passkeys.deleteItem": [["{{name}}"]],
@@ -194,6 +206,7 @@ export const KIT_LABEL_SAMPLES: Readonly<Record<string, readonly (readonly unkno
194
206
  "translationReview.scope": [["{{areas}}"]],
195
207
  "translationReview.exportCorrections": [[0], [1], [3]],
196
208
  "translationReview.approvedToast": one,
209
+ "translationReview.clearedToast": one,
197
210
  "translationReview.groupCount": [
198
211
  [1, 12],
199
212
  [3, 12],
package/src/i18n/swiss.ts CHANGED
@@ -12,7 +12,11 @@ export function swiss<T>(value: T): T {
12
12
  if (typeof value === "string") return respell(value) as T;
13
13
  if (typeof value === "function") {
14
14
  const fn = value as (...args: unknown[]) => unknown;
15
- return ((...args: unknown[]) => swiss(fn(...args))) as T;
15
+ const wrapped = (...args: unknown[]) => swiss(fn(...args));
16
+ // Keep the label's arity: a rest-parameter wrapper reports 0, and whatever inspects
17
+ // a label by its parameters (the catalogue tests do) would then pass it nothing.
18
+ Object.defineProperty(wrapped, "length", { value: fn.length });
19
+ return wrapped as T;
16
20
  }
17
21
  if (value && typeof value === "object") {
18
22
  return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, swiss(v)])) as T;
package/src/index.ts CHANGED
@@ -327,6 +327,19 @@ export * from "./feedback/feedback-attachment";
327
327
  export * from "./feedback/feedback-dialog";
328
328
  export * from "./feedback/feedback-inbox";
329
329
  export * from "./feedback/feedback-thread";
330
+ // 0.27.0: the feedback harmonization (docs/feedback-harmonization.md) — one record,
331
+ // one menu, dialog, table, detail and crash reporter for keksdose, kastlan, Kurvenschmiede.
332
+ export * from "./feedback/feedback-record";
333
+ export * from "./feedback/feedback-labels";
334
+ export * from "./feedback/feedback-status-undo";
335
+ export * from "./feedback/feedback-swipe";
336
+ export * from "./feedback/feedback-menu";
337
+ export * from "./feedback/feedback-context";
338
+ export * from "./feedback/feedback-capture";
339
+ export * from "./feedback/feedback-submit";
340
+ export * from "./feedback/feedback-table";
341
+ export * from "./feedback/feedback-row-detail";
342
+ export * from "./feedback/feedback-crash";
330
343
 
331
344
  // ── multi-step wizard ────────────────────────────────────────────────────────
332
345
  // The engine (step machine, validators, collected data), the chrome around it
@@ -395,6 +408,10 @@ export {
395
408
  groupTranslationRows,
396
409
  unreviewedRows,
397
410
  reviewUndo,
411
+ // 0.26: swipe bindings for an app's Settings → Interaction (keksdose #377 rework).
412
+ TRANSLATION_REVIEW_SWIPE_ACTIONS,
413
+ DEFAULT_TRANSLATION_REVIEW_SWIPE,
414
+ translationReviewSwipePlan,
398
415
  } from "./lib/translation-review";
399
416
  export type {
400
417
  TranslationVerdict,
@@ -411,6 +428,8 @@ export type {
411
428
  TranslationCorrection,
412
429
  TranslationRowGroup,
413
430
  TranslationReviewUndo,
431
+ TranslationReviewSwipeAction,
432
+ TranslationReviewSwipeBinding,
414
433
  } from "./lib/translation-review";
415
434
  export {
416
435
  TranslationReviewPanel,
@@ -512,6 +512,115 @@ export function dropReviews<T extends TranslationReviewKey>(
512
512
  return prev.filter((r) => !gone.has(`${r.locale}|${r.key}`));
513
513
  }
514
514
 
515
+ // ── Swipe bindings ──────────────────────────────────────────────────────────────
516
+
517
+ /**
518
+ * What a phone card's swipe can be bound to in `TranslationReviewPanel`'s `swipe`
519
+ * (keksdose — Marcel's live #377 rework, 2026-10-03: *"Add the swipe options to be shown
520
+ * also to the settings /settings#interaction area where the other swipe options are
521
+ * defined"*). keksdose lets the user bind every list's swipes there — per side, a primary
522
+ * action at the first threshold and a secondary one at a longer drag — and lists each
523
+ * surface's ids in its `SWIPE_ACTIONS`; this is the translation list's, in the order a
524
+ * settings page offers them.
525
+ *
526
+ * - `approve` — the string is right as it stands. With the panel's Undo toast.
527
+ * - `edit` — open the editor with the cursor in the wording: "Needs a change" (or
528
+ * "Suggest translation" on a missing string). Writes nothing; the editor does.
529
+ * - `clear` — take the verdict back: unreviewed again. With the Undo toast, which stores
530
+ * the verdict again.
531
+ *
532
+ * THERE IS NO SEPARATE "needs a change". The editor has no verdict to preselect: Approve
533
+ * and "Needs a change" stand side by side in it, and "Needs a change" takes a note or a
534
+ * different wording — a verdict without either tells whoever fixes the string nothing, so
535
+ * a swipe never sends one blind (0.25). The one honest thing a "needs a change" swipe can
536
+ * do is therefore open the editor with the cursor in the wording — which is `edit`, and
537
+ * `edit` already says "Needs a change" on the card. A second id doing the same would arm
538
+ * a second threshold that does what the first already did: the duplicate keksdose's
539
+ * `resolveSwipePlan` drops for exactly that reason.
540
+ */
541
+ export const TRANSLATION_REVIEW_SWIPE_ACTIONS = ["approve", "edit", "clear"] as const;
542
+
543
+ /** One of {@link TRANSLATION_REVIEW_SWIPE_ACTIONS}. */
544
+ export type TranslationReviewSwipeAction = (typeof TRANSLATION_REVIEW_SWIPE_ACTIONS)[number];
545
+
546
+ /**
547
+ * Which swipe does what on a phone card — `TranslationReviewPanel`'s `swipe`. Each side is
548
+ * an ordered ladder, exactly as `SwipeableRow` and DataTable's `mobileSwipeActions` model
549
+ * one: index 0 commits at the first threshold, index 1 at the longer drag (and so on — the
550
+ * thresholds spread evenly over the card's width). A side left out, or empty, does not
551
+ * swipe.
552
+ *
553
+ * LOGICAL SIDES: `end` is a drag toward the reading end of the line — right in a
554
+ * left-to-right page, left in a right-to-left one — and `start` the other way, so one
555
+ * binding holds in both directions. An app whose settings store physical sides (keksdose's
556
+ * `right`/`left`) hands `right` as `end` for a left-to-right page.
557
+ */
558
+ export interface TranslationReviewSwipeBinding {
559
+ /** A drag toward the reading START, nearest threshold first. */
560
+ start?: readonly TranslationReviewSwipeAction[];
561
+ /** A drag toward the reading END, nearest threshold first. */
562
+ end?: readonly TranslationReviewSwipeAction[];
563
+ }
564
+
565
+ /** What `swipe={true}` means — 0.25's fixed mapping: approve toward the end, open the
566
+ * editor ("Needs a change") toward the start. A settings page's "reset" goes back here. */
567
+ export const DEFAULT_TRANSLATION_REVIEW_SWIPE: TranslationReviewSwipeBinding = Object.freeze({
568
+ start: Object.freeze(["edit"] as const),
569
+ end: Object.freeze(["approve"] as const),
570
+ });
571
+
572
+ /** The ladders one row actually offers, from a {@link TranslationReviewSwipeBinding}. */
573
+ export interface TranslationReviewSwipePlan {
574
+ start: TranslationReviewSwipeAction[];
575
+ end: TranslationReviewSwipeAction[];
576
+ }
577
+
578
+ /**
579
+ * The binding resolved against one row — keksdose's `resolveSwipePlan`, for this list.
580
+ * An id the row cannot offer DROPS OUT and the ladder closes up behind it, so the second
581
+ * stage becomes the first rather than the side going dead behind an unreachable first
582
+ * stage (or arming a threshold that does nothing):
583
+ *
584
+ * - `approve`: not on a missing string (nothing to approve) or an approved one (it would
585
+ * say it again) — the rows that have no approve button either;
586
+ * - `clear`: not without `canClear` (the app passed no `onClear`), and not on a row with
587
+ * no verdict to take back (unreviewed; missing with no suggestion);
588
+ * - `edit`: on every row;
589
+ * - an id named twice on one side: the second time (a longer drag to the same effect);
590
+ * - an id this version does not know (a binding stored by another version, an app's own
591
+ * "none" slot): dropped like one that does not apply.
592
+ *
593
+ * Only what the ROW decides. Whether the panel may write at all — `readOnly`, no
594
+ * `onSave`, a write lock, the row's own write still out — is the panel's, and then no
595
+ * side swipes.
596
+ */
597
+ export function translationReviewSwipePlan(
598
+ binding: TranslationReviewSwipeBinding,
599
+ row: TranslationRow,
600
+ { canClear = false }: { canClear?: boolean } = {},
601
+ ): TranslationReviewSwipePlan {
602
+ const offers = (id: TranslationReviewSwipeAction): boolean => {
603
+ switch (id) {
604
+ case "approve":
605
+ return row.text !== "" && row.status !== "approved";
606
+ case "edit":
607
+ return true;
608
+ case "clear":
609
+ return canClear && row.review !== null;
610
+ default:
611
+ return false;
612
+ }
613
+ };
614
+ const side = (ids: readonly TranslationReviewSwipeAction[] | undefined): TranslationReviewSwipeAction[] => {
615
+ const out: TranslationReviewSwipeAction[] = [];
616
+ for (const id of ids ?? []) {
617
+ if (!out.includes(id) && offers(id)) out.push(id);
618
+ }
619
+ return out;
620
+ };
621
+ return { start: side(binding.start), end: side(binding.end) };
622
+ }
623
+
515
624
  // ── Export ──────────────────────────────────────────────────────────────────────
516
625
 
517
626
  /**
package/tokens.css CHANGED
@@ -205,6 +205,9 @@
205
205
  not a call to action, and painting it `--brand` would make every table look
206
206
  like it had a primary button in the toolbar. */
207
207
  --info: #0369a1; /* sky-700 */
208
+ /* Text on an `--info` fill (0.27: the feedback inbox's "advance" swipe) — white here,
209
+ the darkest sky in dark mode, where the fill is a pastel. */
210
+ --info-contrast: #ffffff;
208
211
  --info-border: #7dd3fc; /* sky-300 */
209
212
  --info-bg: #e0f2fe; /* sky-100 */
210
213
 
@@ -213,6 +216,9 @@
213
216
  journey to the database, this one an ACTION's outcome. Emerald rather than the
214
217
  money teal, so a "resolved" chip cannot be misread as an inflow. */
215
218
  --success: #047857; /* emerald-700 */
219
+ /* Text on a `--success` fill (0.26: a swipe's approve panel) — white here, the
220
+ darkest emerald in dark mode, where the fill is a pastel and white text failed. */
221
+ --success-contrast: #ffffff;
216
222
  --success-border: #6ee7b7; /* emerald-300 */
217
223
  --success-bg: #d1fae5; /* emerald-100 */
218
224
  }
@@ -233,10 +239,12 @@
233
239
  --warning-bg: rgba(120, 53, 15, 0.2);
234
240
 
235
241
  --info: #7dd3fc; /* sky-300 */
242
+ --info-contrast: #082f49; /* sky-950 */
236
243
  --info-border: rgba(3, 105, 161, 0.6);
237
244
  --info-bg: rgba(12, 74, 110, 0.25);
238
245
 
239
246
  --success: #6ee7b7; /* emerald-300 */
247
+ --success-contrast: #022c22; /* emerald-950 */
240
248
  --success-border: rgba(4, 120, 87, 0.6);
241
249
  --success-bg: rgba(6, 78, 59, 0.25);
242
250
  }