@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.
- package/README.md +40 -13
- package/dist/components/activity/Activity.d.ts +69 -0
- package/dist/components/activity/Activity.js +279 -0
- package/dist/components/activity/ActivityBadge.d.ts +16 -0
- package/dist/components/activity/ActivityBadge.js +29 -0
- package/dist/components/{chatter → activity}/Messages.d.ts +2 -2
- package/dist/components/{chatter → activity}/Messages.js +9 -6
- package/dist/components/activity/index.d.ts +4 -0
- package/dist/components/activity/index.js +5 -0
- package/dist/components/assist/AssistMark.d.ts +3 -3
- package/dist/components/assist/AssistMark.js +1 -1
- package/dist/components/assist/assist.d.ts +1 -1
- package/dist/components/assist/assist.js +1 -1
- package/dist/components/calendar/RecordCalendar.d.ts +48 -0
- package/dist/components/calendar/RecordCalendar.js +101 -0
- package/dist/components/calendar/index.d.ts +1 -0
- package/dist/components/calendar/index.js +1 -0
- package/dist/components/form/Sheet.d.ts +4 -0
- package/dist/components/form/Sheet.js +16 -5
- package/dist/components/gantt/RecordGantt.d.ts +44 -0
- package/dist/components/gantt/RecordGantt.js +110 -0
- package/dist/components/gantt/index.d.ts +1 -0
- package/dist/components/gantt/index.js +1 -0
- package/dist/components/index.d.ts +4 -1
- package/dist/components/index.js +4 -1
- package/dist/components/lines/LineItems.d.ts +45 -5
- package/dist/components/lines/LineItems.js +106 -18
- package/dist/components/listing/BoardColumns.d.ts +39 -0
- package/dist/components/listing/BoardColumns.js +138 -0
- package/dist/components/listing/Listing.js +1 -1
- package/dist/components/listing/ListingBar.d.ts +46 -2
- package/dist/components/listing/ListingBar.js +47 -5
- package/dist/components/listing/PivotExplorer.d.ts +34 -0
- package/dist/components/listing/PivotExplorer.js +86 -0
- package/dist/components/listing/RecordCard.d.ts +6 -8
- package/dist/components/listing/RecordCard.js +13 -7
- package/dist/components/listing/Row.d.ts +25 -2
- package/dist/components/listing/Row.js +30 -13
- package/dist/components/listing/index.d.ts +2 -0
- package/dist/components/listing/index.js +2 -0
- package/dist/components/listing/set.d.ts +1 -1
- package/dist/components/navigation/index.d.ts +0 -2
- package/dist/components/navigation/index.js +2 -3
- package/dist/components/record/RecordAudit.d.ts +17 -0
- package/dist/components/record/RecordAudit.js +27 -0
- package/dist/components/record/RecordHeader.d.ts +27 -17
- package/dist/components/record/RecordHeader.js +64 -20
- package/dist/components/record/RecordNotices.d.ts +37 -0
- package/dist/components/record/RecordNotices.js +75 -0
- package/dist/components/record/RecordRibbon.d.ts +13 -0
- package/dist/components/record/RecordRibbon.js +22 -0
- package/dist/components/record/ThumbBar.js +1 -1
- package/dist/components/record/index.d.ts +2 -0
- package/dist/components/record/index.js +2 -0
- package/dist/components/search/CriteriaChips.d.ts +6 -1
- package/dist/components/search/CriteriaChips.js +71 -20
- package/dist/components/search/SearchBar.d.ts +4 -1
- package/dist/components/search/SearchBar.js +15 -7
- package/dist/components/timeline/RecordTimeline.d.ts +60 -0
- package/dist/components/timeline/RecordTimeline.js +214 -0
- package/dist/components/timeline/TimelineToolbar.d.ts +30 -0
- package/dist/components/timeline/TimelineToolbar.js +31 -0
- package/dist/components/timeline/index.d.ts +3 -0
- package/dist/components/timeline/index.js +3 -0
- package/dist/components/timeline/time.d.ts +43 -0
- package/dist/components/timeline/time.js +135 -0
- package/dist/foundations/copy.d.ts +194 -18
- package/dist/foundations/copy.es.js +142 -15
- package/dist/foundations/copy.js +133 -11
- package/dist/foundations/index.d.ts +1 -1
- package/dist/foundations/match.d.ts +23 -0
- package/dist/foundations/match.js +63 -0
- package/dist/foundations/slots.d.ts +1 -1
- package/dist/foundations/slots.js +8 -3
- package/dist/foundations/types.d.ts +7 -0
- package/dist/foundations/types.js +0 -36
- package/dist/primitives/block/index.d.ts +1 -1
- package/dist/primitives/block/index.js +1 -1
- package/dist/primitives/cell/CellStack.d.ts +7 -1
- package/dist/primitives/cell/CellStack.js +5 -2
- package/dist/primitives/choice/ComboBox.d.ts +3 -0
- package/dist/primitives/choice/ComboBox.js +10 -6
- package/dist/primitives/choice/KanbanState.d.ts +14 -0
- package/dist/primitives/choice/KanbanState.js +37 -0
- package/dist/primitives/choice/Priority.d.ts +20 -0
- package/dist/primitives/choice/Priority.js +41 -0
- package/dist/primitives/choice/SearchField.d.ts +10 -1
- package/dist/primitives/choice/SearchField.js +21 -2
- package/dist/primitives/choice/Slider.d.ts +6 -1
- package/dist/primitives/choice/Slider.js +2 -2
- package/dist/primitives/choice/index.d.ts +2 -0
- package/dist/primitives/choice/index.js +2 -0
- package/dist/primitives/date/Calendar.js +30 -6
- package/dist/primitives/date/DatePicker.d.ts +11 -3
- package/dist/primitives/date/DatePicker.js +12 -8
- package/dist/primitives/date/DateTime.d.ts +35 -0
- package/dist/primitives/date/DateTime.js +100 -0
- package/dist/primitives/date/index.d.ts +1 -0
- package/dist/primitives/date/index.js +4 -2
- package/dist/primitives/dialog/Dialog.d.ts +9 -3
- package/dist/primitives/dialog/Dialog.js +41 -5
- package/dist/primitives/field/DropZone.js +1 -1
- package/dist/primitives/field/Field.d.ts +14 -2
- package/dist/primitives/field/Field.js +25 -14
- package/dist/primitives/field/copy.d.ts +16 -0
- package/dist/primitives/field/copy.js +69 -0
- package/dist/primitives/field/index.d.ts +2 -0
- package/dist/primitives/field/index.js +4 -0
- package/dist/primitives/field/note.d.ts +55 -0
- package/dist/primitives/field/note.js +117 -0
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.js +1 -0
- package/dist/primitives/menu/Menu.d.ts +28 -0
- package/dist/primitives/menu/Menu.js +47 -17
- package/dist/primitives/notice/Callout.js +1 -1
- package/dist/primitives/notice/Flag.d.ts +13 -0
- package/dist/primitives/notice/Flag.js +31 -0
- package/dist/primitives/notice/index.d.ts +2 -1
- package/dist/primitives/notice/index.js +2 -1
- package/dist/primitives/overlay/Preview.d.ts +19 -0
- package/dist/primitives/overlay/Preview.js +69 -0
- package/dist/primitives/overlay/index.d.ts +1 -0
- package/dist/primitives/overlay/index.js +3 -1
- package/dist/primitives/picker/MatchedText.d.ts +10 -0
- package/dist/primitives/picker/MatchedText.js +12 -0
- package/dist/primitives/picker/Picker.d.ts +67 -4
- package/dist/primitives/picker/Picker.js +142 -23
- package/dist/primitives/table/CellCopy.d.ts +20 -0
- package/dist/primitives/table/CellCopy.js +23 -0
- package/dist/primitives/table/DataTable.d.ts +55 -1
- package/dist/primitives/table/DataTable.js +126 -40
- package/dist/primitives/table/EditableTable.d.ts +102 -2
- package/dist/primitives/table/EditableTable.js +287 -32
- package/dist/primitives/table/ReportTable.js +2 -1
- package/dist/primitives/table/RowActions.js +7 -2
- package/dist/primitives/table/SheetTable.d.ts +4 -1
- package/dist/primitives/table/SheetTable.js +38 -5
- package/dist/primitives/table/Table.d.ts +5 -0
- package/dist/primitives/table/Table.js +17 -8
- package/dist/primitives/table/index.d.ts +2 -2
- package/dist/primitives/table/index.js +1 -1
- package/dist/primitives/tabs/Tabs.d.ts +2 -2
- package/dist/primitives/tabs/Tabs.js +1 -1
- package/dist/primitives/tag/Tags.d.ts +2 -0
- package/dist/primitives/tag/Tags.js +2 -1
- package/dist/primitives/tag/TagsField.d.ts +13 -0
- package/dist/primitives/tag/TagsField.js +39 -10
- package/dist/primitives/tag/choices.d.ts +2 -0
- package/dist/primitives/tree/Tree.d.ts +56 -0
- package/dist/primitives/tree/Tree.js +74 -0
- package/dist/primitives/tree/index.d.ts +1 -0
- package/dist/primitives/tree/index.js +3 -0
- package/dist/primitives/value/Avatar.d.ts +16 -0
- package/dist/primitives/value/Avatar.js +91 -0
- package/dist/primitives/value/Copyable.d.ts +11 -0
- package/dist/primitives/value/Copyable.js +27 -6
- package/dist/primitives/value/Fecha.js +10 -1
- package/dist/primitives/value/Person.d.ts +6 -51
- package/dist/primitives/value/Person.js +9 -148
- package/dist/primitives/value/ProgressBar.d.ts +31 -0
- package/dist/primitives/value/ProgressBar.js +53 -0
- package/dist/primitives/value/Relation.d.ts +22 -5
- package/dist/primitives/value/Relation.js +42 -14
- package/dist/primitives/value/Totals.d.ts +102 -7
- package/dist/primitives/value/Totals.js +52 -2
- package/dist/primitives/value/Value.d.ts +0 -37
- package/dist/primitives/value/Value.js +0 -39
- package/dist/primitives/value/contact.d.ts +30 -0
- package/dist/primitives/value/contact.js +51 -0
- package/dist/primitives/value/index.d.ts +5 -4
- package/dist/primitives/value/index.js +5 -4
- package/dist/tokens.css +179 -7
- package/dist/views/list/List.d.ts +32 -3
- package/dist/views/list/List.js +51 -7
- package/dist/views/list/ListView.d.ts +1 -1
- package/dist/views/list/ListView.js +70 -13
- package/dist/views/list/columns.js +8 -1
- package/dist/views/list/derive.d.ts +12 -1
- package/dist/views/list/derive.js +29 -3
- package/dist/views/list/presentations.d.ts +5 -2
- package/dist/views/list/presentations.js +35 -3
- package/dist/views/list/types.d.ts +57 -1
- package/dist/views/list/useNarrowList.d.ts +10 -0
- package/dist/views/list/useNarrowList.js +20 -6
- package/dist/views/record/Record.d.ts +41 -8
- package/dist/views/record/Record.js +113 -28
- package/dist/views/record/index.d.ts +1 -1
- package/package.json +15 -4
- package/dist/components/chatter/Chatter.d.ts +0 -161
- package/dist/components/chatter/Chatter.js +0 -232
- package/dist/components/chatter/index.d.ts +0 -3
- package/dist/components/chatter/index.js +0 -4
- package/dist/components/navigation/CommandPalette.d.ts +0 -40
- package/dist/components/navigation/CommandPalette.js +0 -114
- package/dist/components/navigation/commands.d.ts +0 -30
- package/dist/components/navigation/commands.js +0 -30
- /package/dist/components/{chatter → activity}/Timeline.d.ts +0 -0
- /package/dist/components/{chatter → activity}/Timeline.js +0 -0
package/dist/foundations/copy.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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: "
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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: [
|
|
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
|
|
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
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
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
|
+
}
|