├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── build-js.yml │ ├── build-py.yml │ ├── deploy.yml │ ├── publish-npm-package.yml │ └── publish-pypi-package.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── docs ├── .gitignore ├── README.md ├── components │ └── Steps │ │ ├── Steps.module.css │ │ └── Steps.tsx ├── custom │ ├── plugins │ │ └── inject-custom-docs.mjs │ └── reference │ │ └── js │ │ └── react-core │ │ ├── functions │ │ ├── ChatProvider.md │ │ ├── processStreamedMessage.md │ │ └── useThreadManagerSelector.md │ │ ├── interfaces │ │ └── ResponseTemplate.md │ │ └── type-aliases │ │ ├── ThreadListManager.md │ │ └── ThreadManager.md ├── docs │ ├── concepts │ │ ├── 001-core-concepts.md │ │ ├── 002-generative-ui.md │ │ ├── 003-data-format.mdx │ │ └── assets │ │ │ └── visual-guide.png │ ├── examples.mdx │ ├── guides │ │ ├── 001-getting-started.mdx │ │ ├── 002-rendering-markdown.mdx │ │ └── customization │ │ │ ├── 003-connecting-to-backend.mdx │ │ │ ├── 004-customizing-ui.mdx │ │ │ ├── 005-response-templates.mdx │ │ │ ├── advanced-customization │ │ │ ├── 001-integrating-custom-components.md │ │ │ ├── 002-message-context.mdx │ │ │ ├── assets │ │ │ │ └── advanced-ui-customization.png │ │ │ └── index.mdx │ │ │ └── index.mdx │ ├── index.mdx │ ├── quickstart │ │ ├── 001-python-fastapi.mdx │ │ └── 002-nextjs.mdx │ └── reference │ │ └── js │ │ └── react-core │ │ ├── functions │ │ ├── ChatProvider.md │ │ ├── MessageContext.md │ │ ├── MessageProvider.md │ │ ├── processStreamedMessage.md │ │ ├── useMessage.md │ │ ├── useThreadActions.md │ │ ├── useThreadListActions.md │ │ ├── useThreadListManager.md │ │ ├── useThreadListState.md │ │ ├── useThreadManager.md │ │ ├── useThreadManagerSelector.md │ │ └── useThreadState.md │ │ ├── index.md │ │ ├── interfaces │ │ └── ResponseTemplate.md │ │ ├── type-aliases │ │ ├── AssistantMessage.md │ │ ├── ChatManager.md │ │ ├── CreateMessage.md │ │ ├── Message.md │ │ ├── Thread.md │ │ ├── ThreadActions.md │ │ ├── ThreadListActions.md │ │ ├── ThreadListManager.md │ │ ├── ThreadListState.md │ │ ├── ThreadManager.md │ │ ├── ThreadState.md │ │ ├── UseThreadListManagerParams.md │ │ ├── UseThreadManagerParams.md │ │ └── UserMessage.md │ │ └── typedoc-sidebar.cjs ├── docusaurus.config.ts ├── package.json ├── pnpm-lock.yaml ├── sidebars.ts ├── src │ ├── components │ │ ├── HomepageFeatures │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ │ ├── Navbar.js │ │ ├── Navbar.module.css │ │ ├── PrimaryButton.js │ │ ├── PrimaryButton.module.css │ │ ├── SecondaryButton.js │ │ └── SecondaryButton.module.css │ ├── css │ │ └── custom.css │ ├── pages │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── index.module.css │ │ ├── index.tsx │ │ ├── markdown-page.md │ │ └── page.module.css │ └── sections │ │ ├── FAQ.js │ │ ├── FAQ.module.css │ │ ├── FeatureAccordion.js │ │ ├── FeatureAccordion.module.css │ │ ├── Features.js │ │ ├── Features.module.css │ │ ├── Footer.js │ │ ├── Footer.module.css │ │ ├── Hero.js │ │ └── Hero.module.css ├── static │ ├── .nojekyll │ ├── img │ │ ├── batteries.png │ │ ├── components-mobile.png │ │ ├── components.png │ │ ├── crayon-logo.svg │ │ ├── customize.svg │ │ ├── favicon.ico │ │ ├── file.svg │ │ ├── footer-background.png │ │ ├── github-logo.svg │ │ ├── globe.svg │ │ ├── hero-background.png │ │ ├── logo.png │ │ ├── logo.svg │ │ ├── social-card.png │ │ ├── social-icons.png │ │ ├── tablet-smartphone.png │ │ ├── thesys-logo.svg │ │ ├── thesys-t.svg │ │ ├── undraw_docusaurus_mountain.svg │ │ ├── undraw_docusaurus_react.svg │ │ ├── undraw_docusaurus_tree.svg │ │ ├── universal.svg │ │ └── window.svg │ └── robots.txt └── tsconfig.json ├── js ├── .gitignore ├── .prettierrc.json ├── eslint.config.cjs ├── package.json ├── packages │ ├── react-core │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── ChatProvider.tsx │ │ │ ├── hooks │ │ │ │ ├── useMessage.tsx │ │ │ │ ├── useThreadActions.ts │ │ │ │ ├── useThreadListActions.ts │ │ │ │ ├── useThreadListState.ts │ │ │ │ ├── useThreadManagerSelector.ts │ │ │ │ └── useThreadState.ts │ │ │ ├── index.ts │ │ │ ├── internal │ │ │ │ ├── ChatContext.ts │ │ │ │ ├── useThreadListManagerStore.ts │ │ │ │ └── useThreadManagerStore.ts │ │ │ ├── stream │ │ │ │ └── processStreamedMessage.ts │ │ │ ├── types │ │ │ │ ├── chatManager.ts │ │ │ │ ├── index.ts │ │ │ │ ├── message.ts │ │ │ │ └── responseTemplate.ts │ │ │ ├── useThreadListManager.ts │ │ │ └── useThreadManager.ts │ │ └── tsconfig.json │ ├── react-ui │ │ ├── .storybook │ │ │ ├── main.ts │ │ │ ├── manager.css │ │ │ ├── manager.ts │ │ │ ├── preflight.css │ │ │ ├── preview.tsx │ │ │ └── theme.ts │ │ ├── README.md │ │ ├── cp-css.js │ │ ├── package.json │ │ ├── src │ │ │ ├── components │ │ │ │ ├── Accordion │ │ │ │ │ ├── Accordion.tsx │ │ │ │ │ ├── accordion.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── accordion.stories.tsx │ │ │ │ ├── Button │ │ │ │ │ ├── Button.tsx │ │ │ │ │ ├── button.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── Button.stories.tsx │ │ │ │ ├── Buttons │ │ │ │ │ ├── Buttons.tsx │ │ │ │ │ ├── buttons.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── buttons.stories.tsx │ │ │ │ ├── Calendar │ │ │ │ │ ├── Calendar.tsx │ │ │ │ │ ├── calendar.scss │ │ │ │ │ ├── components │ │ │ │ │ │ ├── calendarHelperComponents.scss │ │ │ │ │ │ └── helperComponents.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── Calendar.stories.tsx │ │ │ │ │ └── utils │ │ │ │ │ │ ├── calendarBaseStyle.scss │ │ │ │ │ │ ├── helperFn.tsx │ │ │ │ │ │ └── styles.tsx │ │ │ │ ├── Callout │ │ │ │ │ ├── Callout.tsx │ │ │ │ │ ├── callout.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── callout.stories.tsx │ │ │ │ ├── Card │ │ │ │ │ ├── Card.tsx │ │ │ │ │ ├── card.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── card.stories.tsx │ │ │ │ ├── CardHeader │ │ │ │ │ ├── CardHeader.tsx │ │ │ │ │ ├── cardHeader.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── cardHeader.stories.tsx │ │ │ │ ├── Carousel │ │ │ │ │ ├── Carousel.tsx │ │ │ │ │ ├── carousel.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── carousel.stories.tsx │ │ │ │ ├── Charts │ │ │ │ │ ├── AreaChart │ │ │ │ │ │ ├── AreaChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── areaChart.stories.tsx │ │ │ │ │ ├── BarChart │ │ │ │ │ │ ├── BarChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── barChart.stories.tsx │ │ │ │ │ ├── Charts.tsx │ │ │ │ │ ├── LineChart │ │ │ │ │ │ ├── LineChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── lineChart.stories.tsx │ │ │ │ │ ├── PieChart │ │ │ │ │ │ ├── PieChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── pieChart.stories.tsx │ │ │ │ │ ├── RadarChart │ │ │ │ │ │ ├── RadarChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── raderChart.stories.tsx │ │ │ │ │ ├── RadialChart │ │ │ │ │ │ ├── RadialChart.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── stories │ │ │ │ │ │ │ └── radialChart.stories.tsx │ │ │ │ │ ├── cartesianGrid.tsx │ │ │ │ │ ├── charts.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── utils │ │ │ │ │ │ └── PalletUtils.ts │ │ │ │ ├── CheckBoxGroup │ │ │ │ │ ├── CheckBoxGroup.tsx │ │ │ │ │ ├── checkBoxGroup.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── CheckBoxGroup.stories.tsx │ │ │ │ ├── CheckBoxItem │ │ │ │ │ ├── CheckBoxItem.tsx │ │ │ │ │ ├── checkBoxItem.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── CheckBoxItem.stories.tsx │ │ │ │ ├── CodeBlock │ │ │ │ │ ├── CodeBlock.tsx │ │ │ │ │ ├── codeBlock.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── CodeBlock.stories.tsx │ │ │ │ ├── CopilotShell │ │ │ │ │ ├── Container.tsx │ │ │ │ │ ├── Header.tsx │ │ │ │ │ ├── Thread.tsx │ │ │ │ │ ├── copilotShell.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── header.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ ├── Shell.stories.tsx │ │ │ │ │ │ ├── style.module.scss │ │ │ │ │ │ └── thesysdev_logo.jpeg │ │ │ │ │ └── thread.scss │ │ │ │ ├── CrayonChat │ │ │ │ │ ├── ComposedCopilot.tsx │ │ │ │ │ ├── ComposedStandalone.tsx │ │ │ │ │ ├── CrayonChat.tsx │ │ │ │ │ ├── crayonChat.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── CrayonChat.stories.tsx │ │ │ │ ├── DatePicker │ │ │ │ │ ├── DatePicker.tsx │ │ │ │ │ ├── datePicker.scss │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── helpers │ │ │ │ │ │ ├── components │ │ │ │ │ │ │ ├── DatePickerRenderer.tsx │ │ │ │ │ │ │ ├── FloatingDatePickerRenderer.tsx │ │ │ │ │ │ │ ├── HelperComponents.tsx │ │ │ │ │ │ │ ├── datePickerRenderer.scss │ │ │ │ │ │ │ ├── floatingDatePickerRenderer.scss │ │ │ │ │ │ │ └── helperComponents.scss │ │ │ │ │ │ ├── context │ │ │ │ │ │ │ └── DatePickerContext.tsx │ │ │ │ │ │ └── utils │ │ │ │ │ │ │ ├── datePickerBaseStyle.scss │ │ │ │ │ │ │ ├── helperFn.tsx │ │ │ │ │ │ │ └── styles.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── DatePicker.stories.tsx │ │ │ │ ├── FollowUpBlock │ │ │ │ │ ├── FollowUpBlock.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── followUpBlock.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── FollowUpBlock.stories.tsx │ │ │ │ ├── FollowUpItem │ │ │ │ │ ├── FollowUpItem.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── followUpItem.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── FollowUpItem.stories.tsx │ │ │ │ ├── FormControl │ │ │ │ │ ├── FormControl.tsx │ │ │ │ │ ├── Hint │ │ │ │ │ │ ├── Hint.tsx │ │ │ │ │ │ ├── hint.scss │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── formControl.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── FormControl.stories.tsx │ │ │ │ ├── IconButton │ │ │ │ │ ├── IconButton.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── iconButton.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── iconButton.stories.tsx │ │ │ │ ├── Image │ │ │ │ │ ├── Image.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── image.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── Image.stories.tsx │ │ │ │ ├── ImageGallery │ │ │ │ │ ├── GalleryModal.tsx │ │ │ │ │ ├── ImageGallery.tsx │ │ │ │ │ ├── imageGallery.scss │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stories │ │ │ │ │ │ └── imsgeGallery.stories.tsx │ │ │ │ ├── Input │ │ │ │ │ ├── Input.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── input.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── Input.stories.tsx │ │ │ │ ├── Label │ │ │ │ │ ├── Label.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ └── label.scss │ │ │ │ ├── ListBlock │ │ │ │ │ ├── ListBlock.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── listBlock.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── ListBlock.stories.tsx │ │ │ │ ├── ListItem │ │ │ │ │ ├── ListItem.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── listItem.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── ListItem.stories.tsx │ │ │ │ ├── MarkDownRenderer │ │ │ │ │ ├── MarkDownRenderer.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── markDownRenderer.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── MarkDownRenderer.stories.tsx │ │ │ │ ├── MessageLoading │ │ │ │ │ ├── MessageLoading.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── messageLoading.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── MessageLoading.stories.tsx │ │ │ │ ├── RadioGroup │ │ │ │ │ ├── RadioGroup.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── radioGroup.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── RadioGroup.stories.tsx │ │ │ │ ├── RadioItem │ │ │ │ │ ├── RadioItem.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── radioItem.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── RadioItem.stories.tsx │ │ │ │ ├── Select │ │ │ │ │ ├── Select.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── select.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── select.stories.tsx │ │ │ │ ├── Shell │ │ │ │ │ ├── Container.tsx │ │ │ │ │ ├── MobileHeader.tsx │ │ │ │ │ ├── NewChatButton.tsx │ │ │ │ │ ├── Sidebar.tsx │ │ │ │ │ ├── Thread.tsx │ │ │ │ │ ├── ThreadList.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── mobileHeader.scss │ │ │ │ │ ├── shell.scss │ │ │ │ │ ├── sidebar.scss │ │ │ │ │ ├── store.tsx │ │ │ │ │ ├── stories │ │ │ │ │ │ ├── Shell.stories.tsx │ │ │ │ │ │ └── thesysdev_logo.jpeg │ │ │ │ │ ├── thread.scss │ │ │ │ │ └── threadlist.scss │ │ │ │ ├── Slider │ │ │ │ │ ├── Slider.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── slider.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── slider.stories.tsx │ │ │ │ ├── Steps │ │ │ │ │ ├── Steps.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── steps.scss │ │ │ │ │ └── stories │ │ │ │ │ │ └── steps.stories.tsx │ │ │ │ ├── SwitchGroup │ │ │ │ │ ├── SwitchGroup.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── SwitchGroup.stories.tsx │ │ │ │ │ └── switchGroup.scss │ │ │ │ ├── SwitchItem │ │ │ │ │ ├── SwitchItem.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── SwitchItem.stories.tsx │ │ │ │ │ └── switchItem.scss │ │ │ │ ├── Table │ │ │ │ │ ├── Table.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── Table.stories.tsx │ │ │ │ │ └── table.scss │ │ │ │ ├── Tabs │ │ │ │ │ ├── Tabs.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── tabs.stories.tsx │ │ │ │ │ └── tabs.scss │ │ │ │ ├── Tag │ │ │ │ │ ├── Tag.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── Tag.stories.tsx │ │ │ │ │ └── tag.scss │ │ │ │ ├── TagBlock │ │ │ │ │ ├── TagBlock.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── TagBlock.stories.tsx │ │ │ │ │ └── tagBlock.scss │ │ │ │ ├── TextArea │ │ │ │ │ ├── TextArea.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── TextArea.stories.tsx │ │ │ │ │ └── textArea.scss │ │ │ │ ├── TextContent │ │ │ │ │ ├── TextContent.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── TextContent.stories.tsx │ │ │ │ │ └── textContent.scss │ │ │ │ ├── ThemeProvider │ │ │ │ │ ├── ThemeProvider.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── themePresets.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── ToggleGroup │ │ │ │ │ ├── ToggleGroup.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── stories │ │ │ │ │ │ └── ToggleGroup.stories.tsx │ │ │ │ │ └── toggleGroup.scss │ │ │ │ ├── ToggleItem │ │ │ │ │ ├── ToggleItem.tsx │ │ │ │ │ ├── dependencies.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── toggleItem.scss │ │ │ │ └── index.scss │ │ │ ├── context │ │ │ │ └── LayoutContext.tsx │ │ │ ├── cssUtils.scss │ │ │ ├── hooks │ │ │ │ ├── useComposerState.ts │ │ │ │ ├── useElementSize.ts │ │ │ │ ├── useMultipleRefs.ts │ │ │ │ └── useScrollToBottom.ts │ │ │ ├── index.ts │ │ │ ├── internalUtils │ │ │ │ └── ref.ts │ │ │ ├── lib │ │ │ │ └── tailwind │ │ │ │ │ ├── generateTailwindPlugin.ts │ │ │ │ │ ├── pluginTemplate.txt │ │ │ │ │ └── utils.ts │ │ │ ├── scripts │ │ │ │ └── scss-import.js │ │ │ ├── types.d.ts │ │ │ ├── types │ │ │ │ └── postcss-js.d.ts │ │ │ └── utils │ │ │ │ ├── DatePickerUtils.ts │ │ │ │ └── index.ts │ │ └── tsconfig.json │ └── stream │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ ├── anthropic.ts │ │ ├── crayonStream.ts │ │ ├── index.ts │ │ ├── jsonSchemaHelpers.ts │ │ ├── openai.ts │ │ ├── textSchema.ts │ │ ├── transformer.ts │ │ ├── types.ts │ │ └── utils.ts │ │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── tsconfig.json └── py ├── .gitignore ├── Makefile ├── poetry.lock ├── pyproject.toml └── stream ├── README.md ├── poetry.lock ├── pyproject.toml ├── setup.py ├── src └── crayonai_stream │ ├── __init__.py │ ├── best_effort_json_parser.py │ ├── crayon_message.py │ ├── integrations │ ├── __init__.py │ └── openai │ │ ├── __init__.py │ │ ├── helper.py │ │ └── stream.py │ ├── js_schema_helpers.py │ ├── logger.py │ ├── protocol.py │ ├── py.typed │ ├── sse.py │ └── stream.py └── tests └── test_best_effort_json_parser.py /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/build-js.yml: -------------------------------------------------------------------------------- 1 | name: Build JS 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - js/** 8 | pull_request: 9 | branches: [ main ] 10 | paths: 11 | - js/** 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | defaults: 17 | run: 18 | working-directory: js 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - uses: pnpm/action-setup@v2 24 | with: 25 | version: 9.0.6 26 | - uses: actions/setup-node@v4 27 | with: 28 | node-version: 18 29 | cache: pnpm 30 | cache-dependency-path: '**/pnpm-lock.yaml' 31 | 32 | - name: Install dependencies 33 | run: pnpm install --frozen-lockfile 34 | 35 | - name: Build affected projects 36 | run: pnpm -r build 37 | 38 | - name: Check affected projects 39 | run: pnpm -r run ci 40 | -------------------------------------------------------------------------------- /.github/workflows/build-py.yml: -------------------------------------------------------------------------------- 1 | name: Build Python 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - py/** 8 | pull_request: 9 | branches: [ main ] 10 | paths: 11 | - py/** 12 | 13 | defaults: 14 | run: 15 | working-directory: py 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | with: 23 | fetch-depth: 0 24 | 25 | - name: Set up Python 26 | uses: actions/setup-python@v5 27 | with: 28 | python-version: '3.11' 29 | 30 | - name: Install Poetry 31 | uses: snok/install-poetry@v1 32 | with: 33 | version: 1.7.1 34 | virtualenvs-create: true 35 | virtualenvs-in-project: true 36 | 37 | - name: Load cached Poetry dependencies 38 | uses: actions/cache@v3 39 | with: 40 | path: | 41 | py/.venv 42 | py/stream/.venv 43 | key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} 44 | 45 | - name: Install dependencies 46 | run: make install 47 | 48 | - name: Run checks 49 | run: make ci 50 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Build and deploy docs 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | defaults: 10 | run: 11 | working-directory: docs 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - uses: pnpm/action-setup@v2 21 | with: 22 | version: 9.0.6 23 | - uses: actions/setup-node@v4 24 | with: 25 | node-version: 18 26 | cache: pnpm 27 | cache-dependency-path: '**/pnpm-lock.yaml' 28 | 29 | - name: Install dependencies of sdk 30 | run: pnpm install --frozen-lockfile 31 | working-directory: js 32 | - name: Install dependencies 33 | run: pnpm install --frozen-lockfile 34 | - name: Build website 35 | run: pnpm build 36 | 37 | - name: Upload Build Artifact 38 | if: github.ref == 'refs/heads/main' 39 | uses: actions/upload-pages-artifact@v3 40 | with: 41 | path: docs/build 42 | 43 | deploy: 44 | name: Deploy to GitHub Pages 45 | if: github.ref == 'refs/heads/main' 46 | needs: build 47 | 48 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 49 | permissions: 50 | pages: write # to deploy to Pages 51 | id-token: write # to verify the deployment originates from an appropriate source 52 | 53 | # Deploy to the github-pages environment 54 | environment: 55 | name: github-pages 56 | url: ${{ steps.deployment.outputs.page_url }} 57 | 58 | runs-on: ubuntu-latest 59 | steps: 60 | - name: Deploy to GitHub Pages 61 | id: deployment 62 | uses: actions/deploy-pages@v4 63 | -------------------------------------------------------------------------------- /.github/workflows/publish-npm-package.yml: -------------------------------------------------------------------------------- 1 | name: Publish NPM packages 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | package: 7 | description: 'Package to publish (react-ui, react-core, or stream)' 8 | required: true 9 | type: choice 10 | options: 11 | - react-ui 12 | - react-core 13 | - stream 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | defaults: 19 | run: 20 | working-directory: js 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | - uses: pnpm/action-setup@v2 26 | with: 27 | version: 9.15.4 28 | - uses: actions/setup-node@v4 29 | with: 30 | node-version: 18 31 | registry-url: 'https://registry.npmjs.org' 32 | cache: pnpm 33 | cache-dependency-path: '**/pnpm-lock.yaml' 34 | 35 | - name: Install dependencies 36 | run: pnpm install --frozen-lockfile 37 | 38 | - name: Build projects 39 | run: pnpm -r run ci 40 | 41 | - name: Publish package 42 | working-directory: ./js/packages/${{ inputs.package }} 43 | run: pnpm publish --access public 44 | env: 45 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 46 | -------------------------------------------------------------------------------- /.github/workflows/publish-pypi-package.yml: -------------------------------------------------------------------------------- 1 | name: Publish PyPI package 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | package: 7 | description: 'Package to publish' 8 | required: true 9 | type: choice 10 | options: 11 | - stream 12 | 13 | defaults: 14 | run: 15 | working-directory: py 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | # Required for OIDC token 21 | permissions: 22 | id-token: write 23 | contents: read 24 | 25 | steps: 26 | - uses: actions/checkout@v4 27 | with: 28 | fetch-depth: 0 29 | 30 | - name: Set up Python 31 | uses: actions/setup-python@v5 32 | with: 33 | python-version: '3.11' 34 | 35 | - name: Install Poetry 36 | uses: snok/install-poetry@v1 37 | with: 38 | version: 1.7.1 39 | virtualenvs-create: true 40 | virtualenvs-in-project: true 41 | 42 | - name: Load cached Poetry dependencies 43 | uses: actions/cache@v3 44 | with: 45 | path: py/${{ inputs.package }}/.venv 46 | key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} 47 | 48 | - name: Install dependencies 49 | working-directory: py/${{ inputs.package }} 50 | run: poetry install 51 | 52 | - name: Build package 53 | working-directory: py/${{ inputs.package }} 54 | run: poetry build 55 | 56 | - name: Publish package distributions to PyPI 57 | uses: pypa/gh-action-pypi-publish@release/v1 58 | with: 59 | packages-dir: py/${{ inputs.package }}/dist/ 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | .DS_Store 3 | 4 | 5 | # IDEs and editors 6 | /.idea 7 | .project 8 | .classpath 9 | .c9/ 10 | *.launch 11 | .settings/ 12 | *.sublime-workspace 13 | 14 | # IDE - VSCode 15 | .vscode/* 16 | !.vscode/settings.json 17 | !.vscode/tasks.json 18 | !.vscode/launch.json 19 | !.vscode/extensions.json 20 | *.tsbuildinfo 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for considering contributing to *crayon*! This document provides guidelines for contributing. 4 | 5 | ## How to Contribute 6 | 7 | 1. Fork the repository. 8 | 2. Create a new branch (`git checkout -b feature/amazing-feature`) & make your changes. 9 | 3. Ensure your code follows our style guidelines. 10 | 4. Update the README.md & autogenerate docs if needed. 11 | 5. Open a Pull Request 12 | 13 | ## Bug Reports 14 | 15 | Use Github Issues to report bugs. When reporting bugs, please include: 16 | - A clear description of the issue 17 | - Steps to reproduce 18 | - Expected vs actual behavior 19 | - Your environment details 20 | 21 | ## Questions? 22 | 23 | We're happy to help! Feel free to open an issue for any questions or concerns. 24 | You can also join our [Discord](https://discord.gg/Pbv5PsqUSv) to chat with the team 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2024 Thesys Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | We take the security of Crayon seriously. If you believe you have found a security vulnerability, please report it to us through GitHub's Security Advisory "Report a Vulnerability" tab. 6 | 7 | **Please do not report security vulnerabilities through public GitHub issues.** 8 | 9 | Instead: 10 | 1. Go to the "Security" tab of this repository 11 | 2. Click "Report a vulnerability" 12 | 3. Fill out the form with a description of the vulnerability 13 | 14 | We will respond as quickly as possible to your report and work with you to verify and address the issue. 15 | 16 | Thank you for helping keep Crayon and its users safe! 17 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | static/ui/ 23 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /docs/components/Steps/Steps.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./Steps.module.css"; // Using CSS Modules for styling 3 | 4 | interface StepsProps { 5 | children: React.ReactNode; 6 | } 7 | 8 | /** 9 | * Renders a container for Step components, automatically numbering them. 10 | */ 11 | export const Steps: React.FC = ({ children }) => { 12 | let stepNumber = 0; 13 | 14 | return ( 15 |
16 | {React.Children.map(children, (child) => { 17 | if (React.isValidElement(child)) { 18 | stepNumber++; 19 | return React.cloneElement(child as React.ReactElement, { 20 | stepNumber: stepNumber, 21 | }); 22 | } 23 | return child; 24 | })} 25 |
26 | ); 27 | }; 28 | 29 | interface StepProps { 30 | /** The title to display for this step */ 31 | title: string | React.ReactNode; 32 | /** The content of the step */ 33 | children: React.ReactNode; 34 | /** The step number, automatically injected by the parent Steps component */ 35 | stepNumber?: number; 36 | } 37 | 38 | /** 39 | * Renders a single numbered step with a title and content. 40 | * Should be used as a child of the Steps component. 41 | */ 42 | export const Step: React.FC = ({ title, children, stepNumber }) => { 43 | return ( 44 |
45 |
46 |
{stepNumber}
47 |
48 |
49 |
50 |

{title}

51 | {children} 52 |
53 |
54 | ); 55 | }; 56 | -------------------------------------------------------------------------------- /docs/custom/plugins/inject-custom-docs.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import path from "path"; 3 | import fs from "fs"; 4 | 5 | /** 6 | * @param app {import('typedoc-plugin-markdown').MarkdownApplication} app 7 | */ 8 | export function load(app) { 9 | app.renderer.markdownHooks.on("page.begin", (page) => { 10 | const dirname = path.dirname(new URL(import.meta.url).pathname); 11 | const customFilePath = page.page.filename.split("/").slice(-5).join("/"); // -5 because we want the path starting from the reference directory 12 | const filePath = path.resolve(dirname, "..", customFilePath); 13 | if (fs.existsSync(filePath)) { 14 | const fileContent = fs.readFileSync(filePath, "utf-8"); 15 | const separatedFileContent = fileContent.concat("\n---\n"); 16 | return separatedFileContent; 17 | } 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/functions/ChatProvider.md: -------------------------------------------------------------------------------- 1 | ChatProvider is a top-level React context provider component that makes it possible for hooks like the [`useThreadListManager`](../functions/useThreadListManager.md) and 2 | [`useThreadManager`](../functions/useThreadManager) to work. It contains the entire application context, including the [`ThreadManager`](../type-aliases/ThreadManager.md) 3 | and [`ThreadListManager`](../type-aliases/ThreadListManager.md). 4 | 5 | ## Props 6 | 7 | | Prop | Description | 8 | | ------------------- | ------------------------------------------------------------------------------------------------------------ | 9 | | `threadManager` | The [ThreadManager](../type-aliases/ThreadManager.md) instance for handling individual chat threads | 10 | | `threadListManager` | The [ThreadListManager](../type-aliases/ThreadListManager.md) instance for handling the list of chat threads | 11 | | `children` | The child components that will be provided and will have access to this chat context | 12 | 13 | ## Example 14 | 15 | ```tsx 16 | 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/functions/processStreamedMessage.md: -------------------------------------------------------------------------------- 1 | A utility function that helps process a streamed assistant message from the server. It takes functions to create, update and delete messages, 2 | and calls them as necessary on the required message when a streamed response is received. Generally helpful when defining the `processMessage` 3 | function in [`ThreadManager`](../type-aliases/ThreadManager.md) using [`useThreadManager`](../functions/useThreadManager.md). 4 | 5 | ## Example 6 | 7 | ```ts 8 | await processStreamedMessage({ 9 | response, 10 | createMessage: threadManager.appendMessages, 11 | updateMessage: threadManager.updateMessage, 12 | deleteMessage: threadManager.deleteMessage, 13 | }); 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/functions/useThreadManagerSelector.md: -------------------------------------------------------------------------------- 1 | `useThreadManagerSelector` allows you to efficiently extract one or more values from the [`ThreadManager`](../type-aliases/ThreadManager.md) instance 2 | without having to access the entire [`ThreadManager`](../type-aliases/ThreadManager.md). 3 | 4 | ## Example: 5 | 6 | ```ts 7 | interface MessagesAndTemplates { 8 | messages: Message[]; 9 | templates: ResponseTemplate[]; 10 | } 11 | 12 | const { messages, templates } = useThreadManagerSelector( 13 | (threadManager) => ({ 14 | messages: threadManager.messages, 15 | templates: Object.values(threadManager.responseTemplates), 16 | }) 17 | ); 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/interfaces/ResponseTemplate.md: -------------------------------------------------------------------------------- 1 | A type that contains information about the name of the response template and the React component required to render the response template with that name. 2 | For detailed information on response templates, see [Core Concepts](../../../../concepts/001-core-concepts.md#response-templates), and for a guide on how to implement and use response templates, 3 | see [Creating Response Templates](../../../../guides/customization/005-response-templates.mdx). 4 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/type-aliases/ThreadListManager.md: -------------------------------------------------------------------------------- 1 | The Thread List Manager is an entity that encapsulates the [`ThreadListState`](./ThreadListState.md) and actions ([`ThreadListActions`](./ThreadListActions.md)) that help modify the state. 2 | It can be passed to the `ChatProvider` or the `CrayonChat` component to dictate how a thread list should be managed, and what APIs should be called on each event. 3 | -------------------------------------------------------------------------------- /docs/custom/reference/js/react-core/type-aliases/ThreadManager.md: -------------------------------------------------------------------------------- 1 | The Thread Manager is an entity that encapsulates the [`ThreadState`](./ThreadState.md) and actions ([`ThreadActions`](./ThreadActions.md)) that help modify the state. 2 | It can be passed to the `ChatProvider` or the `CrayonChat` component to dictate how a thread should be managed, and what APIs should be called on each event. 3 | -------------------------------------------------------------------------------- /docs/docs/concepts/assets/visual-guide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/docs/concepts/assets/visual-guide.png -------------------------------------------------------------------------------- /docs/docs/examples.mdx: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | :::info 4 | You can find example projects demonstrating Crayon's capabilities in real-world applications. 5 | 6 | These examples provide practical implementations that can help you understand how to integrate Crayon into your own projects. 7 | ::: 8 | 9 | ## Simple Cookbook 10 | 11 | A TypeScript-based cookbook application that showcases how to integrate Crayon with Next.js. This example demonstrates: 12 | 13 | - Recipe generation using AI 14 | - Structured output handling for ingredients and instructions 15 | - Real-time recipe generation 16 | - Integration with OpenAI's API 17 | 18 | 34 | 35 | 40 | 50 | 51 |
52 | 53 | 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /docs/src/components/PrimaryButton.js: -------------------------------------------------------------------------------- 1 | import styles from "./PrimaryButton.module.css"; 2 | 3 | export default function PrimaryButton({ children, onClick }) { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /docs/src/components/PrimaryButton.module.css: -------------------------------------------------------------------------------- 1 | .primaryButton { 2 | padding: 12px 16px; 3 | background-color: white; 4 | color: black; 5 | border: none; 6 | border-radius: 9999px; 7 | font-size: 1.125rem; 8 | cursor: pointer; 9 | transition: all 0.2s ease; 10 | } 11 | 12 | .primaryButton:hover { 13 | background-color: rgba(255, 255, 255, 0.9); 14 | } 15 | 16 | @media screen and (max-width: 720px) { 17 | .primaryButton { 18 | padding: 10px 16px; 19 | font-size: 1rem; 20 | } 21 | 22 | } 23 | 24 | @media screen and (max-width: 372px) { 25 | .primaryButton { 26 | padding: 8px 14px; 27 | font-size: 0.9rem; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /docs/src/components/SecondaryButton.js: -------------------------------------------------------------------------------- 1 | import styles from "./SecondaryButton.module.css"; 2 | 3 | export default function SecondaryButton({ children, onClick }) { 4 | return ( 5 | 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /docs/src/components/SecondaryButton.module.css: -------------------------------------------------------------------------------- 1 | .secondaryButton { 2 | padding: 12px 16px; 3 | background-color: transparent; 4 | color: var(--primary-text); 5 | border: 1px solid var(--border-primary); 6 | border-radius: 9999px; 7 | font-family: 'Inter', sans-serif; 8 | font-size: 1.125rem; 9 | cursor: pointer; 10 | transition: all 0.2s ease; 11 | } 12 | 13 | .secondaryButton:hover { 14 | background-color: rgba(255, 255, 255, 0.1); 15 | } 16 | 17 | @media screen and (max-width: 720px) { 18 | .secondaryButton { 19 | padding: 10px 16px; 20 | font-size: 1rem; 21 | } 22 | 23 | } 24 | 25 | @media screen and (max-width: 372px) { 26 | .secondaryButton { 27 | padding: 8px 14px; 28 | font-size: 0.9rem; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /docs/src/pages/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/src/pages/favicon.ico -------------------------------------------------------------------------------- /docs/src/pages/globals.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --background-website: #0F0F0F; 3 | --borders: rgba(255,255,255,0.08); 4 | --border-primary: rgba(255,255,255,0.32); 5 | --primary-text: #FFFFFF; 6 | --secondary-text: rgba(255,255,255,0.4); 7 | --elevated-container:rgba(0,0,0,0.24); 8 | } 9 | 10 | html, 11 | body { 12 | max-width: 100vw; 13 | overflow-x: hidden; 14 | } 15 | 16 | body { 17 | font-family: var(--font-inter) , Helvetica, sans-serif; 18 | -webkit-font-smoothing: antialiased; 19 | -moz-osx-font-smoothing: grayscale; 20 | } 21 | 22 | * { 23 | box-sizing: border-box; 24 | padding: 0; 25 | margin: 0; 26 | } 27 | 28 | a { 29 | color: inherit; 30 | text-decoration: none; 31 | } 32 | -------------------------------------------------------------------------------- /docs/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | 7 | .heroBanner { 8 | padding: 4rem 0; 9 | text-align: center; 10 | position: relative; 11 | overflow: hidden; 12 | } 13 | 14 | @media screen and (max-width: 996px) { 15 | .heroBanner { 16 | padding: 2rem; 17 | } 18 | } 19 | 20 | .buttons { 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | } 25 | 26 | .bodyWrapper{ 27 | width: 100%; 28 | height:100%; 29 | background-color: var(--background-website); 30 | } 31 | 32 | .bodyWrapper a:hover{ 33 | text-decoration: none; 34 | color: #61CEDA; 35 | } 36 | -------------------------------------------------------------------------------- /docs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | 3 | import FAQ from "@site/src/sections/FAQ"; 4 | import Features from "../sections/Features"; 5 | import Footer from "@site/src/sections/Footer"; 6 | import Hero from "../sections/Hero"; 7 | 8 | import styles from "./index.module.css"; 9 | import Navbar from "../components/Navbar"; 10 | 11 | export default function Home() { 12 | return ( 13 |
14 | 15 |
16 | 17 | 18 | 19 |
20 | 21 | {/* 22 | */} 23 |
24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /docs/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /docs/src/pages/page.module.css: -------------------------------------------------------------------------------- 1 | .page { 2 | font-family: var(--font-inter); 3 | background-color: var(--background-website); 4 | } 5 | 6 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/img/batteries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/batteries.png -------------------------------------------------------------------------------- /docs/static/img/components-mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/components-mobile.png -------------------------------------------------------------------------------- /docs/static/img/components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/components.png -------------------------------------------------------------------------------- /docs/static/img/customize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/img/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/static/img/footer-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/footer-background.png -------------------------------------------------------------------------------- /docs/static/img/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/static/img/hero-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/hero-background.png -------------------------------------------------------------------------------- /docs/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/logo.png -------------------------------------------------------------------------------- /docs/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/static/img/social-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/social-card.png -------------------------------------------------------------------------------- /docs/static/img/social-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/social-icons.png -------------------------------------------------------------------------------- /docs/static/img/tablet-smartphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/docs/static/img/tablet-smartphone.png -------------------------------------------------------------------------------- /docs/static/img/thesys-t.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/static/img/universal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/static/img/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | }, 7 | "exclude": [".docusaurus", "build"] 8 | } 9 | -------------------------------------------------------------------------------- /js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | typings 3 | dist 4 | .DS_Store 5 | *storybook.log 6 | 7 | # Generated tailwind plugin TS file 8 | packages/react-ui/src/lib/tailwind/tailwind.ts 9 | -------------------------------------------------------------------------------- /js/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "trailingComma": "all", 4 | "singleQuote": false, 5 | "printWidth": 100, 6 | "tabWidth": 2, 7 | "plugins": ["prettier-plugin-organize-imports"] 8 | } -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js", 3 | "version": "1.0.0", 4 | "description": "Monorepo for Crayon's JavaScript packages. See https://crayonai.org for more information.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "devDependencies": { 10 | "typescript": "^5.5.4", 11 | "@typescript-eslint/eslint-plugin": "^8.21.0", 12 | "eslint": "^9.19.0", 13 | "eslint-config-prettier": "^9.1.0", 14 | "eslint-plugin-prettier": "^5.1.3", 15 | "eslint-plugin-react-hooks": "^5.1.0", 16 | "eslint-plugin-react-refresh": "^0.4.18", 17 | "eslint-plugin-storybook": "^0.11.2", 18 | "eslint-plugin-unused-imports": "^3.2.0", 19 | "prettier": "^3.2.5", 20 | "prettier-plugin-organize-imports": "^3.2.4" 21 | }, 22 | "keywords": [], 23 | "author": "engineering@crayon.ai", 24 | "license": "MIT" 25 | } 26 | -------------------------------------------------------------------------------- /js/packages/react-core/README.md: -------------------------------------------------------------------------------- 1 | # Core Framework (`react-core`) 2 | 3 | This package provides the core framework and hooks for managing state and agents. 4 | -------------------------------------------------------------------------------- /js/packages/react-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@crayonai/react-core", 3 | "version": "0.7.5", 4 | "description": "Generative UI SDK", 5 | "license": "MIT", 6 | "main": "dist/index.js", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1", 13 | "build": "tsc -p .", 14 | "lint:check": "eslint ./src", 15 | "lint:fix": "eslint ./src --fix", 16 | "format:fix": "prettier --write ./src", 17 | "format:check": "prettier --check ./src", 18 | "prepare": "pnpm run build", 19 | "ci": "pnpm run lint:check && pnpm run format:check" 20 | }, 21 | "peerDependencies": { 22 | "react": ">=18.0.0", 23 | "react-dom": ">=18.0.0", 24 | "tiny-invariant": "^1.3.3", 25 | "zustand": "^5.0.2", 26 | "eventsource-parser": "^3.0.0", 27 | "@crayonai/stream": "workspace:^" 28 | }, 29 | "devDependencies": { 30 | "@types/react": ">=18.0.0", 31 | "@typescript-eslint/eslint-plugin": "^8.18.0", 32 | "eslint": "^9.17.0", 33 | "eslint-config-prettier": "^9.1.0", 34 | "eslint-plugin-prettier": "^5.2.1", 35 | "eslint-plugin-react-hooks": "^5.1.0", 36 | "eslint-plugin-react-refresh": "^0.4.16", 37 | "eslint-plugin-unused-imports": "^3.1.0", 38 | "prettier-plugin-organize-imports": "^3.2.4" 39 | }, 40 | "keywords": [], 41 | "author": "engineering@thesys.dev", 42 | "dependencies": { 43 | "zod": "^3.24.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /js/packages/react-core/src/ChatProvider.tsx: -------------------------------------------------------------------------------- 1 | import { FC, useMemo } from "react"; 2 | import { ChatContext } from "./internal/ChatContext"; 3 | import { useThreadListManagerStore } from "./internal/useThreadListManagerStore"; 4 | import { useThreadManagerStore } from "./internal/useThreadManagerStore"; 5 | import { ChatManager } from "./types"; 6 | 7 | /** 8 | * @category Components 9 | */ 10 | export const ChatProvider: FC> = ({ 11 | threadManager: inputThreadManager, 12 | threadListManager: inputThreadListManager, 13 | children, 14 | }: React.PropsWithChildren) => { 15 | const threadManagerStore = useThreadManagerStore(inputThreadManager); 16 | const threadListManagerStore = useThreadListManagerStore(inputThreadListManager); 17 | 18 | const ctxValue = useMemo( 19 | () => ({ 20 | threadListManager: threadListManagerStore, 21 | threadManager: threadManagerStore, 22 | }), 23 | [threadListManagerStore, threadManagerStore], 24 | ); 25 | 26 | return {children}; 27 | }; 28 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useMessage.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | import { useShallow } from "zustand/shallow"; 3 | import { Message } from "../types"; 4 | 5 | /** 6 | * @category Contexts 7 | */ 8 | export const MessageContext = createContext<{ message: Message } | null>(null); 9 | 10 | /** 11 | * @category Hooks 12 | * @returns The current message. See {@link Message} for more information. 13 | */ 14 | export const useMessage = () => { 15 | const context = useContext(MessageContext); 16 | if (!context) { 17 | throw new Error("useMessage must be used within a MessageProvider"); 18 | } 19 | return context; 20 | }; 21 | 22 | /** 23 | * @category Components 24 | */ 25 | export const MessageProvider = ({ 26 | message, 27 | children, 28 | }: { 29 | message: Message; 30 | children: React.ReactNode; 31 | }) => { 32 | const ctxValue = useShallow((_s: void) => ({ message }))(); 33 | 34 | return {children}; 35 | }; 36 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useThreadActions.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "zustand"; 2 | import { useChatContext } from "../internal/ChatContext"; 3 | import { ThreadActions } from "../types"; 4 | 5 | /** 6 | * `useThreadActions` allows you to modify the {@link ThreadState} by providing access to {@link ThreadActions} which contains methods to modify the state. 7 | * 8 | * @category Hooks 9 | */ 10 | export const useThreadActions = (): ThreadActions => { 11 | const { threadManager } = useChatContext(); 12 | 13 | return { 14 | processMessage: useStore(threadManager, (store) => store.processMessage), 15 | appendMessages: useStore(threadManager, (store) => store.appendMessages), 16 | updateMessage: useStore(threadManager, (store) => store.updateMessage), 17 | setMessages: useStore(threadManager, (store) => store.setMessages), 18 | onCancel: useStore(threadManager, (store) => store.onCancel), 19 | deleteMessage: useStore(threadManager, (store) => store.deleteMessage), 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useThreadListActions.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "zustand"; 2 | import { useChatContext } from "../internal/ChatContext"; 3 | import { ThreadListActions } from "../types"; 4 | 5 | /** 6 | * `useThreadListActions` allows you to modify the {@link ThreadListState} by providing access to {@link ThreadListActions} which contains methods to modify the state. 7 | * 8 | * @category Hooks 9 | */ 10 | export const useThreadListActions = (): ThreadListActions => { 11 | const { threadListManager } = useChatContext(); 12 | 13 | return { 14 | load: useStore(threadListManager, (store) => store.load), 15 | switchToNewThread: useStore(threadListManager, (store) => store.switchToNewThread), 16 | selectThread: useStore(threadListManager, (store) => store.selectThread), 17 | createThread: useStore(threadListManager, (store) => store.createThread), 18 | deleteThread: useStore(threadListManager, (store) => store.deleteThread), 19 | updateThread: useStore(threadListManager, (store) => store.updateThread), 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useThreadListState.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "zustand"; 2 | import { useChatContext } from "../internal/ChatContext"; 3 | import { ThreadListState } from "../types"; 4 | 5 | /** 6 | * `useThreadListState` allows you to access the {@link ThreadListState}. This is helpful for multiple reasons, including but not limited to: 7 | * 8 | * - You can use the state to render the thread list UI 9 | * - You can use the state to trigger actions on the thread list 10 | * 11 | * @category Hooks 12 | */ 13 | export const useThreadListState = (): ThreadListState => { 14 | const { threadListManager } = useChatContext(); 15 | return { 16 | isLoading: useStore(threadListManager, (store) => store.isLoading), 17 | threads: useStore(threadListManager, (store) => store.threads), 18 | error: useStore(threadListManager, (store) => store.error), 19 | selectedThreadId: useStore(threadListManager, (store) => store.selectedThreadId), 20 | shouldResetThreadState: useStore(threadListManager, (store) => store.shouldResetThreadState), 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useThreadManagerSelector.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "zustand"; 2 | import { useShallow } from "zustand/shallow"; 3 | import { useChatContext } from "../internal/ChatContext"; 4 | import { ThreadManager } from "../types"; 5 | 6 | type AtomicAccessor = (store: ThreadManager) => T; 7 | /** 8 | * @typeParam R - The type of the value to be extracted from the {@link ThreadManager} instance. For example, `boolean | undefined`: 9 | * ```ts 10 | * const isRunning = useThreadManagerSelector((threadManager) => threadManager.isRunning); // returning any other type throws an error 11 | * ``` 12 | * If no type is passed, one is inferred from the accessor function. 13 | * 14 | * @param accessor - A function that is passed the {@link ThreadManager} instance as an argument and returns the value to be extracted. 15 | * @returns The value returned by the accessor function. 16 | * @category Hooks 17 | */ 18 | export const useThreadManagerSelector = (accessor: AtomicAccessor): R => { 19 | const { threadManager } = useChatContext(); 20 | return useStore(threadManager, useShallow(accessor)); 21 | }; 22 | -------------------------------------------------------------------------------- /js/packages/react-core/src/hooks/useThreadState.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "zustand"; 2 | import { useChatContext } from "../internal/ChatContext"; 3 | import { ThreadState } from "../types"; 4 | 5 | /** 6 | * `useThreadState` allows you to access the {@link ThreadState}. This is helpful for multiple reasons, including but not limited to: 7 | * 8 | * - You can use the state to render the thread UI 9 | * - You can use the state to trigger actions on the thread 10 | * 11 | * @category Hooks 12 | */ 13 | export const useThreadState = (): ThreadState => { 14 | const { threadManager } = useChatContext(); 15 | 16 | return { 17 | isLoadingMessages: useStore(threadManager, (store) => store.isLoadingMessages), 18 | isRunning: useStore(threadManager, (store) => store.isRunning), 19 | messages: useStore(threadManager, (store) => store.messages), 20 | error: useStore(threadManager, (store) => store.error), 21 | responseTemplates: useStore(threadManager, (store) => store.responseTemplates), 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /js/packages/react-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { ChatProvider } from "./ChatProvider"; 2 | // Re-export hooks from react-core 3 | export { MessageContext, MessageProvider, useMessage } from "./hooks/useMessage"; 4 | export { useThreadActions } from "./hooks/useThreadActions"; 5 | export { useThreadListActions } from "./hooks/useThreadListActions"; 6 | export { useThreadListState } from "./hooks/useThreadListState"; 7 | export { useThreadManagerSelector } from "./hooks/useThreadManagerSelector"; 8 | export { useThreadState } from "./hooks/useThreadState"; 9 | export { processStreamedMessage } from "./stream/processStreamedMessage"; 10 | export { UseThreadListManagerParams, useThreadListManager } from "./useThreadListManager"; 11 | export { UseThreadManagerParams, useThreadManager } from "./useThreadManager"; 12 | 13 | export * from "./types"; 14 | -------------------------------------------------------------------------------- /js/packages/react-core/src/internal/ChatContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | import invariant from "tiny-invariant"; 3 | import { StoreApi } from "zustand"; 4 | import { ThreadListManager, ThreadManager } from "../types"; 5 | 6 | export const ChatContext = createContext<{ 7 | threadListManager: StoreApi; 8 | threadManager: StoreApi; 9 | } | null>(null); 10 | 11 | export const useChatContext = () => { 12 | const chatCtxValue = useContext(ChatContext); 13 | invariant(chatCtxValue, "chat context not found"); 14 | 15 | return chatCtxValue; 16 | }; 17 | -------------------------------------------------------------------------------- /js/packages/react-core/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./chatManager"; 2 | export * from "./message"; 3 | export * from "./responseTemplate"; 4 | -------------------------------------------------------------------------------- /js/packages/react-core/src/types/responseTemplate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @category Types 3 | */ 4 | export interface ResponseTemplate { 5 | name: string; 6 | Component: React.ComponentType; 7 | } 8 | -------------------------------------------------------------------------------- /js/packages/react-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "../../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./dist", 6 | "rootDir": "./src", 7 | "declaration": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/.storybook/manager.css: -------------------------------------------------------------------------------- 1 | .sidebar-header img { 2 | width: auto; 3 | height: 32px; 4 | } 5 | -------------------------------------------------------------------------------- /js/packages/react-ui/.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/manager-api"; 2 | import "./manager.css"; 3 | import theme from "./theme"; 4 | 5 | addons.setConfig({ 6 | theme: theme, 7 | 8 | }); 9 | 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/.storybook/theme.ts: -------------------------------------------------------------------------------- 1 | import { create } from "@storybook/theming"; 2 | 3 | export default create({ 4 | base: "dark", 5 | brandTitle: "Crayon Components", 6 | brandUrl: "https://crayonai.org/docs/ui", 7 | brandImage: "https://crayonai.org/img/logo.png", 8 | brandTarget: "_self", 9 | }); 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/README.md: -------------------------------------------------------------------------------- 1 | ## UI Components 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/cp-css.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import { camelCase } from "lodash-es"; 3 | import path from "path"; 4 | 5 | const dirname = path.dirname(new URL(import.meta.url).pathname); 6 | 7 | // Create directories if they don't exist 8 | function ensureDirectoryExists(dirPath) { 9 | if (!fs.existsSync(dirPath)) { 10 | fs.mkdirSync(dirPath, { recursive: true }); 11 | } 12 | } 13 | 14 | // Copy CSS files from src to dist 15 | function copyCssFiles() { 16 | const srcDir = path.join(dirname, "dist", "components"); 17 | const distDir = path.join(dirname, "dist", "styles"); 18 | 19 | // Ensure the dist/styles directory exists 20 | ensureDirectoryExists(distDir); 21 | 22 | // Read all component directories 23 | const components = fs.readdirSync(srcDir); 24 | 25 | components.forEach((component) => { 26 | const componentSrcPath = path.join(srcDir, component); 27 | const componentStylesheetName = `${camelCase(component)}.css`; 28 | 29 | // Skip if not a directory 30 | if (!fs.statSync(componentSrcPath).isDirectory()) { 31 | return; 32 | } 33 | 34 | const stylePath = path.join(componentSrcPath, componentStylesheetName); 35 | const distFile = path.join(distDir, componentStylesheetName); 36 | if (fs.existsSync(stylePath)) { 37 | fs.copyFileSync(stylePath, distFile); 38 | } else { 39 | console.warn(`No stylesheet found for ${component}`); 40 | } 41 | }); 42 | 43 | const indexCSSContent = fs.readFileSync(path.join(srcDir, "index.css"), "utf8"); 44 | fs.writeFileSync(path.join(distDir, "index.css"), indexCSSContent); 45 | } 46 | 47 | try { 48 | copyCssFiles(); 49 | console.log("CSS files copied successfully!"); 50 | } catch (error) { 51 | console.error("Error copying CSS files:", error); 52 | process.exit(1); 53 | } 54 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Accordion/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Accordion"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Accordion/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Accordion"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { forwardRef, ReactNode } from "react"; 3 | 4 | type ButtonVariant = "primary" | "secondary" | "tertiary"; 5 | type ButtonSize = "small" | "medium" | "large"; 6 | 7 | export interface ButtonProps extends React.ButtonHTMLAttributes { 8 | variant?: ButtonVariant; 9 | size?: ButtonSize; 10 | iconLeft?: ReactNode; 11 | iconRight?: ReactNode; 12 | } 13 | 14 | const variantMap: Record = { 15 | primary: "crayon-button-base-primary", 16 | secondary: "crayon-button-base-secondary", 17 | tertiary: "crayon-button-base-tertiary", 18 | }; 19 | 20 | const sizeMap: Record = { 21 | small: "crayon-button-base-small", 22 | medium: "crayon-button-base-medium", 23 | large: "crayon-button-base-large", 24 | }; 25 | 26 | export const Button = forwardRef( 27 | ( 28 | { children, variant = "primary", size = "medium", iconLeft, iconRight, className, ...props }, 29 | ref, 30 | ) => { 31 | return ( 32 | 41 | ); 42 | }, 43 | ); 44 | 45 | Button.displayName = "Button"; 46 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Button/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Button"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Button/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Button"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Buttons/Buttons.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, HTMLAttributes, ReactElement } from "react"; 3 | import { ButtonProps } from "../Button"; 4 | import { IconButtonProps } from "../IconButton"; 5 | 6 | type ButtonsVariant = "vertical" | "horizontal"; 7 | 8 | export interface ButtonsProps extends HTMLAttributes { 9 | variant?: ButtonsVariant; 10 | children: 11 | | ReactElement 12 | | ReactElement[]; 13 | className?: string; 14 | style?: CSSProperties; 15 | } 16 | 17 | const variantMap: Record = { 18 | vertical: "crayon-buttons-vertical", 19 | horizontal: "crayon-buttons-horizontal", 20 | }; 21 | 22 | export const Buttons = forwardRef((props, ref) => { 23 | const { className, style, variant = "horizontal", children, ...rest } = props; 24 | return ( 25 |
31 | {children} 32 |
33 | ); 34 | }); 35 | 36 | Buttons.displayName = "Buttons"; 37 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Buttons/buttons.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-buttons { 4 | display: flex; 5 | width: 100%; 6 | gap: cssUtils.$spacing-m; 7 | box-sizing: border-box; 8 | 9 | &-horizontal { 10 | flex-direction: row; 11 | flex-wrap: wrap; 12 | } 13 | 14 | &-vertical { 15 | flex-direction: column; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Buttons/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Buttons"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Buttons/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Buttons"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/Calendar.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React, { forwardRef, useRef } from "react"; 3 | import { DayPicker } from "react-day-picker"; 4 | import { useLayoutContext } from "../../context/LayoutContext"; 5 | import { useMultipleRefs } from "../../hooks/useMultipleRefs"; 6 | import { MonthsDropdown, YearsDropdown } from "./components/helperComponents"; 7 | import { getDayPickerStyles } from "./utils/styles"; 8 | export type CalendarProps = React.ComponentProps; 9 | 10 | export const Calendar = forwardRef( 11 | ({ className, classNames, ...props }, ref) => { 12 | const { layout } = useLayoutContext(); 13 | const { DateSingleClasses, DateRangeClasses } = getDayPickerStyles(layout); 14 | const containerRef = useRef(null); 15 | const assignRef = useMultipleRefs(ref, containerRef); 16 | 17 | const commonProps = { 18 | captionLayout: "dropdown" as const, 19 | components: { 20 | MonthsDropdown: (props: any) => ( 21 | 22 | ), 23 | YearsDropdown: (props: any) => ( 24 | 25 | ), 26 | }, 27 | }; 28 | 29 | return ( 30 |
31 | 41 |
42 | ); 43 | }, 44 | ); 45 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/calendar.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | @forward "./components/calendarHelperComponents.scss"; 3 | @forward "./utils/calendarBaseStyle.scss"; 4 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/components/calendarHelperComponents.scss: -------------------------------------------------------------------------------- 1 | @use "../../../cssUtils" as cssUtils; 2 | 3 | .crayon-calendar-container .crayon-calendar-select-content-months { 4 | padding: cssUtils.$spacing-2xs 0; 5 | background-color: cssUtils.$bg-container; 6 | box-shadow: none; 7 | } 8 | 9 | .crayon-calendar-container .crayon-calendar-select-content-years { 10 | max-height: 295px; 11 | min-width: 362px; 12 | padding: cssUtils.$spacing-2xs 0; 13 | background-color: cssUtils.$bg-container; 14 | box-shadow: none; 15 | .crayon-calendar-select-viewport { 16 | display: grid; 17 | grid-template-columns: repeat(3, 1fr); 18 | gap: 4px; 19 | 20 | &-mobile { 21 | grid-template-columns: repeat(2, 1fr); 22 | } 23 | } 24 | 25 | .crayon-calendar-select-item { 26 | display: flex; 27 | align-items: center; 28 | justify-content: center; 29 | align-self: center; 30 | justify-self: center; 31 | border-radius: cssUtils.$rounded-s; 32 | padding: cssUtils.$spacing-s; 33 | 34 | &:hover { 35 | background-color: cssUtils.$bg-container-hover; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/dependencies.ts: -------------------------------------------------------------------------------- 1 | import IconButtonDeps from "../IconButton/dependencies"; 2 | import SelectDeps from "../Select/dependencies"; 3 | 4 | const dependencies = ["Calendar", ...IconButtonDeps, ...SelectDeps]; 5 | 6 | export default dependencies; 7 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Calendar"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Calendar/utils/helperFn.tsx: -------------------------------------------------------------------------------- 1 | export const getMonthName = (monthNumber: number): string => { 2 | switch (monthNumber) { 3 | case 0: 4 | return "January"; 5 | case 1: 6 | return "February"; 7 | case 2: 8 | return "March"; 9 | case 3: 10 | return "April"; 11 | case 4: 12 | return "May"; 13 | case 5: 14 | return "June"; 15 | case 6: 16 | return "July"; 17 | case 7: 18 | return "August"; 19 | case 8: 20 | return "September"; 21 | case 9: 22 | return "October"; 23 | case 10: 24 | return "November"; 25 | case 11: 26 | return "December"; 27 | default: 28 | return "Invalid Month"; 29 | } 30 | }; 31 | 32 | export const getMonthNumber = (monthName: string): number => { 33 | switch (monthName) { 34 | case "January": 35 | return 0; 36 | case "February": 37 | return 1; 38 | case "March": 39 | return 2; 40 | case "April": 41 | return 3; 42 | case "May": 43 | return 4; 44 | case "June": 45 | return 5; 46 | case "July": 47 | return 6; 48 | case "August": 49 | return 7; 50 | case "September": 51 | return 8; 52 | case "October": 53 | return 9; 54 | case "November": 55 | return 10; 56 | case "December": 57 | return 11; 58 | default: 59 | return -1; 60 | } 61 | }; 62 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Callout/Callout.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React from "react"; 3 | 4 | type CalloutVariant = "neutral" | "info" | "warning" | "success"; 5 | 6 | export interface CalloutProps extends Omit, "title"> { 7 | variant?: CalloutVariant; 8 | title?: React.ReactNode; 9 | icon?: React.ReactNode; 10 | description?: React.ReactNode; 11 | } 12 | 13 | const variantMap: Record = { 14 | neutral: "crayon-callout-neutral", 15 | info: "crayon-callout-info", 16 | warning: "crayon-callout-warning", 17 | success: "crayon-callout-success", 18 | }; 19 | 20 | export const Callout = React.forwardRef((props, ref) => { 21 | const { className, variant = "neutral", title, icon, description, ...rest } = props; 22 | 23 | return ( 24 |
25 | {icon && ( 26 |
27 | {icon} 28 |
29 | )} 30 |
31 | {title && {title}} 32 | {description && {description}} 33 |
34 |
35 | ); 36 | }); 37 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Callout/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Callout"]; 2 | 3 | export default dependencies; 4 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Callout/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Callout"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Card/Card.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React from "react"; 3 | 4 | type CardVariant = "clear" | "card" | "sunk"; 5 | type CardWidth = "standard" | "full"; 6 | 7 | export interface CardProps extends React.HTMLAttributes { 8 | variant?: CardVariant; 9 | width?: CardWidth; 10 | } 11 | 12 | const variantMap: Record = { 13 | clear: "crayon-card-clear", 14 | card: "crayon-card-card", 15 | sunk: "crayon-card-sunk", 16 | }; 17 | 18 | const widthMap: Record = { 19 | standard: "crayon-card-standard", 20 | full: "crayon-card-full", 21 | }; 22 | 23 | export const Card = React.forwardRef((props, ref) => { 24 | const { className, children, variant = "card", width = "standard", ...rest } = props; 25 | 26 | return ( 27 |
32 | {children} 33 |
34 | ); 35 | }); 36 | 37 | Card.displayName = "Card"; 38 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Card/card.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-card { 4 | display: flex; 5 | flex-direction: column; 6 | gap: cssUtils.$spacing-l; 7 | border: 1px solid transparent; 8 | box-sizing: border-box; 9 | color: cssUtils.$primary-text; 10 | @include cssUtils.typography(body, default); 11 | 12 | // override theme variables so that other crayon components don't depend on chat colors 13 | // this solves the case where the crayon-card component is used without the crayon-shell-container 14 | --crayon-primary-text: #{cssUtils.$chat-assistant-response-text}; 15 | --crayon-container-fills: #{cssUtils.$chat-assistant-response-bg}; 16 | 17 | &-card { 18 | padding: cssUtils.$spacing-l; 19 | border-radius: cssUtils.$rounded-3xl; 20 | border-color: cssUtils.$stroke-default; 21 | background-color: cssUtils.$bg-container; 22 | box-shadow: none; 23 | } 24 | 25 | &-clear { 26 | padding: 0px cssUtils.$spacing-l; 27 | border-radius: cssUtils.$rounded-3xl; 28 | background-color: transparent; 29 | box-shadow: none; 30 | } 31 | 32 | &-sunk { 33 | padding: cssUtils.$spacing-l; 34 | border-radius: cssUtils.$rounded-3xl; 35 | background-color: cssUtils.$bg-sunk; 36 | border-color: cssUtils.$stroke-default; 37 | box-shadow: cssUtils.$shadow-m; 38 | } 39 | 40 | &-standard { 41 | width: 80%; 42 | } 43 | 44 | &-full { 45 | width: 100%; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Card/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Card"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Card/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Card"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CardHeader/CardHeader.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { cloneElement, CSSProperties, forwardRef, ReactElement, ReactNode } from "react"; 3 | import { ButtonProps } from "../Button"; 4 | import { IconButtonProps } from "../IconButton"; 5 | 6 | export interface CardHeaderProps { 7 | icon?: ReactNode; 8 | title?: ReactNode; 9 | subtitle?: ReactNode; 10 | actions?: 11 | | ReactElement 12 | | ReactElement[]; 13 | className?: string; 14 | styles?: CSSProperties; 15 | } 16 | 17 | export const CardHeader = forwardRef((props, ref) => { 18 | const { icon, title, subtitle, actions, className, styles, ...rest } = props; 19 | return ( 20 |
21 |
22 |
23 | {icon && {icon}} 24 | {title} 25 |
26 |
27 | {Array.isArray(actions) 28 | ? actions.map((action, index) => cloneElement(action, { key: index })) 29 | : actions} 30 |
31 |
32 |
{subtitle}
33 |
34 | ); 35 | }); 36 | 37 | CardHeader.displayName = "CardHeader"; 38 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CardHeader/cardHeader.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-header { 4 | display: flex; 5 | flex-direction: column; 6 | gap: cssUtils.$spacing-2xs; 7 | overflow-wrap: break-word; 8 | 9 | &-top { 10 | display: flex; 11 | flex-direction: row; 12 | justify-content: space-between; 13 | align-items: center; 14 | 15 | &-left { 16 | display: flex; 17 | flex-direction: row; 18 | align-items: center; 19 | gap: cssUtils.$spacing-2xs; 20 | color: cssUtils.$primary-text; 21 | @include cssUtils.typography(title, default); 22 | 23 | &-icon { 24 | display: flex; 25 | align-items: center; 26 | justify-content: center; 27 | height: 16px; 28 | width: 16px; 29 | } 30 | } 31 | 32 | &-right { 33 | display: flex; 34 | flex-direction: row; 35 | align-items: center; 36 | gap: cssUtils.$spacing-2xs; 37 | } 38 | } 39 | 40 | &-bottom { 41 | color: cssUtils.$secondary-text; 42 | @include cssUtils.typography(body, default); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CardHeader/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["CardHeader"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CardHeader/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CardHeader"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Carousel/carousel.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-carousel { 4 | position: relative; 5 | display: flex; 6 | 7 | &-content { 8 | position: relative; 9 | display: flex; 10 | flex-direction: row; 11 | gap: cssUtils.$spacing-m; 12 | overflow-x: auto; 13 | scroll-snap-type: x mandatory; 14 | -ms-overflow-x: hidden; 15 | scrollbar-width: none; 16 | 17 | &-wrapper { 18 | display: flex; 19 | gap: cssUtils.$spacing-m; 20 | } 21 | 22 | &::-webkit-scrollbar { 23 | display: none; 24 | } 25 | 26 | & > * { 27 | box-sizing: border-box; 28 | scroll-snap-align: start; 29 | } 30 | } 31 | 32 | &-item { 33 | @include cssUtils.typography(body, default); 34 | display: flex; 35 | flex-direction: column; 36 | gap: cssUtils.$spacing-s; 37 | min-width: 200px; 38 | max-width: 200px; 39 | border-radius: cssUtils.$rounded-m; 40 | background-color: cssUtils.$bg-container; 41 | padding: cssUtils.$spacing-m; 42 | border: 1px solid cssUtils.$stroke-default; 43 | } 44 | 45 | &-button { 46 | position: absolute; 47 | top: 50%; 48 | z-index: 10; 49 | transform: translateY(-50%); 50 | 51 | &-left { 52 | left: 0; 53 | } 54 | 55 | &-right { 56 | right: 0; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Carousel/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Carousel"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Carousel/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Carousel"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/AreaChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./AreaChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/BarChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./BarChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/LineChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./LineChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/PieChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./PieChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/RadarChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./RadarChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/RadialChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./RadialChart"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/cartesianGrid.tsx: -------------------------------------------------------------------------------- 1 | import { CartesianGrid } from "recharts"; 2 | 3 | export const cartesianGrid = () => ( 4 | 15 | ); 16 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Charts"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Charts/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./AreaChart"; 2 | export * from "./BarChart"; 3 | export * from "./LineChart"; 4 | export * from "./PieChart"; 5 | export * from "./RadarChart"; 6 | export * from "./RadialChart"; 7 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxGroup/CheckBoxGroup.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React from "react"; 3 | import { CheckBoxItemProps } from "../CheckBoxItem"; 4 | 5 | type CheckBoxGroupVariant = "clear" | "card" | "sunk"; 6 | 7 | interface CheckBoxGroupProps { 8 | children: React.ReactElement | React.ReactElement[]; 9 | className?: string; 10 | style?: React.CSSProperties; 11 | variant?: CheckBoxGroupVariant; 12 | } 13 | 14 | const variantMap: Record = { 15 | clear: "crayon-checkbox-group-clear", 16 | card: "crayon-checkbox-group-card", 17 | sunk: "crayon-checkbox-group-sunk", 18 | }; 19 | 20 | const CheckBoxGroup = React.forwardRef((props, ref) => { 21 | const { children, className, style, variant = "clear" } = props; 22 | return ( 23 |
28 | {children} 29 |
30 | ); 31 | }); 32 | 33 | CheckBoxGroup.displayName = "CheckBoxGroup"; 34 | 35 | export { CheckBoxGroup, type CheckBoxGroupProps }; 36 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxGroup/checkBoxGroup.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-checkbox-group { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-direction: column; 7 | gap: cssUtils.$spacing-3xs; 8 | border: 1px solid; 9 | border-radius: cssUtils.$rounded-m; 10 | 11 | &-clear { 12 | border-color: transparent; 13 | background-color: transparent; 14 | padding: cssUtils.$spacing-0; 15 | } 16 | 17 | &-card { 18 | border-color: cssUtils.$stroke-default; 19 | padding: cssUtils.$spacing-l; 20 | } 21 | 22 | &-sunk { 23 | border-color: cssUtils.$stroke-default; 24 | background-color: cssUtils.$bg-sunk; 25 | padding: cssUtils.$spacing-l; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxGroup/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["CheckBoxGroup"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxGroup/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CheckBoxGroup"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxItem/CheckBoxItem.tsx: -------------------------------------------------------------------------------- 1 | import * as Checkbox from "@radix-ui/react-checkbox"; 2 | import clsx from "clsx"; 3 | import { Check } from "lucide-react"; 4 | import { CSSProperties, forwardRef, ReactNode, useId } from "react"; 5 | 6 | export interface CheckBoxItemProps { 7 | label?: ReactNode; 8 | className?: string; 9 | style?: CSSProperties; 10 | checked?: boolean; 11 | defaultChecked?: boolean; 12 | disabled?: boolean; 13 | required?: boolean; 14 | name?: string; 15 | value?: string; 16 | onChange?: (checked: boolean) => void; 17 | } 18 | 19 | const CheckBoxItem = forwardRef((props, ref) => { 20 | const { label, onChange, className, disabled, required, ...rest } = props; 21 | const id = useId(); 22 | return ( 23 |
24 | 33 | 34 | 35 | 36 | 37 | {label && ( 38 | 41 | )} 42 |
43 | ); 44 | }); 45 | 46 | CheckBoxItem.displayName = "CheckBoxItem"; 47 | 48 | export { CheckBoxItem }; 49 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxItem/checkBoxItem.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-checkbox-item-container { 4 | display: flex; 5 | align-items: center; 6 | gap: cssUtils.$spacing-xs; 7 | width: 100%; 8 | max-width: 100%; 9 | overflow: hidden; 10 | padding-top: cssUtils.$spacing-3xs; 11 | padding-bottom: cssUtils.$spacing-3xs; 12 | padding-left: cssUtils.$spacing-0; 13 | padding-right: cssUtils.$spacing-2xs; 14 | } 15 | 16 | .crayon-checkbox-item-root { 17 | display: inline-flex; 18 | align-items: center; 19 | justify-content: center; 20 | width: 14px; 21 | height: 14px; 22 | border-radius: 2px; 23 | border: 1px solid cssUtils.$stroke-interactive-el; 24 | background-color: cssUtils.$bg-container; 25 | cursor: pointer; 26 | 27 | &[data-state="checked"] { 28 | background-color: cssUtils.$bg-brand-el; 29 | color: cssUtils.$primary-text; 30 | } 31 | 32 | &:not(:disabled):hover { 33 | border-color: cssUtils.$stroke-interactive-el-hover; 34 | } 35 | 36 | &:disabled { 37 | cursor: not-allowed; 38 | color: cssUtils.$disabled-text; 39 | } 40 | } 41 | 42 | .crayon-checkbox-item-indicator { 43 | display: flex; 44 | align-items: center; 45 | justify-content: center; 46 | color: cssUtils.$brand-text; 47 | } 48 | 49 | .crayon-checkbox-item-label { 50 | flex: 1; 51 | @include cssUtils.typography(primary, default); 52 | color: cssUtils.$primary-text; 53 | &:disabled { 54 | color: cssUtils.$disabled-text; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxItem/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["CheckBoxItem"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CheckBoxItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CheckBoxItem"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CodeBlock/CodeBlock.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CheckCheck, Copy } from "lucide-react"; 3 | import { useState } from "react"; 4 | import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; 5 | import { vscDarkPlus } from "react-syntax-highlighter/dist/esm/styles/prism"; 6 | import { IconButton } from "../IconButton"; 7 | 8 | export interface CodeBlockProps { 9 | language: string; 10 | codeString: string; 11 | theme?: { 12 | [key: string]: React.CSSProperties; 13 | }; 14 | } 15 | 16 | export const CodeBlock = ({ language, codeString, theme }: CodeBlockProps) => { 17 | const [copied, setCopied] = useState(false); 18 | 19 | const handleCopy = () => { 20 | navigator.clipboard.writeText(codeString); 21 | setCopied(true); 22 | setTimeout(() => setCopied(false), 1000); 23 | }; 24 | 25 | return ( 26 |
27 | : } 35 | /> 36 | 42 | {codeString} 43 | 44 |
45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CodeBlock/codeBlock.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | /* Code Block Styles */ 4 | .crayon-code-block-wrapper { 5 | position: relative; 6 | 7 | &:hover { 8 | .crayon-code-block-copy-button { 9 | opacity: 1; 10 | } 11 | } 12 | 13 | .crayon-code-block-copy-button { 14 | position: absolute; 15 | right: 0.5rem; 16 | top: 0.5rem; 17 | opacity: 0; 18 | transition: opacity 0.2s ease-in-out; 19 | &.crayon-code-block-copy-button-copied { 20 | color: cssUtils.$success-text; 21 | background-color: cssUtils.$bg-success; 22 | } 23 | } 24 | 25 | .crayon-code-block-syntax-highlighter { 26 | margin: 0 !important; 27 | border-radius: 0.5rem; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CodeBlock/dependencies.ts: -------------------------------------------------------------------------------- 1 | import IconButtonDeps from "../IconButton/dependencies"; 2 | 3 | const dependencies = ["CodeBlock", ...IconButtonDeps]; 4 | 5 | export default dependencies; 6 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CodeBlock/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./CodeBlock"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/Container.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { LayoutContextProvider } from "../../context/LayoutContext"; 3 | import { ShellStoreProvider } from "../Shell/store"; 4 | 5 | interface ContainerProps { 6 | children?: React.ReactNode; 7 | logoUrl: string; 8 | agentName: string; 9 | className?: string; 10 | } 11 | 12 | export const Container = ({ children, logoUrl, agentName, className }: ContainerProps) => { 13 | return ( 14 | 15 | 16 |
{children}
17 |
18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/Header.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { useShellStore } from "../Shell/store"; 3 | 4 | export const Header = ({ className }: { className?: string }) => { 5 | const { logoUrl, agentName } = useShellStore((state) => ({ 6 | logoUrl: state.logoUrl, 7 | agentName: state.agentName, 8 | })); 9 | 10 | return ( 11 |
12 |
13 | Logo 14 | {agentName} 15 |
16 |
17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/copilotShell.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | @use "./thread.scss"; 3 | @use "./header.scss"; 4 | 5 | .crayon-copilot-shell-container { 6 | display: flex; 7 | position: relative; 8 | height: 100dvh; 9 | width: 530px; 10 | overflow: hidden; 11 | 12 | border: 1px solid cssUtils.$stroke-default; 13 | border-width: 0 1px; 14 | 15 | background: cssUtils.$chat-container-bg; 16 | box-sizing: border-box; 17 | & * { 18 | box-sizing: border-box; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/dependencies.ts: -------------------------------------------------------------------------------- 1 | import buttonDeps from "../Button/dependencies"; 2 | import iconButtonDeps from "../IconButton/dependencies"; 3 | 4 | const dependencies = ["Shell", ...iconButtonDeps, ...buttonDeps]; 5 | export default dependencies; 6 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/header.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-copilot-shell-header { 4 | display: flex; 5 | align-items: center; 6 | justify-content: space-between; 7 | padding: cssUtils.$spacing-m cssUtils.$spacing-l; 8 | border-bottom: 1px solid cssUtils.$stroke-default; 9 | background-color: cssUtils.$bg-container; 10 | } 11 | 12 | .crayon-copilot-shell-header-logo-container { 13 | display: flex; 14 | align-items: center; 15 | gap: cssUtils.$spacing-s; 16 | @include cssUtils.typography(title, medium); 17 | } 18 | 19 | .crayon-copilot-shell-header-logo { 20 | width: 32px; 21 | height: 32px; 22 | border-radius: cssUtils.$rounded-m; 23 | } 24 | 25 | .crayon-copilot-shell-header-agent-name { 26 | @include cssUtils.typography(title, medium); 27 | color: cssUtils.$primary-text; 28 | } 29 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Container"; 2 | export * from "./Header"; 3 | export * from "./Thread"; 4 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/stories/style.module.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | display: flex; 3 | } 4 | 5 | .left { 6 | flex-grow: 1; 7 | background: white; 8 | } 9 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CopilotShell/stories/thesysdev_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/js/packages/react-ui/src/components/CopilotShell/stories/thesysdev_logo.jpeg -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CrayonChat/ComposedCopilot.tsx: -------------------------------------------------------------------------------- 1 | import { ScrollVariant } from "../../hooks/useScrollToBottom"; 2 | import { 3 | Composer, 4 | Container, 5 | Header, 6 | MessageLoading, 7 | Messages, 8 | ScrollArea, 9 | ThreadContainer, 10 | } from "../CopilotShell"; 11 | interface ComposedCopilotProps { 12 | logoUrl?: string; 13 | agentName?: string; 14 | messageLoadingComponent?: () => React.ReactNode; 15 | scrollVariant: ScrollVariant; 16 | } 17 | 18 | export const ComposedCopilot = ({ 19 | logoUrl = "https://crayonai.org/img/logo.png", 20 | agentName = "My Agent", 21 | messageLoadingComponent: MessageLoadingComponent = MessageLoading, 22 | scrollVariant, 23 | }: ComposedCopilotProps) => { 24 | return ( 25 | 26 | 27 |
28 | 29 | } /> 30 | 31 | 32 | 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CrayonChat/ComposedStandalone.tsx: -------------------------------------------------------------------------------- 1 | import { ScrollVariant } from "../../hooks/useScrollToBottom"; 2 | import { 3 | Composer, 4 | Container, 5 | MessageLoading, 6 | Messages, 7 | MobileHeader, 8 | NewChatButton, 9 | ScrollArea, 10 | SidebarContainer, 11 | SidebarContent, 12 | SidebarHeader, 13 | SidebarSeparator, 14 | ThreadContainer, 15 | ThreadList, 16 | } from "../Shell"; 17 | interface ComposedStandaloneProps { 18 | logoUrl?: string; 19 | agentName?: string; 20 | messageLoadingComponent?: () => React.ReactNode; 21 | scrollVariant: ScrollVariant; 22 | } 23 | 24 | export const ComposedStandalone = ({ 25 | logoUrl = "https://crayonai.org/img/logo.png", 26 | agentName = "My Agent", 27 | messageLoadingComponent: MessageLoadingComponent = MessageLoading, 28 | scrollVariant, 29 | }: ComposedStandaloneProps) => { 30 | return ( 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | } /> 44 | 45 | 46 | 47 | 48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CrayonChat/crayonChat.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/js/packages/react-ui/src/components/CrayonChat/crayonChat.scss -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CrayonChat/dependencies.ts: -------------------------------------------------------------------------------- 1 | import shellDeps from "../Shell/dependencies"; 2 | 3 | const dependencies = ["CrayonChat", ...shellDeps]; 4 | 5 | export default dependencies; 6 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/CrayonChat/index.ts: -------------------------------------------------------------------------------- 1 | export { CrayonChat } from "./CrayonChat"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/DatePicker/datePicker.scss: -------------------------------------------------------------------------------- 1 | @forward "./helpers/components/helperComponents"; 2 | @forward "./helpers/components/datePickerRenderer"; 3 | @forward "./helpers/components/floatingDatePickerRenderer"; 4 | @forward "./helpers/utils/datePickerBaseStyle"; 5 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/DatePicker/dependencies.ts: -------------------------------------------------------------------------------- 1 | import IconButtonDeps from "../IconButton/dependencies"; 2 | import SelectDeps from "../Select/dependencies"; 3 | 4 | const dependencies = ["DatePicker", ...IconButtonDeps, ...SelectDeps]; 5 | 6 | export default dependencies; 7 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/DatePicker/helpers/components/datePickerRenderer.scss: -------------------------------------------------------------------------------- 1 | .crayon-date-picker-renderer-single-mode { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | .crayon-date-picker-renderer-range-mode { 7 | width: 100%; 8 | height: 100%; 9 | } 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/DatePicker/helpers/components/helperComponents.scss: -------------------------------------------------------------------------------- 1 | @use "../../../../cssUtils" as cssUtils; 2 | 3 | .crayon-date-picker-renderer-floating-menu .crayon-date-picker-select-content-months { 4 | padding: cssUtils.$spacing-2xs 0; 5 | background-color: cssUtils.$bg-container; 6 | box-shadow: none; 7 | border-color: transparent; 8 | } 9 | 10 | .crayon-date-picker-renderer-floating-menu .crayon-date-picker-select-content-years { 11 | max-height: 295px; 12 | min-width: 362px; 13 | padding: cssUtils.$spacing-2xs 0; 14 | background-color: cssUtils.$bg-container; 15 | box-shadow: none; 16 | border-color: transparent; 17 | .crayon-date-picker-select-viewport { 18 | display: grid; 19 | grid-template-columns: repeat(3, 1fr); 20 | gap: 4px; 21 | 22 | &-mobile { 23 | grid-template-columns: repeat(2, 1fr); 24 | } 25 | } 26 | 27 | .crayon-date-picker-select-item { 28 | display: flex; 29 | align-items: center; 30 | justify-content: center; 31 | align-self: center; 32 | justify-self: center; 33 | border-radius: cssUtils.$rounded-s; 34 | padding: cssUtils.$spacing-s; 35 | 36 | &:hover { 37 | background-color: cssUtils.$bg-container-hover; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/DatePicker/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./DatePicker"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpBlock/FollowUpBlock.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, ReactElement } from "react"; 3 | import { FollowUpItemProps } from "../FollowUpItem"; 4 | 5 | export interface FollowUpBlockProps { 6 | children: ReactElement | ReactElement[]; 7 | className?: string; 8 | style?: CSSProperties; 9 | } 10 | 11 | const FollowUpBlock = forwardRef((props, ref) => { 12 | const { children, className, style } = props; 13 | return ( 14 |
15 | {children} 16 |
17 | ); 18 | }); 19 | 20 | FollowUpBlock.displayName = "FollowUpBlock"; 21 | 22 | export { FollowUpBlock }; 23 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpBlock/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["FollowUpBlock"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpBlock/followUpBlock.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-follow-up-block { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-direction: column; 7 | gap: cssUtils.$spacing-3xs; 8 | } 9 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpBlock/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./FollowUpBlock"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpItem/FollowUpItem.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { ButtonHTMLAttributes, forwardRef, ReactNode } from "react"; 3 | 4 | export interface FollowUpItemProps extends ButtonHTMLAttributes { 5 | text: ReactNode; 6 | icon?: ReactNode; 7 | className?: string; 8 | } 9 | 10 | const FollowUpItem = forwardRef((props, ref) => { 11 | const { className, text, icon, ...rest } = props; 12 | return ( 13 | 17 | ); 18 | }); 19 | 20 | FollowUpItem.displayName = "FollowUpItem"; 21 | 22 | export { FollowUpItem }; 23 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpItem/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["FollowUpItem"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpItem/followUpItem.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-follow-up-item { 4 | @include cssUtils.button-reset; 5 | @include cssUtils.typography(primary, default); 6 | box-sizing: border-box; 7 | padding: cssUtils.$spacing-xs cssUtils.$spacing-0; 8 | border-bottom: 1px solid cssUtils.$stroke-default; 9 | background-color: transparent; 10 | gap: cssUtils.$spacing-xs; 11 | display: flex; 12 | align-items: center; 13 | justify-content: space-between; 14 | width: 100%; 15 | color: cssUtils.$primary-text; 16 | cursor: pointer; 17 | } 18 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./FollowUpItem"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FollowUpItem/stories/FollowUpItem.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from "@storybook/react"; 2 | import { ArrowRight } from "lucide-react"; 3 | import { FollowUpItem } from "../FollowUpItem"; 4 | 5 | const meta: Meta = { 6 | title: "Components/FollowUpItem", 7 | component: FollowUpItem, 8 | parameters: { 9 | layout: "centered", 10 | docs: { 11 | description: { 12 | component: "```tsx\nimport { FollowUpItem } from '@crayon-ui/react-ui';\n```", 13 | }, 14 | }, 15 | }, 16 | tags: ["!dev", "!autodocs"], 17 | argTypes: { 18 | text: { 19 | control: "text", 20 | description: "The text content of the follow-up item", 21 | table: { 22 | category: "Content", 23 | type: { summary: "string" }, 24 | }, 25 | }, 26 | icon: { 27 | control: false, 28 | description: "", 29 | table: { 30 | category: "Content", 31 | type: { summary: "ReactNode" }, 32 | }, 33 | }, 34 | className: { 35 | control: false, 36 | description: "Additional CSS class names", 37 | table: { 38 | category: "Styling", 39 | type: { summary: "string" }, 40 | }, 41 | }, 42 | }, 43 | }; 44 | 45 | export default meta; 46 | type Story = StoryObj; 47 | 48 | export const Default: Story = { 49 | args: { 50 | text: "Continue with this topic", 51 | icon: , 52 | }, 53 | }; 54 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/FormControl.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React, { forwardRef } from "react"; 3 | 4 | export interface FormControlProps { 5 | children: React.ReactNode; 6 | className?: string; 7 | style?: React.CSSProperties; 8 | } 9 | 10 | const FormControl = forwardRef((props, ref) => { 11 | return ( 12 |
13 | {props.children} 14 |
15 | ); 16 | }); 17 | 18 | FormControl.displayName = "FormControl"; 19 | 20 | export { FormControl }; 21 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/Hint/Hint.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React, { forwardRef } from "react"; 3 | 4 | export interface HintProps extends React.ComponentPropsWithoutRef<"div"> { 5 | children: React.ReactNode; 6 | className?: string; 7 | style?: React.CSSProperties; 8 | } 9 | 10 | const Hint = forwardRef( 11 | ({ children, className, style, ...props }, ref) => { 12 | return ( 13 |
14 | {children} 15 |
16 | ); 17 | }, 18 | ); 19 | 20 | Hint.displayName = "Hint"; 21 | 22 | export { Hint }; 23 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/Hint/hint.scss: -------------------------------------------------------------------------------- 1 | @use "../../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-hint { 4 | box-sizing: border-box; 5 | @include cssUtils.typography(label, default); 6 | color: cssUtils.$secondary-text; 7 | display: flex; 8 | align-items: center; 9 | gap: cssUtils.$spacing-2xs; 10 | } 11 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/Hint/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Hint"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["FormControl"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/formControl.scss: -------------------------------------------------------------------------------- 1 | @forward "./Hint/hint"; 2 | @use "../../cssUtils.scss" as cssUtils; 3 | 4 | .crayon-form-control { 5 | box-sizing: border-box; 6 | display: flex; 7 | flex-direction: column; 8 | gap: cssUtils.$spacing-s; 9 | } 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/FormControl/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./FormControl"; 2 | export * from "./Hint"; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/IconButton/IconButton.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { ButtonHTMLAttributes, forwardRef, ReactNode } from "react"; 3 | 4 | type IconButtonVariant = "primary" | "secondary" | "tertiary"; 5 | type IconButtonSize = "extra-small" | "small" | "medium" | "large"; 6 | type IconButtonShape = "square" | "circle"; 7 | 8 | export interface IconButtonProps extends ButtonHTMLAttributes { 9 | icon: ReactNode; 10 | variant?: IconButtonVariant; 11 | size?: IconButtonSize; 12 | shape?: IconButtonShape; 13 | className?: string; 14 | } 15 | 16 | const iconButtonVariants = { 17 | primary: "crayon-icon-button-primary", 18 | secondary: "crayon-icon-button-secondary", 19 | tertiary: "crayon-icon-button-tertiary", 20 | } as const; 21 | 22 | const iconButtonSizes = { 23 | "extra-small": "crayon-icon-button-extra-small", 24 | small: "crayon-icon-button-small", 25 | medium: "crayon-icon-button-medium", 26 | large: "crayon-icon-button-large", 27 | } as const; 28 | 29 | const iconButtonShapes = { 30 | square: "crayon-icon-button-square", 31 | circle: "crayon-icon-button-circle", 32 | } as const; 33 | 34 | export const IconButton = forwardRef((props, ref) => { 35 | const { 36 | className, 37 | icon, 38 | variant = "primary", 39 | size = "medium", 40 | shape = "square", 41 | ...rest 42 | } = props; 43 | 44 | return ( 45 | 58 | ); 59 | }); 60 | 61 | IconButton.displayName = "IconButton"; 62 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/IconButton/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["IconButton"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/IconButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./IconButton"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Image/Image.tsx: -------------------------------------------------------------------------------- 1 | import * as AspectRatio from "@radix-ui/react-aspect-ratio"; 2 | import clsx from "clsx"; 3 | import React, { forwardRef } from "react"; 4 | 5 | type AspectRatioType = "1:1" | "3:2" | "3:4" | "4:3" | "16:9"; 6 | type ScaleType = "fit" | "fill"; 7 | 8 | export interface ImageProps extends React.ImgHTMLAttributes { 9 | src: string; 10 | alt?: string; 11 | styles?: React.CSSProperties; 12 | className?: string; 13 | aspectRatio?: AspectRatioType; 14 | scale?: ScaleType; 15 | } 16 | 17 | const aspectRatioMap: Record = { 18 | "1:1": 1, 19 | "3:2": 3 / 2, 20 | "3:4": 3 / 4, 21 | "4:3": 4 / 3, 22 | "16:9": 16 / 9, 23 | }; 24 | 25 | const scaleMap: Record = { 26 | fit: "crayon-image-fit", 27 | fill: "crayon-image-fill", 28 | }; 29 | 30 | export const Image = forwardRef((props, ref) => { 31 | const { src, alt, styles, className, aspectRatio = "3:2", scale = "fill", ...rest } = props; 32 | 33 | const imageClasses = clsx( 34 | "crayon-image", 35 | { 36 | [`${scaleMap[scale]}`]: scale, 37 | }, 38 | className, 39 | ); 40 | 41 | const image = ( 42 | {alt} { 49 | e.currentTarget.style.display = "none"; 50 | console.error(`Failed to load image: ${src}`); 51 | }} 52 | {...rest} 53 | /> 54 | ); 55 | 56 | return {image}; 57 | }); 58 | 59 | Image.displayName = "Image"; 60 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Image/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Image"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Image/image.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-image { 4 | display: flex; 5 | box-sizing: border-box; 6 | max-width: 100%; 7 | height: auto; 8 | overflow: clip; 9 | border-radius: cssUtils.$rounded-m; 10 | border: 1px solid cssUtils.$stroke-default; 11 | background-color: cssUtils.$bg-container; 12 | 13 | &-fit { 14 | object-fit: contain; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | 19 | &-fill { 20 | object-fit: cover; 21 | width: 100%; 22 | height: 100%; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Image/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Image"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ImageGallery/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./GalleryModal"; 2 | export * from "./ImageGallery"; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Input/Input.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React from "react"; 3 | 4 | export interface InputProps extends Omit, "size"> { 5 | styles?: React.CSSProperties; 6 | className?: string; 7 | size?: "small" | "medium" | "large"; 8 | } 9 | 10 | const sizes = { 11 | small: "crayon-input-small", 12 | medium: "crayon-input-medium", 13 | large: "crayon-input-large", 14 | } as const; 15 | 16 | export const Input = React.forwardRef( 17 | ({ className, styles, size = "medium", ...props }, ref) => { 18 | return ( 19 | 26 | ); 27 | }, 28 | ); 29 | 30 | Input.displayName = "Input"; 31 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Input/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Input"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Input/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Input"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Input/input.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-input { 4 | @include cssUtils.typography(body, default); 5 | border: 1px solid cssUtils.$stroke-default; 6 | border-radius: cssUtils.$rounded-xs; 7 | box-sizing: border-box; 8 | width: 100%; 9 | gap: cssUtils.$spacing-xs; 10 | background-color: cssUtils.$bg-container; 11 | color: cssUtils.$primary-text; 12 | 13 | &-small { 14 | padding: cssUtils.$spacing-2xs cssUtils.$spacing-s; 15 | } 16 | 17 | &-medium { 18 | padding: cssUtils.$spacing-xs cssUtils.$spacing-s; 19 | } 20 | 21 | &-large { 22 | padding: cssUtils.$spacing-s; 23 | } 24 | &::placeholder { 25 | color: cssUtils.$disabled-text; 26 | } 27 | &:focus { 28 | outline: none; 29 | border-color: cssUtils.$stroke-interactive-el-hover; 30 | } 31 | 32 | &:disabled { 33 | background-color: cssUtils.$bg-container; 34 | border: 1px solid cssUtils.$stroke-default; 35 | cursor: not-allowed; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Label/Label.tsx: -------------------------------------------------------------------------------- 1 | import * as LabelPrimitive from "@radix-ui/react-label"; 2 | import clsx from "clsx"; 3 | import React, { forwardRef } from "react"; 4 | 5 | export interface LabelProps extends React.ComponentPropsWithoutRef { 6 | children: React.ReactNode; 7 | className?: string; 8 | style?: React.CSSProperties; 9 | disabled?: boolean; 10 | required?: boolean; 11 | } 12 | 13 | const Label = forwardRef( 14 | ({ children, className, style, disabled, required, ...props }, ref) => { 15 | return ( 16 | 28 | {children} 29 | {required && *} 30 | 31 | ); 32 | }, 33 | ); 34 | 35 | Label.displayName = LabelPrimitive.Root.displayName; 36 | 37 | export { Label }; 38 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Label/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Label"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Label/label.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-label { 4 | box-sizing: border-box; 5 | @include cssUtils.typography(primary, default); 6 | color: cssUtils.$secondary-text; 7 | 8 | &-disabled { 9 | color: cssUtils.$disabled-text; 10 | cursor: not-allowed; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListBlock/ListBlock.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, ReactElement } from "react"; 3 | import { ListItemProps } from "../ListItem"; 4 | 5 | export interface ListBlockProps { 6 | children: ReactElement | ReactElement[]; 7 | className?: string; 8 | style?: CSSProperties; 9 | } 10 | 11 | const ListBlock = forwardRef((props, ref) => { 12 | return ( 13 |
14 | {props.children} 15 |
16 | ); 17 | }); 18 | 19 | ListBlock.displayName = "ListBlock"; 20 | 21 | export { ListBlock }; 22 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListBlock/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["ListBlock"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListBlock/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ListBlock"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListBlock/listBlock.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-list-block { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-direction: column; 7 | width: 100%; 8 | border: 1px solid cssUtils.$stroke-default; 9 | border-radius: cssUtils.$rounded-m; 10 | } 11 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListItem/ListItem.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React, { CSSProperties, ReactNode } from "react"; 3 | 4 | export interface ListItemProps { 5 | className?: string; 6 | style?: CSSProperties; 7 | decorativeIcon?: ReactNode; 8 | title?: ReactNode; 9 | subtitle?: ReactNode; 10 | actionIcon?: ReactNode; 11 | onClick?: () => void; 12 | } 13 | 14 | const ListItem = React.forwardRef((props, ref) => { 15 | const { className, style, decorativeIcon, title, subtitle, actionIcon, onClick, ...rest } = props; 16 | return ( 17 |
24 |
25 | {decorativeIcon && decorativeIcon} 26 | {title &&
{title}
} 27 | {subtitle &&
{subtitle}
} 28 |
29 | {actionIcon &&
{actionIcon}
} 30 |
31 | ); 32 | }); 33 | 34 | ListItem.displayName = "ListItem"; 35 | 36 | export { ListItem }; 37 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListItem/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["ListItem"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ListItem"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/ListItem/listItem.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils.scss" as cssUtils; 2 | 3 | .crayon-list-item { 4 | box-sizing: border-box; 5 | display: flex; 6 | align-items: center; 7 | justify-content: space-between; 8 | border-bottom: 1px solid cssUtils.$stroke-default; 9 | padding: cssUtils.$spacing-s; 10 | cursor: pointer; 11 | 12 | &:last-child { 13 | border-bottom: none; 14 | } 15 | 16 | svg { 17 | color: cssUtils.$secondary-text; 18 | } 19 | 20 | .crayon-list-item-content { 21 | box-sizing: border-box; 22 | flex: 1; 23 | display: flex; 24 | flex-direction: column; 25 | align-items: flex-start; 26 | width: 100%; 27 | gap: cssUtils.$spacing-2xs; 28 | 29 | &-action-icon { 30 | display: flex; 31 | align-items: center; 32 | justify-content: center; 33 | padding: cssUtils.$spacing-3xs; 34 | } 35 | } 36 | 37 | .crayon-list-item-title { 38 | @include cssUtils.typography("primary", "default"); 39 | color: cssUtils.$primary-text; 40 | } 41 | 42 | .crayon-list-item-subtitle { 43 | @include cssUtils.typography("primary", "default"); 44 | color: cssUtils.$secondary-text; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MarkDownRenderer/dependencies.ts: -------------------------------------------------------------------------------- 1 | import CodeBlockDeps from "../CodeBlock/dependencies"; 2 | import TableDeps from "../Table/dependencies"; 3 | 4 | const dependencies = ["MarkDownRenderer", ...CodeBlockDeps, ...TableDeps]; 5 | 6 | export default dependencies; 7 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MarkDownRenderer/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./MarkDownRenderer"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MessageLoading/MessageLoading.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | 3 | export const MessageLoading = ({ className }: { className?: string }) => { 4 | return ( 5 |
6 |
7 |
8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MessageLoading/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["MessageLoading"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MessageLoading/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./MessageLoading"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MessageLoading/messageLoading.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | @keyframes l7 { 4 | 33% { 5 | background-size: 6 | calc(100% / 3) 0%, 7 | calc(100% / 3) 100%, 8 | calc(100% / 3) 100%; 9 | } 10 | 50% { 11 | background-size: 12 | calc(100% / 3) 100%, 13 | calc(100% / 3) 0%, 14 | calc(100% / 3) 100%; 15 | } 16 | 66% { 17 | background-size: 18 | calc(100% / 3) 100%, 19 | calc(100% / 3) 100%, 20 | calc(100% / 3) 0%; 21 | } 22 | } 23 | 24 | .crayon-message-loading-container { 25 | border-radius: cssUtils.$spacing-xl; 26 | border: 1px solid cssUtils.$stroke-default; 27 | padding: cssUtils.$spacing-s; 28 | height: 32px; 29 | display: flex; 30 | align-items: center; 31 | width: fit-content; 32 | box-sizing: border-box; 33 | } 34 | 35 | .crayon-message-loading { 36 | width: 24px; 37 | aspect-ratio: 4; 38 | --_g: no-repeat 39 | radial-gradient(circle closest-side, #{cssUtils.$disabled-text} 90%, transparent 90%); 40 | background: 41 | var(--_g) 0% 50%, 42 | var(--_g) 50% 50%, 43 | var(--_g) 100% 50%; 44 | background-size: calc(100% / 3) 100%; 45 | animation: l7 750ms infinite linear; 46 | } 47 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/MessageLoading/stories/MessageLoading.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Meta, StoryObj } from "@storybook/react"; 2 | import { MessageLoading } from "../MessageLoading"; 3 | 4 | const meta: Meta = { 5 | title: "Components/MessageLoading", 6 | component: MessageLoading, 7 | parameters: { 8 | layout: "centered", 9 | docs: { 10 | description: { 11 | component: "```tsx\nimport { MessageLoading } from '@crayon-ui/react-ui';\n```", 12 | }, 13 | }, 14 | }, 15 | decorators: [ 16 | (Story) => ( 17 |
18 | 19 |
20 | ), 21 | ], 22 | tags: ["!dev", "autodocs"], 23 | }; 24 | 25 | export default meta; 26 | type Story = StoryObj; 27 | 28 | export const Default: Story = { 29 | render: () => , 30 | parameters: { 31 | docs: { 32 | description: { 33 | story: "A loading indicator that appears while a message is being processed.", 34 | }, 35 | }, 36 | }, 37 | }; 38 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioGroup/RadioGroup.tsx: -------------------------------------------------------------------------------- 1 | import * as Radio from "@radix-ui/react-radio-group"; 2 | import clsx from "clsx"; 3 | import { CSSProperties, forwardRef, ReactElement } from "react"; 4 | import { RadioItemProps } from "../RadioItem"; 5 | 6 | type RadioGroupVariant = "clear" | "card" | "sunk"; 7 | interface RadioGroupProps extends Radio.RadioGroupProps { 8 | children: ReactElement | ReactElement[]; 9 | variant?: RadioGroupVariant; 10 | className?: string; 11 | style?: CSSProperties; 12 | } 13 | 14 | const variants: Record = { 15 | clear: "crayon-radio-group-clear", 16 | card: "crayon-radio-group-card", 17 | sunk: "crayon-radio-group-sunk", 18 | }; 19 | 20 | const RadioGroup = forwardRef((props, ref) => { 21 | const { children, className, style, variant = "clear", ...rest } = props; 22 | return ( 23 | 29 | {children} 30 | 31 | ); 32 | }); 33 | 34 | RadioGroup.displayName = "RadioGroup"; 35 | 36 | export { RadioGroup, type RadioGroupProps }; 37 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioGroup/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["RadioGroup"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioGroup/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./RadioGroup"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioGroup/radioGroup.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-radio-group { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-direction: column; 7 | gap: cssUtils.$spacing-3xs; 8 | border: 1px solid; 9 | border-radius: cssUtils.$rounded-m; 10 | 11 | &-clear { 12 | border-color: transparent; 13 | background-color: transparent; 14 | padding: cssUtils.$spacing-0; 15 | } 16 | 17 | &-card { 18 | border-color: cssUtils.$stroke-default; 19 | padding: cssUtils.$spacing-l; 20 | } 21 | 22 | &-sunk { 23 | border-color: cssUtils.$stroke-default; 24 | background-color: cssUtils.$bg-sunk; 25 | padding: cssUtils.$spacing-l; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioItem/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["RadioItem"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/RadioItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./RadioItem"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Select/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Select"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Select/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Select"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/Container.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { useRef } from "react"; 3 | import { LayoutContextProvider } from "../../context/LayoutContext"; 4 | import { useElementSize } from "../../hooks/useElementSize"; 5 | import { ShellStoreProvider } from "./store"; 6 | 7 | interface ContainerProps { 8 | children?: React.ReactNode; 9 | logoUrl: string; 10 | agentName: string; 11 | className?: string; 12 | } 13 | 14 | export const Container = ({ children, logoUrl, agentName, className }: ContainerProps) => { 15 | const ref = useRef(null); 16 | const { width } = useElementSize({ ref }) || {}; 17 | // TODO: revisit this logic 18 | const isMobile = width > 0 && width < 768; 19 | const isFullScreen = width > 768; 20 | const layout = isMobile ? "mobile" : isFullScreen ? "fullscreen" : "tray"; 21 | 22 | return ( 23 | 24 | 25 |
35 | {children} 36 |
37 |
38 |
39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/MobileHeader.tsx: -------------------------------------------------------------------------------- 1 | import { useThreadListActions } from "@crayonai/react-core"; 2 | import clsx from "clsx"; 3 | import { Menu, Plus } from "lucide-react"; 4 | import { IconButton } from "../IconButton"; 5 | import { useShellStore } from "./store"; 6 | 7 | export const MobileHeader = ({ className }: { className?: string }) => { 8 | const { switchToNewThread } = useThreadListActions(); 9 | const { logoUrl, agentName, setIsSidebarOpen } = useShellStore((state) => ({ 10 | logoUrl: state.logoUrl, 11 | agentName: state.agentName, 12 | setIsSidebarOpen: state.setIsSidebarOpen, 13 | })); 14 | 15 | return ( 16 |
17 | } 20 | onClick={() => setIsSidebarOpen(true)} 21 | variant="secondary" 22 | /> 23 |
24 | Logo 25 | {agentName} 26 |
27 | } 30 | onClick={switchToNewThread} 31 | variant="secondary" 32 | /> 33 |
34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/NewChatButton.tsx: -------------------------------------------------------------------------------- 1 | import { useThreadListActions } from "@crayonai/react-core"; 2 | import clsx from "clsx"; 3 | import { Plus } from "lucide-react"; 4 | import { Button } from "../Button"; 5 | 6 | export const NewChatButton = ({ className }: { className?: string }) => { 7 | const { switchToNewThread } = useThreadListActions(); 8 | 9 | return ( 10 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/dependencies.ts: -------------------------------------------------------------------------------- 1 | import buttonDeps from "../Button/dependencies"; 2 | import iconButtonDeps from "../IconButton/dependencies"; 3 | 4 | const dependencies = ["Shell", ...iconButtonDeps, ...buttonDeps]; 5 | export default dependencies; 6 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Container"; 2 | export * from "./MobileHeader"; 3 | export * from "./NewChatButton"; 4 | export * from "./Sidebar"; 5 | export * from "./store"; 6 | export * from "./Thread"; 7 | export * from "./ThreadList"; 8 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/mobileHeader.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-shell-mobile-header { 4 | display: none; 5 | 6 | .crayon-shell-container--mobile & { 7 | display: flex; 8 | align-items: center; 9 | justify-content: space-between; 10 | padding: cssUtils.$spacing-m cssUtils.$spacing-l; 11 | background-color: cssUtils.$bg-container; 12 | } 13 | } 14 | 15 | .crayon-shell-mobile-header-logo-container { 16 | display: flex; 17 | align-items: center; 18 | gap: cssUtils.$spacing-m; 19 | @include cssUtils.typography(title, medium); 20 | } 21 | 22 | .crayon-shell-mobile-header-logo { 23 | width: 32px; 24 | height: 32px; 25 | border-radius: cssUtils.$rounded-m; 26 | } 27 | 28 | .crayon-shell-mobile-header-agent-name { 29 | @include cssUtils.typography(title, medium); 30 | color: cssUtils.$primary-text; 31 | } 32 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/shell.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | @use "./sidebar.scss"; 3 | @use "./threadlist.scss"; 4 | @use "./thread.scss"; 5 | @use "./mobileHeader.scss"; 6 | 7 | .crayon-shell-container { 8 | display: flex; 9 | position: relative; 10 | height: 100dvh; 11 | width: 100dvw; 12 | padding: cssUtils.$spacing-m; 13 | overflow: hidden; 14 | 15 | background: cssUtils.$chat-container-bg; 16 | box-sizing: border-box; 17 | & * { 18 | box-sizing: border-box; 19 | } 20 | 21 | &.crayon-shell-container--mobile { 22 | padding: 0; 23 | } 24 | } 25 | 26 | .crayon-shell-new-chat-button { 27 | width: 100%; 28 | justify-content: space-between; 29 | } 30 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Shell/stories/thesysdev_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thesysdev/crayon/91f43448537d79667aabaaefbcf6384f120b7ced/js/packages/react-ui/src/components/Shell/stories/thesysdev_logo.jpeg -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Slider/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Slider"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Slider/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Slider"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Steps/Steps.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext } from "react"; 2 | 3 | export interface StepsItemProps { 4 | title: React.ReactNode; 5 | details: React.ReactNode; 6 | number?: number; 7 | } 8 | 9 | export interface StepsProps { 10 | children: React.ReactNode; 11 | } 12 | 13 | const StepNumberContext = createContext(0); 14 | 15 | export const Steps: React.FC = ({ children }) => { 16 | return ( 17 |
18 |
19 | {React.Children.map(children, (child, index) => ( 20 | {child} 21 | ))} 22 |
23 |
24 | ); 25 | }; 26 | 27 | export const StepsItem: React.FC = ({ title, details, number }) => { 28 | const stepNumber = useContext(StepNumberContext); 29 | 30 | return ( 31 |
32 |
33 |
34 |
35 | {Number.isInteger(number) ? number : stepNumber} 36 |
37 |
38 |
39 |
40 |
41 | {title} 42 |
{details}
43 |
44 |
45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Steps/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Steps"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Steps/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Steps"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchGroup/SwitchGroup.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, ReactElement } from "react"; 3 | import { SwitchItemProps } from "../SwitchItem"; 4 | 5 | type SwitchGroupVariant = "clear" | "card" | "sunk"; 6 | export interface SwitchGroupProps { 7 | children: ReactElement | ReactElement[]; 8 | className?: string; 9 | style?: CSSProperties; 10 | variant?: SwitchGroupVariant; 11 | } 12 | 13 | const variants: Record = { 14 | clear: "crayon-switch-group-clear", 15 | card: "crayon-switch-group-card", 16 | sunk: "crayon-switch-group-sunk", 17 | }; 18 | 19 | const SwitchGroup = forwardRef((props, ref) => { 20 | const { children, className, style, variant = "clear" } = props; 21 | return ( 22 |
27 | {children} 28 |
29 | ); 30 | }); 31 | 32 | SwitchGroup.displayName = "SwitchGroup"; 33 | 34 | export { SwitchGroup }; 35 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchGroup/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["SwitchGroup"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchGroup/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./SwitchGroup"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchGroup/switchGroup.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-switch-group { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-direction: column; 7 | gap: cssUtils.$spacing-3xs; 8 | border: 1px solid; 9 | border-radius: cssUtils.$rounded-m; 10 | 11 | &-clear { 12 | border-color: transparent; 13 | background-color: transparent; 14 | padding: cssUtils.$spacing-0; 15 | } 16 | 17 | &-card { 18 | border-color: cssUtils.$stroke-default; 19 | padding: cssUtils.$spacing-l; 20 | } 21 | 22 | &-sunk { 23 | border-color: cssUtils.$stroke-default; 24 | background-color: cssUtils.$bg-sunk; 25 | padding: cssUtils.$spacing-l; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchItem/SwitchItem.tsx: -------------------------------------------------------------------------------- 1 | import * as Switch from "@radix-ui/react-switch"; 2 | import clsx from "clsx"; 3 | import { CSSProperties, forwardRef, ReactNode, useId } from "react"; 4 | 5 | interface SwitchItemProps { 6 | label?: ReactNode; 7 | className?: string; 8 | style?: CSSProperties; 9 | checked?: boolean; 10 | disabled?: boolean; 11 | defaultChecked?: boolean; 12 | required?: boolean; 13 | name?: string; 14 | value?: string; 15 | onChange?: (value: boolean) => void; 16 | } 17 | 18 | const SwitchItem = forwardRef((props, ref) => { 19 | const { label, onChange, className, disabled, required, ...rest } = props; 20 | const id = useId(); 21 | return ( 22 |
23 | 32 | 33 | 34 | {label && ( 35 | 38 | )} 39 |
40 | ); 41 | }); 42 | 43 | SwitchItem.displayName = "SwitchItem"; 44 | 45 | export { SwitchItem, type SwitchItemProps }; 46 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchItem/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["SwitchItem"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/SwitchItem/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./SwitchItem"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Table/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Table"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Table/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Table"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Table/table.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-table-container { 4 | position: relative; 5 | width: 100%; 6 | overflow: auto; 7 | } 8 | 9 | .crayon-table { 10 | @include cssUtils.typography(label, heavy); 11 | width: 100%; 12 | caption-side: bottom; 13 | border-collapse: collapse; 14 | } 15 | 16 | .crayon-table-body { 17 | & tr { 18 | &:hover { 19 | background-color: cssUtils.$bg-container-hover; 20 | } 21 | } 22 | } 23 | 24 | .crayon-table-footer { 25 | border-top: 1px solid cssUtils.$stroke-default; 26 | 27 | & > tr:last-child { 28 | border-bottom: 0; 29 | } 30 | } 31 | 32 | .crayon-table-cell, 33 | .crayon-table-head { 34 | padding: cssUtils.$spacing-m; 35 | color: cssUtils.$primary-text; 36 | } 37 | 38 | .crayon-table-head { 39 | border-bottom: 1px solid cssUtils.$stroke-default; 40 | & .crayon-table-head-label { 41 | @include cssUtils.typography(label, heavy); 42 | color: cssUtils.$secondary-text; 43 | display: inline-flex; 44 | flex-grow: 1; 45 | justify-content: left; 46 | } 47 | 48 | & .crayon-table-head-content { 49 | display: flex; 50 | align-items: center; 51 | gap: cssUtils.$spacing-2xs; 52 | } 53 | 54 | & .crayon-table-head-icon { 55 | display: flex; 56 | align-items: center; 57 | justify-content: center; 58 | color: cssUtils.$secondary-text; 59 | } 60 | } 61 | 62 | .crayon-table-caption { 63 | @include cssUtils.typography(label, heavy); 64 | color: cssUtils.$primary-text; 65 | margin-top: cssUtils.$spacing-m; 66 | } 67 | 68 | .crayon-table-row { 69 | border-bottom: 1px solid cssUtils.$stroke-default; 70 | 71 | &:last-child { 72 | border-bottom: 0; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tabs/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Tabs"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tabs/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Tabs"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tag/Tag.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, ReactNode } from "react"; 3 | 4 | export interface TagProps { 5 | className?: string; 6 | styles?: CSSProperties; 7 | icon?: ReactNode; 8 | text: ReactNode; 9 | } 10 | 11 | export const Tag = forwardRef((props, ref) => { 12 | return ( 13 |
14 | {props.icon && {props.icon}} 15 | {props.text} 16 |
17 | ); 18 | }); 19 | 20 | Tag.displayName = "Tag"; 21 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tag/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["Tag"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tag/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Tag"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tag/stories/Tag.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | import { User } from "lucide-react"; 3 | import { Tag } from "../Tag"; 4 | 5 | const meta: Meta = { 6 | title: "Components/Tag", 7 | component: Tag, 8 | parameters: { 9 | layout: "centered", 10 | docs: { 11 | description: { 12 | component: "```tsx\nimport { Tag } from '@crayon-ui/react-ui';\n```", 13 | }, 14 | }, 15 | }, 16 | argTypes: { 17 | text: { 18 | control: "text", 19 | description: "The text content of the tag", 20 | table: { 21 | category: "Content", 22 | type: { summary: "string" }, 23 | }, 24 | }, 25 | icon: { 26 | control: false, 27 | description: "The icon to display in the tag", 28 | table: { 29 | category: "Content", 30 | type: { summary: "ReactNode" }, 31 | }, 32 | }, 33 | className: { 34 | control: false, 35 | description: "Additional CSS class name for custom styling", 36 | table: { 37 | category: "Styling", 38 | type: { summary: "string" }, 39 | }, 40 | }, 41 | styles: { 42 | control: false, 43 | description: "Additional CSS styles for custom styling", 44 | table: { 45 | category: "Styling", 46 | type: { summary: "CSSProperties" }, 47 | }, 48 | }, 49 | }, 50 | tags: ["!dev", "!autodocs"], 51 | }; 52 | 53 | export default meta; 54 | type Story = StoryObj; 55 | 56 | // Basic Tag 57 | export const Default: Story = { 58 | args: { 59 | text: "User Tag", 60 | icon: , 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/Tag/tag.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-tag { 4 | box-sizing: border-box; 5 | display: flex; 6 | align-items: center; 7 | overflow: hidden; 8 | max-width: 100%; 9 | height: auto; 10 | border: 1px solid cssUtils.$stroke-default; 11 | border-radius: cssUtils.$rounded-s; 12 | padding: cssUtils.$spacing-2xs cssUtils.$spacing-s cssUtils.$spacing-2xs cssUtils.$spacing-2xs; 13 | background: cssUtils.$bg-elevated; 14 | color: cssUtils.$primary-text; 15 | @include cssUtils.typography(label, small); 16 | gap: cssUtils.$spacing-2xs; 17 | 18 | &-icon { 19 | display: flex; 20 | align-items: center; 21 | } 22 | 23 | &-text { 24 | overflow: hidden; 25 | white-space: nowrap; 26 | text-overflow: ellipsis; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TagBlock/TagBlock.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import { CSSProperties, forwardRef, ReactElement } from "react"; 3 | import { Tag } from "../Tag"; 4 | 5 | export interface TagBlockProps { 6 | children: ReactElement | ReactElement[]; 7 | styles?: CSSProperties; 8 | className?: string; 9 | } 10 | 11 | export const TagBlock = forwardRef((props, ref) => { 12 | return ( 13 |
14 | {props.children} 15 |
16 | ); 17 | }); 18 | 19 | TagBlock.displayName = "TagBlock"; 20 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TagBlock/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = ["TagBlock"]; 2 | export default dependencies; 3 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TagBlock/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./TagBlock"; 2 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TagBlock/stories/TagBlock.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | import { Heart, Star, User } from "lucide-react"; 3 | import { Tag } from "../../Tag"; 4 | import { TagBlock } from "../TagBlock"; 5 | 6 | const meta: Meta = { 7 | title: "Components/TagBlock", 8 | component: TagBlock, 9 | subcomponents: { 10 | Tag: Tag as any, 11 | }, 12 | parameters: { 13 | layout: "centered", 14 | docs: { 15 | description: { 16 | component: "```tsx\nimport { TagBlock, Tag } from '@crayon-ui/react-ui';\n```", 17 | }, 18 | }, 19 | }, 20 | argTypes: { 21 | children: { 22 | control: false, 23 | description: "Accepts Tag components as children", 24 | table: { 25 | category: "Content", 26 | type: { summary: "ReactElement | ReactElement[]" }, 27 | }, 28 | }, 29 | className: { 30 | control: false, 31 | description: "Additional CSS class name for custom styling", 32 | table: { 33 | category: "Styling", 34 | type: { summary: "string" }, 35 | }, 36 | }, 37 | styles: { 38 | control: false, 39 | description: "Additional CSS styles for custom styling", 40 | table: { 41 | category: "Styling", 42 | type: { summary: "CSSProperties" }, 43 | }, 44 | }, 45 | }, 46 | tags: ["!dev", "autodocs"], 47 | }; 48 | 49 | export default meta; 50 | type Story = StoryObj; 51 | 52 | export const Default: Story = { 53 | render: (args) => ( 54 | 55 | } text="User" /> 56 | } text="Star" /> 57 | } text="Heart" /> 58 | 59 | ), 60 | }; 61 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TagBlock/tagBlock.scss: -------------------------------------------------------------------------------- 1 | @use "../../cssUtils" as cssUtils; 2 | 3 | .crayon-tag-block { 4 | box-sizing: border-box; 5 | display: flex; 6 | flex-wrap: wrap; 7 | gap: cssUtils.$spacing-xs; 8 | max-width: 100%; 9 | } 10 | -------------------------------------------------------------------------------- /js/packages/react-ui/src/components/TextArea/TextArea.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import React, { forwardRef } from "react"; 3 | 4 | export interface TextAreaProps 5 | extends Omit, "size"> { 6 | className?: string; 7 | placeholder?: string; 8 | rows?: number; 9 | } 10 | 11 | const TextArea = forwardRef((props, ref) => { 12 | const { className, rows = 3, ...rest } = props; 13 | 14 | return ( 15 |