From 7ce26309fc61ef44ef1fe8ffadab1c641550bfc6 Mon Sep 17 00:00:00 2001 From: Colleen <32280146+ctoddy@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:00:57 -0400 Subject: [PATCH] feat(FocusRing): mvp for FocusRing component (#37) * feat(FocusRing): create component WIP * feat(FocusRing): creating ring logic, WIP * feat(FocusRing): mvp of focusRing component * fix(FocusRing): comment clean up * feat(FocusRing): updated docs and cleaned up code * feat(FocusRing): cleaned up docs * feat(FocusRing): updated exports * chore(FocusRing): clean up comments * feat(FocusRing): clean up docs update ref type --- .../FocusRing/FocusRing.stories.tsx | 102 ++++++++++++++++++ .../components/FocusRing/FocusRing.styles.ts | 48 +++++++++ .../solid/components/FocusRing/FocusRing.tsx | 38 +++++++ .../components/FocusRing/FocusRing.types.ts | 40 +++++++ packages/solid/components/FocusRing/index.ts | 21 ++++ .../components/FocusRing/setFocusRing.ts | 34 ++++++ packages/solid/index.ts | 7 ++ 7 files changed, 290 insertions(+) create mode 100644 packages/solid/components/FocusRing/FocusRing.stories.tsx create mode 100644 packages/solid/components/FocusRing/FocusRing.styles.ts create mode 100644 packages/solid/components/FocusRing/FocusRing.tsx create mode 100644 packages/solid/components/FocusRing/FocusRing.types.ts create mode 100644 packages/solid/components/FocusRing/index.ts create mode 100644 packages/solid/components/FocusRing/setFocusRing.ts diff --git a/packages/solid/components/FocusRing/FocusRing.stories.tsx b/packages/solid/components/FocusRing/FocusRing.stories.tsx new file mode 100644 index 00000000..e646dc31 --- /dev/null +++ b/packages/solid/components/FocusRing/FocusRing.stories.tsx @@ -0,0 +1,102 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import type { Meta, StoryObj } from 'storybook-solidjs'; +import FocusRing from './FocusRing.jsx'; + +type Story = StoryObj; + +/** + * Fancy ring to focus on Items. + * + * ## Usage + * These steps set up a FocusRing component and associates it with a reference. This reference is then used by the setFocusRing function and the focus manager to set the focus ring to the current activeElement. + * #### 1. Necessary imports: + * + * - `useFocusManager`: an Effect used to manage focus within the application. See more on `useFocusManager` [here](https://lightning-tv.github.io/solid/#/primitives/useFocusManager?id=usefocusmanager-for-key-handling). + * - `onMount`: This lifecyle is used to run code after the component has mounted. + * - `setFocusRing`: This function in the FocusRing package is used to set the FocusRing reference and position the component on the current `activeElement`. + * - `FocusRing` : The FocusRing itself. + * + * ```js + * import { onMount } from 'solid-js'; + * import { useFocusManager } from '@lightningtv/solid/primitives'; + * import { FocusRing, setFocusRing } from '@lightningtv/solid-ui'; + * ``` + * #### 2. Create a ref: + * Declare an empty variable that will be used to store a reference to the `FocusRing` component. For example `let focusRef;` + * + * #### 3. Use the focus manager: + * Use the focus manager (`useFocusManager();`) Effect to activate focus management. + * + * #### 4. Use the FocusRing reference after the components are rendered: + * This code runs after the component has mounted. It calls the `setFocusRing` function to position the FocusRing to the current `activeElement` using the ref variable. + * + * ```js + * onMount(() => { + * setFocusRing(focusRef); + * }); + * ``` + * #### 5. Render the FocusRing component and use the declared reference variable: + * This line renders the `FocusRing` component, passing `focusRef` as a prop. This allows the `setFocusRing` function to associate the FocusRing with the component instance. + * + * ```js + * + * ``` + * ## Example usage + * + * ```js + * import { View } from '@lightningtv/solid'; + * import { onMount } from 'solid-js'; + * import { useFocusManager } from '@lightningtv/solid/primitives'; + * import { Button, FocusRing, setFocusRing } from '@lightningtv/solid-ui'; + * + * const App = () => { + * let focusRef; // Declared reference variables + * useFocusManager(); // Effect that manages focus + * + * onMount(() => { // Function that runs after components are mounted + * setFocusRing(focusRef);// Sets rings location to the current focused element + * }); + * + * return ( + * + * // Passing the ref variable as a ref prop + * // Other components that receive focus + * + * + * + * ); + * }; + * + * export default App; + * ``` + */ + +const meta: Meta = { + title: 'Components/FocusRing', + component: FocusRing, + tags: ['autodocs'] +}; + +export default meta; + +export const Basic: Story = { + render: args => { + return ; + }, + args: {} +}; diff --git a/packages/solid/components/FocusRing/FocusRing.styles.ts b/packages/solid/components/FocusRing/FocusRing.styles.ts new file mode 100644 index 00000000..61a79480 --- /dev/null +++ b/packages/solid/components/FocusRing/FocusRing.styles.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import theme from 'theme'; +import { makeComponentStyles } from '../../utils/index.js'; +import type { FocusRingStyles, FocusRingConfig } from './FocusRing.types.js'; + +/* @ts-expect-error next-line themes are supplied by client applications so this setup is necessary */ +const { FocusRing: { defaultTone, ...themeStyles } = { themeStyles: {} } } = theme?.componentConfig; + +const container: FocusRingConfig = { + themeKeys: { + borderRadius: 'radius' + }, + base: { + x: 0, + y: 0, + borderRadius: theme.radius.lg, + border: { + color: theme.color.interactiveNeutralFocus, + width: theme.stroke.md + } + }, + themeStyles +}; + +const Container = makeComponentStyles(container); + +const styles: FocusRingStyles = { + tone: defaultTone || 'neutral', + Container +}; + +export default styles; diff --git a/packages/solid/components/FocusRing/FocusRing.tsx b/packages/solid/components/FocusRing/FocusRing.tsx new file mode 100644 index 00000000..829a5ec8 --- /dev/null +++ b/packages/solid/components/FocusRing/FocusRing.tsx @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { View } from '@lightningtv/solid'; +import { type Component } from 'solid-js'; +import type { FocusRingProps } from './FocusRing.types.js'; +import styles from './FocusRing.styles.js'; + +const FocusRing: Component = (props: FocusRingProps) => { + return ( + + ); +}; + +export default FocusRing; diff --git a/packages/solid/components/FocusRing/FocusRing.types.ts b/packages/solid/components/FocusRing/FocusRing.types.ts new file mode 100644 index 00000000..3d1249d2 --- /dev/null +++ b/packages/solid/components/FocusRing/FocusRing.types.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import type { UIComponentProps } from 'types/interfaces.js'; +import type { ComponentStyleConfig, NodeStyleSet, Tone } from 'types/types.js'; +import type { NodeStyles } from '@lightningtv/solid'; + +export interface FocusRingProps extends UIComponentProps { + /** + * placeholder for FocusRingProps + */ +} + +export interface FocusRingStyleProperties { + /** + * corner radius of input + */ + radius?: NodeStyles['borderRadius']; +} + +export interface FocusRingStyles { + tone: Tone; + Container: NodeStyleSet; +} + +export type FocusRingConfig = ComponentStyleConfig; diff --git a/packages/solid/components/FocusRing/index.ts b/packages/solid/components/FocusRing/index.ts new file mode 100644 index 00000000..c49869cb --- /dev/null +++ b/packages/solid/components/FocusRing/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +export { default as default } from './FocusRing.jsx'; +export { default as focusRingStyles } from './FocusRing.styles.js'; +export type { FocusRingProps, FocusRingStyles } from './FocusRing.types.js'; +export { setFocusRing } from './setFocusRing.js'; diff --git a/packages/solid/components/FocusRing/setFocusRing.ts b/packages/solid/components/FocusRing/setFocusRing.ts new file mode 100644 index 00000000..1dfe3a61 --- /dev/null +++ b/packages/solid/components/FocusRing/setFocusRing.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Comcast Cable Communications Management, LLC + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createEffect, on } from 'solid-js'; +import { activeElement, type SolidNode } from '@lightningtv/solid'; + +export const setFocusRing = (focusRingRef: SolidNode) => + createEffect( + on( + activeElement, + element => { + focusRingRef.parent = element.parent; + focusRingRef.x = element.x; + focusRingRef.y = element.y; + focusRingRef.width = element.width; + focusRingRef.height = element.height; + }, + { defer: true } + ) + ); diff --git a/packages/solid/index.ts b/packages/solid/index.ts index 3e104863..3d540039 100644 --- a/packages/solid/index.ts +++ b/packages/solid/index.ts @@ -42,6 +42,13 @@ export { type ColumnProps, type ColumnStyles } from './components/Column/index.js'; +export { + default as FocusRing, + focusRingStyles, + type FocusRingProps, + type FocusRingStyles, + setFocusRing +} from './components/FocusRing/index.js'; export { default as Icon, iconStyles, type IconProps, type IconStyles } from './components/Icon/index.js'; export { default as Input,