@kitn.ai/ui 0.28.0 → 0.29.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/README.md +1 -1
- package/dist/agent-tooling/construct/public.d.ts +15 -0
- package/dist/agent-tooling/construct/schema.d.ts +111 -0
- package/dist/construct-cli.es.js +3 -3
- package/dist/construct.d.ts +5 -0
- package/dist/construct.js +327 -0
- package/dist/core-C8fzo39E.js +1 -12
- package/dist/engine-javascript-C1x7zo1_.js +1 -141
- package/dist/mcp.es.js +1 -1
- package/package.json +16 -16
- package/bin/route.test.js +0 -58
- package/src/agent-tooling/README.md +0 -192
- package/src/agent-tooling/archetypes.ts +0 -205
- package/src/agent-tooling/catalog/README.md +0 -676
- package/src/agent-tooling/catalog/catalog-types.ts +0 -231
- package/src/agent-tooling/catalog/fabrications.ts +0 -96
- package/src/agent-tooling/catalog/invariants.ts +0 -284
- package/src/agent-tooling/catalog/labs-titles.ts +0 -114
- package/src/agent-tooling/catalog/scenarios.ts +0 -87
- package/src/agent-tooling/catalog/surfaces.ts +0 -347
- package/src/agent-tooling/construct/cli-entry.ts +0 -8
- package/src/agent-tooling/construct/cli.ts +0 -147
- package/src/agent-tooling/construct/codegen.ts +0 -1635
- package/src/agent-tooling/construct/construct.v1.schema.json +0 -319
- package/src/agent-tooling/construct/dev.ts +0 -148
- package/src/agent-tooling/construct/fixtures/demo-widget.construct.json +0 -7
- package/src/agent-tooling/construct/fixtures/ops-console.construct.json +0 -44
- package/src/agent-tooling/construct/fixtures/owner-widget.construct.json +0 -32
- package/src/agent-tooling/construct/schema.ts +0 -452
- package/src/agent-tooling/integrations/anthropic.ts +0 -442
- package/src/agent-tooling/integrations/cloudflare.ts +0 -218
- package/src/agent-tooling/integrations/langgraph.ts +0 -133
- package/src/agent-tooling/integrations/mastra.ts +0 -182
- package/src/agent-tooling/integrations/mock.ts +0 -148
- package/src/agent-tooling/integrations/ollama.ts +0 -97
- package/src/agent-tooling/integrations/openai.ts +0 -95
- package/src/agent-tooling/integrations/openrouter.ts +0 -82
- package/src/agent-tooling/integrations/pi.ts +0 -176
- package/src/agent-tooling/integrations/pydantic-ai.ts +0 -108
- package/src/agent-tooling/integrations/vercel-ai-sdk.ts +0 -398
- package/src/agent-tooling/mcp/css-raw.d.ts +0 -12
- package/src/agent-tooling/mcp/manifest.ts +0 -422
- package/src/agent-tooling/mcp/server.ts +0 -116
- package/src/agent-tooling/mcp/stdio.ts +0 -18
- package/src/agent-tooling/mcp/tools/construct.ts +0 -130
- package/src/agent-tooling/mcp/tools/debug.ts +0 -621
- package/src/agent-tooling/mcp/tools/reference.ts +0 -980
- package/src/agent-tooling/mcp/tools/scaffold.ts +0 -6708
- package/src/agent-tooling/mcp/tools/theme.ts +0 -456
- package/src/agent-tooling/mcp/tools/types.ts +0 -14
- package/src/agent-tooling/mcp/validate-args.ts +0 -141
- package/src/agent-tooling/recipes/composed-thread.ts +0 -714
- package/src/agent-tooling/recipes/index.ts +0 -22
- package/src/agent-tooling/recipes/types.ts +0 -32
- package/src/agent-tooling/registry.ts +0 -132
- package/src/agent-tooling/route-emit.ts +0 -305
- package/src/agent-tooling/types.ts +0 -390
- package/src/components/artifact-card.tsx +0 -120
- package/src/components/artifact.tsx +0 -914
- package/src/components/attachment-types.ts +0 -66
- package/src/components/attachments.tsx +0 -536
- package/src/components/audio-visualizer/audio-visualizer.voice-fixture.ts +0 -257
- package/src/components/audio-visualizer/aurora.glsl.ts +0 -330
- package/src/components/audio-visualizer/fit-scale.ts +0 -112
- package/src/components/audio-visualizer/index.tsx +0 -528
- package/src/components/audio-visualizer/labs/lab-choreography.ts +0 -187
- package/src/components/audio-visualizer/labs/lab-shaders.ts +0 -363
- package/src/components/audio-visualizer/labs/lab-visualizer.tsx +0 -102
- package/src/components/audio-visualizer/shader-canvas.tsx +0 -876
- package/src/components/audio-visualizer/sizes.ts +0 -54
- package/src/components/audio-visualizer/variant-aurora.tsx +0 -305
- package/src/components/audio-visualizer/variant-bar.tsx +0 -175
- package/src/components/audio-visualizer/variant-custom.tsx +0 -344
- package/src/components/audio-visualizer/variant-grid.tsx +0 -175
- package/src/components/audio-visualizer/variant-radial.tsx +0 -163
- package/src/components/audio-visualizer/variant-wave.tsx +0 -130
- package/src/components/audio-visualizer/wave.glsl.ts +0 -130
- package/src/components/card-fallback.tsx +0 -60
- package/src/components/card-renderer.tsx +0 -220
- package/src/components/card.tsx +0 -212
- package/src/components/chain-of-thought.tsx +0 -348
- package/src/components/chat-container.tsx +0 -89
- package/src/components/chat-scope-picker.tsx +0 -57
- package/src/components/chat-thread.tsx +0 -1014
- package/src/components/checkpoint.tsx +0 -88
- package/src/components/choice-card.tsx +0 -743
- package/src/components/coachmark.tsx +0 -249
- package/src/components/code-block.tsx +0 -181
- package/src/components/composer-dom.ts +0 -159
- package/src/components/composer-highlight.ts +0 -242
- package/src/components/composer-history.ts +0 -82
- package/src/components/composer.tsx +0 -1075
- package/src/components/confirm-card.tsx +0 -402
- package/src/components/context.tsx +0 -377
- package/src/components/conversation-item.tsx +0 -241
- package/src/components/conversation-list.tsx +0 -429
- package/src/components/conversation-panel.tsx +0 -118
- package/src/components/dismissed-stub.tsx +0 -80
- package/src/components/embed.tsx +0 -200
- package/src/components/empty.tsx +0 -177
- package/src/components/feedback-bar.tsx +0 -166
- package/src/components/file-tree.tsx +0 -530
- package/src/components/file-upload.tsx +0 -167
- package/src/components/form-widgets.tsx +0 -525
- package/src/components/form.tsx +0 -1296
- package/src/components/home-panel.tsx +0 -159
- package/src/components/image.tsx +0 -65
- package/src/components/link-preview.tsx +0 -195
- package/src/components/loader.tsx +0 -367
- package/src/components/markdown.tsx +0 -162
- package/src/components/message-skills.tsx +0 -40
- package/src/components/message.tsx +0 -765
- package/src/components/model-switcher.tsx +0 -132
- package/src/components/prompt-input.tsx +0 -188
- package/src/components/prompt-suggestion.tsx +0 -150
- package/src/components/reasoning.tsx +0 -293
- package/src/components/response-compare-types.ts +0 -152
- package/src/components/response-compare.tsx +0 -455
- package/src/components/response-stream.tsx +0 -109
- package/src/components/screen.tsx +0 -181
- package/src/components/scroll-button.tsx +0 -93
- package/src/components/source.tsx +0 -192
- package/src/components/tasks-card.tsx +0 -801
- package/src/components/text-shimmer.tsx +0 -37
- package/src/components/thinking-bar.tsx +0 -50
- package/src/components/thread.tsx +0 -228
- package/src/components/toast.tsx +0 -503
- package/src/components/tool-classify.ts +0 -26
- package/src/components/tool-types.ts +0 -49
- package/src/components/tool.tsx +0 -190
- package/src/components/use-card-resolution.ts +0 -44
- package/src/components/voice-input.tsx +0 -222
- package/src/components/voice-output.tsx +0 -242
- package/src/components/widget-tab-bar.tsx +0 -73
- package/src/components/workspace-shell.tsx +0 -285
- package/src/diagnostics/hook.ts +0 -352
- package/src/diagnostics/index.ts +0 -82
- package/src/diagnostics/report-request.ts +0 -296
- package/src/elements/agent-card.tsx +0 -67
- package/src/elements/artifact.tsx +0 -194
- package/src/elements/attachments.tsx +0 -140
- package/src/elements/audio-visualizer.tsx +0 -227
- package/src/elements/autoloader.ts +0 -89
- package/src/elements/avatar.tsx +0 -33
- package/src/elements/badge.tsx +0 -32
- package/src/elements/button.tsx +0 -149
- package/src/elements/card.tsx +0 -133
- package/src/elements/cards.tsx +0 -266
- package/src/elements/chain-of-thought.tsx +0 -141
- package/src/elements/chat-scope-picker.tsx +0 -65
- package/src/elements/chat-types.ts +0 -102
- package/src/elements/chat-workspace.tsx +0 -188
- package/src/elements/chat.tsx +0 -304
- package/src/elements/checkbox-group.tsx +0 -164
- package/src/elements/checkbox.tsx +0 -134
- package/src/elements/checkpoint.tsx +0 -47
- package/src/elements/choice.tsx +0 -100
- package/src/elements/coachmark.tsx +0 -90
- package/src/elements/code-block.tsx +0 -60
- package/src/elements/command.tsx +0 -197
- package/src/elements/compare.tsx +0 -111
- package/src/elements/compiled.css +0 -2
- package/src/elements/composer.tsx +0 -162
- package/src/elements/confirm-card.tsx +0 -76
- package/src/elements/context-meter.tsx +0 -107
- package/src/elements/conversation-item.tsx +0 -120
- package/src/elements/conversation-list.tsx +0 -203
- package/src/elements/css.ts +0 -5
- package/src/elements/default-input.tsx +0 -392
- package/src/elements/define-entry.ts +0 -12
- package/src/elements/define.tsx +0 -563
- package/src/elements/diagnostic-events.ts +0 -114
- package/src/elements/dialog.tsx +0 -145
- package/src/elements/disclosure.ts +0 -95
- package/src/elements/dock.tsx +0 -215
- package/src/elements/dropdown.tsx +0 -123
- package/src/elements/editable-label.tsx +0 -140
- package/src/elements/element-data-types.ts +0 -152
- package/src/elements/element-diagnostics.ts +0 -392
- package/src/elements/element-manifest.json +0 -354
- package/src/elements/element-nonscalar.json +0 -187
- package/src/elements/element-types.d.ts +0 -4353
- package/src/elements/embed.tsx +0 -35
- package/src/elements/empty.tsx +0 -29
- package/src/elements/feedback-bar.tsx +0 -66
- package/src/elements/file-tree.tsx +0 -62
- package/src/elements/file-upload.tsx +0 -44
- package/src/elements/form.tsx +0 -94
- package/src/elements/hover-card.tsx +0 -80
- package/src/elements/icon.tsx +0 -41
- package/src/elements/image.tsx +0 -32
- package/src/elements/input.tsx +0 -492
- package/src/elements/kbd.tsx +0 -45
- package/src/elements/link-preview.tsx +0 -34
- package/src/elements/loader.tsx +0 -25
- package/src/elements/markdown.tsx +0 -38
- package/src/elements/menu.tsx +0 -241
- package/src/elements/message-skills.tsx +0 -83
- package/src/elements/message.tsx +0 -361
- package/src/elements/model-switcher.tsx +0 -121
- package/src/elements/nav.tsx +0 -87
- package/src/elements/notice.tsx +0 -53
- package/src/elements/pane-grid.tsx +0 -111
- package/src/elements/pane-group.tsx +0 -119
- package/src/elements/pane.tsx +0 -129
- package/src/elements/popover.tsx +0 -81
- package/src/elements/progress-bar.tsx +0 -39
- package/src/elements/prompt-dock.tsx +0 -82
- package/src/elements/prompt-input.tsx +0 -240
- package/src/elements/prompt-suggestions.tsx +0 -113
- package/src/elements/radio-group.tsx +0 -129
- package/src/elements/reasoning.tsx +0 -71
- package/src/elements/register-impl.ts +0 -148
- package/src/elements/register.ts +0 -76
- package/src/elements/remote.tsx +0 -225
- package/src/elements/resizable.globals.d.ts +0 -36
- package/src/elements/resizable.tsx +0 -704
- package/src/elements/response-stream.tsx +0 -40
- package/src/elements/screen.tsx +0 -90
- package/src/elements/scroll-area.tsx +0 -33
- package/src/elements/scroll-button.tsx +0 -179
- package/src/elements/search.tsx +0 -185
- package/src/elements/segmented.tsx +0 -129
- package/src/elements/select.tsx +0 -165
- package/src/elements/separator.tsx +0 -36
- package/src/elements/setting-item.tsx +0 -50
- package/src/elements/settings-group.tsx +0 -37
- package/src/elements/skeleton.tsx +0 -45
- package/src/elements/slider.tsx +0 -171
- package/src/elements/slot-text.ts +0 -73
- package/src/elements/slots.ts +0 -787
- package/src/elements/source.tsx +0 -126
- package/src/elements/status.tsx +0 -42
- package/src/elements/styles.css +0 -328
- package/src/elements/switch.tsx +0 -118
- package/src/elements/tabs.tsx +0 -95
- package/src/elements/tasks.tsx +0 -103
- package/src/elements/text-shimmer.tsx +0 -28
- package/src/elements/thinking-bar.tsx +0 -43
- package/src/elements/thread.tsx +0 -139
- package/src/elements/toast.tsx +0 -106
- package/src/elements/tool.tsx +0 -78
- package/src/elements/tooltip.tsx +0 -85
- package/src/elements/validate-messages.ts +0 -76
- package/src/elements/voice-input.tsx +0 -100
- package/src/elements/voice-output.tsx +0 -82
- package/src/index.ts +0 -430
- package/src/primitives/audio-bands.ts +0 -174
- package/src/primitives/card-component-types.ts +0 -63
- package/src/primitives/card-contract.ts +0 -80
- package/src/primitives/card-data-types.ts +0 -361
- package/src/primitives/card-host.tsx +0 -37
- package/src/primitives/card-recovery.ts +0 -160
- package/src/primitives/card-registry.tsx +0 -78
- package/src/primitives/card-resolution.ts +0 -36
- package/src/primitives/card-routing.ts +0 -85
- package/src/primitives/card-schemas/artifact.schema.json +0 -92
- package/src/primitives/card-schemas/card-envelope.schema.json +0 -14
- package/src/primitives/card-schemas/card-event.schema.json +0 -12
- package/src/primitives/card-schemas/choice.schema.json +0 -75
- package/src/primitives/card-schemas/confirm.schema.json +0 -65
- package/src/primitives/card-schemas/embed.schema.json +0 -63
- package/src/primitives/card-schemas/form.result.schema.json +0 -7
- package/src/primitives/card-schemas/form.schema.json +0 -53
- package/src/primitives/card-schemas/link.schema.json +0 -54
- package/src/primitives/card-schemas/tasks.result.schema.json +0 -16
- package/src/primitives/card-schemas/tasks.schema.json +0 -83
- package/src/primitives/card-tags.ts +0 -61
- package/src/primitives/card-validate-cards.ts +0 -255
- package/src/primitives/card-validate-schemas.ts +0 -58
- package/src/primitives/card-validate.ts +0 -131
- package/src/primitives/chat-config.tsx +0 -103
- package/src/primitives/composer-model.ts +0 -49
- package/src/primitives/composer-triggers.ts +0 -35
- package/src/primitives/controllable.ts +0 -21
- package/src/primitives/conversation-store.ts +0 -248
- package/src/primitives/create-kai-chat.ts +0 -66
- package/src/primitives/create-tween.ts +0 -266
- package/src/primitives/embed-providers.ts +0 -254
- package/src/primitives/field-mask.ts +0 -256
- package/src/primitives/field-semantics.ts +0 -115
- package/src/primitives/highlighter.ts +0 -157
- package/src/primitives/input-mask.ts +0 -853
- package/src/primitives/link-preview.ts +0 -87
- package/src/primitives/message-feedback.ts +0 -124
- package/src/primitives/pdf-preview.ts +0 -121
- package/src/primitives/toast-store.ts +0 -338
- package/src/primitives/url-scheme-policy.ts +0 -70
- package/src/primitives/use-audio-analysis.ts +0 -340
- package/src/primitives/use-auto-resize.ts +0 -31
- package/src/primitives/use-resize-observer.ts +0 -45
- package/src/primitives/use-sequencer.ts +0 -72
- package/src/primitives/use-speech-recognition.ts +0 -146
- package/src/primitives/use-stick-to-bottom.ts +0 -75
- package/src/primitives/use-text-stream.ts +0 -143
- package/src/primitives/use-voice-recorder.ts +0 -62
- package/src/primitives/visualizer-sequences.ts +0 -350
- package/src/remote/host-embed.ts +0 -345
- package/src/remote/index.ts +0 -2
- package/src/remote/origin.ts +0 -30
- package/src/remote/provider-runtime.ts +0 -262
- package/src/remote/provider.ts +0 -2
- package/src/remote/validate.ts +0 -22
- package/src/remote/version.ts +0 -12
- package/src/remote/wire.ts +0 -48
- package/src/schemas/from-tool-call.ts +0 -151
- package/src/schemas/index.ts +0 -341
- package/src/schemas/provider-subsets.ts +0 -538
- package/src/schemas/registry.ts +0 -355
- package/src/schemas/tool-defs.ts +0 -793
- package/src/solid.ts +0 -173
- package/src/state/index.ts +0 -44
- package/src/state/messages.ts +0 -53
- package/src/state/mock.ts +0 -297
- package/src/state/parts.ts +0 -295
- package/src/state/persistence.ts +0 -180
- package/src/state/stream.ts +0 -246
- package/src/state/suggestions.ts +0 -9
- package/src/state/threads.ts +0 -142
- package/src/test-utils/fake-clock.ts +0 -88
- package/src/types.ts +0 -95
- package/src/ui/action-icons.ts +0 -53
- package/src/ui/agent-card.tsx +0 -218
- package/src/ui/avatar.tsx +0 -23
- package/src/ui/badge.tsx +0 -21
- package/src/ui/button.tsx +0 -49
- package/src/ui/card.tsx +0 -245
- package/src/ui/checkbox-group.tsx +0 -153
- package/src/ui/checkbox.tsx +0 -63
- package/src/ui/collapsible.tsx +0 -163
- package/src/ui/command.tsx +0 -103
- package/src/ui/dialog.tsx +0 -223
- package/src/ui/dock.tsx +0 -630
- package/src/ui/dropdown.tsx +0 -636
- package/src/ui/editable-label.tsx +0 -112
- package/src/ui/hover-card.tsx +0 -345
- package/src/ui/icon.tsx +0 -167
- package/src/ui/input.tsx +0 -391
- package/src/ui/kbd.tsx +0 -118
- package/src/ui/nav.tsx +0 -282
- package/src/ui/notice.tsx +0 -84
- package/src/ui/overlay.tsx +0 -277
- package/src/ui/pane-grid.tsx +0 -117
- package/src/ui/pane-group.tsx +0 -291
- package/src/ui/pane.tsx +0 -193
- package/src/ui/popover.tsx +0 -106
- package/src/ui/progress-bar.tsx +0 -83
- package/src/ui/prompt-dock.tsx +0 -145
- package/src/ui/radio.tsx +0 -150
- package/src/ui/resizable.tsx +0 -693
- package/src/ui/scroll-area.tsx +0 -26
- package/src/ui/segmented.tsx +0 -109
- package/src/ui/select.tsx +0 -168
- package/src/ui/separator.tsx +0 -10
- package/src/ui/settings-group.tsx +0 -67
- package/src/ui/skeleton.tsx +0 -73
- package/src/ui/slider.tsx +0 -178
- package/src/ui/status.tsx +0 -48
- package/src/ui/switch.tsx +0 -119
- package/src/ui/tabs.tsx +0 -168
- package/src/ui/textarea.tsx +0 -21
- package/src/ui/tooltip.tsx +0 -118
- package/src/utils/cn.ts +0 -30
- package/src/wire/chunk.ts +0 -248
- package/src/wire/consume.ts +0 -599
- package/src/wire/diagnostics.ts +0 -727
- package/src/wire/encode-probe.ts +0 -214
- package/src/wire/encode.ts +0 -947
- package/src/wire/files.ts +0 -342
- package/src/wire/formats/anthropic.ts +0 -274
- package/src/wire/formats/openai.ts +0 -228
- package/src/wire/index.ts +0 -95
- package/src/wire/media-types.ts +0 -344
- package/src/wire/read.ts +0 -396
- package/src/wire/sink-helpers.ts +0 -50
- package/src/wire/sse.ts +0 -153
package/src/ui/dialog.tsx
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createEffect, createSignal, createUniqueId, Show, type Accessor, type JSX,
|
|
3
|
-
} from 'solid-js';
|
|
4
|
-
import { Portal } from 'solid-js/web';
|
|
5
|
-
import { cn } from '../utils/cn';
|
|
6
|
-
import { useChatConfig } from '../primitives/chat-config';
|
|
7
|
-
import { createPresence } from './overlay';
|
|
8
|
-
|
|
9
|
-
/** Imperative open controller, handed to a parent (e.g. the kai-dialog facade)
|
|
10
|
-
* via `controllerRef` so it can drive/observe open state with `wireDisclosure`. */
|
|
11
|
-
export interface DialogController { open: Accessor<boolean>; setOpen: (v: boolean) => void; }
|
|
12
|
-
|
|
13
|
-
export interface DialogProps {
|
|
14
|
-
/** Dialog body — the default slot / main content. */
|
|
15
|
-
children?: JSX.Element;
|
|
16
|
-
/** Optional header region (e.g. a title). Rendered above the body with a divider. */
|
|
17
|
-
header?: JSX.Element;
|
|
18
|
-
/** Optional footer region (e.g. action buttons). Rendered below the body with a divider. */
|
|
19
|
-
footer?: JSX.Element;
|
|
20
|
-
/** Controlled open state. When set, the component never changes it itself —
|
|
21
|
-
* drive it from `onOpenChange`. Omit for uncontrolled (internal) state. */
|
|
22
|
-
open?: boolean;
|
|
23
|
-
/** Initial open state when uncontrolled. */
|
|
24
|
-
defaultOpen?: boolean;
|
|
25
|
-
/** Fires whenever the dialog wants to open or close (Escape / backdrop / method). */
|
|
26
|
-
onOpenChange?: (open: boolean) => void;
|
|
27
|
-
/** Receive the open controller (open accessor + setOpen) once mounted. */
|
|
28
|
-
controllerRef?: (api: DialogController) => void;
|
|
29
|
-
/** Receive the focusable panel node so a facade's `focus()` can target it. */
|
|
30
|
-
panelRef?: (el: HTMLElement) => void;
|
|
31
|
-
/** Accessible name for the dialog when no `header` is provided. */
|
|
32
|
-
'aria-label'?: string;
|
|
33
|
-
/** Extra class applied to the panel (e.g. a wider `max-w-*`). */
|
|
34
|
-
class?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Focusable-element selector for the Tab focus trap. */
|
|
38
|
-
const FOCUSABLE_SELECTOR = [
|
|
39
|
-
'a[href]', 'button:not([disabled])', 'input:not([disabled])',
|
|
40
|
-
'select:not([disabled])', 'textarea:not([disabled])',
|
|
41
|
-
'audio[controls]', 'video[controls]', '[contenteditable]:not([contenteditable="false"])',
|
|
42
|
-
'[tabindex]:not([tabindex="-1"])',
|
|
43
|
-
].join(',');
|
|
44
|
-
|
|
45
|
-
/** Roughly "rendered + not visibility:hidden" — skips display:none / hidden nodes. */
|
|
46
|
-
function isVisible(el: HTMLElement): boolean {
|
|
47
|
-
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length)
|
|
48
|
-
&& getComputedStyle(el).visibility !== 'hidden';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Tabbable descendants of `panel`, in tab order. Crosses `<slot>` boundaries:
|
|
53
|
-
* when used as a web-component facade the panel's real content is light-DOM nodes
|
|
54
|
-
* assigned to its slots, not panel descendants, so a plain querySelectorAll would
|
|
55
|
-
* miss them. We walk the tree and expand each slot to its assigned elements.
|
|
56
|
-
*/
|
|
57
|
-
function getTabbables(panel: HTMLElement): HTMLElement[] {
|
|
58
|
-
const out: HTMLElement[] = [];
|
|
59
|
-
const walk = (node: Element) => {
|
|
60
|
-
for (const child of Array.from(node.children)) {
|
|
61
|
-
if (child instanceof HTMLSlotElement) {
|
|
62
|
-
for (const assigned of child.assignedElements()) {
|
|
63
|
-
if (assigned instanceof HTMLElement) {
|
|
64
|
-
if (assigned.matches(FOCUSABLE_SELECTOR)) out.push(assigned);
|
|
65
|
-
walk(assigned);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} else if (child instanceof HTMLElement) {
|
|
69
|
-
if (child.matches(FOCUSABLE_SELECTOR)) out.push(child);
|
|
70
|
-
walk(child);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
walk(panel);
|
|
75
|
-
return out.filter(isVisible);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** The deepest active element, drilling through nested shadow roots (so a focused
|
|
79
|
-
* node inside a shadow tree resolves to the real element, not its host). */
|
|
80
|
-
function deepActiveElement(): HTMLElement | null {
|
|
81
|
-
let el = document.activeElement as HTMLElement | null;
|
|
82
|
-
while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement as HTMLElement;
|
|
83
|
-
return el;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Dialog is the presentational centered modal surface. It renders through a Portal
|
|
88
|
-
* (so it escapes any clipping/stacking ancestor), dims the page with a backdrop,
|
|
89
|
-
* and centers a panel with a sensible max width/height and internal scroll. It
|
|
90
|
-
* closes on Escape and on a backdrop click (never on a panel click), moves focus
|
|
91
|
-
* into the panel on open and restores it on close, and runs a basic Tab focus
|
|
92
|
-
* trap so keyboard focus cycles within the panel while open. The developer owns
|
|
93
|
-
* when it opens (drive `open` / `defaultOpen`); this owns being the modal.
|
|
94
|
-
*
|
|
95
|
-
* Styleable parts: `backdrop` · `panel` · `header` · `body` · `footer`.
|
|
96
|
-
*/
|
|
97
|
-
export function Dialog(props: DialogProps) {
|
|
98
|
-
const config = useChatConfig();
|
|
99
|
-
const [internalOpen, setInternalOpen] = createSignal(props.defaultOpen ?? false);
|
|
100
|
-
const headerId = `kai-dialog-title-${createUniqueId()}`;
|
|
101
|
-
|
|
102
|
-
const isControlled = () => props.open !== undefined;
|
|
103
|
-
const isOpen = () => (isControlled() ? !!props.open : internalOpen());
|
|
104
|
-
const setOpen = (v: boolean) => {
|
|
105
|
-
if (!isControlled()) setInternalOpen(v);
|
|
106
|
-
props.onOpenChange?.(v);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Hand the open controller up to a parent (e.g. the kai-dialog facade) so it can
|
|
110
|
-
// drive/observe open state via wireDisclosure.
|
|
111
|
-
props.controllerRef?.({ open: isOpen, setOpen });
|
|
112
|
-
|
|
113
|
-
const presence = createPresence(isOpen);
|
|
114
|
-
|
|
115
|
-
let backdrop: HTMLElement | undefined;
|
|
116
|
-
let panel: HTMLElement | undefined;
|
|
117
|
-
// The element that had focus before we opened, restored on close.
|
|
118
|
-
let restoreFocus: HTMLElement | null = null;
|
|
119
|
-
// Track where a click started so a drag that ends on the backdrop (e.g. a text
|
|
120
|
-
// selection begun inside the panel) does not falsely dismiss.
|
|
121
|
-
let pointerDownOnBackdrop = false;
|
|
122
|
-
|
|
123
|
-
// Move focus into the panel on open; restore it on close. Seeded prev=false so a
|
|
124
|
-
// `defaultOpen` (open-at-mount) still runs the open branch.
|
|
125
|
-
createEffect((wasOpen: boolean) => {
|
|
126
|
-
const open = isOpen();
|
|
127
|
-
if (open && !wasOpen) {
|
|
128
|
-
restoreFocus = deepActiveElement();
|
|
129
|
-
queueMicrotask(() => panel?.focus());
|
|
130
|
-
} else if (!open && wasOpen) {
|
|
131
|
-
const target = restoreFocus;
|
|
132
|
-
restoreFocus = null;
|
|
133
|
-
if (target && target.isConnected) queueMicrotask(() => target.focus());
|
|
134
|
-
}
|
|
135
|
-
return open;
|
|
136
|
-
}, false);
|
|
137
|
-
|
|
138
|
-
const onKeyDown = (e: KeyboardEvent) => {
|
|
139
|
-
if (e.key === 'Escape') {
|
|
140
|
-
e.stopPropagation();
|
|
141
|
-
setOpen(false);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (e.key !== 'Tab' || !panel) return;
|
|
145
|
-
// Basic focus trap: keep Tab / Shift+Tab cycling within the panel.
|
|
146
|
-
const items = getTabbables(panel);
|
|
147
|
-
if (!items.length) {
|
|
148
|
-
e.preventDefault();
|
|
149
|
-
panel.focus();
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const active = deepActiveElement();
|
|
153
|
-
const idx = active ? items.indexOf(active) : -1;
|
|
154
|
-
if (e.shiftKey) {
|
|
155
|
-
if (idx <= 0) { e.preventDefault(); items[items.length - 1].focus(); }
|
|
156
|
-
} else if (idx === -1 || idx === items.length - 1) {
|
|
157
|
-
e.preventDefault();
|
|
158
|
-
items[0].focus();
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
const onClick = (e: MouseEvent) => {
|
|
163
|
-
if (pointerDownOnBackdrop && e.target === backdrop) setOpen(false);
|
|
164
|
-
pointerDownOnBackdrop = false;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<Show when={presence.present()}>
|
|
169
|
-
<Portal mount={config.portalMount()}>
|
|
170
|
-
<div
|
|
171
|
-
ref={(el) => { backdrop = el; presence.setRef(el); }}
|
|
172
|
-
part="backdrop"
|
|
173
|
-
data-expanded={presence.state() === 'open' ? '' : undefined}
|
|
174
|
-
data-closed={presence.state() === 'closed' ? '' : undefined}
|
|
175
|
-
onPointerDown={(e) => { pointerDownOnBackdrop = e.target === e.currentTarget; }}
|
|
176
|
-
onClick={onClick}
|
|
177
|
-
onKeyDown={onKeyDown}
|
|
178
|
-
class={cn(
|
|
179
|
-
'fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4',
|
|
180
|
-
'animate-in fade-in-0 data-[closed]:animate-out data-[closed]:fade-out-0 motion-reduce:animate-none',
|
|
181
|
-
)}
|
|
182
|
-
>
|
|
183
|
-
<div
|
|
184
|
-
ref={(el) => { panel = el; props.panelRef?.(el); }}
|
|
185
|
-
part="panel"
|
|
186
|
-
role="dialog"
|
|
187
|
-
aria-modal="true"
|
|
188
|
-
aria-labelledby={props.header ? headerId : undefined}
|
|
189
|
-
aria-label={props.header ? undefined : props['aria-label']}
|
|
190
|
-
tabindex={-1}
|
|
191
|
-
data-expanded={presence.state() === 'open' ? '' : undefined}
|
|
192
|
-
data-closed={presence.state() === 'closed' ? '' : undefined}
|
|
193
|
-
// `outline-none` is DELIBERATE here and must stay. This is a
|
|
194
|
-
// `tabindex={-1}` focus-trap container: it is focused
|
|
195
|
-
// programmatically on open to move keyboard and screen-reader
|
|
196
|
-
// context into the dialog, and is never a tab stop. Drawing a ring
|
|
197
|
-
// would put a blue box around the entire dialog every time it
|
|
198
|
-
// opened. The controls inside it carry their own focus rings.
|
|
199
|
-
class={cn(
|
|
200
|
-
'flex max-h-[85vh] w-full max-w-lg flex-col overflow-hidden rounded-xl border border-border bg-background text-foreground shadow-xl outline-none',
|
|
201
|
-
'animate-in fade-in-0 zoom-in-95 data-[closed]:animate-out data-[closed]:fade-out-0 data-[closed]:zoom-out-95 motion-reduce:animate-none',
|
|
202
|
-
props.class,
|
|
203
|
-
)}
|
|
204
|
-
>
|
|
205
|
-
<Show when={props.header}>
|
|
206
|
-
<header part="header" id={headerId} class="shrink-0 border-b border-border px-5 py-4 text-base font-semibold text-foreground">
|
|
207
|
-
{props.header}
|
|
208
|
-
</header>
|
|
209
|
-
</Show>
|
|
210
|
-
<div part="body" class="min-h-0 flex-1 overflow-auto px-5 py-4 text-sm text-foreground">
|
|
211
|
-
{props.children}
|
|
212
|
-
</div>
|
|
213
|
-
<Show when={props.footer}>
|
|
214
|
-
<footer part="footer" class="flex shrink-0 items-center justify-end gap-2 border-t border-border px-5 py-3">
|
|
215
|
-
{props.footer}
|
|
216
|
-
</footer>
|
|
217
|
-
</Show>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
</Portal>
|
|
221
|
-
</Show>
|
|
222
|
-
);
|
|
223
|
-
}
|