From 46bdcbe01aeb7309bb7616114310736af70317d8 Mon Sep 17 00:00:00 2001 From: Mariya Radchuk Date: Thu, 18 Jul 2024 12:17:21 +0200 Subject: [PATCH] feat(pie-checkbox-group): DSW-2182 main component functionality (#1581) * feat(pie-checkbox-group): DSW-2182 main component functionality * feat(pie-checkbox-group): DSW-2182 removes aria prop from checkbox and checkbox-group * feat(pie-checkbox-group): DSW-2182 enabling/disabling children + aria attr updates * feat(pie-checkbox-group): DSW-2182 pie-checkbox-group-disabled custom event * feat(pie-checkbox-group): DSW-2182 name attribute + connected and disconncted callbacks changes * feat(pie-checkbox-group): DSW-2182 removes aria prop from checkbox story * Update apps/pie-storybook/stories/pie-checkbox-group.stories.ts Co-authored-by: leksaBoiko <168754213+leksaBoiko@users.noreply.github.com> * Update packages/components/pie-checkbox-group/README.md Co-authored-by: Xander Marjoram * feat(pie-checkbox-group): DSW-2182 queryAssignedElements decorator --------- Co-authored-by: leksaBoiko <168754213+leksaBoiko@users.noreply.github.com> Co-authored-by: Xander Marjoram --- .changeset/dry-frogs-grin.md | 6 + .changeset/wicked-crews-serve.md | 6 + .../stories/pie-checkbox-group.stories.ts | 79 ++++++++- .../stories/pie-checkbox.stories.ts | 13 +- .../components/pie-checkbox-group/README.md | 49 +++++- .../pie-checkbox-group/package.json | 1 + .../pie-checkbox-group/src/defs-react.ts | 9 +- .../components/pie-checkbox-group/src/defs.ts | 47 +++++- .../pie-checkbox-group/src/index.ts | 94 ++++++++++- .../test/component/pie-checkbox-group.spec.ts | 154 ++++++++++++++++++ packages/components/pie-checkbox/README.md | 30 ++-- packages/components/pie-checkbox/src/defs.ts | 12 +- packages/components/pie-checkbox/src/index.ts | 48 +++--- yarn.lock | 30 ++-- 14 files changed, 472 insertions(+), 106 deletions(-) create mode 100644 .changeset/dry-frogs-grin.md create mode 100644 .changeset/wicked-crews-serve.md diff --git a/.changeset/dry-frogs-grin.md b/.changeset/dry-frogs-grin.md new file mode 100644 index 0000000000..5195069a1d --- /dev/null +++ b/.changeset/dry-frogs-grin.md @@ -0,0 +1,6 @@ +--- +"@justeattakeaway/pie-checkbox-group": minor +"pie-storybook": patch +--- + +[Added] - main logic for checkbox-group diff --git a/.changeset/wicked-crews-serve.md b/.changeset/wicked-crews-serve.md new file mode 100644 index 0000000000..f9f737e533 --- /dev/null +++ b/.changeset/wicked-crews-serve.md @@ -0,0 +1,6 @@ +--- +"@justeattakeaway/pie-checkbox": minor +--- + +[Added] - event listener for pie-checkbox-group-disabled custom event +[Removed] - aria prop since aria attributes should be passed to the component directly diff --git a/apps/pie-storybook/stories/pie-checkbox-group.stories.ts b/apps/pie-storybook/stories/pie-checkbox-group.stories.ts index 10f2132676..4d46b694eb 100644 --- a/apps/pie-storybook/stories/pie-checkbox-group.stories.ts +++ b/apps/pie-storybook/stories/pie-checkbox-group.stories.ts @@ -1,36 +1,97 @@ import { html } from 'lit'; - +import { ifDefined } from 'lit/directives/if-defined.js'; /* eslint-disable import/no-duplicates */ import '@justeattakeaway/pie-checkbox-group'; -import { CheckboxGroupProps } from '@justeattakeaway/pie-checkbox-group'; +import { CheckboxGroupProps, defaultProps, statusTypes } from '@justeattakeaway/pie-checkbox-group'; /* eslint-enable import/no-duplicates */ import { type StoryMeta } from '../types'; import { createStory } from '../utilities'; +import '@justeattakeaway/pie-link'; +import '@justeattakeaway/pie-checkbox'; + type CheckboxGroupStoryMeta = StoryMeta; -const defaultArgs: CheckboxGroupProps = {}; +const defaultArgs: CheckboxGroupProps = { + ...defaultProps, +}; const checkboxGroupStoryMeta: CheckboxGroupStoryMeta = { title: 'Checkbox Group', component: 'pie-checkbox-group', - argTypes: {}, + argTypes: { + name: { + description: 'The name associated with the group.', + control: 'text', + }, + label: { + description: 'The visible label for the checkbox group.', + control: 'text', + }, + status: { + description: 'The status of the checkbox group component / assistive text. Can be default, success or error.', + control: 'select', + options: statusTypes, + defaultValue: { + summary: defaultProps.status, + }, + }, + disabled: { + description: 'If true, disables the whole checkbox group. If you need to disable only one checkbox pass the disabled prop to the needed checkbox.', + control: 'boolean', + defaultValue: { + summary: defaultArgs.disabled, + }, + }, + assistiveText: { + description: 'An optional assistive text to display below the checkbox group.', + control: 'text', + defaultValue: { + summary: '', + }, + }, + }, args: defaultArgs, parameters: { design: { type: 'figma', - url: '', + url: 'https://www.figma.com/file/aD4m0j97Ruw8Q4S5lED2Bl/Checkbox-audit?node-id=9938-14138&t=1V1VEYmtArFih6AX-4', }, }, }; export default checkboxGroupStoryMeta; -// TODO: remove the eslint-disable rule when props are added -// eslint-disable-next-line no-empty-pattern -const Template = ({}: CheckboxGroupProps) => html` - +const Template = ({ + name, + label, + assistiveText, + status, + disabled, +}: CheckboxGroupProps) => html` +

Please note, the checkboxes are separate components. See + pie-checkbox.

+ + + + + + + + `; export const Default = createStory(Template, defaultArgs)(); diff --git a/apps/pie-storybook/stories/pie-checkbox.stories.ts b/apps/pie-storybook/stories/pie-checkbox.stories.ts index b745f02e3f..6d25ff131c 100644 --- a/apps/pie-storybook/stories/pie-checkbox.stories.ts +++ b/apps/pie-storybook/stories/pie-checkbox.stories.ts @@ -20,10 +20,6 @@ const defaultArgs: CheckboxProps = { disabled: false, indeterminate: false, required: false, - aria: { - label: '', - labelledby: '', - }, }; const checkboxStoryMeta: CheckboxStoryMeta = { @@ -91,10 +87,6 @@ const checkboxStoryMeta: CheckboxStoryMeta = { }, }, - aria: { - description: 'ARIA object to pass label/labelledby/describedby aria attributes', - control: 'object', - }, assistiveText: { description: 'An optional assistive text to display below the checkbox element. Must be provided when the status is success or error.', control: 'text', @@ -102,6 +94,7 @@ const checkboxStoryMeta: CheckboxStoryMeta = { summary: '', }, }, + status: { description: 'The status of the checkbox component / assistive text. Can be default, success or error.', control: 'select', @@ -131,7 +124,6 @@ const Template = ({ disabled, indeterminate, required, - aria, assistiveText, status, }: CheckboxProps) => { @@ -151,7 +143,6 @@ const Template = ({ ?disabled="${disabled}" ?indeterminate="${indeterminate}" ?required="${required}" - .aria="${aria}" @change="${onChange}" assistiveText="${ifDefined(assistiveText)}" status=${ifDefined(status)}> @@ -167,7 +158,6 @@ const ExampleFormTemplate: TemplateFunction = ({ disabled, indeterminate, required, - aria, assistiveText, status, }: CheckboxProps) => { @@ -188,7 +178,6 @@ const ExampleFormTemplate: TemplateFunction = ({ ?disabled="${disabled}" ?indeterminate="${indeterminate}" ?required="${required}" - .aria="${aria}" @change="${onChange}" assistiveText="${ifDefined(assistiveText)}" status=${ifDefined(status)}> diff --git a/packages/components/pie-checkbox-group/README.md b/packages/components/pie-checkbox-group/README.md index b56e3f1143..f1f9e571c3 100644 --- a/packages/components/pie-checkbox-group/README.md +++ b/packages/components/pie-checkbox-group/README.md @@ -21,6 +21,8 @@ `pie-checkbox-group` is a Web Component built using the Lit library. +It is a helper component that groups PieCheckbox components into a visual and functional group. + This component can be easily integrated into various frontend frameworks and customized through a set of properties. @@ -29,10 +31,9 @@ This component can be easily integrated into various frontend frameworks and cus To install `pie-checkbox-group` in your application, run the following on your command line: ```bash -# npm $ npm i @justeattakeaway/pie-checkbox-group - -# yarn +``` +```bash $ yarn add @justeattakeaway/pie-checkbox-group ``` @@ -74,18 +75,54 @@ import { PieCheckboxGroup } from '@justeattakeaway/pie-checkbox-group/dist/react | Property | Type | Default | Description | |---|---|---|---| -| - | - | - | - | +| `name` | string | - | The name associated with the group. | +| `label` | string | - | The label value of the component | +| `disabled` | boolean | - | Same as the HTML disabled attribute - indicates whether or not the checkbox group is disabled. | +| `assistiveText` | `string` | - | Allows assistive text to be displayed below the checkbox group. | +| `status` | `'default'`, `'error'`, `'success'` | `'default'` | The status of the checkbox group / assistive text. If you use `status` you must provide an `assistiveText` prop value for accessibility purposes. | + In your markup or JSX, you can then use these to set the properties for the `pie-checkbox-group` component: ```html - + + + + + + + + - + + + + + + + + ``` +## Events +| Event | Type | Description | +|-------|------|-------------| +| `pie-checkbox-group-disabled` | `CustomEvent` | Triggered after the disabled state of the checkbox group changes. | + ## Contributing Check out our [contributing guide](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide) for more information on [local development](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide#local-development) and how to run specific [component tests](https://github.com/justeattakeaway/pie/wiki/Contributing-Guide#testing). \ No newline at end of file diff --git a/packages/components/pie-checkbox-group/package.json b/packages/components/pie-checkbox-group/package.json index cae80b5055..e0814640a0 100644 --- a/packages/components/pie-checkbox-group/package.json +++ b/packages/components/pie-checkbox-group/package.json @@ -40,6 +40,7 @@ "cem-plugin-module-file-extensions": "0.0.5" }, "dependencies": { + "@justeattakeaway/pie-assistive-text": "0.5.1", "@justeattakeaway/pie-webc-core": "0.24.0" }, "volta": { diff --git a/packages/components/pie-checkbox-group/src/defs-react.ts b/packages/components/pie-checkbox-group/src/defs-react.ts index 97258f7d24..3f39c4cc6b 100644 --- a/packages/components/pie-checkbox-group/src/defs-react.ts +++ b/packages/components/pie-checkbox-group/src/defs-react.ts @@ -1,8 +1,3 @@ import React from 'react'; -/** - * TODO: Verify if ReactBaseType can be set as a more specific React interface - * Use the React IntrinsicElements interface to find how to map standard HTML elements to existing React Interfaces - * Example: an HTML button maps to `React.ButtonHTMLAttributes` - * https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0bb210867d16170c4a08d9ce5d132817651a0f80/types/react/index.d.ts#L2829 - */ -export type ReactBaseType = React.HTMLAttributes + +export type ReactBaseType = React.FieldsetHTMLAttributes diff --git a/packages/components/pie-checkbox-group/src/defs.ts b/packages/components/pie-checkbox-group/src/defs.ts index c5c14dd68e..90a9b7b329 100644 --- a/packages/components/pie-checkbox-group/src/defs.ts +++ b/packages/components/pie-checkbox-group/src/defs.ts @@ -1,3 +1,44 @@ -// TODO - please remove the eslint disable comment below when you add props to this interface -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface CheckboxGroupProps {} +import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core'; + +export const statusTypes = ['default', 'success', 'error'] as const; + +export interface CheckboxGroupProps { + /** + * The name associated with the group. + */ + name?: string; + + /** + * The label value of the component + */ + label?: string; + + /** + * An optional assistive text to display below the checkbox group. + */ + assistiveText?: string; + + /** + * Same as the HTML disabled attribute - indicates whether or not the checkbox group is disabled. + */ + disabled?: boolean; + + /** + * The status of the checkbox component / assistive text. Can be default, success or error. + */ + status?: typeof statusTypes[number]; +} + +/** + * Event name for when checkbox group becomes disabled. + * + * @constant + */ +export const ON_CHECKBOX_GROUP_DISABLED = 'pie-checkbox-group-disabled'; + +export type DefaultProps = ComponentDefaultProps; + +export const defaultProps: DefaultProps = { + status: 'default', + disabled: false, +}; diff --git a/packages/components/pie-checkbox-group/src/index.ts b/packages/components/pie-checkbox-group/src/index.ts index bbcc4f3fb9..9d302749c5 100644 --- a/packages/components/pie-checkbox-group/src/index.ts +++ b/packages/components/pie-checkbox-group/src/index.ts @@ -1,20 +1,102 @@ -import { LitElement, html, unsafeCSS } from 'lit'; -import { RtlMixin, defineCustomElement } from '@justeattakeaway/pie-webc-core'; - +import { + LitElement, html, unsafeCSS, PropertyValues, +} from 'lit'; +import { property, queryAssignedElements } from 'lit/decorators.js'; +import { + RtlMixin, + defineCustomElement, + FormControlMixin, + validPropertyValues, +} from '@justeattakeaway/pie-webc-core'; +import { ifDefined } from 'lit/directives/if-defined.js'; import styles from './checkbox-group.scss?inline'; -import { CheckboxGroupProps } from './defs'; +import { + ON_CHECKBOX_GROUP_DISABLED, + CheckboxGroupProps, + defaultProps, + statusTypes, +} from './defs'; +import '@justeattakeaway/pie-assistive-text'; // Valid values available to consumers export * from './defs'; const componentSelector = 'pie-checkbox-group'; +const assistiveTextId = 'assistive-text'; /** * @tagname pie-checkbox-group + * @event {CustomEvent} pie-checkbox-group-disabled - triggered after the disabled state of the checkbox group changes. */ -export class PieCheckboxGroup extends RtlMixin(LitElement) implements CheckboxGroupProps { +export class PieCheckboxGroup extends FormControlMixin(RtlMixin(LitElement)) implements CheckboxGroupProps { + @property({ type: String }) + public name?: CheckboxGroupProps['name']; + + @property({ type: String }) + public label?: CheckboxGroupProps['label']; + + @property({ type: String }) + public assistiveText?: CheckboxGroupProps['assistiveText']; + + @property({ type: String }) + @validPropertyValues(componentSelector, statusTypes, defaultProps.status) + public status = defaultProps.status; + + @property({ type: Boolean, reflect: true }) + public disabled = defaultProps.disabled; + + @queryAssignedElements({}) _slottedChildren!: Array; + + private _handleDisabled () : void { + if (this._slottedChildren) { + this._slottedChildren.forEach((child) => { + child.dispatchEvent(new CustomEvent(ON_CHECKBOX_GROUP_DISABLED, { bubbles: false, composed: false, detail: { disabled: this.disabled } })); + }); + } + } + + private _handleStatus () : void { + if (this._slottedChildren) { + this._slottedChildren.forEach((child) => child.setAttribute('status', this.status)); + } + } + + protected updated (_changedProperties: PropertyValues): void { + if (_changedProperties.has('disabled')) { + this._handleDisabled(); + } + + if (_changedProperties.has('status')) { + this._handleStatus(); + } + } + render () { - return html`

Hello world!

`; + const { + name, + label, + assistiveText, + status, + disabled, + } = this; + return html` +
+ ${label && html`${label}`} + +
+ ${assistiveText && html` + + ${assistiveText} + `} + `; } // Renders a `CSSResult` generated from SCSS by Vite diff --git a/packages/components/pie-checkbox-group/test/component/pie-checkbox-group.spec.ts b/packages/components/pie-checkbox-group/test/component/pie-checkbox-group.spec.ts index f813802be9..f7572a06dd 100644 --- a/packages/components/pie-checkbox-group/test/component/pie-checkbox-group.spec.ts +++ b/packages/components/pie-checkbox-group/test/component/pie-checkbox-group.spec.ts @@ -1,14 +1,35 @@ import { test, expect } from '@sand4rt/experimental-ct-web'; +import { PieAssistiveText } from '@justeattakeaway/pie-assistive-text'; +import { PieCheckbox } from '@justeattakeaway/pie-checkbox'; import { PieCheckboxGroup, CheckboxGroupProps } from '../../src/index.ts'; +import { statusTypes } from '../../src/defs.ts'; const componentSelector = '[data-test-id="pie-checkbox-group"]'; +const assistiveTextSelector = '[data-test-id="pie-checkbox-group-assistive-text"]'; +const checkboxSelector = '[data-test-id="checkbox-input"]'; test.describe('PieCheckboxGroup - Component tests', () => { + // IMPORTANT: Mounting and Unmounting the component before each test ensures that any tests that do not explicitly + // mount the component will still have it available in Playwright's cache (loaded and registered in the test browser) + test.beforeEach(async ({ mount }) => { + const component = await mount(PieCheckboxGroup); + await component.unmount(); + + const assistiveTextComponent = await mount(PieAssistiveText); + await assistiveTextComponent.unmount(); + + const CheckboxComponent = await mount(PieCheckbox); + await CheckboxComponent.unmount(); + }); + test('should render successfully', async ({ mount, page }) => { // Arrange await mount(PieCheckboxGroup, { props: {} as CheckboxGroupProps, + slots: { + default: '', + }, }); // Act @@ -17,4 +38,137 @@ test.describe('PieCheckboxGroup - Component tests', () => { // Assert expect(checkboxGroup).toBeVisible(); }); + + test.describe('assistiveText', () => { + test('should not render the assistive text component if the prop is not provided', async ({ mount, page }) => { + // Arrange + await mount(PieCheckboxGroup, {}); + + // Act + const assistiveText = page.locator(assistiveTextSelector); + + // Assert + expect(assistiveText).not.toBeVisible(); + }); + + test('should apply the "default" variant attribute if no status is provided', async ({ mount, page }) => { + // Arrange + await mount(PieCheckboxGroup, { + props: { + assistiveText: 'Assistive text', + } as PieCheckboxGroup, + }); + + // Act + const assistiveText = page.locator(assistiveTextSelector); + + // Assert + expect(assistiveText).toBeVisible(); + expect(await assistiveText.getAttribute('variant')).toBe('default'); + expect(assistiveText).toHaveText('Assistive text'); + }); + + test.describe('Assistive text: Status', () => { + statusTypes.forEach((status) => { + test(`should render the assistive text component with the ${status} variant`, async ({ mount, page }) => { + // Arrange + await mount(PieCheckboxGroup, { + props: { + assistiveText: 'Assistive text', + status, + } as PieCheckboxGroup, + }); + + // Act + const assistiveText = page.locator(assistiveTextSelector); + + // Assert + expect(assistiveText).toBeVisible(); + expect(assistiveText).toHaveAttribute('variant', status); + expect(assistiveText).toHaveText('Assistive text'); + }); + }); + }); + + test.describe('Assistive test ID attribute', () => { + test('should contain an ID associated with the checkbox group element for a11y', async ({ mount, page }) => { + // Arrange + const component = await mount(PieCheckboxGroup, { + props: { + assistiveText: 'Assistive text', + } as PieCheckboxGroup, + }); + + // Act + const checkboxGroup = component.locator(componentSelector); + const assistiveText = page.locator(assistiveTextSelector); + + const componentAttribute = await checkboxGroup.getAttribute('aria-describedby'); + + // Assert + await expect(assistiveText).toHaveAttribute('id', 'assistive-text'); + expect(componentAttribute).toBe('assistive-text'); + }); + }); + }); + + test.describe('Props', () => { + test.describe('disabled', () => { + test.describe('when true', () => { + test('should disable the slotted component', async ({ mount }) => { + // Arrange + const component = await mount(PieCheckboxGroup, { + props: { + disabled: true, + } as CheckboxGroupProps, + slots: { + default: '', + }, + }); + + // Act + const checkbox = component.locator(checkboxSelector); + + // Assert + expect(checkbox).toBeDisabled(); + }); + }); + test.describe('when false', () => { + test('the slotted checkbox component should not be disabled if checkbox itself is not disabled', async ({ mount }) => { + // Arrange + const component = await mount(PieCheckboxGroup, { + props: { + disabled: false, + } as CheckboxGroupProps, + slots: { + default: '', + }, + }); + + // Act + const checkbox = component.locator(checkboxSelector); + + // Assert + expect(checkbox).not.toBeDisabled(); + }); + test('the slotted checkbox component should be disabled if checkbox itself is disabled', async ({ mount }) => { + // Arrange + const component = await mount(PieCheckboxGroup, { + props: { + disabled: false, + } as CheckboxGroupProps, + slots: { + default: '', + }, + }); + + // Act + const checkbox = component.locator(checkboxSelector); + + // Assert + expect(checkbox).toBeDisabled(); + }); + }); + }); + }); }); diff --git a/packages/components/pie-checkbox/README.md b/packages/components/pie-checkbox/README.md index ac95f36c4e..611d22d104 100644 --- a/packages/components/pie-checkbox/README.md +++ b/packages/components/pie-checkbox/README.md @@ -30,9 +30,10 @@ This component can be easily integrated into various frontend frameworks and cus To install `pie-checkbox` in your application, run the following on your command line: ```bash -npm i @justeattakeaway/pie-checkbox - -yarn add @justeattakeaway/pie-checkbox +$ npm i @justeattakeaway/pie-checkbox +``` +```bash +$ yarn add @justeattakeaway/pie-checkbox ``` For full information on using PIE components as part of an application, check out the [Getting Started Guide](https://github.com/justeattakeaway/pie/wiki/Getting-started-with-PIE-Web-Components). @@ -71,18 +72,17 @@ import { PieCheckbox } from '@justeattakeaway/pie-checkbox/dist/react'; ## Props -| Property | Type | Default | Description | -|---|-------------------------------------|-----------|---| -| `name` | `string` | - | The name of the checkbox (used as a key/value pair with `value`). This is required in order to work properly with forms. | -| `value` | `string` | `'on'` | The value of the input (used as a key/value pair in HTML forms with `name`). If not passed falls back to the html default value "on". | -| `required` | `boolean` | `false` | If true, the checkbox is required to be checked before submitting the form. If it is not in checked state, the component validity state will be invalid. | -| `label` | `string` | `''` | Text associated with the checkbox. If there is no label to provide, make sure to pass label, labelledby or describedby to the aria property. | -| `disabled` | `boolean` | `false` | Indicates whether or not the checkbox is disabled. | -| `checked` | `boolean` | `false` | Controls whether or not the checkbox is checked. | -| `defaultChecked` | `boolean` | `false` | Sets the default checked state for the checkbox. This does not directly set the initial checked state when the page loads, use `checked` for that. If the checkbox is inside a form which is reset, the `checked` state will be updated to match `defaultChecked`. | -| `indeterminate` | `boolean` | `false` | Indicates whether the checkbox visually shows a horizontal line in the box instead of a check/tick. It has no impact on whether the checkbox's value is used in a form submission. That is decided by the checked state, regardless of the indeterminate state. | -| `aria` | `object` | {} | accepts `label`, `labeledby` and `describedby` keys with string values. | -| `assistiveText` | `string` | `''` | Allows assistive text to be displayed below the checkbox element. | +| Property | Type | Default | Description | +|---|---|---|---| +| `name` | `string` | - | The name of the checkbox (used as a key/value pair with `value`). This is required in order to work properly with forms. | +| `value` | `string` `'on'` | The value of the input (used as a key/value pair in HTML forms with `name`). If not passed falls back to the html default value "on". | +| `required` | `boolean` | `false` | If true, the checkbox is required to be checked before submitting the form. If it is not in checked state, the component validity state will be invalid. | +| `label` | `string` | `''` | Text associated with the checkbox. If there is no label to provide, make sure to pass aria-label, aria-labelledby or aria-describedby attributes instead. | +| `disabled` | `boolean` | `false` | Indicates whether or not the checkbox is disabled. | +| `checked` | `boolean` | `false` | Controls whether or not the checkbox is checked. | +| `defaultChecked` | `boolean` | `false` | Sets the default checked state for the checkbox. This does not directly set the initial checked state when the page loads, use `checked` for that. If the checkbox is inside a form which is reset, the `checked` state will be updated to match `defaultChecked`. | +| `indeterminate` | `boolean` | `false` | Indicates whether the checkbox visually shows a horizontal line in the box instead of a check/tick. It has no impact on whether the checkbox's value is used in a form submission. That is decided by the checked state, regardless of the indeterminate state. | +| `assistiveText` | `string` | - | Allows assistive text to be displayed below the checkbox element. | | `status` | `'default'`, `'error'`, `'success'` | `'default'` | The status of the checkbox component / assistive text. If you use `status` you must provide an `assistiveText` prop value for accessibility purposes. | In your markup or JSX, you can then use these to set the properties for the `pie-checkbox` component: diff --git a/packages/components/pie-checkbox/src/defs.ts b/packages/components/pie-checkbox/src/defs.ts index ca16f9bc1c..9d12830ac7 100644 --- a/packages/components/pie-checkbox/src/defs.ts +++ b/packages/components/pie-checkbox/src/defs.ts @@ -1,11 +1,6 @@ import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core'; export const statusTypes = ['default', 'success', 'error'] as const; - -export type AriaProps = { - label?: string; - labelledby?: string; -}; export interface CheckboxProps { /** * The value of the checkbox (used as a key/value pair in HTML forms with `name`). @@ -48,11 +43,6 @@ export interface CheckboxProps { */ required?: boolean; - /** - * Various ARIA attributes. - */ - aria?: AriaProps; - /** * An optional assistive text to display below the input element. Must be provided when the status is success or error. */ @@ -64,7 +54,7 @@ export interface CheckboxProps { status?: typeof statusTypes[number]; } -export type DefaultProps = ComponentDefaultProps>; +export type DefaultProps = ComponentDefaultProps>; export const defaultProps: DefaultProps = { // a default value for the html value attribute. diff --git a/packages/components/pie-checkbox/src/index.ts b/packages/components/pie-checkbox/src/index.ts index 2244bcc541..1ade8ef93b 100644 --- a/packages/components/pie-checkbox/src/index.ts +++ b/packages/components/pie-checkbox/src/index.ts @@ -1,7 +1,7 @@ import { LitElement, html, unsafeCSS, PropertyValues, nothing, } from 'lit'; -import { property, query } from 'lit/decorators.js'; +import { property, query, state } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { live } from 'lit/directives/live.js'; @@ -30,6 +30,9 @@ const assistiveTextIdValue = 'assistive-text'; export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implements CheckboxProps { static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }; + @state() + private disabledByParent = false; + @property({ type: String }) public value = defaultProps.value; @@ -46,7 +49,7 @@ export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implemen public defaultChecked = defaultProps.defaultChecked; @property({ type: Boolean, reflect: true }) - public disabled?: CheckboxProps['disabled']; + public disabled = defaultProps.disabled; @property({ type: Boolean, reflect: true }) public required = defaultProps.required; @@ -54,9 +57,6 @@ export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implemen @property({ type: Boolean, reflect: true }) public indeterminate = defaultProps.indeterminate; - @property({ type: Object }) - public aria: CheckboxProps['aria']; - @query('input[type="checkbox"]') private checkbox!: HTMLInputElement; @@ -67,6 +67,18 @@ export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implemen @validPropertyValues(componentSelector, statusTypes, defaultProps.status) public status = defaultProps.status; + connectedCallback () : void { + super.connectedCallback(); + + this.addEventListener('pie-checkbox-group-disabled', (e: CustomEventInit) => { this.disabledByParent = e.detail.disabled; }); + } + + disconnectedCallback () : void { + super.disconnectedCallback(); + + this.removeEventListener('pie-checkbox-group-disabled', (e: CustomEventInit) => { this.disabledByParent = e.detail.disabled; }); + } + /** * (Read-only) returns a ValidityState with the validity states that this element is in. * https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity @@ -95,15 +107,7 @@ export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implemen this.disabled = disabled; } - protected firstUpdated (_changedProperties: PropertyValues): void { - super.firstUpdated(_changedProperties); - - this.handleFormAssociation(); - } - - protected updated (_changedProperties: PropertyValues): void { - super.updated(_changedProperties); - + protected updated (): void { this.handleFormAssociation(); } @@ -147,18 +151,20 @@ export class PieCheckbox extends FormControlMixin(RtlMixin(LitElement)) implemen name, label, disabled, + disabledByParent, required, indeterminate, - aria, assistiveText, status, } = this; + const componentDisabled = disabled || disabledByParent; + return html`
${label} diff --git a/yarn.lock b/yarn.lock index 53ffd46965..089d1eb398 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15371,8 +15371,8 @@ __metadata: linkType: hard "cacache@npm:^18.0.0": - version: 18.0.3 - resolution: "cacache@npm:18.0.3" + version: 18.0.4 + resolution: "cacache@npm:18.0.4" dependencies: "@npmcli/fs": ^3.1.0 fs-minipass: ^3.0.0 @@ -15386,7 +15386,7 @@ __metadata: ssri: ^10.0.0 tar: ^6.1.11 unique-filename: ^3.0.0 - checksum: b717fd9b36e9c3279bfde4545c3a8f6d5a539b084ee26a9504d48f83694beb724057d26e090b97540f9cc62bea18b9f6cf671c50e18fb7dac60eda9db691714f + checksum: b7422c113b4ec750f33beeca0f426a0024c28e3172f332218f48f963e5b970647fa1ac05679fe5bb448832c51efea9fda4456b9a95c3a1af1105fe6c1833cde2 languageName: node linkType: hard @@ -18827,9 +18827,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.3.723, electron-to-chromium@npm:^1.4.284, electron-to-chromium@npm:^1.4.820": - version: 1.4.825 - resolution: "electron-to-chromium@npm:1.4.825" - checksum: e01e4cdca1ad3c912e03d9c8615f0d3869bc0f2d2621d8e1ba83f78f5e7cd1cffe801914f7c9d631aa3911752d83598a7d4f1827904b380db9b9d034d69d1ab5 + version: 1.4.827 + resolution: "electron-to-chromium@npm:1.4.827" + checksum: ce0b6b28d6555b4a1f0341331def5011d0f5c56542f95d114d5cedce218fb4a4415254494322ca40663ce9e9e5590623b0c0c09170838675d602367251bde677 languageName: node linkType: hard @@ -31516,12 +31516,12 @@ __metadata: linkType: hard "postcss-selector-parser@npm:^6.0.10, postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.13, postcss-selector-parser@npm:^6.0.15, postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9, postcss-selector-parser@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-selector-parser@npm:6.1.0" + version: 6.1.1 + resolution: "postcss-selector-parser@npm:6.1.1" dependencies: cssesc: ^3.0.0 util-deprecate: ^1.0.2 - checksum: 449f614e6706421be307d8638183c61ba45bc3b460fe3815df8971dbb4d59c4087181940d879daee4a7a2daf3d86e915db1cce0c006dd68ca75b4087079273bd + checksum: 1c6a5adfc3c19c6e1e7d94f8addb89a5166fcca72c41f11713043d381ecbe82ce66360c5524e904e17b54f7fc9e6a077994ff31238a456bc7320c3e02e88d92e languageName: node linkType: hard @@ -33979,15 +33979,15 @@ __metadata: linkType: hard "sass@npm:^1.49.7": - version: 1.77.7 - resolution: "sass@npm:1.77.7" + version: 1.77.8 + resolution: "sass@npm:1.77.8" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 64c98cbeb24fb42fb5f29137740a812747e0cfebc2f02b0b03108456930f2058b17b2cf78ddf3df3c958c4a6b6fef765e34a202e6e93670752970bf5a0dbe222 + checksum: 6b5dce17faa1bd1e349b4825bf7f76559a32f3f95d789cd2847623c88ee9635e1485d3458532a05fa5b9134cfbce79a4bad3f13dc63c2433632347674db0abae languageName: node linkType: hard @@ -39399,8 +39399,8 @@ __metadata: linkType: hard "webpack@npm:^5.64.4": - version: 5.92.1 - resolution: "webpack@npm:5.92.1" + version: 5.93.0 + resolution: "webpack@npm:5.93.0" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.5 @@ -39431,7 +39431,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 11bec781260c4180883e98a4a15a08df297aca654ded45e70598f688881dd722f992d680addafe6f6342debede345cddcce2b781c50f5cde29d6c0bc33a82452 + checksum: c93bd73d9e1ab49b07e139582187f1c3760ee2cf0163b6288fab2ae210e39e59240a26284e7e5d29bec851255ef4b43c51642c882fa5a94e16ce7cb906deeb47 languageName: node linkType: hard