@lavalogic/scoria 0.40.31 → 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 (137) 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/Icons.d.ts +3 -3
  38. package/dist/Components/Icons.js +11 -11
  39. package/dist/Components/InfoAlert.svelte +32 -32
  40. package/dist/Components/LoadingAnimation.svelte +228 -227
  41. package/dist/Components/LoadingModal.svelte +19 -19
  42. package/dist/Components/LoadingOverlay.svelte +20 -20
  43. package/dist/Components/Modal.svelte +127 -127
  44. package/dist/Components/MultiSelect.svelte +126 -126
  45. package/dist/Components/Nav/Nav.svelte +71 -71
  46. package/dist/Components/Nav/NavServiceMenuList.svelte +37 -37
  47. package/dist/Components/Nav/NavTab.svelte +46 -46
  48. package/dist/Components/Nav/ServiceMenuItem.svelte +62 -62
  49. package/dist/Components/Nav/ServicesNav.svelte +50 -50
  50. package/dist/Components/NumberInput.svelte +98 -98
  51. package/dist/Components/OptionCards.svelte +58 -58
  52. package/dist/Components/PageHeading.svelte +21 -21
  53. package/dist/Components/PasswordInput.svelte +61 -61
  54. package/dist/Components/PopoverButton.svelte +53 -53
  55. package/dist/Components/Portal.svelte +7 -7
  56. package/dist/Components/ProgressBubble.svelte +42 -42
  57. package/dist/Components/QuerySelect.svelte +102 -102
  58. package/dist/Components/ResourceCalendar/ResourceCalendar.svelte +241 -241
  59. package/dist/Components/SidebarPanel.svelte +32 -32
  60. package/dist/Components/SingleSelect.svelte +122 -122
  61. package/dist/Components/StepButton.svelte +48 -48
  62. package/dist/Components/StepForm.svelte +58 -58
  63. package/dist/Components/Switch.svelte +43 -43
  64. package/dist/Components/Table/ARCHITECTURE.md +298 -298
  65. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +30 -30
  66. package/dist/Components/Table/Body/Rows/ColumnList.svelte +24 -24
  67. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +165 -165
  68. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +13 -13
  69. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +120 -120
  70. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +81 -81
  71. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +92 -92
  72. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +110 -110
  73. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +54 -54
  74. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +35 -35
  75. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +64 -64
  76. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +82 -82
  77. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +88 -88
  78. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +90 -90
  79. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +96 -96
  80. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +71 -71
  81. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +124 -124
  82. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +91 -91
  83. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +88 -88
  84. package/dist/Components/Table/Body/Rows/TableRow.svelte +127 -127
  85. package/dist/Components/Table/Body/TableBody.svelte +92 -92
  86. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +25 -25
  87. package/dist/Components/Table/Headers/SelectAllHeader.svelte +20 -20
  88. package/dist/Components/Table/Headers/TableHead.svelte +175 -175
  89. package/dist/Components/Table/Misc/ColumnPanel.svelte +32 -32
  90. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +29 -29
  91. package/dist/Components/Table/Misc/FilterInput.svelte +326 -326
  92. package/dist/Components/Table/Misc/FilterPanel.svelte +79 -79
  93. package/dist/Components/Table/Misc/FilterPanelModal.svelte +21 -21
  94. package/dist/Components/Table/Misc/ShareViewModal.svelte +118 -118
  95. package/dist/Components/Table/Misc/SidePanel.svelte +24 -24
  96. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +318 -318
  97. package/dist/Components/Table/Misc/TableFooter.svelte +201 -201
  98. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +112 -112
  99. package/dist/Components/Table/Misc/TableSidebar.svelte +116 -116
  100. package/dist/Components/Table/Misc/TableViewDropdown.svelte +25 -25
  101. package/dist/Components/Table/Misc/ToolboxPanel.svelte +60 -60
  102. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +63 -63
  103. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +101 -101
  104. package/dist/Components/Table/NestedTable.svelte +29 -29
  105. package/dist/Components/Table/Table.svelte +140 -140
  106. package/dist/Components/Test/TestContextConsumer.svelte +8 -8
  107. package/dist/Components/TextArea.svelte +92 -90
  108. package/dist/Components/TextInput.svelte +128 -117
  109. package/dist/Components/ThreeStateRadio.svelte +101 -101
  110. package/dist/Components/Touch/BoolCard.svelte +27 -27
  111. package/dist/Components/Touch/DateModal.svelte +98 -98
  112. package/dist/Components/Touch/EditCard.svelte +44 -44
  113. package/dist/Components/Touch/InfoCard.svelte +25 -25
  114. package/dist/Components/Touch/InfoTextCard.svelte +22 -22
  115. package/dist/Components/Touch/ModalExplanation.svelte +13 -13
  116. package/dist/Components/Touch/NumberKeyboard.svelte +81 -81
  117. package/dist/Components/Touch/NumberModal.svelte +49 -49
  118. package/dist/Components/Touch/PlusMinusCard.svelte +40 -40
  119. package/dist/Components/Touch/SelectModal.svelte +86 -86
  120. package/dist/Components/Touch/SummaryCard.svelte +74 -74
  121. package/dist/Components/Touch/TextAreaModal.svelte +53 -53
  122. package/dist/Components/Touch/TextModal.svelte +56 -56
  123. package/dist/Components/Touch/TouchCard.svelte +28 -28
  124. package/dist/Components/Touch/TouchModal.svelte +141 -141
  125. package/dist/Components/Touch/UtilityButton.svelte +63 -63
  126. package/dist/Components/VerticalTabGroup.svelte +38 -38
  127. package/dist/Components/VerticalTabGroupButton.svelte +46 -46
  128. package/dist/Helpers/Datamatrix.d.ts +19 -19
  129. package/dist/Helpers/Datamatrix.js +291 -291
  130. package/dist/Types/Examples/ExampleModal.svelte +27 -27
  131. package/dist/paraglide/README.md +1 -1
  132. package/dist/scss/_basics.scss +12 -12
  133. package/dist/scss/_colours.scss +140 -140
  134. package/dist/scss/_motion.scss +57 -57
  135. package/dist/scss/_sizing.scss +85 -85
  136. package/dist/scss/_transitions.scss +8 -8
  137. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- generics="T extends object, IdType extends Primitive"
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="T extends object, IdType extends Primitive"
6
6
  >import Action from "../../Action.svelte";
