@sincpro/web-ui 0.1.0 → 1.0.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 (198) hide show
  1. package/README.md +40 -13
  2. package/dist/components/activity/Activity.d.ts +69 -0
  3. package/dist/components/activity/Activity.js +279 -0
  4. package/dist/components/activity/ActivityBadge.d.ts +16 -0
  5. package/dist/components/activity/ActivityBadge.js +29 -0
  6. package/dist/components/{chatter → activity}/Messages.d.ts +2 -2
  7. package/dist/components/{chatter → activity}/Messages.js +9 -6
  8. package/dist/components/activity/index.d.ts +4 -0
  9. package/dist/components/activity/index.js +5 -0
  10. package/dist/components/assist/AssistMark.d.ts +3 -3
  11. package/dist/components/assist/AssistMark.js +1 -1
  12. package/dist/components/assist/assist.d.ts +1 -1
  13. package/dist/components/assist/assist.js +1 -1
  14. package/dist/components/calendar/RecordCalendar.d.ts +48 -0
  15. package/dist/components/calendar/RecordCalendar.js +101 -0
  16. package/dist/components/calendar/index.d.ts +1 -0
  17. package/dist/components/calendar/index.js +1 -0
  18. package/dist/components/form/Sheet.d.ts +4 -0
  19. package/dist/components/form/Sheet.js +16 -5
  20. package/dist/components/gantt/RecordGantt.d.ts +44 -0
  21. package/dist/components/gantt/RecordGantt.js +110 -0
  22. package/dist/components/gantt/index.d.ts +1 -0
  23. package/dist/components/gantt/index.js +1 -0
  24. package/dist/components/index.d.ts +4 -1
  25. package/dist/components/index.js +4 -1
  26. package/dist/components/lines/LineItems.d.ts +45 -5
  27. package/dist/components/lines/LineItems.js +106 -18
  28. package/dist/components/listing/BoardColumns.d.ts +39 -0
  29. package/dist/components/listing/BoardColumns.js +138 -0
  30. package/dist/components/listing/Listing.js +1 -1
  31. package/dist/components/listing/ListingBar.d.ts +46 -2
  32. package/dist/components/listing/ListingBar.js +47 -5
  33. package/dist/components/listing/PivotExplorer.d.ts +34 -0
  34. package/dist/components/listing/PivotExplorer.js +86 -0
  35. package/dist/components/listing/RecordCard.d.ts +6 -8
  36. package/dist/components/listing/RecordCard.js +13 -7
  37. package/dist/components/listing/Row.d.ts +25 -2
  38. package/dist/components/listing/Row.js +30 -13
  39. package/dist/components/listing/index.d.ts +2 -0
  40. package/dist/components/listing/index.js +2 -0
  41. package/dist/components/listing/set.d.ts +1 -1
  42. package/dist/components/navigation/index.d.ts +0 -2
  43. package/dist/components/navigation/index.js +2 -3
  44. package/dist/components/record/RecordAudit.d.ts +17 -0
  45. package/dist/components/record/RecordAudit.js +27 -0
  46. package/dist/components/record/RecordHeader.d.ts +27 -17
  47. package/dist/components/record/RecordHeader.js +64 -20
  48. package/dist/components/record/RecordNotices.d.ts +37 -0
  49. package/dist/components/record/RecordNotices.js +75 -0
  50. package/dist/components/record/RecordRibbon.d.ts +13 -0
  51. package/dist/components/record/RecordRibbon.js +22 -0
  52. package/dist/components/record/ThumbBar.js +1 -1
  53. package/dist/components/record/index.d.ts +2 -0
  54. package/dist/components/record/index.js +2 -0
  55. package/dist/components/search/CriteriaChips.d.ts +6 -1
  56. package/dist/components/search/CriteriaChips.js +71 -20
  57. package/dist/components/search/SearchBar.d.ts +4 -1
  58. package/dist/components/search/SearchBar.js +15 -7
  59. package/dist/components/timeline/RecordTimeline.d.ts +60 -0
  60. package/dist/components/timeline/RecordTimeline.js +214 -0
  61. package/dist/components/timeline/TimelineToolbar.d.ts +30 -0
  62. package/dist/components/timeline/TimelineToolbar.js +31 -0
  63. package/dist/components/timeline/index.d.ts +3 -0
  64. package/dist/components/timeline/index.js +3 -0
  65. package/dist/components/timeline/time.d.ts +43 -0
  66. package/dist/components/timeline/time.js +135 -0
  67. package/dist/foundations/copy.d.ts +194 -18
  68. package/dist/foundations/copy.es.js +142 -15
  69. package/dist/foundations/copy.js +133 -11
  70. package/dist/foundations/index.d.ts +1 -1
  71. package/dist/foundations/match.d.ts +23 -0
  72. package/dist/foundations/match.js +63 -0
  73. package/dist/foundations/slots.d.ts +1 -1
  74. package/dist/foundations/slots.js +8 -3
  75. package/dist/foundations/types.d.ts +7 -0
  76. package/dist/foundations/types.js +0 -36
  77. package/dist/primitives/block/index.d.ts +1 -1
  78. package/dist/primitives/block/index.js +1 -1
  79. package/dist/primitives/cell/CellStack.d.ts +7 -1
  80. package/dist/primitives/cell/CellStack.js +5 -2
  81. package/dist/primitives/choice/ComboBox.d.ts +3 -0
  82. package/dist/primitives/choice/ComboBox.js +10 -6
  83. package/dist/primitives/choice/KanbanState.d.ts +14 -0
  84. package/dist/primitives/choice/KanbanState.js +37 -0
  85. package/dist/primitives/choice/Priority.d.ts +20 -0
  86. package/dist/primitives/choice/Priority.js +41 -0
  87. package/dist/primitives/choice/SearchField.d.ts +10 -1
  88. package/dist/primitives/choice/SearchField.js +21 -2
  89. package/dist/primitives/choice/Slider.d.ts +6 -1
  90. package/dist/primitives/choice/Slider.js +2 -2
  91. package/dist/primitives/choice/index.d.ts +2 -0
  92. package/dist/primitives/choice/index.js +2 -0
  93. package/dist/primitives/date/Calendar.js +30 -6
  94. package/dist/primitives/date/DatePicker.d.ts +11 -3
  95. package/dist/primitives/date/DatePicker.js +12 -8
  96. package/dist/primitives/date/DateTime.d.ts +35 -0
  97. package/dist/primitives/date/DateTime.js +100 -0
  98. package/dist/primitives/date/index.d.ts +1 -0
  99. package/dist/primitives/date/index.js +4 -2
  100. package/dist/primitives/dialog/Dialog.d.ts +9 -3
  101. package/dist/primitives/dialog/Dialog.js +41 -5
  102. package/dist/primitives/field/DropZone.js +1 -1
  103. package/dist/primitives/field/Field.d.ts +14 -2
  104. package/dist/primitives/field/Field.js +25 -14
  105. package/dist/primitives/field/copy.d.ts +16 -0
  106. package/dist/primitives/field/copy.js +69 -0
  107. package/dist/primitives/field/index.d.ts +2 -0
  108. package/dist/primitives/field/index.js +4 -0
  109. package/dist/primitives/field/note.d.ts +55 -0
  110. package/dist/primitives/field/note.js +117 -0
  111. package/dist/primitives/index.d.ts +1 -0
  112. package/dist/primitives/index.js +1 -0
  113. package/dist/primitives/menu/Menu.d.ts +28 -0
  114. package/dist/primitives/menu/Menu.js +47 -17
  115. package/dist/primitives/notice/Callout.js +1 -1
  116. package/dist/primitives/notice/Flag.d.ts +13 -0
  117. package/dist/primitives/notice/Flag.js +31 -0
  118. package/dist/primitives/notice/index.d.ts +2 -1
  119. package/dist/primitives/notice/index.js +2 -1
  120. package/dist/primitives/overlay/Preview.d.ts +19 -0
  121. package/dist/primitives/overlay/Preview.js +69 -0
  122. package/dist/primitives/overlay/index.d.ts +1 -0
  123. package/dist/primitives/overlay/index.js +3 -1
  124. package/dist/primitives/picker/MatchedText.d.ts +10 -0
  125. package/dist/primitives/picker/MatchedText.js +12 -0
  126. package/dist/primitives/picker/Picker.d.ts +67 -4
  127. package/dist/primitives/picker/Picker.js +142 -23
  128. package/dist/primitives/table/CellCopy.d.ts +20 -0
  129. package/dist/primitives/table/CellCopy.js +23 -0
  130. package/dist/primitives/table/DataTable.d.ts +55 -1
  131. package/dist/primitives/table/DataTable.js +126 -40
  132. package/dist/primitives/table/EditableTable.d.ts +102 -2
  133. package/dist/primitives/table/EditableTable.js +287 -32
  134. package/dist/primitives/table/ReportTable.js +2 -1
  135. package/dist/primitives/table/RowActions.js +7 -2
  136. package/dist/primitives/table/SheetTable.d.ts +4 -1
  137. package/dist/primitives/table/SheetTable.js +38 -5
  138. package/dist/primitives/table/Table.d.ts +5 -0
  139. package/dist/primitives/table/Table.js +17 -8
  140. package/dist/primitives/table/index.d.ts +2 -2
  141. package/dist/primitives/table/index.js +1 -1
  142. package/dist/primitives/tabs/Tabs.d.ts +2 -2
  143. package/dist/primitives/tabs/Tabs.js +1 -1
  144. package/dist/primitives/tag/Tags.d.ts +2 -0
  145. package/dist/primitives/tag/Tags.js +2 -1
  146. package/dist/primitives/tag/TagsField.d.ts +13 -0
  147. package/dist/primitives/tag/TagsField.js +39 -10
  148. package/dist/primitives/tag/choices.d.ts +2 -0
  149. package/dist/primitives/tree/Tree.d.ts +56 -0
  150. package/dist/primitives/tree/Tree.js +74 -0
  151. package/dist/primitives/tree/index.d.ts +1 -0
  152. package/dist/primitives/tree/index.js +3 -0
  153. package/dist/primitives/value/Avatar.d.ts +16 -0
  154. package/dist/primitives/value/Avatar.js +91 -0
  155. package/dist/primitives/value/Copyable.d.ts +11 -0
  156. package/dist/primitives/value/Copyable.js +27 -6
  157. package/dist/primitives/value/Fecha.js +10 -1
  158. package/dist/primitives/value/Person.d.ts +6 -51
  159. package/dist/primitives/value/Person.js +9 -148
  160. package/dist/primitives/value/ProgressBar.d.ts +31 -0
  161. package/dist/primitives/value/ProgressBar.js +53 -0
  162. package/dist/primitives/value/Relation.d.ts +22 -5
  163. package/dist/primitives/value/Relation.js +42 -14
  164. package/dist/primitives/value/Totals.d.ts +102 -7
  165. package/dist/primitives/value/Totals.js +52 -2
  166. package/dist/primitives/value/Value.d.ts +0 -37
  167. package/dist/primitives/value/Value.js +0 -39
  168. package/dist/primitives/value/contact.d.ts +30 -0
  169. package/dist/primitives/value/contact.js +51 -0
  170. package/dist/primitives/value/index.d.ts +5 -4
  171. package/dist/primitives/value/index.js +5 -4
  172. package/dist/tokens.css +179 -7
  173. package/dist/views/list/List.d.ts +32 -3
  174. package/dist/views/list/List.js +51 -7
  175. package/dist/views/list/ListView.d.ts +1 -1
  176. package/dist/views/list/ListView.js +70 -13
  177. package/dist/views/list/columns.js +8 -1
  178. package/dist/views/list/derive.d.ts +12 -1
  179. package/dist/views/list/derive.js +29 -3
  180. package/dist/views/list/presentations.d.ts +5 -2
  181. package/dist/views/list/presentations.js +35 -3
  182. package/dist/views/list/types.d.ts +57 -1
  183. package/dist/views/list/useNarrowList.d.ts +10 -0
  184. package/dist/views/list/useNarrowList.js +20 -6
  185. package/dist/views/record/Record.d.ts +41 -8
  186. package/dist/views/record/Record.js +113 -28
  187. package/dist/views/record/index.d.ts +1 -1
  188. package/package.json +15 -4
  189. package/dist/components/chatter/Chatter.d.ts +0 -161
  190. package/dist/components/chatter/Chatter.js +0 -232
  191. package/dist/components/chatter/index.d.ts +0 -3
  192. package/dist/components/chatter/index.js +0 -4
  193. package/dist/components/navigation/CommandPalette.d.ts +0 -40
  194. package/dist/components/navigation/CommandPalette.js +0 -114
  195. package/dist/components/navigation/commands.d.ts +0 -30
  196. package/dist/components/navigation/commands.js +0 -30
  197. /package/dist/components/{chatter → activity}/Timeline.d.ts +0 -0
  198. /package/dist/components/{chatter → activity}/Timeline.js +0 -0
