@happyvertical/smrt-svelte 0.55.6 → 0.55.7

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 (124) hide show
  1. package/AGENTS.md +17 -2
  2. package/README.md +83 -4
  3. package/agents/workspace.md +202 -5
  4. package/dist/browser-ai/adapters/stt/dictation-source.d.ts.map +1 -1
  5. package/dist/browser-ai/adapters/stt/dictation-source.js +8 -2
  6. package/dist/browser-ai/adapters/stt/factory.d.ts +6 -3
  7. package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -1
  8. package/dist/browser-ai/adapters/stt/factory.js +19 -9
  9. package/dist/browser-ai/adapters/stt/index.d.ts +3 -1
  10. package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -1
  11. package/dist/browser-ai/adapters/stt/index.js +3 -1
  12. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts +111 -0
  13. package/dist/browser-ai/adapters/stt/local-speech-model.d.ts.map +1 -0
  14. package/dist/browser-ai/adapters/stt/local-speech-model.js +377 -0
  15. package/dist/browser-ai/adapters/stt/local-speech.d.ts +82 -0
  16. package/dist/browser-ai/adapters/stt/local-speech.d.ts.map +1 -0
  17. package/dist/browser-ai/adapters/stt/local-speech.js +317 -0
  18. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts +2 -0
  19. package/dist/browser-ai/adapters/stt/local-speech.worker.d.ts.map +1 -0
  20. package/dist/browser-ai/adapters/stt/local-speech.worker.js +32 -0
  21. package/dist/browser-ai/adapters/stt/transformers-env.d.ts +8 -0
  22. package/dist/browser-ai/adapters/stt/transformers-env.d.ts.map +1 -0
  23. package/dist/browser-ai/adapters/stt/transformers-env.js +17 -0
  24. package/dist/browser-ai/adapters/stt/types.d.ts +54 -9
  25. package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -1
  26. package/dist/browser-ai/capabilities/speech-probe.d.ts +29 -0
  27. package/dist/browser-ai/capabilities/speech-probe.d.ts.map +1 -0
  28. package/dist/browser-ai/capabilities/speech-probe.js +19 -0
  29. package/dist/browser-ai/core/errors.d.ts +9 -0
  30. package/dist/browser-ai/core/errors.d.ts.map +1 -1
  31. package/dist/browser-ai/core/errors.js +12 -0
  32. package/dist/browser-ai/index.d.ts +1 -0
  33. package/dist/browser-ai/index.d.ts.map +1 -1
  34. package/dist/browser-ai/index.js +1 -0
  35. package/dist/components/app/AppShell.svelte +587 -33
  36. package/dist/components/app/AppShell.svelte.d.ts +75 -4
  37. package/dist/components/app/AppShell.svelte.d.ts.map +1 -1
  38. package/dist/components/app/DockToggles.svelte +0 -1
  39. package/dist/components/app/dock-toggle.d.ts +7 -1
  40. package/dist/components/app/dock-toggle.d.ts.map +1 -1
  41. package/dist/components/app/index.d.ts +2 -1
  42. package/dist/components/app/index.d.ts.map +1 -1
  43. package/dist/components/app/slot-item.d.ts +21 -0
  44. package/dist/components/app/slot-item.d.ts.map +1 -0
  45. package/dist/components/app/slot-item.js +1 -0
  46. package/dist/components/forms/AddressInput.svelte +2 -15
  47. package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -1
  48. package/dist/components/forms/DateRangeInput.svelte +2 -15
  49. package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -1
  50. package/dist/components/forms/DateTimeInput.svelte +8 -15
  51. package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -1
  52. package/dist/components/forms/MeasurementInput.svelte +2 -15
  53. package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -1
  54. package/dist/components/forms/MoneyInput.svelte +8 -25
  55. package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -1
  56. package/dist/components/forms/NumberInput.svelte +7 -15
  57. package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -1
  58. package/dist/components/forms/PhoneInput.svelte +7 -15
  59. package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -1
  60. package/dist/components/forms/SelectInput.svelte +34 -40
  61. package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -1
  62. package/dist/components/forms/TextInput.svelte +20 -37
  63. package/dist/components/forms/TextInput.svelte.d.ts.map +1 -1
  64. package/dist/components/forms/TextareaInput.svelte +19 -35
  65. package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -1
  66. package/dist/components/sortable/Sortable.svelte +6 -33
  67. package/dist/components/sortable/Sortable.svelte.d.ts.map +1 -1
  68. package/dist/components/sortable/announce.d.ts +5 -0
  69. package/dist/components/sortable/announce.d.ts.map +1 -0
  70. package/dist/components/sortable/announce.js +33 -0
  71. package/dist/components/workspace/admin-shell/AdminShell.svelte +424 -58
  72. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts +27 -2
  73. package/dist/components/workspace/admin-shell/AdminShell.svelte.d.ts.map +1 -1
  74. package/dist/components/workspace/admin-shell/ShellBrand.svelte +86 -0
  75. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts +18 -0
  76. package/dist/components/workspace/admin-shell/ShellBrand.svelte.d.ts.map +1 -0
  77. package/dist/components/workspace/admin-shell/ShellIconButton.svelte +77 -0
  78. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts +26 -0
  79. package/dist/components/workspace/admin-shell/ShellIconButton.svelte.d.ts.map +1 -0
  80. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte +88 -16
  81. package/dist/components/workspace/admin-shell/ShellLayoutEditor.svelte.d.ts.map +1 -1
  82. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte +531 -0
  83. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts +26 -0
  84. package/dist/components/workspace/admin-shell/ShellNavEditor.svelte.d.ts.map +1 -0
  85. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte +57 -0
  86. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts +22 -0
  87. package/dist/components/workspace/admin-shell/ShellSectionIcon.svelte.d.ts.map +1 -0
  88. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte +290 -0
  89. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts +32 -0
  90. package/dist/components/workspace/admin-shell/ShellSectionMenu.svelte.d.ts.map +1 -0
  91. package/dist/components/workspace/admin-shell/TenantNav.svelte +67 -2
  92. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts +8 -0
  93. package/dist/components/workspace/admin-shell/TenantNav.svelte.d.ts.map +1 -1
  94. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts +67 -0
  95. package/dist/components/workspace/admin-shell/layout-controller.svelte.d.ts.map +1 -1
  96. package/dist/components/workspace/admin-shell/layout-controller.svelte.js +129 -1
  97. package/dist/components/workspace/admin-shell/layout.d.ts +122 -0
  98. package/dist/components/workspace/admin-shell/layout.d.ts.map +1 -1
  99. package/dist/components/workspace/admin-shell/layout.js +410 -10
  100. package/dist/components/workspace/admin-shell/settings.js +4 -4
  101. package/dist/components/workspace/admin-shell/shell-icons.d.ts +45 -0
  102. package/dist/components/workspace/admin-shell/shell-icons.d.ts.map +1 -0
  103. package/dist/components/workspace/admin-shell/shell-icons.js +66 -0
  104. package/dist/components/workspace/admin-shell/slot-labels.d.ts +33 -0
  105. package/dist/components/workspace/admin-shell/slot-labels.d.ts.map +1 -0
  106. package/dist/components/workspace/admin-shell/slot-labels.js +33 -0
  107. package/dist/components/workspace/admin-shell/slots.d.ts +50 -0
  108. package/dist/components/workspace/admin-shell/slots.d.ts.map +1 -0
  109. package/dist/components/workspace/admin-shell/slots.js +77 -0
  110. package/dist/components/workspace/admin-shell/state.svelte.d.ts +35 -0
  111. package/dist/components/workspace/admin-shell/state.svelte.d.ts.map +1 -1
  112. package/dist/components/workspace/admin-shell/state.svelte.js +111 -0
  113. package/dist/components/workspace/admin-shell/types.d.ts +101 -1
  114. package/dist/components/workspace/admin-shell/types.d.ts.map +1 -1
  115. package/dist/components/workspace/index.d.ts +9 -2
  116. package/dist/components/workspace/index.d.ts.map +1 -1
  117. package/dist/components/workspace/index.js +6 -0
  118. package/dist/i18n/strings.workspace.d.ts +49 -0
  119. package/dist/i18n/strings.workspace.d.ts.map +1 -1
  120. package/dist/i18n/strings.workspace.js +49 -0
  121. package/package.json +30 -19
  122. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +0 -51
  123. package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +0 -1
  124. package/dist/browser-ai/adapters/stt/whisper-wasm.js +0 -380
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Icon } from '@happyvertical/smrt-ui';
3
+ import { FieldLabel } from '@happyvertical/smrt-ui/forms';
3
4
  import { matchOption } from '@happyvertical/smrt-ui/utils/forms/formatters.js';