7
7
  import TextInput from "../../TextInput.svelte";
8
8
  import { Colour, ColourSet } from "../../../scss/colours.js";
@@ -102,79 +102,79 @@ function toggleGroup(name) {
102
102
  function noopKeydown(_e) {
103
103
  // intentionally empty
104
104
  }
105
- </script>
106
-
107
- <section class="side-panel-section">
108
- <header class="side-panel-header">
109
- <h2>{i18n['scoria.action.advanced_filter']()}</h2>
110
- </header>
111
-
112
- <div class="toolbar">
113
- <!-- Quick-switch dropdown for saved filter sets. Sits above the
114
- search box; saving a filter is done from the Table
115
- Configuration modal's "Save a new Filter" tab. -->
116
- <TableViewDropdown kind="filter" />
117
- <div class="quick-find">
118
- <TextInput
119
- labelTop={i18n['scoria.label.quick_find_filter']()}
120
- placeholder={i18n['scoria.label.filter_placeholder']()}
121
- bind:value={quickFindValue}
122
- rightIcon={{ name: 'search', size: Size.Medium }}
123
- onkeydown={noopKeydown}
124
- />
125
- </div>
126
- </div>
127
-
128
- <div class="side-panel-body">
129
- {#if filterableDefs.length === 0}
130
- <p class="empty">{i18n['scoria.text.no_filterable_columns']()}</p>
131
- {:else if matchingDefs.length === 0}
132
- <p class="empty">
133
- {i18n['scoria.text.no_filters_match']({ query: quickFindValue })}
134
- </p>
135
- {:else}
136
- <div class="groups">
137
- {#each orderedGroupNames as groupName (groupName)}
138
- {@const defsInGroup = groupedDefs.get(groupName) ?? []}
139
- {@const isCollapsed = collapsedGroups.has(groupName)}
140
- {#if defsInGroup.length > 0}
141
- <section
142
- class="group"
143
- class:collapsed={isCollapsed}
144
- >
145
- <header class="group-header">
146
- <h3>{groupName}</h3>
147
- <Action
148
- label={isCollapsed ? `Expand ${groupName}` : `Collapse ${groupName}`}
149
- colourSet={ColourSet.Auxiliary}
150
- icon={{
151
- name: isCollapsed ? 'circle-plus' : 'circle-minus',
152
- size: Size.Medium,
153
- colour: Colour['$ui-blue-9'],
154
- }}
155
- onclick={() => {
156
- toggleGroup(groupName);
157
- }}
158
- />
159
- </header>
160
- {#if !isCollapsed}
161
- <div class="group-body">
162
- {#each defsInGroup as def (def.id)}
163
- <FilterInput
164
- {def}
165
- customFilters={tableContext.remoteFilters}
166
- />
167
- {/each}
168
- </div>
169
- {/if}
170
- </section>
171
- {/if}
172
- {/each}
173
- </div>
174
- {/if}
175
- </div>
176
- </section>
177
-
105
+ </script>
106
+
107
+ <section class="side-panel-section">
108
+ <header class="side-panel-header">
109
+ <h2>{i18n['scoria.action.advanced_filter']()}</h2>
110
+ </header>
111
+
112
+ <div class="toolbar">
113
+ <!-- Quick-switch dropdown for saved filter sets. Sits above the
114
+ search box; saving a filter is done from the Table
115
+ Configuration modal's "Save a new Filter" tab. -->
116
+ <TableViewDropdown kind="filter" />
117
+ <div class="quick-find">
118
+ <TextInput
119
+ labelTop={i18n['scoria.label.quick_find_filter']()}
120
+ placeholder={i18n['scoria.label.filter_placeholder']()}
121
+ bind:value={quickFindValue}
122
+ rightIcon={{ name: 'search', size: Size.Medium }}
123
+ onkeydown={noopKeydown}
124
+ />
125
+ </div>
126
+ </div>
127
+
128
+ <div class="side-panel-body">
129
+ {#if filterableDefs.length === 0}
130
+ <p class="empty">{i18n['scoria.text.no_filterable_columns']()}</p>
131
+ {:else if matchingDefs.length === 0}
132
+ <p class="empty">
133
+ {i18n['scoria.text.no_filters_match']({ query: quickFindValue })}
134
+ </p>
135
+ {:else}
136
+ <div class="groups">
137
+ {#each orderedGroupNames as groupName (groupName)}
138
+ {@const defsInGroup = groupedDefs.get(groupName) ?? []}
139
+ {@const isCollapsed = collapsedGroups.has(groupName)}
140
+ {#if defsInGroup.length > 0}
141
+ <section
142
+ class="group"
143
+ class:collapsed={isCollapsed}
144
+ >
145
+ <header class="group-header">
146
+ <h3>{groupName}</h3>
147
+ <Action
148
+ label={isCollapsed ? `Expand ${groupName}` : `Collapse ${groupName}`}
149
+ colourSet={ColourSet.Auxiliary}
150
+ icon={{
151
+ name: isCollapsed ? 'circle-plus' : 'circle-minus',
152
+ size: Size.Medium,
153
+ colour: Colour['$ui-blue-9'],
154
+ }}
155
+ onclick={() => {
156
+ toggleGroup(groupName);
157
+ }}
158
+ />
159
+ </header>
160
+ {#if !isCollapsed}
161
+ <div class="group-body">
162
+ {#each defsInGroup as def (def.id)}
163
+ <FilterInput
164
+ {def}
165
+ customFilters={tableContext.remoteFilters}
166
+ />
167
+ {/each}
168
+ </div>
169
+ {/if}
170
+ </section>
171
+ {/if}
172
+ {/each}
173
+ </div>
174
+ {/if}
175
+ </div>
176
+ </section>
177
+
178
178
  <style>.side-panel-section {
179
179
  display: flex;
180
180
  flex-flow: column nowrap;
@@ -313,4 +313,4 @@ p.empty {
313
313
  display: flex;
314
314
  flex-flow: column nowrap;
315
315
  gap: 0.5rem;
316
- }</style>
316
+ }</style>
@@ -1,28 +1,28 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- module
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ module
6
6
  >import DesktopModal from "../../DesktopModal.svelte";
7
7
  import { cssLength } from "../../../Helpers/Helpers.svelte.js";
8
8
  import { m as i18n } from "../../../paraglide/messages.js";
9
9
  import FilterPanel from "./FilterPanel.svelte";
10
- </script>
11
-
10
+ </script>
11
+
12
12
  <script lang="ts">const { onclose } = $props();
13
- </script>
14
-
15
- <DesktopModal
16
- width={cssLength('800px')}
17
- headerLabel={i18n['scoria.label.filter_by']()}
18
- onclose={() => onclose?.()}
19
- buttons={[{ label: i18n['scoria.action.close'](), callback: () => onclose?.() }]}
20
- >
21
- <div class="flex">
22
- <FilterPanel />
23
- </div>
24
- </DesktopModal>
25
-
13
+ </script>
14
+
15
+ <DesktopModal
16
+ width={cssLength('800px')}
17
+ headerLabel={i18n['scoria.label.filter_by']()}
18
+ onclose={() => onclose?.()}
19
+ buttons={[{ label: i18n['scoria.action.close'](), callback: () => onclose?.() }]}
20
+ >
21
+ <div class="flex">
22
+ <FilterPanel />
23
+ </div>
24
+ </DesktopModal>
25
+
26
26
  <style>.flex {
27
27
  display: flex;
28
28
  flex-flow: column nowrap;
@@ -30,4 +30,4 @@ import FilterPanel from "./FilterPanel.svelte";
30
30
  width: 100%;
31
31
  flex: 1;
32
32
  overflow: hidden;
33
- }</style>
33
+ }</style>
@@ -1,8 +1,8 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- generics="T extends object, IdType extends Primitive"
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ generics="T extends object, IdType extends Primitive"
6
6
  >import Button from "../../Button.svelte";
7
7
  import DesktopModal from "../../DesktopModal.svelte";
8
8
  import Icon from "../../Icon.svelte";
@@ -157,118 +157,118 @@ async function save() {
157
157
  saving = false;
158
158
  }
159
159
  }
160
- </script>
161
-
162
- <DesktopModal
163
- headerLabel={i18n['scoria.label.share_header']({ name: view.name })}
164
- headerSubtitle={view.kind === 'filter'
165
- ? i18n['scoria.text.share_filter_subtitle']()
166
- : i18n['scoria.text.share_layout_subtitle']()}
167
- onclose={() => {
168
- if (!saving) {
169
- onclose();
170
- }
171
- }}
172
- width={cssLength('40vw')}
173
- minWidth={cssLength('32rem')}
174
- buttons={[
175
- {
176
- label: i18n['scoria.action.cancel'](),
177
- callback: () => {
178
- if (!saving) {
179
- onclose();
180
- }
181
- },
182
- disabled: saving,
183
- },
184
- {
185
- label: saving ? i18n['scoria.action.saving']() : i18n['scoria.action.save'](),
186
- callback: () => {
187
- void save();
188
- },
189
- colourSet: ColourSet.Primary,
190
- disabled: saving || !dirty || allUsers === null,
191
- },
192
- ]}
193
- >
194
- <div class="share-body">
195
- {#if errorMessage}
196
- <div
197
- class="error-banner"
198
- role="alert"
199
- >
200
- <Icon
201
- name="circle-exclamation"
202
- size={Size.Small}
203
- />
204
- <span>{errorMessage}</span>
205
- </div>
206
- {/if}
207
-
208
- <div class="picker">
209
- {#if loadingUsers && allUsers === null}
210
- <InfoAlert>{i18n['scoria.message.loading_users']()}</InfoAlert>
211
- {:else if allUsers !== null}
212
- <MultiSelect
213
- label={i18n['scoria.label.users']()}
214
- name="User"
215
- placeholder={i18n['scoria.label.select_user']()}
216
- options={allUsers as Array<DatatableViewUser>}
217
- labelProp="displayName"
218
- valueProp="id"
219
- valueAsObject={true}
220
- selectedValues={selected}
221
- onchange={(values) => {
222
- selected = values;
223
- }}
224
- />
225
- {/if}
226
- </div>
227
-
228
- {#if selected.length === 0}
229
- <InfoAlert>
230
- {view.kind === 'filter'
231
- ? i18n['scoria.text.no_users_filter']()
232
- : i18n['scoria.text.no_users_layout']()}
233
- </InfoAlert>
234
- {:else}
235
- <ul class="user-card-list">
236
- {#each selected as user (user.id)}
237
- <li class="user-card">
238
- <div class="user-info">
239
- <Icon
240
- name="user-3"
241
- size={Size.Medium}
242
- />
243
- <span class="user-name">{user.displayName}</span>
244
- </div>
245
- <div class="user-meta">
246
- <!--
247
- v1 sharing exposes a single role - subscriber - so
248
- the "permission" surface is informational only. The
249
- backend's `editor` / `systemOwned` flags are
250
- reserved no-ops in v1 (see `DatatableView` DTO
251
- JSDoc); scoria never sets them.
252
- -->
253
- <span class="permission-pill">{i18n['scoria.label.subscriber']()}</span>
254
- <Button
255
- variant={Variant.Secondary}
256
- size={Size.MediumSmall}
257
- nowrap
258
- iconLeft={{ name: 'circle-cross', size: Size.Small }}
259
- disabled={saving}
260
- onclick={() => {
261
- removeFromSelection(user.id);
262
- }}>{i18n['scoria.action.remove']()}</Button
263
- >
264
- </div>
265
- </li>
266
- {/each}
267
- </ul>
268
- {/if}
269
- </div>
270
- </DesktopModal>
271
-
160
+ </script>
161
+
162
+ <DesktopModal
163
+ headerLabel={i18n['scoria.label.share_header']({ name: view.name })}
164
+ headerSubtitle={view.kind === 'filter'
165
+ ? i18n['scoria.text.share_filter_subtitle']()
166
+ : i18n['scoria.text.share_layout_subtitle']()}
167
+ onclose={() => {
168
+ if (!saving) {
169
+ onclose();
170
+ }
171
+ }}
172
+ width={cssLength('40vw')}
173
+ minWidth={cssLength('32rem')}
174
+ buttons={[
175
+ {
176
+ label: i18n['scoria.action.cancel'](),
177
+ callback: () => {
178
+ if (!saving) {
179
+ onclose();
180
+ }
181
+ },
182
+ disabled: saving,
183
+ },
184
+ {
185
+ label: saving ? i18n['scoria.action.saving']() : i18n['scoria.action.save'](),
186
+ callback: () => {
187
+ void save();
188
+ },
189
+ colourSet: ColourSet.Primary,
190
+ disabled: saving || !dirty || allUsers === null,
191
+ },
192
+ ]}
193
+ >
194
+ <div class="share-body">
195
+ {#if errorMessage}
196
+ <div
197
+ class="error-banner"
198
+ role="alert"
199
+ >
200
+ <Icon
201
+ name="circle-exclamation"
202
+ size={Size.Small}
203
+ />
204
+ <span>{errorMessage}</span>
205
+ </div>
206
+ {/if}
207
+
208
+ <div class="picker">
209
+ {#if loadingUsers && allUsers === null}
210
+ <InfoAlert>{i18n['scoria.message.loading_users']()}</InfoAlert>
211
+ {:else if allUsers !== null}
212
+ <MultiSelect
213
+ label={i18n['scoria.label.users']()}
214
+ name="User"
215
+ placeholder={i18n['scoria.label.select_user']()}
216
+ options={allUsers as Array<DatatableViewUser>}
217
+ labelProp="displayName"
218
+ valueProp="id"
219
+ valueAsObject={true}
220
+ selectedValues={selected}
221
+ onchange={(values) => {
222
+ selected = values;
223
+ }}
224
+ />
225
+ {/if}
226
+ </div>
227
+
228
+ {#if selected.length === 0}
229
+ <InfoAlert>
230
+ {view.kind === 'filter'
231
+ ? i18n['scoria.text.no_users_filter']()
232
+ : i18n['scoria.text.no_users_layout']()}
233
+ </InfoAlert>
234
+ {:else}
235
+ <ul class="user-card-list">
236
+ {#each selected as user (user.id)}
237
+ <li class="user-card">
238
+ <div class="user-info">
239
+ <Icon
240
+ name="user-3"
241
+ size={Size.Medium}
242
+ />
243
+ <span class="user-name">{user.displayName}</span>
244
+ </div>
245
+ <div class="user-meta">
246
+ <!--
247
+ v1 sharing exposes a single role - subscriber - so
248
+ the "permission" surface is informational only. The
249
+ backend's `editor` / `systemOwned` flags are
250
+ reserved no-ops in v1 (see `DatatableView` DTO
251
+ JSDoc); scoria never sets them.
252
+ -->
253
+ <span class="permission-pill">{i18n['scoria.label.subscriber']()}</span>
254
+ <Button
255
+ variant={Variant.Secondary}
256
+ size={Size.MediumSmall}
257
+ nowrap
258
+ iconLeft={{ name: 'circle-cross', size: Size.Small }}
259
+ disabled={saving}
260
+ onclick={() => {
261
+ removeFromSelection(user.id);
262
+ }}>{i18n['scoria.action.remove']()}</Button
263
+ >
264
+ </div>
265
+ </li>
266
+ {/each}
267
+ </ul>
268
+ {/if}
269
+ </div>
270
+ </DesktopModal>
271
+
272
272
  <style>.share-body {
273
273
  display: flex;
274
274
  flex-flow: column nowrap;
@@ -351,4 +351,4 @@ async function save() {
351
351
  border-radius: 999px;
352
352
  background-color: #e9ecf1;
353
353
  color: #3a4952;
354
- }</style>
354
+ }</style>
@@ -1,34 +1,34 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- lang="ts"
5
- module
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ lang="ts"
5
+ module
6
6
  >import { quintOut } from "svelte/easing";
7
7
  import { slide } from "svelte/transition";
8
8
  import { Delay } from "../../../Delay/Delay.js";
9
9
  import { usePrefersReducedMotion } from "../../../Helpers/prefersReducedMotion.svelte.js";
10
10
  import { ToolbarPosition } from "../Types/Toolbar/ToolbarPosition.js";
11
- </script>
12
-
11
+ </script>
12
+
13
13
  <script lang="ts">const { toolbarPosition, onkeydown, ariaLabel, children } = $props();
14
14
  const reducedMotion = usePrefersReducedMotion();
15
15
  const slideDuration = $derived(reducedMotion.matches ? 0 : Delay.Default);
16
- </script>
17
-
18
- <!-- svelte-ignore a11y_no_static_element_interactions -->
19
- <div
20
- class="side-panel"
21
- class:left={toolbarPosition === ToolbarPosition.Left}
22
- class:right={toolbarPosition === ToolbarPosition.Right}
23
- aria-label={ariaLabel}
24
- {onkeydown}
25
- transition:slide={{ duration: slideDuration, easing: quintOut, axis: 'x' }}
26
- >
27
- <div class="side-content">
28
- {#if children}{@render children()}{/if}
29
- </div>
30
- </div>
31
-
16
+ </script>
17
+
18
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
19
+ <div
20
+ class="side-panel"
21
+ class:left={toolbarPosition === ToolbarPosition.Left}
22
+ class:right={toolbarPosition === ToolbarPosition.Right}
23
+ aria-label={ariaLabel}
24
+ {onkeydown}
25
+ transition:slide={{ duration: slideDuration, easing: quintOut, axis: 'x' }}
26
+ >
27
+ <div class="side-content">
28
+ {#if children}{@render children()}{/if}
29
+ </div>
30
+ </div>
31
+
32
32
  <style>.side-panel {
33
33
  display: flex;
34
34
  flex-shrink: 0;
@@ -48,4 +48,4 @@ const slideDuration = $derived(reducedMotion.matches ? 0 : Delay.Default);
48
48
  flex-flow: column nowrap;
49
49
  flex: 1;
50
50
  width: 400px;
51
- }</style>
51
+ }</style>