@marianmeres/stuic 3.168.0 → 3.170.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 (31) hide show
  1. package/AGENTS.md +2 -2
  2. package/dist/README.md +1 -1
  3. package/dist/components/Input/FieldOptions.svelte +89 -54
  4. package/dist/components/Input/FieldOptions.svelte.d.ts +13 -0
  5. package/dist/components/Input/README.md +144 -31
  6. package/dist/components/Input/_internal/FieldLikeChips.svelte +286 -0
  7. package/dist/components/Input/_internal/FieldLikeChips.svelte.d.ts +65 -0
  8. package/dist/components/Input/field-options-i18n-sk.d.ts +21 -0
  9. package/dist/components/Input/field-options-i18n-sk.js +61 -0
  10. package/dist/components/Input/field-options-i18n.d.ts +82 -0
  11. package/dist/components/Input/field-options-i18n.js +90 -0
  12. package/dist/components/Input/index.css +58 -0
  13. package/dist/components/Input/index.d.ts +2 -0
  14. package/dist/components/Input/index.js +2 -0
  15. package/dist/components/Pill/Pill.svelte +8 -2
  16. package/dist/components/Pill/Pill.svelte.d.ts +2 -0
  17. package/dist/components/Pill/README.md +35 -22
  18. package/dist/components/Pill/index.css +57 -18
  19. package/dist/components/Timeline/README.md +204 -0
  20. package/dist/components/Timeline/Timeline.svelte +246 -0
  21. package/dist/components/Timeline/Timeline.svelte.d.ts +87 -0
  22. package/dist/components/Timeline/index.css +311 -0
  23. package/dist/components/Timeline/index.d.ts +1 -0
  24. package/dist/components/Timeline/index.js +1 -0
  25. package/dist/index.css +1 -0
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +1 -0
  28. package/docs/domains/components.md +39 -1
  29. package/docs/maybe-todo.md +37 -13
  30. package/docs/upgrading.md +6 -0
  31. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  ```
25
25
  src/lib/
26
- ├── components/ # 73 component directories
26
+ ├── components/ # 74 component directories
27
27
  ├── actions/ # 15 Svelte actions (use: directives)
28
28
  ├── attachments/ # Svelte attachments ({@attach} — preferred for new DOM helpers)
29
29
  ├── utils/ # 45 utility modules
@@ -129,7 +129,7 @@ Global tokens that control cross-component visual properties. Defined in `src/li
129
129
 
130
130
  ### Domain Docs
131
131
 
132
- - [Components](./docs/domains/components.md) — 73 component directories, Props pattern, snippets
132
+ - [Components](./docs/domains/components.md) — 74 component directories, Props pattern, snippets
133
133
  - [Theming](./docs/domains/theming.md) — CSS tokens, dark mode, themes
134
134
  - [CSS presets](./docs/domains/css-presets.md) — ratio-locked frame (letterbox), safe-area, scrollbar
135
135
  - [Actions](./docs/domains/actions.md) — 15 Svelte directives
package/dist/README.md CHANGED
@@ -43,7 +43,7 @@ npm install @marianmeres/stuic
43
43
  - **FieldRadios** - Radio button group
44
44
  - **FieldFile** - File upload input
45
45
  - **FieldAssets** - Multi-file upload with preview
46
- - **FieldOptions** - Modal-based multi-select picker
46
+ - **FieldOptions** - Modal-based multi-select picker (optional inline `chips` display)
47
47
  - **FieldKeyValues** - Key-value pairs editor with JSON serialization
48
48
  - **FieldSwitch** - Toggle switch within a form
49
49
  - **Fieldset** - Group of form fields with legend
@@ -20,12 +20,11 @@
20
20
  type ValidationResult,
21
21
  } from "../../actions/validate.svelte.js";
22
22
  import type { TranslateFn } from "../../types.js";
23
+ import type { IntentColorKey } from "../../utils/design-tokens.js";
23
24
  import { getId } from "../../utils/get-id.js";
24
- import { isPlainObject } from "../../utils/is-plain-object.js";
25
25
  import { maybeJsonParse } from "../../utils/maybe-json-parse.js";
26
26
  import { waitForNextRepaint } from "../../utils/paint.js";
27
27
  import { qsa } from "../../utils/qsa.js";
28
- import { replaceMap } from "../../utils/replace-map.js";
29
28
  import { strHash } from "../../utils/str-hash.js";
30
29
  import { twMerge } from "../../utils/tw-merge.js";
