@happyvertical/smrt-svelte 0.53.0 → 0.53.2

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 (254) hide show
  1. package/package.json +15 -15
  2. package/dist/__tests__/app-state.test.js +0 -156
  3. package/dist/__tests__/data-surface-bridge.test.js +0 -351
  4. package/dist/__tests__/provider-mode-harness.svelte +0 -14
  5. package/dist/__tests__/provider-mode-harness.svelte.d.ts +0 -11
  6. package/dist/__tests__/provider-mode-harness.svelte.d.ts.map +0 -1
  7. package/dist/__tests__/provider-mode-probe.svelte +0 -13
  8. package/dist/__tests__/provider-mode-probe.svelte.d.ts +0 -8
  9. package/dist/__tests__/provider-mode-probe.svelte.d.ts.map +0 -1
  10. package/dist/__tests__/provider-webmcp-harness.svelte +0 -14
  11. package/dist/__tests__/provider-webmcp-harness.svelte.d.ts +0 -8
  12. package/dist/__tests__/provider-webmcp-harness.svelte.d.ts.map +0 -1
  13. package/dist/__tests__/success-never-text.test.js +0 -100
  14. package/dist/__tests__/warm-clients.test.js +0 -186
  15. package/dist/browser-ai/adapters/llm/bitgpu-inference-backend.test.js +0 -464
  16. package/dist/browser-ai/adapters/llm/webllm-inference-backend.test.js +0 -646
  17. package/dist/browser-ai/adapters/stt/browser-speech.test.js +0 -113
  18. package/dist/browser-ai/adapters/stt/dictation-source.test.js +0 -52
  19. package/dist/browser-ai/svelte/components/__tests__/ModelStatusControl.test.js +0 -172
  20. package/dist/components/board/__tests__/Board.test.js +0 -498
  21. package/dist/components/board/__tests__/BoardSsrHarness.svelte +0 -30
  22. package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts +0 -19
  23. package/dist/components/board/__tests__/BoardSsrHarness.svelte.d.ts.map +0 -1
  24. package/dist/components/forms/__tests__/AddressInput.behavior.test.js +0 -216
  25. package/dist/components/forms/__tests__/CheckboxInput.test.js +0 -92
  26. package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +0 -135
  27. package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +0 -113
  28. package/dist/components/forms/__tests__/FileUpload.error-alert.test.js +0 -37
  29. package/dist/components/forms/__tests__/FileUpload.native-form.test.js +0 -249
  30. package/dist/components/forms/__tests__/FileUpload.test.js +0 -90
  31. package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte +0 -24
  32. package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts +0 -10
  33. package/dist/components/forms/__tests__/FileUploadReset.fixture.svelte.d.ts.map +0 -1
  34. package/dist/components/forms/__tests__/Form.behavior.test.js +0 -137
  35. package/dist/components/forms/__tests__/Form.extraction.test.js +0 -68
  36. package/dist/components/forms/__tests__/Form.stt-error.test.js +0 -57
  37. package/dist/components/forms/__tests__/Form.test.js +0 -86
  38. package/dist/components/forms/__tests__/Form.ui-controls.test.js +0 -119
  39. package/dist/components/forms/__tests__/Form.webmcp.test.js +0 -2336
  40. package/dist/components/forms/__tests__/FormMicButton.test.js +0 -92
  41. package/dist/components/forms/__tests__/FormScope.test.js +0 -39
  42. package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +0 -129
  43. package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +0 -124
  44. package/dist/components/forms/__tests__/NumberInput.behavior.test.js +0 -151
  45. package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +0 -96
  46. package/dist/components/forms/__tests__/SearchInput.test.js +0 -79
  47. package/dist/components/forms/__tests__/SelectInput.behavior.test.js +0 -132
  48. package/dist/components/forms/__tests__/TextInput.behavior.test.js +0 -131
  49. package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +0 -96
  50. package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte +0 -30
  51. package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts +0 -7
  52. package/dist/components/forms/__tests__/async-invalid-field.fixture.svelte.d.ts.map +0 -1
  53. package/dist/components/forms/__tests__/async-validation-form.fixture.svelte +0 -19
  54. package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts +0 -9
  55. package/dist/components/forms/__tests__/async-validation-form.fixture.svelte.d.ts.map +0 -1
  56. package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte +0 -21
  57. package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts +0 -8
  58. package/dist/components/forms/__tests__/async-validation-snapshot-form.fixture.svelte.d.ts.map +0 -1
  59. package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +0 -69
  60. package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte +0 -27
  61. package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts +0 -9
  62. package/dist/components/forms/__tests__/compound-registration-wrapper.fixture.svelte.d.ts.map +0 -1
  63. package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte +0 -48
  64. package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts +0 -10
  65. package/dist/components/forms/__tests__/custom-registration-field.fixture.svelte.d.ts.map +0 -1
  66. package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte +0 -26
  67. package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts +0 -13
  68. package/dist/components/forms/__tests__/form-extraction-values.fixture.svelte.d.ts.map +0 -1
  69. package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte +0 -52
  70. package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts +0 -16
  71. package/dist/components/forms/__tests__/form-registration-lifecycle.fixture.svelte.d.ts.map +0 -1
  72. package/dist/components/forms/__tests__/form-scope.fixture.svelte +0 -30
  73. package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts +0 -10
  74. package/dist/components/forms/__tests__/form-scope.fixture.svelte.d.ts.map +0 -1
  75. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +0 -158
  76. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +0 -51
  77. package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +0 -1
  78. package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte +0 -24
  79. package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts +0 -11
  80. package/dist/components/forms/__tests__/form-with-policy-field.fixture.svelte.d.ts.map +0 -1
  81. package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte +0 -105
  82. package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts +0 -42
  83. package/dist/components/forms/__tests__/form-with-structured-fields.fixture.svelte.d.ts.map +0 -1
  84. package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte +0 -84
  85. package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts +0 -14
  86. package/dist/components/forms/__tests__/form-with-ui-controls.fixture.svelte.d.ts.map +0 -1
  87. package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte +0 -44
  88. package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts +0 -9
  89. package/dist/components/forms/__tests__/legacy-form-context.fixture.svelte.d.ts.map +0 -1
  90. package/dist/components/forms/__tests__/mic-keyboard-a11y.test.js +0 -74
  91. package/dist/components/forms/__tests__/policy-field.fixture.svelte +0 -35
  92. package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts +0 -8
  93. package/dist/components/forms/__tests__/policy-field.fixture.svelte.d.ts.map +0 -1
  94. package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +0 -87
  95. package/dist/components/settings/__tests__/SettingsCatalog.test.js +0 -69
  96. package/dist/components/settings/__tests__/catalog.test.js +0 -46
  97. package/dist/components/workspace/__tests__/AdminShell.responsive.test.js +0 -597
  98. package/dist/components/workspace/__tests__/AdminShell.test.js +0 -572
  99. package/dist/components/workspace/__tests__/RoleShell.test.js +0 -772
  100. package/dist/components/workspace/__tests__/TenantNav.test.js +0 -208
  101. package/dist/components/workspace/__tests__/WorkspaceAccountMenu.test.js +0 -79
  102. package/dist/components/workspace/__tests__/WorkspaceShell.test.js +0 -630
  103. package/dist/components/workspace/__tests__/admin-shell-header-overflow.test.js +0 -25
  104. package/dist/components/workspace/__tests__/admin-shell-hotkeys.test.js +0 -34
  105. package/dist/components/workspace/__tests__/admin-shell-mobile.test.js +0 -217
  106. package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte +0 -52
  107. package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts +0 -23
  108. package/dist/components/workspace/__tests__/admin-shell-mutation-effect-harness.svelte.d.ts.map +0 -1
  109. package/dist/components/workspace/__tests__/admin-shell-page-contracts.test.js +0 -30
  110. package/dist/components/workspace/__tests__/admin-shell-responsive-state.test.js +0 -184
  111. package/dist/components/workspace/__tests__/admin-shell-settings.test.js +0 -25
  112. package/dist/components/workspace/__tests__/admin-shell-state.test.js +0 -286
  113. package/dist/components/workspace/__tests__/admin-shell-theme-hooks.test.js +0 -36
  114. package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +0 -141
  115. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +0 -45
  116. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +0 -21
  117. package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +0 -1
  118. package/dist/components/workspace/__tests__/define-tools-dock.test.js +0 -1188
  119. package/dist/components/workspace/__tests__/harness.svelte +0 -25
  120. package/dist/components/workspace/__tests__/harness.svelte.d.ts +0 -14
  121. package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +0 -1
  122. package/dist/components/workspace/__tests__/index.test.js +0 -28
  123. package/dist/components/workspace/__tests__/legacy-index.test.js +0 -9
  124. package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +0 -24
  125. package/dist/components/workspace/__tests__/manifest-nav.test.js +0 -599
  126. package/dist/components/workspace/__tests__/nav-helpers.test.js +0 -95
  127. package/dist/components/workspace/__tests__/render-harness.svelte +0 -66
  128. package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +0 -32
  129. package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +0 -1
  130. package/dist/components/workspace/__tests__/render-tools-dock.test.js +0 -260
  131. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +0 -58
  132. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +0 -16
  133. package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +0 -1
  134. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +0 -41
  135. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +0 -13
  136. package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +0 -1
  137. package/dist/components/workspace/__tests__/shell-chrome-components.test.js +0 -108
  138. package/dist/components/workspace/__tests__/system-feed.test.js +0 -327
  139. package/dist/components/workspace/__tests__/test-icon.svelte +0 -17
  140. package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +0 -19
  141. package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +0 -1
  142. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +0 -38
  143. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +0 -22
  144. package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +0 -1
  145. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +0 -66
  146. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +0 -1
  147. package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +0 -115
  148. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +0 -15
  149. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +0 -1
  150. package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +0 -7
  151. package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +0 -115
  152. package/dist/components/workspace/__tests__/use-harness-orphan.svelte +0 -9
  153. package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +0 -19
  154. package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +0 -1
  155. package/dist/components/workspace/__tests__/use-harness.svelte +0 -23
  156. package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +0 -8
  157. package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +0 -1
  158. package/dist/components/workspace/__tests__/use-tools-dock.test.js +0 -33
  159. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +0 -43
  160. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +0 -11
  161. package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +0 -1
  162. package/dist/components/workspace/server/__tests__/compose-availability.test.js +0 -383
  163. package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +0 -78
  164. package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +0 -1
  165. package/dist/components/workspace/server/__tests__/typed-context-fixture.js +0 -104
  166. package/dist/hooks/__tests__/stt-consumer.fixture.svelte +0 -25
  167. package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts +0 -15
  168. package/dist/hooks/__tests__/stt-consumer.fixture.svelte.d.ts.map +0 -1
  169. package/dist/hooks/__tests__/stt-ownership-harness.svelte +0 -42
  170. package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts +0 -20
  171. package/dist/hooks/__tests__/stt-ownership-harness.svelte.d.ts.map +0 -1
  172. package/dist/hooks/__tests__/useSTT-ownership.test.js +0 -102
  173. package/dist/i18n/__tests__/server.spec.js +0 -57
  174. package/dist/internal/logger.test.js +0 -54
  175. package/dist/provider-mode.test.js +0 -86
  176. package/dist/provider-webmcp.test.js +0 -244
  177. package/dist/state/__tests__/app-state-ai-lifecycle.test.js +0 -240
  178. package/dist/state/__tests__/warm-clients.test.js +0 -40
  179. package/dist/web/__tests__/activity-feed-harness.svelte +0 -32
  180. package/dist/web/__tests__/activity-feed-harness.svelte.d.ts +0 -18
  181. package/dist/web/__tests__/activity-feed-harness.svelte.d.ts.map +0 -1
  182. package/dist/web/__tests__/activity-feed.integration.svelte.test.js +0 -190
  183. package/dist/web/__tests__/activity-feed.svelte.test.js +0 -235
  184. package/dist/web/__tests__/assistant-dock.integration.svelte.test.js +0 -204
  185. package/dist/web/__tests__/data-surface-conformance.integration.svelte.test.js +0 -1392
  186. package/dist/web/__tests__/harness.svelte +0 -25
  187. package/dist/web/__tests__/harness.svelte.d.ts +0 -15
  188. package/dist/web/__tests__/harness.svelte.d.ts.map +0 -1
  189. package/dist/web/__tests__/list-data-surface.fixture.svelte +0 -59
  190. package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts +0 -14
  191. package/dist/web/__tests__/list-data-surface.fixture.svelte.d.ts.map +0 -1
  192. package/dist/web/__tests__/list-data-surface.svelte.test.js +0 -106
  193. package/dist/web/__tests__/list-data-surface.test.js +0 -651
  194. package/dist/web/__tests__/list-sort-surface.fixture.svelte +0 -41
  195. package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts +0 -15
  196. package/dist/web/__tests__/list-sort-surface.fixture.svelte.d.ts.map +0 -1
  197. package/dist/web/__tests__/list-sort-surface.svelte.test.js +0 -59
  198. package/dist/web/__tests__/live-collection.svelte.test.js +0 -185
  199. package/dist/web/__tests__/provider-ui-registry.fixture.svelte +0 -43
  200. package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts +0 -13
  201. package/dist/web/__tests__/provider-ui-registry.fixture.svelte.d.ts.map +0 -1
  202. package/dist/web/__tests__/provider-ui-registry.test.js +0 -235
  203. package/dist/web/__tests__/remote-query-harness.svelte +0 -27
  204. package/dist/web/__tests__/remote-query-harness.svelte.d.ts +0 -11
  205. package/dist/web/__tests__/remote-query-harness.svelte.d.ts.map +0 -1
  206. package/dist/web/__tests__/remote-query.svelte.test.js +0 -101
  207. package/dist/web/__tests__/surfaces.child.fixture.svelte +0 -69
  208. package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts +0 -16
  209. package/dist/web/__tests__/surfaces.child.fixture.svelte.d.ts.map +0 -1
  210. package/dist/web/__tests__/surfaces.fixture.svelte +0 -26
  211. package/dist/web/__tests__/surfaces.fixture.svelte.d.ts +0 -18
  212. package/dist/web/__tests__/surfaces.fixture.svelte.d.ts.map +0 -1
  213. package/dist/web/__tests__/surfaces.svelte.test.js +0 -140
  214. package/dist/web/__tests__/update-available-harness.svelte +0 -46
  215. package/dist/web/__tests__/update-available-harness.svelte.d.ts +0 -22
  216. package/dist/web/__tests__/update-available-harness.svelte.d.ts.map +0 -1
  217. package/dist/web/__tests__/update-available.svelte.test.js +0 -137
  218. package/dist/web/__tests__/view-intent-provider.fixture.svelte +0 -28
  219. package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts +0 -13
  220. package/dist/web/__tests__/view-intent-provider.fixture.svelte.d.ts.map +0 -1
  221. package/dist/web/__tests__/view-intent.fixture.svelte +0 -33
  222. package/dist/web/__tests__/view-intent.fixture.svelte.d.ts +0 -15
  223. package/dist/web/__tests__/view-intent.fixture.svelte.d.ts.map +0 -1
  224. package/dist/web/__tests__/view-intent.intents.d.ts +0 -14
  225. package/dist/web/__tests__/view-intent.intents.d.ts.map +0 -1
  226. package/dist/web/__tests__/view-intent.intents.js +0 -38
  227. package/dist/web/__tests__/view-intent.svelte.test.js +0 -244
  228. package/dist/web/__tests__/webmcp-composed.child.fixture.svelte +0 -73
  229. package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts +0 -8
  230. package/dist/web/__tests__/webmcp-composed.child.fixture.svelte.d.ts.map +0 -1
  231. package/dist/web/__tests__/webmcp-composed.fixture.svelte +0 -52
  232. package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts +0 -12
  233. package/dist/web/__tests__/webmcp-composed.fixture.svelte.d.ts.map +0 -1
  234. package/dist/web/__tests__/webmcp-composed.integration.svelte.test.js +0 -251
  235. package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte +0 -16
  236. package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts +0 -19
  237. package/dist/web/__tests__/webmcp-effects-reactivity.child.fixture.svelte.d.ts.map +0 -1
  238. package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte +0 -11
  239. package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts +0 -8
  240. package/dist/web/__tests__/webmcp-effects-reactivity.fixture.svelte.d.ts.map +0 -1
  241. package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte +0 -20
  242. package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts +0 -7
  243. package/dist/web/__tests__/webmcp-harness-reactive-samename.svelte.d.ts.map +0 -1
  244. package/dist/web/__tests__/webmcp-harness-unannotated.svelte +0 -14
  245. package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts +0 -19
  246. package/dist/web/__tests__/webmcp-harness-unannotated.svelte.d.ts.map +0 -1
  247. package/dist/web/__tests__/webmcp-harness.svelte +0 -18
  248. package/dist/web/__tests__/webmcp-harness.svelte.d.ts +0 -7
  249. package/dist/web/__tests__/webmcp-harness.svelte.d.ts.map +0 -1
  250. package/dist/web/__tests__/webmcp-ssr.fixture.svelte +0 -13
  251. package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts +0 -19
  252. package/dist/web/__tests__/webmcp-ssr.fixture.svelte.d.ts.map +0 -1
  253. package/dist/web/__tests__/webmcp-ui.test.js +0 -723
  254. package/dist/web/__tests__/webmcp.test.js +0 -234
