@lavalogic/scoria 0.40.32 → 0.40.33

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 (135) hide show
  1. package/README.md +58 -58
  2. package/dist/Components/AccordionGroup.svelte +28 -28
  3. package/dist/Components/AccordionGroupButton.svelte +60 -60
  4. package/dist/Components/Action.svelte +48 -48
  5. package/dist/Components/AlertModal.svelte +102 -102
  6. package/dist/Components/Base/ContextWrapper.svelte +45 -45
  7. package/dist/Components/Base/Pagination.svelte +135 -135
  8. package/dist/Components/Base/Snippets.svelte +25 -25
  9. package/dist/Components/BigRadioSet.svelte +34 -34
  10. package/dist/Components/Bubble.svelte +38 -38
  11. package/dist/Components/Button.svelte +83 -83
  12. package/dist/Components/Checkbox.svelte +71 -71
  13. package/dist/Components/CollapsibleCard.svelte +59 -59
  14. package/dist/Components/CollapsibleMenuGroup.svelte +43 -43
  15. package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +101 -101
  16. package/dist/Components/Contexts/ContextMenu.svelte +76 -76
  17. package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
  18. package/dist/Components/Contexts/ContextMenuOption.svelte +38 -38
  19. package/dist/Components/Contexts/Toast.svelte +71 -71
  20. package/dist/Components/Contexts/ToastContainer.svelte +34 -34
  21. package/dist/Components/Contexts/Tooltip.svelte +32 -32
  22. package/dist/Components/DataMatrixIcon.svelte +37 -37
  23. package/dist/Components/DateInput.svelte +80 -80
  24. package/dist/Components/DatePicker.svelte +86 -86
  25. package/dist/Components/DesktopModal.svelte +65 -65
  26. package/dist/Components/Dial.svelte +35 -35
  27. package/dist/Components/DimensionInput.svelte +95 -95
  28. package/dist/Components/DragMenu/DragMenuHolder.svelte +53 -53
  29. package/dist/Components/DragMenu/DraggableCard.svelte +49 -49
  30. package/dist/Components/FileCard.svelte +18 -18
  31. package/dist/Components/FileUpload.svelte +115 -115
  32. package/dist/Components/GridInput.svelte +123 -123
  33. package/dist/Components/GridInputSet.svelte +21 -21
  34. package/dist/Components/HorizontalTabGroup.svelte +54 -54
  35. package/dist/Components/HorizontalTabGroupButton.svelte +32 -32
  36. package/dist/Components/Icon.svelte +68 -68
  37. package/dist/Components/InfoAlert.svelte +32 -32
  38. package/dist/Components/LoadingAnimation.svelte +228 -227
  39. package/dist/Components/LoadingModal.svelte +19 -19
  40. package/dist/Components/LoadingOverlay.svelte +20 -20
  41. package/dist/Components/Modal.svelte +127 -127
  42. package/dist/Components/MultiSelect.svelte +126 -126
  43. package/dist/Components/Nav/Nav.svelte +71 -71
  44. package/dist/Components/Nav/NavServiceMenuList.svelte +37 -37
  45. package/dist/Components/Nav/NavTab.svelte +46 -46
  46. package/dist/Components/Nav/ServiceMenuItem.svelte +62 -62
  47. package/dist/Components/Nav/ServicesNav.svelte +50 -50
  48. package/dist/Components/NumberInput.svelte +98 -98
  49. package/dist/Components/OptionCards.svelte +58 -58
  50. package/dist/Components/PageHeading.svelte +21 -21
  51. package/dist/Components/PasswordInput.svelte +61 -61
  52. package/dist/Components/PopoverButton.svelte +53 -53
  53. package/dist/Components/Portal.svelte +7 -7
  54. package/dist/Components/ProgressBubble.svelte +42 -42
  55. package/dist/Components/QuerySelect.svelte +102 -102
  56. package/dist/Components/ResourceCalendar/ResourceCalendar.svelte +241 -241
  57. package/dist/Components/SidebarPanel.svelte +32 -32
  58. package/dist/Components/SingleSelect.svelte +122 -122
  59. package/dist/Components/StepButton.svelte +48 -48
  60. package/dist/Components/StepForm.svelte +58 -58
  61. package/dist/Components/Switch.svelte +43 -43
  62. package/dist/Components/Table/ARCHITECTURE.md +298 -298
  63. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +30 -30
  64. package/dist/Components/Table/Body/Rows/ColumnList.svelte +24 -24
  65. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +165 -165
  66. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +13 -13
  67. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +120 -120
  68. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +81 -81
  69. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +92 -92
  70. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +110 -110
  71. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +54 -54
  72. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +35 -35
  73. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +64 -64
  74. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +82 -82
  75. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +88 -88
  76. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +90 -90
  77. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +96 -96
  78. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +71 -71
  79. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +124 -124
  80. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +91 -91
  81. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +88 -88
  82. package/dist/Components/Table/Body/Rows/TableRow.svelte +127 -127
  83. package/dist/Components/Table/Body/TableBody.svelte +92 -92
  84. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +25 -25
  85. package/dist/Components/Table/Headers/SelectAllHeader.svelte +20 -20
  86. package/dist/Components/Table/Headers/TableHead.svelte +175 -175
  87. package/dist/Components/Table/Misc/ColumnPanel.svelte +32 -32
  88. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +29 -29
  89. package/dist/Components/Table/Misc/FilterInput.svelte +326 -326
  90. package/dist/Components/Table/Misc/FilterPanel.svelte +79 -79
  91. package/dist/Components/Table/Misc/FilterPanelModal.svelte +21 -21
  92. package/dist/Components/Table/Misc/ShareViewModal.svelte +118 -118
  93. package/dist/Components/Table/Misc/SidePanel.svelte +24 -24
  94. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +318 -318
  95. package/dist/Components/Table/Misc/TableFooter.svelte +201 -201
  96. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +112 -112
  97. package/dist/Components/Table/Misc/TableSidebar.svelte +116 -116
  98. package/dist/Components/Table/Misc/TableViewDropdown.svelte +25 -25
  99. package/dist/Components/Table/Misc/ToolboxPanel.svelte +60 -60
  100. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +63 -63
  101. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +101 -101
  102. package/dist/Components/Table/NestedTable.svelte +29 -29
  103. package/dist/Components/Table/Table.svelte +140 -140
  104. package/dist/Components/Test/TestContextConsumer.svelte +8 -8
  105. package/dist/Components/TextArea.svelte +92 -90
  106. package/dist/Components/TextInput.svelte +128 -117
  107. package/dist/Components/ThreeStateRadio.svelte +101 -101
  108. package/dist/Components/Touch/BoolCard.svelte +27 -27
  109. package/dist/Components/Touch/DateModal.svelte +98 -98
  110. package/dist/Components/Touch/EditCard.svelte +44 -44
  111. package/dist/Components/Touch/InfoCard.svelte +25 -25
  112. package/dist/Components/Touch/InfoTextCard.svelte +22 -22
  113. package/dist/Components/Touch/ModalExplanation.svelte +13 -13
  114. package/dist/Components/Touch/NumberKeyboard.svelte +81 -81
  115. package/dist/Components/Touch/NumberModal.svelte +49 -49
  116. package/dist/Components/Touch/PlusMinusCard.svelte +40 -40
  117. package/dist/Components/Touch/SelectModal.svelte +86 -86
  118. package/dist/Components/Touch/SummaryCard.svelte +74 -74
  119. package/dist/Components/Touch/TextAreaModal.svelte +53 -53
  120. package/dist/Components/Touch/TextModal.svelte +56 -56
  121. package/dist/Components/Touch/TouchCard.svelte +28 -28
  122. package/dist/Components/Touch/TouchModal.svelte +141 -141
  123. package/dist/Components/Touch/UtilityButton.svelte +63 -63
  124. package/dist/Components/VerticalTabGroup.svelte +38 -38
  125. package/dist/Components/VerticalTabGroupButton.svelte +46 -46
  126. package/dist/Helpers/Datamatrix.d.ts +19 -19
  127. package/dist/Helpers/Datamatrix.js +291 -291
  128. package/dist/Types/Examples/ExampleModal.svelte +27 -27
  129. package/dist/paraglide/README.md +1 -1
  130. package/dist/scss/_basics.scss +12 -12
  131. package/dist/scss/_colours.scss +140 -140
  132. package/dist/scss/_motion.scss +57 -57
  133. package/dist/scss/_sizing.scss +85 -85
  134. package/dist/scss/_transitions.scss +8 -8
  135. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- module