31
30
  import Button from "../Button/Button.svelte";
@@ -36,8 +35,10 @@
36
35
  import X from "../X/X.svelte";
37
36
  import InputWrap from "./_internal/InputWrap.svelte";
38
37
  import FieldLikeButton from "./FieldLikeButton.svelte";
38
+ import FieldLikeChips, { type FieldLikeChip } from "./_internal/FieldLikeChips.svelte";
39
39
  import ListItemButton from "../ListItemButton/ListItemButton.svelte";
40
40
  import type { InputWrapClassProps } from "./types.js";
41
+ import { t_default } from "./field-options-i18n.js";
41
42
 
42
43
  export interface Option {
43
44
  label: string;
@@ -90,6 +91,18 @@
90
91
  * serialized to `value` on submit. No-op for single-select. Default `false`.
91
92
  */
92
93
  ordered?: boolean;
94
+ /**
95
+ * Opt-in: render the current selection as inline, individually removable chips
96
+ * (`Pill`s) instead of the comma-joined text button. Picking still happens in the
97
+ * modal (opened by the trailing button, or by clicking the empty part of the row);
98
+ * removing a chip writes `value` immediately, without the modal. `renderValue` is
99
+ * ignored in this mode (labels come from `renderOptionLabel`). Default `false`.
100
+ */
101
+ chips?: boolean;
102
+ /** Classes for each chip (`chips` mode only) */
103
+ classChip?: string;
104
+ /** Pill intent of the chips (`chips` mode only) */
105
+ chipIntent?: IntentColorKey;
93
106
  showIconsCheckbox?: boolean;
94
107
  showIconsRadio?: boolean;
95
108
  searchPlaceholder?: string;
@@ -97,56 +110,6 @@
97
110
  itemIdPropName?: string;
98
111
  onChange?: (value: string) => void;
99
112
  }
100
-
101
- // i18n ready
102
- function t_default(
103
- k: string,
104
- values: false | null | undefined | Record<string, string | number> = null,
105
- fallback: string | boolean = "",
106
- i18nSpanWrap: boolean = true
107
- ) {
108
- const m: Record<string, string> = {
109
- field_req_att: "This field requires attention. Please review and try again.",
110
- cardinality_of: "of max",
111
- cardinality_selected: "selected",
112
- submit: "Submit",
113
- select_all: "Select all",
114
- clear_all: "Clear selected",
115
- clear: "Clear",
116
- search_placeholder: "Type to search...",
117
- search_submit_placeholder: "Type to search and submit...",
118
- cardinality_full: "Max selection reached",
119
- select_from_list: "Please select from the list only",
120
- x_close: "Clear input or close [esc]",
121
- close: "Close [esc]",
122
- unknown_allowed: "Select or type and submit",
123
- unknown_not_allowed: "Select from the list",
124
- no_results: "No results found.",
125
- add_new: 'Add "{{value}}"...',
126
- click_add_new: "You must add the value to continue",
127
- //
128
- pick_tab: "Pick",
129
- arrange_tab: "Arrange ({{value}})",
130
- arrange_help: "Reorder the selected items. Use the buttons to move them.",
131
- sort_az: "Sort A–Z",
132
- reverse: "Reverse",
133
- shuffle: "Shuffle",
134
- move_up: "Move up",
135
- move_down: "Move down",
136
- move_to_top: "Move to top",
137
- move_to_bottom: "Move to bottom",
138
- remove_item: "Remove",
139
- moved_up: "Moved {{value}} up",
140
- moved_down: "Moved {{value}} down",
141
- removed_item: "Removed {{value}}",
142
- sorted_az: "Sorted A to Z",
143
- reversed: "Order reversed",
144
- shuffled: "Order shuffled",
145
- };
146
- let out = m[k] ?? fallback ?? k;
147
-
148
- return isPlainObject(values) ? replaceMap(out, values as any) : out;
149
- }
150
113
  </script>
151
114
 
152
115
  <script lang="ts">
@@ -214,6 +177,9 @@
214
177
  renderOptionGroup = (s: string) => `${s}`.replaceAll("_", " "),
215
178
  allowUnknown = false,
216
179
  ordered = false,
180
+ chips = false,
181
+ classChip,
182
+ chipIntent,
217
183
  showIconsCheckbox = true,
218
184
  showIconsRadio = false,
219
185
  searchPlaceholder,
@@ -229,8 +195,9 @@
229
195
  modal = modalDialog;
230
196
  });
231
197
 
