@motifx-community/ui 0.1.0-beta.0 → 0.1.0-beta.2

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.

Potentially problematic release.


This version of @motifx-community/ui might be problematic. Click here for more details.

Files changed (165) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +16 -10
  3. package/dist/components/calendar/Calendar.d.ts +12 -0
  4. package/dist/components/calendar/calendar-props.d.ts +5 -0
  5. package/dist/components/daterangebox/DateRangeBox.d.ts +121 -0
  6. package/dist/components/daterangebox/date-range-box-props.d.ts +35 -0
  7. package/dist/components/daterangebox/date-range-preset.d.ts +6 -0
  8. package/dist/components/daterangebox/date-range.d.ts +2 -0
  9. package/dist/components/daterangebox/index.d.ts +4 -0
  10. package/dist/components/dropdown/DropDown.d.ts +14 -0
  11. package/dist/components/dropdown/drop-down-props.d.ts +5 -0
  12. package/dist/components/fileuploader/FileUploader.d.ts +133 -0
  13. package/dist/components/fileuploader/file-uploader-props.d.ts +46 -0
  14. package/dist/components/fileuploader/files-added-event-args.d.ts +9 -0
  15. package/dist/components/fileuploader/index.d.ts +7 -0
  16. package/dist/components/fileuploader/upload-event-args.d.ts +10 -0
  17. package/dist/components/fileuploader/upload-item.d.ts +12 -0
  18. package/dist/components/fileuploader/upload-mode.d.ts +2 -0
  19. package/dist/components/fileuploader/upload-status.d.ts +2 -0
  20. package/dist/components/loadpanel/LoadPanel.d.ts +70 -0
  21. package/dist/components/loadpanel/index.d.ts +3 -0
  22. package/dist/components/loadpanel/load-panel-props.d.ts +29 -0
  23. package/dist/components/loadpanel/load-panel-target.d.ts +3 -0
  24. package/dist/components/popover/Popover.d.ts +98 -0
  25. package/dist/components/popover/index.d.ts +5 -0
  26. package/dist/components/popover/popover-close-reason.d.ts +2 -0
  27. package/dist/components/popover/popover-closing-event-args.d.ts +8 -0
  28. package/dist/components/popover/popover-props.d.ts +39 -0
  29. package/dist/components/popover/popover-show-on.d.ts +2 -0
  30. package/dist/components/scheduler/view/AgendaView.d.ts +1 -1
  31. package/dist/components/scrollview/ScrollView.d.ts +109 -0
  32. package/dist/components/scrollview/index.d.ts +7 -0
  33. package/dist/components/scrollview/pull-down-event-args.d.ts +9 -0
  34. package/dist/components/scrollview/reach-bottom-event-args.d.ts +9 -0
  35. package/dist/components/scrollview/scroll-event-args.d.ts +7 -0
  36. package/dist/components/scrollview/scroll-view-bars.d.ts +2 -0
  37. package/dist/components/scrollview/scroll-view-direction.d.ts +2 -0
  38. package/dist/components/scrollview/scroll-view-props.d.ts +31 -0
  39. package/dist/components/sortable/Sortable.d.ts +106 -0
  40. package/dist/components/sortable/index.d.ts +5 -0
  41. package/dist/components/sortable/sortable-drag-event-args.d.ts +15 -0
  42. package/dist/components/sortable/sortable-drop-event-args.d.ts +11 -0
  43. package/dist/components/sortable/sortable-orientation.d.ts +2 -0
  44. package/dist/components/sortable/sortable-props.d.ts +34 -0
  45. package/dist/components/stepper/Stepper.d.ts +121 -0
  46. package/dist/components/stepper/Wizard.d.ts +112 -0
  47. package/dist/components/stepper/WizardStep.d.ts +44 -0
  48. package/dist/components/stepper/index.d.ts +13 -0
  49. package/dist/components/stepper/step-changed-event-args.d.ts +11 -0
  50. package/dist/components/stepper/step-changing-event-args.d.ts +18 -0
  51. package/dist/components/stepper/stepper-item.d.ts +20 -0
  52. package/dist/components/stepper/stepper-label-position.d.ts +2 -0
  53. package/dist/components/stepper/stepper-orientation.d.ts +1 -0
  54. package/dist/components/stepper/stepper-props.d.ts +32 -0
  55. package/dist/components/stepper/stepper-status.d.ts +2 -0
  56. package/dist/components/stepper/wizard-finishing-event-args.d.ts +7 -0
  57. package/dist/components/stepper/wizard-props.d.ts +48 -0
  58. package/dist/components/stepper/wizard-step-props.d.ts +32 -0
  59. package/dist/core/flow-home.d.ts +6 -0
  60. package/dist/core/fold-text.d.ts +6 -0
  61. package/dist/core/ui-locale.d.ts +0 -2
  62. package/dist/core/ui-strings.d.ts +43 -0
  63. package/dist/generated/tokens.d.ts +1186 -11
  64. package/dist/index.d.ts +8 -1
  65. package/dist/index.js +22542 -20143
  66. package/dist/index.js.map +1 -1
  67. package/dist/locales/en.json +39 -1
  68. package/dist/locales/tr.json +39 -1
  69. package/dist/parts/data/DataItems.d.ts +5 -0
  70. package/dist/parts/data/KeyedItems.d.ts +2 -0
  71. package/dist/styles.css +1912 -8
  72. package/dist/tokens/index.d.ts +1186 -11
  73. package/dist/tokens/index.js +1186 -11
  74. package/dist/tokens/index.js.map +1 -1
  75. package/dist/tr-B218zMtu.js +1191 -0
  76. package/dist/tr-B218zMtu.js.map +1 -0
  77. package/docs/accordion.md +1 -1
  78. package/docs/actionsheet.md +1 -1
  79. package/docs/avatar.md +1 -1
  80. package/docs/badge.md +1 -1
  81. package/docs/bottomsheet.md +3 -3
  82. package/docs/breadcrumb.md +2 -2
  83. package/docs/button.md +3 -3
  84. package/docs/buttongroup.md +1 -1
  85. package/docs/calendar.md +1 -1
  86. package/docs/card.md +1 -1
  87. package/docs/checkbox.md +3 -3
  88. package/docs/chip.md +1 -1
  89. package/docs/colorbox.md +1 -1
  90. package/docs/combobox.md +1 -1
  91. package/docs/control.md +1 -1
  92. package/docs/datagrid-api.md +3 -3
  93. package/docs/datagrid-bands.md +1 -1
  94. package/docs/datagrid-drag-select.md +1 -1
  95. package/docs/datagrid-drag.md +1 -1
  96. package/docs/datagrid-editing.md +1 -1
  97. package/docs/datagrid-filtering.md +1 -1
  98. package/docs/datagrid-forms.md +1 -1
  99. package/docs/datagrid-grouping.md +1 -1
  100. package/docs/datagrid-layout.md +1 -1
  101. package/docs/datagrid-lookups.md +1 -1
  102. package/docs/datagrid-master-detail.md +1 -1
  103. package/docs/datagrid-scrolling.md +1 -1
  104. package/docs/datagrid-selection.md +1 -1
  105. package/docs/datagrid.md +1 -1
  106. package/docs/datebox.md +3 -3
  107. package/docs/daterangebox.md +192 -0
  108. package/docs/drawer.md +1 -1
  109. package/docs/dropdown.md +13 -7
  110. package/docs/fileuploader.md +201 -0
  111. package/docs/filterbuilder.md +3 -3
  112. package/docs/formlayout.md +1 -1
  113. package/docs/home.md +1 -1
  114. package/docs/keyboard.md +1 -1
  115. package/docs/language.md +229 -0
  116. package/docs/layout.md +3 -3
  117. package/docs/listbox.md +3 -3
  118. package/docs/loadpanel.md +184 -0
  119. package/docs/lookup.md +86 -2
  120. package/docs/menus.md +1 -1
  121. package/docs/numberbox.md +3 -3
  122. package/docs/pagination.md +1 -1
  123. package/docs/popover.md +221 -0
  124. package/docs/progress.md +3 -3
  125. package/docs/radiogroup.md +1 -1
  126. package/docs/rating.md +1 -1
  127. package/docs/scheduler-agenda.md +1 -1
  128. package/docs/scheduler-big-data.md +1 -1
  129. package/docs/scheduler-editing.md +1 -1
  130. package/docs/scheduler-form.md +1 -1
  131. package/docs/scheduler-icalendar.md +1 -1
  132. package/docs/scheduler-mobile.md +1 -1
  133. package/docs/scheduler-recurrence.md +1 -1
  134. package/docs/scheduler-resources.md +1 -1
  135. package/docs/scheduler-timeline.md +1 -1
  136. package/docs/scheduler.md +1 -1
  137. package/docs/scrollview.md +185 -0
  138. package/docs/showcase.md +1 -1
  139. package/docs/skeleton.md +1 -1
  140. package/docs/slider.md +3 -3
  141. package/docs/sortable.md +213 -0
  142. package/docs/stepper.md +238 -0
  143. package/docs/switch.md +1 -1
  144. package/docs/tabdocs-dock.md +1 -1
  145. package/docs/tabdocs-drag.md +1 -1
  146. package/docs/tabdocs-menus.md +1 -1
  147. package/docs/tabdocs-mobile.md +1 -1
  148. package/docs/tabdocs-tabs.md +1 -1
  149. package/docs/tabdocs-windows.md +1 -1
  150. package/docs/tabdocs-workspace.md +1 -1
  151. package/docs/tabdocs.md +1 -1
  152. package/docs/tabs.md +3 -3
  153. package/docs/tagbox.md +3 -3
  154. package/docs/textarea.md +3 -3
  155. package/docs/textbox.md +3 -3
  156. package/docs/toast.md +3 -3
  157. package/docs/tokens.md +357 -122
  158. package/docs/toolbar.md +3 -3
  159. package/docs/tooltip.md +1 -1
  160. package/docs/treeview.md +3 -3
  161. package/docs/window.md +3 -3
  162. package/docs/wizard.md +240 -0
  163. package/llms-full.txt +2518 -245
  164. package/llms.txt +10 -1
  165. package/package.json +10 -4