5
- lang="ts"
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ module
5
+ lang="ts"
6
6
  >import { m as i18n } from "../paraglide/messages.js";
7
7
  import { browser } from "$app/environment";
8
8
  import { DATAMatrix } from "../Helpers/Datamatrix.js";
@@ -13,8 +13,8 @@ import { onMount } from "svelte";
13
13
  import Action from "./Action.svelte";
14
14
  import BaseModal from "./Base/BaseModal.svelte";
15
15
  import DataMatrixIcon from "./DataMatrixIcon.svelte";
16
- </script>
17
-
16
+ </script>
17
+
18
18
  <script lang="ts">let { header, buttons, mandatory = false, staticHeight = false, staticWidth = false, minWidth, minHeight, width, height, onShowCallback, submitRef = $bindable(), defaultTimer, isValid = true, noscroll = false, onsubmit, headerExtra, explanation, children, footer, onclose, autofocusSelector } = $props();
19
19
  // `open` drives BaseModal's bindable `value`. Default true (the
20
20
  // legacy "open immediately on mount" semantic). Flipping it to
@@ -87,125 +87,125 @@ const dialogClassNames = $derived([
87
87
  noscroll ? "noscroll" : null
88
88
  ].filter((c) => c !== null).join(" "));
89
89
  const dialogStyle = $derived(`--timer: ${defaultTimer ? defaultTimer.time.toString() + "ms" : "unset"};` + (minWidth != null ? `--dialog-min-width: ${minWidth};` : "") + (minHeight != null ? `--dialog-min-height: ${minHeight};` : "") + (height != null ? `--dialog-height: ${height};` : "") + (width != null ? `--dialog-width: ${width};` : ""));