232
- // Imperative API delegates to the inner FieldLikeButton trigger.
233
- let triggerRef: FieldLikeButton | undefined = $state();
198
+ // Imperative API delegates to the inner trigger (FieldLikeButton, or FieldLikeChips in
199
+ // `chips` mode) both expose the same methods.
200
+ let triggerRef: FieldLikeButton | FieldLikeChips | undefined = $state();
234
201
 
235
202
  /** Trigger validation now. Renders the inline message if invalid. */
236
203
  export function validate(): ValidationResult | undefined {
@@ -604,6 +571,38 @@
604
571
  });
605
572
  }
606
573
 
574
+ // --- chips (inline display of the selection) ---
575
+
576
+ // straight from `value`, in value order — so with `ordered` the arranged order is what
577
+ // the user sees; labels go through the same renderer as the modal's options
578
+ let chipItems: FieldLikeChip[] = $derived.by(() => {
579
+ if (!chips) return [];
580
+ const parsed = maybeJsonParse(value || "[]");
581
+ if (!Array.isArray(parsed)) return [];
582
+ return parsed
583
+ .filter((item) => item != null)
584
+ .map((item: Item, i: number) => {
585
+ const label = _renderOptionLabel(item);
586
+ return {
587
+ // index-suffixed so a (malformed) duplicate id can't break the keyed each
588
+ key: `${item[itemIdPropName] ?? ""}__${i}`,
589
+ label,
590
+ removeLabel: t("chips_remove", { value: label }),
591
+ };
592
+ });
593
+ });
594
+
595
+ // removing a chip is an immediate, modal-less edit of `value` + the same change
596
+ // notification the modal submit does (so validation re-runs)
597
+ function removeChip(_chip: FieldLikeChip, index: number) {
598
+ const parsed = maybeJsonParse(value || "[]");
599
+ if (!Array.isArray(parsed)) return;
600
+ const items = parsed.filter((item) => item != null);
601
+ value = JSON.stringify(items.filter((_, i) => i !== index));
602
+ _dispatch_change_to_owner();
603
+ onChange?.(value);
604
+ }
605
+
607
606
  // "outer" submit - will set the outer bound value (always string) and close modal...
608
607
  // further process is left on the consumer
