@lavalogic/scoria 0.40.28 → 0.40.29

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 (127) hide show
  1. package/dist/Components/AccordionGroup.svelte +1 -1
  2. package/dist/Components/AlertModal.svelte +3 -2
  3. package/dist/Components/Base/Pagination.svelte +20 -12
  4. package/dist/Components/Base/PaginationProps.d.ts +5 -0
  5. package/dist/Components/Base/Snippets.svelte +4 -3
  6. package/dist/Components/Button.svelte +9 -8
  7. package/dist/Components/Checkbox.svelte +2 -2
  8. package/dist/Components/ChipsInput.svelte +6 -6
  9. package/dist/Components/CollapsibleCard.svelte +3 -3
  10. package/dist/Components/ConditionBuilder/ConditionBuilder.svelte +7 -6
  11. package/dist/Components/Contexts/ContextMenu.svelte +3 -2
  12. package/dist/Components/Contexts/Toast.svelte +4 -3
  13. package/dist/Components/Contexts/ToastContainer.svelte +6 -5
  14. package/dist/Components/Contexts/Tooltip.svelte +2 -2
  15. package/dist/Components/DataMatrixIcon.svelte +4 -3
  16. package/dist/Components/DateInput.svelte +25 -26
  17. package/dist/Components/DesktopModal.svelte +1 -1
  18. package/dist/Components/DimensionInput.svelte +30 -31
  19. package/dist/Components/DragMenu/DragMenuHolder.svelte +6 -6
  20. package/dist/Components/DragMenu/DraggableCard.svelte +3 -3
  21. package/dist/Components/FileCard.svelte +3 -2
  22. package/dist/Components/FileUpload.svelte +24 -25
  23. package/dist/Components/GridInput.svelte +2 -2
  24. package/dist/Components/HorizontalTabGroup.svelte +1 -1
  25. package/dist/Components/Icon.svelte +8 -2
  26. package/dist/Components/IconProps.d.ts +7 -0
  27. package/dist/Components/Icons.js +365 -365
  28. package/dist/Components/LoadingAnimation.svelte +50 -30
  29. package/dist/Components/LoadingAnimation.svelte.d.ts +1 -1
  30. package/dist/Components/LoadingModal.svelte +3 -2
  31. package/dist/Components/Modal.svelte +9 -9
  32. package/dist/Components/MultiSelect.svelte +37 -18
  33. package/dist/Components/MultiSelectCommonProps.d.ts +15 -1
  34. package/dist/Components/Nav/Nav.svelte +13 -13
  35. package/dist/Components/Nav/ServiceMenuItem.svelte +2 -0
  36. package/dist/Components/Nav/ServicesNav.svelte +6 -6
  37. package/dist/Components/NumberInput.svelte +25 -26
  38. package/dist/Components/PasswordInput.svelte +25 -24
  39. package/dist/Components/PopoverButton.svelte +8 -8
  40. package/dist/Components/QuerySelect.svelte +33 -16
  41. package/dist/Components/QuerySelectProps.d.ts +10 -1
  42. package/dist/Components/ResourceCalendar/ResourceCalendar.svelte +23 -22
  43. package/dist/Components/SidebarPanel.svelte +1 -1
  44. package/dist/Components/SingleSelect.svelte +30 -15
  45. package/dist/Components/SingleSelectCommonProps.d.ts +10 -1
  46. package/dist/Components/StepForm.svelte +6 -5
  47. package/dist/Components/Switch.svelte +5 -5
  48. package/dist/Components/Table/Body/QuickSearchCell.svelte +363 -351
  49. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +5 -6
  50. package/dist/Components/Table/Body/Rows/ColumnList.svelte +3 -2
  51. package/dist/Components/Table/Body/Rows/ColumnListRow.svelte +7 -6
  52. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +6 -7
  53. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +8 -7
  54. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +11 -9
  55. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +7 -8
  56. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +5 -5
  57. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +3 -2
  58. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +3 -3
  59. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +5 -4
  60. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +9 -6
  61. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +4 -4
  62. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +4 -4
  63. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +3 -3
  64. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +9 -7
  65. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +7 -6
  66. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +6 -7
  67. package/dist/Components/Table/Body/Rows/TableRow.svelte +6 -5
  68. package/dist/Components/Table/Body/TableBody.svelte +2 -2
  69. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +3 -2
  70. package/dist/Components/Table/Headers/SelectAllHeader.svelte +4 -3
  71. package/dist/Components/Table/Headers/TableHead.svelte +6 -5
  72. package/dist/Components/Table/Misc/ColumnPanel.svelte +5 -4
  73. package/dist/Components/Table/Misc/ColumnPanelModal.svelte +5 -4
  74. package/dist/Components/Table/Misc/FilterInput.svelte +23 -14
  75. package/dist/Components/Table/Misc/FilterPanel.svelte +12 -11
  76. package/dist/Components/Table/Misc/FilterPanelModal.svelte +3 -2
  77. package/dist/Components/Table/Misc/ShareViewModal.svelte +25 -15
  78. package/dist/Components/Table/Misc/SidePanel.svelte +2 -2
  79. package/dist/Components/Table/Misc/TableConfigurationModal.svelte +50 -40
  80. package/dist/Components/Table/Misc/TableFooter.svelte +18 -12
  81. package/dist/Components/Table/Misc/TableHorizontalBar.svelte +8 -7
  82. package/dist/Components/Table/Misc/TableSidebar.svelte +8 -7
  83. package/dist/Components/Table/Misc/TableViewDropdown.svelte +6 -2
  84. package/dist/Components/Table/Misc/ToolboxPanel.svelte +8 -7
  85. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +9 -8
  86. package/dist/Components/Table/Misc/UpdateViewOptionsModal.svelte +23 -14
  87. package/dist/Components/Table/Misc/numberDateFilterTypes.d.ts +7 -4
  88. package/dist/Components/Table/Misc/numberDateFilterTypes.js +27 -15
  89. package/dist/Components/Table/Misc/stringFilterTypes.d.ts +7 -3
  90. package/dist/Components/Table/Misc/stringFilterTypes.js +26 -16
  91. package/dist/Components/Table/NestedTable.svelte +4 -0
  92. package/dist/Components/Table/Table.svelte +19 -18
  93. package/dist/Components/Table/Types/Columns/Definitions/Actions/ActionsDef.svelte.js +2 -1
  94. package/dist/Components/Table/Types/Columns/Definitions/RowSelection/RowSelectionDef.svelte.js +2 -1
  95. package/dist/Components/Table/Types/Context/ClipboardState.svelte.js +3 -2
  96. package/dist/Components/Table/Types/Context/ViewState.svelte.js +5 -2
  97. package/dist/Components/Table/Types/DataRepository/IDataRepository.d.ts +6 -0
  98. package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.d.ts +8 -0
  99. package/dist/Components/Table/Types/DataRepository/TableDataRepository.svelte.js +14 -0
  100. package/dist/Components/Table/Types/Public/CreateTableOptions.d.ts +3 -0
  101. package/dist/Components/Table/createTable.svelte.js +3 -0
  102. package/dist/Components/TextArea.svelte +24 -23
  103. package/dist/Components/TextInput.svelte +25 -26
  104. package/dist/Components/ThreeStateRadio.svelte +21 -16
  105. package/dist/Components/Touch/BoolCard.svelte +2 -2
  106. package/dist/Components/Touch/DateModal.svelte +5 -4
  107. package/dist/Components/Touch/EditCard.svelte +7 -7
  108. package/dist/Components/Touch/NumberKeyboard.svelte +3 -2
  109. package/dist/Components/Touch/NumberModal.svelte +4 -3
  110. package/dist/Components/Touch/PlusMinusCard.svelte +6 -5
  111. package/dist/Components/Touch/SelectModal.svelte +5 -4
  112. package/dist/Components/Touch/SummaryCard.svelte +9 -9
  113. package/dist/Components/Touch/TextAreaModal.svelte +4 -3
  114. package/dist/Components/Touch/TextModal.svelte +4 -3
  115. package/dist/Components/Touch/TouchCard.svelte +4 -3
  116. package/dist/Components/Touch/TouchModal.svelte +9 -8
  117. package/dist/Components/VerticalTabGroup.svelte +5 -4
  118. package/dist/Contexts/AlertContext.svelte.d.ts +8 -5
  119. package/dist/Contexts/AlertContext.svelte.js +10 -9
  120. package/dist/Helpers/Helpers.svelte.d.ts +23 -2
  121. package/dist/Helpers/Helpers.svelte.js +37 -9
  122. package/dist/Strings/locale.d.ts +19 -0
  123. package/dist/Strings/locale.js +27 -0
  124. package/dist/index.d.ts +1 -0
  125. package/dist/index.js +1 -0
  126. package/dist/scss/_mixins.scss +3406 -3392
  127. package/package.json +14 -7
