diff --git a/apps/demo-react/src/App.tsx b/apps/demo-react/src/App.tsx index 19bbacbd..4dfac321 100644 --- a/apps/demo-react/src/App.tsx +++ b/apps/demo-react/src/App.tsx @@ -1,23 +1,77 @@ +import React from 'react' +import { OramaChatBox, OramaSearchBox, OramaButton } from '@orama/react-components' import './App.css' -import { defineCustomElements, OramaChatBox } from '@orama/react-components' - -void defineCustomElements() function App() { + const [open, setOpen] = React.useState(false) return ( <>

App React

+

+ Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem + aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. + Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni + dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor + sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore + magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis + suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in + ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas + nulla pariatur? +

+
+

ChatBox in a section

+
+ +
+
+

Another section

+ { + setOpen(true) + }} + > + Open searchbox + +

+ At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti + atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique + sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum + facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil + impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor + repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et + voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, + ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. +

+

+ At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti + atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique + sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum + facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil + impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor + repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et + voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, + ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. +

-

ChatBox

- { + setOpen(false) + }} index={{ - api_key: 'yl2JSnjLNBV6FVfUWEyadpjFr6KzPiDR', - endpoint: 'https://cloud.orama.run/v1/indexes/recipes-m7w9mm', + api_key: 'LerNlbp6379jVKaPs4wt2nZT4MJZbU1J', + endpoint: 'https://cloud.orama.run/v1/indexes/docs-orama-b3f5xd', }} />
diff --git a/apps/storybook/.storybook/preview.ts b/apps/storybook/.storybook/preview.ts index 5c74a95b..cd22ac40 100644 --- a/apps/storybook/.storybook/preview.ts +++ b/apps/storybook/.storybook/preview.ts @@ -1,10 +1,7 @@ -// import { defineCustomElements } from '@orama/wc-components/loader' import '@orama/wc-components/dist/orama-ui/orama-ui.css' import { html } from 'lit-html' import { DARK_THEME_BG, LIGTH_THEME_BG } from '../constants' -// defineCustomElements() - const preview = { decorators: [ (story, context) => { diff --git a/apps/storybook/package.json b/apps/storybook/package.json index 18d01311..30fced96 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -11,8 +11,9 @@ "storybook-test": "storybook build && clear && concurrently -k -s first -n 'Server,Test' -c 'magenta,blue' --hide 'Server' 'http-server ./storybook-static --port 6006 --silent' 'wait-on http-get://127.0.0.1:6006 && test-storybook --no-cache --verbose --'" }, "dependencies": { - "@storybook/web-components": "^8.2.3", - "@orama/wc-components": "workspace:*" + "@orama/wc-components": "workspace:*", + "@storybook/preview-api": "^8.2.9", + "@storybook/web-components": "^8.2.3" }, "devDependencies": { "@chromatic-com/storybook": "^1.6.1", diff --git a/apps/storybook/stories/config.ts b/apps/storybook/stories/config.ts index 6857de52..2f965c96 100644 --- a/apps/storybook/stories/config.ts +++ b/apps/storybook/stories/config.ts @@ -4,6 +4,7 @@ export type DemoIndexConfig = Record const demoIndexes: DemoIndexConfig = { orama: { + open: true, index: { api_key: 'LerNlbp6379jVKaPs4wt2nZT4MJZbU1J', endpoint: 'https://cloud.orama.run/v1/indexes/docs-orama-b3f5xd', @@ -39,6 +40,7 @@ const demoIndexes: DemoIndexConfig = { }, }, recipes: { + open: true, index: { api_key: 'yl2JSnjLNBV6FVfUWEyadpjFr6KzPiDR', endpoint: 'https://cloud.orama.run/v1/indexes/recipes-m7w9mm', @@ -70,6 +72,7 @@ const demoIndexes: DemoIndexConfig = { }, }, videogames: { + open: true, index: { api_key: 'WL7pKdEqCTPf3G2412x8ecneqVbnkklr', endpoint: 'https://cloud.orama.foo/v1/indexes/videogames-rk139h', diff --git a/apps/storybook/stories/docs/frameworks/React.mdx b/apps/storybook/stories/docs/frameworks/React.mdx index abaedd35..9c6077c9 100644 --- a/apps/storybook/stories/docs/frameworks/React.mdx +++ b/apps/storybook/stories/docs/frameworks/React.mdx @@ -16,16 +16,7 @@ npm install @orama/react-components You can use pnpm or yarn if you prefer. ## Usage - -In your `App.tsx` file, import the component definition and use it in your JSX: - -```tsx -import { defineCustomElements } from '@orama/react-components' - -void defineCustomElements() -``` - -You can then import and use the components you need in your project: +You can just import and use the components you need in your project. ```tsx import { OramaChatBox } from '@orama/react-components' diff --git a/apps/storybook/stories/public/orama-search-button.stories.tsx b/apps/storybook/stories/public/orama-search-button.stories.tsx index e70de486..70595df1 100644 --- a/apps/storybook/stories/public/orama-search-button.stories.tsx +++ b/apps/storybook/stories/public/orama-search-button.stories.tsx @@ -1,22 +1,71 @@ import type { StoryObj, Meta } from '@storybook/web-components' import type { Components } from '@orama/wc-components' +import { useArgs } from '@storybook/preview-api' import demoIndexes from '../config' import { html } from 'lit-html' -const meta: Meta = { +const meta: Meta< + Components.OramaSearchButton & { + openSearchbox: boolean + } +> = { title: 'Components/SearchButton', component: 'orama-search-button', + argTypes: { + colorScheme: { + options: ['light', 'dark', 'system'], + table: { + defaultValue: { summary: 'dark' }, + }, + control: { type: 'radio' }, + }, + themeConfig: { + table: { + type: { + summary: 'Partial', + }, + }, + }, + openSearchbox: { + table: { + defaultValue: { summary: 'false' }, + type: { + summary: 'boolean', + }, + }, + control: { type: 'boolean' }, + }, + }, } satisfies Meta export default meta type Story = StoryObj const Template = (label: string) => (args) => { + const [{ openSearchbox }, updateArgs] = useArgs() + + window.addEventListener('searchboxClosed', () => { + updateArgs({ openSearchbox: false }) + }) + return html` -
- ${label} +
+
+ { + updateArgs({ openSearchbox: !openSearchbox }) + }} + > + ${label} + +
(args) => { export const SearchButton: Story = { render: Template('Search...'), - args: {}, } diff --git a/packages/ui-stencil-react/src/components/stencil-generated/index.ts b/packages/ui-stencil-react/src/components/stencil-generated/index.ts index a88c3583..9546e541 100644 --- a/packages/ui-stencil-react/src/components/stencil-generated/index.ts +++ b/packages/ui-stencil-react/src/components/stencil-generated/index.ts @@ -5,8 +5,9 @@ import { createReactComponent } from './react-component-lib'; import type { JSX } from '@orama/wc-components'; +import { defineCustomElements } from '@orama/wc-components/loader'; - +defineCustomElements(); export const OramaButton = /*@__PURE__*/createReactComponent('orama-button'); export const OramaChat = /*@__PURE__*/createReactComponent('orama-chat'); export const OramaChatAssistentMessage = /*@__PURE__*/createReactComponent('orama-chat-assistent-message'); diff --git a/packages/ui-stencil-vue/lib/components.ts b/packages/ui-stencil-vue/lib/components.ts index 771e2624..9f848cc2 100644 --- a/packages/ui-stencil-vue/lib/components.ts +++ b/packages/ui-stencil-vue/lib/components.ts @@ -111,7 +111,9 @@ export const OramaMarkdown = /*@__PURE__*/ defineContainer('o export const OramaModal = /*@__PURE__*/ defineContainer('orama-modal', undefined, [ 'open', 'closeOnEscape', - 'mainTitle' + 'closeOnOutsideClick', + 'mainTitle', + 'modalStatusChanged' ]); @@ -138,11 +140,14 @@ export const OramaSearchBox = /*@__PURE__*/ defineContainer( 'sourceBaseUrl', 'sourcesMap', 'placeholder', - 'suggestions' + 'suggestions', + 'searchParams', + 'searchboxClosed' ]); export const OramaSearchButton = /*@__PURE__*/ defineContainer('orama-search-button', undefined, [ + 'themeConfig', 'colorScheme' ]); diff --git a/packages/ui-stencil/package.json b/packages/ui-stencil/package.json index a9848bb9..e8d07669 100644 --- a/packages/ui-stencil/package.json +++ b/packages/ui-stencil/package.json @@ -9,7 +9,10 @@ }, "main": "dist/index.cjs.js", "module": "dist/index.js", - "files": ["dist/", "loader/"], + "files": [ + "dist/", + "loader/" + ], "scripts": { "build": "stencil build --docs", "clean": "rm -rf node_modules .turbo dist .stencil loader www", @@ -21,6 +24,7 @@ }, "types": "dist/types/index.d.ts", "dependencies": { + "@orama/orama": "^2.0.23", "@oramacloud/client": "1.3.10", "@phosphor-icons/webcomponents": "^2.1.5", "@stencil/core": "^4.19.0", diff --git a/packages/ui-stencil/src/components.d.ts b/packages/ui-stencil/src/components.d.ts index 5ea32266..123fdd38 100644 --- a/packages/ui-stencil/src/components.d.ts +++ b/packages/ui-stencil/src/components.d.ts @@ -10,7 +10,11 @@ import { CloudIndexConfig, ColorScheme, ResultMap, SearchResult, SearchResultByS import { TChatInteraction } from "./context/chatContext"; import { Facet } from "./components/internal/orama-facets/orama-facets"; import { InputProps } from "./components/internal/orama-input/orama-input"; +import { ModalStatus } from "./components/internal/orama-modal/orama-modal"; import { TThemeOverrides } from "./config/theme"; +import { AnyOrama, Orama, SearchParams } from "@orama/orama"; +import { OramaClient } from "@oramacloud/client"; +import { TThemeOverrides as TThemeOverrides1 } from "./components.d"; import { SearchResultsProps } from "./components/internal/orama-search-results/orama-search-results"; import { TextProps } from "./components/internal/orama-text/orama-text"; export { ButtonProps } from "./components/internal/orama-button/orama-button"; @@ -18,7 +22,11 @@ export { CloudIndexConfig, ColorScheme, ResultMap, SearchResult, SearchResultByS export { TChatInteraction } from "./context/chatContext"; export { Facet } from "./components/internal/orama-facets/orama-facets"; export { InputProps } from "./components/internal/orama-input/orama-input"; +export { ModalStatus } from "./components/internal/orama-modal/orama-modal"; export { TThemeOverrides } from "./config/theme"; +export { AnyOrama, Orama, SearchParams } from "@orama/orama"; +export { OramaClient } from "@oramacloud/client"; +export { TThemeOverrides as TThemeOverrides1 } from "./components.d"; export { SearchResultsProps } from "./components/internal/orama-search-results/orama-search-results"; export { TextProps } from "./components/internal/orama-text/orama-text"; export namespace Components { @@ -96,6 +104,7 @@ export namespace Components { } interface OramaModal { "closeOnEscape": boolean; + "closeOnOutsideClick": boolean; "mainTitle": string; "open": boolean; } @@ -115,13 +124,15 @@ export namespace Components { "open": boolean; "placeholder"?: string; "resultMap"?: Partial; + "searchParams"?: SearchParams>; "sourceBaseUrl"?: string; "sourcesMap"?: SourcesMap; "suggestions"?: string[]; "themeConfig"?: Partial; } interface OramaSearchButton { - "colorScheme": ColorScheme; + "colorScheme"?: ColorScheme; + "themeConfig"?: Partial; } interface OramaSearchResults { "error": boolean; @@ -178,6 +189,14 @@ export interface OramaInputCustomEvent extends CustomEvent { detail: T; target: HTMLOramaInputElement; } +export interface OramaModalCustomEvent extends CustomEvent { + detail: T; + target: HTMLOramaModalElement; +} +export interface OramaSearchBoxCustomEvent extends CustomEvent { + detail: T; + target: HTMLOramaSearchBoxElement; +} export interface OramaSearchResultsCustomEvent extends CustomEvent { detail: T; target: HTMLOramaSearchResultsElement; @@ -278,7 +297,18 @@ declare global { prototype: HTMLOramaMarkdownElement; new (): HTMLOramaMarkdownElement; }; + interface HTMLOramaModalElementEventMap { + "modalStatusChanged": ModalStatus; + } interface HTMLOramaModalElement extends Components.OramaModal, HTMLStencilElement { + addEventListener(type: K, listener: (this: HTMLOramaModalElement, ev: OramaModalCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOramaModalElement, ev: OramaModalCustomEvent) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } var HTMLOramaModalElement: { prototype: HTMLOramaModalElement; @@ -296,7 +326,20 @@ declare global { prototype: HTMLOramaSearchElement; new (): HTMLOramaSearchElement; }; + interface HTMLOramaSearchBoxElementEventMap { + "searchboxClosed": { + id: HTMLElement + }; + } interface HTMLOramaSearchBoxElement extends Components.OramaSearchBox, HTMLStencilElement { + addEventListener(type: K, listener: (this: HTMLOramaSearchBoxElement, ev: OramaSearchBoxCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; + addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLOramaSearchBoxElement, ev: OramaSearchBoxCustomEvent) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } var HTMLOramaSearchBoxElement: { prototype: HTMLOramaSearchBoxElement; @@ -452,7 +495,9 @@ declare namespace LocalJSX { } interface OramaModal { "closeOnEscape"?: boolean; + "closeOnOutsideClick"?: boolean; "mainTitle"?: string; + "onModalStatusChanged"?: (event: OramaModalCustomEvent) => void; "open"?: boolean; } interface OramaNavigationBar { @@ -468,9 +513,13 @@ declare namespace LocalJSX { "colorScheme"?: ColorScheme; "facetProperty"?: string; "index"?: CloudIndexConfig; + "onSearchboxClosed"?: (event: OramaSearchBoxCustomEvent<{ + id: HTMLElement + }>) => void; "open"?: boolean; "placeholder"?: string; "resultMap"?: Partial; + "searchParams"?: SearchParams>; "sourceBaseUrl"?: string; "sourcesMap"?: SourcesMap; "suggestions"?: string[]; @@ -478,6 +527,7 @@ declare namespace LocalJSX { } interface OramaSearchButton { "colorScheme"?: ColorScheme; + "themeConfig"?: Partial; } interface OramaSearchResults { "error"?: boolean; diff --git a/packages/ui-stencil/src/components/internal/orama-button/orama-button.scss b/packages/ui-stencil/src/components/internal/orama-button/orama-button.scss index 4e00395e..bc29579f 100644 --- a/packages/ui-stencil/src/components/internal/orama-button/orama-button.scss +++ b/packages/ui-stencil/src/components/internal/orama-button/orama-button.scss @@ -1,7 +1,7 @@ // TODO: We need to revisit this styles. There are some duplications and variables without fallback .button { position: relative; - display: inline-flex; + display: flex; gap: var(--spacing-s, $spacing-s); align-items: center; border-radius: var(--radius-m, $radius-m); @@ -11,6 +11,8 @@ font-family: var(--font-primary, font('primary')); transition: all 0.2s; transition-property: color, background-color, opacity; + width: 100%; + text-align: left; &__tooltip { display: block; @@ -27,6 +29,13 @@ } } +.button__label { + display: flex; + align-items: center; + gap: var(--spacing-xs, $spacing-xs); + flex-grow: 1; +} + .button--primary { background-color: var(--button-background-color-primary, button-background-color('primary')); color: var(--button-text-color-primary, button-text-color('primary')); @@ -41,6 +50,18 @@ background-color: var(--button-background-color-secondary, button-background-color('secondary')); color: var(--button-text-color-secondary, button-text-color('secondary')); border: 1px solid var(--button-border-color-secondary, map-get($palette, 'button-border', 'secondary')); + transition: all 0.3s; + + @media (hover: hover) { + &:hover { + background-color: var(--button-background-color-secondary-hover, button-background-color('secondary-hover')); + } + } + + &:focus-visible { + outline: none; + border: 1px solid #9671b0; + } &:disabled { background-color: var(--background-color-tertiary, background-color('tertiary')); @@ -75,6 +96,11 @@ align-items: center; } +::slotted([slot='adorment-end']), +::slotted([slot='adorment-start']) { + flex-grow: 0; +} + @keyframes fadeInOut { 0% { opacity: 0; diff --git a/packages/ui-stencil/src/components/internal/orama-button/orama-button.tsx b/packages/ui-stencil/src/components/internal/orama-button/orama-button.tsx index 003fc28b..41e1ab8c 100644 --- a/packages/ui-stencil/src/components/internal/orama-button/orama-button.tsx +++ b/packages/ui-stencil/src/components/internal/orama-button/orama-button.tsx @@ -51,9 +51,11 @@ export class OramaButton { return ( - - {this.withTooltip && {this.withTooltip}} - + + + {this.withTooltip && {this.withTooltip}} + + ) diff --git a/packages/ui-stencil/src/components/internal/orama-chat/orama-chat.tsx b/packages/ui-stencil/src/components/internal/orama-chat/orama-chat.tsx index ef95739d..9d2017e6 100644 --- a/packages/ui-stencil/src/components/internal/orama-chat/orama-chat.tsx +++ b/packages/ui-stencil/src/components/internal/orama-chat/orama-chat.tsx @@ -43,7 +43,7 @@ export class OramaChat { handleFocus = () => { if (this.focusInput) { - this.textareaRef.focus() + this.textareaRef?.focus() } } diff --git a/packages/ui-stencil/src/components/internal/orama-input/orama-input.scss b/packages/ui-stencil/src/components/internal/orama-input/orama-input.scss index 12090137..1935a737 100644 --- a/packages/ui-stencil/src/components/internal/orama-input/orama-input.scss +++ b/packages/ui-stencil/src/components/internal/orama-input/orama-input.scss @@ -24,6 +24,8 @@ @media (--md-min) { padding-left: var(--spacing-3xl, $spacing-3xl); background: var(--background-color-primary, background-color('primary')); + border: 0; + border-bottom: 1px solid var(--border-color-primary, border-color('primary')); } } diff --git a/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.scss b/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.scss index f90ff67d..982e2d6e 100644 --- a/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.scss +++ b/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.scss @@ -6,6 +6,7 @@ height: 100%; background-color: var(--backdrop-background-color-primary, palette('backdrop-background', 'primary')); display: none; + z-index: 9999; &.open { display: block; @@ -17,7 +18,6 @@ background-color: var(--background-color-primary, background-color('primary')); position: fixed; inset: 0; - z-index: 9999; flex-direction: column; justify-content: space-between; diff --git a/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.tsx b/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.tsx index 8424a9a2..7f403a47 100644 --- a/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.tsx +++ b/packages/ui-stencil/src/components/internal/orama-modal/orama-modal.tsx @@ -1,15 +1,25 @@ -import { Component, h, Prop, State, Listen, Element } from '@stencil/core' +import { Component, h, Prop, State, Listen, Element, Event, type EventEmitter, Watch } from '@stencil/core' +export type ModalStatus = { + open: boolean + id: HTMLElement +} @Component({ tag: 'orama-modal', styleUrl: 'orama-modal.scss', scoped: true, }) export class OramaModal { - @Prop({ mutable: true }) open = false + @Prop() open = false @Prop() closeOnEscape = true + @Prop() closeOnOutsideClick = true @Prop() mainTitle = '' + @State() activeElement: HTMLElement + @State() modalIsOpen = this.open + + @Event() modalStatusChanged: EventEmitter + @Element() el: HTMLElement private firstFocusableElement: HTMLElement @@ -18,7 +28,7 @@ export class OramaModal { @Listen('keydown', { target: 'document' }) handleKeyDown(ev: KeyboardEvent) { - if (this.open) { + if (this.modalIsOpen) { switch (ev.key) { case 'Tab': this.trapFocus(ev) @@ -40,6 +50,19 @@ export class OramaModal { } } + @Watch('modalIsOpen') + handleOpenChange(newValue: boolean) { + this.modalStatusChanged.emit({ + open: newValue, + id: this.el, + }) + } + + @Watch('open') + handleOpenPropChange(newValue: boolean) { + this.modalIsOpen = newValue + } + private trapFocus(event: KeyboardEvent) { const focusableElements = this.el.querySelectorAll( 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])', @@ -78,11 +101,11 @@ export class OramaModal { } private closeModal() { - this.open = false + this.modalIsOpen = false } componentDidLoad() { - if (this.open) { + if (this.modalIsOpen) { this.activeElement = document.activeElement as HTMLElement this.handleFocus() } @@ -96,7 +119,7 @@ export class OramaModal { } componentDidUpdate() { - if (this.open) { + if (this.modalIsOpen) { this.handleFocus() } else if (this.activeElement) { this.activeElement.focus() @@ -106,6 +129,9 @@ export class OramaModal { handleArrowNavigation(event: KeyboardEvent) { if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return + event.stopPropagation() + event.preventDefault() + const focusableElements = this.el?.querySelectorAll( 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])', ) @@ -134,7 +160,7 @@ export class OramaModal { render() { return (