609
608
  function submit() {
@@ -712,6 +711,42 @@
712
711
  <div>
713
712
  {#if trigger}
714
713
  {@render trigger({ value, modal: modalDialog })}
714
+ {:else if chips}
715
+ <FieldLikeChips
716
+ bind:this={triggerRef}
717
+ bind:value
718
+ bind:input={parentHiddenInputEl}
719
+ chips={chipItems}
720
+ {name}
721
+ class={classProp}
722
+ {label}
723
+ {description}
724
+ {labelLeft}
725
+ {labelAfter}
726
+ {below}
727
+ {labelLeftWidth}
728
+ {labelLeftBreakpoint}
729
+ {classLabel}
730
+ {classLabelBox}
731
+ {classInputBox}
732
+ {classInputBoxWrap}
733
+ {classInputBoxWrapInvalid}
734
+ {classDescBox}
735
+ {classDescBoxToggle}
736
+ {classBelowBox}
737
+ {classValidationBox}
738
+ {style}
739
+ validate={wrappedValidate}
740
+ {required}
741
+ {disabled}
742
+ {tabindex}
743
+ {classChip}
744
+ {chipIntent}
745
+ placeholder={t("chips_placeholder")}
746
+ openLabel={t("chips_open")}
747
+ onOpen={() => modalDialog?.open()}
748
+ onRemove={removeChip}
749
+ />
715
750
  {:else}
716
751
  <FieldLikeButton
717
752
  bind:this={triggerRef}
@@ -2,6 +2,7 @@ import { type Item } from "@marianmeres/item-collection";
2
2
  import { type Snippet } from "svelte";
3
3
  import { type ValidateOptions, type ValidationResult } from "../../actions/validate.svelte.js";
4
4
  import type { TranslateFn } from "../../types.js";
5
+ import type { IntentColorKey } from "../../utils/design-tokens.js";
5
6
  import { ModalDialog } from "../ModalDialog/index.js";
6
7
  import { NotificationsStack } from "../Notifications/index.js";
7
8
  import type { THC } from "../Thc/Thc.svelte";
@@ -62,6 +63,18 @@ export interface Props extends InputWrapClassProps, Record<string, any> {
62
63
  * serialized to `value` on submit. No-op for single-select. Default `false`.
63
64
  */
64
65
  ordered?: boolean;
66
+ /**
67
+ * Opt-in: render the current selection as inline, individually removable chips
68
+ * (`Pill`s) instead of the comma-joined text button. Picking still happens in the
69
+ * modal (opened by the trailing button, or by clicking the empty part of the row);
70
+ * removing a chip writes `value` immediately, without the modal. `renderValue` is
71
+ * ignored in this mode (labels come from `renderOptionLabel`). Default `false`.
72
+ */
73
+ chips?: boolean;
74
+ /** Classes for each chip (`chips` mode only) */
75
+ classChip?: string;
76
+ /** Pill intent of the chips (`chips` mode only) */
77
+ chipIntent?: IntentColorKey;
65
78
  showIconsCheckbox?: boolean;
66
79
  showIconsRadio?: boolean;
67
80
  searchPlaceholder?: string;
@@ -408,48 +408,54 @@ Components use data attributes for CSS styling:
408
408
 
409
409
  ## FieldOptions
410
410
 
411
- A modal-based multi-select/single-select component with search functionality, typeahead support, and option grouping.
411
+ A modal-based multi-select/single-select component with search functionality, typeahead support, and option grouping. The closed field can show the selection as inline removable chips (`chips`).
412
412
 
413
413
  ### Props
414
414
 
415
- | Prop | Type | Default | Description |
416
- | ------------------- | ---------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------- |
417
- | `value` | `string` | `"[]"` | JSON array of selected items (bindable) |
418
- | `name` | `string` | - | Form field name |
419
- | `getOptions` | `(q: string, current: Item[]) => Promise<{found: Item[]}>` | - | Async function to fetch options |
420
- | `cardinality` | `number` | `Infinity` | Max selections (-1 for unlimited) |
421
- | `allowUnknown` | `boolean` | `false` | Allow typing custom values |
422
- | `ordered` | `boolean` | `false` | Opt-in: add an "Arrange" screen to manually order the selection (multi-select only) |
423
- | `renderOptionLabel` | `(item: Item) => string` | - | Custom option label renderer |
424
- | `renderOptionGroup` | `(s: string) => string` | - | Custom optgroup label renderer |
425
- | `renderValue` | `(stringifiedItems: string) => string` | - | Custom value display renderer |
426
- | `showIconsCheckbox` | `boolean` | `true` | Show checkbox icons in multi-select |
427
- | `showIconsRadio` | `boolean` | `false` | Show radio icons in single-select |
428
- | `searchPlaceholder` | `string` | - | Custom search placeholder |
429
- | `itemIdPropName` | `string` | `"id"` | Property name for item ID |
430
- | `notifications` | `NotificationsStack` | - | Notification handler for errors |
415
+ | Prop | Type | Default | Description |
416
+ | ------------------- | ---------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------- |
417
+ | `value` | `string` | `"[]"` | JSON array of selected items (bindable) |
418
+ | `name` | `string` | - | Form field name |
419
+ | `getOptions` | `(q: string, current: Item[]) => Promise<{found: Item[]}>` | - | Async function to fetch options |
420
+ | `cardinality` | `number` | `Infinity` | Max selections (-1 for unlimited) |
421
+ | `allowUnknown` | `boolean` | `false` | Allow typing custom values |
422
+ | `ordered` | `boolean` | `false` | Opt-in: add an "Arrange" screen to manually order the selection (multi-select only) |
423
+ | `chips` | `boolean` | `false` | Opt-in: show the selection as inline removable chips; picking still happens in the modal |
424
+ | `classChip` | `string` | - | Classes for each chip (`chips` mode) |
425
+ | `chipIntent` | `IntentColorKey` | - | Pill intent of the chips (`chips` mode) |
426
+ | `renderOptionLabel` | `(item: Item) => string` | - | Custom option label renderer |
427
+ | `renderOptionGroup` | `(s: string) => string` | - | Custom optgroup label renderer |
428
+ | `renderValue` | `(stringifiedItems: string) => string` | - | Custom value display renderer |
429
+ | `showIconsCheckbox` | `boolean` | `true` | Show checkbox icons in multi-select |
430
+ | `showIconsRadio` | `boolean` | `false` | Show radio icons in single-select |
431
+ | `searchPlaceholder` | `string` | - | Custom search placeholder |
432
+ | `itemIdPropName` | `string` | `"id"` | Property name for item ID |
433
+ | `notifications` | `NotificationsStack` | - | Notification handler for errors |
431
434
 
432
435
  ### Class Props
433
436
 
434
- | Prop | Target |
435
- | ------------------- | ---------------------------- |
436
- | `classOption` | Option item (ListItemButton) |
437
- | `classOptionActive` | Active/selected option |
438
- | `classOptgroup` | Option group label |
439
- | `classModalField` | Modal field wrapper |
437
+ | Prop | Target |
438
+ | ------------------- | -------------------------------- |
439
+ | `classOption` | Option item (ListItemButton) |
440
+ | `classOptionActive` | Active/selected option |
441
+ | `classOptgroup` | Option group label |
442
+ | `classModalField` | Modal field wrapper |
443
+ | `classChip` | Each chip (Pill) in `chips` mode |
440
444
 
441
445
  ### CSS Variables
442
446
 
443
447
  #### Component Tokens
444
448
 
445
- | Variable | Default | Description |
446
- | ------------------------------------------ | -------------------------------- | ------------------------------- |
447
- | `--stuic-field-options-divider` | `--stuic-color-border` | Divider/separator color |
448
- | `--stuic-field-options-control-text` | `--stuic-color-muted-foreground` | Control button text color |
449
- | `--stuic-field-options-control-text-hover` | `--stuic-color-foreground` | Control button hover text color |
450
- | `--stuic-field-options-control-ring` | `--stuic-color-ring` | Control button focus ring |
451
- | `--stuic-field-options-muted-text` | `--stuic-color-muted-foreground` | Muted/secondary text color |
452
- | `--stuic-field-options-optgroup-text` | `--stuic-color-muted-foreground` | Option group label color |
449
+ | Variable | Default | Description |
450
+ | ---------------------------------------------- | -------------------------------- | ----------------------------------------- |
451
+ | `--stuic-field-options-divider` | `--stuic-color-border` | Divider/separator color |
452
+ | `--stuic-field-options-control-text` | `--stuic-color-muted-foreground` | Control button text color |
453
+ | `--stuic-field-options-control-text-hover` | `--stuic-color-foreground` | Control button hover text color |
454
+ | `--stuic-field-options-control-ring` | `--stuic-color-ring` | Control button focus ring |
455
+ | `--stuic-field-options-muted-text` | `--stuic-color-muted-foreground` | Muted/secondary text color |
456
+ | `--stuic-field-options-optgroup-text` | `--stuic-color-muted-foreground` | Option group label color |
457
+ | `--stuic-field-options-chips-gap` | `0.25rem` | Gap between chips (`chips` mode) |
458
+ | `--stuic-field-options-chips-placeholder-text` | `--stuic-input-placeholder` | Placeholder color of an empty `chips` row |
453
459
 
454
460
  ### Usage
455
461
 
@@ -503,6 +509,113 @@ on submit (and round-trips on reopen). Single-select fields ignore the prop.
503
509
  > default contract, so the Arrange list can render selected items even when they aren't in
504
510
  > the current search results.
505
511
 
512
+ ### Chips display (`chips`)
513
+
514
+ By default the closed field is a button showing the selection as comma-joined text. Opt in
515
+ with `chips` to show it as inline, individually removable `Pill` chips instead — the tags form
516
+ factor. Picking still happens in the same modal: open it with the trailing button, or by
517
+ clicking the empty part of the row. Each chip's × removes that item immediately (writes
518
+ `value`, fires `onChange`, re-runs validation) without opening the modal, and keyboard focus
519
+ stays in the field. Chips render in `value` order, so with `ordered` they mirror the arranged
520
+ order. `renderValue` is ignored in this mode; labels come from `renderOptionLabel`.
521
+
522
+ ```svelte
523
+ <FieldOptions
524
+ label="Tags"
525
+ name="tags"
526
+ bind:value
527
+ {getOptions}
528
+ cardinality={-1}
529
+ allowUnknown
530
+ chips
531
+ chipIntent="primary"
532
+ />
533
+ ```
534
+
535
+ Each chip's × is a full-height 24px square (the Pill's own touch-target floor,
536
+ `--stuic-pill-dismiss-min-size`), so no extra hit-area padding is needed on touch devices.
537
+ Typing directly into the field (an inline combobox) is deliberately not part of this mode — the
538
+ modal remains the single place where options are searched and picked, which is what keeps the
539
+ field usable under a soft keyboard.
540
+
541
+ ### i18n
542
+
543
+ All built-in texts go through the `t` prop. English is the built-in default; Slovak ships
544
+ bundled and opt-in (importing it is what pulls it into your bundle — English-only consumers
545
+ pay nothing).
546
+
547
+ ```svelte
548
+ <script>
549
+ import {
550
+ FieldOptions,
551
+ createFieldOptionsT,
552
+ FIELD_OPTIONS_MESSAGES_SK,
553
+ } from "@marianmeres/stuic";
554
+
555
+ const t = createFieldOptionsT(FIELD_OPTIONS_MESSAGES_SK);
556
+ </script>
557
+
558
+ <FieldOptions name="tags" bind:value {getOptions} {t} />
559
+ ```
560
+
561
+ `createFieldOptionsT(messages, fallbackMessages?)` falls back to
562
+ `FIELD_OPTIONS_MESSAGES_EN` for any key the catalog does not define, so a partial catalog is
563
+ fine and a raw key is never rendered — pass your own object to translate into a language
564
+ that is not bundled, or to override individual texts. This matters most with `chips`, where
565
+ `chips_placeholder`, `chips_open` and `chips_remove` end up in the **closed field**, on the
566
+ page, next to your own copy (a filter with nothing selected is not "nothing selected", it is
567
+ _everything_):
568
+
569
+ ```ts
570
+ // reword two strings, keep English everywhere else
571
+ const t = createFieldOptionsT({ chips_placeholder: "Any tag", chips_open: "Edit tags" });
572
+
573
+ // or: full Slovak, plus a field specific tweak
574
+ const t = createFieldOptionsT({
575
+ ...FIELD_OPTIONS_MESSAGES_SK,
576
+ chips_placeholder: "Bez štítkov",
577
+ });
578
+ ```
579
+
580
+ Placeholders are mustache-style (`{{value}}`).
581
+
582
+ | Key | English | Used by |
583
+ | --------------------------- | ----------------------------------------------------------- | ----------------------------------- |
584
+ | `field_req_att` | This field requires attention. Please review and try again. | Validation message |
585
+ | `chips_placeholder` | Nothing selected | Empty `chips` row |
586
+ | `chips_open` | Choose... | `chips` trailing button (+ tooltip) |
587
+ | `chips_remove` | Remove {{value}} | Each chip's × accessible name |
588
+ | `search_placeholder` | Type to search... | Modal search input |
589
+ | `search_submit_placeholder` | Type to search and submit... | Modal search input (`allowUnknown`) |
590
+ | `x_close` | Clear input or close [esc] | Search input's × tooltip |
591
+ | `close` | Close [esc] | Modal close button tooltip |
592
+ | `submit` | Submit | Modal submit button |
593
+ | `select_all` | Select all | Modal control |
594
+ | `clear_all` / `clear` | Clear selected / Clear | Modal control (multi / single) |
595
+ | `cardinality_of` | of max | Selection counter |
596
+ | `cardinality_selected` | selected | Selection counter |
597
+ | `cardinality_full` | Max selection reached | Notification |
598
+ | `no_results` | No results found. | Empty options list |
599
+ | `add_new` | Add "{{value}}"... | `allowUnknown` add row |
600
+ | `click_add_new` | You must add the value to continue | Notification |
601
+ | `select_from_list` | Please select from the list only | Notification |
602
+ | `unknown_allowed` | Select or type and submit | Modal footer hint |
603
+ | `unknown_not_allowed` | Select from the list | Modal footer hint |
604
+ | `pick_tab` / `arrange_tab` | Pick / Arrange ({{value}}) | `ordered` tab header |
605
+ | `arrange_help` | Reorder the selected items. Use the buttons to move them. | `ordered` screen hint |
606
+ | `sort_az` | Sort A–Z | `ordered` shortcut |
607
+ | `reverse` | Reverse | `ordered` shortcut |
608
+ | `shuffle` | Shuffle | `ordered` shortcut |
609
+ | `move_up` / `move_down` | Move up / Move down | `ordered` row buttons |
610
+ | `move_to_top` | Move to top | `ordered` row button |
611
+ | `move_to_bottom` | Move to bottom | `ordered` row button |
612
+ | `remove_item` | Remove | `ordered` row button |
613
+ | `moved_up` / `moved_down` | Moved {{value}} up / Moved {{value}} down | Screen reader announcement |
614
+ | `removed_item` | Removed {{value}} | Screen reader announcement |
615
+ | `sorted_az` | Sorted A to Z | Screen reader announcement |
616
+ | `reversed` | Order reversed | Screen reader announcement |
617
+ | `shuffled` | Order shuffled | Screen reader announcement |
618
+
506
619
  ### Customization Examples
507
620
 
508
621
  ```css