@@ -3,27 +3,30 @@
3
3
  <script
4
4
  lang="ts"
5
5
  module
6
- >/**
6
+ >import { m as i18n } from "../paraglide/messages.js";
7
+ /**
7
8
  * Warm, on-brand phrases printed inside the box's rear flap. One is chosen at
8
9
  * random when the loader mounts and a fresh one is shown on each loop. Pass
9
10
  * the `messages` prop to override this set.
10
11
  */
11
- export const defaultLoaderMessages = [
12
- "You rock",
13
- "Have a great day",
14
- "Thanks for waiting",
15
- "Almost there",
16
- "Hang tight",
17
- "Worth the wait",
18
- "You're a star",
19
- "Nearly done",
20
- "Sit back and relax",
21
- "Good things come to those who wait",
22
- "On its way",
23
- "Making it happen",
24
- "Fresh out the box",
25
- "Hold tight, nearly there"
26
- ];
12
+ export function defaultLoaderMessages() {
13
+ return [
14
+ i18n["scoria.text.loader_you_rock"](),
15
+ i18n["scoria.text.loader_great_day"](),
16
+ i18n["scoria.text.loader_thanks_waiting"](),
17
+ i18n["scoria.text.loader_almost_there"](),
18
+ i18n["scoria.text.loader_hang_tight"](),
19
+ i18n["scoria.text.loader_worth_wait"](),
20
+ i18n["scoria.text.loader_youre_star"](),
21
+ i18n["scoria.text.loader_nearly_done"](),
22
+ i18n["scoria.text.loader_sit_back"](),
23
+ i18n["scoria.text.loader_good_things"](),
24
+ i18n["scoria.text.loader_on_way"](),
25
+ i18n["scoria.text.loader_making_happen"](),
26
+ i18n["scoria.text.loader_fresh_box"](),
27
+ i18n["scoria.text.loader_hold_tight"]()
28
+ ];
29
+ }
27
30
  // ---- geometry constants for the thrown-letter extrusion ----