@@ -0,0 +1,192 @@
1
+ # DateRangeBox
2
+
3
+ > Editors · @motifx-community/ui 0.1.0-beta.2
4
+
5
+ A start and an end date in one field: typed through two masks, or picked on two months side by side, from ready-made ranges, within the dates and the span allowed. The value is a `[start, end]` pair.
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { DateRangeBox, type DateRange } from '@motifx-community/ui';
11
+ ```
12
+
13
+ ## From JSX and from code
14
+
15
+ ```tsx
16
+ import { reactive } from '@motifx/core';
17
+ import { Button, DateRangeBox, Stack, type DateRange } from '@motifx-community/ui';
18
+
19
+ const say = (d: Date | null) => (d ? d.toLocaleDateString('en-GB') : '—');
20
+
21
+ /** A range bound with x-model, and one made from code and read through its properties. */
22
+ export default function FromCode() {
23
+ const s = reactive({ stay: [new Date(2026, 2, 10), new Date(2026, 2, 14)] as DateRange, told: '' });
24
+ const coded = new DateRangeBox({ label: 'Report period', clearButton: true, onValueChanged: e => (s.told = `${say(e.value[0])} to ${say(e.value[1])}`) });
25
+
26
+ return (
27
+ <Stack gap="md">
28
+ <Stack orientation="horizontal" wrap align="center">
29
+ <DateRangeBox label="Stay" x-model={() => s.stay} clearButton />
30
+ <output class="dr-stay">{() => `${say(s.stay[0])} to ${say(s.stay[1])}`}</output>
31
+ </Stack>
32
+ <Stack orientation="horizontal" wrap align="center">
33
+ <span onConfig={c => c.controls.add(coded)} />
34
+ <Button text="This week" variant="outline" onclick={() => (coded.value = [new Date(2026, 2, 16), new Date(2026, 2, 22)])} />
35
+ <output class="dr-told">{() => s.told}</output>
36
+ </Stack>
37
+ </Stack>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ## Presets
43
+
44
+ `presets` puts ready-made ranges beside the calendars: `true` for the kit’s, or your own, each made when it is chosen. `calendars={1}` shows one month.
45
+
46
+ ```tsx
47
+ import { reactive } from '@motifx/core';
48
+ import { DateRangeBox, Stack, type DateRange, type DateRangePreset } from '@motifx-community/ui';
49
+
50
+ const day = (offset: number) => {
51
+ const d = new Date();
52
+ d.setHours(0, 0, 0, 0);
53
+ d.setDate(d.getDate() + offset);
54
+ return d;
55
+ };
56
+
57
+ // Ranges of our own, made when chosen so they are about today.
58
+ const QUARTERS: DateRangePreset[] = [
59
+ { text: 'Next 3 days', range: () => [day(0), day(2)] },
60
+ { text: 'Next week', range: () => [day(1), day(7)] },
61
+ { text: 'Next 90 days', range: () => [day(0), day(89)] }
62
+ ];
63
+
64
+ /** The kit's presets beside the calendars, and presets of your own. */
65
+ export default function Presets() {
66
+ const s = reactive({ sales: [null, null] as DateRange, plan: [null, null] as DateRange });
67
+ return (
68
+ <Stack orientation="horizontal" wrap align="center">
69
+ <DateRangeBox label="Sales period" presets x-model={() => s.sales} />
70
+ <DateRangeBox label="Planning" presets={QUARTERS} calendars={1} x-model={() => s.plan} />
71
+ </Stack>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ## Limits
77
+
78
+ `min`, `max` and `disabledDates` bound both ends, typed or picked; `minDays` and `maxDays` bound the span, and the calendars offer only the days within while the end is being picked. A failed rule says which.
79
+
80
+ ```tsx
81
+ import { reactive } from '@motifx/core';
82
+ import { Button, DateRangeBox, Stack, type DateRange } from '@motifx-community/ui';
83
+
84
+ const today = new Date();
85
+ const inMonths = (n: number) => new Date(today.getFullYear(), today.getMonth() + n, today.getDate());
86
+
87
+ /** A stay of one to fourteen nights, within the next six months, never starting on a Sunday; the message says which rule failed. */
88
+ export default function Limits() {
89
+ const s = reactive({ stay: [null, null] as DateRange, told: '' });
90
+ let box!: DateRangeBox;
91
+ return (
92
+ <Stack orientation="horizontal" wrap align="center">
93
+ <DateRangeBox
94
+ ref={(b: DateRangeBox) => (box = b)}
95
+ label="Stay"
96
+ min={today}
97
+ max={inMonths(6)}
98
+ minDays={1}
99
+ maxDays={14}
100
+ disabledDates={d => d.getDay() === 0}
101
+ required
102
+ x-model={() => s.stay}
103
+ />
104
+ <Button text="Check" variant="outline" onclick={() => void box.validate().then(ok => (s.told = ok ? 'Fine.' : box.validationMessage))} />
105
+ <output class="dr-check">{() => s.told}</output>
106
+ </Stack>
107
+ );
108
+ }
109
+ ```
110
+
111
+ ## With a time, and in another locale
112
+
113
+ ```tsx
114
+ import { reactive } from '@motifx/core';
115
+ import { DateRangeBox, Stack, type DateRange } from '@motifx-community/ui';
116
+
117
+ /** Date and time on both ends: the time is typed after the date, the calendars keep it; one box in Turkish. */
118
+ export default function DateTime() {
119
+ const s = reactive({ shift: [new Date(2026, 2, 10, 8, 30), new Date(2026, 2, 10, 17, 0)] as DateRange, trip: [null, null] as DateRange });
120
+ return (
121
+ <Stack orientation="horizontal" wrap align="center">
122
+ <DateRangeBox label="Shift" type="datetime" x-model={() => s.shift} displayFormat={{ dateStyle: 'short', timeStyle: 'short' }} />
123
+ <DateRangeBox label="Seyahat" locale="tr-TR" showWeekNumbers x-model={() => s.trip} startPlaceholder="gidiş" endPlaceholder="dönüş" />
124
+ </Stack>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ## Behaviour
130
+
131
+ | Topic | How |
132
+ | --- | --- |
133
+ | `Typing` | Each side is a masked input in the locale’s order (`22.11.2006`); a whole, real date is taken as it is finished, an emptied side becomes `null`. Tab moves from the start to the end. |
134
+ | `Picking` | On the popup the first pick is the start, the second the end: an earlier second pick becomes the start. With both chosen, the next pick starts a new range. While the end is being picked, the pointer shows the range it would make. |
135
+ | `Two months` | The calendars show the start’s month and the next; paging one pages the other with it. |
136
+ | `Presets` | A list beside the calendars; a press takes the range and closes. |
137
+ | `Keyboard` | Alt+Down opens the popup; in it the calendars take the arrow keys, Enter picks; Escape closes, and clears the field when `clearButton` is on and the popup is closed. |
138
+
139
+ ## Accessibility
140
+
141
+ | Topic | How |
142
+ | --- | --- |
143
+ | `Inputs` | Two text boxes named “<label>, Start date” and “<label>, End date” in the kit language; the field’s label marks the start. |
144
+ | `Popup` | A dialog named “Choose date”; the calendars are the kit’s grids, the presets a list box. |
145
+ | `Messages` | The rules speak in the kit language; a rule of your own in yours. |
146
+
147
+ ## Styling
148
+
149
+ | Hook | What it is |
150
+ | --- | --- |
151
+ | `.mx-date-range-box` | The field. `data-type`. |
152
+ | `.mx-date-range-box__start, .mx-date-range-box__end, .mx-date-range-box__separator` | The inputs and the glyph between them. |
153
+ | `.mx-date-range-box__toggle, .mx-date-range-box__clear` | The buttons in the box. |
154
+ | `.mx-date-range-box__popup, .mx-date-range-box__calendar, .mx-date-range-box__presets` | The popup, each calendar, the presets. |
155
+
156
+ ### Component tokens
157
+
158
+ | Token | What it sets |
159
+ | --- | --- |
160
+ | `date-range-box.separator, .presets` | Units: the glyph between the inputs (`icon`, `bg`), the list of presets (`focus`, `beside`). |
161
+ | `date-range-box.calendar` | Place: a calendar on the popup. |
162
+ | `date-range-box.popup-gap` | Between the calendars and the presets. |
163
+ | `calendar.cell range-start, range-end, range-single, range-in` | The calendar’s cells in a range: its ends and the days between, drawn by each language. |
164
+
165
+ ## API reference
166
+
167
+ ### Props
168
+
169
+ | Prop | Type | Default | Description |
170
+ | --- | --- | --- | --- |
171
+ | `value` | `Bind<DateRange>` | `[null, null]` | The `[start, end]` pair; either `null` while not chosen. `x-model` binds it two-way. |
172
+ | `type` | `Bind<'date' \| 'datetime'>` | `'date'` | With `datetime` the time is typed after the date; the calendars keep it. |
173
+ | `min, max, disabledDates` | `Bind<Date \| null>`, `Bind<(d: Date) => boolean>` | — | The dates allowed, on both ends, typed or picked. |
174
+ | `minDays, maxDays` | `Bind<number \| null>` | `null` | The least and the most days a range may span, the end counted from the start; while the end is picked the calendars offer only days within. |
175
+ | `presets` | `Bind<readonly DateRangePreset[] \| boolean>` | `false` | `true`: the kit’s ready-made ranges beside the calendars (today, yesterday, the last 7 and 30 days, this and last month); your own as `{ text, range: () => DateRange }`. |
176
+ | `calendars` | `Bind<1 \| 2>` | `2` | Months side by side on the popup; two stay a month apart as one is paged. |
177
+ | `closeOnComplete` | `Bind<boolean>` | `true` | The popup closes once both ends are picked. |
178
+ | `locale, displayFormat, firstDayOfWeek, showWeekNumbers, showSeconds` | | | As on the `DateBox`. |
179
+ | `startPlaceholder, endPlaceholder` | `Bind<string>` | `''` | Shown in an empty box. |
180
+ | `clearButton, showPickerButton` | `Bind<boolean>` | `false`, `true` | The clear button; the button that opens the calendars. |
181
+ | `label, helpText, required, rules, readOnly, size, variant…` | | | The field props, as on every editor. |
182
+
183
+ ### Events, properties and methods
184
+
185
+ | Member | Kind | Description |
186
+ | --- | --- | --- |
187
+ | `startDate, endDate` | `Date \| null` | The ends as properties of their own. |
188
+ | `inputElement, endInputElement` | read-only | The start’s and the end’s inputs. |
189
+ | `open(), close(), opened` | `boolean` / `void` | The popup with the calendars; `onOpened`, `onClosed`. |
190
+ | `clear()` | `void` | Empties both ends. |
191
+ | `validate(), validationMessage, isValid` | | As on every field: an unfinished date, a date outside `min`, `max` or `disabledDates`, a start after the end, a span under `minDays` or over `maxDays`. |
192
+ | `onValueChanged` | event | The pair changed (`value`, `previousValue`, `byUser`). |
package/docs/drawer.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Drawer
2
2
 
3
- > Navigation · @motifx-community/ui 0.1.0-beta.0
3
+ > Navigation · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  A panel that slides in from an edge of the page or of a container, over the content or pushing it aside. A finger swipes it in from the edge and back again; Escape, the scrim and the browser's back close it.
6
6
 
package/docs/dropdown.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # DropDown
2
2
 
3
- > Choice · @motifx-community/ui 0.1.0-beta.0
3
+ > Choice · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  Picks one item from a list. The field shows the chosen item; the list opens below it with the keyboard or a press, can be searched, grouped and drawn your way, and stays fast with thousands of items.
6
6
 
@@ -148,21 +148,22 @@ export const cities = ['Ankara', 'Antalya', 'Bursa', 'İstanbul', 'İzmir', 'Kon
148
148
  | `Groups` | Each group is `role="group"` named by its header. |
149
149
  | `Long lists` | Only the rows in view are drawn; each option says where it is with `aria-posinset` and `aria-setsize`. |
150
150
  | `Search` | The search box controls the list and names the highlighted option the same way. |
151
+ | `Waiting` | While the value's item is asked for, the combobox is `aria-busy` and its text says "Loading…" to screen readers; a key the source does not have carries the reason as its title. |
151
152
 
152
153
  ## Localization
153
154
 
154
- The search box, the clear button and the empty list text come from `uiLocale.strings`.
155
+ The search box, the clear button, the empty list text, the wait (`loading`) and the reason a key is marked (`notInList`, `loadFailed`) come from `uiLocale.strings`.
155
156
 
156
157
  ```tsx
157
158
  import { reactive } from '@motifx/core';
158
- import { Button, DropDown, enStrings, trStrings, uiLocale } from '@motifx-community/ui';
159
+ import { Button, DropDown, uiLocale } from '@motifx-community/ui';
159
160
 
160
161
  /** Switches the texts of every drop-down on the page: the search box, the clear button, the empty list. */
161
162
  export default function Localization() {
162
163
  const s = reactive({ lang: 'en' });
163
164
  const toggle = () => {
164
165
  s.lang = s.lang === 'en' ? 'tr' : 'en';
165
- uiLocale.strings = s.lang === 'en' ? enStrings : trStrings;
166
+ void uiLocale.use(s.lang);
166
167
  };
167
168
  return (
168
169
  <>
@@ -177,8 +178,9 @@ export default function Localization() {
177
178
 
178
179
  | Hook | What it is |
179
180
  | --- | --- |
180
- | `.mx-drop-down` | Added to the field. `data-open` while the list is open; the field attributes of TextBox. |
181
- | `.mx-drop-down__display, .mx-drop-down__text, .mx-drop-down__chevron` | The combobox, the chosen text (`data-placeholder` when empty), the arrow. |
181
+ | `.mx-drop-down` | Added to the field. `data-open` while the list is open, `data-loading` while the value's item is asked for; the field attributes of TextBox. |
182
+ | `.mx-drop-down__display, .mx-drop-down__text, .mx-drop-down__chevron` | The combobox, the chosen text (`data-placeholder` when empty, `data-missing` for a key the source does not have), the arrow. |
183
+ | `.mx-drop-down__spinner` | The spinner in the arrow's place while the value's item is asked for. |
182
184
  | `.mx-drop-down__popup, .mx-drop-down__search` | The popup and its search box. |
183
185
  | `.mx-list, .mx-list__item, .mx-list__header` | The list (shared), its options (`data-active`, `data-selected`) and group headers. |
184
186
 
@@ -187,6 +189,7 @@ export default function Localization() {
187
189
  | Token | What it sets |
188
190
  | --- | --- |
189
191
  | `field.*` | The field, as for TextBox. |
192
+ | `drop-down.value, drop-down.chevron, drop-down.spinner, drop-down.spinner-shape` | Units: the chosen text (`placeholder`, `missing`, `disabled`), the arrow (`open`, `disabled`), the ring that turns while the value's item is asked for and the shape a language may draw instead (with the spinner's shapes and timing). |
190
193
  | `list.item-height, list.item` | The options: their row height, and the item unit in each state (`hover`, `pressed`, `active`, `selected`, `selected-hover`, `selected-pressed`, `disabled`, `next`, `select-all`). |
191
194
  | `list.indicator, list.check, list.mark, list.icon, list.text` | Units: the bar on the chosen option (`multiple`), the check of a list of several choices and its mark, an icon, the text. |
192
195
  | `list.container, list.group, list.header, list.select-all-divider, list.empty` | Units: the list (its space and most height), a group, group headers, the line under "Select all", the empty text. |
@@ -199,6 +202,9 @@ export default function Localization() {
199
202
  | --- | --- | --- | --- |
200
203
  | `value` | `Bind<V \| null>` | `null` | The value of the chosen item. `x-model` binds it two-way. |
201
204
  | `items` | `Bind<readonly T[]>` | `[]` | Plain values, `DropDownItem`s (`{ value, text, icon?, group?, enabled? }`) or objects of your own. A function is followed; items changed in place show after `refresh()`. |
205
+ | `dataSource` | `Bind<DataSource<T> \| null>` | `null` | Items from the data layer, loaded where the list is scrolled to and searched on its `searchFields`. Wins over `items`. A value on no loaded page is asked for by key; meanwhile the field waits (see Lookup). |
206
+ | `valueText` | `Bind<string>` | `''` | The value's text while its item is asked for from `dataSource`, shown at once instead of waiting (a record that carries the name: `valueText={() => order.customerName}`). |
207
+ | `searchDelay` | `Bind<number>` | `250` with a data source, else `0` | Milliseconds between the last key in the search box and the search. |
202
208
  | `textField / valueField` | `Bind<ItemField<T>>` | `'text'` / `'value'` | A property name or a function `(item) => …`. Without `valueField` an object with a `value` gives that, anything else is its own value. |
203
209
  | `iconField, groupField, enabledField` | `Bind<ItemField<T>>` | — | An icon per option; options with the same group follow each other under its name; options that cannot be chosen. |
204
210
  | `placeholder` | `Bind<string>` | `''` | Shown while nothing is chosen. |
@@ -224,7 +230,7 @@ A prop whose value is a function of its own (`textField`, a template) takes the
224
230
 
225
231
  | Method | Returns | Description |
226
232
  | --- | --- | --- |
227
- | `open(search?)` | `boolean` | Opens the list; `search` starts the search box with that text. `false` when disabled or read-only. |
233
+ | `open(search?)` | `boolean` | Opens the list; `search` starts the search box with that text. `false` when disabled, read-only, or while the value's item is asked for. |
228
234
  | `close()` | `void` | Closes it; focus goes back to the field. |
229
235
  | `clear()` | `void` | Empties the value. |
230
236
  | `refresh()` | `void` | Your items may be plain or reactive; the drop-down reads them as they are. After changing them in place, call `refresh()`. The field's text and the open list follow. |
@@ -0,0 +1,201 @@
1
+ # FileUploader
2
+
3
+ > Editors · @motifx-community/ui 0.1.0-beta.2
4
+
5
+ Files chosen with a button or dropped on the box, listed with their size and what happens to them: uploaded as they come, on a button or from code, with progress, cancel, retry and remove on each. Files outside the limits are listed with the reason.
6
+
7
+ ## Import
8
+
9
+ ```tsx
10
+ import { FileUploader } from '@motifx-community/ui';
11
+ ```
12
+
13
+ ## Choosing, dropping, uploading
14
+
15
+ `upload` is your own way to send a file: report progress, stop on the signal, resolve to the response. With `uploadUrl` instead, the uploader sends the file itself, in one piece or in chunks (`chunkSize`).
16
+
17
+ ```tsx
18
+ import { reactive } from '@motifx/core';
19
+ import { FileUploader, Stack } from '@motifx-community/ui';
20
+
21
+ // Stands in for a server: takes two seconds per megabyte, reports as it goes, stops on the signal.
22
+ const send = (file: File, report: (fraction: number) => void, signal: AbortSignal) =>
23
+ new Promise<string>((resolve, reject) => {
24
+ const steps = 20;
25
+ const wait = Math.max(600, Math.min(4000, (file.size / 1_000_000) * 2000)) / steps;
26
+ let step = 0;
27
+ const timer = setInterval(() => {
28
+ step++;
29
+ report(step / steps);
30
+ if (step === steps) {
31
+ clearInterval(timer);
32
+ resolve(`id-${file.name}`);
33
+ }
34
+ }, wait);
35
+ signal.addEventListener('abort', () => {
36
+ clearInterval(timer);
37
+ reject(new Error('stopped'));
38
+ });
39
+ });
40
+
41
+ /** Files chosen or dropped go up as they come, through your own upload; each row shows progress, cancel, retry, remove. */
42
+ export default function Basic() {
43
+ const s = reactive({ files: [] as readonly File[], told: '' });
44
+ return (
45
+ <Stack gap="md" style="inline-size: 100%">
46
+ <FileUploader
47
+ label="Attachments"
48
+ helpText="Any files; a stand-in server takes them."
49
+ upload={send}
50
+ x-model={() => s.files}
51
+ onUploaded={e => (s.told = `${e.file.name} is up as ${String(e.item.response)}.`)}
52
+ onUploadAborted={e => (s.told = `${e.file.name} was stopped.`)}
53
+ />
54
+ <output class="fu-told">{() => s.told || `${s.files.length} file(s) taken`}</output>
55
+ </Stack>
56
+ );
57
+ }
58
+ ```
59
+
60
+ ## Limits
61
+
62
+ ```tsx
63
+ import { reactive } from '@motifx/core';
64
+ import { FileUploader, Stack } from '@motifx-community/ui';
65
+
66
+ /** Only pictures and PDFs, up to 2 MB each and three in all; a file outside is listed with the reason. */
67
+ export default function Limits() {
68
+ const s = reactive({ files: [] as readonly File[], refused: '' });
69
+ return (
70
+ <Stack gap="md" style="inline-size: 100%">
71
+ <FileUploader
72
+ label="Documents"
73
+ accept=".pdf,image/*"
74
+ maxFileSize={2_000_000}
75
+ maxFiles={3}
76
+ required
77
+ x-model={() => s.files}
78
+ onFilesAdded={e => (s.refused = e.refused.length ? e.refused.map(r => r.message).join(' ') : '')}
79
+ />
80
+ <output class="fu-refused">{() => s.refused}</output>
81
+ </Stack>
82
+ );
83
+ }
84
+ ```
85
+
86
+ ## When files go up
87
+
88
+ ```tsx
89
+ import { reactive } from '@motifx/core';
90
+ import { Button, FileUploader, Stack } from '@motifx-community/ui';
91
+
92
+ const quick = (file: File, report: (fraction: number) => void) =>
93
+ new Promise<void>(resolve => {
94
+ let step = 0;
95
+ const timer = setInterval(() => {
96
+ report(++step / 10);
97
+ if (step === 10) {
98
+ clearInterval(timer);
99
+ resolve();
100
+ }
101
+ }, 120);
102
+ });
103
+
104
+ /** An Upload button sends what was chosen; or nothing goes until code says so. One file only, no dropping. */
105
+ export default function Modes() {
106
+ const s = reactive({ one: [] as readonly File[] });
107
+ let manual!: FileUploader;
108
+ return (
109
+ <Stack gap="md" style="inline-size: 100%">
110
+ <FileUploader label="Photo" multiple={false} allowDrop={false} accept="image/*" upload={quick} uploadMode="button" x-model={() => s.one} />
111
+ <Stack orientation="horizontal" wrap align="center">
112
+ <FileUploader ref={(u: FileUploader) => (manual = u)} label="Logs" accept=".log,.txt" upload={quick} uploadMode="manual" />
113
+ <Button text="Send the logs" variant="outline" onclick={() => void manual.upload()} />
114
+ </Stack>
115
+ </Stack>
116
+ );
117
+ }
118
+ ```
119
+
120
+ ## Sending to a server
121
+
122
+ The uploader posts a form with the file in `uploadField` (`file` by default) to `uploadUrl`, with `uploadHeaders`; a 2xx answer is the item’s `response`, JSON parsed when it is JSON. With `chunkSize` each piece carries `Content-Range` and the fields `chunkIndex` and `chunkCount`.
123
+
124
+ ```tsx
125
+ <FileUploader
126
+ label="Attachments"
127
+ uploadUrl="/api/files"
128
+ uploadHeaders={{ Authorization: 'Bearer ' + token }}
129
+ chunkSize={1_000_000}
130
+ onUploaded={(e) => this.attachments.push(e.item.response as Attachment)}
131
+ />
132
+ ```
133
+
134
+ ## Behaviour
135
+
136
+ | Topic | How |
137
+ | --- | --- |
138
+ | `Choosing` | The button opens the file dialog; files may be dropped on the box too, which lights up while they are over it. |
139
+ | `Refusing` | A file outside `accept`, the sizes or `maxFiles` is listed as refused with the reason, and is not in the value. |
140
+ | `Uploading` | As chosen, on the Upload button, or from code. A row shows the progress and a Cancel button meanwhile; afterwards “Uploaded”, or the failure with Retry. The server’s answer is the item’s `response` (JSON parsed). |
141
+ | `Chunks` | With `chunkSize` the file goes in pieces, each a request with `Content-Range: bytes start-end/total`; progress runs over the whole. |
142
+ | `Removing` | Each row has a remove button; a running upload is stopped first. |
143
+
144
+ ## Accessibility
145
+
146
+ | Topic | How |
147
+ | --- | --- |
148
+ | `Button` | The select button is the field’s control: the label marks it, Space and Enter open the dialog. |
149
+ | `List` | A list of rows: the name, the size and the state as text; the progress bar named after the file; the buttons named “Cancel the upload of …”, “Retry”, “Remove …”. |
150
+ | `Messages` | The reasons a file was refused and the failures speak in the kit language, or in the server’s words. |
151
+
152
+ ## Styling
153
+
154
+ | Hook | What it is |
155
+ | --- | --- |
156
+ | `.mx-file-uploader` | The field. `data-dragover` while files are over it. |
157
+ | `.mx-file-uploader__select, .mx-file-uploader__drop, .mx-file-uploader__upload` | The select button, the hint, the Upload button. |
158
+ | `.mx-file-uploader__list, .mx-file-uploader__item` | The list and each row. `data-status` on the row. |
159
+ | `.mx-file-uploader__icon, __name, __size, __state, __progress, __actions, __action` | The parts of a row. |
160
+
161
+ ### Component tokens
162
+
163
+ | Token | What it sets |
164
+ | --- | --- |
165
+ | `file-uploader.over, .select, .upload, .hint, .list, .item, .icon, .name, .size, .state` | Units: the box with files over it, the two buttons (`hover`, `pressed`, `focus`, `disabled`), the hint, the list, a row per status, the file glyph, the texts. |
166
+ | `file-uploader.field, .action` | Places: the field’s box as a drop zone (a dashed frame, its corners, its padding); the row’s buttons. |
167
+ | `file-uploader.box-gap, .button-gap, .item-gap` | The spaces in the box, in a button and in a row. |
168
+
169
+ ## API reference
170
+
171
+ ### Props
172
+
173
+ | Prop | Type | Default | Description |
174
+ | --- | --- | --- | --- |
175
+ | `value` | `Bind<readonly File[]>` | `[]` | The files taken (the refused ones are not in it). `x-model` binds it two-way. |
176
+ | `multiple` | `Bind<boolean>` | `true` | Several files at once; `false` keeps one, the newest. |
177
+ | `accept` | `Bind<string>` | `''` | What may be chosen, as for `<input type="file">`: `.png,.jpg`, `image/*`, `application/pdf`. |
178
+ | `maxFileSize, minFileSize` | `Bind<number \| null>` | `null` | Bytes. A file outside is listed as refused, with the reason. |
179
+ | `maxFiles` | `Bind<number \| null>` | `null` | How many files may be taken in all. |
180
+ | `allowDrop` | `Bind<boolean>` | `true` | Files may be dropped on the box. |
181
+ | `uploadMode` | `Bind<UploadMode>` | `instant` / `manual` | `instant`: as chosen; `button`: an Upload button; `manual`: `upload()` from code. Default `instant` with `uploadUrl` or `upload`, else `manual`. |
182
+ | `uploadUrl, uploadMethod, uploadHeaders, uploadField` | `Bind<string \| null>`, … | `null`, `POST`, `null`, `file` | Where and how the uploader itself sends a file (XMLHttpRequest, with progress), as a form with the file in `uploadField`. |
183
+ | `chunkSize` | `Bind<number \| null>` | `null` | Bytes per request: the file goes in pieces, each with its `Content-Range` and `chunkIndex` / `chunkCount` fields; the last answer is the response. |
184
+ | `upload` | `(file, report, signal) => Promise<unknown>` | — | Your own upload instead of `uploadUrl`: call `report(0…1)` as it goes, stop on `signal`; what it resolves to is the response. |
185
+ | `selectText, dropText, uploadText` | `Bind<string>` | the kit’s | The button, the hint beside it, the Upload button. |
186
+ | `showFileList` | `Bind<boolean>` | `true` | The list of files under the box. |
187
+ | `label, helpText, required, rules, readOnly, size, variant…` | | | The field props, as on every editor. |
188
+
189
+ ### Events, properties and methods
190
+
191
+ | Member | Kind | Description |
192
+ | --- | --- | --- |
193
+ | `items` | read-only | Every file in the list with what happened to it: `file`, `status` (`ready`, `uploading`, `done`, `error`, `aborted`, `invalid`), `progress`, `response`, `message`. |
194
+ | `isUploading` | read-only | An upload is running. |
195
+ | `openDialog()` | `void` | Opens the browser’s file dialog, as the button does. |
196
+ | `addFiles(files)` | `void` | Takes files as if chosen: the limits apply, `onFilesAdded` is asked, uploads start as the mode says. |
197
+ | `upload(item?)` | `Promise<void>` | Uploads the files waiting, or one of them; what `manual` mode calls. |
198
+ | `abort(item?), remove(item), clear()` | `void` | Stops an upload (the file stays, cancelled); takes a file out; takes every file out. |
199
+ | `onFilesAdded` | event | Files were chosen or dropped (`files`, `refused`); `cancel = true` takes none. |
200
+ | `onFileRemoved, onUploadStarted, onProgress, onUploaded, onUploadError, onUploadAborted` | event | One file’s way through: each with `item` and `file`, a failure with `error`. |
201
+ | `onValueChanged` | event | The files taken changed. |
@@ -1,6 +1,6 @@
1
1
  # FilterBuilder
2
2
 
3
- > Data · @motifx-community/ui 0.1.0-beta.0
3
+ > Data · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  A filter builder lets people put a filter together by hand: groups joined by And, Or, Not And or Not Or, and conditions of a field, an operation and a value. Its value is the data layer's filter expression, so it goes to rows in memory and to every adapter as it is. The DataGrid opens it from its filter panel; on its own it serves a report screen or a saved search.
6
6
 
@@ -574,7 +574,7 @@ export default function CustomOperations() {
574
574
  ```tsx
575
575
  import { reactive } from '@motifx/core';
576
576
  import { data } from '@motifx-community/data';
577
- import { Button, FilterBuilder, enStrings, trStrings, uiLocale } from '@motifx-community/ui';
577
+ import { Button, FilterBuilder, uiLocale } from '@motifx-community/ui';
578
578
  import { saleFields } from './sales';
579
579
 
580
580
  /** The builder's texts come from `uiLocale`; `texts` changes some for one builder only. */
@@ -582,7 +582,7 @@ export default function Localization() {
582
582
  const s = reactive({ lang: 'en' });
583
583
  const toggle = () => {
584
584
  s.lang = s.lang === 'en' ? 'tr' : 'en';
585
- uiLocale.strings = s.lang === 'en' ? enStrings : trStrings;
585
+ void uiLocale.use(s.lang);
586
586
  };
587
587
  return (
588
588
  <>
@@ -1,6 +1,6 @@
1
1
  # FormLayout
2
2
 
3
- > Navigation · @motifx-community/ui 0.1.0-beta.0
3
+ > Navigation · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  Lays out the fields of a data object on a grid. Each field gets an editor — by name, or by the type of its value — bound to the object both ways; groups, spans and buttons arrange them; sending the form checks every field first.
6
6
 
package/docs/home.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @motifx-community/ui
2
2
 
3
- > Get started · @motifx-community/ui 0.1.0-beta.0
3
+ > Get started · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  Components for MotifJS that work the way desktop UI does — created when needed, shown anywhere, closed and disposed like windows — drawn from the MotifJS design system's tokens.
6
6
 
package/docs/keyboard.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Keyboard and focus
2
2
 
3
- > Foundations · @motifx-community/ui 0.1.0-beta.0
3
+ > Foundations · @motifx-community/ui 0.1.0-beta.2
4
4
 
5
5
  The rules every control follows: Tab order, the active control of a container, focus that never falls to `<body>`, `&File` access keys and app-wide shortcuts.
6
6