@nuraly/runtime 0.1.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 +778 -0
- package/components/index.ts +13 -0
- package/components/ui/components/Event/EventAttribute/EventAttribute.style.ts +11 -0
- package/components/ui/components/Event/EventAttribute/EventAttribute.ts +28 -0
- package/components/ui/components/Event/EventLabel/EventLabel.ts +19 -0
- package/components/ui/components/Event/EventValue/EventValue.ts +79 -0
- package/components/ui/components/ToastContainer/ToastContainer.ts +126 -0
- package/components/ui/components/advanced/AIChat/AIChat.helper.ts +22 -0
- package/components/ui/components/advanced/AIChat/AIChat.style.ts +52 -0
- package/components/ui/components/advanced/AIChat/AIChat.ts +143 -0
- package/components/ui/components/advanced/CodeEditor/CodeEditor.ts +489 -0
- package/components/ui/components/advanced/Collapse/Collapse.ts +86 -0
- package/components/ui/components/advanced/Collections/Collections.style.ts +21 -0
- package/components/ui/components/advanced/Collections/Collections.ts +125 -0
- package/components/ui/components/advanced/MicroApp/MicroApp.ts +98 -0
- package/components/ui/components/advanced/RefComponent/RefComponent.ts +86 -0
- package/components/ui/components/advanced/RichText/RichText.ts +98 -0
- package/components/ui/components/advanced/RichText/RichTextEditor.ts +536 -0
- package/components/ui/components/base/BaseElement/base-change-detection.ts +18 -0
- package/components/ui/components/base/BaseElement/calculateStyles.ts +31 -0
- package/components/ui/components/base/BaseElement/drag-events.helpers.ts +71 -0
- package/components/ui/components/base/BaseElement/execute-event.helpers.ts +45 -0
- package/components/ui/components/base/BaseElement/handler-component-error.ts +28 -0
- package/components/ui/components/base/BaseElement/input-handler.helpers.ts +358 -0
- package/components/ui/components/base/BaseElement/interactions.helpers.ts +14 -0
- package/components/ui/components/base/BaseElement.ts +711 -0
- package/components/ui/components/display/Badge/Badge.ts +61 -0
- package/components/ui/components/display/BoxModel/BoxModel.ts +372 -0
- package/components/ui/components/display/Code/Code.ts +103 -0
- package/components/ui/components/display/Divider/Divider.ts +98 -0
- package/components/ui/components/display/Icon/Icon.ts +60 -0
- package/components/ui/components/display/Image/Image.ts +75 -0
- package/components/ui/components/display/Table/Table.style.ts +0 -0
- package/components/ui/components/display/Table/Table.ts +178 -0
- package/components/ui/components/display/Tag/Tag.ts +49 -0
- package/components/ui/components/display/TextLabel/TextLabel.style.ts +21 -0
- package/components/ui/components/display/TextLabel/TextLabel.ts +72 -0
- package/components/ui/components/display/Video/Video.ts +46 -0
- package/components/ui/components/inputs/Button/Button.style.ts +0 -0
- package/components/ui/components/inputs/Button/Button.ts +79 -0
- package/components/ui/components/inputs/Checkbox/Checkbox.ts +76 -0
- package/components/ui/components/inputs/ColorPicker/colorpicker.ts +65 -0
- package/components/ui/components/inputs/DatePicker/DatePicker.ts +60 -0
- package/components/ui/components/inputs/Dropdown/Dropdown.ts +128 -0
- package/components/ui/components/inputs/FileUpload/FileUpload.ts +43 -0
- package/components/ui/components/inputs/IconButton/iconbutton.ts +54 -0
- package/components/ui/components/inputs/IconPicker/IconPicker.style.ts +109 -0
- package/components/ui/components/inputs/IconPicker/IconPicker.ts +61 -0
- package/components/ui/components/inputs/InsertDropdown/InsertDropdown.ts +75 -0
- package/components/ui/components/inputs/NumberInput/NumberInput.ts +84 -0
- package/components/ui/components/inputs/RadioButton/Radio-button.ts +69 -0
- package/components/ui/components/inputs/Select/Select.ts +65 -0
- package/components/ui/components/inputs/Slider/Slider.ts +63 -0
- package/components/ui/components/inputs/TextInput/TextInput.style.ts +0 -0
- package/components/ui/components/inputs/TextInput/TextInput.ts +153 -0
- package/components/ui/components/inputs/Textarea/Textarea.ts +110 -0
- package/components/ui/components/inputs/UsersDropdown/UsersDropdown.ts +30 -0
- package/components/ui/components/layout/Card/Card.ts +46 -0
- package/components/ui/components/layout/Containers/Container.style.ts +34 -0
- package/components/ui/components/layout/Containers/Container.ts +127 -0
- package/components/ui/components/layout/Panel/Panel.ts +156 -0
- package/components/ui/components/layout/Panel/index.ts +1 -0
- package/components/ui/components/layout/Tabs/Tabs.style.ts +5 -0
- package/components/ui/components/layout/Tabs/Tabs.ts +120 -0
- package/components/ui/components/navigation/EmbedURL/EmbedURL.ts +108 -0
- package/components/ui/components/navigation/Link/Link.ts +83 -0
- package/components/ui/components/navigation/Menu/Menu.ts +92 -0
- package/components/ui/components/runtime/MicroApp/MicroApp.ts +485 -0
- package/components/ui/components/runtime/MicroApp/MicroAppDataLoader.ts +240 -0
- package/components/ui/components/utility/Border/Border.ts +643 -0
- package/components/ui/components/utility/BoxShadow/BoxShadow.ts +253 -0
- package/components/ui/components/utility/Document/Document.ts +47 -0
- package/components/ui/components/utility/Export-Import/Export-Import.ts +122 -0
- package/components/ui/components/utility/Function/InvokeFunction.ts +63 -0
- package/components/ui/components/utility/Handlers/Handlers.style.ts +0 -0
- package/components/ui/components/utility/Handlers/Handlers.ts +200 -0
- package/components/ui/components/wrappers/ComponentTitle/ComponentTitle.ts +95 -0
- package/components/ui/components/wrappers/GenerikWrapper/DragWrapper/DragWrapper.style.ts +17 -0
- package/components/ui/components/wrappers/GenerikWrapper/DragWrapper/DragWrapper.ts +230 -0
- package/components/ui/components/wrappers/GenerikWrapper/GenerikWrapper.style.ts +135 -0
- package/components/ui/components/wrappers/GenerikWrapper/GenerikWrapper.ts +230 -0
- package/components/ui/components/wrappers/GenerikWrapper/QuickActionWrapper/QuickActionWrapper.style.ts +99 -0
- package/components/ui/components/wrappers/GenerikWrapper/QuickActionWrapper/QuickActionWrapper.ts +94 -0
- package/components/ui/components/wrappers/GenerikWrapper/ResizeWrapper/ResizeWrapper.style.ts +102 -0
- package/components/ui/components/wrappers/GenerikWrapper/ResizeWrapper/ResizeWrapper.ts +258 -0
- package/components/ui/components/wrappers/PreviewWrapper.ts +28 -0
- package/components/ui/components/wrappers/RectangleSelection/RectangleSelection.ts +154 -0
- package/components/ui/nuraly-ui/.storybook/main.ts +31 -0
- package/components/ui/nuraly-ui/.storybook/manager.ts +17 -0
- package/components/ui/nuraly-ui/.storybook/preview.ts +94 -0
- package/components/ui/nuraly-ui/LICENSE +28 -0
- package/components/ui/nuraly-ui/README.md +248 -0
- package/components/ui/nuraly-ui/examples/README.md +413 -0
- package/components/ui/nuraly-ui/packages/common/README.md +137 -0
- package/components/ui/nuraly-ui/packages/common/dist/constants/index.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/constants.js +7 -0
- package/components/ui/nuraly-ui/packages/common/dist/controllers/index.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/controllers.js +22 -0
- package/components/ui/nuraly-ui/packages/common/dist/index.js +27 -0
- package/components/ui/nuraly-ui/packages/common/dist/mixins/index.js +3 -0
- package/components/ui/nuraly-ui/packages/common/dist/mixins.js +29 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/base-mixin.js +38 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/constants.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/dropdown.controller.js +341 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/dropdown.interface.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/index.js +4 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/controllers/theme.controller.js +133 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/dependency-mixin.js +141 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/event-handler-mixin.js +95 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/index.js +17 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/theme-mixin.js +194 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/themes.js +85 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/utils.js +85 -0
- package/components/ui/nuraly-ui/packages/common/dist/shared/validation.types.js +17 -0
- package/components/ui/nuraly-ui/packages/common/dist/themes/index.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/themes.js +23 -0
- package/components/ui/nuraly-ui/packages/common/dist/utils/index.js +2 -0
- package/components/ui/nuraly-ui/packages/common/dist/utils.js +22 -0
- package/components/ui/nuraly-ui/packages/forms/README.md +84 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/LICENSE +15 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/README.md +294 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/copy/copy-sync.js +171 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/copy/copy.js +175 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/copy/index.js +7 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/empty/index.js +39 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/file.js +66 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/index.js +23 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/link.js +64 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/symlink-paths.js +101 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/symlink-type.js +34 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/ensure/symlink.js +67 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/fs/index.js +146 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/index.js +16 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/json/index.js +16 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/json/jsonfile.js +11 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/json/output-json-sync.js +12 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/json/output-json.js +12 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/mkdirs/index.js +14 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/mkdirs/make-dir.js +27 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/mkdirs/utils.js +21 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/move/index.js +7 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/move/move-sync.js +55 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/move/move.js +59 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/output-file/index.js +31 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/path-exists/index.js +12 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/remove/index.js +17 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/util/async.js +29 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/util/stat.js +159 -0
- package/components/ui/nuraly-ui/packages/forms/node_modules/fs-extra/lib/util/utimes.js +36 -0
- package/components/ui/nuraly-ui/packages/layout/README.md +77 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/LICENSE +15 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/README.md +294 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/copy/copy-sync.js +171 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/copy/copy.js +175 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/copy/index.js +7 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/empty/index.js +39 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/file.js +66 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/index.js +23 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/link.js +64 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/symlink-paths.js +101 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/symlink-type.js +34 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/ensure/symlink.js +67 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/fs/index.js +146 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/index.js +16 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/json/index.js +16 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/json/jsonfile.js +11 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/json/output-json-sync.js +12 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/json/output-json.js +12 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/mkdirs/index.js +14 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/mkdirs/make-dir.js +27 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/mkdirs/utils.js +21 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/move/index.js +7 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/move/move-sync.js +55 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/move/move.js +59 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/output-file/index.js +31 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/path-exists/index.js +12 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/remove/index.js +17 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/util/async.js +29 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/util/stat.js +159 -0
- package/components/ui/nuraly-ui/packages/layout/node_modules/fs-extra/lib/util/utimes.js +36 -0
- package/components/ui/nuraly-ui/packages/themes/README.md +146 -0
- package/components/ui/nuraly-ui/packages/themes/scripts/build.js +444 -0
- package/components/ui/nuraly-ui/rollup.config.js +144 -0
- package/components/ui/nuraly-ui/src/components/alert/README.md +236 -0
- package/components/ui/nuraly-ui/src/components/alert/alert.component.ts +225 -0
- package/components/ui/nuraly-ui/src/components/alert/alert.stories.ts +466 -0
- package/components/ui/nuraly-ui/src/components/alert/alert.style.ts +192 -0
- package/components/ui/nuraly-ui/src/components/alert/alert.types.ts +57 -0
- package/components/ui/nuraly-ui/src/components/alert/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/alert/react.ts +17 -0
- package/components/ui/nuraly-ui/src/components/badge/README.md +319 -0
- package/components/ui/nuraly-ui/src/components/badge/badge.component.ts +314 -0
- package/components/ui/nuraly-ui/src/components/badge/badge.stories.ts +582 -0
- package/components/ui/nuraly-ui/src/components/badge/badge.style.ts +250 -0
- package/components/ui/nuraly-ui/src/components/badge/badge.types.ts +100 -0
- package/components/ui/nuraly-ui/src/components/badge/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/badge/react.ts +9 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/README.md +243 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/breadcrumb.component.ts +280 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/breadcrumb.stories.ts +389 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/breadcrumb.style.ts +154 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/breadcrumb.types.ts +66 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/breadcrumb/react.ts +11 -0
- package/components/ui/nuraly-ui/src/components/button/README.md +331 -0
- package/components/ui/nuraly-ui/src/components/button/button.component.ts +317 -0
- package/components/ui/nuraly-ui/src/components/button/button.stories.ts +861 -0
- package/components/ui/nuraly-ui/src/components/button/button.style.ts +520 -0
- package/components/ui/nuraly-ui/src/components/button/button.types.ts +68 -0
- package/components/ui/nuraly-ui/src/components/button/controllers/base.controller.ts +99 -0
- package/components/ui/nuraly-ui/src/components/button/controllers/index.ts +10 -0
- package/components/ui/nuraly-ui/src/components/button/controllers/keyboard.controller.ts +89 -0
- package/components/ui/nuraly-ui/src/components/button/controllers/link.controller.ts +86 -0
- package/components/ui/nuraly-ui/src/components/button/controllers/ripple.controller.ts +79 -0
- package/components/ui/nuraly-ui/src/components/button/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/button/interfaces/base-controller.interface.ts +67 -0
- package/components/ui/nuraly-ui/src/components/button/interfaces/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/button/react.ts +11 -0
- package/components/ui/nuraly-ui/src/components/button/test/nr-button_test.ts +90 -0
- package/components/ui/nuraly-ui/src/components/canvas/canvas.component.ts +306 -0
- package/components/ui/nuraly-ui/src/components/canvas/demo/canvas-demo.ts +18 -0
- package/components/ui/nuraly-ui/src/components/canvas/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/canvas/react.ts +13 -0
- package/components/ui/nuraly-ui/src/components/card/card.component.ts +50 -0
- package/components/ui/nuraly-ui/src/components/card/card.stories.ts +360 -0
- package/components/ui/nuraly-ui/src/components/card/card.style.ts +62 -0
- package/components/ui/nuraly-ui/src/components/card/card.types.ts +17 -0
- package/components/ui/nuraly-ui/src/components/card/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/card/react.ts +12 -0
- package/components/ui/nuraly-ui/src/components/carousel/carousel.component.ts +116 -0
- package/components/ui/nuraly-ui/src/components/carousel/carousel.style.ts +69 -0
- package/components/ui/nuraly-ui/src/components/carousel/demo/carousel-demo.ts +59 -0
- package/components/ui/nuraly-ui/src/components/carousel/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/carousel/react.ts +12 -0
- package/components/ui/nuraly-ui/src/components/chatbot/README.md +527 -0
- package/components/ui/nuraly-ui/src/components/chatbot/chatbot.component.ts +730 -0
- package/components/ui/nuraly-ui/src/components/chatbot/chatbot.stories.ts +2549 -0
- package/components/ui/nuraly-ui/src/components/chatbot/chatbot.style.ts +1272 -0
- package/components/ui/nuraly-ui/src/components/chatbot/chatbot.types.ts +269 -0
- package/components/ui/nuraly-ui/src/components/chatbot/controllers/index.ts +9 -0
- package/components/ui/nuraly-ui/src/components/chatbot/controllers/scroll.controller.ts +59 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/README.md +550 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/chatbot-core.controller.ts +918 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/event-bus.ts +104 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/file-handler.ts +79 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/index.ts +12 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/message-handler.ts +117 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/module-handler.ts +49 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/state-handler.ts +152 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/suggestion-handler.ts +38 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/handlers/thread-handler.ts +153 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/index.ts +47 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/localization.service.ts +20 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/plugin.service.ts +103 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/provider.service.ts +342 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/storage.service.ts +122 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/services/validation.service.ts +107 -0
- package/components/ui/nuraly-ui/src/components/chatbot/core/types.ts +456 -0
- package/components/ui/nuraly-ui/src/components/chatbot/file-upload-validation.stories.ts +278 -0
- package/components/ui/nuraly-ui/src/components/chatbot/index.ts +27 -0
- package/components/ui/nuraly-ui/src/components/chatbot/locales/generated/ar.ts +19 -0
- package/components/ui/nuraly-ui/src/components/chatbot/locales/generated/fr.ts +19 -0
- package/components/ui/nuraly-ui/src/components/chatbot/locales/locale-codes.ts +25 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/analytics-plugin.ts +63 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/chat-plugin.ts +76 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/flight-card-plugin.ts +636 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/flight-card.stories.ts +929 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/index.ts +14 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/markdown-plugin.stories.ts +155 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/markdown-plugin.ts +103 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/persistence-plugin.ts +97 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/print-job-card-plugin.ts +537 -0
- package/components/ui/nuraly-ui/src/components/chatbot/plugins/print-job-card.stories.ts +649 -0
- package/components/ui/nuraly-ui/src/components/chatbot/providers/custom-api-provider.ts +239 -0
- package/components/ui/nuraly-ui/src/components/chatbot/providers/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/chatbot/providers/mock-provider.ts +433 -0
- package/components/ui/nuraly-ui/src/components/chatbot/providers/openai-provider.ts +239 -0
- package/components/ui/nuraly-ui/src/components/chatbot/react.ts +57 -0
- package/components/ui/nuraly-ui/src/components/chatbot/storage/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/chatbot/storage/storage-implementations.ts +167 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/chatbot-main.template.ts +157 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/file-preview-modal.template.ts +90 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/file-upload-area.template.ts +43 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/index.ts +14 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/input-box.template.ts +267 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/message.template.ts +240 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/suggestion.template.ts +57 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/thread-sidebar.template.ts +67 -0
- package/components/ui/nuraly-ui/src/components/chatbot/templates/url-modal.template.ts +121 -0
- package/components/ui/nuraly-ui/src/components/checkbox/checkbox.component.ts +173 -0
- package/components/ui/nuraly-ui/src/components/checkbox/checkbox.stories.ts +521 -0
- package/components/ui/nuraly-ui/src/components/checkbox/checkbox.style.ts +324 -0
- package/components/ui/nuraly-ui/src/components/checkbox/checkbox.types.ts +5 -0
- package/components/ui/nuraly-ui/src/components/checkbox/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/checkbox/mixins/checkbox-event-mixin.ts +180 -0
- package/components/ui/nuraly-ui/src/components/checkbox/mixins/checkbox-focus-mixin.ts +99 -0
- package/components/ui/nuraly-ui/src/components/checkbox/mixins/index.ts +27 -0
- package/components/ui/nuraly-ui/src/components/checkbox/react.ts +12 -0
- package/components/ui/nuraly-ui/src/components/checkbox/test/checkbox_test.ts +97 -0
- package/components/ui/nuraly-ui/src/components/collapse/collapse.component.ts +315 -0
- package/components/ui/nuraly-ui/src/components/collapse/collapse.stories.ts +738 -0
- package/components/ui/nuraly-ui/src/components/collapse/collapse.style.ts +236 -0
- package/components/ui/nuraly-ui/src/components/collapse/collapse.type.ts +95 -0
- package/components/ui/nuraly-ui/src/components/collapse/controllers/accordion.controller.ts +169 -0
- package/components/ui/nuraly-ui/src/components/collapse/controllers/animation.controller.ts +129 -0
- package/components/ui/nuraly-ui/src/components/collapse/controllers/base.controller.ts +114 -0
- package/components/ui/nuraly-ui/src/components/collapse/controllers/index.ts +15 -0
- package/components/ui/nuraly-ui/src/components/collapse/controllers/keyboard.controller.ts +212 -0
- package/components/ui/nuraly-ui/src/components/collapse/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/collapse/react.ts +13 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-holder.component.ts +104 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-holder.style.ts +46 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-picker.component.ts +398 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-picker.stories.ts +888 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-picker.style.ts +86 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/color-picker.types.ts +64 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/controllers/base.controller.ts +64 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/controllers/dropdown.controller.ts +268 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/controllers/event.controller.ts +147 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/controllers/index.ts +3 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/default-color-sets.component.ts +119 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/default-color-sets.style.ts +35 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/interfaces/index.ts +67 -0
- package/components/ui/nuraly-ui/src/components/colorpicker/react.ts +13 -0
- package/components/ui/nuraly-ui/src/components/console/react.ts +12 -0
- package/components/ui/nuraly-ui/src/components/datepicker/README.md +60 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/calendar.controller.ts +252 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/keyboard.controller.ts +290 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/month-year-dropdown.controller.ts +108 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/positioning.controller.ts +278 -0
- package/components/ui/nuraly-ui/src/components/datepicker/controllers/selection.controller.ts +303 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.component.ts +659 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.constant.ts +81 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.stories.ts +461 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.style.ts +456 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.style.variables.ts +119 -0
- package/components/ui/nuraly-ui/src/components/datepicker/datepicker.types.ts +154 -0
- package/components/ui/nuraly-ui/src/components/datepicker/index.ts +3 -0
- package/components/ui/nuraly-ui/src/components/datepicker/interfaces/base-controller.interface.ts +42 -0
- package/components/ui/nuraly-ui/src/components/datepicker/interfaces/datepicker-controllers.interface.ts +128 -0
- package/components/ui/nuraly-ui/src/components/datepicker/interfaces/index.ts +15 -0
- package/components/ui/nuraly-ui/src/components/datepicker/react.ts +24 -0
- package/components/ui/nuraly-ui/src/components/datepicker/templates/days.template.ts +57 -0
- package/components/ui/nuraly-ui/src/components/datepicker/templates/dropdown.template.ts +61 -0
- package/components/ui/nuraly-ui/src/components/datepicker/templates/headers.template.ts +7 -0
- package/components/ui/nuraly-ui/src/components/datepicker/templates/months.template.ts +16 -0
- package/components/ui/nuraly-ui/src/components/datepicker/templates/years.template.ts +18 -0
- package/components/ui/nuraly-ui/src/components/datepicker/test/datepicker_test.ts +124 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/day.helper.ts +56 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/formatter.ts +8 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/locale.helper.ts +152 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/month.helper.ts +26 -0
- package/components/ui/nuraly-ui/src/components/datepicker/utils/string.helper.ts +3 -0
- package/components/ui/nuraly-ui/src/components/divider/divider.component.ts +172 -0
- package/components/ui/nuraly-ui/src/components/divider/divider.stories.ts +271 -0
- package/components/ui/nuraly-ui/src/components/divider/divider.style.ts +139 -0
- package/components/ui/nuraly-ui/src/components/divider/divider.types.ts +59 -0
- package/components/ui/nuraly-ui/src/components/divider/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/divider/react.ts +9 -0
- package/components/ui/nuraly-ui/src/components/document/demo/document-demo.ts +28 -0
- package/components/ui/nuraly-ui/src/components/document/document.component.ts +133 -0
- package/components/ui/nuraly-ui/src/components/document/document.stories.ts +266 -0
- package/components/ui/nuraly-ui/src/components/document/document.style.ts +210 -0
- package/components/ui/nuraly-ui/src/components/document/document.types.ts +83 -0
- package/components/ui/nuraly-ui/src/components/document/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/document/react.ts +15 -0
- package/components/ui/nuraly-ui/src/components/dropdown/controllers/base.controller.ts +85 -0
- package/components/ui/nuraly-ui/src/components/dropdown/controllers/dropdown.controller.ts +476 -0
- package/components/ui/nuraly-ui/src/components/dropdown/controllers/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/dropdown/dropdown.component.ts +348 -0
- package/components/ui/nuraly-ui/src/components/dropdown/dropdown.stories.ts +1271 -0
- package/components/ui/nuraly-ui/src/components/dropdown/dropdown.style.ts +462 -0
- package/components/ui/nuraly-ui/src/components/dropdown/dropdown.types.ts +109 -0
- package/components/ui/nuraly-ui/src/components/dropdown/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/dropdown/interfaces/controller-interfaces.ts +98 -0
- package/components/ui/nuraly-ui/src/components/dropdown/interfaces/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/dropdown/react.ts +14 -0
- package/components/ui/nuraly-ui/src/components/dropdown/templates/nr-dropdown-item.style.ts +35 -0
- package/components/ui/nuraly-ui/src/components/dropdown/templates/nr-dropdown-item.ts +47 -0
- package/components/ui/nuraly-ui/src/components/dropdown/templates/nr-dropdown-menu.style.ts +50 -0
- package/components/ui/nuraly-ui/src/components/dropdown/templates/nr-dropdown-menu.ts +52 -0
- package/components/ui/nuraly-ui/src/components/file-upload/demo/file-upload-demo.ts +151 -0
- package/components/ui/nuraly-ui/src/components/file-upload/file-upload.component.ts +371 -0
- package/components/ui/nuraly-ui/src/components/file-upload/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/file-upload/react.ts +14 -0
- package/components/ui/nuraly-ui/src/components/file-upload/readme.md +98 -0
- package/components/ui/nuraly-ui/src/components/file-upload/styles.ts +284 -0
- package/components/ui/nuraly-ui/src/components/file-upload/types.ts +10 -0
- package/components/ui/nuraly-ui/src/components/file-upload/utils.ts +23 -0
- package/components/ui/nuraly-ui/src/components/flex/README.md +235 -0
- package/components/ui/nuraly-ui/src/components/flex/flex.component.ts +186 -0
- package/components/ui/nuraly-ui/src/components/flex/flex.stories.ts +486 -0
- package/components/ui/nuraly-ui/src/components/flex/flex.style.ts +101 -0
- package/components/ui/nuraly-ui/src/components/flex/flex.types.ts +70 -0
- package/components/ui/nuraly-ui/src/components/flex/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/flex/react.ts +9 -0
- package/components/ui/nuraly-ui/src/components/form/README.md +152 -0
- package/components/ui/nuraly-ui/src/components/form/controllers/submission.controller.ts +243 -0
- package/components/ui/nuraly-ui/src/components/form/controllers/validation.controller.ts +268 -0
- package/components/ui/nuraly-ui/src/components/form/form.component.ts +699 -0
- package/components/ui/nuraly-ui/src/components/form/form.stories.ts +794 -0
- package/components/ui/nuraly-ui/src/components/form/form.style.ts +69 -0
- package/components/ui/nuraly-ui/src/components/form/form.types.ts +104 -0
- package/components/ui/nuraly-ui/src/components/form/index.ts +15 -0
- package/components/ui/nuraly-ui/src/components/form/interfaces/validation.interface.ts +139 -0
- package/components/ui/nuraly-ui/src/components/grid/README.md +196 -0
- package/components/ui/nuraly-ui/src/components/grid/col.component.ts +262 -0
- package/components/ui/nuraly-ui/src/components/grid/col.style.ts +117 -0
- package/components/ui/nuraly-ui/src/components/grid/grid.stories.ts +442 -0
- package/components/ui/nuraly-ui/src/components/grid/grid.types.ts +89 -0
- package/components/ui/nuraly-ui/src/components/grid/index.ts +3 -0
- package/components/ui/nuraly-ui/src/components/grid/react.ts +16 -0
- package/components/ui/nuraly-ui/src/components/grid/row.component.ts +203 -0
- package/components/ui/nuraly-ui/src/components/grid/row.style.ts +68 -0
- package/components/ui/nuraly-ui/src/components/icon/icon.component.ts +219 -0
- package/components/ui/nuraly-ui/src/components/icon/icon.stories.ts +160 -0
- package/components/ui/nuraly-ui/src/components/icon/icon.style.ts +214 -0
- package/components/ui/nuraly-ui/src/components/icon/icon.types.ts +4 -0
- package/components/ui/nuraly-ui/src/components/icon/icon.variables.ts +132 -0
- package/components/ui/nuraly-ui/src/components/icon/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/icon/mixins/clickable-mixin.ts +154 -0
- package/components/ui/nuraly-ui/src/components/icon/mixins/index.ts +7 -0
- package/components/ui/nuraly-ui/src/components/icon/react.ts +8 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/README.md +106 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/controllers/event.controller.ts +94 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/controllers/index.ts +9 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/controllers/search.controller.ts +76 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/controllers/selection.controller.ts +50 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/icon-picker.component.ts +324 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/icon-picker.constant.ts +33 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/icon-picker.stories.ts +255 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/icon-picker.style.ts +217 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/icon-picker.types.ts +56 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/index.ts +9 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/interfaces/icon-picker.interface.ts +14 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/interfaces/index.ts +7 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/react.ts +22 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/utils/icon-filter.utils.ts +119 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/utils/icon-loader.utils.ts +129 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/utils/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/iconpicker/utils/lucide-icons.ts +1624 -0
- package/components/ui/nuraly-ui/src/components/image/image.component.ts +136 -0
- package/components/ui/nuraly-ui/src/components/image/image.stories.ts +236 -0
- package/components/ui/nuraly-ui/src/components/image/image.style.ts +83 -0
- package/components/ui/nuraly-ui/src/components/image/image.types.ts +83 -0
- package/components/ui/nuraly-ui/src/components/image/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/image/react.ts +15 -0
- package/components/ui/nuraly-ui/src/components/input/README.md +432 -0
- package/components/ui/nuraly-ui/src/components/input/controllers/base.controller.ts +114 -0
- package/components/ui/nuraly-ui/src/components/input/controllers/event.controller.ts +421 -0
- package/components/ui/nuraly-ui/src/components/input/controllers/index.ts +32 -0
- package/components/ui/nuraly-ui/src/components/input/controllers/state.controller.ts +313 -0
- package/components/ui/nuraly-ui/src/components/input/controllers/validation.controller.ts +806 -0
- package/components/ui/nuraly-ui/src/components/input/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/input/input.component.ts +557 -0
- package/components/ui/nuraly-ui/src/components/input/input.stories.ts +1759 -0
- package/components/ui/nuraly-ui/src/components/input/input.style.ts +812 -0
- package/components/ui/nuraly-ui/src/components/input/input.types.ts +195 -0
- package/components/ui/nuraly-ui/src/components/input/mixins/focus-mixin.ts +112 -0
- package/components/ui/nuraly-ui/src/components/input/mixins/index.ts +14 -0
- package/components/ui/nuraly-ui/src/components/input/mixins/number-mixin.ts +167 -0
- package/components/ui/nuraly-ui/src/components/input/mixins/selection-mixin.ts +125 -0
- package/components/ui/nuraly-ui/src/components/input/react.ts +15 -0
- package/components/ui/nuraly-ui/src/components/input/test/nr-input_test.ts +163 -0
- package/components/ui/nuraly-ui/src/components/input/utils/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/input/utils/input-renderers.ts +217 -0
- package/components/ui/nuraly-ui/src/components/input/utils/input-validation.utils.ts +133 -0
- package/components/ui/nuraly-ui/src/components/input/validation.ts +3 -0
- package/components/ui/nuraly-ui/src/components/label/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/label/label.component.ts +52 -0
- package/components/ui/nuraly-ui/src/components/label/label.stories.ts +311 -0
- package/components/ui/nuraly-ui/src/components/label/label.style.ts +70 -0
- package/components/ui/nuraly-ui/src/components/label/label.style.variables.ts +35 -0
- package/components/ui/nuraly-ui/src/components/label/label.types.ts +48 -0
- package/components/ui/nuraly-ui/src/components/label/react.ts +11 -0
- package/components/ui/nuraly-ui/src/components/layout/README.md +200 -0
- package/components/ui/nuraly-ui/src/components/layout/content.component.ts +45 -0
- package/components/ui/nuraly-ui/src/components/layout/content.style.ts +17 -0
- package/components/ui/nuraly-ui/src/components/layout/footer.component.ts +54 -0
- package/components/ui/nuraly-ui/src/components/layout/footer.style.ts +17 -0
- package/components/ui/nuraly-ui/src/components/layout/header.component.ts +55 -0
- package/components/ui/nuraly-ui/src/components/layout/header.style.ts +19 -0
- package/components/ui/nuraly-ui/src/components/layout/index.ts +18 -0
- package/components/ui/nuraly-ui/src/components/layout/layout.component.ts +87 -0
- package/components/ui/nuraly-ui/src/components/layout/layout.stories.ts +616 -0
- package/components/ui/nuraly-ui/src/components/layout/layout.style.ts +23 -0
- package/components/ui/nuraly-ui/src/components/layout/layout.types.ts +90 -0
- package/components/ui/nuraly-ui/src/components/layout/react.ts +41 -0
- package/components/ui/nuraly-ui/src/components/layout/sider.component.ts +294 -0
- package/components/ui/nuraly-ui/src/components/layout/sider.style.ts +104 -0
- package/components/ui/nuraly-ui/src/components/menu/README.md +390 -0
- package/components/ui/nuraly-ui/src/components/menu/controllers/accessibility.controller.ts +257 -0
- package/components/ui/nuraly-ui/src/components/menu/controllers/base.controller.ts +123 -0
- package/components/ui/nuraly-ui/src/components/menu/controllers/index.ts +10 -0
- package/components/ui/nuraly-ui/src/components/menu/controllers/keyboard.controller.ts +360 -0
- package/components/ui/nuraly-ui/src/components/menu/controllers/state.controller.ts +268 -0
- package/components/ui/nuraly-ui/src/components/menu/index.ts +3 -0
- package/components/ui/nuraly-ui/src/components/menu/interfaces/controller.interface.ts +56 -0
- package/components/ui/nuraly-ui/src/components/menu/interfaces/index.ts +7 -0
- package/components/ui/nuraly-ui/src/components/menu/menu.component.ts +341 -0
- package/components/ui/nuraly-ui/src/components/menu/menu.constants.ts +12 -0
- package/components/ui/nuraly-ui/src/components/menu/menu.stories.ts +807 -0
- package/components/ui/nuraly-ui/src/components/menu/menu.style.ts +358 -0
- package/components/ui/nuraly-ui/src/components/menu/menu.types.ts +60 -0
- package/components/ui/nuraly-ui/src/components/menu/react.ts +11 -0
- package/components/ui/nuraly-ui/src/components/modal/controllers/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/modal/controllers/modal-drag-controller.ts +139 -0
- package/components/ui/nuraly-ui/src/components/modal/controllers/modal-keyboard-controller.ts +152 -0
- package/components/ui/nuraly-ui/src/components/modal/index.ts +10 -0
- package/components/ui/nuraly-ui/src/components/modal/modal-manager.ts +209 -0
- package/components/ui/nuraly-ui/src/components/modal/modal.component.ts +475 -0
- package/components/ui/nuraly-ui/src/components/modal/modal.stories.ts +823 -0
- package/components/ui/nuraly-ui/src/components/modal/modal.style.ts +369 -0
- package/components/ui/nuraly-ui/src/components/modal/modal.types.ts +148 -0
- package/components/ui/nuraly-ui/src/components/modal/react.ts +16 -0
- package/components/ui/nuraly-ui/src/components/panel/README.md +218 -0
- package/components/ui/nuraly-ui/src/components/panel/controllers/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/panel/controllers/panel-drag-controller.ts +151 -0
- package/components/ui/nuraly-ui/src/components/panel/controllers/panel-resize-controller.ts +153 -0
- package/components/ui/nuraly-ui/src/components/panel/index.ts +9 -0
- package/components/ui/nuraly-ui/src/components/panel/panel.component.ts +760 -0
- package/components/ui/nuraly-ui/src/components/panel/panel.stories.ts +978 -0
- package/components/ui/nuraly-ui/src/components/panel/panel.style.ts +499 -0
- package/components/ui/nuraly-ui/src/components/panel/panel.types.ts +89 -0
- package/components/ui/nuraly-ui/src/components/panel/react.ts +18 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/README.md +403 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/popconfirm.component.ts +336 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/popconfirm.stories.ts +491 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/popconfirm.style.ts +207 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/popconfirm.types.ts +66 -0
- package/components/ui/nuraly-ui/src/components/popconfirm/react.ts +14 -0
- package/components/ui/nuraly-ui/src/components/radio/README.md +95 -0
- package/components/ui/nuraly-ui/src/components/radio/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/radio/radio.component.ts +186 -0
- package/components/ui/nuraly-ui/src/components/radio/radio.stories.ts +317 -0
- package/components/ui/nuraly-ui/src/components/radio/radio.style.ts +150 -0
- package/components/ui/nuraly-ui/src/components/radio/radio.types.ts +14 -0
- package/components/ui/nuraly-ui/src/components/radio/react.ts +20 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/focus.controller.ts +251 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/group.controller.ts +198 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/keyboard.controller.ts +122 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/ripple.controller.ts +248 -0
- package/components/ui/nuraly-ui/src/components/radio-group/controllers/validation.controller.ts +189 -0
- package/components/ui/nuraly-ui/src/components/radio-group/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/base-controller.interface.ts +87 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/focus-controller.interface.ts +45 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/index.ts +14 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/ripple-controller.interface.ts +35 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/selection-controller.interface.ts +51 -0
- package/components/ui/nuraly-ui/src/components/radio-group/interfaces/validation-controller.interface.ts +53 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.component.ts +426 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.stories.ts +1334 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.style.ts +248 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio-group.types.ts +43 -0
- package/components/ui/nuraly-ui/src/components/radio-group/radio.constant.ts +1 -0
- package/components/ui/nuraly-ui/src/components/radio-group/react.ts +18 -0
- package/components/ui/nuraly-ui/src/components/radio-group/test/radio_test.ts +87 -0
- package/components/ui/nuraly-ui/src/components/select/README.md +316 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/base.controller.ts +93 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/dropdown.controller.ts +415 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/event.controller.ts +118 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/focus.controller.ts +255 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/keyboard.controller.ts +407 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/search.controller.ts +187 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/selection.controller.ts +238 -0
- package/components/ui/nuraly-ui/src/components/select/controllers/validation.controller.ts +236 -0
- package/components/ui/nuraly-ui/src/components/select/index.ts +36 -0
- package/components/ui/nuraly-ui/src/components/select/interfaces/base-controller.interface.ts +155 -0
- package/components/ui/nuraly-ui/src/components/select/interfaces/controller-interfaces.ts +105 -0
- package/components/ui/nuraly-ui/src/components/select/interfaces/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/select/react.ts +30 -0
- package/components/ui/nuraly-ui/src/components/select/select.component.ts +804 -0
- package/components/ui/nuraly-ui/src/components/select/select.constant.ts +142 -0
- package/components/ui/nuraly-ui/src/components/select/select.stories.ts +1653 -0
- package/components/ui/nuraly-ui/src/components/select/select.style.ts +593 -0
- package/components/ui/nuraly-ui/src/components/select/select.types.ts +120 -0
- package/components/ui/nuraly-ui/src/components/skeleton/README.md +373 -0
- package/components/ui/nuraly-ui/src/components/skeleton/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/skeleton/react.ts +10 -0
- package/components/ui/nuraly-ui/src/components/skeleton/skeleton.component.ts +385 -0
- package/components/ui/nuraly-ui/src/components/skeleton/skeleton.stories.ts +425 -0
- package/components/ui/nuraly-ui/src/components/skeleton/skeleton.style.ts +224 -0
- package/components/ui/nuraly-ui/src/components/skeleton/skeleton.types.ts +90 -0
- package/components/ui/nuraly-ui/src/components/slider-input/README.md +145 -0
- package/components/ui/nuraly-ui/src/components/slider-input/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/slider-input/react.ts +12 -0
- package/components/ui/nuraly-ui/src/components/slider-input/slider-input.component.ts +184 -0
- package/components/ui/nuraly-ui/src/components/slider-input/slider-input.stories.ts +361 -0
- package/components/ui/nuraly-ui/src/components/slider-input/slider-input.style.ts +171 -0
- package/components/ui/nuraly-ui/src/components/slider-input/slider-input.style.variables.ts +59 -0
- package/components/ui/nuraly-ui/src/components/slider-input/slider-input.types.ts +24 -0
- package/components/ui/nuraly-ui/src/components/slider-input/utils/debounce.ts +7 -0
- package/components/ui/nuraly-ui/src/components/slider-input/utils/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/base.controller.ts +99 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/filter.controller.ts +163 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/pagination.controller.ts +83 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/selection.controller.ts +143 -0
- package/components/ui/nuraly-ui/src/components/table/controllers/sort.controller.ts +115 -0
- package/components/ui/nuraly-ui/src/components/table/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/table/interfaces/index.ts +7 -0
- package/components/ui/nuraly-ui/src/components/table/interfaces/table-host.interface.ts +53 -0
- package/components/ui/nuraly-ui/src/components/table/react.ts +14 -0
- package/components/ui/nuraly-ui/src/components/table/table.component.ts +344 -0
- package/components/ui/nuraly-ui/src/components/table/table.stories.ts +1072 -0
- package/components/ui/nuraly-ui/src/components/table/table.style.ts +689 -0
- package/components/ui/nuraly-ui/src/components/table/table.types.ts +91 -0
- package/components/ui/nuraly-ui/src/components/table/templates/actions.template.ts +22 -0
- package/components/ui/nuraly-ui/src/components/table/templates/column-filter.template.ts +88 -0
- package/components/ui/nuraly-ui/src/components/table/templates/content.template.ts +257 -0
- package/components/ui/nuraly-ui/src/components/table/templates/empty.template.ts +49 -0
- package/components/ui/nuraly-ui/src/components/table/templates/filter.template.ts +35 -0
- package/components/ui/nuraly-ui/src/components/table/templates/index.ts +7 -0
- package/components/ui/nuraly-ui/src/components/table/templates/loading.template.ts +56 -0
- package/components/ui/nuraly-ui/src/components/table/templates/pagination.template.ts +70 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/base.controller.ts +136 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/dragdrop.controller.ts +251 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/editable.controller.ts +292 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/event.controller.ts +294 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/index.ts +42 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/keyboard.controller.ts +276 -0
- package/components/ui/nuraly-ui/src/components/tabs/controllers/popout.controller.ts +516 -0
- package/components/ui/nuraly-ui/src/components/tabs/index.ts +11 -0
- package/components/ui/nuraly-ui/src/components/tabs/react.ts +52 -0
- package/components/ui/nuraly-ui/src/components/tabs/tabs.component.ts +499 -0
- package/components/ui/nuraly-ui/src/components/tabs/tabs.constant.ts +30 -0
- package/components/ui/nuraly-ui/src/components/tabs/tabs.stories.ts +1334 -0
- package/components/ui/nuraly-ui/src/components/tabs/tabs.style.ts +569 -0
- package/components/ui/nuraly-ui/src/components/tabs/tabs.types.ts +261 -0
- package/components/ui/nuraly-ui/src/components/tag/README.md +22 -0
- package/components/ui/nuraly-ui/src/components/tag/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/tag/react.ts +13 -0
- package/components/ui/nuraly-ui/src/components/tag/tag.component.ts +167 -0
- package/components/ui/nuraly-ui/src/components/tag/tag.stories.ts +50 -0
- package/components/ui/nuraly-ui/src/components/tag/tag.style.ts +89 -0
- package/components/ui/nuraly-ui/src/components/tag/tag.types.ts +30 -0
- package/components/ui/nuraly-ui/src/components/textarea/README.md +314 -0
- package/components/ui/nuraly-ui/src/components/textarea/controllers/base.controller.ts +142 -0
- package/components/ui/nuraly-ui/src/components/textarea/controllers/event.controller.ts +484 -0
- package/components/ui/nuraly-ui/src/components/textarea/controllers/index.ts +16 -0
- package/components/ui/nuraly-ui/src/components/textarea/controllers/validation.controller.ts +347 -0
- package/components/ui/nuraly-ui/src/components/textarea/index.ts +19 -0
- package/components/ui/nuraly-ui/src/components/textarea/react.ts +16 -0
- package/components/ui/nuraly-ui/src/components/textarea/textarea.component.ts +716 -0
- package/components/ui/nuraly-ui/src/components/textarea/textarea.stories.ts +453 -0
- package/components/ui/nuraly-ui/src/components/textarea/textarea.style.ts +387 -0
- package/components/ui/nuraly-ui/src/components/textarea/textarea.types.ts +113 -0
- package/components/ui/nuraly-ui/src/components/timeline/README.md +340 -0
- package/components/ui/nuraly-ui/src/components/timeline/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/timeline/react.ts +9 -0
- package/components/ui/nuraly-ui/src/components/timeline/timeline.component.ts +235 -0
- package/components/ui/nuraly-ui/src/components/timeline/timeline.stories.ts +313 -0
- package/components/ui/nuraly-ui/src/components/timeline/timeline.style.ts +235 -0
- package/components/ui/nuraly-ui/src/components/timeline/timeline.types.ts +75 -0
- package/components/ui/nuraly-ui/src/components/timepicker/README.md +238 -0
- package/components/ui/nuraly-ui/src/components/timepicker/controllers/formatting.controller.ts +230 -0
- package/components/ui/nuraly-ui/src/components/timepicker/controllers/index.ts +9 -0
- package/components/ui/nuraly-ui/src/components/timepicker/controllers/selection.controller.ts +213 -0
- package/components/ui/nuraly-ui/src/components/timepicker/controllers/validation.controller.ts +240 -0
- package/components/ui/nuraly-ui/src/components/timepicker/index.ts +12 -0
- package/components/ui/nuraly-ui/src/components/timepicker/interfaces/timepicker.interface.ts +122 -0
- package/components/ui/nuraly-ui/src/components/timepicker/test/timepicker.test.ts +249 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.component.ts +786 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.constants.ts +94 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.stories.ts +643 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.style.ts +569 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.style.variables.ts +122 -0
- package/components/ui/nuraly-ui/src/components/timepicker/timepicker.types.ts +183 -0
- package/components/ui/nuraly-ui/src/components/timepicker/utils/time.utils.ts +288 -0
- package/components/ui/nuraly-ui/src/components/toast/README.md +535 -0
- package/components/ui/nuraly-ui/src/components/toast/controllers/base.controller.ts +105 -0
- package/components/ui/nuraly-ui/src/components/toast/controllers/index.ts +8 -0
- package/components/ui/nuraly-ui/src/components/toast/index.ts +10 -0
- package/components/ui/nuraly-ui/src/components/toast/react.ts +19 -0
- package/components/ui/nuraly-ui/src/components/toast/toast.component.ts +394 -0
- package/components/ui/nuraly-ui/src/components/toast/toast.stories.ts +895 -0
- package/components/ui/nuraly-ui/src/components/toast/toast.style.ts +339 -0
- package/components/ui/nuraly-ui/src/components/toast/toast.types.ts +155 -0
- package/components/ui/nuraly-ui/src/components/tooltips/demo/tooltips-demo.ts +128 -0
- package/components/ui/nuraly-ui/src/components/tooltips/index.ts +1 -0
- package/components/ui/nuraly-ui/src/components/tooltips/react.ts +0 -0
- package/components/ui/nuraly-ui/src/components/tooltips/test/tooltips_test.ts +175 -0
- package/components/ui/nuraly-ui/src/components/tooltips/tooltips.component.ts +282 -0
- package/components/ui/nuraly-ui/src/components/tooltips/tooltips.constant.ts +15 -0
- package/components/ui/nuraly-ui/src/components/tooltips/tooltips.style.ts +103 -0
- package/components/ui/nuraly-ui/src/components/tooltips/tooltips.variables.ts +14 -0
- package/components/ui/nuraly-ui/src/components/video/index.ts +2 -0
- package/components/ui/nuraly-ui/src/components/video/react.ts +17 -0
- package/components/ui/nuraly-ui/src/components/video/video.component.ts +179 -0
- package/components/ui/nuraly-ui/src/components/video/video.stories.ts +289 -0
- package/components/ui/nuraly-ui/src/components/video/video.style.ts +124 -0
- package/components/ui/nuraly-ui/src/components/video/video.types.ts +102 -0
- package/components/ui/nuraly-ui/src/helpers/ThemeHandler.ts +68 -0
- package/components/ui/nuraly-ui/src/helpers/test.ts +8 -0
- package/components/ui/nuraly-ui/src/introduction.stories.ts +161 -0
- package/components/ui/nuraly-ui/src/shared/README.md +87 -0
- package/components/ui/nuraly-ui/src/shared/base-mixin.ts +48 -0
- package/components/ui/nuraly-ui/src/shared/constants.ts +0 -0
- package/components/ui/nuraly-ui/src/shared/controllers/dropdown.controller.ts +393 -0
- package/components/ui/nuraly-ui/src/shared/controllers/dropdown.interface.ts +39 -0
- package/components/ui/nuraly-ui/src/shared/controllers/index.ts +3 -0
- package/components/ui/nuraly-ui/src/shared/controllers/theme.controller.ts +158 -0
- package/components/ui/nuraly-ui/src/shared/dependency-mixin.ts +174 -0
- package/components/ui/nuraly-ui/src/shared/event-handler-mixin.ts +190 -0
- package/components/ui/nuraly-ui/src/shared/index.ts +20 -0
- package/components/ui/nuraly-ui/src/shared/theme-mixin.ts +227 -0
- package/components/ui/nuraly-ui/src/shared/themes/README.md +135 -0
- package/components/ui/nuraly-ui/src/shared/themes/editor/README.md +202 -0
- package/components/ui/nuraly-ui/src/shared/themes/editor.stories.ts +366 -0
- package/components/ui/nuraly-ui/src/shared/themes/index.ts +132 -0
- package/components/ui/nuraly-ui/src/shared/utils.ts +94 -0
- package/components/ui/nuraly-ui/src/shared/validation.types.ts +118 -0
- package/components/ui/nuraly-ui/tools/bump-versions.js +83 -0
- package/components/ui/nuraly-ui/web-dev-server.config.js +25 -0
- package/components/ui/nuraly-ui/web-test-runner.config.js +124 -0
- package/dist/CodeEditor-Ch2tv9BE.js +106211 -0
- package/dist/SmartAttributeHandler-hoSLpm1Y.js +153 -0
- package/dist/abap-B2diVmjb.js +1314 -0
- package/dist/apex-3NuJ-nsI.js +315 -0
- package/dist/assets/editor.worker-vBWydyGC.js +11 -0
- package/dist/assets/html.worker-BSmGlhXp.js +458 -0
- package/dist/assets/json.worker-Dqnoedz4.js +42 -0
- package/dist/assets/ts.worker-DyHHPhrh.js +37021 -0
- package/dist/azcli-XGXuUsMB.js +74 -0
- package/dist/bat-B8Vhm634.js +95 -0
- package/dist/bicep-Cc8X5S_k.js +108 -0
- package/dist/cameligo-Bo3wBh9T.js +168 -0
- package/dist/clojure-CPoQlpIK.js +754 -0
- package/dist/coffee-BxvTGz39.js +228 -0
- package/dist/cpp-5RpEV7vC.js +390 -0
- package/dist/csharp-slXXP3fo.js +320 -0
- package/dist/csp-B98p6-gH.js +57 -0
- package/dist/css-BDsDSAin.js +186 -0
- package/dist/cssMode-Bt2uK8XM.js +1446 -0
- package/dist/cypher-Dc4IMouD.js +262 -0
- package/dist/dart-LhvE3yD2.js +270 -0
- package/dist/dockerfile-CwzplJeZ.js +132 -0
- package/dist/ecl-DxW3FiJi.js +454 -0
- package/dist/elixir-BI40g7TU.js +489 -0
- package/dist/flow9-tR2v0bGz.js +141 -0
- package/dist/freemarker2-DNc2IxPf.js +643 -0
- package/dist/fsharp-BLAma0OT.js +210 -0
- package/dist/go-nYcD3y4Z.js +208 -0
- package/dist/graphql-Dp1cHWmP.js +141 -0
- package/dist/handlebars-CIbFckEw.js +391 -0
- package/dist/hcl-6NT8Kbna.js +177 -0
- package/dist/html-nRs_fneU.js +281 -0
- package/dist/htmlMode-BjehA1YF.js +1456 -0
- package/dist/ini-BZCOLrEc.js +68 -0
- package/dist/java-DAMcfJbX.js +221 -0
- package/dist/javascript-Bn0HduZA.js +75 -0
- package/dist/jsonMode-CfGfcJRX.js +1866 -0
- package/dist/julia-CQ46G71H.js +496 -0
- package/dist/kotlin-CEjVo_6E.js +245 -0
- package/dist/less-DreV99nP.js +168 -0
- package/dist/lexon-DBVJhqLb.js +151 -0
- package/dist/liquid-m4D_LCnC.js +238 -0
- package/dist/lua-Dcc_j6L-.js +157 -0
- package/dist/m3-B9SlZL4n.js +210 -0
- package/dist/markdown-CuGw9_MP.js +202 -0
- package/dist/mdx-CakMRbCr.js +171 -0
- package/dist/micro-app-entry-CI1Rupdh.js +17479 -0
- package/dist/micro-app.bundle.js +8 -0
- package/dist/mips-BUWqP-OH.js +194 -0
- package/dist/msdax-DtkouYCg.js +377 -0
- package/dist/mysql-IkAsWSmF.js +876 -0
- package/dist/objective-c-B2-ronfg.js +188 -0
- package/dist/pascal-Bsnz2eJA.js +245 -0
- package/dist/pascaligo-D_sMUn0Q.js +158 -0
- package/dist/perl-BPzHt9SS.js +599 -0
- package/dist/pgsql-DlTJB0PD.js +847 -0
- package/dist/php-Dmq5OjwK.js +471 -0
- package/dist/pla-HJcccrBy.js +131 -0
- package/dist/postiats-OQn6DKv-.js +544 -0
- package/dist/powerquery-DKaMYC8w.js +890 -0
- package/dist/powershell-DWeJHik1.js +233 -0
- package/dist/protobuf-CBn_IseU.js +422 -0
- package/dist/pug-BoRpCINl.js +393 -0
- package/dist/python-oJwaiPUY.js +259 -0
- package/dist/qsharp-4rGyVZOw.js +282 -0
- package/dist/r-DsgLhBOb.js +245 -0
- package/dist/razor-u_dd4rqc.js +512 -0
- package/dist/redis-B2fdL4Bg.js +298 -0
- package/dist/redshift-DoaeyCkH.js +806 -0
- package/dist/restructuredtext-D-6OFBY9.js +162 -0
- package/dist/ruby-D1DD6baV.js +444 -0
- package/dist/rust-DssUV39M.js +337 -0
- package/dist/sb-Dmb6tAdv.js +110 -0
- package/dist/scala-Co3ETaym.js +353 -0
- package/dist/scheme-CMrqXTty.js +114 -0
- package/dist/scss-DkGudv8Q.js +244 -0
- package/dist/shell-BHN2BI4L.js +224 -0
- package/dist/solidity-b-R-raGB.js +1351 -0
- package/dist/sophia-Y4GjyxNB.js +190 -0
- package/dist/sparql-CDAPZb88.js +193 -0
- package/dist/sql-DkkpPiUq.js +818 -0
- package/dist/st-CSPV91Ej.js +415 -0
- package/dist/style.css +1 -0
- package/dist/swift-DdSC5O48.js +315 -0
- package/dist/systemverilog-CI03XpAv.js +556 -0
- package/dist/tcl-B8DayMSI.js +232 -0
- package/dist/tsMode-DlZ38d3D.js +813 -0
- package/dist/twig-B1AUPVB_.js +323 -0
- package/dist/typescript-Bjs2N5Be.js +328 -0
- package/dist/vb-BIC7ccdG.js +364 -0
- package/dist/wgsl-Bv2xeo60.js +420 -0
- package/dist/xml-BCveATLl.js +95 -0
- package/dist/yaml-BfWQPJQi.js +184 -0
- package/handlers/compiler.ts +362 -0
- package/handlers/context-setup.ts +349 -0
- package/handlers/handler-executor.ts +348 -0
- package/handlers/index.ts +184 -0
- package/handlers/runtime-api/applications.ts +18 -0
- package/handlers/runtime-api/component-properties.ts +78 -0
- package/handlers/runtime-api/components.ts +63 -0
- package/handlers/runtime-api/editor.ts +29 -0
- package/handlers/runtime-api/functions.ts +42 -0
- package/handlers/runtime-api/index.ts +221 -0
- package/handlers/runtime-api/navigation.ts +52 -0
- package/handlers/runtime-api/pages.ts +45 -0
- package/handlers/runtime-api/storage.ts +95 -0
- package/handlers/runtime-api/toast.ts +108 -0
- package/handlers/runtime-api/variables.ts +400 -0
- package/index.ts +188 -0
- package/micro-app/README.md +565 -0
- package/micro-app/index.ts +29 -0
- package/micro-app/messaging/MicroAppMessageBus.ts +246 -0
- package/micro-app/state/MicroAppPageManager.ts +275 -0
- package/micro-app/state/MicroAppRuntimeContext.ts +423 -0
- package/micro-app/state/MicroAppStoreContext.ts +441 -0
- package/micro-app/state/SharedVariableRegistry.ts +187 -0
- package/micro-app/state/VariableScopeManager.ts +310 -0
- package/micro-app/utils/ComponentNamespaceManager.ts +88 -0
- package/micro-app-entry.ts +34 -0
- package/package.json +119 -0
- package/redux/actions/aitchat.ts +17 -0
- package/redux/actions/application/addPageToApplicationAction.ts +14 -0
- package/redux/actions/application/addTempApplication.ts +8 -0
- package/redux/actions/application/closeShareApplicationModalAction.ts +5 -0
- package/redux/actions/application/index.ts +20 -0
- package/redux/actions/application/loadApplicationPermissionAction.ts +10 -0
- package/redux/actions/application/resetPermissionMessage.ts +8 -0
- package/redux/actions/application/setApplication.ts +5 -0
- package/redux/actions/application/setApplicationPermissionAction.ts +6 -0
- package/redux/actions/application/setDefaultApplicationPageIfNotSet.ts +12 -0
- package/redux/actions/application/setPermissionMessage.ts +8 -0
- package/redux/actions/application/showCreateApplicationModalAction.ts +5 -0
- package/redux/actions/application/showShareApplicationModalAction.ts +5 -0
- package/redux/actions/application/updateApplication.ts +16 -0
- package/redux/actions/component/addComponentAction.ts +90 -0
- package/redux/actions/component/addComponentAsChildOf.ts +29 -0
- package/redux/actions/component/addComponentToCurrentPageAction.ts +32 -0
- package/redux/actions/component/copyComponentAction.ts +12 -0
- package/redux/actions/component/deleteComponentAction.ts +52 -0
- package/redux/actions/component/index.ts +22 -0
- package/redux/actions/component/moveDraggedComponent.ts +130 -0
- package/redux/actions/component/moveDraggedComponentInside.ts +64 -0
- package/redux/actions/component/moveDraggedComponentIntoCurrentPageRoot.ts +50 -0
- package/redux/actions/component/setCurrentComponentIdAction.ts +6 -0
- package/redux/actions/component/setDraggingComponentInfo.ts +14 -0
- package/redux/actions/component/setHoveredComponentAction.ts +5 -0
- package/redux/actions/component/setHoveredComponentIdAction.ts +5 -0
- package/redux/actions/component/update-component-name.ts +63 -0
- package/redux/actions/component/updateComponentAttributes.ts +192 -0
- package/redux/actions/component.ts +25 -0
- package/redux/actions/debug/index.ts +1 -0
- package/redux/actions/debug/store.ts +72 -0
- package/redux/actions/editor/closeCreateApplicationModalAction.ts +5 -0
- package/redux/actions/editor/closeEditorTab.ts +9 -0
- package/redux/actions/editor/index.ts +12 -0
- package/redux/actions/editor/openEditorTab.ts +12 -0
- package/redux/actions/editor/setCurrentEditorTab.ts +8 -0
- package/redux/actions/editor/setEnvirementMode.ts +8 -0
- package/redux/actions/environment.ts +5 -0
- package/redux/actions/index.ts +28 -0
- package/redux/actions/kernel/index.ts +1 -0
- package/redux/actions/kernel/set-property.ts +0 -0
- package/redux/actions/page/addPageAction.ts +7 -0
- package/redux/actions/page/deletePageAction.ts +13 -0
- package/redux/actions/page/index.ts +12 -0
- package/redux/actions/page/removeComponentToCurrentPageAction.ts +32 -0
- package/redux/actions/page/setContextMenuEvent.ts +5 -0
- package/redux/actions/page/setCurrentPageAction.ts +6 -0
- package/redux/actions/page/setCurrentPageViewPort.ts +5 -0
- package/redux/actions/page/setResizing.ts +5 -0
- package/redux/actions/page/setShowBorder.ts +5 -0
- package/redux/actions/page/updatePageAction.ts +20 -0
- package/redux/actions/page/updatePageInfo.ts +5 -0
- package/redux/actions/page/updatePageStyleAttributes.ts +13 -0
- package/redux/actions/page/updatePageZoom.ts +5 -0
- package/redux/handlers/aichat/create-chat.handler.ts +22 -0
- package/redux/handlers/api-urls.ts +8 -0
- package/redux/handlers/applications/handler.ts +78 -0
- package/redux/handlers/applications/index.ts +1 -0
- package/redux/handlers/components/add-component.handler.ts +30 -0
- package/redux/handlers/components/delete-component.handler.ts +21 -0
- package/redux/handlers/components/index.ts +6 -0
- package/redux/handlers/components/interfaces/add-component.request.ts +4 -0
- package/redux/handlers/components/interfaces/index.ts +2 -0
- package/redux/handlers/components/interfaces/update-component.reques.ts +3 -0
- package/redux/handlers/components/refresh-component.ts +25 -0
- package/redux/handlers/components/update-component.handler.ts +32 -0
- package/redux/handlers/components/validation-handler.ts +45 -0
- package/redux/handlers/functions/build-function-handler.ts +10 -0
- package/redux/handlers/functions/deploy-function-handler.ts +10 -0
- package/redux/handlers/functions/index.ts +13 -0
- package/redux/handlers/functions/invoke-function-handler.ts +13 -0
- package/redux/handlers/functions/load-functions-handler.ts +10 -0
- package/redux/handlers/functions/update-function-handler.ts +13 -0
- package/redux/handlers/index.ts +10 -0
- package/redux/handlers/pages/deletePageHandler.ts +23 -0
- package/redux/handlers/pages/handler.ts +59 -0
- package/redux/handlers/pages/index.ts +4 -0
- package/redux/handlers/pages/page.interface.ts +14 -0
- package/redux/handlers/pages/refresh-pages.ts +26 -0
- package/redux/handlers/providers/interface.ts +7 -0
- package/redux/index.ts +8 -0
- package/redux/store/actions/component.ts +9 -0
- package/redux/store/apps.ts +160 -0
- package/redux/store/component/component.interface.ts +90 -0
- package/redux/store/component/helper.ts +78 -0
- package/redux/store/component/index.ts +51 -0
- package/redux/store/component/runtime-store.ts +0 -0
- package/redux/store/component/store.ts +306 -0
- package/redux/store/context.ts +138 -0
- package/redux/store/debug.ts +28 -0
- package/redux/store/environment.ts +20 -0
- package/redux/store/index.ts +77 -0
- package/redux/store/interfaces/component.interfaces.ts +4 -0
- package/redux/store/page.ts +105 -0
- package/redux/store/provider.ts +24 -0
- package/redux/store/ssr/server-data.ts +4 -0
- package/redux/store/toast.ts +26 -0
- package/state/editor.ts +370 -0
- package/state/index.ts +27 -0
- package/state/runtime-context.ts +784 -0
- package/types/IRuntimeContext.ts +203 -0
- package/types/core.types.ts +28 -0
- package/types/database.types.ts +395 -0
- package/types/index.ts +7 -0
- package/utils/RuntimeContextHelpers.ts +454 -0
- package/utils/api-calls-utils.ts +9 -0
- package/utils/change-detection.ts +58 -0
- package/utils/clipboard-utils.ts +113 -0
- package/utils/constants.ts +2 -0
- package/utils/envirement.ts +2 -0
- package/utils/handler-security-rules.ts +153 -0
- package/utils/handler-validator.ts +447 -0
- package/utils/index.ts +67 -0
- package/utils/local-storage.ts +26 -0
- package/utils/logger.ts +90 -0
- package/utils/memoize.ts +15 -0
- package/utils/naming-generator.ts +6 -0
- package/utils/object.utils.ts +15 -0
- package/utils/performance-utils.ts +589 -0
- package/utils/randomness.ts +3 -0
- package/utils/register-components.ts +49 -0
- package/utils/render-util.ts +173 -0
- package/utils/runtime-helpers.ts +57 -0
- package/utils/styleUtil.ts +7 -0
- package/utils/time.ts +7 -0
- package/utils/validation-error-formatter.ts +11 -0
- package/vite.config.ts +83 -0
|
@@ -0,0 +1,2549 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Meta, StoryObj } from '@storybook/web-components';
|
|
8
|
+
import { html } from 'lit';
|
|
9
|
+
import {
|
|
10
|
+
ChatbotMessage,
|
|
11
|
+
ChatbotSuggestion,
|
|
12
|
+
ChatbotSender,
|
|
13
|
+
ChatbotSize,
|
|
14
|
+
ChatbotVariant,
|
|
15
|
+
ChatbotLoadingType,
|
|
16
|
+
ChatbotModule,
|
|
17
|
+
ChatbotThread
|
|
18
|
+
} from './chatbot.types.js';
|
|
19
|
+
import { ChatbotFileType } from './chatbot.types.js';
|
|
20
|
+
|
|
21
|
+
// Import the core controller and providers
|
|
22
|
+
import { ChatbotCoreController } from './core/chatbot-core.controller.js';
|
|
23
|
+
import { MockProvider } from './providers/mock-provider.js';
|
|
24
|
+
|
|
25
|
+
// Import storage implementations
|
|
26
|
+
import { MemoryStorage, LocalStorageAdapter, IndexedDBStorage } from './storage/index.js';
|
|
27
|
+
|
|
28
|
+
// Note: Theme CSS is imported globally in .storybook/preview.ts
|
|
29
|
+
// No need to import themes here to avoid conflicts
|
|
30
|
+
import '../input/input.component.js';
|
|
31
|
+
import '../button/button.component.js';
|
|
32
|
+
import '../icon/icon.component.js';
|
|
33
|
+
import '../dropdown/dropdown.component.js';
|
|
34
|
+
import '../select/select.component.js';
|
|
35
|
+
import '../tag/tag.component.js';
|
|
36
|
+
import '../modal/modal.component.js';
|
|
37
|
+
import '../document/document.component.js';
|
|
38
|
+
import './chatbot.component.js';
|
|
39
|
+
|
|
40
|
+
const meta: Meta = {
|
|
41
|
+
title: 'Components/Chatbot',
|
|
42
|
+
component: 'nr-chatbot',
|
|
43
|
+
parameters: {
|
|
44
|
+
layout: 'centered',
|
|
45
|
+
docs: {
|
|
46
|
+
description: {
|
|
47
|
+
component: `
|
|
48
|
+
# Chatbot Component with Controller Architecture
|
|
49
|
+
|
|
50
|
+
A modern, controller-based chatbot component that separates UI from business logic.
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
- **ChatbotCoreController**: Pure business logic, framework-agnostic
|
|
55
|
+
- **Providers**: Pluggable AI/API backends (OpenAI, Custom, Mock)
|
|
56
|
+
- **UI Component**: Lit-based web component that renders the chatbot
|
|
57
|
+
|
|
58
|
+
## Basic Usage
|
|
59
|
+
|
|
60
|
+
\`\`\`javascript
|
|
61
|
+
import { ChatbotCoreController, MockProvider } from '@nuraly/chatbot';
|
|
62
|
+
|
|
63
|
+
// Create controller with provider
|
|
64
|
+
const controller = new ChatbotCoreController({
|
|
65
|
+
provider: new MockProvider(),
|
|
66
|
+
ui: {
|
|
67
|
+
onStateChange: (state) => {
|
|
68
|
+
chatbot.messages = state.messages;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Attach to component
|
|
74
|
+
chatbot.controller = controller;
|
|
75
|
+
\`\`\`
|
|
76
|
+
`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
argTypes: {
|
|
81
|
+
size: {
|
|
82
|
+
control: { type: 'select' },
|
|
83
|
+
options: Object.values(ChatbotSize),
|
|
84
|
+
description: 'Chatbot size variant'
|
|
85
|
+
},
|
|
86
|
+
variant: {
|
|
87
|
+
control: { type: 'select' },
|
|
88
|
+
options: Object.values(ChatbotVariant),
|
|
89
|
+
description: 'Chatbot visual variant'
|
|
90
|
+
},
|
|
91
|
+
loadingIndicator: {
|
|
92
|
+
control: { type: 'select' },
|
|
93
|
+
options: Object.values(ChatbotLoadingType),
|
|
94
|
+
description: 'Loading indicator type'
|
|
95
|
+
},
|
|
96
|
+
isRTL: {
|
|
97
|
+
control: { type: 'boolean' },
|
|
98
|
+
description: 'Right-to-left text direction'
|
|
99
|
+
},
|
|
100
|
+
disabled: {
|
|
101
|
+
control: { type: 'boolean' },
|
|
102
|
+
description: 'Disable input and interactions'
|
|
103
|
+
},
|
|
104
|
+
showSendButton: {
|
|
105
|
+
control: { type: 'boolean' },
|
|
106
|
+
description: 'Show send button'
|
|
107
|
+
},
|
|
108
|
+
autoScroll: {
|
|
109
|
+
control: { type: 'boolean' },
|
|
110
|
+
description: 'Auto-scroll to new messages'
|
|
111
|
+
},
|
|
112
|
+
showThreads: {
|
|
113
|
+
control: { type: 'boolean' },
|
|
114
|
+
description: 'Show thread sidebar'
|
|
115
|
+
},
|
|
116
|
+
boxed: {
|
|
117
|
+
control: { type: 'boolean' },
|
|
118
|
+
description: 'Enable boxed layout for large widths (ChatGPT-style)'
|
|
119
|
+
},
|
|
120
|
+
enableModuleSelection: {
|
|
121
|
+
control: { type: 'boolean' },
|
|
122
|
+
description: 'Enable module selection dropdown'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export default meta;
|
|
128
|
+
type Story = StoryObj;
|
|
129
|
+
|
|
130
|
+
// ===== SAMPLE DATA =====
|
|
131
|
+
|
|
132
|
+
const sampleSuggestions: ChatbotSuggestion[] = [
|
|
133
|
+
{ id: 'sugg1', text: 'What can you help me with?', enabled: true },
|
|
134
|
+
{ id: 'sugg2', text: 'Tell me about your features', enabled: true },
|
|
135
|
+
{ id: 'sugg3', text: 'How do I get started?', enabled: true },
|
|
136
|
+
{ id: 'sugg4', text: 'Show me an example', enabled: true }
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
const sampleModules: ChatbotModule[] = [
|
|
140
|
+
{
|
|
141
|
+
id: 'web-search',
|
|
142
|
+
name: 'Web Search',
|
|
143
|
+
description: 'Search the web for information',
|
|
144
|
+
icon: 'search',
|
|
145
|
+
enabled: true
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'file-analysis',
|
|
149
|
+
name: 'File Analysis',
|
|
150
|
+
description: 'Analyze uploaded files',
|
|
151
|
+
icon: 'file-text',
|
|
152
|
+
enabled: true
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 'code-generation',
|
|
156
|
+
name: 'Code Generation',
|
|
157
|
+
description: 'Generate code snippets',
|
|
158
|
+
icon: 'code',
|
|
159
|
+
enabled: true
|
|
160
|
+
}
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
// ===== HELPER FUNCTIONS =====
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Create a controller and sync it with a chatbot element
|
|
167
|
+
*/
|
|
168
|
+
function createControllerForElement(element: any, providerConfig: any = {}) {
|
|
169
|
+
const controller = new ChatbotCoreController({
|
|
170
|
+
provider: new MockProvider(providerConfig),
|
|
171
|
+
ui: {
|
|
172
|
+
onStateChange: (state) => {
|
|
173
|
+
element.messages = state.messages;
|
|
174
|
+
element.threads = state.threads;
|
|
175
|
+
element.isBotTyping = state.isTyping;
|
|
176
|
+
element.chatStarted = state.messages.length > 0;
|
|
177
|
+
},
|
|
178
|
+
onTypingStart: () => {
|
|
179
|
+
element.isBotTyping = true;
|
|
180
|
+
},
|
|
181
|
+
onTypingEnd: () => {
|
|
182
|
+
element.isBotTyping = false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return controller;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ===== STORIES =====
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Default chatbot with mock provider - Fully interactive!
|
|
194
|
+
* Try asking questions and see contextual responses.
|
|
195
|
+
*/
|
|
196
|
+
export const Default: Story = {
|
|
197
|
+
args: {
|
|
198
|
+
size: ChatbotSize.Medium,
|
|
199
|
+
variant: ChatbotVariant.Default,
|
|
200
|
+
isRTL: false,
|
|
201
|
+
disabled: false,
|
|
202
|
+
showSendButton: true,
|
|
203
|
+
autoScroll: true,
|
|
204
|
+
showThreads: false,
|
|
205
|
+
boxed: false
|
|
206
|
+
},
|
|
207
|
+
render: (args) => {
|
|
208
|
+
setTimeout(() => {
|
|
209
|
+
const chatbot = document.querySelector('nr-chatbot') as any;
|
|
210
|
+
if (chatbot && !chatbot.controller) {
|
|
211
|
+
const controller = createControllerForElement(chatbot, {
|
|
212
|
+
delay: 600,
|
|
213
|
+
streaming: true,
|
|
214
|
+
streamingSpeed: 4,
|
|
215
|
+
streamingInterval: 25,
|
|
216
|
+
contextualResponses: true
|
|
217
|
+
});
|
|
218
|
+
chatbot.controller = controller;
|
|
219
|
+
chatbot.suggestions = sampleSuggestions;
|
|
220
|
+
}
|
|
221
|
+
}, 0);
|
|
222
|
+
|
|
223
|
+
return html`
|
|
224
|
+
<div style="width: 500px; height: 600px;">
|
|
225
|
+
<nr-chatbot
|
|
226
|
+
.size=${args.size}
|
|
227
|
+
.variant=${args.variant}
|
|
228
|
+
.isRTL=${args.isRTL}
|
|
229
|
+
.disabled=${args.disabled}
|
|
230
|
+
.showSendButton=${args.showSendButton}
|
|
231
|
+
.autoScroll=${args.autoScroll}
|
|
232
|
+
.showThreads=${args.showThreads}
|
|
233
|
+
.boxed=${args.boxed}
|
|
234
|
+
></nr-chatbot>
|
|
235
|
+
</div>
|
|
236
|
+
`;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Chatbot with streaming responses
|
|
242
|
+
*/
|
|
243
|
+
export const WithStreaming: Story = {
|
|
244
|
+
args: {
|
|
245
|
+
...Default.args
|
|
246
|
+
},
|
|
247
|
+
render: (args) => {
|
|
248
|
+
setTimeout(() => {
|
|
249
|
+
const chatbot = document.querySelector('#streaming-chatbot') as any;
|
|
250
|
+
if (chatbot && !chatbot.controller) {
|
|
251
|
+
const controller = createControllerForElement(chatbot, {
|
|
252
|
+
delay: 500,
|
|
253
|
+
streaming: true,
|
|
254
|
+
streamingSpeed: 3,
|
|
255
|
+
streamingInterval: 30,
|
|
256
|
+
contextualResponses: true
|
|
257
|
+
});
|
|
258
|
+
chatbot.controller = controller;
|
|
259
|
+
chatbot.suggestions = sampleSuggestions;
|
|
260
|
+
}
|
|
261
|
+
}, 0);
|
|
262
|
+
|
|
263
|
+
return html`
|
|
264
|
+
<div style="width: 500px; height: 600px;">
|
|
265
|
+
<nr-chatbot
|
|
266
|
+
id="streaming-chatbot"
|
|
267
|
+
.size=${args.size}
|
|
268
|
+
.variant=${args.variant}
|
|
269
|
+
.isRTL=${args.isRTL}
|
|
270
|
+
.disabled=${args.disabled}
|
|
271
|
+
.showSendButton=${args.showSendButton}
|
|
272
|
+
.autoScroll=${args.autoScroll}
|
|
273
|
+
.showThreads=${args.showThreads}
|
|
274
|
+
.boxed=${args.boxed}
|
|
275
|
+
></nr-chatbot>
|
|
276
|
+
</div>
|
|
277
|
+
`;
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Chatbot with thread support - Create multiple conversations!
|
|
283
|
+
* Try creating new threads and switching between them.
|
|
284
|
+
*/
|
|
285
|
+
export const WithThreads: Story = {
|
|
286
|
+
args: {
|
|
287
|
+
...Default.args,
|
|
288
|
+
showThreads: true
|
|
289
|
+
},
|
|
290
|
+
render: (args) => {
|
|
291
|
+
setTimeout(() => {
|
|
292
|
+
const chatbot = document.querySelector('#threaded-chatbot') as any;
|
|
293
|
+
if (chatbot && !chatbot.controller) {
|
|
294
|
+
// Create controller with thread support enabled
|
|
295
|
+
const controller = new ChatbotCoreController({
|
|
296
|
+
provider: new MockProvider({
|
|
297
|
+
delay: 500,
|
|
298
|
+
streaming: true,
|
|
299
|
+
streamingSpeed: 5,
|
|
300
|
+
streamingInterval: 20,
|
|
301
|
+
contextualResponses: true
|
|
302
|
+
}),
|
|
303
|
+
enableThreads: true,
|
|
304
|
+
ui: {
|
|
305
|
+
onStateChange: (state) => {
|
|
306
|
+
chatbot.messages = state.messages;
|
|
307
|
+
chatbot.threads = state.threads;
|
|
308
|
+
chatbot.isBotTyping = state.isTyping;
|
|
309
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
310
|
+
},
|
|
311
|
+
onTypingStart: () => {
|
|
312
|
+
chatbot.isBotTyping = true;
|
|
313
|
+
},
|
|
314
|
+
onTypingEnd: () => {
|
|
315
|
+
chatbot.isBotTyping = false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
chatbot.controller = controller;
|
|
321
|
+
chatbot.suggestions = [
|
|
322
|
+
{ id: 'thread1', text: 'Start a conversation about AI', enabled: true },
|
|
323
|
+
{ id: 'thread2', text: 'Ask about programming', enabled: true },
|
|
324
|
+
{ id: 'thread3', text: 'Create a new thread', enabled: true },
|
|
325
|
+
{ id: 'thread4', text: 'Switch between threads', enabled: true }
|
|
326
|
+
];
|
|
327
|
+
chatbot.enableThreadCreation = true;
|
|
328
|
+
}
|
|
329
|
+
}, 0);
|
|
330
|
+
|
|
331
|
+
return html`
|
|
332
|
+
<div style="width: 800px; height: 600px;">
|
|
333
|
+
<nr-chatbot
|
|
334
|
+
id="threaded-chatbot"
|
|
335
|
+
.size=${args.size}
|
|
336
|
+
.variant=${args.variant}
|
|
337
|
+
.isRTL=${args.isRTL}
|
|
338
|
+
.disabled=${args.disabled}
|
|
339
|
+
.showSendButton=${args.showSendButton}
|
|
340
|
+
.autoScroll=${args.autoScroll}
|
|
341
|
+
.showThreads=${args.showThreads}
|
|
342
|
+
.boxed=${args.boxed}
|
|
343
|
+
></nr-chatbot>
|
|
344
|
+
</div>
|
|
345
|
+
`;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Chatbot with module selection - Select modules and chat!
|
|
351
|
+
* Try selecting different modules before sending messages.
|
|
352
|
+
*/
|
|
353
|
+
export const WithModules: Story = {
|
|
354
|
+
args: {
|
|
355
|
+
...Default.args,
|
|
356
|
+
enableModuleSelection: true
|
|
357
|
+
},
|
|
358
|
+
render: (args) => {
|
|
359
|
+
setTimeout(() => {
|
|
360
|
+
const chatbot = document.querySelector('#module-chatbot') as any;
|
|
361
|
+
if (chatbot && !chatbot.controller) {
|
|
362
|
+
const controller = createControllerForElement(chatbot, {
|
|
363
|
+
delay: 500,
|
|
364
|
+
streaming: true,
|
|
365
|
+
streamingSpeed: 5,
|
|
366
|
+
streamingInterval: 20,
|
|
367
|
+
contextualResponses: true
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
chatbot.controller = controller;
|
|
371
|
+
chatbot.suggestions = [
|
|
372
|
+
{ id: 'mod1', text: 'Search the web for information', enabled: true },
|
|
373
|
+
{ id: 'mod2', text: 'Analyze this file', enabled: true },
|
|
374
|
+
{ id: 'mod3', text: 'Generate some code', enabled: true },
|
|
375
|
+
{ id: 'mod4', text: 'What modules are available?', enabled: true }
|
|
376
|
+
];
|
|
377
|
+
chatbot.modules = sampleModules;
|
|
378
|
+
chatbot.enableModuleSelection = true;
|
|
379
|
+
}
|
|
380
|
+
}, 0);
|
|
381
|
+
|
|
382
|
+
return html`
|
|
383
|
+
<div style="width: 500px; height: 600px;">
|
|
384
|
+
<nr-chatbot
|
|
385
|
+
id="module-chatbot"
|
|
386
|
+
.size=${args.size}
|
|
387
|
+
.variant=${args.variant}
|
|
388
|
+
.isRTL=${args.isRTL}
|
|
389
|
+
.disabled=${args.disabled}
|
|
390
|
+
.showSendButton=${args.showSendButton}
|
|
391
|
+
.autoScroll=${args.autoScroll}
|
|
392
|
+
.showThreads=${args.showThreads}
|
|
393
|
+
.boxed=${args.boxed}
|
|
394
|
+
></nr-chatbot>
|
|
395
|
+
</div>
|
|
396
|
+
`;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Boxed layout (ChatGPT-style) - Full-screen interactive experience!
|
|
402
|
+
* Experience a ChatGPT-like interface with centered conversation.
|
|
403
|
+
*/
|
|
404
|
+
export const BoxedLayout: Story = {
|
|
405
|
+
args: {
|
|
406
|
+
...Default.args,
|
|
407
|
+
boxed: true
|
|
408
|
+
},
|
|
409
|
+
parameters: {
|
|
410
|
+
layout: 'fullscreen'
|
|
411
|
+
},
|
|
412
|
+
render: (args) => {
|
|
413
|
+
setTimeout(() => {
|
|
414
|
+
const chatbot = document.querySelector('#boxed-chatbot') as any;
|
|
415
|
+
if (chatbot && !chatbot.controller) {
|
|
416
|
+
const controller = createControllerForElement(chatbot, {
|
|
417
|
+
delay: 400,
|
|
418
|
+
streaming: true,
|
|
419
|
+
streamingSpeed: 6,
|
|
420
|
+
streamingInterval: 15,
|
|
421
|
+
contextualResponses: true
|
|
422
|
+
});
|
|
423
|
+
chatbot.controller = controller;
|
|
424
|
+
chatbot.suggestions = sampleSuggestions;
|
|
425
|
+
}
|
|
426
|
+
}, 0);
|
|
427
|
+
|
|
428
|
+
return html`
|
|
429
|
+
<div style="width: 100vw; height: 100vh; background: var(--nr-color-background, #f5f5f5);">
|
|
430
|
+
<nr-chatbot
|
|
431
|
+
id="boxed-chatbot"
|
|
432
|
+
.size=${args.size}
|
|
433
|
+
.variant=${args.variant}
|
|
434
|
+
.isRTL=${args.isRTL}
|
|
435
|
+
.disabled=${args.disabled}
|
|
436
|
+
.showSendButton=${args.showSendButton}
|
|
437
|
+
.autoScroll=${args.autoScroll}
|
|
438
|
+
.showThreads=${args.showThreads}
|
|
439
|
+
.boxed=${args.boxed}
|
|
440
|
+
></nr-chatbot>
|
|
441
|
+
</div>
|
|
442
|
+
`;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Interactive demo with initial messages
|
|
448
|
+
*/
|
|
449
|
+
export const WithInitialMessages: Story = {
|
|
450
|
+
args: {
|
|
451
|
+
...Default.args
|
|
452
|
+
},
|
|
453
|
+
render: (args) => {
|
|
454
|
+
const initialMessages: ChatbotMessage[] = [
|
|
455
|
+
{
|
|
456
|
+
id: 'welcome-1',
|
|
457
|
+
sender: ChatbotSender.Bot,
|
|
458
|
+
text: 'Hello! 👋 Welcome to the chatbot demo. I\'m powered by a mock provider that simulates realistic conversations.',
|
|
459
|
+
timestamp: new Date().toISOString(),
|
|
460
|
+
introduction: true
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
id: 'welcome-2',
|
|
464
|
+
sender: ChatbotSender.Bot,
|
|
465
|
+
text: 'Try asking me questions! I can respond contextually to greetings, questions about features, and more.',
|
|
466
|
+
timestamp: new Date().toISOString()
|
|
467
|
+
}
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
setTimeout(() => {
|
|
471
|
+
const chatbot = document.querySelector('#initial-messages-chatbot') as any;
|
|
472
|
+
if (chatbot && !chatbot.controller) {
|
|
473
|
+
const controller = new ChatbotCoreController({
|
|
474
|
+
provider: new MockProvider({
|
|
475
|
+
delay: 600,
|
|
476
|
+
streaming: true,
|
|
477
|
+
streamingSpeed: 4,
|
|
478
|
+
streamingInterval: 25,
|
|
479
|
+
contextualResponses: true
|
|
480
|
+
}),
|
|
481
|
+
initialMessages,
|
|
482
|
+
ui: {
|
|
483
|
+
onStateChange: (state) => {
|
|
484
|
+
chatbot.messages = state.messages;
|
|
485
|
+
chatbot.isBotTyping = state.isTyping;
|
|
486
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
chatbot.controller = controller;
|
|
492
|
+
chatbot.suggestions = sampleSuggestions;
|
|
493
|
+
}
|
|
494
|
+
}, 0);
|
|
495
|
+
|
|
496
|
+
return html`
|
|
497
|
+
<div style="width: 500px; height: 600px;">
|
|
498
|
+
<nr-chatbot
|
|
499
|
+
id="initial-messages-chatbot"
|
|
500
|
+
.size=${args.size}
|
|
501
|
+
.variant=${args.variant}
|
|
502
|
+
.isRTL=${args.isRTL}
|
|
503
|
+
.disabled=${args.disabled}
|
|
504
|
+
.showSendButton=${args.showSendButton}
|
|
505
|
+
.autoScroll=${args.autoScroll}
|
|
506
|
+
.showThreads=${args.showThreads}
|
|
507
|
+
.boxed=${args.boxed}
|
|
508
|
+
></nr-chatbot>
|
|
509
|
+
</div>
|
|
510
|
+
`;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* RTL (Right-to-Left) layout demo - Interactive Arabic interface!
|
|
516
|
+
* Try the Arabic suggestions or type your own messages.
|
|
517
|
+
*/
|
|
518
|
+
export const RTLLayout: Story = {
|
|
519
|
+
args: {
|
|
520
|
+
...Default.args,
|
|
521
|
+
isRTL: true
|
|
522
|
+
},
|
|
523
|
+
render: (args) => {
|
|
524
|
+
setTimeout(() => {
|
|
525
|
+
const chatbot = document.querySelector('#rtl-chatbot') as any;
|
|
526
|
+
if (chatbot && !chatbot.controller) {
|
|
527
|
+
const controller = createControllerForElement(chatbot, {
|
|
528
|
+
delay: 500,
|
|
529
|
+
streaming: true,
|
|
530
|
+
streamingSpeed: 3,
|
|
531
|
+
streamingInterval: 30,
|
|
532
|
+
contextualResponses: true
|
|
533
|
+
});
|
|
534
|
+
chatbot.controller = controller;
|
|
535
|
+
chatbot.suggestions = [
|
|
536
|
+
{ id: 'rtl1', text: 'مرحبا كيف حالك؟', enabled: true },
|
|
537
|
+
{ id: 'rtl2', text: 'ما هي الميزات المتاحة؟', enabled: true },
|
|
538
|
+
{ id: 'rtl3', text: 'كيف يمكنني البدء؟', enabled: true },
|
|
539
|
+
{ id: 'rtl4', text: 'أخبرني عن نفسك', enabled: true }
|
|
540
|
+
];
|
|
541
|
+
}
|
|
542
|
+
}, 0);
|
|
543
|
+
|
|
544
|
+
return html`
|
|
545
|
+
<div style="width: 500px; height: 600px;">
|
|
546
|
+
<nr-chatbot
|
|
547
|
+
id="rtl-chatbot"
|
|
548
|
+
.size=${args.size}
|
|
549
|
+
.variant=${args.variant}
|
|
550
|
+
.isRTL=${args.isRTL}
|
|
551
|
+
.disabled=${args.disabled}
|
|
552
|
+
.showSendButton=${args.showSendButton}
|
|
553
|
+
.autoScroll=${args.autoScroll}
|
|
554
|
+
.showThreads=${args.showThreads}
|
|
555
|
+
.boxed=${args.boxed}
|
|
556
|
+
></nr-chatbot>
|
|
557
|
+
</div>
|
|
558
|
+
`;
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Different size variants - All fully interactive!
|
|
564
|
+
*/
|
|
565
|
+
export const SizeVariants: Story = {
|
|
566
|
+
render: () => {
|
|
567
|
+
['small', 'medium', 'large'].forEach((size) => {
|
|
568
|
+
setTimeout(() => {
|
|
569
|
+
const chatbot = document.querySelector(`#chatbot-${size}`) as any;
|
|
570
|
+
if (chatbot && !chatbot.controller) {
|
|
571
|
+
const controller = createControllerForElement(chatbot, {
|
|
572
|
+
delay: 500,
|
|
573
|
+
streaming: true,
|
|
574
|
+
streamingSpeed: 4,
|
|
575
|
+
streamingInterval: 25,
|
|
576
|
+
contextualResponses: true
|
|
577
|
+
});
|
|
578
|
+
chatbot.controller = controller;
|
|
579
|
+
chatbot.suggestions = sampleSuggestions;
|
|
580
|
+
}
|
|
581
|
+
}, 0);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
return html`
|
|
585
|
+
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
|
586
|
+
<div style="flex: 1; min-width: 300px;">
|
|
587
|
+
<h3>Small</h3>
|
|
588
|
+
<div style="width: 100%; height: 400px;">
|
|
589
|
+
<nr-chatbot
|
|
590
|
+
id="chatbot-small"
|
|
591
|
+
.size=${ChatbotSize.Small}
|
|
592
|
+
></nr-chatbot>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
<div style="flex: 1; min-width: 300px;">
|
|
596
|
+
<h3>Medium</h3>
|
|
597
|
+
<div style="width: 100%; height: 500px;">
|
|
598
|
+
<nr-chatbot
|
|
599
|
+
id="chatbot-medium"
|
|
600
|
+
.size=${ChatbotSize.Medium}
|
|
601
|
+
></nr-chatbot>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
<div style="flex: 1; min-width: 300px;">
|
|
605
|
+
<h3>Large</h3>
|
|
606
|
+
<div style="width: 100%; height: 600px;">
|
|
607
|
+
<nr-chatbot
|
|
608
|
+
id="chatbot-large"
|
|
609
|
+
.size=${ChatbotSize.Large}
|
|
610
|
+
></nr-chatbot>
|
|
611
|
+
</div>
|
|
612
|
+
</div>
|
|
613
|
+
</div>
|
|
614
|
+
`;
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Custom provider configuration demo
|
|
620
|
+
*/
|
|
621
|
+
export const CustomConfiguration: Story = {
|
|
622
|
+
args: {
|
|
623
|
+
...Default.args
|
|
624
|
+
},
|
|
625
|
+
render: (args) => {
|
|
626
|
+
setTimeout(() => {
|
|
627
|
+
const chatbot = document.querySelector('#custom-config-chatbot') as any;
|
|
628
|
+
if (chatbot && !chatbot.controller) {
|
|
629
|
+
// Create controller with custom mock responses
|
|
630
|
+
const controller = new ChatbotCoreController({
|
|
631
|
+
provider: new MockProvider({
|
|
632
|
+
delay: 400,
|
|
633
|
+
streaming: true,
|
|
634
|
+
streamingSpeed: 6,
|
|
635
|
+
streamingInterval: 20,
|
|
636
|
+
contextualResponses: true,
|
|
637
|
+
customResponses: [
|
|
638
|
+
"That's a great question! Let me provide you with a detailed answer...",
|
|
639
|
+
"I understand your concern. Here's what I can tell you:",
|
|
640
|
+
"Based on my knowledge, I would recommend the following approach:",
|
|
641
|
+
"Excellent point! This is an important topic to discuss.",
|
|
642
|
+
"Let me break this down for you in a simple way:"
|
|
643
|
+
]
|
|
644
|
+
}),
|
|
645
|
+
ui: {
|
|
646
|
+
onStateChange: (state) => {
|
|
647
|
+
chatbot.messages = state.messages;
|
|
648
|
+
chatbot.isBotTyping = state.isTyping;
|
|
649
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
650
|
+
},
|
|
651
|
+
showNotification: (message, type) => {
|
|
652
|
+
console.log(`[${type.toUpperCase()}]`, message);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
chatbot.controller = controller;
|
|
658
|
+
chatbot.suggestions = sampleSuggestions;
|
|
659
|
+
}
|
|
660
|
+
}, 0);
|
|
661
|
+
|
|
662
|
+
return html`
|
|
663
|
+
<div style="width: 500px; height: 600px;">
|
|
664
|
+
<nr-chatbot
|
|
665
|
+
id="custom-config-chatbot"
|
|
666
|
+
.size=${args.size}
|
|
667
|
+
.variant=${args.variant}
|
|
668
|
+
.isRTL=${args.isRTL}
|
|
669
|
+
.disabled=${args.disabled}
|
|
670
|
+
.showSendButton=${args.showSendButton}
|
|
671
|
+
.autoScroll=${args.autoScroll}
|
|
672
|
+
.showThreads=${args.showThreads}
|
|
673
|
+
.boxed=${args.boxed}
|
|
674
|
+
></nr-chatbot>
|
|
675
|
+
</div>
|
|
676
|
+
`;
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Boxed layout with threads - ChatGPT-style with conversation management
|
|
682
|
+
* Create multiple conversations and switch between them seamlessly!
|
|
683
|
+
*/
|
|
684
|
+
export const BoxedWithThreads: Story = {
|
|
685
|
+
args: {
|
|
686
|
+
...Default.args,
|
|
687
|
+
boxed: true,
|
|
688
|
+
showThreads: true
|
|
689
|
+
},
|
|
690
|
+
parameters: {
|
|
691
|
+
layout: 'fullscreen'
|
|
692
|
+
},
|
|
693
|
+
render: (args) => {
|
|
694
|
+
setTimeout(() => {
|
|
695
|
+
const chatbot = document.querySelector('#boxed-threads-chatbot') as any;
|
|
696
|
+
if (chatbot && !chatbot.controller) {
|
|
697
|
+
// Create controller with thread support and file upload enabled
|
|
698
|
+
const controller = new ChatbotCoreController({
|
|
699
|
+
provider: new MockProvider({
|
|
700
|
+
delay: 500,
|
|
701
|
+
streaming: true,
|
|
702
|
+
streamingSpeed: 5,
|
|
703
|
+
streamingInterval: 20,
|
|
704
|
+
contextualResponses: true
|
|
705
|
+
}),
|
|
706
|
+
enableThreads: true,
|
|
707
|
+
enableFileUpload: true,
|
|
708
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
709
|
+
maxFiles: 5,
|
|
710
|
+
allowedFileTypes: ['image/*', 'application/pdf', 'text/*', 'video/*', 'audio/*'],
|
|
711
|
+
ui: {
|
|
712
|
+
onStateChange: (state) => {
|
|
713
|
+
chatbot.messages = state.messages;
|
|
714
|
+
chatbot.threads = state.threads;
|
|
715
|
+
chatbot.isBotTyping = state.isTyping;
|
|
716
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
717
|
+
chatbot.uploadedFiles = state.uploadedFiles;
|
|
718
|
+
},
|
|
719
|
+
onTypingStart: () => {
|
|
720
|
+
chatbot.isBotTyping = true;
|
|
721
|
+
},
|
|
722
|
+
onTypingEnd: () => {
|
|
723
|
+
chatbot.isBotTyping = false;
|
|
724
|
+
},
|
|
725
|
+
focusInput: () => {
|
|
726
|
+
chatbot.focusInput();
|
|
727
|
+
},
|
|
728
|
+
showNotification: (message, type) => {
|
|
729
|
+
console.log(`[${type.toUpperCase()}] ${message}`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
chatbot.controller = controller;
|
|
735
|
+
//chatbot.suggestions;
|
|
736
|
+
chatbot.enableThreadCreation = true;
|
|
737
|
+
chatbot.enableFileUpload = true;
|
|
738
|
+
chatbot.actionButtons = [
|
|
739
|
+
{ type: 'attach', enabled: true }
|
|
740
|
+
];
|
|
741
|
+
}
|
|
742
|
+
}, 0);
|
|
743
|
+
|
|
744
|
+
return html`
|
|
745
|
+
<div style="width: 100vw; height: 100vh; background: var(--nr-color-background, #f5f5f5);">
|
|
746
|
+
<nr-chatbot
|
|
747
|
+
id="boxed-threads-chatbot"
|
|
748
|
+
.size=${args.size}
|
|
749
|
+
.variant=${args.variant}
|
|
750
|
+
.isRTL=${args.isRTL}
|
|
751
|
+
.disabled=${args.disabled}
|
|
752
|
+
.showSendButton=${args.showSendButton}
|
|
753
|
+
.autoScroll=${args.autoScroll}
|
|
754
|
+
.showThreads=${args.showThreads}
|
|
755
|
+
.boxed=${args.boxed}
|
|
756
|
+
></nr-chatbot>
|
|
757
|
+
</div>
|
|
758
|
+
`;
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Message attachments: initial message shows file tags
|
|
764
|
+
*/
|
|
765
|
+
export const WithInitialMessageAttachments: Story = {
|
|
766
|
+
args: {
|
|
767
|
+
...Default.args,
|
|
768
|
+
boxed: false
|
|
769
|
+
},
|
|
770
|
+
render: (args) => {
|
|
771
|
+
setTimeout(() => {
|
|
772
|
+
const chatbot = document.querySelector('#attachments-initial-chatbot') as any;
|
|
773
|
+
if (chatbot && !chatbot.controller) {
|
|
774
|
+
const controller = new ChatbotCoreController({
|
|
775
|
+
provider: new MockProvider({
|
|
776
|
+
delay: 400,
|
|
777
|
+
streaming: true,
|
|
778
|
+
streamingSpeed: 4,
|
|
779
|
+
streamingInterval: 20,
|
|
780
|
+
contextualResponses: true
|
|
781
|
+
}),
|
|
782
|
+
initialMessages: [
|
|
783
|
+
{
|
|
784
|
+
id: 'intro',
|
|
785
|
+
sender: ChatbotSender.Bot,
|
|
786
|
+
text: 'Hi! I can analyze your files. Try sending a message with attachments.',
|
|
787
|
+
timestamp: new Date().toISOString()
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
id: 'with-files',
|
|
791
|
+
sender: ChatbotSender.User,
|
|
792
|
+
text: 'Please analyze the attached documents.',
|
|
793
|
+
timestamp: new Date().toISOString(),
|
|
794
|
+
files: [
|
|
795
|
+
{ id: 'f1', name: 'report.pdf', size: 123456, type: ChatbotFileType.Document, mimeType: 'application/pdf' },
|
|
796
|
+
{ id: 'f2', name: 'notes.txt', size: 2048, type: ChatbotFileType.Document, mimeType: 'text/plain' }
|
|
797
|
+
]
|
|
798
|
+
}
|
|
799
|
+
],
|
|
800
|
+
ui: {
|
|
801
|
+
onStateChange: (state) => {
|
|
802
|
+
chatbot.messages = state.messages;
|
|
803
|
+
chatbot.isBotTyping = state.isTyping;
|
|
804
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
chatbot.controller = controller;
|
|
809
|
+
}
|
|
810
|
+
}, 0);
|
|
811
|
+
|
|
812
|
+
return html`
|
|
813
|
+
<div style="width: 500px; height: 600px;">
|
|
814
|
+
<nr-chatbot
|
|
815
|
+
id="attachments-initial-chatbot"
|
|
816
|
+
.size=${args.size}
|
|
817
|
+
.variant=${args.variant}
|
|
818
|
+
.isRTL=${args.isRTL}
|
|
819
|
+
.disabled=${args.disabled}
|
|
820
|
+
.showSendButton=${args.showSendButton}
|
|
821
|
+
.autoScroll=${args.autoScroll}
|
|
822
|
+
.showThreads=${args.showThreads}
|
|
823
|
+
.boxed=${args.boxed}
|
|
824
|
+
></nr-chatbot>
|
|
825
|
+
</div>
|
|
826
|
+
`;
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Message attachments: attach files, then send to see tags move to the message
|
|
832
|
+
*/
|
|
833
|
+
export const WithFileUploadAttachments: Story = {
|
|
834
|
+
args: {
|
|
835
|
+
...Default.args,
|
|
836
|
+
boxed: false
|
|
837
|
+
},
|
|
838
|
+
render: (args) => {
|
|
839
|
+
setTimeout(() => {
|
|
840
|
+
const chatbot = document.querySelector('#attachments-upload-chatbot') as any;
|
|
841
|
+
const attachBtn = document.querySelector('#attach-sample-file') as HTMLButtonElement | null;
|
|
842
|
+
const sendBtn = document.querySelector('#send-with-files') as HTMLButtonElement | null;
|
|
843
|
+
|
|
844
|
+
if (chatbot && !chatbot.controller) {
|
|
845
|
+
const controller = new ChatbotCoreController({
|
|
846
|
+
provider: new MockProvider({
|
|
847
|
+
delay: 400,
|
|
848
|
+
streaming: true,
|
|
849
|
+
streamingSpeed: 4,
|
|
850
|
+
streamingInterval: 20,
|
|
851
|
+
contextualResponses: true
|
|
852
|
+
}),
|
|
853
|
+
enableFileUpload: true,
|
|
854
|
+
ui: {
|
|
855
|
+
onStateChange: (state) => {
|
|
856
|
+
chatbot.messages = state.messages;
|
|
857
|
+
chatbot.isBotTyping = state.isTyping;
|
|
858
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
859
|
+
chatbot.uploadedFiles = state.uploadedFiles;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
chatbot.controller = controller;
|
|
864
|
+
chatbot.enableFileUpload = true;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Wire demo buttons
|
|
868
|
+
if (attachBtn) {
|
|
869
|
+
attachBtn.onclick = async () => {
|
|
870
|
+
const chatbotEl = document.querySelector('#attachments-upload-chatbot') as any;
|
|
871
|
+
const controller = chatbotEl?.controller as ChatbotCoreController | undefined;
|
|
872
|
+
if (!controller) return;
|
|
873
|
+
// Create a sample File via Blob
|
|
874
|
+
const pdfBlob = new Blob([new Uint8Array([0x25,0x50,0x44,0x46])], { type: 'application/pdf' });
|
|
875
|
+
const txtBlob = new Blob(['Sample notes'], { type: 'text/plain' });
|
|
876
|
+
const pdf = new File([pdfBlob], 'sample.pdf', { type: 'application/pdf' });
|
|
877
|
+
const txt = new File([txtBlob], 'notes.txt', { type: 'text/plain' });
|
|
878
|
+
await controller.uploadFiles([pdf, txt]);
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (sendBtn) {
|
|
883
|
+
sendBtn.onclick = async () => {
|
|
884
|
+
const chatbotEl = document.querySelector('#attachments-upload-chatbot') as any;
|
|
885
|
+
const controller = chatbotEl?.controller as ChatbotCoreController | undefined;
|
|
886
|
+
if (!controller) return;
|
|
887
|
+
const files = controller.getUploadedFiles();
|
|
888
|
+
await controller.sendMessage('Analyze the attached files, please.', { files });
|
|
889
|
+
controller.clearFiles();
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
}, 0);
|
|
893
|
+
|
|
894
|
+
return html`
|
|
895
|
+
<div style="display: grid; gap: 12px; width: 520px;">
|
|
896
|
+
<div style="display:flex; gap: 8px; align-items:center;">
|
|
897
|
+
<button id="attach-sample-file" type="button">Attach sample files</button>
|
|
898
|
+
<button id="send-with-files" type="button">Send with files</button>
|
|
899
|
+
<span style="color:#666; font-size:12px;">Or use the Attach button inside the chatbot</span>
|
|
900
|
+
</div>
|
|
901
|
+
<div style="width: 500px; height: 600px;">
|
|
902
|
+
<nr-chatbot
|
|
903
|
+
id="attachments-upload-chatbot"
|
|
904
|
+
.size=${args.size}
|
|
905
|
+
.variant=${args.variant}
|
|
906
|
+
.isRTL=${args.isRTL}
|
|
907
|
+
.disabled=${args.disabled}
|
|
908
|
+
.showSendButton=${args.showSendButton}
|
|
909
|
+
.autoScroll=${args.autoScroll}
|
|
910
|
+
.showThreads=${args.showThreads}
|
|
911
|
+
.boxed=${args.boxed}
|
|
912
|
+
></nr-chatbot>
|
|
913
|
+
</div>
|
|
914
|
+
</div>
|
|
915
|
+
`;
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Storage - Memory Storage (Non-persistent)
|
|
921
|
+
* Messages are stored in memory only - lost on page refresh.
|
|
922
|
+
* Try sending messages and note they disappear when you refresh the page.
|
|
923
|
+
*/
|
|
924
|
+
export const StorageMemory: Story = {
|
|
925
|
+
args: {
|
|
926
|
+
...Default.args,
|
|
927
|
+
showThreads: true
|
|
928
|
+
},
|
|
929
|
+
render: (args) => {
|
|
930
|
+
setTimeout(() => {
|
|
931
|
+
const chatbot = document.querySelector('#storage-memory-chatbot') as any;
|
|
932
|
+
if (chatbot && !chatbot.controller) {
|
|
933
|
+
const controller = new ChatbotCoreController({
|
|
934
|
+
provider: new MockProvider({
|
|
935
|
+
delay: 500,
|
|
936
|
+
streaming: true,
|
|
937
|
+
streamingSpeed: 5,
|
|
938
|
+
streamingInterval: 20,
|
|
939
|
+
contextualResponses: true
|
|
940
|
+
}),
|
|
941
|
+
storage: new MemoryStorage(),
|
|
942
|
+
enableThreads: true,
|
|
943
|
+
autoSaveInterval: 1000, // Auto-save every 1 second
|
|
944
|
+
ui: {
|
|
945
|
+
onStateChange: (state) => {
|
|
946
|
+
chatbot.messages = state.messages;
|
|
947
|
+
chatbot.threads = state.threads;
|
|
948
|
+
chatbot.isBotTyping = state.isTyping;
|
|
949
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
950
|
+
},
|
|
951
|
+
onTypingStart: () => {
|
|
952
|
+
chatbot.isBotTyping = true;
|
|
953
|
+
},
|
|
954
|
+
onTypingEnd: () => {
|
|
955
|
+
chatbot.isBotTyping = false;
|
|
956
|
+
},
|
|
957
|
+
showNotification: (message, type) => {
|
|
958
|
+
console.log(`[MemoryStorage ${type.toUpperCase()}] ${message}`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
chatbot.controller = controller;
|
|
964
|
+
chatbot.suggestions = [
|
|
965
|
+
{ id: 'mem1', text: 'Send a message', enabled: true },
|
|
966
|
+
{ id: 'mem2', text: 'Create a thread', enabled: true },
|
|
967
|
+
{ id: 'mem3', text: 'Messages will be lost on refresh!', enabled: true }
|
|
968
|
+
];
|
|
969
|
+
chatbot.enableThreadCreation = true;
|
|
970
|
+
|
|
971
|
+
// Display storage info
|
|
972
|
+
setTimeout(() => {
|
|
973
|
+
console.log('[MemoryStorage] Using in-memory storage - data will be lost on page refresh');
|
|
974
|
+
}, 100);
|
|
975
|
+
}
|
|
976
|
+
}, 0);
|
|
977
|
+
|
|
978
|
+
return html`
|
|
979
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
980
|
+
<div style="padding: 16px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 8px;">
|
|
981
|
+
<h3 style="margin: 0 0 8px 0; color: #856404;">🔄 Memory Storage</h3>
|
|
982
|
+
<p style="margin: 0; color: #856404;">
|
|
983
|
+
Messages are stored in memory only and <strong>will be lost on page refresh</strong>.
|
|
984
|
+
Perfect for temporary conversations or demos.
|
|
985
|
+
</p>
|
|
986
|
+
</div>
|
|
987
|
+
<div style="width: 800px; height: 600px;">
|
|
988
|
+
<nr-chatbot
|
|
989
|
+
id="storage-memory-chatbot"
|
|
990
|
+
.size=${args.size}
|
|
991
|
+
.variant=${args.variant}
|
|
992
|
+
.isRTL=${args.isRTL}
|
|
993
|
+
.disabled=${args.disabled}
|
|
994
|
+
.showSendButton=${args.showSendButton}
|
|
995
|
+
.autoScroll=${args.autoScroll}
|
|
996
|
+
.showThreads=${args.showThreads}
|
|
997
|
+
.boxed=${args.boxed}
|
|
998
|
+
></nr-chatbot>
|
|
999
|
+
</div>
|
|
1000
|
+
</div>
|
|
1001
|
+
`;
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Storage - LocalStorage (Persistent)
|
|
1007
|
+
* Messages persist across page refreshes using browser's localStorage.
|
|
1008
|
+
* Try sending messages, refresh the page, and see them still there!
|
|
1009
|
+
*/
|
|
1010
|
+
export const StorageLocalStorage: Story = {
|
|
1011
|
+
args: {
|
|
1012
|
+
...Default.args,
|
|
1013
|
+
showThreads: true
|
|
1014
|
+
},
|
|
1015
|
+
render: (args) => {
|
|
1016
|
+
setTimeout(() => {
|
|
1017
|
+
const chatbot = document.querySelector('#storage-localstorage-chatbot') as any;
|
|
1018
|
+
if (chatbot && !chatbot.controller) {
|
|
1019
|
+
const controller = new ChatbotCoreController({
|
|
1020
|
+
provider: new MockProvider({
|
|
1021
|
+
delay: 500,
|
|
1022
|
+
streaming: true,
|
|
1023
|
+
streamingSpeed: 5,
|
|
1024
|
+
streamingInterval: 20,
|
|
1025
|
+
contextualResponses: true
|
|
1026
|
+
}),
|
|
1027
|
+
storage: new LocalStorageAdapter(),
|
|
1028
|
+
enableThreads: true,
|
|
1029
|
+
autoSaveInterval: 2000, // Auto-save every 2 seconds
|
|
1030
|
+
ui: {
|
|
1031
|
+
onStateChange: (state) => {
|
|
1032
|
+
chatbot.messages = state.messages;
|
|
1033
|
+
chatbot.threads = state.threads;
|
|
1034
|
+
chatbot.isBotTyping = state.isTyping;
|
|
1035
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
1036
|
+
},
|
|
1037
|
+
onTypingStart: () => {
|
|
1038
|
+
chatbot.isBotTyping = true;
|
|
1039
|
+
},
|
|
1040
|
+
onTypingEnd: () => {
|
|
1041
|
+
chatbot.isBotTyping = false;
|
|
1042
|
+
},
|
|
1043
|
+
showNotification: (message, type) => {
|
|
1044
|
+
console.log(`[LocalStorage ${type.toUpperCase()}] ${message}`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
chatbot.controller = controller;
|
|
1050
|
+
chatbot.suggestions = [
|
|
1051
|
+
{ id: 'local1', text: 'Send a message and refresh!', enabled: true },
|
|
1052
|
+
{ id: 'local2', text: 'Create multiple threads', enabled: true },
|
|
1053
|
+
{ id: 'local3', text: 'Messages persist across refreshes', enabled: true }
|
|
1054
|
+
];
|
|
1055
|
+
chatbot.enableThreadCreation = true;
|
|
1056
|
+
|
|
1057
|
+
// Load persisted data
|
|
1058
|
+
setTimeout(async () => {
|
|
1059
|
+
try {
|
|
1060
|
+
await controller.loadFromStorage('chatbot-state');
|
|
1061
|
+
console.log('[LocalStorage] Successfully loaded persisted conversation history');
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
console.log('[LocalStorage] No persisted data found - starting fresh');
|
|
1064
|
+
}
|
|
1065
|
+
}, 100);
|
|
1066
|
+
}
|
|
1067
|
+
}, 0);
|
|
1068
|
+
|
|
1069
|
+
return html`
|
|
1070
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
1071
|
+
<div style="padding: 16px; background: #d1ecf1; border: 1px solid #17a2b8; border-radius: 8px;">
|
|
1072
|
+
<h3 style="margin: 0 0 8px 0; color: #0c5460;">💾 LocalStorage Persistence</h3>
|
|
1073
|
+
<p style="margin: 0 0 8px 0; color: #0c5460;">
|
|
1074
|
+
Messages persist across page refreshes using <strong>localStorage</strong>.
|
|
1075
|
+
Try sending messages, then refresh the page!
|
|
1076
|
+
</p>
|
|
1077
|
+
<button
|
|
1078
|
+
onclick="localStorage.clear(); location.reload();"
|
|
1079
|
+
style="padding: 8px 16px; background: #17a2b8; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
|
1080
|
+
🗑️ Clear Storage & Reload
|
|
1081
|
+
</button>
|
|
1082
|
+
</div>
|
|
1083
|
+
<div style="width: 800px; height: 600px;">
|
|
1084
|
+
<nr-chatbot
|
|
1085
|
+
id="storage-localstorage-chatbot"
|
|
1086
|
+
.size=${args.size}
|
|
1087
|
+
.variant=${args.variant}
|
|
1088
|
+
.isRTL=${args.isRTL}
|
|
1089
|
+
.disabled=${args.disabled}
|
|
1090
|
+
.showSendButton=${args.showSendButton}
|
|
1091
|
+
.autoScroll=${args.autoScroll}
|
|
1092
|
+
.showThreads=${args.showThreads}
|
|
1093
|
+
.boxed=${args.boxed}
|
|
1094
|
+
></nr-chatbot>
|
|
1095
|
+
</div>
|
|
1096
|
+
</div>
|
|
1097
|
+
`;
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Storage - IndexedDB (High Performance)
|
|
1103
|
+
* Messages persist using IndexedDB for larger datasets and better performance.
|
|
1104
|
+
* Ideal for production applications with extensive conversation history.
|
|
1105
|
+
*/
|
|
1106
|
+
export const StorageIndexedDB: Story = {
|
|
1107
|
+
args: {
|
|
1108
|
+
...Default.args,
|
|
1109
|
+
showThreads: true
|
|
1110
|
+
},
|
|
1111
|
+
render: (args) => {
|
|
1112
|
+
setTimeout(() => {
|
|
1113
|
+
const chatbot = document.querySelector('#storage-indexeddb-chatbot') as any;
|
|
1114
|
+
if (chatbot && !chatbot.controller) {
|
|
1115
|
+
const indexedDBStorage = new IndexedDBStorage('chatbot-demo-db', 'conversations');
|
|
1116
|
+
|
|
1117
|
+
const controller = new ChatbotCoreController({
|
|
1118
|
+
provider: new MockProvider({
|
|
1119
|
+
delay: 500,
|
|
1120
|
+
streaming: true,
|
|
1121
|
+
streamingSpeed: 5,
|
|
1122
|
+
streamingInterval: 20,
|
|
1123
|
+
contextualResponses: true
|
|
1124
|
+
}),
|
|
1125
|
+
storage: indexedDBStorage,
|
|
1126
|
+
enableThreads: true,
|
|
1127
|
+
autoSaveInterval: 3000, // Auto-save every 3 seconds
|
|
1128
|
+
ui: {
|
|
1129
|
+
onStateChange: (state) => {
|
|
1130
|
+
chatbot.messages = state.messages;
|
|
1131
|
+
chatbot.threads = state.threads;
|
|
1132
|
+
chatbot.isBotTyping = state.isTyping;
|
|
1133
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
1134
|
+
},
|
|
1135
|
+
onTypingStart: () => {
|
|
1136
|
+
chatbot.isBotTyping = true;
|
|
1137
|
+
},
|
|
1138
|
+
onTypingEnd: () => {
|
|
1139
|
+
chatbot.isBotTyping = false;
|
|
1140
|
+
},
|
|
1141
|
+
showNotification: (message, type) => {
|
|
1142
|
+
console.log(`[IndexedDB ${type.toUpperCase()}] ${message}`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
chatbot.controller = controller;
|
|
1148
|
+
chatbot.suggestions = [
|
|
1149
|
+
{ id: 'idb1', text: 'High performance storage', enabled: true },
|
|
1150
|
+
{ id: 'idb2', text: 'Handles large datasets', enabled: true },
|
|
1151
|
+
{ id: 'idb3', text: 'Production-ready persistence', enabled: true }
|
|
1152
|
+
];
|
|
1153
|
+
chatbot.enableThreadCreation = true;
|
|
1154
|
+
|
|
1155
|
+
// Load persisted data
|
|
1156
|
+
setTimeout(async () => {
|
|
1157
|
+
try {
|
|
1158
|
+
await controller.loadFromStorage('chatbot-state');
|
|
1159
|
+
console.log('[IndexedDB] Successfully loaded persisted conversation history');
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
console.log('[IndexedDB] No persisted data found - starting fresh');
|
|
1162
|
+
}
|
|
1163
|
+
}, 100);
|
|
1164
|
+
}
|
|
1165
|
+
}, 0);
|
|
1166
|
+
|
|
1167
|
+
return html`
|
|
1168
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
1169
|
+
<div style="padding: 16px; background: #d4edda; border: 1px solid #28a745; border-radius: 8px;">
|
|
1170
|
+
<h3 style="margin: 0 0 8px 0; color: #155724;">🚀 IndexedDB Storage</h3>
|
|
1171
|
+
<p style="margin: 0 0 8px 0; color: #155724;">
|
|
1172
|
+
High-performance persistent storage using <strong>IndexedDB</strong>.
|
|
1173
|
+
Perfect for production apps with extensive conversation history.
|
|
1174
|
+
</p>
|
|
1175
|
+
<div style="display: flex; gap: 8px;">
|
|
1176
|
+
<button
|
|
1177
|
+
onclick="
|
|
1178
|
+
const db = indexedDB.open('chatbot-demo-db');
|
|
1179
|
+
db.onsuccess = (e) => {
|
|
1180
|
+
const database = e.target.result;
|
|
1181
|
+
const transaction = database.transaction(['conversations'], 'readwrite');
|
|
1182
|
+
const store = transaction.objectStore('conversations');
|
|
1183
|
+
store.clear();
|
|
1184
|
+
console.log('[IndexedDB] Cleared all data');
|
|
1185
|
+
setTimeout(() => location.reload(), 500);
|
|
1186
|
+
};
|
|
1187
|
+
"
|
|
1188
|
+
style="padding: 8px 16px; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
|
1189
|
+
🗑️ Clear IndexedDB & Reload
|
|
1190
|
+
</button>
|
|
1191
|
+
<button
|
|
1192
|
+
onclick="
|
|
1193
|
+
const db = indexedDB.open('chatbot-demo-db');
|
|
1194
|
+
db.onsuccess = (e) => {
|
|
1195
|
+
const database = e.target.result;
|
|
1196
|
+
const transaction = database.transaction(['conversations'], 'readonly');
|
|
1197
|
+
const store = transaction.objectStore('conversations');
|
|
1198
|
+
const request = store.get('chatbot-state');
|
|
1199
|
+
request.onsuccess = () => {
|
|
1200
|
+
console.log('[IndexedDB] Current state:', request.result);
|
|
1201
|
+
alert('Check console for IndexedDB data');
|
|
1202
|
+
};
|
|
1203
|
+
};
|
|
1204
|
+
"
|
|
1205
|
+
style="padding: 8px 16px; background: #17a2b8; color: white; border: none; border-radius: 4px; cursor: pointer;">
|
|
1206
|
+
🔍 Inspect Data
|
|
1207
|
+
</button>
|
|
1208
|
+
</div>
|
|
1209
|
+
</div>
|
|
1210
|
+
<div style="width: 800px; height: 600px;">
|
|
1211
|
+
<nr-chatbot
|
|
1212
|
+
id="storage-indexeddb-chatbot"
|
|
1213
|
+
.size=${args.size}
|
|
1214
|
+
.variant=${args.variant}
|
|
1215
|
+
.isRTL=${args.isRTL}
|
|
1216
|
+
.disabled=${args.disabled}
|
|
1217
|
+
.showSendButton=${args.showSendButton}
|
|
1218
|
+
.autoScroll=${args.autoScroll}
|
|
1219
|
+
.showThreads=${args.showThreads}
|
|
1220
|
+
.boxed=${args.boxed}
|
|
1221
|
+
></nr-chatbot>
|
|
1222
|
+
</div>
|
|
1223
|
+
</div>
|
|
1224
|
+
`;
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Storage Comparison - See all three storage types side by side
|
|
1230
|
+
* Compare Memory, LocalStorage, and IndexedDB implementations.
|
|
1231
|
+
*/
|
|
1232
|
+
export const StorageComparison: Story = {
|
|
1233
|
+
args: {
|
|
1234
|
+
...Default.args,
|
|
1235
|
+
showThreads: false
|
|
1236
|
+
},
|
|
1237
|
+
render: (args) => {
|
|
1238
|
+
['memory', 'localstorage', 'indexeddb'].forEach((storageType) => {
|
|
1239
|
+
setTimeout(() => {
|
|
1240
|
+
const chatbot = document.querySelector(`#chatbot-${storageType}`) as any;
|
|
1241
|
+
if (chatbot && !chatbot.controller) {
|
|
1242
|
+
let storage;
|
|
1243
|
+
let storageLabel;
|
|
1244
|
+
|
|
1245
|
+
if (storageType === 'memory') {
|
|
1246
|
+
storage = new MemoryStorage();
|
|
1247
|
+
storageLabel = 'Memory';
|
|
1248
|
+
} else if (storageType === 'localstorage') {
|
|
1249
|
+
storage = new LocalStorageAdapter();
|
|
1250
|
+
storageLabel = 'LocalStorage';
|
|
1251
|
+
} else {
|
|
1252
|
+
storage = new IndexedDBStorage(`chatbot-${storageType}-db`, 'messages');
|
|
1253
|
+
storageLabel = 'IndexedDB';
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
const controller = new ChatbotCoreController({
|
|
1257
|
+
provider: new MockProvider({
|
|
1258
|
+
delay: 300,
|
|
1259
|
+
streaming: true,
|
|
1260
|
+
streamingSpeed: 8,
|
|
1261
|
+
streamingInterval: 15,
|
|
1262
|
+
contextualResponses: true
|
|
1263
|
+
}),
|
|
1264
|
+
storage,
|
|
1265
|
+
enableThreads: false,
|
|
1266
|
+
autoSaveInterval: 2000,
|
|
1267
|
+
ui: {
|
|
1268
|
+
onStateChange: (state) => {
|
|
1269
|
+
chatbot.messages = state.messages;
|
|
1270
|
+
chatbot.isBotTyping = state.isTyping;
|
|
1271
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
1272
|
+
},
|
|
1273
|
+
showNotification: (message, type) => {
|
|
1274
|
+
console.log(`[${storageLabel} ${type.toUpperCase()}] ${message}`);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
chatbot.controller = controller;
|
|
1280
|
+
chatbot.suggestions = [
|
|
1281
|
+
{ id: `${storageType}-1`, text: `Test ${storageLabel}`, enabled: true }
|
|
1282
|
+
];
|
|
1283
|
+
}
|
|
1284
|
+
}, 0);
|
|
1285
|
+
});
|
|
1286
|
+
|
|
1287
|
+
return html`
|
|
1288
|
+
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
1289
|
+
<div style="padding: 16px; background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px;">
|
|
1290
|
+
<h3 style="margin: 0 0 8px 0;">📊 Storage Comparison</h3>
|
|
1291
|
+
<p style="margin: 0;">
|
|
1292
|
+
Compare all three storage implementations side by side.
|
|
1293
|
+
Send messages to each and refresh to see persistence differences.
|
|
1294
|
+
</p>
|
|
1295
|
+
</div>
|
|
1296
|
+
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
|
1297
|
+
<div style="flex: 1; min-width: 300px;">
|
|
1298
|
+
<h4 style="margin: 0 0 8px 0; padding: 8px; background: #fff3cd; border-radius: 4px;">
|
|
1299
|
+
🔄 Memory Storage
|
|
1300
|
+
</h4>
|
|
1301
|
+
<div style="width: 100%; height: 450px;">
|
|
1302
|
+
<nr-chatbot
|
|
1303
|
+
id="chatbot-memory"
|
|
1304
|
+
.size=${ChatbotSize.Small}
|
|
1305
|
+
.variant=${args.variant}
|
|
1306
|
+
.showSendButton=${true}
|
|
1307
|
+
.autoScroll=${true}
|
|
1308
|
+
></nr-chatbot>
|
|
1309
|
+
</div>
|
|
1310
|
+
<p style="font-size: 12px; color: #666; margin-top: 8px;">
|
|
1311
|
+
⚠️ Lost on refresh
|
|
1312
|
+
</p>
|
|
1313
|
+
</div>
|
|
1314
|
+
<div style="flex: 1; min-width: 300px;">
|
|
1315
|
+
<h4 style="margin: 0 0 8px 0; padding: 8px; background: #d1ecf1; border-radius: 4px;">
|
|
1316
|
+
💾 LocalStorage
|
|
1317
|
+
</h4>
|
|
1318
|
+
<div style="width: 100%; height: 450px;">
|
|
1319
|
+
<nr-chatbot
|
|
1320
|
+
id="chatbot-localstorage"
|
|
1321
|
+
.size=${ChatbotSize.Small}
|
|
1322
|
+
.variant=${args.variant}
|
|
1323
|
+
.showSendButton=${true}
|
|
1324
|
+
.autoScroll=${true}
|
|
1325
|
+
></nr-chatbot>
|
|
1326
|
+
</div>
|
|
1327
|
+
<p style="font-size: 12px; color: #666; margin-top: 8px;">
|
|
1328
|
+
✅ Persists across refreshes
|
|
1329
|
+
</p>
|
|
1330
|
+
</div>
|
|
1331
|
+
<div style="flex: 1; min-width: 300px;">
|
|
1332
|
+
<h4 style="margin: 0 0 8px 0; padding: 8px; background: #d4edda; border-radius: 4px;">
|
|
1333
|
+
🚀 IndexedDB
|
|
1334
|
+
</h4>
|
|
1335
|
+
<div style="width: 100%; height: 450px;">
|
|
1336
|
+
<nr-chatbot
|
|
1337
|
+
id="chatbot-indexeddb"
|
|
1338
|
+
.size=${ChatbotSize.Small}
|
|
1339
|
+
.variant=${args.variant}
|
|
1340
|
+
.showSendButton=${true}
|
|
1341
|
+
.autoScroll=${true}
|
|
1342
|
+
></nr-chatbot>
|
|
1343
|
+
</div>
|
|
1344
|
+
<p style="font-size: 12px; color: #666; margin-top: 8px;">
|
|
1345
|
+
✅ High performance persistence
|
|
1346
|
+
</p>
|
|
1347
|
+
</div>
|
|
1348
|
+
</div>
|
|
1349
|
+
</div>
|
|
1350
|
+
`;
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Custom API Provider with Custom Headers - Test multipart/form-data streaming
|
|
1356
|
+
* Tests CustomAPIProvider with custom Content-Type headers and streaming text/plain response.
|
|
1357
|
+
*/
|
|
1358
|
+
export const CustomAPIWithHeaders: Story = {
|
|
1359
|
+
args: {
|
|
1360
|
+
...Default.args,
|
|
1361
|
+
boxed: true,
|
|
1362
|
+
showThreads: false
|
|
1363
|
+
},
|
|
1364
|
+
parameters: {
|
|
1365
|
+
layout: 'fullscreen'
|
|
1366
|
+
},
|
|
1367
|
+
render: (args) => {
|
|
1368
|
+
// Mock fetch to simulate streaming text/plain response
|
|
1369
|
+
const originalFetch = window.fetch;
|
|
1370
|
+
const mockFetch = async (url: string | URL | Request, options?: RequestInit) => {
|
|
1371
|
+
if (url.toString().includes('/api/v3/iassistant/text-processing')) {
|
|
1372
|
+
console.log('🎯 Intercepted API call to:', url);
|
|
1373
|
+
console.log('📦 Request options:', options);
|
|
1374
|
+
|
|
1375
|
+
// Simulate streaming text/plain response
|
|
1376
|
+
const responseText = 'This is a simulated streaming response from the API. It demonstrates how the chatbot handles text/plain content type with streaming. Each chunk arrives progressively to create a typewriter effect. 🎉';
|
|
1377
|
+
|
|
1378
|
+
const stream = new ReadableStream({
|
|
1379
|
+
start(controller) {
|
|
1380
|
+
let index = 0;
|
|
1381
|
+
const interval = setInterval(() => {
|
|
1382
|
+
if (index < responseText.length) {
|
|
1383
|
+
// Send 1-3 characters at a time to simulate realistic streaming
|
|
1384
|
+
const chunkSize = Math.floor(Math.random() * 3) + 1;
|
|
1385
|
+
const chunk = responseText.slice(index, index + chunkSize);
|
|
1386
|
+
controller.enqueue(new TextEncoder().encode(chunk));
|
|
1387
|
+
index += chunkSize;
|
|
1388
|
+
} else {
|
|
1389
|
+
clearInterval(interval);
|
|
1390
|
+
controller.close();
|
|
1391
|
+
}
|
|
1392
|
+
}, 50); // 50ms delay between chunks
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
return new Response(stream, {
|
|
1397
|
+
status: 200,
|
|
1398
|
+
headers: {
|
|
1399
|
+
'Content-Type': 'text/plain',
|
|
1400
|
+
'Transfer-Encoding': 'chunked'
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
return originalFetch(url, options);
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
setTimeout(async () => {
|
|
1408
|
+
const chatbot = document.querySelector('#custom-api-headers-chatbot') as any;
|
|
1409
|
+
if (chatbot && !chatbot.controller) {
|
|
1410
|
+
// Temporarily replace fetch
|
|
1411
|
+
window.fetch = mockFetch as any;
|
|
1412
|
+
|
|
1413
|
+
// Import CustomAPIProvider
|
|
1414
|
+
const { CustomAPIProvider } = await import('./providers/custom-api-provider.js');
|
|
1415
|
+
|
|
1416
|
+
// Extend CustomAPIProvider to override buildPayload
|
|
1417
|
+
class ExtendedAPIProvider extends CustomAPIProvider {
|
|
1418
|
+
buildPayload(text: string, context: any): any {
|
|
1419
|
+
console.log('📤 Building payload with context:', context);
|
|
1420
|
+
const payload = {
|
|
1421
|
+
userText: text,
|
|
1422
|
+
variables: context.metadata || {},
|
|
1423
|
+
tag: context.metadata?.tag || 'default',
|
|
1424
|
+
stream: true
|
|
1425
|
+
};
|
|
1426
|
+
console.log('📤 Payload:', payload);
|
|
1427
|
+
return payload;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
const provider = new ExtendedAPIProvider();
|
|
1432
|
+
|
|
1433
|
+
// Connect with custom headers
|
|
1434
|
+
try {
|
|
1435
|
+
await provider.connect({
|
|
1436
|
+
apiUrl: '/api/v3/iassistant/text-processing',
|
|
1437
|
+
headers: {
|
|
1438
|
+
'accept': 'text/plain',
|
|
1439
|
+
'Content-Type': 'multipart/form-data'
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
console.log('✅ CustomAPIProvider connected with custom headers');
|
|
1443
|
+
console.log('📋 Headers configured for multipart/form-data with text/plain streaming');
|
|
1444
|
+
} catch (error) {
|
|
1445
|
+
console.error('❌ Failed to connect:', error);
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
const controller = new ChatbotCoreController({
|
|
1449
|
+
provider,
|
|
1450
|
+
enableThreads: false,
|
|
1451
|
+
enableFileUpload: true,
|
|
1452
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
1453
|
+
maxFiles: 5,
|
|
1454
|
+
allowedFileTypes: ['image/*', 'application/pdf', 'text/*', 'video/*', 'audio/*'],
|
|
1455
|
+
metadata: {
|
|
1456
|
+
tag: 'summarize'
|
|
1457
|
+
},
|
|
1458
|
+
ui: {
|
|
1459
|
+
onStateChange: (state) => {
|
|
1460
|
+
chatbot.messages = state.messages;
|
|
1461
|
+
chatbot.threads = state.threads;
|
|
1462
|
+
chatbot.isBotTyping = state.isTyping;
|
|
1463
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
1464
|
+
chatbot.uploadedFiles = state.uploadedFiles;
|
|
1465
|
+
},
|
|
1466
|
+
onTypingStart: () => { chatbot.isBotTyping = true; },
|
|
1467
|
+
onTypingEnd: () => { chatbot.isBotTyping = false; },
|
|
1468
|
+
focusInput: () => { chatbot.focusInput(); },
|
|
1469
|
+
showNotification: (message, type) => {
|
|
1470
|
+
console.log(`[${type.toUpperCase()}] ${message}`);
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1475
|
+
chatbot.controller = controller;
|
|
1476
|
+
chatbot.enableThreadCreation = false;
|
|
1477
|
+
chatbot.enableFileUpload = true;
|
|
1478
|
+
chatbot.actionButtons = [
|
|
1479
|
+
{ type: 'attach', enabled: true }
|
|
1480
|
+
];
|
|
1481
|
+
|
|
1482
|
+
chatbot.suggestions = [
|
|
1483
|
+
{ id: 'test1', text: 'Test streaming response', enabled: true },
|
|
1484
|
+
{ id: 'test2', text: 'Send with multipart/form-data', enabled: true },
|
|
1485
|
+
{ id: 'test3', text: 'Check console for logs', enabled: true }
|
|
1486
|
+
];
|
|
1487
|
+
|
|
1488
|
+
// Cleanup on unmount
|
|
1489
|
+
const cleanup = () => {
|
|
1490
|
+
window.fetch = originalFetch;
|
|
1491
|
+
};
|
|
1492
|
+
|
|
1493
|
+
// Store cleanup for later
|
|
1494
|
+
(window as any).__storyCleanup = cleanup;
|
|
1495
|
+
}
|
|
1496
|
+
}, 0);
|
|
1497
|
+
|
|
1498
|
+
return html`
|
|
1499
|
+
<div style="width: 100vw; height: 100vh; background: var(--nr-color-background, #f5f5f5);">
|
|
1500
|
+
<div style="position: absolute; top: 16px; left: 16px; right: 16px; z-index: 1000; padding: 16px; background: #fff; border: 2px solid #28a745; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
|
|
1501
|
+
<h3 style="margin: 0 0 8px 0; color: #155724;">🎬 Custom API Provider - Streaming Test</h3>
|
|
1502
|
+
<p style="margin: 0 0 8px 0; color: #155724; font-size: 14px;">
|
|
1503
|
+
This story tests <strong>multipart/form-data</strong> with <strong>text/plain streaming</strong>:
|
|
1504
|
+
</p>
|
|
1505
|
+
<ul style="margin: 0; padding-left: 20px; color: #155724; font-size: 13px;">
|
|
1506
|
+
<li>✅ <strong>Request:</strong> multipart/form-data (FormData fields)</li>
|
|
1507
|
+
<li>✅ <strong>Response:</strong> text/plain with streaming</li>
|
|
1508
|
+
<li>✅ <strong>Metadata tag:</strong> summarize</li>
|
|
1509
|
+
<li>✅ <strong>Effect:</strong> Typewriter streaming animation</li>
|
|
1510
|
+
</ul>
|
|
1511
|
+
<p style="margin: 8px 0 0 0; color: #0c5460; font-size: 12px; background: #d1ecf1; padding: 8px; border-radius: 4px;">
|
|
1512
|
+
💡 <strong>Try it:</strong> Send a message and watch it stream character by character!
|
|
1513
|
+
Open the <strong>Console</strong> to see request/response logs.
|
|
1514
|
+
</p>
|
|
1515
|
+
</div>
|
|
1516
|
+
<nr-chatbot
|
|
1517
|
+
id="custom-api-headers-chatbot"
|
|
1518
|
+
.size=${args.size}
|
|
1519
|
+
.variant=${args.variant}
|
|
1520
|
+
.isRTL=${args.isRTL}
|
|
1521
|
+
.disabled=${args.disabled}
|
|
1522
|
+
.showSendButton=${args.showSendButton}
|
|
1523
|
+
.autoScroll=${args.autoScroll}
|
|
1524
|
+
.showThreads=${args.showThreads}
|
|
1525
|
+
.boxed=${args.boxed}
|
|
1526
|
+
style="padding-top: 220px;"
|
|
1527
|
+
></nr-chatbot>
|
|
1528
|
+
</div>
|
|
1529
|
+
`;
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
|
|
1533
|
+
/**
|
|
1534
|
+
* Custom API Provider - Error Handling Showcase
|
|
1535
|
+
* Demonstrates styled error messages in the chat.
|
|
1536
|
+
*/
|
|
1537
|
+
export const CustomAPIErrorHandling: Story = {
|
|
1538
|
+
args: {
|
|
1539
|
+
...Default.args,
|
|
1540
|
+
boxed: false
|
|
1541
|
+
},
|
|
1542
|
+
render: (args) => {
|
|
1543
|
+
// Mock fetch to simulate different error scenarios
|
|
1544
|
+
const originalFetch = window.fetch;
|
|
1545
|
+
let errorScenario = 0;
|
|
1546
|
+
|
|
1547
|
+
const mockFetch = async (url: string | URL | Request, options?: RequestInit) => {
|
|
1548
|
+
if (url.toString().includes('/api/v3/iassistant/text-processing')) {
|
|
1549
|
+
console.log('🎯 Intercepted API call - Scenario:', errorScenario);
|
|
1550
|
+
|
|
1551
|
+
// Cycle through different error scenarios
|
|
1552
|
+
const scenarios = [
|
|
1553
|
+
// Scenario 0: Success
|
|
1554
|
+
() => {
|
|
1555
|
+
const stream = new ReadableStream({
|
|
1556
|
+
start(controller) {
|
|
1557
|
+
const text = '✅ Success! This is a successful streaming response.';
|
|
1558
|
+
let index = 0;
|
|
1559
|
+
const interval = setInterval(() => {
|
|
1560
|
+
if (index < text.length) {
|
|
1561
|
+
controller.enqueue(new TextEncoder().encode(text[index]));
|
|
1562
|
+
index++;
|
|
1563
|
+
} else {
|
|
1564
|
+
clearInterval(interval);
|
|
1565
|
+
controller.close();
|
|
1566
|
+
}
|
|
1567
|
+
}, 30);
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
return new Response(stream, {
|
|
1571
|
+
status: 200,
|
|
1572
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1573
|
+
});
|
|
1574
|
+
},
|
|
1575
|
+
// Scenario 1: 404 Not Found
|
|
1576
|
+
() => new Response('The requested endpoint was not found on this server.', {
|
|
1577
|
+
status: 404,
|
|
1578
|
+
statusText: 'Not Found',
|
|
1579
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1580
|
+
}),
|
|
1581
|
+
// Scenario 2: 500 Internal Server Error
|
|
1582
|
+
() => new Response('An internal server error occurred while processing your request.', {
|
|
1583
|
+
status: 500,
|
|
1584
|
+
statusText: 'Internal Server Error',
|
|
1585
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1586
|
+
}),
|
|
1587
|
+
// Scenario 3: 401 Unauthorized
|
|
1588
|
+
() => new Response('You must be authenticated to access this resource.', {
|
|
1589
|
+
status: 401,
|
|
1590
|
+
statusText: 'Unauthorized',
|
|
1591
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1592
|
+
}),
|
|
1593
|
+
// Scenario 4: Network error (simulated)
|
|
1594
|
+
() => Promise.reject(new Error('Failed to fetch: Network connection was lost')),
|
|
1595
|
+
// Scenario 5: Streaming error mid-stream
|
|
1596
|
+
() => {
|
|
1597
|
+
const stream = new ReadableStream({
|
|
1598
|
+
start(controller) {
|
|
1599
|
+
const text = 'Starting to stream response... ';
|
|
1600
|
+
controller.enqueue(new TextEncoder().encode(text));
|
|
1601
|
+
setTimeout(() => {
|
|
1602
|
+
controller.error(new Error('Connection interrupted while streaming'));
|
|
1603
|
+
}, 100);
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
return new Response(stream, {
|
|
1607
|
+
status: 200,
|
|
1608
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
];
|
|
1612
|
+
|
|
1613
|
+
const scenario = scenarios[errorScenario % scenarios.length];
|
|
1614
|
+
errorScenario = (errorScenario + 1) % scenarios.length;
|
|
1615
|
+
|
|
1616
|
+
return scenario();
|
|
1617
|
+
}
|
|
1618
|
+
return originalFetch(url, options);
|
|
1619
|
+
};
|
|
1620
|
+
|
|
1621
|
+
setTimeout(async () => {
|
|
1622
|
+
const chatbot = document.querySelector('#error-handling-chatbot') as any;
|
|
1623
|
+
if (chatbot && !chatbot.controller) {
|
|
1624
|
+
window.fetch = mockFetch as any;
|
|
1625
|
+
|
|
1626
|
+
const { CustomAPIProvider } = await import('./providers/custom-api-provider.js');
|
|
1627
|
+
|
|
1628
|
+
class ExtendedAPIProvider extends CustomAPIProvider {
|
|
1629
|
+
buildPayload(text: string, context: any): any {
|
|
1630
|
+
return {
|
|
1631
|
+
userText: text,
|
|
1632
|
+
variables: context.metadata || {},
|
|
1633
|
+
tag: context.metadata?.tag || 'default',
|
|
1634
|
+
stream: true
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
const provider = new ExtendedAPIProvider();
|
|
1640
|
+
|
|
1641
|
+
await provider.connect({
|
|
1642
|
+
apiUrl: '/api/v3/iassistant/text-processing',
|
|
1643
|
+
headers: {
|
|
1644
|
+
'accept': 'text/plain',
|
|
1645
|
+
'Content-Type': 'multipart/form-data'
|
|
1646
|
+
}
|
|
1647
|
+
});
|
|
1648
|
+
|
|
1649
|
+
const controller = new ChatbotCoreController({
|
|
1650
|
+
provider,
|
|
1651
|
+
metadata: { tag: 'test' },
|
|
1652
|
+
ui: {
|
|
1653
|
+
onStateChange: (state) => {
|
|
1654
|
+
chatbot.messages = state.messages;
|
|
1655
|
+
chatbot.isBotTyping = state.isTyping;
|
|
1656
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
1657
|
+
},
|
|
1658
|
+
onTypingStart: () => { chatbot.isBotTyping = true; },
|
|
1659
|
+
onTypingEnd: () => { chatbot.isBotTyping = false; },
|
|
1660
|
+
focusInput: () => { chatbot.focusInput(); }
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1663
|
+
|
|
1664
|
+
chatbot.controller = controller;
|
|
1665
|
+
chatbot.suggestions = [
|
|
1666
|
+
{ id: 'test1', text: 'Test success (1st)', enabled: true },
|
|
1667
|
+
{ id: 'test2', text: 'Test 404 error (2nd)', enabled: true },
|
|
1668
|
+
{ id: 'test3', text: 'Test 500 error (3rd)', enabled: true },
|
|
1669
|
+
{ id: 'test4', text: 'Test 401 error (4th)', enabled: true },
|
|
1670
|
+
{ id: 'test5', text: 'Test network error (5th)', enabled: true },
|
|
1671
|
+
{ id: 'test6', text: 'Test stream error (6th)', enabled: true }
|
|
1672
|
+
];
|
|
1673
|
+
|
|
1674
|
+
(window as any).__storyCleanup = () => {
|
|
1675
|
+
window.fetch = originalFetch;
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
}, 0);
|
|
1679
|
+
|
|
1680
|
+
return html`
|
|
1681
|
+
<div style="display: flex; flex-direction: column; gap: 16px; padding: 20px; max-width: 800px;">
|
|
1682
|
+
<div style="padding: 16px; background: #fff; border: 2px solid #dc3545; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
|
|
1683
|
+
<h3 style="margin: 0 0 8px 0; color: #721c24;">🚨 Styled Error Handling</h3>
|
|
1684
|
+
<p style="margin: 0 0 8px 0; color: #721c24; font-size: 14px;">
|
|
1685
|
+
Errors are displayed in a styled container with a title and description:
|
|
1686
|
+
</p>
|
|
1687
|
+
<ul style="margin: 0; padding-left: 20px; color: #721c24; font-size: 13px;">
|
|
1688
|
+
<li><strong>1st message:</strong> ✅ Success - Normal streaming response</li>
|
|
1689
|
+
<li><strong>2nd message:</strong> ⚠️ 404 Not Found error</li>
|
|
1690
|
+
<li><strong>3rd message:</strong> ⚠️ 500 Internal Server Error</li>
|
|
1691
|
+
<li><strong>4th message:</strong> ⚠️ 401 Unauthorized error</li>
|
|
1692
|
+
<li><strong>5th message:</strong> ⚠️ Network connection error</li>
|
|
1693
|
+
<li><strong>6th message:</strong> ⚠️ Streaming interrupted mid-stream</li>
|
|
1694
|
+
</ul>
|
|
1695
|
+
<p style="margin: 8px 0 0 0; color: #0c5460; font-size: 12px; background: #d1ecf1; padding: 8px; border-radius: 4px;">
|
|
1696
|
+
💡 <strong>Try it:</strong> Send messages one by one to see each error type with styled formatting!
|
|
1697
|
+
</p>
|
|
1698
|
+
</div>
|
|
1699
|
+
<div style="width: 100%; height: 600px; border: 1px solid #dee2e6; border-radius: 8px; overflow: hidden;">
|
|
1700
|
+
<nr-chatbot
|
|
1701
|
+
id="error-handling-chatbot"
|
|
1702
|
+
.size=${args.size}
|
|
1703
|
+
.variant=${args.variant}
|
|
1704
|
+
.showSendButton=${true}
|
|
1705
|
+
.autoScroll=${true}
|
|
1706
|
+
></nr-chatbot>
|
|
1707
|
+
</div>
|
|
1708
|
+
</div>
|
|
1709
|
+
`;
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1713
|
+
/**
|
|
1714
|
+
* Mock API with Conversation Loading
|
|
1715
|
+
* Tests overriding conversation loading by mocking fetch API to simulate:
|
|
1716
|
+
* - Loading existing conversations from API
|
|
1717
|
+
* - Creating new conversations
|
|
1718
|
+
* - Switching between conversations
|
|
1719
|
+
* - Deleting conversations
|
|
1720
|
+
*/
|
|
1721
|
+
export const MockAPIWithConversationLoading: Story = {
|
|
1722
|
+
args: {
|
|
1723
|
+
...Default.args,
|
|
1724
|
+
showThreads: true
|
|
1725
|
+
},
|
|
1726
|
+
render: (args) => {
|
|
1727
|
+
const originalFetch = window.fetch;
|
|
1728
|
+
|
|
1729
|
+
// Mock conversation data
|
|
1730
|
+
const mockConversations = [
|
|
1731
|
+
{
|
|
1732
|
+
id: 'conv_1',
|
|
1733
|
+
title: 'Product Recommendations',
|
|
1734
|
+
messages: [
|
|
1735
|
+
{
|
|
1736
|
+
id: 'msg_1',
|
|
1737
|
+
text: 'Can you recommend a laptop for programming?',
|
|
1738
|
+
sender: 'user' as ChatbotSender,
|
|
1739
|
+
timestamp: new Date(Date.now() - 3600000).toISOString()
|
|
1740
|
+
},
|
|
1741
|
+
{
|
|
1742
|
+
id: 'msg_2',
|
|
1743
|
+
text: 'I recommend the MacBook Pro M3 for development work. It offers excellent performance, long battery life, and a great development environment with macOS.',
|
|
1744
|
+
sender: 'bot' as ChatbotSender,
|
|
1745
|
+
timestamp: new Date(Date.now() - 3590000).toISOString()
|
|
1746
|
+
}
|
|
1747
|
+
],
|
|
1748
|
+
createdAt: new Date(Date.now() - 7200000).toISOString(),
|
|
1749
|
+
updatedAt: new Date(Date.now() - 3590000).toISOString()
|
|
1750
|
+
},
|
|
1751
|
+
{
|
|
1752
|
+
id: 'conv_2',
|
|
1753
|
+
title: 'Web Development Tips',
|
|
1754
|
+
messages: [
|
|
1755
|
+
{
|
|
1756
|
+
id: 'msg_3',
|
|
1757
|
+
text: 'What are the best practices for React development?',
|
|
1758
|
+
sender: 'user' as ChatbotSender,
|
|
1759
|
+
timestamp: new Date(Date.now() - 86400000).toISOString()
|
|
1760
|
+
},
|
|
1761
|
+
{
|
|
1762
|
+
id: 'msg_4',
|
|
1763
|
+
text: 'Key React best practices include: 1) Use functional components with hooks, 2) Keep components small and focused, 3) Use proper state management, 4) Implement code splitting, and 5) Follow the single responsibility principle.',
|
|
1764
|
+
sender: 'bot' as ChatbotSender,
|
|
1765
|
+
timestamp: new Date(Date.now() - 86395000).toISOString()
|
|
1766
|
+
},
|
|
1767
|
+
{
|
|
1768
|
+
id: 'msg_5',
|
|
1769
|
+
text: 'How about TypeScript integration?',
|
|
1770
|
+
sender: 'user' as ChatbotSender,
|
|
1771
|
+
timestamp: new Date(Date.now() - 86300000).toISOString()
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
id: 'msg_6',
|
|
1775
|
+
text: 'TypeScript with React is highly recommended! It provides type safety, better IDE support, and catches errors at compile time. Use proper typing for props, state, and events.',
|
|
1776
|
+
sender: 'bot' as ChatbotSender,
|
|
1777
|
+
timestamp: new Date(Date.now() - 86295000).toISOString()
|
|
1778
|
+
}
|
|
1779
|
+
],
|
|
1780
|
+
createdAt: new Date(Date.now() - 172800000).toISOString(),
|
|
1781
|
+
updatedAt: new Date(Date.now() - 86295000).toISOString()
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
id: 'conv_3',
|
|
1785
|
+
title: 'Database Design Question',
|
|
1786
|
+
messages: [
|
|
1787
|
+
{
|
|
1788
|
+
id: 'msg_7',
|
|
1789
|
+
text: 'What database should I use for a high-traffic app?',
|
|
1790
|
+
sender: 'user' as ChatbotSender,
|
|
1791
|
+
timestamp: new Date(Date.now() - 259200000).toISOString()
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
id: 'msg_8',
|
|
1795
|
+
text: 'For high-traffic applications, consider PostgreSQL for relational data or MongoDB for document-based data. Redis is excellent for caching. The choice depends on your data structure and query patterns.',
|
|
1796
|
+
sender: 'bot' as ChatbotSender,
|
|
1797
|
+
timestamp: new Date(Date.now() - 259195000).toISOString()
|
|
1798
|
+
}
|
|
1799
|
+
],
|
|
1800
|
+
createdAt: new Date(Date.now() - 259200000).toISOString(),
|
|
1801
|
+
updatedAt: new Date(Date.now() - 259195000).toISOString()
|
|
1802
|
+
}
|
|
1803
|
+
];
|
|
1804
|
+
|
|
1805
|
+
let conversationStore = [...mockConversations];
|
|
1806
|
+
|
|
1807
|
+
// Mock fetch implementation
|
|
1808
|
+
const mockFetch = async (url: string | URL | Request, options?: RequestInit) => {
|
|
1809
|
+
const urlString = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
1810
|
+
|
|
1811
|
+
// Mock: Load specific conversation (check this BEFORE the list endpoint)
|
|
1812
|
+
if (urlString.match(/\/api\/conversations\/[^/?]+$/) && (!options?.method || options?.method === 'GET')) {
|
|
1813
|
+
const conversationId = urlString.split('/').pop();
|
|
1814
|
+
const conversation = conversationStore.find(c => c.id === conversationId);
|
|
1815
|
+
|
|
1816
|
+
await new Promise(resolve => setTimeout(resolve, 300)); // Simulate network delay
|
|
1817
|
+
|
|
1818
|
+
if (conversation) {
|
|
1819
|
+
return new Response(JSON.stringify(conversation), {
|
|
1820
|
+
status: 200,
|
|
1821
|
+
headers: { 'Content-Type': 'application/json' }
|
|
1822
|
+
});
|
|
1823
|
+
} else {
|
|
1824
|
+
return new Response(JSON.stringify({ error: 'Conversation not found' }), {
|
|
1825
|
+
status: 404,
|
|
1826
|
+
headers: { 'Content-Type': 'application/json' }
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
// Mock: Load conversations list
|
|
1832
|
+
if (urlString.includes('/api/conversations') && (!options?.method || options?.method === 'GET')) {
|
|
1833
|
+
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate network delay
|
|
1834
|
+
return new Response(JSON.stringify({
|
|
1835
|
+
conversations: conversationStore.map(c => ({
|
|
1836
|
+
id: c.id,
|
|
1837
|
+
title: c.title,
|
|
1838
|
+
messageCount: c.messages.length,
|
|
1839
|
+
createdAt: c.createdAt,
|
|
1840
|
+
updatedAt: c.updatedAt
|
|
1841
|
+
}))
|
|
1842
|
+
}), {
|
|
1843
|
+
status: 200,
|
|
1844
|
+
headers: { 'Content-Type': 'application/json' }
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
// Mock: Create new conversation
|
|
1849
|
+
if (urlString.includes('/api/conversations') && options?.method === 'POST') {
|
|
1850
|
+
await new Promise(resolve => setTimeout(resolve, 400)); // Simulate network delay
|
|
1851
|
+
|
|
1852
|
+
const body = JSON.parse(options?.body as string || '{}');
|
|
1853
|
+
const newConversation = {
|
|
1854
|
+
id: `conv_${Date.now()}`,
|
|
1855
|
+
title: body.title || `Chat ${conversationStore.length + 1}`,
|
|
1856
|
+
messages: [],
|
|
1857
|
+
createdAt: new Date().toISOString(),
|
|
1858
|
+
updatedAt: new Date().toISOString()
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1861
|
+
conversationStore = [newConversation, ...conversationStore];
|
|
1862
|
+
|
|
1863
|
+
return new Response(JSON.stringify(newConversation), {
|
|
1864
|
+
status: 201,
|
|
1865
|
+
headers: { 'Content-Type': 'application/json' }
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// Mock: Delete conversation
|
|
1870
|
+
if (urlString.match(/\/api\/conversations\/[^/]+$/) && options?.method === 'DELETE') {
|
|
1871
|
+
const conversationId = urlString.split('/').pop();
|
|
1872
|
+
await new Promise(resolve => setTimeout(resolve, 300)); // Simulate network delay
|
|
1873
|
+
|
|
1874
|
+
conversationStore = conversationStore.filter(c => c.id !== conversationId);
|
|
1875
|
+
|
|
1876
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
1877
|
+
status: 200,
|
|
1878
|
+
headers: { 'Content-Type': 'application/json' }
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// Mock: Send message to conversation (streaming response)
|
|
1883
|
+
if (urlString.includes('/api/chat') && options?.method === 'POST') {
|
|
1884
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
1885
|
+
|
|
1886
|
+
const body = JSON.parse(options?.body as string || '{}');
|
|
1887
|
+
const userMessage = body.message || body.userMessage || body.text;
|
|
1888
|
+
|
|
1889
|
+
// Generate AI response based on keywords
|
|
1890
|
+
let aiResponse = 'I understand your question. Let me help you with that.';
|
|
1891
|
+
|
|
1892
|
+
if (userMessage.toLowerCase().includes('hello') || userMessage.toLowerCase().includes('hi')) {
|
|
1893
|
+
aiResponse = 'Hello! 👋 How can I assist you today?';
|
|
1894
|
+
} else if (userMessage.toLowerCase().includes('api')) {
|
|
1895
|
+
aiResponse = 'APIs are essential for modern web development. They allow different applications to communicate with each other. RESTful APIs are the most common, using HTTP methods like GET, POST, PUT, and DELETE.';
|
|
1896
|
+
} else if (userMessage.toLowerCase().includes('conversation') || userMessage.toLowerCase().includes('thread')) {
|
|
1897
|
+
aiResponse = 'This chatbot supports multiple conversations! You can create new threads, switch between them, and each conversation maintains its own history. Try creating a new conversation using the sidebar.';
|
|
1898
|
+
} else if (userMessage.toLowerCase().includes('help')) {
|
|
1899
|
+
aiResponse = 'I can help you with:\n• Web development questions\n• Programming best practices\n• Technology recommendations\n• Code architecture advice\n\nJust ask me anything!';
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
// Stream the response
|
|
1903
|
+
const stream = new ReadableStream({
|
|
1904
|
+
async start(controller) {
|
|
1905
|
+
for (let i = 0; i < aiResponse.length; i++) {
|
|
1906
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
1907
|
+
controller.enqueue(new TextEncoder().encode(aiResponse[i]));
|
|
1908
|
+
}
|
|
1909
|
+
controller.close();
|
|
1910
|
+
}
|
|
1911
|
+
});
|
|
1912
|
+
|
|
1913
|
+
return new Response(stream, {
|
|
1914
|
+
status: 200,
|
|
1915
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
// Fallback to original fetch for other requests
|
|
1920
|
+
return originalFetch(url, options);
|
|
1921
|
+
};
|
|
1922
|
+
|
|
1923
|
+
setTimeout(async () => {
|
|
1924
|
+
const chatbot = document.querySelector('#conversation-loading-chatbot') as any;
|
|
1925
|
+
if (chatbot && !chatbot.controller) {
|
|
1926
|
+
// Override fetch
|
|
1927
|
+
window.fetch = mockFetch as any;
|
|
1928
|
+
|
|
1929
|
+
const { CustomAPIProvider } = await import('./providers/custom-api-provider.js');
|
|
1930
|
+
|
|
1931
|
+
// Type definitions for API responses
|
|
1932
|
+
interface ConversationSummary {
|
|
1933
|
+
id: string;
|
|
1934
|
+
title: string;
|
|
1935
|
+
messageCount: number;
|
|
1936
|
+
createdAt: string;
|
|
1937
|
+
updatedAt: string;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
interface ConversationDetail extends ConversationSummary {
|
|
1941
|
+
messages: ChatbotMessage[];
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
interface ConversationsListResponse {
|
|
1945
|
+
conversations: ConversationSummary[];
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
// Extended provider with conversation loading support
|
|
1949
|
+
class ConversationAPIProvider extends CustomAPIProvider {
|
|
1950
|
+
async loadConversations(): Promise<ConversationSummary[]> {
|
|
1951
|
+
try {
|
|
1952
|
+
const response = await fetch('/api/conversations', { method: 'GET' });
|
|
1953
|
+
const data: ConversationsListResponse = await response.json();
|
|
1954
|
+
return data.conversations || [];
|
|
1955
|
+
} catch (error) {
|
|
1956
|
+
console.error('Failed to load conversations:', error);
|
|
1957
|
+
return [];
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
async loadConversation(conversationId: string): Promise<ConversationDetail | null> {
|
|
1962
|
+
try {
|
|
1963
|
+
const response = await fetch(`/api/conversations/${conversationId}`, { method: 'GET' });
|
|
1964
|
+
return await response.json() as ConversationDetail;
|
|
1965
|
+
} catch (error) {
|
|
1966
|
+
console.error(`Failed to load conversation ${conversationId}:`, error);
|
|
1967
|
+
return null;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
async createConversation(title?: string): Promise<ConversationDetail | null> {
|
|
1972
|
+
try {
|
|
1973
|
+
const response = await fetch('/api/conversations', {
|
|
1974
|
+
method: 'POST',
|
|
1975
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1976
|
+
body: JSON.stringify({ title })
|
|
1977
|
+
});
|
|
1978
|
+
return await response.json() as ConversationDetail;
|
|
1979
|
+
} catch (error) {
|
|
1980
|
+
console.error('Failed to create conversation:', error);
|
|
1981
|
+
return null;
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
async deleteConversation(conversationId: string): Promise<boolean> {
|
|
1986
|
+
try {
|
|
1987
|
+
const response = await fetch(`/api/conversations/${conversationId}`, { method: 'DELETE' });
|
|
1988
|
+
return response.ok;
|
|
1989
|
+
} catch (error) {
|
|
1990
|
+
console.error(`Failed to delete conversation ${conversationId}:`, error);
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
buildPayload(text: string, context: any): any {
|
|
1996
|
+
return {
|
|
1997
|
+
message: text,
|
|
1998
|
+
conversationId: context.conversationId,
|
|
1999
|
+
metadata: context.metadata || {}
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
const provider = new ConversationAPIProvider();
|
|
2005
|
+
|
|
2006
|
+
await provider.connect({
|
|
2007
|
+
apiUrl: '/api/chat',
|
|
2008
|
+
headers: {
|
|
2009
|
+
'accept': 'text/plain',
|
|
2010
|
+
'Content-Type': 'application/json'
|
|
2011
|
+
}
|
|
2012
|
+
});
|
|
2013
|
+
|
|
2014
|
+
// Create controller with threads enabled
|
|
2015
|
+
const controller = new ChatbotCoreController({
|
|
2016
|
+
provider,
|
|
2017
|
+
enableThreads: true,
|
|
2018
|
+
ui: {
|
|
2019
|
+
onStateChange: (state) => {
|
|
2020
|
+
chatbot.messages = state.messages;
|
|
2021
|
+
chatbot.threads = state.threads;
|
|
2022
|
+
chatbot.isBotTyping = state.isTyping;
|
|
2023
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
2024
|
+
},
|
|
2025
|
+
onTypingStart: () => { chatbot.isBotTyping = true; },
|
|
2026
|
+
onTypingEnd: () => { chatbot.isBotTyping = false; },
|
|
2027
|
+
focusInput: () => { chatbot.focusInput(); }
|
|
2028
|
+
}
|
|
2029
|
+
});
|
|
2030
|
+
|
|
2031
|
+
chatbot.controller = controller;
|
|
2032
|
+
|
|
2033
|
+
// Listen to thread events for debugging and state sync
|
|
2034
|
+
controller.on('thread:selected', (thread) => {
|
|
2035
|
+
console.log('Thread selected event:', thread);
|
|
2036
|
+
const state = controller.getState();
|
|
2037
|
+
console.log('Current state after selection:', {
|
|
2038
|
+
currentThreadId: state.currentThreadId,
|
|
2039
|
+
messagesCount: state.messages.length,
|
|
2040
|
+
threadsCount: state.threads.length
|
|
2041
|
+
});
|
|
2042
|
+
// Force update the UI
|
|
2043
|
+
chatbot.messages = state.messages;
|
|
2044
|
+
chatbot.threads = state.threads;
|
|
2045
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
controller.on('thread:created', (thread) => {
|
|
2049
|
+
console.log('Thread created event:', thread);
|
|
2050
|
+
const state = controller.getState();
|
|
2051
|
+
chatbot.threads = state.threads;
|
|
2052
|
+
});
|
|
2053
|
+
|
|
2054
|
+
controller.on('thread:deleted', (threadId) => {
|
|
2055
|
+
console.log('Thread deleted event:', threadId);
|
|
2056
|
+
const state = controller.getState();
|
|
2057
|
+
chatbot.threads = state.threads;
|
|
2058
|
+
chatbot.messages = state.messages;
|
|
2059
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
2060
|
+
});
|
|
2061
|
+
|
|
2062
|
+
// Load existing conversations from API
|
|
2063
|
+
try {
|
|
2064
|
+
const conversations = await provider.loadConversations();
|
|
2065
|
+
console.log('Loaded conversations:', conversations);
|
|
2066
|
+
|
|
2067
|
+
// Convert API conversations to threads
|
|
2068
|
+
const loadedThreads: ChatbotThread[] = [];
|
|
2069
|
+
for (const conv of conversations) {
|
|
2070
|
+
const fullConversation = await provider.loadConversation(conv.id);
|
|
2071
|
+
if (fullConversation) {
|
|
2072
|
+
console.log('Loaded full conversation:', fullConversation);
|
|
2073
|
+
const thread: ChatbotThread = {
|
|
2074
|
+
id: fullConversation.id,
|
|
2075
|
+
title: fullConversation.title,
|
|
2076
|
+
messages: fullConversation.messages || [],
|
|
2077
|
+
createdAt: fullConversation.createdAt,
|
|
2078
|
+
updatedAt: fullConversation.updatedAt
|
|
2079
|
+
};
|
|
2080
|
+
loadedThreads.push(thread);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// Add all threads to controller state at once
|
|
2085
|
+
if (loadedThreads.length > 0) {
|
|
2086
|
+
console.log('Setting initial state with threads:', loadedThreads);
|
|
2087
|
+
const currentState = controller.getState();
|
|
2088
|
+
controller.setState({
|
|
2089
|
+
threads: loadedThreads,
|
|
2090
|
+
currentThreadId: loadedThreads[0].id,
|
|
2091
|
+
messages: [...loadedThreads[0].messages],
|
|
2092
|
+
isTyping: false
|
|
2093
|
+
});
|
|
2094
|
+
|
|
2095
|
+
console.log('State after initialization:', controller.getState());
|
|
2096
|
+
|
|
2097
|
+
// Force UI update
|
|
2098
|
+
chatbot.threads = loadedThreads;
|
|
2099
|
+
chatbot.messages = [...loadedThreads[0].messages];
|
|
2100
|
+
chatbot.chatStarted = loadedThreads[0].messages.length > 0;
|
|
2101
|
+
|
|
2102
|
+
console.log('UI updated - messages:', chatbot.messages.length, 'threads:', chatbot.threads.length);
|
|
2103
|
+
}
|
|
2104
|
+
} catch (error) {
|
|
2105
|
+
console.error('Failed to initialize conversations:', error);
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
chatbot.suggestions = [
|
|
2109
|
+
{ id: 'api', text: 'Tell me about APIs', enabled: true },
|
|
2110
|
+
{ id: 'threads', text: 'How do conversations work?', enabled: true },
|
|
2111
|
+
{ id: 'help', text: 'What can you help with?', enabled: true }
|
|
2112
|
+
];
|
|
2113
|
+
|
|
2114
|
+
// Store cleanup function
|
|
2115
|
+
(window as any).__storyCleanup = () => {
|
|
2116
|
+
window.fetch = originalFetch;
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
}, 0);
|
|
2120
|
+
|
|
2121
|
+
return html`
|
|
2122
|
+
<div style="display: flex; flex-direction: column; gap: 16px; padding: 20px; max-width: 1200px;">
|
|
2123
|
+
<div style="padding: 16px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); color: white;">
|
|
2124
|
+
<h3 style="margin: 0 0 12px 0; font-size: 20px;">💬 Mock API with Conversation Loading</h3>
|
|
2125
|
+
<p style="margin: 0 0 12px 0; font-size: 14px; opacity: 0.95;">
|
|
2126
|
+
This story demonstrates loading existing conversations from a mocked API backend.
|
|
2127
|
+
</p>
|
|
2128
|
+
<div style="background: rgba(255,255,255,0.1); padding: 12px; border-radius: 6px; margin-bottom: 12px;">
|
|
2129
|
+
<p style="margin: 0 0 8px 0; font-weight: 600; font-size: 14px;">🔄 Mocked API Endpoints:</p>
|
|
2130
|
+
<ul style="margin: 0; padding-left: 20px; font-size: 13px; opacity: 0.9;">
|
|
2131
|
+
<li><code>GET /api/conversations</code> - Load all conversations</li>
|
|
2132
|
+
<li><code>GET /api/conversations/:id</code> - Load specific conversation</li>
|
|
2133
|
+
<li><code>POST /api/conversations</code> - Create new conversation</li>
|
|
2134
|
+
<li><code>DELETE /api/conversations/:id</code> - Delete conversation</li>
|
|
2135
|
+
<li><code>POST /api/chat</code> - Send message (streaming response)</li>
|
|
2136
|
+
</ul>
|
|
2137
|
+
</div>
|
|
2138
|
+
<div style="background: rgba(255,255,255,0.1); padding: 12px; border-radius: 6px;">
|
|
2139
|
+
<p style="margin: 0 0 8px 0; font-weight: 600; font-size: 14px;">✨ Features:</p>
|
|
2140
|
+
<ul style="margin: 0; padding-left: 20px; font-size: 13px; opacity: 0.9;">
|
|
2141
|
+
<li>3 pre-loaded conversations with message history</li>
|
|
2142
|
+
<li>Network delays simulated (300-500ms)</li>
|
|
2143
|
+
<li>Create new conversations via the sidebar</li>
|
|
2144
|
+
<li>Switch between conversations seamlessly</li>
|
|
2145
|
+
<li>Delete conversations (with API sync)</li>
|
|
2146
|
+
<li>Streaming AI responses</li>
|
|
2147
|
+
</ul>
|
|
2148
|
+
</div>
|
|
2149
|
+
</div>
|
|
2150
|
+
<div style="width: 100%; height: 700px; border: 1px solid #dee2e6; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
|
|
2151
|
+
<nr-chatbot
|
|
2152
|
+
id="conversation-loading-chatbot"
|
|
2153
|
+
.size=${args.size}
|
|
2154
|
+
.variant=${args.variant}
|
|
2155
|
+
.showSendButton=${true}
|
|
2156
|
+
.autoScroll=${true}
|
|
2157
|
+
.showThreads=${true}
|
|
2158
|
+
.boxed=${true}
|
|
2159
|
+
></nr-chatbot>
|
|
2160
|
+
</div>
|
|
2161
|
+
</div>
|
|
2162
|
+
`;
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
2165
|
+
|
|
2166
|
+
/**
|
|
2167
|
+
* Auto-Loading Conversations with Custom Provider
|
|
2168
|
+
* Demonstrates automatic conversation loading when extending CustomAPIProvider.
|
|
2169
|
+
* The controller automatically calls loadConversations() when the provider connects,
|
|
2170
|
+
* eliminating the need for manual initialization code.
|
|
2171
|
+
*/
|
|
2172
|
+
export const AutoLoadingConversations: Story = {
|
|
2173
|
+
args: {
|
|
2174
|
+
...Default.args,
|
|
2175
|
+
showThreads: true
|
|
2176
|
+
},
|
|
2177
|
+
render: (args) => {
|
|
2178
|
+
const originalFetch = window.fetch;
|
|
2179
|
+
|
|
2180
|
+
// Mock conversation data store
|
|
2181
|
+
let conversationStore = [
|
|
2182
|
+
{
|
|
2183
|
+
id: 'auto_conv_1',
|
|
2184
|
+
title: '✈️ Flight Booking',
|
|
2185
|
+
messages: [
|
|
2186
|
+
{
|
|
2187
|
+
id: 'auto_msg_1',
|
|
2188
|
+
text: 'I need to book a flight from New York to London',
|
|
2189
|
+
sender: 'user' as ChatbotSender,
|
|
2190
|
+
timestamp: new Date(Date.now() - 3600000).toISOString()
|
|
2191
|
+
},
|
|
2192
|
+
{
|
|
2193
|
+
id: 'auto_msg_2',
|
|
2194
|
+
text: 'I found some great flight options for you:\n\n[FLIGHT]{\n "flightNumber": "BA117",\n "airline": "British Airways",\n "origin": "JFK",\n "destination": "LHR",\n "departureTime": "6:30 PM",\n "arrivalTime": "6:45 AM",\n "departureDate": "Mar 15, 2024",\n "arrivalDate": "Mar 16, 2024",\n "duration": "7h 15min",\n "terminal": "7",\n "gate": "B32",\n "arrivalTerminal": "5",\n "arrivalGate": "A18"\n}[/FLIGHT]\n\nThis is a direct flight with excellent reviews! Would you like to see more options?',
|
|
2195
|
+
sender: 'bot' as ChatbotSender,
|
|
2196
|
+
timestamp: new Date(Date.now() - 3590000).toISOString()
|
|
2197
|
+
},
|
|
2198
|
+
{
|
|
2199
|
+
id: 'auto_msg_3',
|
|
2200
|
+
text: 'Perfect! Can you show me a business class option?',
|
|
2201
|
+
sender: 'user' as ChatbotSender,
|
|
2202
|
+
timestamp: new Date(Date.now() - 3580000).toISOString()
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
id: 'auto_msg_4',
|
|
2206
|
+
text: 'Here\'s a premium business class option:\n\n[FLIGHT]{\n "flightNumber": "VS4",\n "airline": "Virgin Atlantic",\n "origin": "JFK",\n "destination": "LHR",\n "departureTime": "8:00 PM",\n "arrivalTime": "8:15 AM",\n "departureDate": "Mar 15, 2024",\n "arrivalDate": "Mar 16, 2024",\n "duration": "7h 15min",\n "terminal": "4",\n "gate": "B24",\n "arrivalTerminal": "3",\n "arrivalGate": "A10",\n "status": "On Time"\n}[/FLIGHT]\n\nThis includes lie-flat seats, premium dining, priority boarding, and access to the Clubhouse lounge!',
|
|
2207
|
+
sender: 'bot' as ChatbotSender,
|
|
2208
|
+
timestamp: new Date(Date.now() - 3570000).toISOString()
|
|
2209
|
+
}
|
|
2210
|
+
],
|
|
2211
|
+
createdAt: new Date(Date.now() - 3600000).toISOString(),
|
|
2212
|
+
updatedAt: new Date(Date.now() - 3570000).toISOString()
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
id: 'auto_conv_2',
|
|
2216
|
+
title: '🚀 Project Setup Guide',
|
|
2217
|
+
messages: [
|
|
2218
|
+
{
|
|
2219
|
+
id: 'auto_msg_5',
|
|
2220
|
+
text: 'How do I set up a new React project?',
|
|
2221
|
+
sender: 'user' as ChatbotSender,
|
|
2222
|
+
timestamp: new Date(Date.now() - 7200000).toISOString()
|
|
2223
|
+
},
|
|
2224
|
+
{
|
|
2225
|
+
id: 'auto_msg_6',
|
|
2226
|
+
text: 'Here\'s a quick guide to set up a React project:\n\n1. **Using Create React App:**\n```bash\nnpx create-react-app my-app\ncd my-app\nnpm start\n```\n\n2. **Using Vite (faster):**\n```bash\nnpm create vite@latest my-app -- --template react\ncd my-app\nnpm install\nnpm run dev\n```\n\nVite is recommended for new projects due to faster build times!',
|
|
2227
|
+
sender: 'bot' as ChatbotSender,
|
|
2228
|
+
timestamp: new Date(Date.now() - 7190000).toISOString()
|
|
2229
|
+
}
|
|
2230
|
+
],
|
|
2231
|
+
createdAt: new Date(Date.now() - 7200000).toISOString(),
|
|
2232
|
+
updatedAt: new Date(Date.now() - 7190000).toISOString()
|
|
2233
|
+
},
|
|
2234
|
+
{
|
|
2235
|
+
id: 'auto_conv_3',
|
|
2236
|
+
title: '💡 TypeScript Best Practices',
|
|
2237
|
+
messages: [
|
|
2238
|
+
{
|
|
2239
|
+
id: 'auto_msg_7',
|
|
2240
|
+
text: 'What are some TypeScript best practices?',
|
|
2241
|
+
sender: 'user' as ChatbotSender,
|
|
2242
|
+
timestamp: new Date(Date.now() - 86400000).toISOString()
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
id: 'auto_msg_8',
|
|
2246
|
+
text: 'Here are key TypeScript best practices:\n\n✅ **Enable strict mode** in tsconfig.json\n✅ **Use interfaces** for object shapes\n✅ **Avoid "any" type** - use unknown or proper types\n✅ **Leverage utility types** (Partial, Pick, Omit, etc.)\n✅ **Use type guards** for runtime type checking\n✅ **Document with JSDoc** for better IDE support\n\nThese practices will make your code more maintainable and catch bugs early!',
|
|
2247
|
+
sender: 'bot' as ChatbotSender,
|
|
2248
|
+
timestamp: new Date(Date.now() - 86390000).toISOString()
|
|
2249
|
+
}
|
|
2250
|
+
],
|
|
2251
|
+
createdAt: new Date(Date.now() - 86400000).toISOString(),
|
|
2252
|
+
updatedAt: new Date(Date.now() - 86390000).toISOString()
|
|
2253
|
+
},
|
|
2254
|
+
{
|
|
2255
|
+
id: 'auto_conv_4',
|
|
2256
|
+
title: '🎨 CSS Architecture',
|
|
2257
|
+
messages: [
|
|
2258
|
+
{
|
|
2259
|
+
id: 'auto_msg_9',
|
|
2260
|
+
text: 'How should I organize my CSS in a large project?',
|
|
2261
|
+
sender: 'user' as ChatbotSender,
|
|
2262
|
+
timestamp: new Date(Date.now() - 172800000).toISOString()
|
|
2263
|
+
},
|
|
2264
|
+
{
|
|
2265
|
+
id: 'auto_msg_10',
|
|
2266
|
+
text: 'For large projects, consider these CSS organization strategies:\n\n**1. CSS Modules:**\n- Scoped styles per component\n- Prevents naming conflicts\n\n**2. CSS-in-JS:**\n- Styled Components\n- Emotion\n- Dynamic theming\n\n**3. Utility-First:**\n- Tailwind CSS\n- Rapid development\n\n**4. BEM Methodology:**\n- Block__Element--Modifier\n- Clear naming conventions\n\nChoose based on your team\'s preferences and project requirements!',
|
|
2267
|
+
sender: 'bot' as ChatbotSender,
|
|
2268
|
+
timestamp: new Date(Date.now() - 172790000).toISOString()
|
|
2269
|
+
}
|
|
2270
|
+
],
|
|
2271
|
+
createdAt: new Date(Date.now() - 172800000).toISOString(),
|
|
2272
|
+
updatedAt: new Date(Date.now() - 172790000).toISOString()
|
|
2273
|
+
}
|
|
2274
|
+
];
|
|
2275
|
+
|
|
2276
|
+
// Mock fetch to intercept API calls
|
|
2277
|
+
const mockFetch = async (url: string | URL | Request, options?: RequestInit) => {
|
|
2278
|
+
const urlString = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
2279
|
+
|
|
2280
|
+
// Mock: Load specific conversation
|
|
2281
|
+
if (urlString.match(/\/api\/conversations\/[^/?]+$/) && (!options?.method || options?.method === 'GET')) {
|
|
2282
|
+
const conversationId = urlString.split('/').pop();
|
|
2283
|
+
const conversation = conversationStore.find(c => c.id === conversationId);
|
|
2284
|
+
|
|
2285
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
2286
|
+
|
|
2287
|
+
if (conversation) {
|
|
2288
|
+
return new Response(JSON.stringify(conversation), {
|
|
2289
|
+
status: 200,
|
|
2290
|
+
headers: { 'Content-Type': 'application/json' }
|
|
2291
|
+
});
|
|
2292
|
+
} else {
|
|
2293
|
+
return new Response(JSON.stringify({ error: 'Conversation not found' }), {
|
|
2294
|
+
status: 404,
|
|
2295
|
+
headers: { 'Content-Type': 'application/json' }
|
|
2296
|
+
});
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
// Mock: Load conversations list
|
|
2301
|
+
if (urlString.includes('/api/conversations') && (!options?.method || options?.method === 'GET')) {
|
|
2302
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
2303
|
+
return new Response(JSON.stringify({
|
|
2304
|
+
conversations: conversationStore.map(c => ({
|
|
2305
|
+
id: c.id,
|
|
2306
|
+
title: c.title,
|
|
2307
|
+
messageCount: c.messages.length,
|
|
2308
|
+
createdAt: c.createdAt,
|
|
2309
|
+
updatedAt: c.updatedAt
|
|
2310
|
+
}))
|
|
2311
|
+
}), {
|
|
2312
|
+
status: 200,
|
|
2313
|
+
headers: { 'Content-Type': 'application/json' }
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
// Mock: Create new conversation
|
|
2318
|
+
if (urlString.includes('/api/conversations') && options?.method === 'POST') {
|
|
2319
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
2320
|
+
|
|
2321
|
+
const body = JSON.parse(options?.body as string || '{}');
|
|
2322
|
+
const newConversation = {
|
|
2323
|
+
id: `auto_conv_${Date.now()}`,
|
|
2324
|
+
title: body.title || `New Chat ${conversationStore.length + 1}`,
|
|
2325
|
+
messages: [],
|
|
2326
|
+
createdAt: new Date().toISOString(),
|
|
2327
|
+
updatedAt: new Date().toISOString()
|
|
2328
|
+
};
|
|
2329
|
+
|
|
2330
|
+
conversationStore = [newConversation, ...conversationStore];
|
|
2331
|
+
|
|
2332
|
+
return new Response(JSON.stringify(newConversation), {
|
|
2333
|
+
status: 201,
|
|
2334
|
+
headers: { 'Content-Type': 'application/json' }
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
// Mock: Delete conversation
|
|
2339
|
+
if (urlString.match(/\/api\/conversations\/[^/]+$/) && options?.method === 'DELETE') {
|
|
2340
|
+
const conversationId = urlString.split('/').pop();
|
|
2341
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
2342
|
+
|
|
2343
|
+
conversationStore = conversationStore.filter(c => c.id !== conversationId);
|
|
2344
|
+
|
|
2345
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
2346
|
+
status: 200,
|
|
2347
|
+
headers: { 'Content-Type': 'application/json' }
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
// Mock: Send message (streaming response)
|
|
2352
|
+
if (urlString.includes('/api/chat') && options?.method === 'POST') {
|
|
2353
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
2354
|
+
|
|
2355
|
+
const body = JSON.parse(options?.body as string || '{}');
|
|
2356
|
+
const userMessage = body.userMessage || body.message || '';
|
|
2357
|
+
|
|
2358
|
+
let aiResponse = 'Thanks for your question! ';
|
|
2359
|
+
|
|
2360
|
+
if (userMessage.toLowerCase().includes('hello') || userMessage.toLowerCase().includes('hi')) {
|
|
2361
|
+
aiResponse += 'Hello! How can I help you today with your development questions?';
|
|
2362
|
+
} else if (userMessage.toLowerCase().includes('help')) {
|
|
2363
|
+
aiResponse += 'I can assist you with:\n• Programming concepts\n• Framework recommendations\n• Best practices\n• Code architecture\n\nWhat would you like to know?';
|
|
2364
|
+
} else {
|
|
2365
|
+
aiResponse += 'That\'s an interesting question! Let me help you with that...';
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
const stream = new ReadableStream({
|
|
2369
|
+
async start(controller) {
|
|
2370
|
+
for (let i = 0; i < aiResponse.length; i++) {
|
|
2371
|
+
await new Promise(resolve => setTimeout(resolve, 15));
|
|
2372
|
+
controller.enqueue(new TextEncoder().encode(aiResponse[i]));
|
|
2373
|
+
}
|
|
2374
|
+
controller.close();
|
|
2375
|
+
}
|
|
2376
|
+
});
|
|
2377
|
+
|
|
2378
|
+
return new Response(stream, {
|
|
2379
|
+
status: 200,
|
|
2380
|
+
headers: { 'Content-Type': 'text/plain' }
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
return originalFetch(url, options);
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2387
|
+
setTimeout(async () => {
|
|
2388
|
+
const chatbot = document.querySelector('#auto-loading-chatbot') as any;
|
|
2389
|
+
if (chatbot && !chatbot.controller) {
|
|
2390
|
+
// Override fetch
|
|
2391
|
+
window.fetch = mockFetch as any;
|
|
2392
|
+
|
|
2393
|
+
const { CustomAPIProvider } = await import('./providers/custom-api-provider.js');
|
|
2394
|
+
const { ChatbotCoreController } = await import('./core/chatbot-core.controller.js');
|
|
2395
|
+
const { FlightCardPlugin } = await import('./plugins/flight-card-plugin.js');
|
|
2396
|
+
|
|
2397
|
+
// Extended provider with auto-loading support
|
|
2398
|
+
class AutoLoadingProvider extends CustomAPIProvider {
|
|
2399
|
+
async loadConversations(): Promise<Array<{id: string, title: string, createdAt: string, updatedAt: string}>> {
|
|
2400
|
+
console.log('[AutoLoadingProvider] loadConversations() called automatically!');
|
|
2401
|
+
try {
|
|
2402
|
+
const response = await fetch('/api/conversations', { method: 'GET' });
|
|
2403
|
+
const data = await response.json();
|
|
2404
|
+
console.log('[AutoLoadingProvider] Loaded conversation summaries:', data.conversations);
|
|
2405
|
+
return data.conversations || [];
|
|
2406
|
+
} catch (error) {
|
|
2407
|
+
console.error('[AutoLoadingProvider] Failed to load conversations:', error);
|
|
2408
|
+
return [];
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
async loadConversation(conversationId: string): Promise<any> {
|
|
2413
|
+
console.log(`[AutoLoadingProvider] loadConversation(${conversationId}) called automatically!`);
|
|
2414
|
+
try {
|
|
2415
|
+
const response = await fetch(`/api/conversations/${conversationId}`, { method: 'GET' });
|
|
2416
|
+
const data = await response.json();
|
|
2417
|
+
console.log(`[AutoLoadingProvider] Loaded full conversation ${conversationId}:`, data);
|
|
2418
|
+
return data;
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
console.error(`[AutoLoadingProvider] Failed to load conversation ${conversationId}:`, error);
|
|
2421
|
+
return null;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
buildPayload(text: string, context: any): any {
|
|
2426
|
+
return {
|
|
2427
|
+
userMessage: text,
|
|
2428
|
+
conversationId: context.currentThread?.id,
|
|
2429
|
+
metadata: context.metadata || {}
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
const provider = new AutoLoadingProvider();
|
|
2435
|
+
|
|
2436
|
+
console.log('[Story] Connecting provider...');
|
|
2437
|
+
await provider.connect({
|
|
2438
|
+
apiUrl: '/api/chat',
|
|
2439
|
+
headers: {
|
|
2440
|
+
'accept': 'text/plain',
|
|
2441
|
+
'Content-Type': 'application/json'
|
|
2442
|
+
}
|
|
2443
|
+
});
|
|
2444
|
+
console.log('[Story] Provider connected!');
|
|
2445
|
+
|
|
2446
|
+
// Create controller - conversations will load automatically!
|
|
2447
|
+
console.log('[Story] Creating ChatbotCoreController...');
|
|
2448
|
+
const controller = new ChatbotCoreController({
|
|
2449
|
+
provider,
|
|
2450
|
+
enableThreads: true,
|
|
2451
|
+
debug: true, // Enable debug logging to see auto-load process
|
|
2452
|
+
plugins: [new FlightCardPlugin()], // Add flight card plugin for HTML rendering
|
|
2453
|
+
ui: {
|
|
2454
|
+
onStateChange: (state) => {
|
|
2455
|
+
console.log('[UI] State changed:', {
|
|
2456
|
+
threadsCount: state.threads.length,
|
|
2457
|
+
messagesCount: state.messages.length,
|
|
2458
|
+
currentThreadId: state.currentThreadId
|
|
2459
|
+
});
|
|
2460
|
+
chatbot.messages = state.messages;
|
|
2461
|
+
chatbot.threads = state.threads;
|
|
2462
|
+
chatbot.isBotTyping = state.isTyping;
|
|
2463
|
+
chatbot.chatStarted = state.messages.length > 0;
|
|
2464
|
+
},
|
|
2465
|
+
onTypingStart: () => { chatbot.isBotTyping = true; },
|
|
2466
|
+
onTypingEnd: () => { chatbot.isBotTyping = false; },
|
|
2467
|
+
focusInput: () => { chatbot.focusInput(); }
|
|
2468
|
+
}
|
|
2469
|
+
});
|
|
2470
|
+
|
|
2471
|
+
chatbot.controller = controller;
|
|
2472
|
+
|
|
2473
|
+
// Note: No manual conversation loading code needed!
|
|
2474
|
+
// The controller automatically calls provider.loadConversations() on connect
|
|
2475
|
+
|
|
2476
|
+
chatbot.suggestions = [
|
|
2477
|
+
{ id: 'react', text: '⚛️ React tips', enabled: true },
|
|
2478
|
+
{ id: 'typescript', text: '📘 TypeScript help', enabled: true },
|
|
2479
|
+
{ id: 'css', text: '🎨 CSS advice', enabled: true }
|
|
2480
|
+
];
|
|
2481
|
+
|
|
2482
|
+
// Cleanup
|
|
2483
|
+
(window as any).__storyCleanup = () => {
|
|
2484
|
+
window.fetch = originalFetch;
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
}, 0);
|
|
2488
|
+
|
|
2489
|
+
return html`
|
|
2490
|
+
<div style="display: flex; flex-direction: column; gap: 16px; padding: 20px; max-width: 1200px;">
|
|
2491
|
+
<div style="padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; box-shadow: 0 4px 20px rgba(102,126,234,0.4); color: white;">
|
|
2492
|
+
<h3 style="margin: 0 0 16px 0; font-size: 24px; font-weight: 600;">✨ Auto-Loading Conversations Demo</h3>
|
|
2493
|
+
<p style="margin: 0 0 16px 0; font-size: 15px; line-height: 1.6; opacity: 0.95;">
|
|
2494
|
+
This story demonstrates the <strong>automatic conversation loading</strong> feature.
|
|
2495
|
+
When you extend <code style="background: rgba(255,255,255,0.2); padding: 2px 6px; border-radius: 4px;">CustomAPIProvider</code>
|
|
2496
|
+
and implement <code style="background: rgba(255,255,255,0.2); padding: 2px 6px; border-radius: 4px;">loadConversations()</code>,
|
|
2497
|
+
the controller automatically loads existing conversations when the provider connects!
|
|
2498
|
+
</p>
|
|
2499
|
+
|
|
2500
|
+
<div style="background: rgba(255,255,255,0.15); padding: 16px; border-radius: 8px; margin-bottom: 16px;">
|
|
2501
|
+
<p style="margin: 0 0 12px 0; font-weight: 600; font-size: 15px;">🔄 How it works:</p>
|
|
2502
|
+
<ol style="margin: 0; padding-left: 24px; font-size: 14px; line-height: 1.8; opacity: 0.95;">
|
|
2503
|
+
<li>Provider connects via <code style="background: rgba(255,255,255,0.2); padding: 2px 6px; border-radius: 4px;">provider.connect()</code></li>
|
|
2504
|
+
<li>Controller detects <code style="background: rgba(255,255,255,0.2); padding: 2px 6px; border-radius: 4px;">loadConversations()</code> method</li>
|
|
2505
|
+
<li>Automatically calls it to fetch conversation list</li>
|
|
2506
|
+
<li>Loads full details for each conversation</li>
|
|
2507
|
+
<li><strong>Processes messages through plugins</strong> (e.g., renders flight cards)</li>
|
|
2508
|
+
<li>Updates UI with loaded threads - <strong>no manual code needed!</strong></li>
|
|
2509
|
+
</ol>
|
|
2510
|
+
</div>
|
|
2511
|
+
|
|
2512
|
+
<div style="background: rgba(255,255,255,0.15); padding: 16px; border-radius: 8px;">
|
|
2513
|
+
<p style="margin: 0 0 12px 0; font-weight: 600; font-size: 15px;">📋 Pre-loaded conversations:</p>
|
|
2514
|
+
<ul style="margin: 0; padding-left: 24px; font-size: 14px; line-height: 1.8; opacity: 0.95;">
|
|
2515
|
+
<li>✈️ <strong>Flight Booking</strong> - Demonstrates HTML rendering with flight cards</li>
|
|
2516
|
+
<li>🚀 Project Setup Guide</li>
|
|
2517
|
+
<li>💡 TypeScript Best Practices</li>
|
|
2518
|
+
<li>🎨 CSS Architecture</li>
|
|
2519
|
+
</ul>
|
|
2520
|
+
</div>
|
|
2521
|
+
|
|
2522
|
+
<div style="background: rgba(46,213,115,0.2); padding: 12px; border-radius: 6px; margin-top: 16px; border-left: 4px solid #2ed573;">
|
|
2523
|
+
<p style="margin: 0; font-size: 13px; line-height: 1.6;">
|
|
2524
|
+
<strong>💡 Tip:</strong> Click on the "Flight Booking" conversation to see rich HTML cards automatically rendered from loaded messages!
|
|
2525
|
+
</p>
|
|
2526
|
+
</div>
|
|
2527
|
+
|
|
2528
|
+
<div style="background: rgba(255,193,7,0.2); padding: 12px; border-radius: 6px; margin-top: 12px; border-left: 4px solid #ffc107;">
|
|
2529
|
+
<p style="margin: 0; font-size: 13px; line-height: 1.6;">
|
|
2530
|
+
<strong>🔍 Debug:</strong> Open the browser console to see the auto-loading process and plugin rendering in action!
|
|
2531
|
+
</p>
|
|
2532
|
+
</div>
|
|
2533
|
+
</div>
|
|
2534
|
+
|
|
2535
|
+
<div style="width: 100%; height: 700px; border: 1px solid #dee2e6; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 16px rgba(0,0,0,0.1);">
|
|
2536
|
+
<nr-chatbot
|
|
2537
|
+
id="auto-loading-chatbot"
|
|
2538
|
+
.size=${args.size}
|
|
2539
|
+
.variant=${args.variant}
|
|
2540
|
+
.showSendButton=${true}
|
|
2541
|
+
.autoScroll=${true}
|
|
2542
|
+
.showThreads=${true}
|
|
2543
|
+
.boxed=${true}
|
|
2544
|
+
></nr-chatbot>
|
|
2545
|
+
</div>
|
|
2546
|
+
</div>
|
|
2547
|
+
`;
|
|
2548
|
+
}
|
|
2549
|
+
};
|