28
31
  const MAXLW = 200;
29
32
  const DEPTH = 19;
@@ -96,7 +99,7 @@ function fluteCol(k, faceRGB, deepRGB) {
96
99
  </script>
97
100
 
98
101
  <script lang="ts">import { loaderDefaults } from "../Helpers/loaderDefaults.svelte.js";
99
- const { name = "", showText = true, label = "Loading", caption = "Loading", messages = defaultLoaderMessages, letterFace = "#cdab73", letterDeep = "#2a1d0d" } = $props();
102
+ const { name = "", showText = true, label = i18n["scoria.label.loading"](), caption = i18n["scoria.label.loading"](), messages = defaultLoaderMessages(), letterFace = "#cdab73", letterDeep = "#2a1d0d" } = $props();
100
103
  // The word the box spells: the caller's first name, or the product name as a
101
104
  // friendly fallback. Block capitals tumble cleanly and dodge lowercase
102
105
  // descenders clipping the baseline on landing.
@@ -609,7 +612,7 @@ $effect(() => {
609
612
  <div class="face floor"></div>
610
613
  <div class="face front">
611
614
  <div class="label-wrap">
612
- <div class="label">Goods<br />Loading</div>
615
+ <div class="label">{i18n['scoria.text.crate_label']()}</div>
613
616
  </div>
614
617
  </div>
615
618
 
@@ -793,7 +796,7 @@ $effect(() => {
793
796
  .flowms-loader .front {
794
797
  width: var(--w);
795
798
  height: var(--h);
796
- margin-left: calc(var(--w) / -2);
799
+ margin-inline-start: calc(var(--w) / -2);
797
800
  margin-top: calc(var(--h) / -2);
798
801
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.1333333333), rgba(0, 0, 0, 0.0941176471)), var(--kraft-front);
799
802
  transform: translateZ(var(--hd));
@@ -801,7 +804,7 @@ $effect(() => {
801
804
  .flowms-loader .back {
802
805
  width: var(--w);
803
806
  height: var(--h);
804
- margin-left: calc(var(--w) / -2);
807
+ margin-inline-start: calc(var(--w) / -2);
805
808
  margin-top: calc(var(--h) / -2);
806
809
  background: var(--kraft-back);
807
810
  transform: rotateY(180deg) translateZ(var(--hd));
@@ -809,7 +812,7 @@ $effect(() => {
809
812
  .flowms-loader .right {
810
813
  width: var(--d);
811
814
  height: var(--h);
812
- margin-left: calc(var(--d) / -2);
815
+ margin-inline-start: calc(var(--d) / -2);
813
816
  margin-top: calc(var(--h) / -2);
814
817
  background: linear-gradient(160deg, rgba(0, 0, 0, 0.062745098), rgba(0, 0, 0, 0.1882352941)), var(--kraft-side);
815
818
  transform: rotateY(90deg) translateZ(var(--hw));
@@ -817,7 +820,7 @@ $effect(() => {
817
820
  .flowms-loader .left {
818
821
  width: var(--d);
819
822
  height: var(--h);
820
- margin-left: calc(var(--d) / -2);
823
+ margin-inline-start: calc(var(--d) / -2);
821
824
  margin-top: calc(var(--h) / -2);
822
825
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.0941176471), rgba(0, 0, 0, 0.1333333333)), var(--kraft-side);
823
826
  transform: rotateY(-90deg) translateZ(var(--hw));
@@ -825,7 +828,7 @@ $effect(() => {
825
828
  .flowms-loader .floor {
826
829
  width: var(--w);
827
830
  height: var(--d);
828
- margin-left: calc(var(--w) / -2);
831
+ margin-inline-start: calc(var(--w) / -2);
829
832
  margin-top: calc(var(--d) / -2);
830
833
  background: var(--kraft-inner);
831
834
  transform: rotateX(-90deg) translateZ(var(--hh));
@@ -843,6 +846,9 @@ $effect(() => {
843
846
  }
844
847
  .flowms-loader .label {
845
848
  display: inline-block;
849
+ max-width: var(--w);
850
+ box-sizing: border-box;
851
+ overflow-wrap: break-word;
846
852
  padding: 6px 12px 5px;
847
853
  border: 3px solid var(--ink);
848
854
  border-radius: 3px;
@@ -850,13 +856,27 @@ $effect(() => {
850
856
  letter-spacing: 1.5px;
851
857
  text-transform: uppercase;
852
858
  text-align: center;
853
- white-space: nowrap;
859
+ white-space: pre-line;
854
860
  color: var(--ink);
855
861
  opacity: 0.72;
856
862
  mix-blend-mode: multiply;
857
863
  transform: rotate(-2.6deg);
858
864
  filter: url(#flowms-stamp);
859
865
  }
866
+ .flowms-loader {
867
+ /* Measured against the 90px content area inside the stamp: these are the
868
+ largest sizes at which the longest word still fits without breaking.
869
+ letter-spacing is fixed, so the sizes are not a linear scale of 15px. */
870
+ }
871
+ :global(html[lang='de']) .flowms-loader .label {
872
+ font-size: 14px;
873
+ }
874
+ :global(html[lang='es']) .flowms-loader .label {
875
+ font-size: 13px;
876
+ }
877
+ :global(html[lang='fr']) .flowms-loader .label {
878
+ font-size: 10px;
879
+ }
860
880
  .flowms-loader {
861
881
  /* positive message printed inside the rear flap */
862
882
  }
@@ -922,7 +942,7 @@ $effect(() => {
922
942
  position: absolute;
923
943
  width: var(--w);
924
944
  height: var(--hw);
925
- margin-left: calc(var(--w) / -2);
945
+ margin-inline-start: calc(var(--w) / -2);
926
946
  transform-origin: 50% 0;
927
947
  transform: rotateX(-90deg);
928
948
  transform-style: preserve-3d;
@@ -967,7 +987,7 @@ $effect(() => {
967
987
  top: 0;
968
988
  width: 96px;
969
989
  height: 96px;
970
- margin-left: -48px;
990
+ margin-inline-start: -48px;
971
991
  margin-top: -48px;
972
992
  border-radius: 50%;
973
993
  opacity: 0;
@@ -979,7 +999,7 @@ $effect(() => {
979
999
  top: 0;
980
1000
  width: 13px;
981
1001
  height: 13px;
982
- margin-left: -6.5px;
1002
+ margin-inline-start: -6.5px;
983
1003
  margin-top: -6.5px;
984
1004
  border-radius: 3px;
985
1005
  opacity: 0;
@@ -1004,7 +1024,7 @@ $effect(() => {
1004
1024
  .flowms-loader .fill:nth-child(3n) {
1005
1025
  width: 9px;
1006
1026
  height: 9px;
1007
- margin-left: -4.5px;
1027
+ margin-inline-start: -4.5px;
1008
1028
  margin-top: -4.5px;
1009
1029
  border-radius: 50%;
1010
1030
  }
@@ -1082,7 +1102,7 @@ $effect(() => {
1082
1102
  }
1083
1103
  .flowms-loader .caption-dots {
1084
1104
  display: inline-block;
1085
- text-align: left;
1105
+ text-align: start;
1086
1106
  }
1087
1107
  .flowms-loader .caption-dots span:nth-child(2),
1088
1108
  .flowms-loader .caption-dots span:nth-child(3) {
@@ -3,7 +3,7 @@
3
3
  * random when the loader mounts and a fresh one is shown on each loop. Pass
4
4
  * the `messages` prop to override this set.
5
5
  */
6
- export declare const defaultLoaderMessages: string[];
6
+ export declare function defaultLoaderMessages(): string[];
7
7
  import type { LoadingAnimationProps } from './LoadingAnimationProps.js';
8
8
  declare const LoadingAnimation: import("svelte").Component<LoadingAnimationProps, {}, "">;
9
9
  type LoadingAnimation = ReturnType<typeof LoadingAnimation>;
@@ -1,6 +1,7 @@
1
1
  <svelte:options runes />
2
2
 
3
- <script lang="ts">import LoadingAnimation from "./LoadingAnimation.svelte";
3
+ <script lang="ts">import { m as i18n } from "../paraglide/messages.js";
4
+ import LoadingAnimation from "./LoadingAnimation.svelte";
4
5
  const { showModal, message, name, caption } = $props();
5
6
  let dialog = $state();
6
7
  $effect(() => {
@@ -23,7 +24,7 @@ function uncloseable(e) {
23
24
  <dialog
24
25
  bind:this={dialog}
25
26
  onkeydown={uncloseable}
26
- aria-label={message ?? 'Loading'}
27
+ aria-label={message ?? i18n['scoria.label.loading']()}
27
28
  aria-live="polite"
28
29
  >
29
30
  <div class="modal-root">
@@ -3,7 +3,8 @@
3
3
  <script
4
4
  module
5
5
  lang="ts"
6
- >import { browser } from "$app/environment";
6
+ >import { m as i18n } from "../paraglide/messages.js";
7
+ import { browser } from "$app/environment";
7
8
  import { DATAMatrix } from "../Helpers/Datamatrix.js";
8
9
  import { passthrough } from "../Helpers/Helpers.svelte.js";
9
10
  import { ColourSet } from "../scss/colours.js";
@@ -127,7 +128,7 @@ const dialogStyle = $derived(`--timer: ${defaultTimer ? defaultTimer.time.toStri
127
128
  }}
128
129
  onkeydown={handleEsc}
129
130
  colourSet={ColourSet.Primary}
130
- label="Close Modal"
131
+ label={i18n['scoria.action.close_modal_generic']()}
131
132
  />
132
133
  </div>
133
134
  </div>
@@ -175,8 +176,8 @@ const dialogStyle = $derived(`--timer: ${defaultTimer ? defaultTimer.time.toStri
175
176
  {/if}
176
177
  <button
177
178
  onkeydown={passthrough}
178
- class:margin-left={button.margin === 'left'}
179
- class:margin-right={button.margin === 'right'}
179
+ class:margin-inline-start={button.margin === 'left'}
180
+ class:margin-inline-end={button.margin === 'right'}
180
181
  type={button.type ?? 'button'}
181
182
  onclick={button.callback}>{button.label}</button
182
183
  >
@@ -192,8 +193,8 @@ const dialogStyle = $derived(`--timer: ${defaultTimer ? defaultTimer.time.toStri
192
193
  <button
193
194
  onkeydown={passthrough}
194
195
  disabled={!isValid}
195
- class:margin-left={button.margin === 'left'}
196
- class:margin-right={button.margin === 'right'}
196
+ class:margin-inline-start={button.margin === 'left'}
197
+ class:margin-inline-end={button.margin === 'right'}
197
198
  bind:this={submitRef}
198
199
  type={button.type ?? 'submit'}>{button.label}</button
199
200
  >
@@ -494,8 +495,7 @@ div.button-barcode-set {
494
495
  }
495
496
  .title-wrapper .modal-heading {
496
497
  position: absolute;
497
- left: 0;
498
- right: 0;
498
+ inset-inline: 0;
499
499
  top: 0;
500
500
  bottom: 0;
501
501
  }
@@ -538,7 +538,7 @@ div.bar-container {
538
538
  div.bar-container div.bar-timer {
539
539
  position: absolute;
540
540
  top: 0;
541
- left: 0;
541
+ inset-inline-start: 0;
542
542
  height: 1rem;
543
543
  background-color: #259fc7;
544
544
  animation: timer linear var(--timer);
@@ -3,7 +3,8 @@
3
3
  <script
4
4
  lang="ts"
5
5
  generics="V extends object, VP extends ValueProp<V>"
6
- >import { autoPluralise, generateWeakId, vowels } from "../Helpers/Helpers.svelte.js";
6
+ >import { m as i18n } from "../paraglide/messages.js";
7
+ import { autoPluralise, generateWeakId, vowels } from "../Helpers/Helpers.svelte.js";
7
8
  import { attachDropdownPortal } from "../Helpers/dropdownPortal.js";
8
9
  import { Colour, ColourSet } from "../scss/colours.js";
9
10
  import { Size } from "../Types/Internal/Size.js";
@@ -13,8 +14,17 @@ import { onMount } from "svelte";
13
14
  import Action from "./Action.svelte";
14
15
  import Icon from "./Icon.svelte";
15
16
  // NOTE selectedValues is mutated by svelecte without asking, so we sometimes have to reverse it without a callback (side effects)
16
- const { label, inputId = generateWeakId(), options, labelProp, valueProp, width, valueAsObject = true, height, selectedValues, onchange, collapseSelection = false, name = "Item", disabled, required, invalid } = $props();
17
- const an = $derived(name && vowels.has(name.at(0)?.toLocaleLowerCase() ?? "") ? "an" : "a");
17
+ const { label, inputId = generateWeakId(), options, labelProp, valueProp, width, valueAsObject = true, height, selectedValues, onchange, collapseSelection = false, placeholder, selectionLabel, name = "Item", disabled, required, invalid } = $props();
18
+ // English-only article choice. The article itself lives in the message, so a
19
+ // translator owns the whole phrase and can drop or decline it per locale.
20
+ const fallbackPlaceholder = $derived(name ? vowels.has(name.at(0)?.toLocaleLowerCase() ?? "") ? i18n["scoria.label.select_an_named"]({ name }) : i18n["scoria.label.select_a_named"]({ name }) : i18n["scoria.label.please_select"]());
21
+ function collapsedText(count) {
22
+ if (selectionLabel) return selectionLabel(count);
23
+ return name ? i18n["scoria.text.selected_count_named"]({
24
+ count,
25
+ noun: autoPluralise(name, count)
26
+ }) : i18n["scoria.text.selected_count"]({ count });
27
+ }
18
28
  // Pre-computed set of selected primitive keys. Used in the option snippet
19
29
  // to avoid an O(n*m) findIndex sweep per render.
20
30
  const selectedKeys = $derived.by(() => {
@@ -108,7 +118,7 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
108
118
  collapseSelection={collapseSelection ? 'always' : null}
109
119
  deselectMode="toggle"
110
120
  highlightFirstItem={false}
111
- placeholder="Please Select {name ? `${an} ${name}` : ''}"
121
+ placeholder={placeholder ?? fallbackPlaceholder}
112
122
  selection={collapseSelection ? selection : undefined}
113
123
  >
114
124
  {#snippet option(opt)}
@@ -128,12 +138,9 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
128
138
  {/snippet}
129
139
 
130
140
  {#snippet collapsedSelection(selectedOptions: Array<object> /*_i18n*/)}
141
+ {@const count = selectedOptions.length}
131
142
  <span class="selection"
132
- >{#if selectedOptions.length}{selectedOptions.length}
133
- {#if name}{autoPluralise(name, selectedOptions.length)}{/if} Selected
134
- {:else}Please Select {#if name}
135
- {an} {name}{/if}
136
- {/if}</span
143
+ >{count ? collapsedText(count) : (placeholder ?? fallbackPlaceholder)}</span
137
144
  >
138
145
  {/snippet}
139
146
 
@@ -208,19 +215,20 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
208
215
  }
209
216
  .select-wrapper label {
210
217
  position: absolute;
211
- left: 0.5rem;
218
+ inset-inline-start: 0.5rem;
212
219
  z-index: 1;
220
+ width: calc(100% - 1rem);
213
221
  font-size: 0.875rem;
214
222
  padding: 0.05rem 0.4rem;
215
223
  color: #647d8e;
216
224
  }
217
225
  .select-wrapper label span:not(.border) {
218
226
  position: absolute;
219
- left: 0.5rem;
227
+ inset-inline-start: 0.5rem;
220
228
  font-size: 0.875rem;
221
229
  user-select: none;
222
- padding-left: 0.5rem;
223
- padding-right: 0.5rem;
230
+ padding-inline-start: 0.5rem;
231
+ padding-inline-end: 0.5rem;
224
232
  line-height: 1rem;
225
233
  padding: 0rem 0.5rem;
226
234
  top: calc(-0.875rem / 2 - 2px);
@@ -231,13 +239,18 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
231
239
  .select-wrapper label span:not(.border).invalid {
232
240
  color: #aa1414;
233
241
  }
242
+ .select-wrapper label span:not(.border) {
243
+ max-width: calc(100% - 1rem);
244
+ overflow: hidden;
245
+ text-overflow: ellipsis;
246
+ }
234
247
  .select-wrapper label span.border {
235
248
  position: absolute;
236
- left: 0.5rem;
249
+ inset-inline-start: 0.5rem;
237
250
  font-size: 0.875rem;
238
251
  user-select: none;
239
- padding-left: 0.5rem;
240
- padding-right: 0.5rem;
252
+ padding-inline-start: 0.5rem;
253
+ padding-inline-end: 0.5rem;
241
254
  line-height: 1rem;
242
255
  z-index: 1;
243
256
  white-space: nowrap;
@@ -249,6 +262,11 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
249
262
  .select-wrapper label span.border.invalid {
250
263
  border-bottom-color: #f9e9e9;
251
264
  }
265
+ .select-wrapper label span.border {
266
+ max-width: calc(100% - 1rem);
267
+ overflow: hidden;
268
+ text-overflow: ellipsis;
269
+ }
252
270
  .select-wrapper :global(.svelecte.svelecte-control) {
253
271
  cursor: pointer;
254
272
  max-width: 100%;
@@ -294,7 +312,7 @@ const isInvalid = $derived(required && !selectedValues.length || invalid);
294
312
  }
295
313
  .select-wrapper .selection {
296
314
  font-size: 0.875rem;
297
- padding-left: 0.5rem;
315
+ padding-inline-start: 0.5rem;
298
316
  white-space: nowrap;
299
317
  display: flex;
300
318
  }
@@ -313,7 +331,7 @@ div.icons {
313
331
  flex-flow: row nowrap;
314
332
  gap: 0.25rem;
315
333
  height: 100%;
316
- margin-right: 0.25rem;
334
+ margin-inline-end: 0.25rem;
317
335
  box-sizing: border-box;
318
336
  }
319
337
 
@@ -338,6 +356,7 @@ div.icons {
338
356
  text-overflow: ellipsis;
339
357
  gap: 1rem;
340
358
  font-size: 0.875rem;
359
+ line-height: 1.6;
341
360
  fill: #259fc7;
342
361
  }
343
362
  :global(.dropdown-item) .toggle-icon {
@@ -9,8 +9,22 @@ export type StringValuedKey<V> = NonNullableKey<V>;
9
9
  export interface MultiSelectCommonProps<V extends object, VP extends ValueProp<V>> {
10
10
  /** Available options to choose from. */
11
11
  options: Array<V>;
12
- /** Singular display name of the entity. */
12
+ /**
13
+ * Singular display name of the entity. This is the `<Svelecte>` **form-field
14
+ * attribute**, not display copy - it is only used to compose the English-only
15
+ * fallback placeholder when `placeholder` is not supplied.
16
+ */
13
17
  name?: string;
18
+ /**
19
+ * Complete placeholder sentence. Pass a translated whole phrase; when omitted
20
+ * scoria composes an English-only fallback from `name`.
21
+ */
22
+ placeholder?: string;
23
+ /**
24
+ * Complete collapsed-selection sentence, e.g. `(n) => `${n} warehouses selected``.
25
+ * English-only fallback when omitted.
26
+ */
27
+ selectionLabel?: (count: number) => string;
14
28
  /** Key of `V` whose value is the human-readable label. */
15
29
  labelProp: NonNullableKey<V>;
16
30
  /** Key of `V` whose value is the unique identifier. */
@@ -3,7 +3,8 @@
3
3
  <script
4
4
  lang="ts"
5
5
  generics="T"
6
- >import { afterNavigate } from "$app/navigation";
6
+ >import { m as i18n } from "../../paraglide/messages.js";
7
+ import { afterNavigate } from "$app/navigation";
7
8
  import { Size } from "../../Types/Internal/Size.js";
8
9
  import Icon from "../Icon.svelte";
9
10
  import ServicesNav from "./ServicesNav.svelte";
@@ -46,7 +47,7 @@ afterNavigate(() => {
46
47
  name="block-menu"
47
48
  size={Size.Medium}
48
49
  />
49
- <span>Services</span>
50
+ <span>{i18n['scoria.label.services']()}</span>
50
51
  </div>
51
52
  </button>
52
53
 
@@ -95,8 +96,7 @@ afterNavigate(() => {
95
96
  position: fixed;
96
97
  top: calc(3.25rem + var(--env-border-height, 0));
97
98
  bottom: 0;
98
- left: 0;
99
- right: 0;
99
+ inset-inline: 0;
100
100
  z-index: 98;
101
101
  background-color: rgba(0, 0, 0, 0.2);
102
102
  }
@@ -114,7 +114,7 @@ div.user {
114
114
  background-color: #ffffff;
115
115
  padding: 0.75rem;
116
116
  top: calc(3.25rem + var(--env-border-height, 0));
117
- right: 0.5rem;
117
+ inset-inline-end: 0.5rem;
118
118
  z-index: 99;
119
119
  box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1333333333);
120
120
  }
@@ -172,22 +172,22 @@ nav button:hover {
172
172
  .main-navigation > *:nth-child(even)::before {
173
173
  content: "";
174
174
  height: 1.5rem;
175
- border-left: solid 1px #e9ecf1;
175
+ border-inline-start: solid 1px #e9ecf1;
176
176
  border-radius: 5px;
177
- left: 0;
177
+ inset-inline-start: 0;
178
178
  position: absolute;
179
179
  }
180
180
  .main-navigation > *:nth-child(even)::after {
181
181
  content: "";
182
182
  height: 1.5rem;
183
- border-right: solid 1px #e9ecf1;
183
+ border-inline-end: solid 1px #e9ecf1;
184
184
  border-radius: 5px;
185
185
  position: absolute;
186
- right: 0;
186
+ inset-inline-end: 0;
187
187
  }
188
188
  .main-navigation > *:nth-child(even).selects {
189
- padding-left: 1px;
190
- padding-right: 1px;
189
+ padding-inline-start: 1px;
190
+ padding-inline-end: 1px;
191
191
  width: 32rem;
192
192
  --sv-border: none;
193
193
  --input-width: calc(50% - 0.5rem);
@@ -202,8 +202,8 @@ nav button:hover {
202
202
  transition: background-color 200ms ease 0s;
203
203
  }
204
204
  .nav-link.padded {
205
- padding-left: 1rem;
206
- padding-right: 1rem;
205
+ padding-inline-start: 1rem;
206
+ padding-inline-end: 1rem;
207
207
  gap: 1.5rem;
208
208
  }
209
209
 
@@ -148,6 +148,7 @@ a {
148
148
  button .icon-wrapper,
149
149
  a .icon-wrapper {
150
150
  width: var(--iconWidth);
151
+ flex-shrink: 0;
151
152
  display: flex;
152
153
  flex-flow: row nowrap;
153
154
  align-items: center;
@@ -166,4 +167,5 @@ a:hover {
166
167
  button .spacer,
167
168
  a .spacer {
168
169
  width: 0.5rem;
170
+ flex-shrink: 0;
169
171
  }</style>
@@ -3,7 +3,8 @@
3
3
  <script
4
4
  lang="ts"
5
5
  generics="Args"
6
- >import { devCatch } from "../../Helpers/Helpers.svelte.js";
6
+ >import { m as i18n } from "../../paraglide/messages.js";
7
+ import { devCatch } from "../../Helpers/Helpers.svelte.js";
7
8
  import HorizontalTabGroup from "../HorizontalTabGroup.svelte";
8
9
  import NavTab from "./NavTab.svelte";
9
10
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments
@@ -30,7 +31,7 @@ $effect(() => {
30
31
 
31
32
  <dialog
32
33
  bind:this={dialogRef}
33
- aria-label="Services"
34
+ aria-label={i18n['scoria.label.services']()}
34
35
  class="overlay"
35
36
  oncancel={(e) => {
36
37
  // Escape fires `cancel` first; prevent the native close so we
@@ -49,7 +50,7 @@ $effect(() => {
49
50
  >
50
51
  <div
51
52
  role="navigation"
52
- aria-label="Services tabs"
53
+ aria-label={i18n['scoria.label.services_tabs']()}
53
54
  class="services"
54
55
  >
55
56
  <HorizontalTabGroup
@@ -74,8 +75,7 @@ $effect(() => {
74
75
  position: fixed;
75
76
  top: calc(3.25rem + var(--env-border-height, 0));
76
77
  bottom: 0;
77
- left: 0;
78
- right: 0;
78
+ inset-inline: 0;
79
79
  width: 100%;
80
80
  height: auto;
81
81
  max-width: none;
@@ -98,7 +98,7 @@ div.services {
98
98
  border-radius: 4px;
99
99
  background-color: #ffffff;
100
100
  top: calc(3.25rem + var(--env-border-height, 0));
101
- left: 7.5rem;
101
+ inset-inline-start: 7.5rem;
102
102
  z-index: 99;
103
103
  box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1333333333);
104
104
  padding: 0;