@happyvertical/smrt-svelte 0.30.0
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.
- package/AGENTS.md +317 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +185 -0
- package/dist/Provider.svelte +204 -0
- package/dist/Provider.svelte.d.ts +73 -0
- package/dist/Provider.svelte.d.ts.map +1 -0
- package/dist/__tests__/app-state.test.js +156 -0
- package/dist/__tests__/warm-clients.test.js +186 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts +38 -0
- package/dist/browser-ai/adapters/llm/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/factory.js +91 -0
- package/dist/browser-ai/adapters/llm/index.d.ts +7 -0
- package/dist/browser-ai/adapters/llm/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/index.js +6 -0
- package/dist/browser-ai/adapters/llm/types.d.ts +182 -0
- package/dist/browser-ai/adapters/llm/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/types.js +43 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts +33 -0
- package/dist/browser-ai/adapters/llm/webllm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/llm/webllm.js +225 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts +31 -0
- package/dist/browser-ai/adapters/stt/browser-speech.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/browser-speech.js +217 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts +49 -0
- package/dist/browser-ai/adapters/stt/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/factory.js +110 -0
- package/dist/browser-ai/adapters/stt/index.d.ts +9 -0
- package/dist/browser-ai/adapters/stt/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/index.js +8 -0
- package/dist/browser-ai/adapters/stt/types.d.ts +154 -0
- package/dist/browser-ai/adapters/stt/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/types.js +4 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts +46 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-cpp.js +348 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts +51 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.d.ts.map +1 -0
- package/dist/browser-ai/adapters/stt/whisper-wasm.js +380 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts +42 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/browser-synthesis.js +235 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts +53 -0
- package/dist/browser-ai/adapters/tts/factory.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/factory.js +92 -0
- package/dist/browser-ai/adapters/tts/index.d.ts +7 -0
- package/dist/browser-ai/adapters/tts/index.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/index.js +6 -0
- package/dist/browser-ai/adapters/tts/types.d.ts +140 -0
- package/dist/browser-ai/adapters/tts/types.d.ts.map +1 -0
- package/dist/browser-ai/adapters/tts/types.js +4 -0
- package/dist/browser-ai/capabilities/detector.d.ts +38 -0
- package/dist/browser-ai/capabilities/detector.d.ts.map +1 -0
- package/dist/browser-ai/capabilities/detector.js +211 -0
- package/dist/browser-ai/core/errors.d.ts +62 -0
- package/dist/browser-ai/core/errors.d.ts.map +1 -0
- package/dist/browser-ai/core/errors.js +92 -0
- package/dist/browser-ai/core/index.d.ts +6 -0
- package/dist/browser-ai/core/index.d.ts.map +1 -0
- package/dist/browser-ai/core/index.js +5 -0
- package/dist/browser-ai/core/types.d.ts +115 -0
- package/dist/browser-ai/core/types.d.ts.map +1 -0
- package/dist/browser-ai/core/types.js +34 -0
- package/dist/browser-ai/index.d.ts +12 -0
- package/dist/browser-ai/index.d.ts.map +1 -0
- package/dist/browser-ai/index.js +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte +77 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/AILoadingOverlay.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte +57 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/CapabilityGate.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte +141 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts +15 -0
- package/dist/browser-ai/svelte/components/DownloadProgress.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte +379 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts +9 -0
- package/dist/browser-ai/svelte/components/STTTest.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte +200 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts +16 -0
- package/dist/browser-ai/svelte/components/VoiceInput.svelte.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.d.ts +15 -0
- package/dist/browser-ai/svelte/index.d.ts.map +1 -0
- package/dist/browser-ai/svelte/index.js +28 -0
- package/dist/browser-ai/ui.d.ts +16 -0
- package/dist/browser-ai/ui.d.ts.map +1 -0
- package/dist/browser-ai/ui.js +67 -0
- package/dist/components/admin/AgentAdminPanel.svelte +111 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts +25 -0
- package/dist/components/admin/AgentAdminPanel.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentAdminTabs.svelte +280 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts +23 -0
- package/dist/components/admin/AgentAdminTabs.svelte.d.ts.map +1 -0
- package/dist/components/admin/AgentSettingsShell.svelte +257 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts +33 -0
- package/dist/components/admin/AgentSettingsShell.svelte.d.ts.map +1 -0
- package/dist/components/admin/index.d.ts +5 -0
- package/dist/components/admin/index.d.ts.map +1 -0
- package/dist/components/admin/index.js +6 -0
- package/dist/components/forms/AddressInput.svelte +500 -0
- package/dist/components/forms/AddressInput.svelte.d.ts +36 -0
- package/dist/components/forms/AddressInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/CheckboxInput.svelte +208 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts +20 -0
- package/dist/components/forms/CheckboxInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateRangeInput.svelte +628 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts +33 -0
- package/dist/components/forms/DateRangeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/DateTimeInput.svelte +521 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts +24 -0
- package/dist/components/forms/DateTimeInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/FileUpload.svelte +358 -0
- package/dist/components/forms/FileUpload.svelte.d.ts +22 -0
- package/dist/components/forms/FileUpload.svelte.d.ts.map +1 -0
- package/dist/components/forms/Form.svelte +771 -0
- package/dist/components/forms/Form.svelte.d.ts +26 -0
- package/dist/components/forms/Form.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormGroup.svelte +86 -0
- package/dist/components/forms/FormGroup.svelte.d.ts +13 -0
- package/dist/components/forms/FormGroup.svelte.d.ts.map +1 -0
- package/dist/components/forms/FormMicButton.svelte +179 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts +10 -0
- package/dist/components/forms/FormMicButton.svelte.d.ts.map +1 -0
- package/dist/components/forms/Input.svelte +83 -0
- package/dist/components/forms/Input.svelte.d.ts +9 -0
- package/dist/components/forms/Input.svelte.d.ts.map +1 -0
- package/dist/components/forms/MeasurementInput.svelte +505 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts +35 -0
- package/dist/components/forms/MeasurementInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/MoneyInput.svelte +412 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts +30 -0
- package/dist/components/forms/MoneyInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/NumberInput.svelte +310 -0
- package/dist/components/forms/NumberInput.svelte.d.ts +28 -0
- package/dist/components/forms/NumberInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/PhoneInput.svelte +530 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts +22 -0
- package/dist/components/forms/PhoneInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/SearchInput.svelte +358 -0
- package/dist/components/forms/SearchInput.svelte.d.ts +33 -0
- package/dist/components/forms/SearchInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Select.svelte +83 -0
- package/dist/components/forms/Select.svelte.d.ts +11 -0
- package/dist/components/forms/Select.svelte.d.ts.map +1 -0
- package/dist/components/forms/SelectInput.svelte +254 -0
- package/dist/components/forms/SelectInput.svelte.d.ts +25 -0
- package/dist/components/forms/SelectInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextInput.svelte +415 -0
- package/dist/components/forms/TextInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Textarea.svelte +85 -0
- package/dist/components/forms/Textarea.svelte.d.ts +10 -0
- package/dist/components/forms/Textarea.svelte.d.ts.map +1 -0
- package/dist/components/forms/TextareaInput.svelte +386 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts +26 -0
- package/dist/components/forms/TextareaInput.svelte.d.ts.map +1 -0
- package/dist/components/forms/Toggle.svelte +217 -0
- package/dist/components/forms/Toggle.svelte.d.ts +37 -0
- package/dist/components/forms/Toggle.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/AddressInput.behavior.test.js +122 -0
- package/dist/components/forms/__tests__/CheckboxInput.test.js +92 -0
- package/dist/components/forms/__tests__/DateRangeInput.behavior.test.js +135 -0
- package/dist/components/forms/__tests__/DateTimeInput.behavior.test.js +103 -0
- package/dist/components/forms/__tests__/FileUpload.test.js +90 -0
- package/dist/components/forms/__tests__/Form.behavior.test.js +137 -0
- package/dist/components/forms/__tests__/Form.test.js +58 -0
- package/dist/components/forms/__tests__/FormGroup.test.js +48 -0
- package/dist/components/forms/__tests__/FormMicButton.test.js +86 -0
- package/dist/components/forms/__tests__/Input.test.js +49 -0
- package/dist/components/forms/__tests__/MeasurementInput.behavior.test.js +129 -0
- package/dist/components/forms/__tests__/MoneyInput.behavior.test.js +124 -0
- package/dist/components/forms/__tests__/NumberInput.behavior.test.js +141 -0
- package/dist/components/forms/__tests__/PhoneInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/SearchInput.test.js +79 -0
- package/dist/components/forms/__tests__/Select.test.js +37 -0
- package/dist/components/forms/__tests__/SelectInput.behavior.test.js +132 -0
- package/dist/components/forms/__tests__/TextInput.behavior.test.js +131 -0
- package/dist/components/forms/__tests__/Textarea.test.js +39 -0
- package/dist/components/forms/__tests__/TextareaInput.behavior.test.js +96 -0
- package/dist/components/forms/__tests__/Toggle.test.js +87 -0
- package/dist/components/forms/__tests__/composite-inputs-a11y.test.js +69 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte +16 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts +9 -0
- package/dist/components/forms/__tests__/form-group-input.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte +33 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts +12 -0
- package/dist/components/forms/__tests__/form-with-fields.fixture.svelte.d.ts.map +1 -0
- package/dist/components/forms/__tests__/rich-inputs-a11y.test.js +87 -0
- package/dist/components/forms/index.d.ts +25 -0
- package/dist/components/forms/index.d.ts.map +1 -0
- package/dist/components/forms/index.js +25 -0
- package/dist/components/forms/types.d.ts +33 -0
- package/dist/components/forms/types.d.ts.map +1 -0
- package/dist/components/forms/types.js +4 -0
- package/dist/components/module/ModulePanel.svelte +134 -0
- package/dist/components/module/ModulePanel.svelte.d.ts +22 -0
- package/dist/components/module/ModulePanel.svelte.d.ts.map +1 -0
- package/dist/components/module/index.d.ts +5 -0
- package/dist/components/module/index.d.ts.map +1 -0
- package/dist/components/module/index.js +4 -0
- package/dist/components/workspace/Breadcrumbs.svelte +141 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts +21 -0
- package/dist/components/workspace/Breadcrumbs.svelte.d.ts.map +1 -0
- package/dist/components/workspace/NavTree.svelte +354 -0
- package/dist/components/workspace/NavTree.svelte.d.ts +45 -0
- package/dist/components/workspace/NavTree.svelte.d.ts.map +1 -0
- package/dist/components/workspace/README.md +34 -0
- package/dist/components/workspace/RoleShell.svelte +309 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts +91 -0
- package/dist/components/workspace/RoleShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/WorkspaceShell.svelte +951 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts +112 -0
- package/dist/components/workspace/WorkspaceShell.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/RoleShell.test.js +772 -0
- package/dist/components/workspace/__tests__/WorkspaceShell.test.js +630 -0
- package/dist/components/workspace/__tests__/breadcrumbs-helpers.test.js +141 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte +45 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts +21 -0
- package/dist/components/workspace/__tests__/context-forwarding-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/define-tools-dock.test.js +1010 -0
- package/dist/components/workspace/__tests__/harness.svelte +25 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts +14 -0
- package/dist/components/workspace/__tests__/harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/index.test.js +37 -0
- package/dist/components/workspace/__tests__/manifest-nav-helpers.test.js +24 -0
- package/dist/components/workspace/__tests__/manifest-nav.test.js +599 -0
- package/dist/components/workspace/__tests__/nav-helpers.test.js +95 -0
- package/dist/components/workspace/__tests__/render-harness.svelte +66 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts +32 -0
- package/dist/components/workspace/__tests__/render-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/render-tools-dock.test.js +243 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte +58 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts +16 -0
- package/dist/components/workspace/__tests__/role-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte +41 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts +13 -0
- package/dist/components/workspace/__tests__/role-shell-switch-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/test-icon.svelte +17 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/test-icon.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte +38 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts +22 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/TypedTool.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts +65 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/register-typed-tool.js +115 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts +15 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture/typed-tool-types.js +7 -0
- package/dist/components/workspace/__tests__/typed-tool-fixture.test.js +115 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte +9 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts +19 -0
- package/dist/components/workspace/__tests__/use-harness-orphan.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-harness.svelte +23 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts +8 -0
- package/dist/components/workspace/__tests__/use-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/__tests__/use-tools-dock.test.js +33 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte +43 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts +11 -0
- package/dist/components/workspace/__tests__/workspace-shell-bind-harness.svelte.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts +44 -0
- package/dist/components/workspace/breadcrumbs-helpers.d.ts.map +1 -0
- package/dist/components/workspace/breadcrumbs-helpers.js +88 -0
- package/dist/components/workspace/index.d.ts +16 -0
- package/dist/components/workspace/index.d.ts.map +1 -0
- package/dist/components/workspace/index.js +14 -0
- package/dist/components/workspace/manifest-nav.d.ts +200 -0
- package/dist/components/workspace/manifest-nav.d.ts.map +1 -0
- package/dist/components/workspace/manifest-nav.js +408 -0
- package/dist/components/workspace/nav-helpers.d.ts +36 -0
- package/dist/components/workspace/nav-helpers.d.ts.map +1 -0
- package/dist/components/workspace/nav-helpers.js +60 -0
- package/dist/components/workspace/server/__tests__/compose-availability.test.js +383 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts +78 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.d.ts.map +1 -0
- package/dist/components/workspace/server/__tests__/typed-context-fixture.js +104 -0
- package/dist/components/workspace/server/compose-availability.d.ts +73 -0
- package/dist/components/workspace/server/compose-availability.d.ts.map +1 -0
- package/dist/components/workspace/server/compose-availability.js +114 -0
- package/dist/components/workspace/server/index.d.ts +13 -0
- package/dist/components/workspace/server/index.d.ts.map +1 -0
- package/dist/components/workspace/server/index.js +11 -0
- package/dist/components/workspace/server/types.d.ts +108 -0
- package/dist/components/workspace/server/types.d.ts.map +1 -0
- package/dist/components/workspace/server/types.js +11 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte +565 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts +14 -0
- package/dist/components/workspace/tools-dock/ToolsDock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts +143 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/define-tools-dock.svelte.js +487 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts +41 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.d.ts.map +1 -0
- package/dist/components/workspace/tools-dock/use-tools-dock.js +50 -0
- package/dist/components/workspace/types.d.ts +372 -0
- package/dist/components/workspace/types.d.ts.map +1 -0
- package/dist/components/workspace/types.js +6 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +10 -0
- package/dist/hooks/useAppState.svelte.d.ts +46 -0
- package/dist/hooks/useAppState.svelte.d.ts.map +1 -0
- package/dist/hooks/useAppState.svelte.js +59 -0
- package/dist/hooks/useAuth.svelte.d.ts +41 -0
- package/dist/hooks/useAuth.svelte.d.ts.map +1 -0
- package/dist/hooks/useAuth.svelte.js +43 -0
- package/dist/hooks/useLLM.svelte.d.ts +69 -0
- package/dist/hooks/useLLM.svelte.d.ts.map +1 -0
- package/dist/hooks/useLLM.svelte.js +85 -0
- package/dist/hooks/useSTT.svelte.d.ts +68 -0
- package/dist/hooks/useSTT.svelte.d.ts.map +1 -0
- package/dist/hooks/useSTT.svelte.js +97 -0
- package/dist/hooks/useSocket.svelte.d.ts +45 -0
- package/dist/hooks/useSocket.svelte.d.ts.map +1 -0
- package/dist/hooks/useSocket.svelte.js +54 -0
- package/dist/hooks/useTTS.svelte.d.ts +65 -0
- package/dist/hooks/useTTS.svelte.d.ts.map +1 -0
- package/dist/hooks/useTTS.svelte.js +93 -0
- package/dist/hooks/useTheme.d.ts +13 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +16 -0
- package/dist/i18n/__tests__/server.spec.js +50 -0
- package/dist/i18n/server.d.ts +47 -0
- package/dist/i18n/server.d.ts.map +1 -0
- package/dist/i18n/server.js +58 -0
- package/dist/i18n/strings.forms.d.ts +33 -0
- package/dist/i18n/strings.forms.d.ts.map +1 -0
- package/dist/i18n/strings.forms.js +54 -0
- package/dist/i18n/strings.workspace.d.ts +34 -0
- package/dist/i18n/strings.workspace.d.ts.map +1 -0
- package/dist/i18n/strings.workspace.js +40 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/state/__tests__/warm-clients.test.js +40 -0
- package/dist/state/app-state.d.ts +308 -0
- package/dist/state/app-state.d.ts.map +1 -0
- package/dist/state/app-state.js +64 -0
- package/dist/state/app-state.svelte.d.ts +196 -0
- package/dist/state/app-state.svelte.d.ts.map +1 -0
- package/dist/state/app-state.svelte.js +774 -0
- package/dist/state/context.d.ts +23 -0
- package/dist/state/context.d.ts.map +1 -0
- package/dist/state/context.js +32 -0
- package/dist/state/form-context.d.ts +59 -0
- package/dist/state/form-context.d.ts.map +1 -0
- package/dist/state/form-context.js +31 -0
- package/dist/state/form-group-context.d.ts +13 -0
- package/dist/state/form-group-context.d.ts.map +1 -0
- package/dist/state/form-group-context.js +28 -0
- package/dist/state/index.d.ts +9 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +8 -0
- package/dist/state/warm-clients.d.ts +136 -0
- package/dist/state/warm-clients.d.ts.map +1 -0
- package/dist/state/warm-clients.js +231 -0
- package/package.json +137 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineToolsDock - factory for the ToolsDock API
|
|
3
|
+
*
|
|
4
|
+
* Creates a reactive {@link ToolsDockApi} instance backed by Svelte 5 runes
|
|
5
|
+
* (`$state`) and registers it in Svelte context under {@link TOOLS_DOCK_KEY}.
|
|
6
|
+
* Inside a `<ToolsDock>` provider tree, descendants (tools, deep panels,
|
|
7
|
+
* arbitrary consumers) read the same instance via {@link useToolsDock}.
|
|
8
|
+
*
|
|
9
|
+
* The dock is intentionally domain-agnostic:
|
|
10
|
+
* - Tool IDs are arbitrary strings (no enum).
|
|
11
|
+
* - Availability is controlled via the optional `fetchAvailability` callback;
|
|
12
|
+
* when omitted, every registered tool is available.
|
|
13
|
+
* - Persistence is opt-in via `storageKey` and is SSR-safe.
|
|
14
|
+
* - Inter-tool messaging happens through a typed pub/sub bus (`emit`/`on`)
|
|
15
|
+
* in lieu of `window.dispatchEvent` patterns from older portals.
|
|
16
|
+
*
|
|
17
|
+
* @example Register a dock and a tool
|
|
18
|
+
* ```ts
|
|
19
|
+
* // somewhere in a +layout.svelte:
|
|
20
|
+
* import { defineToolsDock } from '@happyvertical/smrt-svelte/workspace';
|
|
21
|
+
* import ChatTool from './ChatTool.svelte';
|
|
22
|
+
*
|
|
23
|
+
* const dock = defineToolsDock({
|
|
24
|
+
* tools: [{ id: 'chat', label: 'Chat', component: ChatTool }],
|
|
25
|
+
* storageKey: 'app-name:tools-dock:v1',
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @remarks ModuleUIRegistry integration point
|
|
30
|
+
*
|
|
31
|
+
* Consumer apps that want tools to come from `@happyvertical/smrt-*` module
|
|
32
|
+
* packages (commerce, content, etc.) can populate `options.tools` from the
|
|
33
|
+
* `ModuleUIRegistry` (see {@link ../../../registry/module-registry}) — e.g.
|
|
34
|
+
* by walking `ModuleUIRegistry.getModules()` and pulling components from a
|
|
35
|
+
* conventional slot id like `'tools-dock'`. This is left to consumers so the
|
|
36
|
+
* dock has zero coupling to the registry; the surface area exposed here
|
|
37
|
+
* (`ToolDef[]`) is what such an adapter would produce.
|
|
38
|
+
*/
|
|
39
|
+
import type { AvailableTool, ToolDef, ToolsDockApi, ToolsDockContext } from '../types.js';
|
|
40
|
+
/**
|
|
41
|
+
* Svelte context key for the active ToolsDock API instance.
|
|
42
|
+
*/
|
|
43
|
+
export declare const TOOLS_DOCK_KEY: unique symbol;
|
|
44
|
+
/**
|
|
45
|
+
* Options accepted by {@link defineToolsDock}.
|
|
46
|
+
*
|
|
47
|
+
* `TData` types the shape of `context.data` passed through `setContext()` /
|
|
48
|
+
* `fetchAvailability` — narrow it at the factory site to get a typed
|
|
49
|
+
* `ctx.data` inside the availability callback without manual casts.
|
|
50
|
+
* Defaults to `Record<string, unknown>` so existing callers keep compiling.
|
|
51
|
+
*
|
|
52
|
+
* `TActions` types the shape of `context.actions` and flows the same way.
|
|
53
|
+
* Defaults to `Record<string, (...args: any[]) => unknown>` so the untyped
|
|
54
|
+
* `dock.setContext({ actions: { triggerSave() {} } })` pattern keeps
|
|
55
|
+
* compiling without a generic argument. The constraint is a self-mapped
|
|
56
|
+
* `{ [K in keyof TActions]: (...args: any[]) => any }` so interface-style
|
|
57
|
+
* action maps (without a string index signature) satisfy the bound —
|
|
58
|
+
* see the JSDoc on {@link ToolsDockContext} for rationale.
|
|
59
|
+
*
|
|
60
|
+
* Tools themselves are stored as `ToolDef[]` (the generics are erased at
|
|
61
|
+
* registration). Inside a tool component, type the prop locally — see the
|
|
62
|
+
* JSDoc on {@link ToolDef.component} for the recommended pattern.
|
|
63
|
+
*/
|
|
64
|
+
export interface DefineToolsDockOptions<TData = Record<string, unknown>, TActions extends {
|
|
65
|
+
[K in keyof TActions]: (...args: any[]) => any;
|
|
66
|
+
} = Record<string, (...args: any[]) => unknown>> {
|
|
67
|
+
/** Registered tools. Order is preserved when rendering the activation rail/topbar. */
|
|
68
|
+
tools: ToolDef[];
|
|
69
|
+
/**
|
|
70
|
+
* Optional backend-driven gating callback. Returns the subset of tools that
|
|
71
|
+
* should be exposed for the current `context`. When omitted, every
|
|
72
|
+
* registered tool is treated as available.
|
|
73
|
+
*
|
|
74
|
+
* The callback may return tool ids that aren't present in `tools` — these
|
|
75
|
+
* are ignored. Conversely, tools missing from the callback's response are
|
|
76
|
+
* hidden from the dock UI.
|
|
77
|
+
*
|
|
78
|
+
* The `ctx` parameter is typed against the factory's `TData` / `TActions`
|
|
79
|
+
* generics — narrow them at the factory site for typed access to
|
|
80
|
+
* `ctx.data` / `ctx.actions` here without manual casts.
|
|
81
|
+
*/
|
|
82
|
+
fetchAvailability?: (ctx: ToolsDockContext<TData, TActions> | null) => Promise<AvailableTool[]>;
|
|
83
|
+
/**
|
|
84
|
+
* Optional `localStorage` key. When provided, the dock will persist a small
|
|
85
|
+
* `{ isOpen, activeTool }` blob and hydrate it on mount. Persistence is
|
|
86
|
+
* SSR-safe — no `localStorage` access happens at module scope or during
|
|
87
|
+
* initial render on the server.
|
|
88
|
+
*/
|
|
89
|
+
storageKey?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Activation UI layout. Defaults to `'rail'`.
|
|
92
|
+
*
|
|
93
|
+
* - `'rail'`: vertical icon rail with the panel contained inside the
|
|
94
|
+
* dock's own aside. Safe to compose alongside `<WorkspaceShell>`'s
|
|
95
|
+
* `inspector` snippet — they don't fight for positioning.
|
|
96
|
+
* - `'topbar'`: inline activation buttons with a SEPARATE
|
|
97
|
+
* `position: fixed` panel anchored to the bottom-right of the
|
|
98
|
+
* viewport. **Do not also use `<WorkspaceShell>`'s `inspector`
|
|
99
|
+
* snippet in this mode** — the shell renders its own
|
|
100
|
+
* `position: fixed` inspector with no z-index coordination, and the
|
|
101
|
+
* two panels will visibly overlap. Render `<ToolsDock layout='topbar'>`
|
|
102
|
+
* inside the shell's `topbarActions` snippet and leave the inspector
|
|
103
|
+
* slot unused.
|
|
104
|
+
*/
|
|
105
|
+
layout?: 'rail' | 'topbar';
|
|
106
|
+
/** Initial open state. Hydration from storage takes precedence. Defaults to `false`. */
|
|
107
|
+
initialOpen?: boolean;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Internal extension of {@link ToolsDockApi} with framework-only members:
|
|
111
|
+
* the registered tools, the configured layout, and the persistence key.
|
|
112
|
+
*
|
|
113
|
+
* Mirrors the same `<TData, TActions>` generics as {@link ToolsDockApi} so
|
|
114
|
+
* the narrowed `context` / `setContext()` signatures from
|
|
115
|
+
* `defineToolsDock<TData, TActions>(...)` flow through to consumers that
|
|
116
|
+
* hold the returned instance directly. Defaults preserve back-compat for
|
|
117
|
+
* untyped callers (`defineToolsDock({...})`).
|
|
118
|
+
*/
|
|
119
|
+
export interface ToolsDockInstance<TData = Record<string, unknown>, TActions extends {
|
|
120
|
+
[K in keyof TActions]: (...args: any[]) => any;
|
|
121
|
+
} = Record<string, (...args: any[]) => unknown>> extends ToolsDockApi<TData, TActions> {
|
|
122
|
+
readonly tools: ReadonlyArray<ToolDef>;
|
|
123
|
+
readonly layout: 'rail' | 'topbar';
|
|
124
|
+
readonly storageKey: string | null;
|
|
125
|
+
/** Internal: hydrate persisted state from `localStorage` (called by `<ToolsDock>` on mount). */
|
|
126
|
+
hydrate(): void;
|
|
127
|
+
/** Internal: persist current state to `localStorage`. */
|
|
128
|
+
persist(): void;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a tools-dock instance and register it on Svelte context.
|
|
132
|
+
*
|
|
133
|
+
* Must be called inside a Svelte component initialization scope (`<script>`
|
|
134
|
+
* top level, `+layout.svelte`, etc.) — `setContext` requires it.
|
|
135
|
+
*
|
|
136
|
+
* @param options factory options
|
|
137
|
+
* @returns the {@link ToolsDockInstance} (a {@link ToolsDockApi} plus
|
|
138
|
+
* framework metadata `<ToolsDock>` consumes when rendering)
|
|
139
|
+
*/
|
|
140
|
+
export declare function defineToolsDock<TData = Record<string, unknown>, TActions extends {
|
|
141
|
+
[K in keyof TActions]: (...args: any[]) => any;
|
|
142
|
+
} = Record<string, (...args: any[]) => unknown>>(options: DefineToolsDockOptions<TData, TActions>): ToolsDockInstance<TData, TActions>;
|
|
143
|
+
//# sourceMappingURL=define-tools-dock.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-tools-dock.svelte.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/tools-dock/define-tools-dock.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,OAAO,EACP,YAAY,EACZ,gBAAgB,EAEjB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,eAAO,MAAM,cAAc,eAA4B,CAAC;AAExD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,sBAAsB,CACrC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,SAAS;KAAG,CAAC,IAAI,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;CAAE,GAAG,MAAM,CAC1E,MAAM,EACN,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAC5B;IAED,sFAAsF;IACtF,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,CAClB,GAAG,EAAE,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAI,KAC1C,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,wFAAwF;IACxF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,SAAS;KAAG,CAAC,IAAI,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;CAAE,GAAG,MAAM,CAC1E,MAAM,EACN,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAC5B,CACD,SAAQ,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,gGAAgG;IAChG,OAAO,IAAI,IAAI,CAAC;IAChB,yDAAyD;IACzD,OAAO,IAAI,IAAI,CAAC;CACjB;AAiDD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,SAAS;KAAG,CAAC,IAAI,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;CAAE,GAAG,MAAM,CAC1E,MAAM,EACN,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAC5B,EAED,OAAO,EAAE,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAC/C,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAyZpC"}
|
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* defineToolsDock - factory for the ToolsDock API
|
|
3
|
+
*
|
|
4
|
+
* Creates a reactive {@link ToolsDockApi} instance backed by Svelte 5 runes
|
|
5
|
+
* (`$state`) and registers it in Svelte context under {@link TOOLS_DOCK_KEY}.
|
|
6
|
+
* Inside a `<ToolsDock>` provider tree, descendants (tools, deep panels,
|
|
7
|
+
* arbitrary consumers) read the same instance via {@link useToolsDock}.
|
|
8
|
+
*
|
|
9
|
+
* The dock is intentionally domain-agnostic:
|
|
10
|
+
* - Tool IDs are arbitrary strings (no enum).
|
|
11
|
+
* - Availability is controlled via the optional `fetchAvailability` callback;
|
|
12
|
+
* when omitted, every registered tool is available.
|
|
13
|
+
* - Persistence is opt-in via `storageKey` and is SSR-safe.
|
|
14
|
+
* - Inter-tool messaging happens through a typed pub/sub bus (`emit`/`on`)
|
|
15
|
+
* in lieu of `window.dispatchEvent` patterns from older portals.
|
|
16
|
+
*
|
|
17
|
+
* @example Register a dock and a tool
|
|
18
|
+
* ```ts
|
|
19
|
+
* // somewhere in a +layout.svelte:
|
|
20
|
+
* import { defineToolsDock } from '@happyvertical/smrt-svelte/workspace';
|
|
21
|
+
* import ChatTool from './ChatTool.svelte';
|
|
22
|
+
*
|
|
23
|
+
* const dock = defineToolsDock({
|
|
24
|
+
* tools: [{ id: 'chat', label: 'Chat', component: ChatTool }],
|
|
25
|
+
* storageKey: 'app-name:tools-dock:v1',
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @remarks ModuleUIRegistry integration point
|
|
30
|
+
*
|
|
31
|
+
* Consumer apps that want tools to come from `@happyvertical/smrt-*` module
|
|
32
|
+
* packages (commerce, content, etc.) can populate `options.tools` from the
|
|
33
|
+
* `ModuleUIRegistry` (see {@link ../../../registry/module-registry}) — e.g.
|
|
34
|
+
* by walking `ModuleUIRegistry.getModules()` and pulling components from a
|
|
35
|
+
* conventional slot id like `'tools-dock'`. This is left to consumers so the
|
|
36
|
+
* dock has zero coupling to the registry; the surface area exposed here
|
|
37
|
+
* (`ToolDef[]`) is what such an adapter would produce.
|
|
38
|
+
*/
|
|
39
|
+
import { setContext, untrack } from 'svelte';
|
|
40
|
+
/**
|
|
41
|
+
* Svelte context key for the active ToolsDock API instance.
|
|
42
|
+
*/
|
|
43
|
+
export const TOOLS_DOCK_KEY = Symbol('smrt-tools-dock');
|
|
44
|
+
// Availability fetches are token-gated for race-safety (stale results are
|
|
45
|
+
// dropped — see `refreshAvailability`). We deliberately do NOT debounce by
|
|
46
|
+
// default because:
|
|
47
|
+
// - `setContext` is typically called from `$effect` on route changes, not
|
|
48
|
+
// in a tight loop
|
|
49
|
+
// - debouncing complicates testing without buying meaningful protection
|
|
50
|
+
// given the token-based stale-result drop
|
|
51
|
+
// Consumers that need debounce can wrap their own setContext call.
|
|
52
|
+
function isBrowser() {
|
|
53
|
+
return typeof window !== 'undefined';
|
|
54
|
+
}
|
|
55
|
+
function safeReadStorage(key) {
|
|
56
|
+
if (!isBrowser())
|
|
57
|
+
return null;
|
|
58
|
+
try {
|
|
59
|
+
const raw = window.localStorage.getItem(key);
|
|
60
|
+
if (!raw)
|
|
61
|
+
return null;
|
|
62
|
+
const parsed = JSON.parse(raw);
|
|
63
|
+
if (!parsed || typeof parsed !== 'object')
|
|
64
|
+
return null;
|
|
65
|
+
const { isOpen, activeTool } = parsed;
|
|
66
|
+
return {
|
|
67
|
+
isOpen: typeof isOpen === 'boolean' ? isOpen : undefined,
|
|
68
|
+
activeTool: typeof activeTool === 'string' || activeTool === null
|
|
69
|
+
? activeTool
|
|
70
|
+
: undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function safeWriteStorage(key, payload) {
|
|
78
|
+
if (!isBrowser())
|
|
79
|
+
return;
|
|
80
|
+
try {
|
|
81
|
+
window.localStorage.setItem(key, JSON.stringify(payload));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Quota errors, private browsing, etc. — silently drop.
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a tools-dock instance and register it on Svelte context.
|
|
89
|
+
*
|
|
90
|
+
* Must be called inside a Svelte component initialization scope (`<script>`
|
|
91
|
+
* top level, `+layout.svelte`, etc.) — `setContext` requires it.
|
|
92
|
+
*
|
|
93
|
+
* @param options factory options
|
|
94
|
+
* @returns the {@link ToolsDockInstance} (a {@link ToolsDockApi} plus
|
|
95
|
+
* framework metadata `<ToolsDock>` consumes when rendering)
|
|
96
|
+
*/
|
|
97
|
+
export function defineToolsDock(options) {
|
|
98
|
+
const layout = options.layout ?? 'rail';
|
|
99
|
+
const storageKey = options.storageKey ?? null;
|
|
100
|
+
const fetchAvailability = options.fetchAvailability;
|
|
101
|
+
const registeredTools = options.tools.slice();
|
|
102
|
+
const registeredIds = new Set(registeredTools.map((t) => t.id));
|
|
103
|
+
// Reactive state
|
|
104
|
+
let isOpen = $state(Boolean(options.initialOpen));
|
|
105
|
+
let activeTool = $state(null);
|
|
106
|
+
let context = $state(null);
|
|
107
|
+
// Shadow of the last raw context reference passed to `setContextValue`.
|
|
108
|
+
// Used for strict-equality short-circuiting: Svelte 5 wraps stored object
|
|
109
|
+
// `$state` values in a Proxy, so `ctx === context` would never match the
|
|
110
|
+
// original input. Comparing against this shadow gives us proxy-free
|
|
111
|
+
// reference equality and avoids the `state_proxy_equality_mismatch`
|
|
112
|
+
// warning.
|
|
113
|
+
let rawContextRef = null;
|
|
114
|
+
let availableTools = $state(registeredTools.map((t) => ({ id: t.id, label: t.label, badge: t.badge })));
|
|
115
|
+
// Race-handle: each fetchAvailability call gets a token; only the most
|
|
116
|
+
// recent token may apply its result.
|
|
117
|
+
let availabilityToken = 0;
|
|
118
|
+
/**
|
|
119
|
+
* Set to `true` once the factory has finished wiring the instance. Used
|
|
120
|
+
* to gate `'dock:change'` emits so handlers can't run before the instance
|
|
121
|
+
* exists / is registered on context. Mutations issued from inside the
|
|
122
|
+
* factory body (e.g. `applyAvailability` running during initial
|
|
123
|
+
* availability snapshot) are silent.
|
|
124
|
+
*/
|
|
125
|
+
let ready = false;
|
|
126
|
+
// Pub/sub bus
|
|
127
|
+
const listeners = new Map();
|
|
128
|
+
function emit(event, payload) {
|
|
129
|
+
const set = listeners.get(event);
|
|
130
|
+
if (!set || set.size === 0)
|
|
131
|
+
return;
|
|
132
|
+
// Copy so handlers that unsubscribe themselves don't mutate during iteration.
|
|
133
|
+
for (const handler of Array.from(set)) {
|
|
134
|
+
try {
|
|
135
|
+
handler(payload);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
// Don't let one handler kill the rest.
|
|
139
|
+
if (isBrowser())
|
|
140
|
+
console.error('[ToolsDock] handler error', err);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function on(event, handler) {
|
|
145
|
+
let set = listeners.get(event);
|
|
146
|
+
if (!set) {
|
|
147
|
+
set = new Set();
|
|
148
|
+
listeners.set(event, set);
|
|
149
|
+
}
|
|
150
|
+
set.add(handler);
|
|
151
|
+
return () => {
|
|
152
|
+
const current = listeners.get(event);
|
|
153
|
+
if (!current)
|
|
154
|
+
return;
|
|
155
|
+
current.delete(handler);
|
|
156
|
+
if (current.size === 0)
|
|
157
|
+
listeners.delete(event);
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Emit the appropriate dock-owned change events. Guarded by the `ready`
|
|
162
|
+
* flag so handlers can't run during factory construction (before the
|
|
163
|
+
* instance is fully wired / registered on Svelte context). Always reads
|
|
164
|
+
* the latest `$state` values so handlers see the post-update state,
|
|
165
|
+
* regardless of how many updates happened in a single call.
|
|
166
|
+
*
|
|
167
|
+
* The `$state` reads are wrapped in `untrack` so that when this is
|
|
168
|
+
* invoked from inside a Svelte `$effect` (e.g. `<ToolsDock>`'s effect
|
|
169
|
+
* forwarding the `context` prop into `dock.setContext`), the reads do
|
|
170
|
+
* NOT become dependencies of that effect. Without this guard, a
|
|
171
|
+
* subsequent `open()` / `close()` would re-run the calling effect,
|
|
172
|
+
* which would call `setContext` again, triggering another availability
|
|
173
|
+
* fetch and another emit — an infinite-ish feedback loop.
|
|
174
|
+
*
|
|
175
|
+
* Three events fan out from a single call, each gated by what actually
|
|
176
|
+
* changed:
|
|
177
|
+
* - `'dock:state-changed'` — fired when `stateChanged` is true (open /
|
|
178
|
+
* close / toggle / availability cleared the active tool)
|
|
179
|
+
* - `'dock:context-changed'` — fired when `contextChanged` is true
|
|
180
|
+
* (`setContext` saw a different reference)
|
|
181
|
+
* - `'dock:change'` — legacy event, fired whenever this is called.
|
|
182
|
+
* Stays for back-compat; consumers should prefer the granular pair.
|
|
183
|
+
*
|
|
184
|
+
* Callers that only see a badge/label refresh (no state or context
|
|
185
|
+
* change) still funnel through here so the legacy `'dock:change'`
|
|
186
|
+
* subscribers see badge updates — but `stateChanged` / `contextChanged`
|
|
187
|
+
* both stay `false`, keeping the granular events silent.
|
|
188
|
+
*/
|
|
189
|
+
function emitChange(opts) {
|
|
190
|
+
if (!ready)
|
|
191
|
+
return;
|
|
192
|
+
const snapshot = untrack(() => ({
|
|
193
|
+
isOpen,
|
|
194
|
+
activeTool,
|
|
195
|
+
context,
|
|
196
|
+
}));
|
|
197
|
+
if (opts.stateChanged) {
|
|
198
|
+
emit('dock:state-changed', {
|
|
199
|
+
isOpen: snapshot.isOpen,
|
|
200
|
+
activeTool: snapshot.activeTool,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
if (opts.contextChanged) {
|
|
204
|
+
emit('dock:context-changed', {
|
|
205
|
+
context: snapshot.context,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
emit('dock:change', snapshot);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Discriminating comparison of two availability snapshots. Returns true
|
|
212
|
+
* when the new snapshot differs from the previous one in any user-visible
|
|
213
|
+
* way (id ordering, badge value, or label). Used by `applyAvailability`
|
|
214
|
+
* to decide whether to fire a `'dock:change'` event: refreshes that
|
|
215
|
+
* resolve to byte-identical availability (the common no-op case when a
|
|
216
|
+
* side-channel signal fires but underlying data didn't change) stay
|
|
217
|
+
* silent, avoiding spurious work in consumer-side `'dock:change'`
|
|
218
|
+
* mirrors.
|
|
219
|
+
*
|
|
220
|
+
* Both inputs come from `registeredTools.filter(...).map(...)` in the
|
|
221
|
+
* same registration order, so a positional comparison is sufficient.
|
|
222
|
+
*/
|
|
223
|
+
function availabilityActuallyChanged(prev, next) {
|
|
224
|
+
if (prev.length !== next.length)
|
|
225
|
+
return true;
|
|
226
|
+
for (let i = 0; i < prev.length; i++) {
|
|
227
|
+
const a = prev[i];
|
|
228
|
+
const b = next[i];
|
|
229
|
+
if (a.id !== b.id)
|
|
230
|
+
return true;
|
|
231
|
+
if ((a.badge ?? null) !== (b.badge ?? null))
|
|
232
|
+
return true;
|
|
233
|
+
if ((a.label ?? '') !== (b.label ?? ''))
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
function applyAvailability(next) {
|
|
239
|
+
// Filter to registered tools, preserve registration order, merge labels/badges.
|
|
240
|
+
const byId = new Map(next.map((t) => [t.id, t]));
|
|
241
|
+
const prev = availableTools;
|
|
242
|
+
availableTools = registeredTools
|
|
243
|
+
.filter((t) => byId.has(t.id))
|
|
244
|
+
.map((t) => {
|
|
245
|
+
const reported = byId.get(t.id);
|
|
246
|
+
// Distinguish "key absent" (fall back to registered default) from
|
|
247
|
+
// "key present with null" (explicitly clear the badge).
|
|
248
|
+
const reportedBadge = reported && 'badge' in reported ? reported.badge : undefined;
|
|
249
|
+
return {
|
|
250
|
+
id: t.id,
|
|
251
|
+
label: reported?.label ?? t.label,
|
|
252
|
+
badge: reportedBadge !== undefined ? reportedBadge : (t.badge ?? null),
|
|
253
|
+
};
|
|
254
|
+
});
|
|
255
|
+
let stateChanged = false;
|
|
256
|
+
let anyChange = false;
|
|
257
|
+
// If the active tool is no longer available, clear it. Auto-close policy:
|
|
258
|
+
//
|
|
259
|
+
// - If the available set is now empty, close the dock too (nothing left
|
|
260
|
+
// to show — leaving `isOpen: true, activeTool: null` would render a
|
|
261
|
+
// floating empty panel in the topbar layout).
|
|
262
|
+
// - If other tools remain, the dock stays open with `activeTool: null`.
|
|
263
|
+
// Consumers see the cleared state via `'dock:state-changed'` and can
|
|
264
|
+
// decide what to do (auto-pick the first remaining tool via
|
|
265
|
+
// `dock.open(availableTools[0].id)`, or surface a "select a tool"
|
|
266
|
+
// hint). The primitive stays policy-free — there's no universally
|
|
267
|
+
// correct auto-selection (the previously-active tool's adjacency to
|
|
268
|
+
// any specific replacement is consumer-specific).
|
|
269
|
+
if (activeTool && !availableTools.some((t) => t.id === activeTool)) {
|
|
270
|
+
activeTool = null;
|
|
271
|
+
if (isOpen && availableTools.length === 0) {
|
|
272
|
+
isOpen = false;
|
|
273
|
+
}
|
|
274
|
+
// Persist the cleared state so the factory's persistence guarantees
|
|
275
|
+
// don't depend on the <ToolsDock> component being mounted to rescue
|
|
276
|
+
// them via its $effect.
|
|
277
|
+
persist();
|
|
278
|
+
stateChanged = true;
|
|
279
|
+
anyChange = true;
|
|
280
|
+
}
|
|
281
|
+
// Even when the active tool stayed put, the availability set may have
|
|
282
|
+
// shifted in ways consumers care about (badge counts, label overrides,
|
|
283
|
+
// tools appearing/disappearing). Emit so consumers mirroring
|
|
284
|
+
// `availableTools` into their own state (badges in topbars, etc.) see
|
|
285
|
+
// the update without polling.
|
|
286
|
+
if (!anyChange) {
|
|
287
|
+
anyChange = availabilityActuallyChanged(prev, availableTools);
|
|
288
|
+
}
|
|
289
|
+
if (anyChange) {
|
|
290
|
+
// Pure badge/label refresh (no `stateChanged`, no context change)
|
|
291
|
+
// still fires the legacy `'dock:change'` event for back-compat with
|
|
292
|
+
// consumers mirroring `availableTools` — but stays silent on the
|
|
293
|
+
// granular pair, which is the point of the U2 split.
|
|
294
|
+
emitChange({ stateChanged, contextChanged: false });
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function refreshAvailability() {
|
|
298
|
+
if (!fetchAvailability) {
|
|
299
|
+
// Static availability — every registered tool.
|
|
300
|
+
applyAvailability(registeredTools.map((t) => ({
|
|
301
|
+
id: t.id,
|
|
302
|
+
label: t.label,
|
|
303
|
+
badge: t.badge,
|
|
304
|
+
})));
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const token = ++availabilityToken;
|
|
308
|
+
// Internally we store `context` as the default-generic shape; the
|
|
309
|
+
// factory's `TData` / `TActions` only constrain the public callback
|
|
310
|
+
// signature. Cast at the call boundary to thread the consumer's narrowed
|
|
311
|
+
// type through without polluting the runtime store with the generic.
|
|
312
|
+
const snapshotCtx = context;
|
|
313
|
+
// Funnel both synchronous throws (argument validation, undefined
|
|
314
|
+
// dereferences before the promise is returned) and asynchronous
|
|
315
|
+
// rejections through the same error path so neither escapes
|
|
316
|
+
// `setContext` to the component.
|
|
317
|
+
let pending;
|
|
318
|
+
try {
|
|
319
|
+
pending = Promise.resolve(fetchAvailability(snapshotCtx));
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
pending = Promise.reject(err);
|
|
323
|
+
}
|
|
324
|
+
void pending
|
|
325
|
+
.then((result) => {
|
|
326
|
+
if (token !== availabilityToken)
|
|
327
|
+
return; // stale
|
|
328
|
+
applyAvailability(Array.isArray(result) ? result : []);
|
|
329
|
+
})
|
|
330
|
+
.catch(() => {
|
|
331
|
+
if (token !== availabilityToken)
|
|
332
|
+
return;
|
|
333
|
+
// On error, surface zero availability rather than stale state.
|
|
334
|
+
applyAvailability([]);
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
function persist() {
|
|
338
|
+
if (!storageKey)
|
|
339
|
+
return;
|
|
340
|
+
safeWriteStorage(storageKey, { isOpen, activeTool });
|
|
341
|
+
}
|
|
342
|
+
function hydrate() {
|
|
343
|
+
if (!storageKey)
|
|
344
|
+
return;
|
|
345
|
+
const persisted = safeReadStorage(storageKey);
|
|
346
|
+
if (!persisted)
|
|
347
|
+
return;
|
|
348
|
+
if (typeof persisted.isOpen === 'boolean') {
|
|
349
|
+
isOpen = persisted.isOpen;
|
|
350
|
+
}
|
|
351
|
+
if (typeof persisted.activeTool === 'string' &&
|
|
352
|
+
registeredIds.has(persisted.activeTool)) {
|
|
353
|
+
activeTool = persisted.activeTool;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function open(id) {
|
|
357
|
+
const prevIsOpen = isOpen;
|
|
358
|
+
const prevActive = activeTool;
|
|
359
|
+
if (id) {
|
|
360
|
+
if (!availableTools.some((t) => t.id === id))
|
|
361
|
+
return; // unavailable — no-op
|
|
362
|
+
activeTool = id;
|
|
363
|
+
}
|
|
364
|
+
else if (!activeTool && availableTools.length > 0) {
|
|
365
|
+
activeTool = availableTools[0].id;
|
|
366
|
+
}
|
|
367
|
+
isOpen = true;
|
|
368
|
+
persist();
|
|
369
|
+
// Skip emit when nothing observable changed — avoids spurious
|
|
370
|
+
// 'dock:change' events when consumers idempotently call open() on the
|
|
371
|
+
// already-active tool.
|
|
372
|
+
if (isOpen !== prevIsOpen || activeTool !== prevActive) {
|
|
373
|
+
emitChange({ stateChanged: true, contextChanged: false });
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function close() {
|
|
377
|
+
if (!isOpen) {
|
|
378
|
+
// Already closed — persist (cheap, no-op when nothing changed) but
|
|
379
|
+
// skip emit so consumers don't see spurious 'dock:change' events.
|
|
380
|
+
persist();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
isOpen = false;
|
|
384
|
+
persist();
|
|
385
|
+
emitChange({ stateChanged: true, contextChanged: false });
|
|
386
|
+
}
|
|
387
|
+
function toggle(id) {
|
|
388
|
+
const prevIsOpen = isOpen;
|
|
389
|
+
const prevActive = activeTool;
|
|
390
|
+
if (id) {
|
|
391
|
+
if (!availableTools.some((t) => t.id === id))
|
|
392
|
+
return;
|
|
393
|
+
if (isOpen && activeTool === id) {
|
|
394
|
+
isOpen = false;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
activeTool = id;
|
|
398
|
+
isOpen = true;
|
|
399
|
+
}
|
|
400
|
+
persist();
|
|
401
|
+
if (isOpen !== prevIsOpen || activeTool !== prevActive) {
|
|
402
|
+
emitChange({ stateChanged: true, contextChanged: false });
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
isOpen = !isOpen;
|
|
407
|
+
if (isOpen && !activeTool && availableTools.length > 0) {
|
|
408
|
+
activeTool = availableTools[0].id;
|
|
409
|
+
}
|
|
410
|
+
persist();
|
|
411
|
+
if (isOpen !== prevIsOpen || activeTool !== prevActive) {
|
|
412
|
+
emitChange({ stateChanged: true, contextChanged: false });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
function setContextValue(ctx) {
|
|
416
|
+
// Strict-equality short-circuit: passing the same context reference is a
|
|
417
|
+
// no-op. Skips both the availability refresh and the `'dock:change'`
|
|
418
|
+
// emit so consumers (e.g. `<ToolsDock>`'s context-forwarding `$effect`)
|
|
419
|
+
// can call this repeatedly without amplifying side effects. Consumers
|
|
420
|
+
// who want a "force refresh" can pass a fresh object or `null` first.
|
|
421
|
+
//
|
|
422
|
+
// Compare against `rawContextRef` (a non-reactive shadow) rather than the
|
|
423
|
+
// `$state` value, because Svelte 5 wraps object `$state` in a Proxy and
|
|
424
|
+
// the original input would never `===` the proxied stored value.
|
|
425
|
+
//
|
|
426
|
+
// Internally the `context` `$state` is typed as the default
|
|
427
|
+
// `ToolsDockContext` so the runtime store stays generic-erased — the
|
|
428
|
+
// narrowed type only lives on the public boundary (this function
|
|
429
|
+
// signature and the `instance.context` getter).
|
|
430
|
+
const erased = ctx;
|
|
431
|
+
if (erased === rawContextRef)
|
|
432
|
+
return;
|
|
433
|
+
rawContextRef = erased;
|
|
434
|
+
context = erased;
|
|
435
|
+
if (fetchAvailability)
|
|
436
|
+
refreshAvailability();
|
|
437
|
+
// Emit AFTER kicking off availability refresh. The refresh is async and
|
|
438
|
+
// may emit a second event later if it clears `activeTool` — that is
|
|
439
|
+
// the intended behaviour (one event per observable state transition).
|
|
440
|
+
// `contextChanged: true` fires `'dock:context-changed'`; `stateChanged`
|
|
441
|
+
// stays false here because `setContext` itself doesn't touch isOpen/
|
|
442
|
+
// activeTool (the async availability refresh handles that).
|
|
443
|
+
emitChange({ stateChanged: false, contextChanged: true });
|
|
444
|
+
}
|
|
445
|
+
const instance = {
|
|
446
|
+
// Reactive getters — keep the api surface read-only.
|
|
447
|
+
get isOpen() {
|
|
448
|
+
return isOpen;
|
|
449
|
+
},
|
|
450
|
+
get activeTool() {
|
|
451
|
+
return activeTool;
|
|
452
|
+
},
|
|
453
|
+
get availableTools() {
|
|
454
|
+
return availableTools;
|
|
455
|
+
},
|
|
456
|
+
// Internal `context` `$state` is typed as the default-generic shape so
|
|
457
|
+
// the runtime store stays homogeneous. Cast at the public boundary —
|
|
458
|
+
// structurally a `ToolsDockContext<TData, TActions>` IS a
|
|
459
|
+
// `ToolsDockContext<defaults>` (the generics flow covariantly through
|
|
460
|
+
// the field shapes); the cast threads the consumer's narrowed type
|
|
461
|
+
// through to the API surface without forcing the internal store to
|
|
462
|
+
// carry the generic.
|
|
463
|
+
get context() {
|
|
464
|
+
return context;
|
|
465
|
+
},
|
|
466
|
+
open,
|
|
467
|
+
close,
|
|
468
|
+
toggle,
|
|
469
|
+
setContext: setContextValue,
|
|
470
|
+
refreshAvailability,
|
|
471
|
+
emit,
|
|
472
|
+
on,
|
|
473
|
+
// Framework-only members:
|
|
474
|
+
tools: registeredTools,
|
|
475
|
+
layout,
|
|
476
|
+
storageKey,
|
|
477
|
+
hydrate,
|
|
478
|
+
persist,
|
|
479
|
+
};
|
|
480
|
+
setContext(TOOLS_DOCK_KEY, instance);
|
|
481
|
+
// From this point forward, mutations may emit `'dock:change'`. Anything
|
|
482
|
+
// that ran during the factory body above (e.g. seeding `availableTools`
|
|
483
|
+
// from the registered tools) is treated as part of initialization and
|
|
484
|
+
// stays silent.
|
|
485
|
+
ready = true;
|
|
486
|
+
return instance;
|
|
487
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useToolsDock - read the {@link ToolsDockApi} from Svelte context.
|
|
3
|
+
*
|
|
4
|
+
* Tools and arbitrary descendants of `<ToolsDock>` use this to obtain the
|
|
5
|
+
* dock instance that owns them — open/close themselves, push events through
|
|
6
|
+
* the typed bus, react to the current `context`, etc.
|
|
7
|
+
*
|
|
8
|
+
* Throws a clear error if called outside a `<ToolsDock>` provider tree so
|
|
9
|
+
* misuse fails loudly during development rather than producing silent nulls.
|
|
10
|
+
*
|
|
11
|
+
* The returned `dock.context` is the default {@link ToolsDockContext} shape.
|
|
12
|
+
* For typed access from within a tool body, the recommended pattern is to
|
|
13
|
+
* type the component's own `context` prop locally — see the JSDoc on
|
|
14
|
+
* {@link ToolDef.component} for an example. (`ToolDef` deliberately erases
|
|
15
|
+
* its context generic at registration time so the dock can store tools as
|
|
16
|
+
* a single homogeneous `ToolDef[]`.)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```svelte
|
|
20
|
+
* <script lang="ts">
|
|
21
|
+
* import { useToolsDock } from '@happyvertical/smrt-svelte/workspace';
|
|
22
|
+
* const dock = useToolsDock();
|
|
23
|
+
* </script>
|
|
24
|
+
*
|
|
25
|
+
* <button type="button" onclick={() => dock.close()}>Close</button>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
import type { ToolsDockApi } from '../types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Retrieve the {@link ToolsDockApi} from Svelte context.
|
|
31
|
+
*
|
|
32
|
+
* @throws Error when called outside a `<ToolsDock>` provider tree
|
|
33
|
+
*/
|
|
34
|
+
export declare function useToolsDock(): ToolsDockApi;
|
|
35
|
+
/**
|
|
36
|
+
* Non-throwing variant — returns `null` outside a provider. Useful for
|
|
37
|
+
* optional integrations where a tool should degrade gracefully if not
|
|
38
|
+
* embedded inside a `<ToolsDock>`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function tryUseToolsDock(): ToolsDockApi | null;
|
|
41
|
+
//# sourceMappingURL=use-tools-dock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-tools-dock.d.ts","sourceRoot":"","sources":["../../../../src/components/workspace/tools-dock/use-tools-dock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,YAAY,CAS3C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD"}
|