glirastes 0.3.0 → 0.3.1
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/CHANGELOG.md +63 -0
- package/README.md +146 -9
- package/codegen/package.json +5 -0
- package/dist/cjs/codegen/asset-sync.d.ts +20 -0
- package/dist/cjs/codegen/asset-sync.js +28 -0
- package/dist/cjs/codegen/coverage.d.ts +66 -0
- package/dist/cjs/codegen/coverage.js +408 -0
- package/dist/cjs/codegen/endpoint-scanner.d.ts +16 -0
- package/dist/cjs/codegen/endpoint-scanner.js +197 -0
- package/dist/cjs/codegen/format.d.ts +17 -0
- package/dist/cjs/codegen/format.js +34 -0
- package/dist/cjs/codegen/fs-utils.d.ts +45 -0
- package/dist/cjs/codegen/fs-utils.js +165 -0
- package/dist/cjs/codegen/index.d.ts +13 -0
- package/dist/cjs/codegen/index.js +33 -0
- package/dist/cjs/codegen/mcp-generator.d.ts +50 -0
- package/dist/cjs/codegen/mcp-generator.js +803 -0
- package/dist/cjs/codegen/module-generator.d.ts +11 -0
- package/dist/cjs/codegen/module-generator.js +353 -0
- package/dist/cjs/codegen/nestjs-scanner.d.ts +43 -0
- package/dist/cjs/codegen/nestjs-scanner.js +241 -0
- package/dist/cjs/codegen/output-recommender.d.ts +23 -0
- package/dist/cjs/codegen/output-recommender.js +33 -0
- package/dist/cjs/codegen/scaffolder.d.ts +36 -0
- package/dist/cjs/codegen/scaffolder.js +262 -0
- package/dist/cjs/codegen/skill-generator.d.ts +49 -0
- package/dist/cjs/codegen/skill-generator.js +967 -0
- package/dist/cjs/codegen/types.d.ts +52 -0
- package/dist/cjs/codegen/types.js +16 -0
- package/dist/cjs/codegen/ui-scanner.d.ts +24 -0
- package/dist/cjs/codegen/ui-scanner.js +202 -0
- package/dist/cjs/codegen/validator.d.ts +35 -0
- package/dist/cjs/codegen/validator.js +292 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/openapi/index.d.ts +78 -0
- package/dist/cjs/openapi/index.js +347 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/react/audio-worklet-processor.d.ts +16 -0
- package/dist/cjs/react/audio-worklet-processor.js +27 -0
- package/dist/cjs/react/bridges/rest-session-bridge.d.ts +113 -0
- package/dist/cjs/react/bridges/rest-session-bridge.js +209 -0
- package/dist/cjs/react/components/ai-chat-panel.d.ts +12 -0
- package/dist/cjs/react/components/ai-chat-panel.js +67 -0
- package/dist/cjs/react/components/ai-trigger-button.d.ts +2 -0
- package/dist/cjs/react/components/ai-trigger-button.js +239 -0
- package/dist/cjs/react/components/approval-card.d.ts +9 -0
- package/dist/cjs/react/components/approval-card.js +24 -0
- package/dist/cjs/react/components/bulk-approval-card.d.ts +9 -0
- package/dist/cjs/react/components/bulk-approval-card.js +36 -0
- package/dist/cjs/react/components/chat-input.d.ts +10 -0
- package/dist/cjs/react/components/chat-input.js +60 -0
- package/dist/cjs/react/components/chat-window.d.ts +2 -0
- package/dist/cjs/react/components/chat-window.js +134 -0
- package/dist/cjs/react/components/confirm-dialog.d.ts +32 -0
- package/dist/cjs/react/components/confirm-dialog.js +48 -0
- package/dist/cjs/react/components/floating-chat-ui.d.ts +90 -0
- package/dist/cjs/react/components/floating-chat-ui.js +163 -0
- package/dist/cjs/react/components/mention-chip.d.ts +16 -0
- package/dist/cjs/react/components/mention-chip.js +42 -0
- package/dist/cjs/react/components/mention-input.d.ts +8 -0
- package/dist/cjs/react/components/mention-input.js +117 -0
- package/dist/cjs/react/components/message-bubble.d.ts +11 -0
- package/dist/cjs/react/components/message-bubble.js +171 -0
- package/dist/cjs/react/components/message-list.d.ts +8 -0
- package/dist/cjs/react/components/message-list.js +52 -0
- package/dist/cjs/react/components/pipeline-timeline.d.ts +7 -0
- package/dist/cjs/react/components/pipeline-timeline.js +72 -0
- package/dist/cjs/react/components/recording-bar.d.ts +2 -0
- package/dist/cjs/react/components/recording-bar.js +81 -0
- package/dist/cjs/react/components/recording-controls.d.ts +18 -0
- package/dist/cjs/react/components/recording-controls.js +38 -0
- package/dist/cjs/react/components/rich-mention-input.d.ts +2 -0
- package/dist/cjs/react/components/rich-mention-input.js +571 -0
- package/dist/cjs/react/components/session-switcher.d.ts +14 -0
- package/dist/cjs/react/components/session-switcher.js +133 -0
- package/dist/cjs/react/components/suggestion-bar.d.ts +9 -0
- package/dist/cjs/react/components/suggestion-bar.js +47 -0
- package/dist/cjs/react/components/suggestion-chip.d.ts +9 -0
- package/dist/cjs/react/components/suggestion-chip.js +14 -0
- package/dist/cjs/react/components/voice-input-addon.d.ts +13 -0
- package/dist/cjs/react/components/voice-input-addon.js +31 -0
- package/dist/cjs/react/components/voice-input-button.d.ts +2 -0
- package/dist/cjs/react/components/voice-input-button.js +55 -0
- package/dist/cjs/react/components/wavesurfer-loader.d.ts +5 -0
- package/dist/cjs/react/components/wavesurfer-loader.js +36 -0
- package/dist/cjs/react/hooks/use-ai-chat.d.ts +22 -0
- package/dist/cjs/react/hooks/use-ai-chat.js +51 -0
- package/dist/cjs/react/hooks/use-approvals.d.ts +23 -0
- package/dist/cjs/react/hooks/use-approvals.js +63 -0
- package/dist/cjs/react/hooks/use-deepgram-transcription.d.ts +2 -0
- package/dist/cjs/react/hooks/use-deepgram-transcription.js +329 -0
- package/dist/cjs/react/hooks/use-drag-resize-panel.d.ts +48 -0
- package/dist/cjs/react/hooks/use-drag-resize-panel.js +308 -0
- package/dist/cjs/react/hooks/use-draggable-position.d.ts +25 -0
- package/dist/cjs/react/hooks/use-draggable-position.js +134 -0
- package/dist/cjs/react/hooks/use-keyboard-shortcut.d.ts +20 -0
- package/dist/cjs/react/hooks/use-keyboard-shortcut.js +93 -0
- package/dist/cjs/react/hooks/use-mentions.d.ts +23 -0
- package/dist/cjs/react/hooks/use-mentions.js +42 -0
- package/dist/cjs/react/hooks/use-suggestions.d.ts +22 -0
- package/dist/cjs/react/hooks/use-suggestions.js +39 -0
- package/dist/cjs/react/index.d.ts +43 -0
- package/dist/cjs/react/index.js +111 -0
- package/dist/cjs/react/provider/ai-chat-provider.d.ts +45 -0
- package/dist/cjs/react/provider/ai-chat-provider.js +1024 -0
- package/dist/cjs/react/provider/chat-context.d.ts +84 -0
- package/dist/cjs/react/provider/chat-context.js +13 -0
- package/dist/cjs/react/template.d.ts +84 -0
- package/dist/cjs/react/template.js +90 -0
- package/dist/cjs/react/themes.d.ts +24 -0
- package/dist/cjs/react/themes.js +273 -0
- package/dist/cjs/react/transports/langgraph/index.d.ts +2 -0
- package/dist/cjs/react/transports/langgraph/index.js +8 -0
- package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.d.ts +62 -0
- package/dist/cjs/react/transports/langgraph/langgraph-ai-chat.js +94 -0
- package/dist/cjs/react/transports/langgraph.d.ts +71 -0
- package/dist/cjs/react/transports/langgraph.js +369 -0
- package/dist/cjs/react/transports/vercel/index.d.ts +2 -0
- package/dist/cjs/react/transports/vercel/index.js +8 -0
- package/dist/cjs/react/transports/vercel/vercel-ai-chat.d.ts +49 -0
- package/dist/cjs/react/transports/vercel/vercel-ai-chat.js +81 -0
- package/dist/cjs/react/transports/vercel.d.ts +30 -0
- package/dist/cjs/react/transports/vercel.js +69 -0
- package/dist/cjs/react/types.d.ts +760 -0
- package/dist/cjs/react/types.js +2 -0
- package/dist/cjs/react/ui.d.ts +73 -0
- package/dist/cjs/react/ui.js +183 -0
- package/dist/cjs/react/utils/create-approval-description.d.ts +53 -0
- package/dist/cjs/react/utils/create-approval-description.js +122 -0
- package/dist/cjs/react/utils/create-tool-result-handler.d.ts +90 -0
- package/dist/cjs/react/utils/create-tool-result-handler.js +168 -0
- package/dist/cjs/react/utils/mention-markup.d.ts +13 -0
- package/dist/cjs/react/utils/mention-markup.js +117 -0
- package/dist/cjs/react/utils/merge-pipeline-steps.d.ts +19 -0
- package/dist/cjs/react/utils/merge-pipeline-steps.js +81 -0
- package/dist/cjs/react/utils/sanitize-stored-messages.d.ts +23 -0
- package/dist/cjs/react/utils/sanitize-stored-messages.js +52 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.d.ts +10 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-auth.guard.js +42 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.d.ts +32 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat-module-options.interface.js +4 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.d.ts +11 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.controller.js +80 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.d.ts +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.module.js +119 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.d.ts +13 -0
- package/dist/cjs/server/adapters/nestjs/chat/ai-chat.service.js +131 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.d.ts +7 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/ai-chat-request.dto.js +52 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.d.ts +19 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message-part.dto.js +108 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.d.ts +8 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/chat-message.dto.js +59 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/index.d.ts +3 -0
- package/dist/cjs/server/adapters/nestjs/chat/dto/index.js +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/index.d.ts +3 -0
- package/dist/cjs/server/adapters/nestjs/chat/index.js +9 -0
- package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +4 -0
- package/dist/cjs/server/adapters/nestjs/chat/speech-stream.gateway.js +73 -0
- package/dist/cjs/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
- package/dist/cjs/server/adapters/nestjs/chat/ws-loader.js +72 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.d.ts +6 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-module.decorator.js +13 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.d.ts +5 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-param.decorator.js +15 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.d.ts +6 -0
- package/dist/cjs/server/adapters/nestjs/decorators/ai-tool.decorator.js +22 -0
- package/dist/cjs/server/adapters/nestjs/decorators/constants.d.ts +4 -0
- package/dist/cjs/server/adapters/nestjs/decorators/constants.js +7 -0
- package/dist/cjs/server/adapters/nestjs/index.d.ts +14 -0
- package/dist/cjs/server/adapters/nestjs/index.js +42 -0
- package/dist/cjs/server/adapters/nestjs/metadata.d.ts +39 -0
- package/dist/cjs/server/adapters/nestjs/metadata.js +36 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.d.ts +36 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools-explorer.service.js +159 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.d.ts +37 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.module.js +44 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.d.ts +28 -0
- package/dist/cjs/server/adapters/nestjs/module/ai-tools.service.js +41 -0
- package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.d.ts +16 -0
- package/dist/cjs/server/adapters/nestjs/scanner/nestjs-scanner.js +117 -0
- package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.d.ts +26 -0
- package/dist/cjs/server/adapters/nestjs/scanner/schema-builder.js +259 -0
- package/dist/cjs/server/adapters/nestjs/swagger.d.ts +7 -0
- package/dist/cjs/server/adapters/nestjs/swagger.js +39 -0
- package/dist/cjs/server/adapters/nextjs/context-helpers.d.ts +22 -0
- package/dist/cjs/server/adapters/nextjs/context-helpers.js +60 -0
- package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.d.ts +94 -0
- package/dist/cjs/server/adapters/nextjs/create-ai-chat-handler.js +965 -0
- package/dist/cjs/server/adapters/nextjs/filter-fallback-error.d.ts +11 -0
- package/dist/cjs/server/adapters/nextjs/filter-fallback-error.js +41 -0
- package/dist/cjs/server/adapters/nextjs/index.d.ts +8 -0
- package/dist/cjs/server/adapters/nextjs/index.js +22 -0
- package/dist/cjs/server/adapters/nextjs/prepare-model-messages.d.ts +58 -0
- package/dist/cjs/server/adapters/nextjs/prepare-model-messages.js +114 -0
- package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.d.ts +64 -0
- package/dist/cjs/server/adapters/nextjs/sanitize-model-messages.js +489 -0
- package/dist/cjs/server/adapters/nextjs/server-action-helper.d.ts +7 -0
- package/dist/cjs/server/adapters/nextjs/server-action-helper.js +40 -0
- package/dist/cjs/server/adapters/nextjs/types.d.ts +246 -0
- package/dist/cjs/server/adapters/nextjs/types.js +2 -0
- package/dist/cjs/server/adapters/nextjs/with-ai-tool.d.ts +9 -0
- package/dist/cjs/server/adapters/nextjs/with-ai-tool.js +12 -0
- package/dist/cjs/server/core/followup-tool.d.ts +9 -0
- package/dist/cjs/server/core/followup-tool.js +82 -0
- package/dist/cjs/server/core/index.d.ts +139 -0
- package/dist/cjs/server/core/index.js +818 -0
- package/dist/cjs/server/core/intent-classifier.d.ts +94 -0
- package/dist/cjs/server/core/intent-classifier.js +324 -0
- package/dist/cjs/server/core/model-selector.d.ts +12 -0
- package/dist/cjs/server/core/model-selector.js +48 -0
- package/dist/cjs/server/core/module-router.d.ts +14 -0
- package/dist/cjs/server/core/module-router.js +110 -0
- package/dist/cjs/server/core/zod-compact.d.ts +18 -0
- package/dist/cjs/server/core/zod-compact.js +129 -0
- package/dist/cjs/server/index.d.ts +6 -0
- package/dist/cjs/server/index.js +28 -0
- package/dist/cjs/server/lancer/cache.d.ts +9 -0
- package/dist/cjs/server/lancer/cache.js +33 -0
- package/dist/cjs/server/lancer/client.d.ts +2 -0
- package/dist/cjs/server/lancer/client.js +279 -0
- package/dist/cjs/server/lancer/errors.d.ts +13 -0
- package/dist/cjs/server/lancer/errors.js +21 -0
- package/dist/cjs/server/lancer/index.d.ts +3 -0
- package/dist/cjs/server/lancer/index.js +7 -0
- package/dist/cjs/server/lancer/telemetry-buffer.d.ts +15 -0
- package/dist/cjs/server/lancer/telemetry-buffer.js +64 -0
- package/dist/cjs/server/lancer/types.d.ts +201 -0
- package/dist/cjs/server/lancer/types.js +5 -0
- package/dist/cjs/server/pii-shield/aegis-detector.d.ts +26 -0
- package/dist/cjs/server/pii-shield/aegis-detector.js +26 -0
- package/dist/cjs/server/pii-shield/create-pii-shield.d.ts +2 -0
- package/dist/cjs/server/pii-shield/create-pii-shield.js +191 -0
- package/dist/cjs/server/pii-shield/deep-walk.d.ts +1 -0
- package/dist/cjs/server/pii-shield/deep-walk.js +19 -0
- package/dist/cjs/server/pii-shield/fake-data.d.ts +5 -0
- package/dist/cjs/server/pii-shield/fake-data.js +170 -0
- package/dist/cjs/server/pii-shield/index.d.ts +4 -0
- package/dist/cjs/server/pii-shield/index.js +9 -0
- package/dist/cjs/server/pii-shield/leakage.d.ts +1 -0
- package/dist/cjs/server/pii-shield/leakage.js +15 -0
- package/dist/cjs/server/pii-shield/session-mapping.d.ts +12 -0
- package/dist/cjs/server/pii-shield/session-mapping.js +70 -0
- package/dist/cjs/server/pipeline.d.ts +26 -0
- package/dist/cjs/server/pipeline.js +127 -0
- package/dist/cjs/server/testing/approvals.d.ts +11 -0
- package/dist/cjs/server/testing/approvals.js +41 -0
- package/dist/cjs/server/testing/combination.d.ts +3 -0
- package/dist/cjs/server/testing/combination.js +83 -0
- package/dist/cjs/server/testing/create-test-suite.d.ts +29 -0
- package/dist/cjs/server/testing/create-test-suite.js +81 -0
- package/dist/cjs/server/testing/edge-cases.d.ts +8 -0
- package/dist/cjs/server/testing/edge-cases.js +277 -0
- package/dist/cjs/server/testing/guardrails.d.ts +14 -0
- package/dist/cjs/server/testing/guardrails.js +152 -0
- package/dist/cjs/server/testing/helpers.d.ts +14 -0
- package/dist/cjs/server/testing/helpers.js +119 -0
- package/dist/cjs/server/testing/index.d.ts +12 -0
- package/dist/cjs/server/testing/index.js +37 -0
- package/dist/cjs/server/testing/mock-executor.d.ts +8 -0
- package/dist/cjs/server/testing/mock-executor.js +40 -0
- package/dist/cjs/server/testing/regression.d.ts +7 -0
- package/dist/cjs/server/testing/regression.js +27 -0
- package/dist/cjs/server/testing/routing.d.ts +12 -0
- package/dist/cjs/server/testing/routing.js +63 -0
- package/dist/cjs/server/testing/schema-consistency.d.ts +6 -0
- package/dist/cjs/server/testing/schema-consistency.js +56 -0
- package/dist/cjs/server/testing/smoke.d.ts +11 -0
- package/dist/cjs/server/testing/smoke.js +64 -0
- package/dist/cjs/server/testing/types.d.ts +156 -0
- package/dist/cjs/server/testing/types.js +2 -0
- package/dist/cjs/types.d.ts +696 -0
- package/dist/cjs/types.js +91 -0
- package/dist/cli/commands/install-skills.d.ts +17 -0
- package/dist/cli/commands/install-skills.js +185 -0
- package/dist/cli/commands/install-skills.js.map +1 -0
- package/dist/cli/index.js +25 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/react/components/ai-trigger-button.js +4 -6
- package/dist/react/components/ai-trigger-button.js.map +1 -1
- package/dist/react/components/recording-bar.js +4 -6
- package/dist/react/components/recording-bar.js.map +1 -1
- package/dist/react/components/wavesurfer-loader.d.ts +5 -0
- package/dist/react/components/wavesurfer-loader.js +34 -0
- package/dist/react/components/wavesurfer-loader.js.map +1 -0
- package/dist/server/adapters/nestjs/chat/ai-chat.module.d.ts +1 -1
- package/dist/server/adapters/nestjs/chat/ai-chat.module.js +3 -2
- package/dist/server/adapters/nestjs/chat/ai-chat.module.js.map +1 -1
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.d.ts +1 -1
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js +10 -8
- package/dist/server/adapters/nestjs/chat/speech-stream.gateway.js.map +1 -1
- package/dist/server/adapters/nestjs/chat/ws-loader.d.ts +5 -0
- package/dist/server/adapters/nestjs/chat/ws-loader.js +37 -0
- package/dist/server/adapters/nestjs/chat/ws-loader.js.map +1 -0
- package/openapi/package.json +5 -0
- package/package.json +59 -16
- package/react/langgraph/package.json +5 -0
- package/react/package.json +5 -0
- package/react/vercel/package.json +5 -0
- package/server/nestjs/package.json +5 -0
- package/server/nextjs/package.json +5 -0
- package/server/package.json +5 -0
- package/server/testing/package.json +5 -0
- package/skills/README.md +107 -0
- package/skills/building-glirastes-chat-ui/SKILL.md +378 -0
- package/skills/integrating-glirastes-nestjs/SKILL.md +346 -0
- package/skills/integrating-glirastes-nextjs/SKILL.md +306 -0
- package/skills/integrating-glirastes-nextjs-with-nestjs-backend/SKILL.md +359 -0
- package/skills/maintaining-glirastes-tools/SKILL.md +463 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatInput = ChatInput;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
7
|
+
const voice_input_addon_js_1 = require("./voice-input-addon.js");
|
|
8
|
+
/**
|
|
9
|
+
* Plain chat input field with submit handling.
|
|
10
|
+
*
|
|
11
|
+
* Submits on Enter (without Shift). Renders the InputExtra component
|
|
12
|
+
* from provider config if available (e.g., voice input button).
|
|
13
|
+
*
|
|
14
|
+
* Toggles between send and stop button based on loading state.
|
|
15
|
+
*/
|
|
16
|
+
function ChatInput({ className, onSubmit }) {
|
|
17
|
+
const { send, stop, isLoading, classNames, locale, components, voice } = (0, chat_context_js_1.useChatContext)();
|
|
18
|
+
const [value, setValue] = (0, react_1.useState)('');
|
|
19
|
+
const InputExtra = components.InputExtra;
|
|
20
|
+
const textareaRef = (0, react_1.useRef)(null);
|
|
21
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
22
|
+
const el = textareaRef.current;
|
|
23
|
+
if (!el)
|
|
24
|
+
return;
|
|
25
|
+
el.style.height = 'auto';
|
|
26
|
+
el.style.overflowY = 'hidden';
|
|
27
|
+
const borderY = el.offsetHeight - el.clientHeight;
|
|
28
|
+
const next = el.scrollHeight + borderY;
|
|
29
|
+
const max = parseFloat(getComputedStyle(el).maxHeight) || Infinity;
|
|
30
|
+
if (next > max) {
|
|
31
|
+
el.style.height = `${max}px`;
|
|
32
|
+
el.style.overflowY = 'auto';
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
el.style.height = `${next}px`;
|
|
36
|
+
}
|
|
37
|
+
}, [value]);
|
|
38
|
+
const handleSubmit = (0, react_1.useCallback)((e) => {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
const trimmed = value.trim();
|
|
41
|
+
if (!trimmed || isLoading)
|
|
42
|
+
return;
|
|
43
|
+
if (onSubmit) {
|
|
44
|
+
onSubmit(trimmed);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
send(trimmed);
|
|
48
|
+
}
|
|
49
|
+
setValue('');
|
|
50
|
+
}, [value, isLoading, onSubmit, send]);
|
|
51
|
+
const handleKeyDown = (0, react_1.useCallback)((e) => {
|
|
52
|
+
if (e.key === 'Enter' && !e.shiftKey) {
|
|
53
|
+
e.preventDefault();
|
|
54
|
+
handleSubmit(e);
|
|
55
|
+
}
|
|
56
|
+
}, [handleSubmit]);
|
|
57
|
+
return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: className ?? classNames.input, "data-component": "chat-input", children: [(0, jsx_runtime_1.jsx)("textarea", { ref: textareaRef, autoFocus: true, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: locale.placeholder, disabled: isLoading, rows: 1, "data-state": isLoading ? 'loading' : 'idle' }), voice.enabled && ((0, jsx_runtime_1.jsx)(voice_input_addon_js_1.VoiceInputAddon, { disabled: isLoading, language: voice.language ?? 'de', baseUrl: voice.baseUrl, getToken: voice.getToken, onTranscript: (text) => {
|
|
58
|
+
setValue((prev) => (prev.length > 0 ? `${prev} ${text}` : text));
|
|
59
|
+
}, onError: voice.onError, showRecordingBar: voice.recordingBar?.enabled ?? true, recordingBarVariant: voice.recordingBar?.variant ?? 'inline' })), InputExtra && (0, jsx_runtime_1.jsx)(InputExtra, {}), isLoading ? ((0, jsx_runtime_1.jsx)("button", { type: "button", onClick: stop, "data-action": "stop", children: locale.stopButton })) : ((0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: !value.trim(), "data-action": "send", children: locale.sendButton }))] }));
|
|
60
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { ChatWindowProps } from '../types.js';
|
|
2
|
+
export declare function ChatWindow({ children, title, closeChatAriaLabel, className, headerClassName, bodyClassName, portal, open, defaultOpen, onOpenChange, draggable, resizable, constrainToViewport, width, height, minWidth, minHeight, maxWidth, maxHeight, initialPosition, snapToCenter, snapRadius, edgeThreshold, persistDimensions, header, headerActions, headerTitle, renderHeader, onPositionChange, onDimensionChange, resizeHandleClassName, snapIndicatorClassName, }: ChatWindowProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ChatWindow = ChatWindow;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_dom_1 = require("react-dom");
|
|
7
|
+
const use_drag_resize_panel_js_1 = require("../hooks/use-drag-resize-panel.js");
|
|
8
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
9
|
+
function ChatWindow({ children, title = 'Assistant', closeChatAriaLabel, className, headerClassName, bodyClassName, portal = true, open, defaultOpen = true, onOpenChange, draggable = true, resizable = true, constrainToViewport = true, width = 420, height = 640, minWidth = 320, minHeight = 420, maxWidth, maxHeight, initialPosition, snapToCenter, snapRadius, edgeThreshold, persistDimensions, header, headerActions, headerTitle, renderHeader, onPositionChange, onDimensionChange, resizeHandleClassName, snapIndicatorClassName, }) {
|
|
10
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, react_1.useState)(defaultOpen);
|
|
11
|
+
const isOpen = open ?? uncontrolledOpen;
|
|
12
|
+
// Read theme vars from context if mounted inside a provider. ChatWindow
|
|
13
|
+
// can be used standalone, so fall back to an empty object.
|
|
14
|
+
const ctx = (0, react_1.useContext)(chat_context_js_1.ChatContext);
|
|
15
|
+
const themeVars = ctx?.themeVars ?? {};
|
|
16
|
+
const themeEffect = ctx?.themeEffect;
|
|
17
|
+
const panelRef = (0, react_1.useRef)(null);
|
|
18
|
+
const { position, size, isDragging, isResizing, activeEdge, isNearSnapZone, nearEdge, handlers, } = (0, use_drag_resize_panel_js_1.useDragResizePanel)({
|
|
19
|
+
panelRef,
|
|
20
|
+
width,
|
|
21
|
+
height,
|
|
22
|
+
minWidth,
|
|
23
|
+
minHeight,
|
|
24
|
+
maxWidth,
|
|
25
|
+
maxHeight,
|
|
26
|
+
initialPosition,
|
|
27
|
+
snapToCenter,
|
|
28
|
+
snapRadius,
|
|
29
|
+
edgeThreshold,
|
|
30
|
+
persistDimensions,
|
|
31
|
+
draggable,
|
|
32
|
+
resizable,
|
|
33
|
+
});
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Notify position/dimension changes
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
(0, react_1.useEffect)(() => {
|
|
38
|
+
onPositionChange?.(position);
|
|
39
|
+
}, [position, onPositionChange]);
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
41
|
+
onDimensionChange?.(size);
|
|
42
|
+
}, [size, onDimensionChange]);
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Open/close
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
const updateOpen = (0, react_1.useCallback)((nextOpen) => {
|
|
47
|
+
if (open === undefined) {
|
|
48
|
+
setUncontrolledOpen(nextOpen);
|
|
49
|
+
}
|
|
50
|
+
onOpenChange?.(nextOpen);
|
|
51
|
+
}, [onOpenChange, open]);
|
|
52
|
+
const handleClose = (0, react_1.useCallback)(() => updateOpen(false), [updateOpen]);
|
|
53
|
+
if (!isOpen)
|
|
54
|
+
return null;
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Position style — always use translate(-50%, 0) so x means "center"
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
const positionStyle = position !== null
|
|
59
|
+
? { position: 'fixed', left: position.x, top: position.y, transform: 'translate(-50%, 0)' }
|
|
60
|
+
: { position: 'fixed', left: '50%', bottom: 16, transform: 'translate(-50%, 0)' };
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Header rendering
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
let headerContent;
|
|
65
|
+
if (renderHeader) {
|
|
66
|
+
headerContent = renderHeader({
|
|
67
|
+
onClose: handleClose,
|
|
68
|
+
isDragging,
|
|
69
|
+
onDragStart: handlers.onDragStart,
|
|
70
|
+
onDoubleClick: handlers.onDoubleClickHeader,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
headerContent = ((0, jsx_runtime_1.jsx)("header", { className: headerClassName, "data-component": "chat-window-header", onMouseDown: handlers.onDragStart, onDoubleClick: handlers.onDoubleClickHeader, children: header ?? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { "data-element": "title-wrap", children: headerTitle ?? (0, jsx_runtime_1.jsx)("strong", { "data-element": "title", children: title }) }), (0, jsx_runtime_1.jsxs)("div", { "data-element": "actions", children: [headerActions, (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: handleClose, "data-action": "close", "aria-label": closeChatAriaLabel ?? 'Close chat', title: closeChatAriaLabel ?? 'Close chat', children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) })] })] })) }));
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Content
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
const content = ((0, jsx_runtime_1.jsxs)("section", { ref: panelRef, className: className, "data-component": "chat-window", "data-theme-effect": themeEffect, style: {
|
|
80
|
+
...themeVars,
|
|
81
|
+
...positionStyle,
|
|
82
|
+
width: size.width,
|
|
83
|
+
height: size.height,
|
|
84
|
+
}, onMouseMove: handlers.onPanelMouseMove, onMouseLeave: handlers.onPanelMouseLeave, children: [resizable && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { "data-component": "chat-window-resize-handle", "data-edge": "top", className: resizeHandleClassName, style: {
|
|
85
|
+
position: 'absolute',
|
|
86
|
+
top: -4,
|
|
87
|
+
left: 16,
|
|
88
|
+
right: 16,
|
|
89
|
+
height: 12,
|
|
90
|
+
cursor: 'ns-resize',
|
|
91
|
+
display: 'flex',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
justifyContent: 'center',
|
|
94
|
+
opacity: nearEdge.top || activeEdge === 'top' ? 1 : 0,
|
|
95
|
+
transition: 'opacity 150ms',
|
|
96
|
+
zIndex: 10,
|
|
97
|
+
}, onMouseDown: handlers.onEdgeResizeStart('top') }), (0, jsx_runtime_1.jsx)("div", { "data-component": "chat-window-resize-handle", "data-edge": "left", className: resizeHandleClassName, style: {
|
|
98
|
+
position: 'absolute',
|
|
99
|
+
left: -4,
|
|
100
|
+
top: 16,
|
|
101
|
+
bottom: 16,
|
|
102
|
+
width: 12,
|
|
103
|
+
cursor: 'ew-resize',
|
|
104
|
+
display: 'flex',
|
|
105
|
+
alignItems: 'center',
|
|
106
|
+
justifyContent: 'center',
|
|
107
|
+
opacity: nearEdge.left || activeEdge === 'left' ? 1 : 0,
|
|
108
|
+
transition: 'opacity 150ms',
|
|
109
|
+
zIndex: 10,
|
|
110
|
+
}, onMouseDown: handlers.onEdgeResizeStart('left') }), (0, jsx_runtime_1.jsx)("div", { "data-component": "chat-window-resize-handle", "data-edge": "right", className: resizeHandleClassName, style: {
|
|
111
|
+
position: 'absolute',
|
|
112
|
+
right: -4,
|
|
113
|
+
top: 16,
|
|
114
|
+
bottom: 16,
|
|
115
|
+
width: 12,
|
|
116
|
+
cursor: 'ew-resize',
|
|
117
|
+
display: 'flex',
|
|
118
|
+
alignItems: 'center',
|
|
119
|
+
justifyContent: 'center',
|
|
120
|
+
opacity: nearEdge.right || activeEdge === 'right' ? 1 : 0,
|
|
121
|
+
transition: 'opacity 150ms',
|
|
122
|
+
zIndex: 10,
|
|
123
|
+
}, onMouseDown: handlers.onEdgeResizeStart('right') })] })), isDragging && isNearSnapZone && ((0, jsx_runtime_1.jsx)("div", { "data-component": "chat-window-snap-indicator", className: snapIndicatorClassName, style: {
|
|
124
|
+
position: 'absolute',
|
|
125
|
+
inset: 0,
|
|
126
|
+
borderRadius: 'inherit',
|
|
127
|
+
pointerEvents: 'none',
|
|
128
|
+
boxShadow: '0 0 0 3px rgba(99, 102, 241, 0.5)',
|
|
129
|
+
} })), headerContent, (0, jsx_runtime_1.jsx)("div", { className: bodyClassName, "data-component": "chat-window-body", children: children })] }));
|
|
130
|
+
if (portal && typeof document !== 'undefined') {
|
|
131
|
+
return (0, react_dom_1.createPortal)(content, document.body);
|
|
132
|
+
}
|
|
133
|
+
return content;
|
|
134
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface ConfirmDialogProps {
|
|
3
|
+
/** Whether the dialog is visible. */
|
|
4
|
+
open: boolean;
|
|
5
|
+
/** Short title — bold, first line. */
|
|
6
|
+
title: ReactNode;
|
|
7
|
+
/** Body message — descriptive, second line. Optional. */
|
|
8
|
+
message?: ReactNode;
|
|
9
|
+
/** Label for the primary/confirm button. Default: `'Confirm'`. */
|
|
10
|
+
confirmLabel?: string;
|
|
11
|
+
/** Label for the cancel button. Default: `'Cancel'`. */
|
|
12
|
+
cancelLabel?: string;
|
|
13
|
+
/**
|
|
14
|
+
* When true, the confirm button is styled with the danger color —
|
|
15
|
+
* use for destructive actions like delete.
|
|
16
|
+
*/
|
|
17
|
+
destructive?: boolean;
|
|
18
|
+
/** Disable the confirm button (e.g. while async work is in flight). */
|
|
19
|
+
confirmDisabled?: boolean;
|
|
20
|
+
/** Called when the user clicks Confirm or presses Enter. */
|
|
21
|
+
onConfirm: () => void;
|
|
22
|
+
/** Called when the user clicks Cancel, backdrop, or presses Escape. */
|
|
23
|
+
onCancel: () => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Themed confirmation dialog used by the built-in delete / clear flows.
|
|
27
|
+
* Replaces `window.confirm()` so the prompt matches the widget's palette
|
|
28
|
+
* and theme. Portal'd to `document.body`, keyboard-accessible (Enter to
|
|
29
|
+
* confirm, Escape to cancel), and inherits CSS theme vars from the
|
|
30
|
+
* nearest `<AiChatProvider>`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function ConfirmDialog({ open, title, message, confirmLabel, cancelLabel, destructive, confirmDisabled, onConfirm, onCancel, }: ConfirmDialogProps): import("react").ReactPortal | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfirmDialog = ConfirmDialog;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const react_dom_1 = require("react-dom");
|
|
7
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
8
|
+
/**
|
|
9
|
+
* Themed confirmation dialog used by the built-in delete / clear flows.
|
|
10
|
+
* Replaces `window.confirm()` so the prompt matches the widget's palette
|
|
11
|
+
* and theme. Portal'd to `document.body`, keyboard-accessible (Enter to
|
|
12
|
+
* confirm, Escape to cancel), and inherits CSS theme vars from the
|
|
13
|
+
* nearest `<AiChatProvider>`.
|
|
14
|
+
*/
|
|
15
|
+
function ConfirmDialog({ open, title, message, confirmLabel = 'Confirm', cancelLabel = 'Cancel', destructive = false, confirmDisabled = false, onConfirm, onCancel, }) {
|
|
16
|
+
const ctx = (0, react_1.useContext)(chat_context_js_1.ChatContext);
|
|
17
|
+
const themeVars = ctx?.themeVars ?? {};
|
|
18
|
+
const confirmBtnRef = (0, react_1.useRef)(null);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
if (!open)
|
|
21
|
+
return;
|
|
22
|
+
// Focus the confirm button so Enter commits without tabbing.
|
|
23
|
+
confirmBtnRef.current?.focus();
|
|
24
|
+
const onKey = (e) => {
|
|
25
|
+
if (e.key === 'Escape') {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
onCancel();
|
|
28
|
+
}
|
|
29
|
+
else if (e.key === 'Enter') {
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
if (!confirmDisabled)
|
|
32
|
+
onConfirm();
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
window.addEventListener('keydown', onKey);
|
|
36
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
37
|
+
}, [open, confirmDisabled, onConfirm, onCancel]);
|
|
38
|
+
if (!open)
|
|
39
|
+
return null;
|
|
40
|
+
if (typeof document === 'undefined')
|
|
41
|
+
return null;
|
|
42
|
+
const dialog = ((0, jsx_runtime_1.jsx)("div", { "data-component": "confirm-dialog-backdrop", style: themeVars, onClick: (e) => {
|
|
43
|
+
// Only close when clicking the backdrop itself, not the panel
|
|
44
|
+
if (e.target === e.currentTarget)
|
|
45
|
+
onCancel();
|
|
46
|
+
}, role: "presentation", children: (0, jsx_runtime_1.jsxs)("div", { "data-component": "confirm-dialog", "data-destructive": destructive || undefined, role: "alertdialog", "aria-modal": "true", "aria-labelledby": "confirm-dialog-title", onClick: (e) => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("div", { "data-element": "title", id: "confirm-dialog-title", children: title }), message && (0, jsx_runtime_1.jsx)("div", { "data-element": "message", children: message }), (0, jsx_runtime_1.jsxs)("div", { "data-element": "actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "data-element": "cancel", onClick: onCancel, children: cancelLabel }), (0, jsx_runtime_1.jsx)("button", { ref: confirmBtnRef, type: "button", "data-element": "confirm", "data-destructive": destructive || undefined, disabled: confirmDisabled, onClick: onConfirm, children: confirmLabel })] })] }) }));
|
|
47
|
+
return (0, react_dom_1.createPortal)(dialog, document.body);
|
|
48
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import '../styles.css';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
import type { ChatSize } from '../types.js';
|
|
4
|
+
export interface FloatingChatUIProps {
|
|
5
|
+
/** Window header title. Default: "AI Assistant" */
|
|
6
|
+
title?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Controlled open state. When provided, the component becomes a
|
|
9
|
+
* controlled component and `defaultOpen` is ignored. Pair with
|
|
10
|
+
* `onOpenChange` to drive the window from external state (e.g. a
|
|
11
|
+
* trigger button elsewhere in the page).
|
|
12
|
+
*/
|
|
13
|
+
open?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Called whenever the window wants to open or close itself — from the
|
|
16
|
+
* trigger pill, the close button, the Escape key, or the keyboard
|
|
17
|
+
* shortcut. Required to fully control `open`.
|
|
18
|
+
*/
|
|
19
|
+
onOpenChange?: (open: boolean) => void;
|
|
20
|
+
/** Whether the window starts open. Default: false */
|
|
21
|
+
defaultOpen?: boolean;
|
|
22
|
+
/** Window is draggable by its header. Default: true */
|
|
23
|
+
draggable?: boolean;
|
|
24
|
+
/** Window is resizable. Default: true */
|
|
25
|
+
resizable?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Window size — a preset (`'sm' | 'md' | 'lg' | 'xl' | 'full'`) or an
|
|
28
|
+
* explicit `{ width, height }` pair. Dimensions accept numbers (px)
|
|
29
|
+
* or CSS strings like `'40vw'`, `'70vh'`, `'32rem'` — viewport units
|
|
30
|
+
* are re-resolved on window resize.
|
|
31
|
+
*
|
|
32
|
+
* Default: `'md'` (420×640).
|
|
33
|
+
*
|
|
34
|
+
* ```tsx
|
|
35
|
+
* <LangGraphAiChat size="lg" />
|
|
36
|
+
* <LangGraphAiChat size={{ width: '40vw', height: '70vh' }} />
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
size?: ChatSize;
|
|
40
|
+
/**
|
|
41
|
+
* Hide the floating trigger pill while the chat window is open.
|
|
42
|
+
* Default: true. Set to false to keep both visible simultaneously.
|
|
43
|
+
*/
|
|
44
|
+
hideTriggerWhenOpen?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Global keyboard shortcut that toggles the window. Use `false` to
|
|
47
|
+
* disable. Defaults to `'mod+i'` (⌘I on Mac, Ctrl+I elsewhere).
|
|
48
|
+
*/
|
|
49
|
+
shortcut?: string | false;
|
|
50
|
+
/** Show the built-in clear / trash button in the header. Default: true. */
|
|
51
|
+
showClearButton?: boolean;
|
|
52
|
+
/** Ask for confirmation before clearing. Default: true. */
|
|
53
|
+
confirmClear?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Render the built-in session switcher in the header. Default: auto —
|
|
56
|
+
* shown when the provider's `session.list/create/remove` are all defined.
|
|
57
|
+
*/
|
|
58
|
+
showSessionSwitcher?: boolean | 'auto';
|
|
59
|
+
/** Replace the default header actions with a custom node. */
|
|
60
|
+
headerActions?: ReactNode;
|
|
61
|
+
/**
|
|
62
|
+
* Replace the sparkle icon on the floating trigger pill with a custom
|
|
63
|
+
* node — typically a small logo or branded SVG. Default: built-in
|
|
64
|
+
* sparkle.
|
|
65
|
+
*
|
|
66
|
+
* ```tsx
|
|
67
|
+
* <LangGraphAiChat triggerIcon={<img src="/logo.svg" width={16} height={16} />} />
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
triggerIcon?: ReactNode;
|
|
71
|
+
/**
|
|
72
|
+
* Show the mic button on the trigger pill. When unset, the mic auto-
|
|
73
|
+
* shows only if `voice.enabled` is true on the provider config. Set
|
|
74
|
+
* to `false` to force-hide (renders a single-icon trigger) or `true`
|
|
75
|
+
* to force-show.
|
|
76
|
+
*/
|
|
77
|
+
showMic?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Ephemeral assistant greeting shown only while the current session
|
|
80
|
+
* has no messages. Not persisted — forwarded to `AiChatPanel`. See
|
|
81
|
+
* `AiChatPanelProps.welcomeMessage`.
|
|
82
|
+
*/
|
|
83
|
+
welcomeMessage?: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Floating chat UI: a fixed trigger pill + a draggable, resizable chat
|
|
87
|
+
* window that opens when the pill is clicked. Must be mounted inside an
|
|
88
|
+
* `<AiChatProvider>`.
|
|
89
|
+
*/
|
|
90
|
+
export declare function FloatingChatUI({ title, open: controlledOpen, onOpenChange, defaultOpen, draggable, resizable, size, hideTriggerWhenOpen, shortcut, showClearButton, confirmClear, showSessionSwitcher, headerActions, triggerIcon, showMic, welcomeMessage, }?: FloatingChatUIProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.FloatingChatUI = FloatingChatUI;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
require("../styles.css");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const ai_trigger_button_js_1 = require("./ai-trigger-button.js");
|
|
9
|
+
const chat_window_js_1 = require("./chat-window.js");
|
|
10
|
+
const ai_chat_panel_js_1 = require("./ai-chat-panel.js");
|
|
11
|
+
const session_switcher_js_1 = require("./session-switcher.js");
|
|
12
|
+
const confirm_dialog_js_1 = require("./confirm-dialog.js");
|
|
13
|
+
const chat_context_js_1 = require("../provider/chat-context.js");
|
|
14
|
+
const use_keyboard_shortcut_js_1 = require("../hooks/use-keyboard-shortcut.js");
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Size resolution
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
const SIZE_PRESETS = {
|
|
19
|
+
sm: { width: 360, height: 560 },
|
|
20
|
+
md: { width: 420, height: 640 },
|
|
21
|
+
lg: { width: 520, height: 720 },
|
|
22
|
+
xl: { width: 640, height: 820 },
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Parse a single CSS length into a pixel count. Viewport-relative units
|
|
26
|
+
* are resolved against the supplied `vw`/`vh` values (typically from
|
|
27
|
+
* `window.innerWidth/innerHeight`). Unknown units fall back to the
|
|
28
|
+
* default.
|
|
29
|
+
*/
|
|
30
|
+
function parseDimension(value, axis, vw, vh, fallback) {
|
|
31
|
+
if (typeof value === 'number')
|
|
32
|
+
return value;
|
|
33
|
+
const trimmed = value.trim();
|
|
34
|
+
const match = trimmed.match(/^(-?[\d.]+)(px|vw|vh|%|em|rem)?$/);
|
|
35
|
+
if (!match)
|
|
36
|
+
return fallback;
|
|
37
|
+
const n = parseFloat(match[1]);
|
|
38
|
+
const unit = (match[2] ?? 'px');
|
|
39
|
+
switch (unit) {
|
|
40
|
+
case 'vw':
|
|
41
|
+
return (vw * n) / 100;
|
|
42
|
+
case 'vh':
|
|
43
|
+
return (vh * n) / 100;
|
|
44
|
+
case '%':
|
|
45
|
+
// `%` in this context means percentage of the relevant viewport axis.
|
|
46
|
+
return ((axis === 'w' ? vw : vh) * n) / 100;
|
|
47
|
+
case 'em':
|
|
48
|
+
case 'rem':
|
|
49
|
+
return n * 16;
|
|
50
|
+
case 'px':
|
|
51
|
+
default:
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function resolveSize(size, vw, vh) {
|
|
56
|
+
if (size === undefined) {
|
|
57
|
+
return { ...SIZE_PRESETS.md, fullscreen: false };
|
|
58
|
+
}
|
|
59
|
+
if (size === 'full') {
|
|
60
|
+
return { width: vw, height: vh, fullscreen: true };
|
|
61
|
+
}
|
|
62
|
+
if (typeof size === 'string') {
|
|
63
|
+
const preset = SIZE_PRESETS[size] ?? SIZE_PRESETS.md;
|
|
64
|
+
return { ...preset, fullscreen: false };
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
width: parseDimension(size.width, 'w', vw, vh, SIZE_PRESETS.md.width),
|
|
68
|
+
height: parseDimension(size.height, 'h', vw, vh, SIZE_PRESETS.md.height),
|
|
69
|
+
fullscreen: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Track `window.innerWidth`/`innerHeight` with a render on resize so
|
|
74
|
+
* viewport-relative sizes (`40vw`, `70vh`, `'full'`) re-resolve as the
|
|
75
|
+
* browser window changes shape.
|
|
76
|
+
*/
|
|
77
|
+
function useViewportSize() {
|
|
78
|
+
const [size, setSize] = (0, react_1.useState)(() => ({
|
|
79
|
+
vw: typeof window !== 'undefined' ? window.innerWidth : 1024,
|
|
80
|
+
vh: typeof window !== 'undefined' ? window.innerHeight : 768,
|
|
81
|
+
}));
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
if (typeof window === 'undefined')
|
|
84
|
+
return;
|
|
85
|
+
const onResize = () => {
|
|
86
|
+
setSize({ vw: window.innerWidth, vh: window.innerHeight });
|
|
87
|
+
};
|
|
88
|
+
window.addEventListener('resize', onResize);
|
|
89
|
+
return () => window.removeEventListener('resize', onResize);
|
|
90
|
+
}, []);
|
|
91
|
+
return size;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Floating chat UI: a fixed trigger pill + a draggable, resizable chat
|
|
95
|
+
* window that opens when the pill is clicked. Must be mounted inside an
|
|
96
|
+
* `<AiChatProvider>`.
|
|
97
|
+
*/
|
|
98
|
+
function FloatingChatUI({ title, open: controlledOpen, onOpenChange, defaultOpen = false, draggable = true, resizable = true, size, hideTriggerWhenOpen = true, shortcut = 'mod+i', showClearButton = true, confirmClear = true, showSessionSwitcher = 'auto', headerActions, triggerIcon, showMic, welcomeMessage, } = {}) {
|
|
99
|
+
const { classNames, locale, voice, sessionsSupported } = (0, chat_context_js_1.useChatContext)();
|
|
100
|
+
const { vw, vh } = useViewportSize();
|
|
101
|
+
const resolvedSize = resolveSize(size, vw, vh);
|
|
102
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, react_1.useState)(defaultOpen);
|
|
103
|
+
const isControlled = controlledOpen !== undefined;
|
|
104
|
+
const open = isControlled ? controlledOpen : uncontrolledOpen;
|
|
105
|
+
const setOpen = (0, react_1.useCallback)((next) => {
|
|
106
|
+
const resolved = typeof next === 'function'
|
|
107
|
+
? next(open)
|
|
108
|
+
: next;
|
|
109
|
+
if (!isControlled)
|
|
110
|
+
setUncontrolledOpen(resolved);
|
|
111
|
+
onOpenChange?.(resolved);
|
|
112
|
+
}, [isControlled, onOpenChange, open]);
|
|
113
|
+
const noop = (0, react_1.useCallback)(() => { }, []);
|
|
114
|
+
(0, use_keyboard_shortcut_js_1.useKeyboardShortcut)(shortcut, () => setOpen((v) => !v));
|
|
115
|
+
(0, use_keyboard_shortcut_js_1.useKeyboardShortcut)('escape', () => setOpen(false), { enabled: open });
|
|
116
|
+
// Was the title prop explicitly set by the consumer? (vs using the
|
|
117
|
+
// locale fallback.) Drives the "title + switcher coexist" branch.
|
|
118
|
+
const hasConsumerTitle = title !== undefined;
|
|
119
|
+
const resolvedTitle = title ?? locale.chatTitle;
|
|
120
|
+
const switcherIsOn = showSessionSwitcher === true ||
|
|
121
|
+
(showSessionSwitcher === 'auto' && sessionsSupported);
|
|
122
|
+
// When both a consumer title AND a session switcher exist, the title
|
|
123
|
+
// holds the main header slot and the switcher moves into the actions
|
|
124
|
+
// strip so they don't fight for the same real estate.
|
|
125
|
+
const renderSwitcherInActions = hasConsumerTitle && switcherIsOn;
|
|
126
|
+
// Auto-hide the mic when the consumer didn't opt into voice. Explicit
|
|
127
|
+
// `showMic` prop always wins.
|
|
128
|
+
const effectiveShowMic = showMic ?? Boolean(voice?.enabled);
|
|
129
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(!hideTriggerWhenOpen || !open) && ((0, jsx_runtime_1.jsx)(ai_trigger_button_js_1.AiTriggerButton, { onClickChat: () => setOpen(true), onClickMic: noop, showMic: effectiveShowMic, icon: triggerIcon, className: classNames.trigger, buttonClassName: classNames.triggerPill, ariaLabel: locale.triggerAriaLabel, micAriaLabel: locale.micAriaLabel, stopAriaLabel: locale.stopRecordingAriaLabel, cancelAriaLabel: locale.cancelRecordingAriaLabel })), (0, jsx_runtime_1.jsx)(chat_window_js_1.ChatWindow, { open: open, onOpenChange: setOpen, title: resolvedTitle, closeChatAriaLabel: locale.closeChatAriaLabel, draggable: draggable && !resolvedSize.fullscreen, resizable: resizable && !resolvedSize.fullscreen, width: resolvedSize.width, height: resolvedSize.height, className: classNames.window, headerClassName: classNames.windowHeader, bodyClassName: classNames.windowBody, headerTitle: renderSwitcherInActions ? ((0, jsx_runtime_1.jsx)("strong", { "data-element": "title", children: resolvedTitle })) : ((0, jsx_runtime_1.jsx)(FloatingHeaderTitle, { fallback: resolvedTitle, showSessionSwitcher: showSessionSwitcher, className: classNames.switcher })), headerActions: headerActions ?? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [renderSwitcherInActions && ((0, jsx_runtime_1.jsx)(session_switcher_js_1.SessionSwitcher, { className: classNames.switcher })), (0, jsx_runtime_1.jsx)(FloatingHeaderActions, { showClearButton: showClearButton, confirmClear: confirmClear })] })), children: (0, jsx_runtime_1.jsx)(ai_chat_panel_js_1.AiChatPanel, { welcomeMessage: welcomeMessage }) })] }));
|
|
130
|
+
}
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Header sub-components — must live inside the provider so they can read
|
|
133
|
+
// the chat context (clear(), sessions, etc).
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
function FloatingHeaderTitle({ fallback, showSessionSwitcher, className, }) {
|
|
136
|
+
const ctx = (0, chat_context_js_1.useChatContext)();
|
|
137
|
+
const shouldShow = showSessionSwitcher === true ||
|
|
138
|
+
(showSessionSwitcher === 'auto' && ctx.sessionsSupported);
|
|
139
|
+
if (!shouldShow) {
|
|
140
|
+
return (0, jsx_runtime_1.jsx)("strong", { "data-element": "title", children: fallback });
|
|
141
|
+
}
|
|
142
|
+
return (0, jsx_runtime_1.jsx)(session_switcher_js_1.SessionSwitcher, { fallbackTitle: fallback, className: className });
|
|
143
|
+
}
|
|
144
|
+
function FloatingHeaderActions({ showClearButton, confirmClear, }) {
|
|
145
|
+
const { clear, messages, locale } = (0, chat_context_js_1.useChatContext)();
|
|
146
|
+
const [confirmOpen, setConfirmOpen] = (0, react_1.useState)(false);
|
|
147
|
+
if (!showClearButton)
|
|
148
|
+
return null;
|
|
149
|
+
const disabled = messages.length === 0;
|
|
150
|
+
const onClick = () => {
|
|
151
|
+
if (disabled)
|
|
152
|
+
return;
|
|
153
|
+
if (confirmClear) {
|
|
154
|
+
setConfirmOpen(true);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
clear();
|
|
158
|
+
};
|
|
159
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { type: "button", onClick: onClick, "data-action": "clear", "aria-label": locale.clearChatAriaLabel, title: locale.clearChatAriaLabel, disabled: disabled, children: (0, jsx_runtime_1.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("polyline", { points: "3 6 5 6 21 6" }), (0, jsx_runtime_1.jsx)("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 11v6" }), (0, jsx_runtime_1.jsx)("path", { d: "M14 11v6" }), (0, jsx_runtime_1.jsx)("path", { d: "M9 6V4a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2" })] }) }), (0, jsx_runtime_1.jsx)(confirm_dialog_js_1.ConfirmDialog, { open: confirmOpen, title: locale.confirmClearPrompt, confirmLabel: locale.clearButton, cancelLabel: locale.cancelButton, destructive: true, onConfirm: () => {
|
|
160
|
+
setConfirmOpen(false);
|
|
161
|
+
clear();
|
|
162
|
+
}, onCancel: () => setConfirmOpen(false) })] }));
|
|
163
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MentionChipProps, MentionChipListProps } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Inline mention chip for displaying referenced entities.
|
|
4
|
+
*
|
|
5
|
+
* Renders with data-attributes for styling by the host app:
|
|
6
|
+
* - `data-component="mention-chip"`
|
|
7
|
+
* - `data-mention-type` — the mention type (task, person, group, command, etc.)
|
|
8
|
+
* - `data-size` — "inline" | "compact" | "default"
|
|
9
|
+
*
|
|
10
|
+
* Sub-elements: icon, prefix, display-name, remove button.
|
|
11
|
+
*/
|
|
12
|
+
export declare function MentionChip({ mention, onRemove, className, compact, inline, }: MentionChipProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
/**
|
|
14
|
+
* List of mention chips wrapped in a container.
|
|
15
|
+
*/
|
|
16
|
+
export declare function MentionChipList({ mentions, onRemove, className, }: MentionChipListProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MentionChip = MentionChip;
|
|
4
|
+
exports.MentionChipList = MentionChipList;
|
|
5
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
6
|
+
/**
|
|
7
|
+
* Inline mention chip for displaying referenced entities.
|
|
8
|
+
*
|
|
9
|
+
* Renders with data-attributes for styling by the host app:
|
|
10
|
+
* - `data-component="mention-chip"`
|
|
11
|
+
* - `data-mention-type` — the mention type (task, person, group, command, etc.)
|
|
12
|
+
* - `data-size` — "inline" | "compact" | "default"
|
|
13
|
+
*
|
|
14
|
+
* Sub-elements: icon, prefix, display-name, remove button.
|
|
15
|
+
*/
|
|
16
|
+
function MentionChip({ mention, onRemove, className, compact = false, inline = false, }) {
|
|
17
|
+
const size = inline ? 'inline' : compact ? 'compact' : 'default';
|
|
18
|
+
const prefix = mention.prefix ?? (mention.type === 'task' || mention.type === 'command' ? '/' : '@');
|
|
19
|
+
return ((0, jsx_runtime_1.jsxs)("span", { className: className, "data-component": "mention-chip", "data-mention-type": mention.type, "data-size": size, children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "icon" }), (0, jsx_runtime_1.jsxs)("span", { "data-element": "display-name", children: [(0, jsx_runtime_1.jsx)("span", { "data-element": "prefix", children: prefix }), mention.displayName] }), onRemove && ((0, jsx_runtime_1.jsxs)("button", { type: "button", onClick: (e) => {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
e.stopPropagation();
|
|
22
|
+
onRemove();
|
|
23
|
+
}, "data-action": "remove", children: ['\u00D7', (0, jsx_runtime_1.jsx)("span", { style: {
|
|
24
|
+
position: 'absolute',
|
|
25
|
+
width: 1,
|
|
26
|
+
height: 1,
|
|
27
|
+
padding: 0,
|
|
28
|
+
margin: -1,
|
|
29
|
+
overflow: 'hidden',
|
|
30
|
+
clip: 'rect(0,0,0,0)',
|
|
31
|
+
whiteSpace: 'nowrap',
|
|
32
|
+
borderWidth: 0,
|
|
33
|
+
}, children: "Remove" })] }))] }));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* List of mention chips wrapped in a container.
|
|
37
|
+
*/
|
|
38
|
+
function MentionChipList({ mentions, onRemove, className, }) {
|
|
39
|
+
if (mentions.length === 0)
|
|
40
|
+
return null;
|
|
41
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: className, "data-component": "mention-chip-list", children: mentions.map((mention) => ((0, jsx_runtime_1.jsx)(MentionChip, { mention: mention, onRemove: onRemove ? () => onRemove(mention.id) : undefined }, mention.id))) }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MentionInputProps } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Chat input with mention autocomplete support.
|
|
4
|
+
*
|
|
5
|
+
* Uses `RichMentionInput` for editing, provides autocomplete for `@` and `/`,
|
|
6
|
+
* and keeps selected mentions in provider state for serialization on send.
|
|
7
|
+
*/
|
|
8
|
+
export declare function MentionInput({ className, onSubmit }: MentionInputProps): import("react/jsx-runtime").JSX.Element;
|