4
5
  import { useAppState } from '../../hooks/useAppState.svelte.js';
5
6
  import {
@@ -42,10 +43,24 @@ let {
42
43
  onchange,
43
44
  }: Props = $props();
44
45
 
46
+ // Unique per instance: the control stays labelled even if `name` repeats on a page.
47
+ const uid = $props.id();
48
+ const labelId = `${uid}-label`;
49
+
45
50
  const app = useAppState();
46
51
  const formContext = tryGetFormContext();
47
52
 
48
53
  let isFocused = $state(false);
54
+ /** A caller-supplied empty choice replaces the placeholder: one empty option only. */
55
+ const hasEmptyOption = $derived(options.some((o) => o.value === ''));
56
+ // Options are keyed by value: a repeated value (e.g. two empty choices) would
57
+ // throw each_key_duplicate and take the whole form down, so keep the first.
58
+ const uniqueOptions = $derived(
59
+ options.filter(
60
+ (option, index) =>
61
+ options.findIndex((o) => o.value === option.value) === index,
62
+ ),
63
+ );
49
64
  const isSmrt = $derived(app.state.mode === 'smrt');
50
65
 
51
66
  // Helper to update value
@@ -123,15 +138,14 @@ function handleChange(e: Event) {
123
138
  class:disabled
124
139
  class:has-value={!!value}
125
140
  >
141
+ {#if label}
142
+ <FieldLabel id={labelId} for={name} {label} {required} />
143
+ {/if}
126
144
  <div class="container">
127
145
  <div class="content">
128
- {#if label}
129
- <label for={name} class="label">
130
- {label}{#if required}*{/if}
131
- </label>
132
- {/if}
133
146
  <select
134
147
  id={name}
148
+ aria-labelledby={label ? labelId : undefined}
135
149
  {name}
136
150
  {value}
137
151
  {disabled}
@@ -142,8 +156,10 @@ function handleChange(e: Event) {
142
156
  onfocus={() => isFocused = true}
143
157
  onblur={() => isFocused = false}
144
158
  >
145
- <option value="" disabled selected={!value}>{placeholder}</option>
146
- {#each options as option (option.value)}
159
+ {#if !hasEmptyOption}
160
+ <option value="" disabled selected={!value}>{placeholder}</option>
161
+ {/if}
162
+ {#each uniqueOptions as option (option.value)}
147
163
  <option value={option.value}>{option.label}</option>
148
164
  {/each}
149
165
  </select>
@@ -179,10 +195,11 @@ function handleChange(e: Event) {
179
195
  position: relative;
180
196
  display: flex;
181
197
  align-items: center;
182
- background-color: var(--field-bg);
183
- border-radius: var(--smrt-radius-sm, 4px) var(--smrt-radius-sm, 4px) 0 0;
184
- min-height: 56px;
185
- padding: 0 var(--smrt-spacing-4, 16px);
198
+ background-color: var(--smrt-color-surface, #fff);
199
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
200
+ border-radius: var(--smrt-radius-small, 6px);
201
+ min-height: 40px;
202
+ padding: 0 var(--smrt-spacing-3, 12px);
186
203
  transition: background-color var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
187
204
  }
188
205
 
@@ -196,23 +213,8 @@ function handleChange(e: Event) {
196
213
  flex-direction: column;
197
214
  justify-content: center;
198
215
  height: 100%;
199
- padding-top: var(--smrt-spacing-2, 8px);
200
- }
216
+ }
201
217
 
202
- .label {
203
- font-size: var(--smrt-typography-body-large-size, 1rem);
204
- line-height: var(--smrt-typography-body-large-line-height, 1.5);
205
- letter-spacing: var(--smrt-typography-body-large-tracking, 0.5px);
206
- color: var(--field-color);
207
- pointer-events: none;
208
- transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
209
- transform-origin: top left;
210
- }
211
-
212
- .focused .label, .has-value .label {
213
- transform: translateY(-8px) scale(0.75);
214
- color: var(--field-active);
215
- }
216
218
 
217
219
  .input {
218
220
  border: none;
@@ -242,23 +244,15 @@ function handleChange(e: Event) {
242
244
  margin-right: -4px;
243
245
  }
244
246
 
245
- .active-indicator {
246
- position: absolute;
247
- bottom: 0;
248
- left: 0;
249
- right: 0;
250
- height: 1px;
251
- background-color: var(--field-color);
252
- transition: all 200ms cubic-bezier(0.2, 0, 0, 1);
253
- }
247
+ .active-indicator { display: none; }
254
248
 
255
- .focused .active-indicator {
256
- height: 2px;
257
- background-color: var(--field-active);
249
+ .focused .container {
250
+ border-color: var(--field-active);
251
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--field-active) 10%, transparent);
258
252
  }
259
253
 
260
254
  .supporting-text {
261
- padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-4, 16px) 0;
255
+ padding: var(--smrt-spacing-1, 4px) 0 0;
262
256
  font-size: var(--smrt-typography-body-small-size, 0.75rem);
263
257
  }
264
258
 
@@ -1 +1 @@
1
- {"version":3,"file":"SelectInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/SelectInput.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAkID,QAAA,MAAM,WAAW,gDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"SelectInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/SelectInput.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAiJD,QAAA,MAAM,WAAW,gDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Icon, ripple } from '@happyvertical/smrt-ui';
3
+ import { FieldLabel } from '@happyvertical/smrt-ui/forms';
3
4
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
4
5
  import {
5
6
  formatEmail,
@@ -53,6 +54,10 @@ let {
53
54
  onchange,
54
55
  }: Props = $props();
55
56
 
57
+ // Unique per instance: the control stays labelled even if `name` repeats on a page.
58
+ const uid = $props.id();
59
+ const labelId = `${uid}-label`;
60
+
56
61
  const app = useAppState();
57
62
  const stt = useSTT();
58
63
  const formContext = tryGetFormContext();
@@ -262,14 +267,15 @@ function handleInput(e: Event) {
262
267
  class:has-value={!!value}
263
268
  class:listening={isHolding}
264
269
  >
270
+ {#if label}
271
+ <FieldLabel id={labelId} for={name} {label} {required} />
272
+ {/if}
265
273
  <div class="container">
266
274
  <div class="content">
267
- {#if label}
268
- <label for={name} class="label">{label}{#if required}*{/if}</label>
269
- {/if}
270
275
  <input
271
276
  bind:this={inputEl}
272
277
  id={name}
278
+ aria-labelledby={label ? labelId : undefined}
273
279
  {name}
274
280
  type={type}
275
281
  placeholder={isFocused ? placeholder : ''}
@@ -346,10 +352,11 @@ function handleInput(e: Event) {
346
352
  position: relative;
347
353
  display: flex;
348
354
  align-items: center;
349
- background-color: var(--field-bg);
350
- border-radius: var(--smrt-radius-sm, 4px) var(--smrt-radius-sm, 4px) 0 0;
351
- min-height: 56px;
352
- padding: 0 var(--smrt-spacing-4, 16px);
355
+ background-color: var(--smrt-color-surface, #fff);
356
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
357
+ border-radius: var(--smrt-radius-small, 6px);
358
+ min-height: 40px;
359
+ padding: 0 var(--smrt-spacing-3, 12px);
353
360
  transition: background-color var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
354
361
  }
355
362
 
@@ -363,24 +370,8 @@ function handleInput(e: Event) {
363
370
  flex-direction: column;
364
371
  justify-content: center;
365
372
  height: 100%;
366
- padding-top: var(--smrt-spacing-2, 8px);
367
- }
373
+ }
368
374
 
369
- .label {
370
- font-size: var(--smrt-typography-body-large-size, 1rem);
371
- line-height: var(--smrt-typography-body-large-line-height, 1.5);
372
- letter-spacing: var(--smrt-typography-body-large-tracking, 0.5px);
373
- color: var(--field-color);
374
- pointer-events: none;
375
- transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
376
- transform-origin: top left;
377
- }
378
-
379
- /* Label float logic */
380
- .focused .label, .has-value .label, .listening .label {
381
- transform: translateY(-8px) scale(0.75);
382
- color: var(--field-active);
383
- }
384
375
 
385
376
  .input {
386
377
  border: none;
@@ -399,19 +390,11 @@ function handleInput(e: Event) {
399
390
  outline: none;
400
391
  }
401
392
 
402
- .active-indicator {
403
- position: absolute;
404
- bottom: 0;
405
- left: 0;
406
- right: 0;
407
- height: 1px;
408
- background-color: var(--field-color);
409
- transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
410
- }
393
+ .active-indicator { display: none; }
411
394
 
412
- .focused .active-indicator {
413
- height: 2px;
414
- background-color: var(--field-active);
395
+ .focused .container {
396
+ border-color: var(--field-active);
397
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--field-active) 10%, transparent);
415
398
  }
416
399
 
417
400
  .mic-btn {
@@ -435,7 +418,7 @@ function handleInput(e: Event) {
435
418
  }
436
419
 
437
420
  .supporting-text {
438
- padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-4, 16px) 0;
421
+ padding: var(--smrt-spacing-1, 4px) 0 0;
439
422
  font-size: var(--smrt-typography-body-small-size, 0.75rem);
440
423
  min-height: 16px;
441
424
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/TextInput.svelte.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AA2QD,QAAA,MAAM,SAAS,gDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"TextInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/TextInput.svelte.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAgRD,QAAA,MAAM,SAAS,gDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Icon, ripple } from '@happyvertical/smrt-ui';
3
+ import { FieldLabel } from '@happyvertical/smrt-ui/forms';
3
4
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
4
5
  import { formatText } from '@happyvertical/smrt-ui/utils/forms/formatters.js';
5
6
  import { useAppState } from '../../hooks/useAppState.svelte.js';
@@ -50,6 +51,10 @@ let {
50
51
  onchange,
51
52
  }: Props = $props();
52
53
 
54
+ // Unique per instance: the control stays labelled even if `name` repeats on a page.
55
+ const uid = $props.id();
56
+ const labelId = `${uid}-label`;
57
+
53
58
  const app = useAppState();
54
59
  const stt = useSTT();
55
60
  const formContext = tryGetFormContext();
@@ -225,14 +230,15 @@ function handleInput(e: Event) {
225
230
  class:has-value={!!value}
226
231
  class:listening={isHolding}
227
232
  >
233
+ {#if label}
234
+ <FieldLabel id={labelId} for={name} {label} {required} />
235
+ {/if}
228
236
  <div class="container">
229
237
  <div class="content">
230
- {#if label}
231
- <label for={name} class="label">{label}{#if required}*{/if}</label>
232
- {/if}
233
238
  <textarea
234
239
  bind:this={textareaEl}
235
240
  id={name}
241
+ aria-labelledby={label ? labelId : undefined}
236
242
  {name}
237
243
  placeholder={isFocused ? placeholder : ''}
238
244
  {value}
@@ -306,10 +312,11 @@ function handleInput(e: Event) {
306
312
  position: relative;
307
313
  display: flex;
308
314
  align-items: flex-start;
309
- background-color: var(--field-bg);
310
- border-radius: var(--smrt-radius-sm, 4px) var(--smrt-radius-sm, 4px) 0 0;
311
- min-height: 56px;
312
- padding: 0 var(--smrt-spacing-4, 16px);
315
+ background-color: var(--smrt-color-surface, #fff);
316
+ border: 1px solid var(--smrt-color-outline-variant, #d1d5db);
317
+ border-radius: var(--smrt-radius-small, 6px);
318
+ min-height: 40px;
319
+ padding: 0 var(--smrt-spacing-3, 12px);
313
320
  transition: background-color var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
314
321
  }
315
322
 
@@ -325,21 +332,6 @@ function handleInput(e: Event) {
325
332
  padding-bottom: var(--smrt-spacing-2, 8px);
326
333
  }
327
334
 
328
- .label {
329
- font-size: var(--smrt-typography-body-large-size, 1rem);
330
- line-height: var(--smrt-typography-body-large-line-height, 1.5);
331
- letter-spacing: var(--smrt-typography-body-large-tracking, 0.5px);
332
- color: var(--field-color);
333
- pointer-events: none;
334
- transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
335
- transform-origin: top left;
336
- margin-bottom: var(--smrt-spacing-1, 4px);
337
- }
338
-
339
- .focused .label, .has-value .label, .listening .label {
340
- transform: translateY(-4px) scale(0.75);
341
- color: var(--field-active);
342
- }
343
335
 
344
336
  .input {
345
337
  border: none;
@@ -359,19 +351,11 @@ function handleInput(e: Event) {
359
351
  outline: none;
360
352
  }
361
353
 
362
- .active-indicator {
363
- position: absolute;
364
- bottom: 0;
365
- left: 0;
366
- right: 0;
367
- height: 1px;
368
- background-color: var(--field-color);
369
- transition: all var(--smrt-duration-short3, 200ms) var(--smrt-easing-standard, cubic-bezier(0.2, 0, 0, 1));
370
- }
354
+ .active-indicator { display: none; }
371
355
 
372
- .focused .active-indicator {
373
- height: 2px;
374
- background-color: var(--field-active);
356
+ .focused .container {
357
+ border-color: var(--field-active);
358
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--field-active) 10%, transparent);
375
359
  }
376
360
 
377
361
  .mic-btn {
@@ -396,7 +380,7 @@ function handleInput(e: Event) {
396
380
  }
397
381
 
398
382
  .supporting-text {
399
- padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-4, 16px) 0;
383
+ padding: var(--smrt-spacing-1, 4px) 0 0;
400
384
  font-size: var(--smrt-typography-body-small-size, 0.75rem);
401
385
  min-height: 16px;
402
386
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextareaInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/TextareaInput.svelte.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAwOD,QAAA,MAAM,aAAa,gDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"TextareaInput.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/TextareaInput.svelte.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,KAAK;IACpB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AA6OD,QAAA,MAAM,aAAa,gDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" generics="Item extends SortableItem, Container extends SortableContainer">
2
2
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
3
3
  import { M } from '../../i18n/strings.sortable.js';
4
+ import { formatSortableAnnouncement } from './announce.js';
4
5
  import {
5
6
  createSortable,
6
7
  type SortableAnnouncement,
@@ -53,35 +54,7 @@ const containersById = $derived(
53
54
  );
54
55
 
55
56
  function itemMessage(announcement: SortableAnnouncement): string {
56
- switch (announcement.type) {
57
- case 'pickup':
58
- return t(M['ui.sortable.pickup'], {
59
- item: announcement.item,
60
- destinations: announcement.destinations.join(', '),
61
- });
62
- case 'position':
63
- return t(M['ui.sortable.position'], {
64
- item: announcement.item,
65
- container: announcement.container,
66
- position: announcement.position,
67
- count: announcement.count,
68
- });
69
- case 'drop':
70
- return t(M['ui.sortable.drop'], {
71
- item: announcement.item,
72
- container: announcement.container,
73
- position: announcement.position,
74
- count: announcement.count,
75
- });
76
- case 'unavailable':
77
- return t(M['ui.sortable.unavailable'], {
78
- container: announcement.container,
79
- });
80
- case 'failed':
81
- return t(M['ui.sortable.failed'], { item: announcement.item });
82
- case 'cancel':
83
- return t(M['ui.sortable.cancel'], { item: announcement.item });
84
- }
57
+ return formatSortableAnnouncement(t, announcement);
85
58
  }
86
59
 
87
60
  const itemSortable = createSortable({
@@ -338,14 +311,14 @@ function containerRank(id: string): number {
338
311
  </div>
339
312
 
340
313
  <style>
341
- .smrt-sortable { display: grid; gap: var(--smrt-spacing-3); min-width: 0; position: relative; }
342
- .smrt-sortable__containers { display: grid; gap: var(--smrt-spacing-3); }
343
- .smrt-sortable__container { display: grid; gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-md); background: var(--smrt-color-surface-container); min-width: 0; }
314
+ .smrt-sortable { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-3); min-width: 0; position: relative; }
315
+ .smrt-sortable__containers { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-3); min-width: 0; }
316
+ .smrt-sortable__container { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-md); background: var(--smrt-color-surface-container); min-width: 0; }
344
317
  .smrt-sortable__container--disabled { opacity: 0.6; }
345
318
  .smrt-sortable__container--dragging { opacity: 0.55; }
346
319
  .smrt-sortable__header { display: flex; align-items: center; gap: var(--smrt-spacing-2); min-block-size: 2.25rem; }
347
320
  .smrt-sortable__content { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: var(--smrt-spacing-2); }
348
- .smrt-sortable__items { display: grid; gap: var(--smrt-spacing-1); min-block-size: 2.25rem; }
321
+ .smrt-sortable__items { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--smrt-spacing-1); min-block-size: 2.25rem; min-width: 0; }
349
322
  .smrt-sortable__item { display: flex; align-items: center; gap: var(--smrt-spacing-2); padding: var(--smrt-spacing-1) var(--smrt-spacing-2); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-sm); background: var(--smrt-color-surface); min-width: 0; }
350
323
  .smrt-sortable__item--dragging { opacity: 0.55; }
351
324
  .smrt-sortable__handle { display: inline-grid; place-items: center; flex: 0 0 auto; inline-size: 2rem; block-size: 2rem; padding: 0; border: 0; border-radius: var(--smrt-radius-sm); background: transparent; color: var(--smrt-color-on-surface-variant); cursor: grab; touch-action: none; }
@@ -1 +1 @@
1
- {"version":3,"file":"Sortable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/Sortable.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,iBAAS,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAE,SAAS,SAAS,iBAAiB;WAiRnD,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC;;;;;EAA4E;AACvI,cAAM,iBAAiB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB;IACjF,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACtgB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACjN,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,EAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACrE;AACD,QAAA,MAAM,QAAQ,EAAE,qBAAmC,CAAC;AAClC,KAAK,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC;AAC/H,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Sortable.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/Sortable.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,iBAAS,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAE,SAAS,SAAS,iBAAiB;WAsPnD,aAAa,CAAC,IAAI,EAAE,SAAS,CAAC;;;;;EAA4E;AACvI,cAAM,iBAAiB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB;IACjF,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC/D,KAAK,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,QAAQ;IACR,OAAO;CACV;AAED,UAAU,qBAAqB;IAC3B,KAAK,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;KAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACtgB,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACjN,YAAY,CAAC,EAAE,UAAU,CAAC,iBAAiB,CAAC,GAAG,EAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;CACrE;AACD,QAAA,MAAM,QAAQ,EAAE,qBAAmC,CAAC;AAClC,KAAK,QAAQ,CAAC,IAAI,SAAS,YAAY,EAAC,SAAS,SAAS,iBAAiB,IAAI,YAAY,CAAC,OAAO,QAAQ,CAAC,IAAI,EAAC,SAAS,CAAC,CAAC,CAAC;AAC/H,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { useI18n } from '@happyvertical/smrt-ui/i18n';
2
+ import type { SortableAnnouncement } from './controller.svelte.js';
3
+ /** Localized screen-reader text for a sortable engine announcement. */
4
+ export declare function formatSortableAnnouncement(t: ReturnType<typeof useI18n>['t'], announcement: SortableAnnouncement): string;
5
+ //# sourceMappingURL=announce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"announce.d.ts","sourceRoot":"","sources":["../../../src/components/sortable/announce.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,uEAAuE;AACvE,wBAAgB,0BAA0B,CACxC,CAAC,EAAE,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,GAAG,CAAC,EAClC,YAAY,EAAE,oBAAoB,GACjC,MAAM,CA8BR"}
@@ -0,0 +1,33 @@
1
+ import { M } from '../../i18n/strings.sortable.js';
2
+ /** Localized screen-reader text for a sortable engine announcement. */
3
+ export function formatSortableAnnouncement(t, announcement) {
4
+ switch (announcement.type) {
5
+ case 'pickup':
6
+ return t(M['ui.sortable.pickup'], {
7
+ item: announcement.item,
8
+ destinations: announcement.destinations.join(', '),
9
+ });
10
+ case 'position':
11
+ return t(M['ui.sortable.position'], {
12
+ item: announcement.item,
13
+ container: announcement.container,
14
+ position: announcement.position,
15
+ count: announcement.count,
16
+ });
17
+ case 'drop':
18
+ return t(M['ui.sortable.drop'], {
19
+ item: announcement.item,
20
+ container: announcement.container,
21
+ position: announcement.position,
22
+ count: announcement.count,
23
+ });
24
+ case 'unavailable':
25
+ return t(M['ui.sortable.unavailable'], {
26
+ container: announcement.container,
27
+ });
28
+ case 'failed':
29
+ return t(M['ui.sortable.failed'], { item: announcement.item });
30
+ case 'cancel':
31
+ return t(M['ui.sortable.cancel'], { item: announcement.item });
32
+ }
33
+ }