@@ -10,6 +10,9 @@ export const ENGLISH_COPY = {
10
10
  sheet: "Sheet",
11
11
  report: "Report",
12
12
  pivot: "Pivot",
13
+ calendar: "Calendar",
14
+ gantt: "Gantt",
15
+ timeline: "Planning",
13
16
  chart: "Chart",
14
17
  group: "How to view",
15
18
  },
@@ -31,6 +34,7 @@ export const ENGLISH_COPY = {
31
34
  named: "Select {name}",
32
35
  more: "More actions",
33
36
  moreOf: "More actions for {name}",
37
+ allMatching: "Select all {count} that match",
34
38
  },
35
39
  pager: {
36
40
  size: "Rows per page",
@@ -49,6 +53,12 @@ export const ENGLISH_COPY = {
49
53
  saving: "Saving…",
50
54
  discard: "Discard",
51
55
  failed: "failed",
56
+ notices: "Notices about this record",
57
+ noticeOne: "{count} notice",
58
+ noticeMany: "{count} notices",
59
+ blocking: "What is wrong with this record",
60
+ created: "Created by {by} · {at}",
61
+ updated: "Last changed by {by} · {at}",
52
62
  },
53
63
  shell: {
54
64
  modules: "All modules",
@@ -61,7 +71,6 @@ export const ENGLISH_COPY = {
61
71
  closePreview: "Close preview",
62
72
  account: "My account",
63
73
  openAsPanel: "Open as panel",
64
- commandPalette: "Command palette",
65
74
  },
66
75
  field: {
67
76
  drop: "Drop a file here, or choose one.",
@@ -77,6 +86,7 @@ export const ENGLISH_COPY = {
77
86
  },
78
87
  choice: {
79
88
  noResults: "No results",
89
+ search: "Search",
80
90
  },
81
91
  search: {
82
92
  tools: "Filter, group and favorites",
@@ -89,6 +99,10 @@ export const ENGLISH_COPY = {
89
99
  or: "or",
90
100
  groupedBy: "grouped by",
91
101
  narrowedBy: "showing",
102
+ moreFacets: "+{count}",
103
+ fewerFacets: "show less",
104
+ removeGrouping: "Stop grouping",
105
+ clearAll: "Clear every filter and grouping",
92
106
  switchJoin: "All of them, or any of them",
93
107
  joins: { all: "all", any: "any", none: "none" },
94
108
  notWord: "not",
@@ -119,6 +133,7 @@ export const ENGLISH_COPY = {
119
133
  retry: "Try again",
120
134
  },
121
135
  table: {
136
+ add: "Add",
122
137
  row: "row",
123
138
  rows: "rows",
124
139
  yes: "yes",
@@ -134,8 +149,12 @@ export const ENGLISH_COPY = {
134
149
  list: {
135
150
  empty: "There is nothing here yet.",
136
151
  emptyFiltered: "Nothing matches what is on.",
152
+ countOne: "1 record",
153
+ count: "{count} records",
154
+ peek: "Quick look",
155
+ open: "Open",
137
156
  },
138
- chatter: {
157
+ activity: {
139
158
  bySystem: "the system",
140
159
  more: "show the whole error",
141
160
  less: "show less",
@@ -146,13 +165,26 @@ export const ENGLISH_COPY = {
146
165
  recipients: "Who receives it",
147
166
  noRecipients: "nobody to send it to yet",
148
167
  messagePlaceholder: "Write a message…",
149
- empty: "Nothing has happened here yet.",
150
- history: "history",
168
+ emptyMessages: "Nobody has written here yet.",
169
+ emptyEvents: "Nothing has been logged yet.",
170
+ title: "Activity",
151
171
  open: "Open the {label}",
152
172
  fold: "Fold the {label}",
153
- tabAll: "all",
154
- tabMessages: "messages",
155
- tabEvents: "events",
173
+ alerts: "Notices",
174
+ conversation: "Conversation",
175
+ history: "History",
176
+ viewTimeline: "Timeline",
177
+ moreAlerts: "Show {count} more",
178
+ fewerAlerts: "Show fewer",
179
+ filters: "Show",
180
+ filterAll: "All",
181
+ filterConversation: "Messages",
182
+ filterNotes: "Notes",
183
+ filterEvents: "Events",
184
+ today: "Today",
185
+ yesterday: "Yesterday",
186
+ emptyFilter: "Nothing of this kind yet.",
187
+ goTo: "Go to {owner}",
156
188
  send: "Send",
157
189
  sending: "Sending…",
158
190
  cancel: "Cancel",
@@ -161,6 +193,8 @@ export const ENGLISH_COPY = {
161
193
  label: "Copy",
162
194
  done: "Copied",
163
195
  failed: "Could not copy",
196
+ field: "Copy «{label}»",
197
+ empty: "Nothing to copy",
164
198
  },
165
199
  sorting: {
166
200
  label: "Sort",
@@ -217,8 +251,11 @@ export const ENGLISH_COPY = {
217
251
  },
218
252
  editable: {
219
253
  add: "Add a line",
254
+ addRow: "Add a row",
220
255
  empty: "No lines yet.",
221
256
  remove: "Remove the line",
257
+ reorder: "Move the row",
258
+ reorderHint: "Drag it, or Alt + ↑ / ↓",
222
259
  },
223
260
  picker: {
224
261
  placeholder: "pick one…",
@@ -228,7 +265,19 @@ export const ENGLISH_COPY = {
228
265
  more: "{count} more",
229
266
  refine: "— narrow the filter",
230
267
  open: "Open",
231
- browseAll: "see all…",
268
+ browseAll: "Search more…",
269
+ create: "Create «{name}»",
270
+ createAndEdit: "Create and edit…",
271
+ matched: "matches",
272
+ loadingMore: "loading more…",
273
+ openIn: {
274
+ modal: "Open in a modal",
275
+ peek: "Quick look",
276
+ page: "Open as the page",
277
+ side: "Open beside",
278
+ window: "Open in a window",
279
+ },
280
+ openMore: "Open in…",
232
281
  },
233
282
  cell: {
234
283
  missing: "missing",
@@ -307,14 +356,20 @@ export const ENGLISH_COPY = {
307
356
  total: "Total",
308
357
  rows: "rows",
309
358
  open: "Open {row} × {column}",
359
+ measures: "Measures",
360
+ rowsAxis: "Rows",
361
+ columnsAxis: "Columns",
362
+ addLevel: "Add to {axis}",
363
+ removeLevel: "Remove {level}",
364
+ swap: "Swap rows and columns",
365
+ download: "Download",
366
+ fromSearch: "from the search's grouping",
310
367
  },
311
368
  person: {
312
369
  unassigned: "unassigned",
313
- contact: "Contact",
314
370
  email: "Write an email",
315
371
  call: "Call",
316
372
  whatsapp: "WhatsApp",
317
- open: "Open profile",
318
373
  },
319
374
  lines: {
320
375
  add: "Add a line",
@@ -323,6 +378,10 @@ export const ENGLISH_COPY = {
323
378
  remove: "Remove line",
324
379
  empty: "No lines yet.",
325
380
  done: "Done",
381
+ addSection: "Add a section",
382
+ addNote: "Add a note",
383
+ section: "Section",
384
+ note: "Note",
326
385
  },
327
386
  lineItems: {
328
387
  one: "{count} line",
@@ -334,6 +393,50 @@ export const ENGLISH_COPY = {
334
393
  undo: "Undo",
335
394
  table: "Lines",
336
395
  },
396
+ priority: {
397
+ label: "Priority",
398
+ level: "{value} of {max}",
399
+ none: "no priority",
400
+ },
401
+ board: {
402
+ emptyLane: "Nothing in this stage.",
403
+ moveHint: "Drag it, or Alt + ← / → to move it to another stage",
404
+ moved: "{name} moved to {column}",
405
+ quickCreate: "Quick create in {column}",
406
+ quickPlaceholder: "Name… (Enter creates)",
407
+ fold: "Fold {column}",
408
+ unfold: "Unfold {column}",
409
+ addColumn: "Add a stage",
410
+ addColumnPlaceholder: "Stage name… (Enter adds)",
411
+ },
412
+ timeline: {
413
+ prev: "Previous",
414
+ next: "Next",
415
+ today: "Today",
416
+ goTo: "Go to a date",
417
+ zoom: "Zoom",
418
+ zoomIn: "Zoom in",
419
+ zoomOut: "Zoom out",
420
+ fullscreen: "Full screen",
421
+ exitFullscreen: "Exit full screen",
422
+ scale: "Scale",
423
+ scales: { day: "Day", week: "Week", month: "Month", year: "Year" },
424
+ moveHint: "Drag it to move it, its right edge to stretch it; Alt + arrows from the keyboard",
425
+ moved: "{name}: {range}",
426
+ create: "Create in {row} · {at}",
427
+ },
428
+ kanbanState: {
429
+ label: "State",
430
+ normal: "In progress",
431
+ done: "Ready for the next stage",
432
+ blocked: "Blocked",
433
+ },
434
+ activityState: {
435
+ none: "No activities",
436
+ overdue: "Overdue",
437
+ today: "Due today",
438
+ planned: "Planned",
439
+ },
337
440
  relation: {
338
441
  open: "Open",
339
442
  none: "Not set",
@@ -341,6 +444,15 @@ export const ENGLISH_COPY = {
341
444
  relationCard: {
342
445
  summary: "Summary of {name}",
343
446
  },
447
+ totals: {
448
+ less: "less",
449
+ details: "Details: {label}",
450
+ open: "Open",
451
+ unlink: "Unlink",
452
+ credits: "Outstanding credits",
453
+ apply: "Apply",
454
+ applyCredit: "Apply {label}",
455
+ },
344
456
  inlineEdit: {
345
457
  addTag: "Add…",
346
458
  createTag: "Create «{name}»",
@@ -352,6 +464,9 @@ export const ENGLISH_COPY = {
352
464
  light: "Light",
353
465
  dark: "Dark",
354
466
  },
467
+ tree: {
468
+ empty: "Nothing here yet.",
469
+ },
355
470
  assist: {
356
471
  assistant: "Assistant",
357
472
  suggests: "suggests",
@@ -430,7 +545,7 @@ export function mergeCopy(over) {
430
545
  ops: { ...ENGLISH_COPY.ops, ...over.ops },
431
546
  sorting: { ...ENGLISH_COPY.sorting, ...over.sorting },
432
547
  copyable: { ...ENGLISH_COPY.copyable, ...over.copyable },
433
- chatter: { ...ENGLISH_COPY.chatter, ...over.chatter },
548
+ activity: { ...ENGLISH_COPY.activity, ...over.activity },
434
549
  editable: { ...ENGLISH_COPY.editable, ...over.editable },
435
550
  picker: { ...ENGLISH_COPY.picker, ...over.picker },
436
551
  cell: { ...ENGLISH_COPY.cell, ...over.cell },
@@ -442,10 +557,17 @@ export function mergeCopy(over) {
442
557
  person: { ...ENGLISH_COPY.person, ...over.person },
443
558
  lines: { ...ENGLISH_COPY.lines, ...over.lines },
444
559
  lineItems: { ...ENGLISH_COPY.lineItems, ...over.lineItems },
560
+ priority: { ...ENGLISH_COPY.priority, ...over.priority },
561
+ board: { ...ENGLISH_COPY.board, ...over.board },
562
+ kanbanState: { ...ENGLISH_COPY.kanbanState, ...over.kanbanState },
563
+ timeline: { ...ENGLISH_COPY.timeline, ...over.timeline },
564
+ activityState: { ...ENGLISH_COPY.activityState, ...over.activityState },
445
565
  relation: { ...ENGLISH_COPY.relation, ...over.relation },
446
566
  relationCard: { ...ENGLISH_COPY.relationCard, ...over.relationCard },
567
+ totals: { ...ENGLISH_COPY.totals, ...over.totals },
447
568
  inlineEdit: { ...ENGLISH_COPY.inlineEdit, ...over.inlineEdit },
448
569
  theme: { ...ENGLISH_COPY.theme, ...over.theme },
570
+ tree: { ...ENGLISH_COPY.tree, ...over.tree },
449
571
  assist: { ...ENGLISH_COPY.assist, ...over.assist },
450
572
  };
451
573
  }
@@ -2,7 +2,7 @@ export { currentCopy, currentCopyLocale, ENGLISH_COPY, fillCopy, installCopy, me
2
2
  export { byDensity, type Density, DensityProvider, useDensity, } from "./density.js";
3
3
  export { bySurface, SurfaceProvider, useSurface } from "./surface.js";
4
4
  export { applyTheme, isTheme, type ResolvedTheme, resolveTheme, type Theme, THEME_ATTRIBUTE, ThemeProvider, type ThemeProviderProps, THEMES, useTheme, } from "./theme.js";
5
- export type { Size, Surface, Tone } from "./types.js";
5
+ export type { OpenTarget, Size, Surface, Tone } from "./types.js";
6
6
  /** El castellano del sistema, para quien lo quiera instalar entero. */
7
7
  export { SPANISH_COPY } from "./copy.es.js";
8
8
  export { flatten, loose, pick, pickAll, propsOf, slot, slotOf, type Slotted, } from "./slots.js";
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Where a typed search falls inside a text — «tería» inside «Ferretería» — so a list can SHOW
3
+ * why each option is there.
4
+ *
5
+ * Context: a picker filters accent- and case-insensitively (React Aria's `useFilter`, base
6
+ * sensitivity): «ferreteria» finds «Ferretería». Highlighting has to agree with it, or the
7
+ * option is listed with nothing marked and reads as a wrong match. So the text is folded the
8
+ * same way — decomposed, marks dropped, lower-cased in the locale — while remembering which
9
+ * original character each folded one came from, and the spans are cut on the ORIGINAL text:
10
+ * what is drawn keeps its accents.
11
+ */
12
+ export type MatchSpan = {
13
+ text: string;
14
+ hit: boolean;
15
+ };
16
+ /** The text cut into what matched the query and what did not, in order. An empty query (or
17
+ * one that does not occur) is one span with no hit. */
18
+ export declare function matchSpans(text: string, query: string, locale?: string): MatchSpan[];
19
+ /** Whether the query occurs in the text, folded the same way as `matchSpans`. */
20
+ export declare function matches(text: string, query: string, locale?: string): boolean;
21
+ /** The word of a hidden search text where the query fell — the code «CEM-IP30» out of
22
+ * «CEM-IP30 7771234000017» — to say why an option whose name does not match is listed. */
23
+ export declare function matchedWord(text: string, query: string, locale?: string): string | null;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Where a typed search falls inside a text — «tería» inside «Ferretería» — so a list can SHOW
3
+ * why each option is there.
4
+ *
5
+ * Context: a picker filters accent- and case-insensitively (React Aria's `useFilter`, base
6
+ * sensitivity): «ferreteria» finds «Ferretería». Highlighting has to agree with it, or the
7
+ * option is listed with nothing marked and reads as a wrong match. So the text is folded the
8
+ * same way — decomposed, marks dropped, lower-cased in the locale — while remembering which
9
+ * original character each folded one came from, and the spans are cut on the ORIGINAL text:
10
+ * what is drawn keeps its accents.
11
+ */
12
+ function fold(char, locale) {
13
+ return char.normalize("NFD").replace(/\p{M}/gu, "").toLocaleLowerCase(locale);
14
+ }
15
+ /** The text cut into what matched the query and what did not, in order. An empty query (or
16
+ * one that does not occur) is one span with no hit. */
17
+ export function matchSpans(text, query, locale) {
18
+ const wanted = [...query.trim()].map((char) => fold(char, locale)).join("");
19
+ if (wanted === "")
20
+ return [{ text, hit: false }];
21
+ /* `origin[i]` is where, in the original text, folded character i came from. One more entry
22
+ at the end maps «the end of the folded text» to the end of the original. */
23
+ let folded = "";
24
+ const origin = [];
25
+ let at = 0;
26
+ for (const char of text) {
27
+ const piece = fold(char, locale);
28
+ for (let k = 0; k < piece.length; k += 1)
29
+ origin.push(at);
30
+ folded += piece;
31
+ at += char.length;
32
+ }
33
+ origin.push(text.length);
34
+ const spans = [];
35
+ let cursor = 0;
36
+ let found = folded.indexOf(wanted);
37
+ while (found !== -1) {
38
+ const start = origin[found] ?? text.length;
39
+ const end = origin[found + wanted.length] ?? text.length;
40
+ if (start > cursor)
41
+ spans.push({ text: text.slice(cursor, start), hit: false });
42
+ if (end > start)
43
+ spans.push({ text: text.slice(start, end), hit: true });
44
+ cursor = Math.max(cursor, end);
45
+ found = folded.indexOf(wanted, found + wanted.length);
46
+ }
47
+ if (cursor < text.length)
48
+ spans.push({ text: text.slice(cursor), hit: false });
49
+ return spans.length === 0 ? [{ text, hit: false }] : spans;
50
+ }
51
+ /** Whether the query occurs in the text, folded the same way as `matchSpans`. */
52
+ export function matches(text, query, locale) {
53
+ return matchSpans(text, query, locale).some((span) => span.hit);
54
+ }
55
+ /** The word of a hidden search text where the query fell — the code «CEM-IP30» out of
56
+ * «CEM-IP30 7771234000017» — to say why an option whose name does not match is listed. */
57
+ export function matchedWord(text, query, locale) {
58
+ for (const word of text.split(/\s+/)) {
59
+ if (word !== "" && matches(word, query, locale))
60
+ return word;
61
+ }
62
+ return null;
63
+ }
@@ -52,7 +52,7 @@ export declare function slotOf<Name extends string>(node: ReactNode): Name | und
52
52
  * medio del árbol —lo que escribe cualquiera que ponga dos ranuras bajo un
53
53
  * condicional— escondería las ranuras que tiene adentro.
54
54
  */
55
- export declare function flatten(children: ReactNode): ReactNode[];
55
+ export declare function flatten(children: ReactNode, prefix?: string): ReactNode[];
56
56
  /** La primera ranura de ese nombre. */
57
57
  export declare function pick<Name extends string>(nodes: readonly ReactNode[], name: Name): ReactNode | undefined;
58
58
  /** Todas las ranuras de ese nombre, en el orden en que se escribieron. Lo usa el
@@ -1,4 +1,4 @@
1
- import { Children, Fragment, isValidElement } from "react";
1
+ import { Children, cloneElement, Fragment, isValidElement } from "react";
2
2
  /**
3
3
  * Marca un componente como ranura y lo devuelve.
4
4
  *
@@ -26,11 +26,16 @@ export function slotOf(node) {
26
26
  * medio del árbol —lo que escribe cualquiera que ponga dos ranuras bajo un
27
27
  * condicional— escondería las ranuras que tiene adentro.
28
28
  */
29
- export function flatten(children) {
29
+ export function flatten(children, prefix = "") {
30
30
  const out = [];
31
31
  for (const child of Children.toArray(children)) {
32
32
  if (isValidElement(child) && child.type === Fragment) {
33
- out.push(...flatten(child.props.children));
33
+ /* The fragment's children are keyed from zero again («.0», «.1»…): without the
34
+ fragment's own key in front they collide with their new siblings. */
35
+ out.push(...flatten(child.props.children, `${prefix}${String(child.key)}/`));
36
+ }
37
+ else if (prefix !== "" && isValidElement(child)) {
38
+ out.push(cloneElement(child, { key: `${prefix}${String(child.key)}` }));
34
39
  }
35
40
  else {
36
41
  out.push(child);
@@ -21,3 +21,10 @@ export type Tone = "neutral" | "info" | "good" | "warn" | "bad" | "accent";
21
21
  * Three and not five: a fourth intermediate step gets picked out of habit and
22
22
  * stops meaning a place. */
23
23
  export type Size = "sm" | "md" | "lg";
24
+ /**
25
+ * WHERE a record opens, in the words a workspace (the composer) uses: the page (with its crumb
26
+ * back), a modal over the surface that asked, a peek (a drawer, reading without leaving), a
27
+ * side panel, a floating window; web-ui only SAYS which one the person chose — opening is the
28
+ * app's (`api.open(ref, { to })`). See the guide «Cómo abrimos las cosas».
29
+ */
30
+ export type OpenTarget = "modal" | "peek" | "page" | "side" | "window";
@@ -12,39 +12,3 @@
12
12
  * `list/`, even if it is shared across its three files.
13
13
  * ==================================================================== */
14
14
  export {};
15
- /* ==================================================================== *
16
- * THE SYSTEM'S TWO API CONVENTIONS
17
- *
18
- * They are here and not in the README because a convention that lives in the
19
- * documentation breaks in the first component written in a hurry. Here it is
20
- * read by whoever is going to write the next component.
21
- *
22
- * ── 1. How a callback is named ──────────────────────────────────────
23
- *
24
- * onXChange the component proposes a NEW value for `x`, and whoever
25
- * uses it decides whether to accept it. It ALWAYS goes with
26
- * the `x` prop.
27
- * → onTermsChange(terms), onSelectedChange(set), onSortChange(sort)
28
- *
29
- * onX something happened that is not a value change: an intent.
30
- * → onClose(), onOpen(), onPromote(), onBrowseAll()
31
- *
32
- * The test for knowing which one: **is there a prop with that name next to
33
- * it?** If `value` exists, it is `onValueChange`. If not, it is an event and
34
- * goes without a suffix.
35
- *
36
- * ── 2. Controlled, always ───────────────────────────────────────────
37
- *
38
- * Any state the consumer might want to read, store in the URL or restore on
39
- * reload is CONTROLLED: `value` + `onValueChange`, with no internal memory.
40
- * That is what lets the entire workspace live in the hash.
41
- *
42
- * The exception, and there is only one: **what dies with the component and
43
- * nobody cares about afterwards.** An open menu, an expanded filter panel, the
44
- * half-typed text in the search box. That does keep state inside, because
45
- * exposing it would force every consumer to declare a `useState` for something
46
- * they are never going to read.
47
- *
48
- * Put another way: if it makes sense to send it to a colleague over chat so
49
- * they see the same thing, it is controlled.
50
- * ==================================================================== */
@@ -1,4 +1,4 @@
1
- export { Block, type BlockProps, type BlockStatus, Rule, SectionHeader, } from "./Block.js";
1
+ export { Block, type BlockProps, type BlockStatus, Rule, } from "./Block.js";
2
2
  export { FullWidth, SectionGrid } from "./SectionGrid.js";
3
3
  export { Line } from "./Line.js";
4
4
  export { Step, type StepProps, Steps, type StepsProps, useSteps, } from "./Steps.js";
@@ -1,5 +1,5 @@
1
1
  /* The structure of a view: where each section starts and ends. */
2
- export { Block, Rule, SectionHeader, } from "./Block.js";
2
+ export { Block, Rule, } from "./Block.js";
3
3
  export { FullWidth, SectionGrid } from "./SectionGrid.js";
4
4
  /* La línea de tres zonas: lo que centra el centro contra la LÍNEA y no contra
5
5
  lo que sobra. La usan las dos bandas — la del registro y la de la lista. */
@@ -31,7 +31,7 @@ export declare function Thumb({ src, alt, icon: Icon, size, }: {
31
31
  * card. The second line wraps or truncates (`wrap`); the first always truncates, with the full
32
32
  * text on hover.
33
33
  */
34
- export declare function CellStack({ primary, secondary, media, wrap, }: {
34
+ export declare function CellStack({ primary, secondary, media, avatar, wrap, }: {
35
35
  /** What the row is — the name. In ink, one line. */
36
36
  primary: ReactNode;
37
37
  /** What tells it apart — a description, a code, a reference. Small and quiet. */
@@ -42,6 +42,12 @@ export declare function CellStack({ primary, secondary, media, wrap, }: {
42
42
  alt?: string;
43
43
  icon?: LucideIcon;
44
44
  };
45
+ /** A person or a company instead of `media`: its round face — the photo, or the initials in
46
+ * the color it has everywhere. The same contract as a list row's `avatar`. */
47
+ avatar?: {
48
+ name: string;
49
+ src?: string;
50
+ };
45
51
  /** Let the second line wrap (a description) instead of truncating (a code). */
46
52
  wrap?: boolean;
47
53
  }): import("react").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Avatar } from "../value/Avatar.js";
2
3
  /**
3
4
  * A thumbnail — the photo of a product, the logo of a customer — or, when there is none, its
4
5
  * icon on a quiet tile. One size per context so a column of them lines up.
@@ -28,6 +29,8 @@ export function Thumb({ src, alt, icon: Icon, size = "md", }) {
28
29
  * card. The second line wraps or truncates (`wrap`); the first always truncates, with the full
29
30
  * text on hover.
30
31
  */
31
- export function CellStack({ primary, secondary, media, wrap = false, }) {
32
- return (_jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [media === undefined ? null : (_jsx(Thumb, { size: "md", ...(media.src === undefined ? {} : { src: media.src }), ...(media.alt === undefined ? {} : { alt: media.alt }), ...(media.icon === undefined ? {} : { icon: media.icon }) })), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate text-meta font-medium text-ink", ...(typeof primary === "string" ? { title: primary } : {}), children: primary }), secondary === undefined ? null : (_jsx("span", { className: `text-micro text-muted ${wrap ? "line-clamp-2" : "truncate"}`, ...(typeof secondary === "string" ? { title: secondary } : {}), children: secondary }))] })] }));
32
+ export function CellStack({ primary, secondary, media, avatar, wrap = false, }) {
33
+ return (_jsxs("span", { className: "flex min-w-0 items-center gap-2.5", children: [avatar !== undefined ? (
34
+ /* The name is written beside it: the photo's `alt` would say it twice. */
35
+ _jsx("span", { "aria-hidden": true, className: "flex shrink-0", children: _jsx(Avatar, { name: avatar.name, size: "lg", ...(avatar.src === undefined ? {} : { src: avatar.src }) }) })) : media === undefined ? null : (_jsx(Thumb, { size: "md", ...(media.src === undefined ? {} : { src: media.src }), ...(media.alt === undefined ? {} : { alt: media.alt }), ...(media.icon === undefined ? {} : { icon: media.icon }) })), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate text-meta font-medium text-ink", ...(typeof primary === "string" ? { title: primary } : {}), children: primary }), secondary === undefined ? null : (_jsx("span", { className: `text-micro text-muted ${wrap ? "line-clamp-2" : "truncate"}`, ...(typeof secondary === "string" ? { title: secondary } : {}), children: secondary }))] })] }));
33
36
  }
@@ -10,6 +10,9 @@ export type ComboBoxProps = {
10
10
  id?: string;
11
11
  describedBy?: string;
12
12
  invalid?: boolean;
13
+ /** The name of the control when it is NOT inside a `Field` — a cell of an editable table.
14
+ * Inside a field, the field's label names it. */
15
+ "aria-label"?: string;
13
16
  /** Forces the mode. By default it inherits the form's: in read mode it draws the label. */
14
17
  mode?: FormMode;
15
18
  };
@@ -10,7 +10,7 @@ import { Popover } from "../overlay/Popover.js";
10
10
  import { Check, ChevronDown } from "lucide-react";
11
11
  import { ComboBox as AriaComboBox, Input, ListBox, ListBoxItem, Text, useFilter, } from "react-aria-components";
12
12
  /**
13
- * One of many, found by typing: the customer of an invoice, the product of a line.
13
+ * One of a closed list, found by typing: a country, a currency, a tax regime, a unit.
14
14
  *
15
15
  * Context: a `Select` makes you scroll a list you already know the name in; here you type
16
16
  * three letters of it. The filter is React Aria's `contains` in the locale of the copy table
@@ -18,9 +18,13 @@ import { ComboBox as AriaComboBox, Input, ListBox, ListBoxItem, Text, useFilter,
18
18
  * The value is the option's `value` string — what the backend stores — never React Aria's
19
19
  * `Key`.
20
20
  *
21
- * It is not `Picker`: that one chooses a RECORD among thousands, with metadata rows, a cap
22
- * and a "see more". This is a closed list already in memory — tens to a few hundred — where
23
- * one muted line under the name (a tax id, a city) is enough to tell two apart.
21
+ * The four ways to choose, and which is which:
22
+ * - `Select` a short closed list (a handful): open it and read it.
23
+ * - `ComboBox` a long closed list already in memory (tens to a few hundred): type three
24
+ * letters; one muted line under the name is enough to tell two apart.
25
+ * - `Picker` a RECORD — a customer, a product — among thousands: rows with face, facts
26
+ * and widgets, «Buscar más…», create, and opening the chosen one.
27
+ * - `Suggest` free text that proposes what already exists without forbidding a new one.
24
28
  *
25
29
  * When nothing matches, the list simply closes: an empty floating box tells nothing the
26
30
  * unchanged field does not, and the system has no "no results" sentence of its own here.
@@ -37,14 +41,14 @@ export function ComboBox({ mode, ...props }) {
37
41
  to be ABOVE the component that asks for it. */
38
42
  return (_jsx(AriaLocale, { children: _jsx(EditableComboBox, { ...props }) }));
39
43
  }
40
- function EditableComboBox({ value, onChange, options, placeholder, disabled = false, id: ownId, describedBy: ownDescribedBy, invalid: ownInvalid, }) {
44
+ function EditableComboBox({ value, onChange, options, placeholder, disabled = false, id: ownId, describedBy: ownDescribedBy, invalid: ownInvalid, "aria-label": ariaLabel, }) {
41
45
  const { id, labelledBy, describedBy, invalid } = useFieldIds({
42
46
  id: ownId,
43
47
  describedBy: ownDescribedBy,
44
48
  invalid: ownInvalid,
45
49
  });
46
50
  const { contains } = useFilter({ sensitivity: "base" });
47
- return (_jsxs(AriaComboBox, { id: id, "aria-labelledby": labelledBy, "aria-describedby": describedBy,
51
+ return (_jsxs(AriaComboBox, { id: id, "aria-labelledby": labelledBy, "aria-label": ariaLabel, "aria-describedby": describedBy,
48
52
  /* `defaultItems` and not `items`: with `items` React Aria hands the filtering to the
49
53
  consumer. These are the same options every render — only the filtering is React
50
54
  Aria's. */
@@ -0,0 +1,14 @@
1
+ export type KanbanStateValue = "normal" | "done" | "blocked";
2
+ /**
3
+ * Odoo's kanban state — the traffic light on a card: in progress, ready for the next stage,
4
+ * blocked.
5
+ *
6
+ * Context: it answers «can this move on?» without opening the record, and the stage alone does
7
+ * not say it — two cards in «propuesta», one waiting on the customer, one ready to send. A dot
8
+ * never goes alone (docs/PRINCIPLES.md §3): its word is the button's name and title, and the
9
+ * list it opens says all three. Without `onChange` it only shows.
10
+ */
11
+ export declare function KanbanState({ value, onChange, }: {
12
+ value: KanbanStateValue;
13
+ onChange?: (next: KanbanStateValue) => void;
14
+ }): import("react").JSX.Element;
@@ -0,0 +1,37 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useUiCopy } from "../../foundations/copy.js";
4
+ import { PopoverTrigger } from "../overlay/PopoverTrigger.js";
5
+ const ORDER = ["normal", "done", "blocked"];
6
+ const FILL = {
7
+ normal: "bg-line-strong",
8
+ done: "bg-good",
9
+ blocked: "bg-bad",
10
+ };
11
+ /** The dot as `PopoverTrigger`'s opener: it hands over `expanded` / `haspopup`, which a bare
12
+ * `<button>` would pass to the DOM as unknown attributes. */
13
+ function DotButton({ expanded, haspopup, ...rest }) {
14
+ return _jsx("button", { type: "button", "aria-expanded": expanded, "aria-haspopup": haspopup, ...rest });
15
+ }
16
+ /**
17
+ * Odoo's kanban state — the traffic light on a card: in progress, ready for the next stage,
18
+ * blocked.
19
+ *
20
+ * Context: it answers «can this move on?» without opening the record, and the stage alone does
21
+ * not say it — two cards in «propuesta», one waiting on the customer, one ready to send. A dot
22
+ * never goes alone (docs/PRINCIPLES.md §3): its word is the button's name and title, and the
23
+ * list it opens says all three. Without `onChange` it only shows.
24
+ */
25
+ export function KanbanState({ value, onChange, }) {
26
+ const copy = useUiCopy();
27
+ const words = copy.kanbanState;
28
+ const said = `${words.label}: ${words[value]}`;
29
+ const dot = (state) => (_jsx("span", { "aria-hidden": true, className: `block size-2.5 rounded-pill ${FILL[state]}` }));
30
+ if (onChange === undefined) {
31
+ return (_jsx("span", { role: "img", "aria-label": said, title: said, className: "inline-flex p-1", children: dot(value) }));
32
+ }
33
+ return (_jsx(PopoverTrigger, { label: words.label, placement: "bottom end", trigger: _jsx(DotButton, { "aria-label": said, title: said, className: "relative z-10 inline-flex rounded-pill p-1 transition-colors duration-(--duration-instant) hover:bg-ink/8 focus-visible:outline-2 focus-visible:outline-primary", children: dot(value) }), children: (close) => (_jsx("div", { role: "radiogroup", "aria-label": words.label, className: "flex flex-col p-1", children: ORDER.map((state) => (_jsxs("button", { type: "button", role: "radio", "aria-checked": state === value, onClick: () => {
34
+ onChange(state);
35
+ close();
36
+ }, className: `flex items-center gap-2 rounded-control px-2 py-1.5 text-left text-meta text-ink transition-colors duration-(--duration-instant) hover:bg-ink/5 ${state === value ? "font-medium" : ""}`, children: [dot(state), words[state]] }, state))) })) }));
37
+ }