@@ -1,630 +0,0 @@
1
- /**
2
- * Tests for WorkspaceShell — issue happyvertical/smrt#1227.
3
- *
4
- * Uses Svelte 5's `mount` / `unmount` APIs and `createRawSnippet` to exercise
5
- * the component in jsdom without pulling in `@testing-library/svelte` (which
6
- * the package doesn't depend on).
7
- */
8
- import { createRawSnippet, mount, tick, unmount } from 'svelte';
9
- import { compile } from 'svelte/compiler';
10
- import { afterEach, beforeEach, describe, expect, it } from 'vitest';
11
- import WorkspaceShell from '../WorkspaceShell.svelte';
12
- import workspaceShellSource from '../WorkspaceShell.svelte?raw';
13
- import BindHarness from './workspace-shell-bind-harness.svelte';
14
- function textSnippet(text) {
15
- return createRawSnippet(() => ({
16
- render: () => `<span>${text}</span>`,
17
- }));
18
- }
19
- function longNavSnippet(itemCount = 48) {
20
- const links = Array.from({ length: itemCount }, (_, index) => `<a href="/item-${index}">Navigation item ${index}</a>`).join('');
21
- return createRawSnippet(() => ({
22
- render: () => `<div class="long-nav">${links}</div>`,
23
- }));
24
- }
25
- function getWorkspaceShellStyle(selector) {
26
- const { css } = compile(workspaceShellSource, {
27
- filename: 'WorkspaceShell.svelte',
28
- generate: 'client',
29
- });
30
- const style = document.createElement('style');
31
- style.textContent = css?.code ?? '';
32
- document.head.appendChild(style);
33
- try {
34
- const rules = Array.from(style.sheet?.cssRules ?? []);
35
- const rule = rules.find((candidate) => 'selectorText' in candidate &&
36
- candidate.selectorText.includes(selector));
37
- return rule?.style ?? null;
38
- }
39
- finally {
40
- style.remove();
41
- }
42
- }
43
- let container;
44
- beforeEach(() => {
45
- container = document.createElement('div');
46
- document.body.appendChild(container);
47
- });
48
- afterEach(() => {
49
- container.remove();
50
- });
51
- describe('WorkspaceShell', () => {
52
- it('renders with only required children prop', () => {
53
- const component = mount(WorkspaceShell, {
54
- target: container,
55
- props: {
56
- children: textSnippet('main content'),
57
- },
58
- });
59
- try {
60
- expect(container.querySelector('.smrt-workspace-shell')).not.toBeNull();
61
- expect(container.querySelector('.smrt-workspace-content')?.textContent).toContain('main content');
62
- }
63
- finally {
64
- unmount(component);
65
- }
66
- });
67
- it('renders the brand snippet when provided', () => {
68
- const component = mount(WorkspaceShell, {
69
- target: container,
70
- props: {
71
- children: textSnippet('content'),
72
- brand: textSnippet('MyBrand'),
73
- },
74
- });
75
- try {
76
- const brand = container.querySelector('.brand');
77
- expect(brand?.textContent).toContain('MyBrand');
78
- }
79
- finally {
80
- unmount(component);
81
- }
82
- });
83
- it('falls back to title / subtitle / eyebrow when no brand snippet is given', () => {
84
- const component = mount(WorkspaceShell, {
85
- target: container,
86
- props: {
87
- children: textSnippet('content'),
88
- title: 'Workspace',
89
- subtitle: 'Engineering',
90
- eyebrow: 'SMRT',
91
- },
92
- });
93
- try {
94
- const brand = container.querySelector('.brand');
95
- expect(brand?.textContent).toContain('Workspace');
96
- expect(brand?.textContent).toContain('Engineering');
97
- expect(brand?.textContent).toContain('SMRT');
98
- }
99
- finally {
100
- unmount(component);
101
- }
102
- });
103
- it('renders the nav snippet inside an aria-labelled region', () => {
104
- const component = mount(WorkspaceShell, {
105
- target: container,
106
- props: {
107
- children: textSnippet('content'),
108
- nav: textSnippet('nav-content'),
109
- },
110
- });
111
- try {
112
- const navRegion = container.querySelector('nav.nav-region');
113
- expect(navRegion).not.toBeNull();
114
- expect(navRegion?.getAttribute('aria-label')).toBe('Workspace navigation');
115
- expect(navRegion?.textContent).toContain('nav-content');
116
- }
117
- finally {
118
- unmount(component);
119
- }
120
- });
121
- it('renders the sidebar footer snippet when provided', () => {
122
- const component = mount(WorkspaceShell, {
123
- target: container,
124
- props: {
125
- children: textSnippet('content'),
126
- sidebarFooter: textSnippet('account-menu'),
127
- },
128
- });
129
- try {
130
- const footer = container.querySelector('.sidebar-footer');
131
- expect(footer?.textContent).toContain('account-menu');
132
- }
133
- finally {
134
- unmount(component);
135
- }
136
- });
137
- it('keeps long sidebar navigation scrolling above a fixed footer', () => {
138
- const component = mount(WorkspaceShell, {
139
- target: container,
140
- props: {
141
- children: textSnippet('content'),
142
- nav: longNavSnippet(),
143
- sidebarFooter: textSnippet('account-menu'),
144
- },
145
- });
146
- try {
147
- const sidebar = container.querySelector('.smrt-workspace-sidebar');
148
- const navRegion = container.querySelector('.nav-region');
149
- const footer = container.querySelector('.sidebar-footer');
150
- expect(sidebar).not.toBeNull();
151
- expect(navRegion).not.toBeNull();
152
- expect(footer).not.toBeNull();
153
- const sidebarStyle = getWorkspaceShellStyle('.smrt-workspace-sidebar');
154
- const navStyle = getWorkspaceShellStyle('.nav-region');
155
- const footerStyle = getWorkspaceShellStyle('.sidebar-footer');
156
- expect(sidebarStyle?.position).toBe('sticky');
157
- expect(sidebarStyle?.overflow).toBe('hidden');
158
- expect(navStyle?.flex).toBe('1 1 auto');
159
- expect(navStyle?.overflowY).toBe('auto');
160
- expect(footerStyle?.flex).toBe('0 0 auto');
161
- }
162
- finally {
163
- unmount(component);
164
- }
165
- });
166
- it('renders topbar actions on the right of the top bar', () => {
167
- const component = mount(WorkspaceShell, {
168
- target: container,
169
- props: {
170
- children: textSnippet('content'),
171
- topbarActions: textSnippet('action-button'),
172
- },
173
- });
174
- try {
175
- const actions = container.querySelector('.topbar-actions');
176
- expect(actions?.textContent).toContain('action-button');
177
- }
178
- finally {
179
- unmount(component);
180
- }
181
- });
182
- it('does NOT render inspector when showInspector is false', () => {
183
- const component = mount(WorkspaceShell, {
184
- target: container,
185
- props: {
186
- children: textSnippet('content'),
187
- inspector: textSnippet('inspector-content'),
188
- showInspector: false,
189
- },
190
- });
191
- try {
192
- expect(container.querySelector('.smrt-workspace-inspector')).toBeNull();
193
- const shell = container.querySelector('.smrt-workspace-shell');
194
- expect(shell?.classList.contains('has-inspector')).toBe(false);
195
- }
196
- finally {
197
- unmount(component);
198
- }
199
- });
200
- it('renders inspector and has-inspector class when showInspector is true', () => {
201
- const component = mount(WorkspaceShell, {
202
- target: container,
203
- props: {
204
- children: textSnippet('content'),
205
- inspector: textSnippet('inspector-content'),
206
- showInspector: true,
207
- },
208
- });
209
- try {
210
- const inspector = container.querySelector('.smrt-workspace-inspector');
211
- expect(inspector).not.toBeNull();
212
- expect(inspector?.textContent).toContain('inspector-content');
213
- const shell = container.querySelector('.smrt-workspace-shell');
214
- expect(shell?.classList.contains('has-inspector')).toBe(true);
215
- }
216
- finally {
217
- unmount(component);
218
- }
219
- });
220
- it('renders inspector close button when onCloseInspector is provided', () => {
221
- let closed = false;
222
- const component = mount(WorkspaceShell, {
223
- target: container,
224
- props: {
225
- children: textSnippet('content'),
226
- inspector: textSnippet('inspector-content'),
227
- showInspector: true,
228
- onCloseInspector: () => {
229
- closed = true;
230
- },
231
- },
232
- });
233
- try {
234
- const closeBtn = container.querySelector('.inspector-close');
235
- expect(closeBtn).not.toBeNull();
236
- closeBtn?.click();
237
- expect(closed).toBe(true);
238
- }
239
- finally {
240
- unmount(component);
241
- }
242
- });
243
- it('omits the inspector close button when onCloseInspector is not provided', () => {
244
- const component = mount(WorkspaceShell, {
245
- target: container,
246
- props: {
247
- children: textSnippet('content'),
248
- inspector: textSnippet('inspector-content'),
249
- showInspector: true,
250
- },
251
- });
252
- try {
253
- expect(container.querySelector('.inspector-close')).toBeNull();
254
- }
255
- finally {
256
- unmount(component);
257
- }
258
- });
259
- it('renders the inspector rail snippet when provided', () => {
260
- const component = mount(WorkspaceShell, {
261
- target: container,
262
- props: {
263
- children: textSnippet('content'),
264
- inspectorRail: textSnippet('rail-button'),
265
- },
266
- });
267
- try {
268
- const rail = container.querySelector('.smrt-workspace-inspector-rail');
269
- expect(rail).not.toBeNull();
270
- expect(rail?.textContent).toContain('rail-button');
271
- }
272
- finally {
273
- unmount(component);
274
- }
275
- });
276
- it('shows a collapse toggle by default and invokes onToggleCollapsed', () => {
277
- let toggles = 0;
278
- const component = mount(WorkspaceShell, {
279
- target: container,
280
- props: {
281
- children: textSnippet('content'),
282
- title: 'Brand',
283
- collapsed: false,
284
- onToggleCollapsed: () => {
285
- toggles += 1;
286
- },
287
- },
288
- });
289
- try {
290
- const toggle = container.querySelector('.shell-toggle');
291
- expect(toggle).not.toBeNull();
292
- expect(toggle?.getAttribute('aria-expanded')).toBe('true');
293
- toggle?.click();
294
- expect(toggles).toBe(1);
295
- }
296
- finally {
297
- unmount(component);
298
- }
299
- });
300
- it('hides the collapse toggle when collapsible is false', () => {
301
- const component = mount(WorkspaceShell, {
302
- target: container,
303
- props: {
304
- children: textSnippet('content'),
305
- title: 'Brand',
306
- collapsible: false,
307
- },
308
- });
309
- try {
310
- expect(container.querySelector('.shell-toggle')).toBeNull();
311
- }
312
- finally {
313
- unmount(component);
314
- }
315
- });
316
- it('applies sidebar-collapsed class when collapsed prop is true', () => {
317
- const component = mount(WorkspaceShell, {
318
- target: container,
319
- props: {
320
- children: textSnippet('content'),
321
- collapsed: true,
322
- },
323
- });
324
- try {
325
- const shell = container.querySelector('.smrt-workspace-shell');
326
- expect(shell?.classList.contains('sidebar-collapsed')).toBe(true);
327
- }
328
- finally {
329
- unmount(component);
330
- }
331
- });
332
- it('renders the mode badge when modeLabel is provided', () => {
333
- const component = mount(WorkspaceShell, {
334
- target: container,
335
- props: {
336
- children: textSnippet('content'),
337
- modeLabel: 'Local-first mode',
338
- modeStatus: 'local-only',
339
- },
340
- });
341
- try {
342
- const badge = container.querySelector('.mode-badge');
343
- expect(badge).not.toBeNull();
344
- expect(badge?.getAttribute('data-status')).toBe('local-only');
345
- expect(badge?.textContent).toContain('Local-first mode');
346
- }
347
- finally {
348
- unmount(component);
349
- }
350
- });
351
- it('omits the mode badge when no modeLabel/modeStatus is provided', () => {
352
- const component = mount(WorkspaceShell, {
353
- target: container,
354
- props: {
355
- children: textSnippet('content'),
356
- },
357
- });
358
- try {
359
- expect(container.querySelector('.mode-badge')).toBeNull();
360
- }
361
- finally {
362
- unmount(component);
363
- }
364
- });
365
- it('invokes onCloseInspector when Escape is pressed while inspector is open', async () => {
366
- let closes = 0;
367
- const component = mount(WorkspaceShell, {
368
- target: container,
369
- props: {
370
- children: textSnippet('content'),
371
- inspector: textSnippet('inspector-content'),
372
- showInspector: true,
373
- onCloseInspector: () => {
374
- closes += 1;
375
- },
376
- },
377
- });
378
- try {
379
- await tick();
380
- window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
381
- expect(closes).toBe(1);
382
- }
383
- finally {
384
- unmount(component);
385
- }
386
- });
387
- it('renders an interactive button backdrop only when onCloseInspector is set', () => {
388
- const component = mount(WorkspaceShell, {
389
- target: container,
390
- props: {
391
- children: textSnippet('content'),
392
- inspector: textSnippet('inspector-content'),
393
- showInspector: true,
394
- onCloseInspector: () => { },
395
- },
396
- });
397
- try {
398
- const backdrop = container.querySelector('.inspector-backdrop');
399
- expect(backdrop).not.toBeNull();
400
- expect(backdrop?.tagName).toBe('BUTTON');
401
- }
402
- finally {
403
- unmount(component);
404
- }
405
- });
406
- it('renders a non-interactive backdrop when onCloseInspector is omitted', () => {
407
- const component = mount(WorkspaceShell, {
408
- target: container,
409
- props: {
410
- children: textSnippet('content'),
411
- inspector: textSnippet('inspector-content'),
412
- showInspector: true,
413
- },
414
- });
415
- try {
416
- const backdrop = container.querySelector('.inspector-backdrop');
417
- expect(backdrop).not.toBeNull();
418
- expect(backdrop?.tagName).toBe('DIV');
419
- expect(backdrop?.getAttribute('aria-hidden')).toBe('true');
420
- }
421
- finally {
422
- unmount(component);
423
- }
424
- });
425
- it('renders the default "Inspector" header label when inspectorTitle is omitted', () => {
426
- const component = mount(WorkspaceShell, {
427
- target: container,
428
- props: {
429
- children: textSnippet('content'),
430
- inspector: textSnippet('inspector-content'),
431
- showInspector: true,
432
- },
433
- });
434
- try {
435
- const title = container.querySelector('.inspector-title');
436
- expect(title?.textContent).toBe('Inspector');
437
- }
438
- finally {
439
- unmount(component);
440
- }
441
- });
442
- it('uses a custom inspectorTitle and exposes it via aria-label', () => {
443
- // The inspector aside uses aria-label (not aria-labelledby with a hard-coded
444
- // id) so multiple <WorkspaceShell> instances on the same page can't collide
445
- // on duplicate ids — see Copilot review on PR #1232.
446
- const component = mount(WorkspaceShell, {
447
- target: container,
448
- props: {
449
- children: textSnippet('content'),
450
- inspector: textSnippet('inspector-content'),
451
- showInspector: true,
452
- inspectorTitle: 'Properties',
453
- },
454
- });
455
- try {
456
- const title = container.querySelector('.inspector-title');
457
- expect(title?.textContent).toBe('Properties');
458
- const aside = container.querySelector('.smrt-workspace-inspector');
459
- expect(aside?.getAttribute('aria-label')).toBe('Properties');
460
- expect(aside?.getAttribute('aria-labelledby')).toBeNull();
461
- }
462
- finally {
463
- unmount(component);
464
- }
465
- });
466
- it('marks the sidebar inert on mobile when the drawer is closed', async () => {
467
- const originalMatchMedia = window.matchMedia;
468
- // Force the mobile breakpoint so `isMobileViewport` becomes true.
469
- window.matchMedia = ((query) => ({
470
- matches: /max-width:\s*960px/.test(query),
471
- media: query,
472
- onchange: null,
473
- addListener: () => { },
474
- removeListener: () => { },
475
- addEventListener: () => { },
476
- removeEventListener: () => { },
477
- dispatchEvent: () => false,
478
- }));
479
- const component = mount(WorkspaceShell, {
480
- target: container,
481
- props: {
482
- children: textSnippet('content'),
483
- nav: textSnippet('nav-content'),
484
- },
485
- });
486
- try {
487
- await tick();
488
- const sidebar = container.querySelector('.smrt-workspace-sidebar');
489
- // jsdom reflects the `inert` attribute as a boolean property — both
490
- // forms are acceptable, the contract is "keyboard tab order skips
491
- // the sidebar when it's offscreen".
492
- expect(sidebar?.hasAttribute('inert') ||
493
- sidebar?.inert === true).toBe(true);
494
- }
495
- finally {
496
- unmount(component);
497
- window.matchMedia = originalMatchMedia;
498
- }
499
- });
500
- describe('bindable mobileNavOpen', () => {
501
- it('opens the drawer when the bound value flips to true externally', async () => {
502
- let controls;
503
- const component = mount(BindHarness, {
504
- target: container,
505
- props: {
506
- onReady: (c) => {
507
- controls = c;
508
- },
509
- },
510
- });
511
- try {
512
- await tick();
513
- const shell = container.querySelector('.smrt-workspace-shell');
514
- expect(shell?.classList.contains('nav-open')).toBe(false);
515
- controls.setMobileNavOpen(true);
516
- await tick();
517
- expect(shell?.classList.contains('nav-open')).toBe(true);
518
- expect(controls.getMobileNavOpen()).toBe(true);
519
- controls.setMobileNavOpen(false);
520
- await tick();
521
- expect(shell?.classList.contains('nav-open')).toBe(false);
522
- expect(controls.getMobileNavOpen()).toBe(false);
523
- }
524
- finally {
525
- unmount(component);
526
- }
527
- });
528
- it('propagates internal hamburger clicks back through bind:', async () => {
529
- let controls;
530
- const component = mount(BindHarness, {
531
- target: container,
532
- props: {
533
- onReady: (c) => {
534
- controls = c;
535
- },
536
- },
537
- });
538
- try {
539
- await tick();
540
- expect(controls.getMobileNavOpen()).toBe(false);
541
- const hamburger = container.querySelector('.mobile-menu');
542
- expect(hamburger).not.toBeNull();
543
- hamburger?.click();
544
- await tick();
545
- expect(controls.getMobileNavOpen()).toBe(true);
546
- // Toggle a second time — closes the drawer.
547
- hamburger?.click();
548
- await tick();
549
- expect(controls.getMobileNavOpen()).toBe(false);
550
- }
551
- finally {
552
- unmount(component);
553
- }
554
- });
555
- it('propagates internal backdrop clicks back through bind:', async () => {
556
- let controls;
557
- const component = mount(BindHarness, {
558
- target: container,
559
- props: {
560
- initial: true,
561
- onReady: (c) => {
562
- controls = c;
563
- },
564
- },
565
- });
566
- try {
567
- await tick();
568
- expect(controls.getMobileNavOpen()).toBe(true);
569
- const backdrop = container.querySelector('.mobile-backdrop');
570
- expect(backdrop).not.toBeNull();
571
- backdrop?.click();
572
- await tick();
573
- expect(controls.getMobileNavOpen()).toBe(false);
574
- }
575
- finally {
576
- unmount(component);
577
- }
578
- });
579
- it('honors a non-default initial value passed by the consumer', async () => {
580
- let controls;
581
- const component = mount(BindHarness, {
582
- target: container,
583
- props: {
584
- initial: true,
585
- onReady: (c) => {
586
- controls = c;
587
- },
588
- },
589
- });
590
- try {
591
- await tick();
592
- const shell = container.querySelector('.smrt-workspace-shell');
593
- expect(shell?.classList.contains('nav-open')).toBe(true);
594
- expect(controls.getMobileNavOpen()).toBe(true);
595
- }
596
- finally {
597
- unmount(component);
598
- }
599
- });
600
- });
601
- it('restores focus to the hamburger button when the mobile drawer closes via Escape', async () => {
602
- const component = mount(WorkspaceShell, {
603
- target: container,
604
- props: {
605
- children: textSnippet('content'),
606
- nav: textSnippet('nav-content'),
607
- },
608
- });
609
- try {
610
- const hamburger = container.querySelector('.mobile-menu');
611
- expect(hamburger).not.toBeNull();
612
- // Simulate keyboard-driven opening of the drawer.
613
- hamburger?.focus();
614
- expect(document.activeElement).toBe(hamburger);
615
- hamburger?.click();
616
- await tick();
617
- // Move focus elsewhere as a real drawer interaction would.
618
- const elsewhere = document.createElement('button');
619
- container.appendChild(elsewhere);
620
- elsewhere.focus();
621
- expect(document.activeElement).toBe(elsewhere);
622
- window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
623
- await tick();
624
- expect(document.activeElement).toBe(hamburger);
625
- }
626
- finally {
627
- unmount(component);
628
- }
629
- });
630
- });
@@ -1,25 +0,0 @@
1
- /**
2
- * The header row hosts actions that open menus (a notifications bell, an
3
- * account menu). Its overflow must clip sideways only, or every dropdown
4
- * opened from it is cut off at the header's bottom edge.
5
- */
6
- import { readFileSync } from 'node:fs';
7
- import { join } from 'node:path';
8
- import { describe, expect, it } from 'vitest';
9
- const packageRoot = process.cwd().endsWith('packages/smrt-svelte')
10
- ? process.cwd()
11
- : join(process.cwd(), 'packages/smrt-svelte');
12
- const source = readFileSync(join(packageRoot, 'src/components/workspace/admin-shell/AdminShell.svelte'), 'utf8');
13
- function ruleBody(selector) {
14
- const start = source.indexOf(`${selector} {`);
15
- expect(start).toBeGreaterThan(-1);
16
- return source.slice(start, source.indexOf('}', start));
17
- }
18
- describe('AdminShell header overflow', () => {
19
- it('lets header menus drop below the header row', () => {
20
- const header = ruleBody('.smrt-admin-shell__header');
21
- expect(header).not.toMatch(/(^|\s)overflow:\s*hidden/);
22
- expect(header).toMatch(/overflow-x:\s*clip/);
23
- expect(header).toMatch(/overflow-y:\s*visible/);
24
- });
25
- });
@@ -1,34 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { hotkeyMatchesEvent, shellActionFromKeyboardEvent, } from '../admin-shell/hotkeys.js';
3
- import { resolveShellConfig } from '../admin-shell/settings.js';
4
- function keyEvent(init) {
5
- return new KeyboardEvent('keydown', init);
6
- }
7
- describe('AdminShell hotkeys', () => {
8
- it('matches physical KeyboardEvent.code bindings', () => {
9
- expect(hotkeyMatchesEvent({ code: 'KeyW' }, keyEvent({ code: 'KeyW' }))).toBe(true);
10
- expect(hotkeyMatchesEvent({ code: 'KeyW' }, keyEvent({ code: 'KeyZ' }))).toBe(false);
11
- });
12
- it('maps WASD codes to shell edges', () => {
13
- const { panels } = resolveShellConfig();
14
- expect(shellActionFromKeyboardEvent(keyEvent({ code: 'KeyW' }), panels)).toEqual({ type: 'toggle-panel', edge: 'top' });
15
- expect(shellActionFromKeyboardEvent(keyEvent({ code: 'KeyA' }), panels)).toEqual({ type: 'toggle-panel', edge: 'left' });
16
- expect(shellActionFromKeyboardEvent(keyEvent({ code: 'KeyS' }), panels)).toEqual({ type: 'toggle-panel', edge: 'bottom' });
17
- expect(shellActionFromKeyboardEvent(keyEvent({ code: 'KeyD' }), panels)).toEqual({ type: 'toggle-panel', edge: 'right' });
18
- });
19
- it('suppresses panel hotkeys in editable controls', () => {
20
- const input = document.createElement('input');
21
- const event = keyEvent({ code: 'KeyW' });
22
- Object.defineProperty(event, 'target', { value: input });
23
- expect(shellActionFromKeyboardEvent(event, resolveShellConfig().panels)).toBe(null);
24
- });
25
- it('keeps the shortcuts overlay available on question mark', () => {
26
- expect(shellActionFromKeyboardEvent(keyEvent({ key: '?', code: 'Slash', shiftKey: true }), resolveShellConfig().panels)).toEqual({ type: 'show-shortcuts' });
27
- });
28
- it('does not open shortcuts when typing ? in an editable control', () => {
29
- const input = document.createElement('input');
30
- const event = keyEvent({ key: '?', code: 'Slash', shiftKey: true });
31
- Object.defineProperty(event, 'target', { value: input });
32
- expect(shellActionFromKeyboardEvent(event, resolveShellConfig().panels)).toBe(null);
33
- });
34
- });