90
- </script>
91
-
92
- <BaseModal
93
- bind:value={open}
94
- {onclose}
95
- {mandatory}
96
- {autofocusSelector}
97
- dialogClass={dialogClassNames}
98
- {dialogStyle}
99
- >
100
- <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
101
- <!-- svelte-ignore a11y_click_events_have_key_events -->
102
- <form
103
- method="dialog"
104
- bind:this={form}
105
- onsubmit={(e) => {
106
- e.preventDefault();
107
- clearTimer();
108
- if (isActive) {
109
- onsubmit?.(e);
110
- }
111
- }}
112
- onclick={clearTimer}
113
- class="modal-root"
114
- >
115
- <div class="modal-header">
116
- {#if typeof header === 'string'}
117
- {#if mandatory}
118
- <h3 class="modal-heading">{header}</h3>
119
- {:else}
120
- <div class="title-wrapper">
121
- <h3 class="modal-heading">{header}</h3>
122
- <div class="close-button">
123
- <Action
124
- size={Size.DoubleXLarge}
125
- onclick={requestClose}
126
- icon={{
127
- name: 'cross',
128
- }}
129
- onkeydown={handleEsc}
130
- colourSet={ColourSet.Primary}
131
- label={i18n['scoria.action.close_modal_generic']()}
132
- />
133
- </div>
134
- </div>
135
- {/if}
136
- {:else if typeof header === 'function'}
137
- {@render header()}
138
- {/if}
139
-
140
- {#if headerExtra}
141
- {@render headerExtra()}
142
- {/if}
143
- </div>
144
-
145
- {#if defaultTimer}
146
- <div class="bar-container">
147
- <div
148
- class:paused
149
- class="bar-timer"
150
- ></div>
151
- </div>
152
- {/if}
153
-
154
- <div
155
- class="modal-main"
156
- class:noscroll
157
- >
158
- {#if explanation}
159
- {@render explanation()}
160
- {/if}
161
- {@render children()}
162
- </div>
163
-
164
- {#if footer}
165
- {@render footer()}
166
- {:else if buttons?.length}
167
- <div class="modal-footer">
168
- {#each buttons as button, index (button.label)}
169
- {#if button.callback}
170
- <div class="button-barcode-set">
171
- {#if barcodeIcons[index]}
172
- <DataMatrixIcon
173
- title={button.label}
174
- icon={{ kind: 'svg', svg: barcodeIcons[index] }}
175
- />
176
- {/if}
177
- <button
178
- onkeydown={passthrough}
179
- class:margin-inline-start={button.margin === 'left'}
180
- class:margin-inline-end={button.margin === 'right'}
181
- type={button.type ?? 'button'}
182
- onclick={button.callback}>{button.label}</button
183
- >
184
- </div>
185
- {:else}
186
- <div class="button-barcode-set">
187
- {#if barcodeIcons[index]}
188
- <DataMatrixIcon
189
- title={button.label}
190
- icon={{ kind: 'svg', svg: barcodeIcons[index] }}
191
- />
192
- {/if}
193
- <button
194
- onkeydown={passthrough}
195
- disabled={!isValid}
196
- class:margin-inline-start={button.margin === 'left'}
197
- class:margin-inline-end={button.margin === 'right'}
198
- bind:this={submitRef}
199
- type={button.type ?? 'submit'}>{button.label}</button
200
- >
201
- </div>
202
- {/if}
203
- {/each}
204
- </div>
205
- {/if}
206
- </form>
207
- </BaseModal>
208
-
90
+ </script>
91
+
92
+ <BaseModal
93
+ bind:value={open}
94
+ {onclose}
95
+ {mandatory}
96
+ {autofocusSelector}
97
+ dialogClass={dialogClassNames}
98
+ {dialogStyle}
99
+ >
100
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
101
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
102
+ <form
103
+ method="dialog"
104
+ bind:this={form}
105
+ onsubmit={(e) => {
106
+ e.preventDefault();
107
+ clearTimer();
108
+ if (isActive) {
109
+ onsubmit?.(e);
110
+ }
111
+ }}
112
+ onclick={clearTimer}
113
+ class="modal-root"
114
+ >
115
+ <div class="modal-header">
116
+ {#if typeof header === 'string'}
117
+ {#if mandatory}
118
+ <h3 class="modal-heading">{header}</h3>
119
+ {:else}
120
+ <div class="title-wrapper">
121
+ <h3 class="modal-heading">{header}</h3>
122
+ <div class="close-button">
123
+ <Action
124
+ size={Size.DoubleXLarge}
125
+ onclick={requestClose}
126
+ icon={{
127
+ name: 'cross',
128
+ }}
129
+ onkeydown={handleEsc}
130
+ colourSet={ColourSet.Primary}
131
+ label={i18n['scoria.action.close_modal_generic']()}
132
+ />
133
+ </div>
134
+ </div>
135
+ {/if}
136
+ {:else if typeof header === 'function'}
137
+ {@render header()}
138
+ {/if}
139
+
140
+ {#if headerExtra}
141
+ {@render headerExtra()}
142
+ {/if}
143
+ </div>
144
+
145
+ {#if defaultTimer}
146
+ <div class="bar-container">
147
+ <div
148
+ class:paused
149
+ class="bar-timer"
150
+ ></div>
151
+ </div>
152
+ {/if}
153
+
154
+ <div
155
+ class="modal-main"
156
+ class:noscroll
157
+ >
158
+ {#if explanation}
159
+ {@render explanation()}
160
+ {/if}
161
+ {@render children()}
162
+ </div>
163
+
164
+ {#if footer}
165
+ {@render footer()}
166
+ {:else if buttons?.length}
167
+ <div class="modal-footer">
168
+ {#each buttons as button, index (button.label)}
169
+ {#if button.callback}
170
+ <div class="button-barcode-set">
171
+ {#if barcodeIcons[index]}
172
+ <DataMatrixIcon
173
+ title={button.label}
174
+ icon={{ kind: 'svg', svg: barcodeIcons[index] }}
175
+ />
176
+ {/if}
177
+ <button
178
+ onkeydown={passthrough}
179
+ class:margin-inline-start={button.margin === 'left'}
180
+ class:margin-inline-end={button.margin === 'right'}
181
+ type={button.type ?? 'button'}
182
+ onclick={button.callback}>{button.label}</button
183
+ >
184
+ </div>
185
+ {:else}
186
+ <div class="button-barcode-set">
187
+ {#if barcodeIcons[index]}
188
+ <DataMatrixIcon
189
+ title={button.label}
190
+ icon={{ kind: 'svg', svg: barcodeIcons[index] }}
191
+ />
192
+ {/if}
193
+ <button
194
+ onkeydown={passthrough}
195
+ disabled={!isValid}
196
+ class:margin-inline-start={button.margin === 'left'}
197
+ class:margin-inline-end={button.margin === 'right'}
198
+ bind:this={submitRef}
199
+ type={button.type ?? 'submit'}>{button.label}</button
200
+ >
201
+ </div>
202
+ {/if}
203
+ {/each}
204
+ </div>
205
+ {/if}
206
+ </form>
207
+ </BaseModal>
208
+
209
209
  <style>dialog {
210
210
  overflow: clip;
211
211
  background-color: #e9ecf1;
@@ -554,4 +554,4 @@ div.bar-container div.bar-timer.paused {
554
554
  }
555
555
  :global form > *:last-child {
556
556
  border-radius: 0px 0px 4px 4px;
557
- }</style>
557
+ }</style>
@@ -1,8 +1,8 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- generics="V extends object, VP extends ValueProp<V>"
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="V extends object, VP extends ValueProp<V>"
6
6
  >import { m as i18n } from "../paraglide/messages.js";
7
7
  import { autoPluralise, generateWeakId, vowels } from "../Helpers/Helpers.svelte.js";
8
8
  import { attachDropdownPortal } from "../Helpers/dropdownPortal.js";
@@ -74,126 +74,126 @@ onMount(() => {
74
74
  };
75
75
  });
76
76
  const isInvalid = $derived(required && !selectedValues.length || invalid);
77
- </script>
78
-
79
- <div
80
- class:invalid={isInvalid}
81
- class="select-wrapper"
82
- style={`${width ? `--input-width: ${width};` : ''}${height ? `--input-height: ${height};` : ''}`}
83
- >
84
- {#if label}
85
- <label for={inputId}>
86
- <span>{label}</span>
87
- <span class="border">{label}</span>
88
- </label>
89
- {/if}
90
-
91
- <Svelecte
92
- multiple
93
- {valueAsObject}
94
- {disabled}
95
- {inputId}
96
- valueField={valueProp}
97
- labelField={labelProp}
98
- {options}
99
- searchable
100
- value={selectedValues}
101
- onChange={(e: Array<V>) => {
102
- // svelecte always emits the full option objects; normalise to the
103
- // shape the variant promised: primitives for AsPrimitive,
104
- // objects for AsObject. This is what the discriminated
105
- // `onchange` typing now guarantees to consumers.
106
- if (valueAsObject) {
107
- void (onchange as (v: Array<V>) => void | Promise<void>)(e);
108
- } else {
109
- const primitives = e.map((it) => it[valueProp]);
110
- void (onchange as (v: Array<V[VP]>) => void | Promise<void>)(primitives);
111
- }
112
- }}
113
- {name}
114
- selectOnTab
115
- keepSelectionInList
116
- searchProps={{ keepSelectionInList: true }}
117
- creatable={false}
118
- collapseSelection={collapseSelection ? 'always' : null}
119
- deselectMode="toggle"
120
- highlightFirstItem={false}
121
- placeholder={placeholder ?? fallbackPlaceholder}
122
- selection={collapseSelection ? selection : undefined}
123
- >
124
- {#snippet option(opt)}
125
- {@const option = opt as V}
126
- <span class="dropdown-item">
127
- <div
128
- class="toggle-icon"
129
- class:yes={selectedKeys.has(option[valueProp])}
130
- >
131
- <Icon
132
- name="tick"
133
- size={Size.MediumSmall}
134
- />
135
- </div>
136
- {option[labelProp]}</span
137
- >
138
- {/snippet}
139
-
140
- {#snippet collapsedSelection(selectedOptions: Array<object> /*_i18n*/)}
141
- {@const count = selectedOptions.length}
142
- <span class="selection"
143
- >{count ? collapsedText(count) : (placeholder ?? fallbackPlaceholder)}</span
144
- >
145
- {/snippet}
146
-
147
- {#snippet append()}
148
- <div class="icons">
149
- <Action
150
- {disabled}
151
- size={Size.Small}
152
- noTabIndex
153
- colourSet={ColourSet.Auxiliary}
154
- onclick={(e: MouseEvent) => {
155
- if (isExpanded) {
156
- e.stopPropagation();
157
- }
158
-
159
- if (selectedValues.length) {
160
- // Empty array satisfies both Array<V> and Array<V[VP]>.
161
- void (onchange as (v: Array<V> | Array<V[VP]>) => void | Promise<void>)([]);
162
- } else if (valueAsObject) {
163
- void (onchange as (v: Array<V>) => void | Promise<void>)(options.concat());
164
- } else {
165
- const primitives = options.map((it) => it[valueProp]);
166
- void (onchange as (v: Array<V[VP]>) => void | Promise<void>)(primitives);
167
- }
168
- }}
169
- icon={{
170
- name: selectedValues.length ? 'close-menu-cross' : 'manage-product-group',
171
- colour: Colour['$ui-blue-10'],
172
- }}
173
- />
174
-
175
- <Action
176
- {disabled}
177
- size={Size.Small}
178
- noTabIndex
179
- colourSet={ColourSet.Auxiliary}
180
- icon={{
181
- name: isExpanded ? 'chevron-up' : 'chevron-down',
182
- colour: Colour['$ui-blue-10'],
183
- }}
184
- />
185
- </div>
186
- {/snippet}
187
- {#snippet toggleIcon()}
188
- <div class="nothing"></div>
189
- {/snippet}
190
- </Svelecte>
191
-
192
- {#snippet selection(/*_selectedOptions: Array<unknown>*/)}
193
- <!-- collapsed selection rendered above -->
194
- {/snippet}
195
- </div>
196
-
77
+ </script>
78
+
79
+ <div
80
+ class:invalid={isInvalid}
81
+ class="select-wrapper"
82
+ style={`${width ? `--input-width: ${width};` : ''}${height ? `--input-height: ${height};` : ''}`}
83
+ >
84
+ {#if label}
85
+ <label for={inputId}>
86
+ <span>{label}</span>
87
+ <span class="border">{label}</span>
88
+ </label>
89
+ {/if}
90
+
91
+ <Svelecte
92
+ multiple
93
+ {valueAsObject}
94
+ {disabled}
95
+ {inputId}
96
+ valueField={valueProp}
97
+ labelField={labelProp}
98
+ {options}
99
+ searchable
100
+ value={selectedValues}
101
+ onChange={(e: Array<V>) => {
102
+ // svelecte always emits the full option objects; normalise to the
103
+ // shape the variant promised: primitives for AsPrimitive,
104
+ // objects for AsObject. This is what the discriminated
105
+ // `onchange` typing now guarantees to consumers.
106
+ if (valueAsObject) {
107
+ void (onchange as (v: Array<V>) => void | Promise<void>)(e);
108
+ } else {
109
+ const primitives = e.map((it) => it[valueProp]);
110
+ void (onchange as (v: Array<V[VP]>) => void | Promise<void>)(primitives);
111
+ }
112
+ }}
113
+ {name}
114
+ selectOnTab
115
+ keepSelectionInList
116
+ searchProps={{ keepSelectionInList: true }}
117
+ creatable={false}
118
+ collapseSelection={collapseSelection ? 'always' : null}
119
+ deselectMode="toggle"
120
+ highlightFirstItem={false}
121
+ placeholder={placeholder ?? fallbackPlaceholder}
122
+ selection={collapseSelection ? selection : undefined}
123
+ >
124
+ {#snippet option(opt)}
125
+ {@const option = opt as V}
126
+ <span class="dropdown-item">
127
+ <div
128
+ class="toggle-icon"
129
+ class:yes={selectedKeys.has(option[valueProp])}
130
+ >
131
+ <Icon
132
+ name="tick"
133
+ size={Size.MediumSmall}
134
+ />
135
+ </div>
136
+ {option[labelProp]}</span
137
+ >
138
+ {/snippet}
139
+
140
+ {#snippet collapsedSelection(selectedOptions: Array<object> /*_i18n*/)}
141
+ {@const count = selectedOptions.length}
142
+ <span class="selection"
143
+ >{count ? collapsedText(count) : (placeholder ?? fallbackPlaceholder)}</span
144
+ >
145
+ {/snippet}
146
+
147
+ {#snippet append()}
148
+ <div class="icons">
149
+ <Action
150
+ {disabled}
151
+ size={Size.Small}
152
+ noTabIndex
153
+ colourSet={ColourSet.Auxiliary}
154
+ onclick={(e: MouseEvent) => {
155
+ if (isExpanded) {
156
+ e.stopPropagation();
157
+ }
158
+
159
+ if (selectedValues.length) {
160
+ // Empty array satisfies both Array<V> and Array<V[VP]>.
161
+ void (onchange as (v: Array<V> | Array<V[VP]>) => void | Promise<void>)([]);
162
+ } else if (valueAsObject) {
163
+ void (onchange as (v: Array<V>) => void | Promise<void>)(options.concat());
164
+ } else {
165
+ const primitives = options.map((it) => it[valueProp]);
166
+ void (onchange as (v: Array<V[VP]>) => void | Promise<void>)(primitives);
167
+ }
168
+ }}
169
+ icon={{
170
+ name: selectedValues.length ? 'close-menu-cross' : 'manage-product-group',
171
+ colour: Colour['$ui-blue-10'],
172
+ }}
173
+ />
174
+
175
+ <Action
176
+ {disabled}
177
+ size={Size.Small}
178
+ noTabIndex
179
+ colourSet={ColourSet.Auxiliary}
180
+ icon={{
181
+ name: isExpanded ? 'chevron-up' : 'chevron-down',
182
+ colour: Colour['$ui-blue-10'],
183
+ }}
184
+ />
185
+ </div>
186
+ {/snippet}
187
+ {#snippet toggleIcon()}
188
+ <div class="nothing"></div>
189
+ {/snippet}
190
+ </Svelecte>
191
+
192
+ {#snippet selection(/*_selectedOptions: Array<unknown>*/)}
193
+ <!-- collapsed selection rendered above -->
194
+ {/snippet}
195
+ </div>
196
+
197
197
  <style>.select-wrapper {
198
198
  min-width: var(--input-min-width, 12rem);
199
199
  width: var(--input-width, 100%);
@@ -368,4 +368,4 @@ div.icons {
368
368
  }
369
369
  :global(.dropdown-item) .toggle-icon.yes {
370
370
  opacity: 1;
371
- }</style>
371
+ }</style>