From f8dca5d1a8055341b3e6a4f32d26e0083d2115a5 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Wed, 4 Jun 2025 08:09:14 -0400 Subject: [PATCH] refactor styles and simplify custom states (#1016) --- .../plop/templates/component/component.hbs | 2 +- .../animated-image/animated-image.ts | 2 +- .../src/components/animation/animation.ts | 2 +- .../src/components/avatar/avatar.ts | 2 +- .../webawesome/src/components/badge/badge.ts | 2 +- .../breadcrumb-item/breadcrumb-item.ts | 2 +- .../src/components/breadcrumb/breadcrumb.ts | 2 +- .../components/button-group/button-group.ts | 2 +- .../src/components/button/button.ts | 2 +- .../src/components/callout/callout.ts | 2 +- .../webawesome/src/components/card/card.ts | 2 +- .../components/carousel-item/carousel-item.ts | 2 +- .../src/components/carousel/carousel.ts | 2 +- .../src/components/checkbox/checkbox.test.ts | 24 ++-- .../src/components/checkbox/checkbox.ts | 8 +- .../color-picker/color-picker.test.ts | 32 ++--- .../components/color-picker/color-picker.ts | 2 +- .../src/components/comparison/comparison.ts | 6 +- .../src/components/copy-button/copy-button.ts | 2 +- .../src/components/details/details.ts | 2 +- .../src/components/dialog/dialog.ts | 2 +- .../src/components/divider/divider.ts | 2 +- .../src/components/drawer/drawer.ts | 2 +- .../src/components/dropdown/dropdown.ts | 2 +- .../src/components/icon-button/icon-button.ts | 2 +- .../webawesome/src/components/icon/icon.ts | 2 +- .../src/components/include/include.ts | 2 +- .../src/components/input/input.test.ts | 56 ++++----- .../webawesome/src/components/input/input.ts | 4 +- .../src/components/menu-item/menu-item.ts | 6 +- .../src/components/menu-label/menu-label.ts | 2 +- .../webawesome/src/components/menu/menu.ts | 2 +- .../mutation-observer/mutation-observer.ts | 2 +- .../src/components/option/option.ts | 10 +- .../webawesome/src/components/page/page.ts | 2 +- .../src/components/popover/popover.ts | 11 +- .../webawesome/src/components/popup/popup.ts | 2 +- .../components/progress-bar/progress-bar.ts | 2 +- .../components/progress-ring/progress-ring.ts | 2 +- .../src/components/qr-code/qr-code.ts | 2 +- .../radio-group/radio-group.test.ts | 44 +++---- .../src/components/radio-group/radio-group.ts | 2 +- .../webawesome/src/components/radio/radio.ts | 6 +- .../src/components/rating/rating.ts | 2 +- .../resize-observer/resize-observer.ts | 2 +- .../src/components/scroller/scroller.ts | 2 +- .../src/components/select/select.test.ts | 44 +++---- .../src/components/select/select.ts | 4 +- .../src/components/skeleton/skeleton.ts | 2 +- .../src/components/slider/slider.test.ts | 20 +-- .../src/components/slider/slider.ts | 2 +- .../src/components/spinner/spinner.ts | 2 +- .../src/components/split-panel/split-panel.ts | 2 +- .../src/components/switch/switch.test.ts | 12 +- .../src/components/switch/switch.ts | 4 +- .../src/components/tab-group/tab-group.ts | 2 +- .../src/components/tab-panel/tab-panel.ts | 2 +- packages/webawesome/src/components/tab/tab.ts | 2 +- packages/webawesome/src/components/tag/tag.ts | 2 +- .../src/components/textarea/textarea.test.ts | 56 ++++----- .../src/components/textarea/textarea.ts | 4 +- .../src/components/tooltip/tooltip.ts | 2 +- .../components/tree-item/tree-item.test.ts | 4 +- .../src/components/tree-item/tree-item.ts | 10 +- .../webawesome/src/components/tree/tree.ts | 2 +- .../components/viewport-demo/viewport-demo.ts | 2 +- .../internal/test/form-control-base-tests.ts | 12 +- .../src/internal/webawesome-element.ts | 118 +++++++----------- .../webawesome-form-associated-element.ts | 14 +-- 69 files changed, 291 insertions(+), 310 deletions(-) diff --git a/packages/webawesome/scripts/plop/templates/component/component.hbs b/packages/webawesome/scripts/plop/templates/component/component.hbs index 1f141f54b..a1c9cfa26 100644 --- a/packages/webawesome/scripts/plop/templates/component/component.hbs +++ b/packages/webawesome/scripts/plop/templates/component/component.hbs @@ -21,7 +21,7 @@ import styles from './{{ tagWithoutPrefix tag }}.css'; */ @customElement("{{ tag }}") export default class {{ properCase tag }} extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; /** An example attribute. */ @property() attr = 'example'; diff --git a/packages/webawesome/src/components/animated-image/animated-image.ts b/packages/webawesome/src/components/animated-image/animated-image.ts index adb15abf7..fd2d68fd1 100644 --- a/packages/webawesome/src/components/animated-image/animated-image.ts +++ b/packages/webawesome/src/components/animated-image/animated-image.ts @@ -28,7 +28,7 @@ import styles from './animated-image.css'; */ @customElement('wa-animated-image') export default class WaAnimatedImage extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @query('.animated') animatedImage: HTMLImageElement; diff --git a/packages/webawesome/src/components/animation/animation.ts b/packages/webawesome/src/components/animation/animation.ts index b5fc68130..6df15c2ef 100644 --- a/packages/webawesome/src/components/animation/animation.ts +++ b/packages/webawesome/src/components/animation/animation.ts @@ -23,7 +23,7 @@ import { animations } from './animations.js'; */ @customElement('wa-animation') export default class WaAnimation extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private animation?: Animation; private hasStarted = false; diff --git a/packages/webawesome/src/components/avatar/avatar.ts b/packages/webawesome/src/components/avatar/avatar.ts index e163fa86d..cf6a06981 100644 --- a/packages/webawesome/src/components/avatar/avatar.ts +++ b/packages/webawesome/src/components/avatar/avatar.ts @@ -29,7 +29,7 @@ import styles from './avatar.css'; */ @customElement('wa-avatar') export default class WaAvatar extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @state() private hasError = false; diff --git a/packages/webawesome/src/components/badge/badge.ts b/packages/webawesome/src/components/badge/badge.ts index 9ce62ac5a..32491182f 100644 --- a/packages/webawesome/src/components/badge/badge.ts +++ b/packages/webawesome/src/components/badge/badge.ts @@ -21,7 +21,7 @@ import styles from './badge.css'; */ @customElement('wa-badge') export default class WaBadge extends WebAwesomeElement { - static shadowStyle = [variantStyles, appearanceStyles, styles]; + static css = [variantStyles, appearanceStyles, styles]; /** The badge's theme variant. Defaults to `brand` if not within another element with a variant. */ @property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' = 'brand'; diff --git a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts index 8fe3a33d7..5874dc24d 100644 --- a/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts +++ b/packages/webawesome/src/components/breadcrumb-item/breadcrumb-item.ts @@ -24,7 +24,7 @@ import styles from './breadcrumb-item.css'; */ @customElement('wa-breadcrumb-item') export default class WaBreadcrumbItem extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @query('slot:not([name])') defaultSlot: HTMLSlotElement; diff --git a/packages/webawesome/src/components/breadcrumb/breadcrumb.ts b/packages/webawesome/src/components/breadcrumb/breadcrumb.ts index ff3b11843..b3cfe866f 100644 --- a/packages/webawesome/src/components/breadcrumb/breadcrumb.ts +++ b/packages/webawesome/src/components/breadcrumb/breadcrumb.ts @@ -21,7 +21,7 @@ import styles from './breadcrumb.css'; */ @customElement('wa-breadcrumb') export default class WaBreadcrumb extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); private separatorDir = this.localize.dir(); diff --git a/packages/webawesome/src/components/button-group/button-group.ts b/packages/webawesome/src/components/button-group/button-group.ts index 0ce7f17c6..b0fe26dce 100644 --- a/packages/webawesome/src/components/button-group/button-group.ts +++ b/packages/webawesome/src/components/button-group/button-group.ts @@ -20,7 +20,7 @@ import styles from './button-group.css'; */ @customElement('wa-button-group') export default class WaButtonGroup extends WebAwesomeElement { - static shadowStyle = [sizeStyles, variantStyles, styles]; + static css = [sizeStyles, variantStyles, styles]; @query('slot') defaultSlot: HTMLSlotElement; diff --git a/packages/webawesome/src/components/button/button.ts b/packages/webawesome/src/components/button/button.ts index ada012fb8..0518539f3 100644 --- a/packages/webawesome/src/components/button/button.ts +++ b/packages/webawesome/src/components/button/button.ts @@ -53,7 +53,7 @@ import styles from './button.css'; */ @customElement('wa-button') export default class WaButton extends WebAwesomeFormAssociatedElement { - static shadowStyle = [styles, variantStyles, sizeStyles, appearanceStyles]; + static css = [styles, variantStyles, sizeStyles, appearanceStyles]; static get validators() { return [...super.validators, MirrorValidator()]; diff --git a/packages/webawesome/src/components/callout/callout.ts b/packages/webawesome/src/components/callout/callout.ts index d4c5489f1..a8f2bd066 100644 --- a/packages/webawesome/src/components/callout/callout.ts +++ b/packages/webawesome/src/components/callout/callout.ts @@ -24,7 +24,7 @@ import styles from './callout.css'; */ @customElement('wa-callout') export default class WaCallout extends WebAwesomeElement { - static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, styles]; + static css = [variantStyles, appearanceStyles, sizeStyles, styles]; /** The callout's theme variant. Defaults to `brand` if not within another element with a variant. */ @property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' | 'brand' = 'brand'; diff --git a/packages/webawesome/src/components/card/card.ts b/packages/webawesome/src/components/card/card.ts index 856fa8ba2..4206ce82e 100644 --- a/packages/webawesome/src/components/card/card.ts +++ b/packages/webawesome/src/components/card/card.ts @@ -30,7 +30,7 @@ import styles from './card.css'; */ @customElement('wa-card') export default class WaCard extends WebAwesomeElement { - static shadowStyle = [sizeStyles, appearanceStyles, styles]; + static css = [sizeStyles, appearanceStyles, styles]; private readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'media'); diff --git a/packages/webawesome/src/components/carousel-item/carousel-item.ts b/packages/webawesome/src/components/carousel-item/carousel-item.ts index 76fac9d19..779d5df08 100644 --- a/packages/webawesome/src/components/carousel-item/carousel-item.ts +++ b/packages/webawesome/src/components/carousel-item/carousel-item.ts @@ -16,7 +16,7 @@ import styles from './carousel-item.css'; */ @customElement('wa-carousel-item') export default class WaCarouselItem extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; connectedCallback() { super.connectedCallback(); diff --git a/packages/webawesome/src/components/carousel/carousel.ts b/packages/webawesome/src/components/carousel/carousel.ts index 295d3dacd..ff6acea9e 100644 --- a/packages/webawesome/src/components/carousel/carousel.ts +++ b/packages/webawesome/src/components/carousel/carousel.ts @@ -52,7 +52,7 @@ import styles from './carousel.css'; */ @customElement('wa-carousel') export default class WaCarousel extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; /** When set, allows the user to navigate the carousel in the same direction indefinitely. */ @property({ type: Boolean, reflect: true }) loop = false; diff --git a/packages/webawesome/src/components/checkbox/checkbox.test.ts b/packages/webawesome/src/components/checkbox/checkbox.test.ts index 823e25708..c5d89ba69 100644 --- a/packages/webawesome/src/components/checkbox/checkbox.test.ts +++ b/packages/webawesome/src/components/checkbox/checkbox.test.ts @@ -199,17 +199,17 @@ describe('', () => { expect(checkbox.checkValidity()).to.be.false; expect(checkbox.checkValidity()).to.be.false; - expect(checkbox.hasCustomState('invalid')).to.be.true; - expect(checkbox.hasCustomState('valid')).to.be.false; - expect(checkbox.hasCustomState('user-invalid')).to.be.true; - expect(checkbox.hasCustomState('user-valid')).to.be.false; + expect(checkbox.customStates.has('invalid')).to.be.true; + expect(checkbox.customStates.has('valid')).to.be.false; + expect(checkbox.customStates.has('user-invalid')).to.be.true; + expect(checkbox.customStates.has('user-valid')).to.be.false; await clickOnElement(checkbox); await checkbox.updateComplete; await aTimeout(0); - expect(checkbox.hasCustomState('user-invalid')).to.be.true; - expect(checkbox.hasCustomState('user-valid')).to.be.false; + expect(checkbox.customStates.has('user-invalid')).to.be.true; + expect(checkbox.customStates.has('user-valid')).to.be.false; }); it('should be invalid when required and unchecked', async () => { @@ -244,12 +244,12 @@ describe('', () => { `); const checkbox = el.querySelector('wa-checkbox')!; - expect(checkbox.hasCustomState('required')).to.be.true; - expect(checkbox.hasCustomState('optional')).to.be.false; - expect(checkbox.hasCustomState('invalid')).to.be.true; - expect(checkbox.hasCustomState('valid')).to.be.false; - expect(checkbox.hasCustomState('user-invalid')).to.be.false; - expect(checkbox.hasCustomState('user-valid')).to.be.false; + expect(checkbox.customStates.has('required')).to.be.true; + expect(checkbox.customStates.has('optional')).to.be.false; + expect(checkbox.customStates.has('invalid')).to.be.true; + expect(checkbox.customStates.has('valid')).to.be.false; + expect(checkbox.customStates.has('user-invalid')).to.be.false; + expect(checkbox.customStates.has('user-valid')).to.be.false; }); }); diff --git a/packages/webawesome/src/components/checkbox/checkbox.ts b/packages/webawesome/src/components/checkbox/checkbox.ts index 8cba0e871..7ee8e2f0a 100644 --- a/packages/webawesome/src/components/checkbox/checkbox.ts +++ b/packages/webawesome/src/components/checkbox/checkbox.ts @@ -55,7 +55,7 @@ import styles from './checkbox.css'; */ @customElement('wa-checkbox') export default class WaCheckbox extends WebAwesomeFormAssociatedElement { - static shadowStyle = [formControlStyles, sizeStyles, styles]; + static css = [formControlStyles, sizeStyles, styles]; static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true }; @@ -156,14 +156,14 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement { this.input.indeterminate = this.indeterminate; // force a sync update } - this.toggleCustomState('checked', this.checked); - this.toggleCustomState('indeterminate', this.indeterminate); + this.customStates.set('checked', this.checked); + this.customStates.set('indeterminate', this.indeterminate); this.updateValidity(); } @watch('disabled') handleDisabledChange() { - this.toggleCustomState('disabled', this.disabled); + this.customStates.set('disabled', this.disabled); } protected willUpdate(changedProperties: PropertyValues): void { diff --git a/packages/webawesome/src/components/color-picker/color-picker.test.ts b/packages/webawesome/src/components/color-picker/color-picker.test.ts index fc91d55ef..7bd417783 100644 --- a/packages/webawesome/src/components/color-picker/color-picker.test.ts +++ b/packages/webawesome/src/components/color-picker/color-picker.test.ts @@ -501,12 +501,12 @@ describe('', () => { const grid = el.shadowRoot!.querySelector('[part~="grid"]')!; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.false; - expect(el.hasCustomState('valid')).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.false; + expect(el.customStates.has('valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; await clickOnElement(trigger); await aTimeout(500); @@ -514,8 +514,8 @@ describe('', () => { await el.updateComplete; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.true; }); it('should receive the correct validation attributes ("states") when invalid', async () => { @@ -523,12 +523,12 @@ describe('', () => { const trigger = el.shadowRoot!.querySelector('[part~="trigger"]')!; const grid = el.shadowRoot!.querySelector('[part~="grid"]')!; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.true; - expect(el.hasCustomState('valid')).to.be.false; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.true; + expect(el.customStates.has('valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; await clickOnElement(trigger); await aTimeout(500); @@ -536,8 +536,8 @@ describe('', () => { await el.updateComplete; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.true; }); }); }); diff --git a/packages/webawesome/src/components/color-picker/color-picker.ts b/packages/webawesome/src/components/color-picker/color-picker.ts index 2943fc5fa..b9e82d93d 100644 --- a/packages/webawesome/src/components/color-picker/color-picker.ts +++ b/packages/webawesome/src/components/color-picker/color-picker.ts @@ -102,7 +102,7 @@ declare const EyeDropper: EyeDropperConstructor; */ @customElement('wa-color-picker') export default class WaColorPicker extends WebAwesomeFormAssociatedElement { - static shadowStyle = [visuallyHidden, sizeStyles, formControlStyles, styles]; + static css = [visuallyHidden, sizeStyles, formControlStyles, styles]; static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true }; diff --git a/packages/webawesome/src/components/comparison/comparison.ts b/packages/webawesome/src/components/comparison/comparison.ts index 94e27d2f0..df8d5f42c 100644 --- a/packages/webawesome/src/components/comparison/comparison.ts +++ b/packages/webawesome/src/components/comparison/comparison.ts @@ -38,7 +38,7 @@ import styles from './comparison.css'; */ @customElement('wa-comparison') export default class WaComparison extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); @@ -55,12 +55,12 @@ export default class WaComparison extends WebAwesomeElement { drag(this, { onMove: x => { - this.toggleCustomState('dragging', true); + this.customStates.set('dragging', true); this.position = parseFloat(clamp((x / width) * 100, 0, 100).toFixed(2)); if (isRtl) this.position = 100 - this.position; }, onStop: () => { - this.toggleCustomState('dragging', false); + this.customStates.set('dragging', false); }, initialEvent: event, }); diff --git a/packages/webawesome/src/components/copy-button/copy-button.ts b/packages/webawesome/src/components/copy-button/copy-button.ts index b4f696e7f..0b06d5101 100644 --- a/packages/webawesome/src/components/copy-button/copy-button.ts +++ b/packages/webawesome/src/components/copy-button/copy-button.ts @@ -44,7 +44,7 @@ import styles from './copy-button.css'; */ @customElement('wa-copy-button') export default class WaCopyButton extends WebAwesomeElement { - static shadowStyle = [visuallyHidden, styles]; + static css = [visuallyHidden, styles]; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/details/details.ts b/packages/webawesome/src/components/details/details.ts index 1b1ffc2d0..2cc9a554f 100644 --- a/packages/webawesome/src/components/details/details.ts +++ b/packages/webawesome/src/components/details/details.ts @@ -46,7 +46,7 @@ import styles from './details.css'; */ @customElement('wa-details') export default class WaDetails extends WebAwesomeElement { - static shadowStyle = [appearanceStyles, styles]; + static css = [appearanceStyles, styles]; private detailsObserver: MutationObserver; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/dialog/dialog.ts b/packages/webawesome/src/components/dialog/dialog.ts index 26f4dd9f1..4b95d5d40 100644 --- a/packages/webawesome/src/components/dialog/dialog.ts +++ b/packages/webawesome/src/components/dialog/dialog.ts @@ -54,7 +54,7 @@ import styles from './dialog.css'; */ @customElement('wa-dialog') export default class WaDialog extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); private readonly hasSlotController = new HasSlotController(this, 'footer', 'header-actions', 'label'); diff --git a/packages/webawesome/src/components/divider/divider.ts b/packages/webawesome/src/components/divider/divider.ts index aa866ae5b..0ac4e7c74 100644 --- a/packages/webawesome/src/components/divider/divider.ts +++ b/packages/webawesome/src/components/divider/divider.ts @@ -15,7 +15,7 @@ import styles from './divider.css'; */ @customElement('wa-divider') export default class WaDivider extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; /** Sets the divider's orientation. */ @property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal'; diff --git a/packages/webawesome/src/components/drawer/drawer.ts b/packages/webawesome/src/components/drawer/drawer.ts index a32bf731e..57615f7f8 100644 --- a/packages/webawesome/src/components/drawer/drawer.ts +++ b/packages/webawesome/src/components/drawer/drawer.ts @@ -59,7 +59,7 @@ import styles from './drawer.css'; */ @customElement('wa-drawer') export default class WaDrawer extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); private readonly hasSlotController = new HasSlotController(this, 'footer', 'header-actions', 'label'); diff --git a/packages/webawesome/src/components/dropdown/dropdown.ts b/packages/webawesome/src/components/dropdown/dropdown.ts index 022b5bd19..7a881eab4 100644 --- a/packages/webawesome/src/components/dropdown/dropdown.ts +++ b/packages/webawesome/src/components/dropdown/dropdown.ts @@ -44,7 +44,7 @@ import styles from './dropdown.css'; */ @customElement('wa-dropdown') export default class WaDropdown extends WebAwesomeElement { - static shadowStyle = [sizeStyles, styles]; + static css = [sizeStyles, styles]; @query('.dropdown') popup: WaPopup; @query('#trigger') trigger: HTMLSlotElement; diff --git a/packages/webawesome/src/components/icon-button/icon-button.ts b/packages/webawesome/src/components/icon-button/icon-button.ts index 64ec7475e..fb12dbc2e 100644 --- a/packages/webawesome/src/components/icon-button/icon-button.ts +++ b/packages/webawesome/src/components/icon-button/icon-button.ts @@ -26,7 +26,7 @@ import styles from './icon-button.css'; */ @customElement('wa-icon-button') export default class WaIconButton extends WebAwesomeFormAssociatedElement { - static shadowStyle = styles; + static css = styles; @query('.icon-button') button: HTMLButtonElement | HTMLLinkElement; diff --git a/packages/webawesome/src/components/icon/icon.ts b/packages/webawesome/src/components/icon/icon.ts index 2ef8edc69..c5e9f64f6 100644 --- a/packages/webawesome/src/components/icon/icon.ts +++ b/packages/webawesome/src/components/icon/icon.ts @@ -41,7 +41,7 @@ interface IconSource { */ @customElement('wa-icon') export default class WaIcon extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @state() private svg: SVGElement | HTMLTemplateResult | null = null; diff --git a/packages/webawesome/src/components/include/include.ts b/packages/webawesome/src/components/include/include.ts index ee232beb5..66197a2df 100644 --- a/packages/webawesome/src/components/include/include.ts +++ b/packages/webawesome/src/components/include/include.ts @@ -18,7 +18,7 @@ import { requestInclude } from './request.js'; */ @customElement('wa-include') export default class WaInclude extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; /** * The location of the HTML file to include. Be sure you trust the content you are including as it will be executed as diff --git a/packages/webawesome/src/components/input/input.test.ts b/packages/webawesome/src/components/input/input.test.ts index ffaa5fc57..735ea00da 100644 --- a/packages/webawesome/src/components/input/input.test.ts +++ b/packages/webawesome/src/components/input/input.test.ts @@ -108,12 +108,12 @@ describe('', () => { const el = await fixture(html` `); expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.false; - expect(el.hasCustomState('valid')).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.false; + expect(el.customStates.has('valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; el.focus(); await el.updateComplete; @@ -123,19 +123,19 @@ describe('', () => { await el.updateComplete; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.true; }); it('should receive the correct validation attributes ("states") when invalid', async () => { const el = await fixture(html` `); - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.true; - expect(el.hasCustomState('valid')).to.be.false; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.true; + expect(el.customStates.has('valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; el.focus(); await el.updateComplete; @@ -145,20 +145,20 @@ describe('', () => { el.blur(); await el.updateComplete; - expect(el.hasCustomState('user-invalid')).to.be.true; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.true; + expect(el.customStates.has('user-valid')).to.be.false; }); it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => { const el = await fixture(html`
`); const input = el.querySelector('wa-input')!; - expect(input.hasCustomState('required')).to.be.true; - expect(input.hasCustomState('optional')).to.be.false; - expect(input.hasCustomState('invalid')).to.be.true; - expect(input.hasCustomState('valid')).to.be.false; - expect(input.hasCustomState('user-invalid')).to.be.false; - expect(input.hasCustomState('user-valid')).to.be.false; + expect(input.customStates.has('required')).to.be.true; + expect(input.customStates.has('optional')).to.be.false; + expect(input.customStates.has('invalid')).to.be.true; + expect(input.customStates.has('valid')).to.be.false; + expect(input.customStates.has('user-invalid')).to.be.false; + expect(input.customStates.has('user-valid')).to.be.false; }); }); @@ -215,10 +215,10 @@ describe('', () => { await input.updateComplete; expect(input.checkValidity()).to.be.false; - expect(input.hasCustomState('invalid')).to.be.true; - expect(input.hasCustomState('valid')).to.be.false; - expect(input.hasCustomState('user-invalid')).to.be.false; - expect(input.hasCustomState('user-valid')).to.be.false; + expect(input.customStates.has('invalid')).to.be.true; + expect(input.customStates.has('valid')).to.be.false; + expect(input.customStates.has('user-invalid')).to.be.false; + expect(input.customStates.has('user-valid')).to.be.false; input.focus(); await sendKeys({ type: 'test' }); @@ -226,8 +226,8 @@ describe('', () => { input.blur(); await input.updateComplete; - expect(input.hasCustomState('user-invalid')).to.be.true; - expect(input.hasCustomState('user-valid')).to.be.false; + expect(input.customStates.has('user-invalid')).to.be.true; + expect(input.customStates.has('user-valid')).to.be.false; }); it('should be present in form data when using the form attribute and located outside of a
', async () => { diff --git a/packages/webawesome/src/components/input/input.ts b/packages/webawesome/src/components/input/input.ts index c52c44d4b..5ffe73c8f 100644 --- a/packages/webawesome/src/components/input/input.ts +++ b/packages/webawesome/src/components/input/input.ts @@ -57,7 +57,7 @@ import styles from './input.css'; */ @customElement('wa-input') export default class WaInput extends WebAwesomeFormAssociatedElement { - static shadowStyle = [sizeStyles, appearanceStyles, formControlStyles, styles]; + static css = [sizeStyles, appearanceStyles, formControlStyles, styles]; static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true }; @@ -300,7 +300,7 @@ export default class WaInput extends WebAwesomeFormAssociatedElement { super.updated(changedProperties); if (changedProperties.has('value')) { - this.toggleCustomState('blank', !this.value); + this.customStates.set('blank', !this.value); } } diff --git a/packages/webawesome/src/components/menu-item/menu-item.ts b/packages/webawesome/src/components/menu-item/menu-item.ts index 7a3e1fe9a..408021639 100644 --- a/packages/webawesome/src/components/menu-item/menu-item.ts +++ b/packages/webawesome/src/components/menu-item/menu-item.ts @@ -43,7 +43,7 @@ import { SubmenuController } from './submenu-controller.js'; */ @customElement('wa-menu-item') export default class WaMenuItem extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); @@ -133,7 +133,7 @@ export default class WaMenuItem extends WebAwesomeElement { this.dispatchEvent(new Event('slotchange', { bubbles: true, composed: false, cancelable: false })); } - this.toggleCustomState('has-submenu', this.isSubmenu()); + this.customStates.set('has-submenu', this.isSubmenu()); } private handleHostClick = (event: MouseEvent) => { @@ -201,7 +201,7 @@ export default class WaMenuItem extends WebAwesomeElement { render() { const isRtl = this.hasUpdated ? this.localize.dir() === 'rtl' : this.dir === 'rtl'; const isSubmenuExpanded = this.submenuController.isExpanded(); - this.toggleCustomState('submenu-expanded', isSubmenuExpanded); + this.customStates.set('submenu-expanded', isSubmenuExpanded); this.internals.ariaHasPopup = this.isSubmenu() + ''; this.internals.ariaExpanded = isSubmenuExpanded + ''; diff --git a/packages/webawesome/src/components/menu-label/menu-label.ts b/packages/webawesome/src/components/menu-label/menu-label.ts index 46b44b6b6..7450db65c 100644 --- a/packages/webawesome/src/components/menu-label/menu-label.ts +++ b/packages/webawesome/src/components/menu-label/menu-label.ts @@ -13,7 +13,7 @@ import styles from './menu-label.css'; */ @customElement('wa-menu-label') export default class WaMenuLabel extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; render() { return html``; diff --git a/packages/webawesome/src/components/menu/menu.ts b/packages/webawesome/src/components/menu/menu.ts index 6280b2d6f..f95ad2faa 100644 --- a/packages/webawesome/src/components/menu/menu.ts +++ b/packages/webawesome/src/components/menu/menu.ts @@ -25,7 +25,7 @@ export interface MenuSelectEventDetail { */ @customElement('wa-menu') export default class WaMenu extends WebAwesomeElement { - static shadowStyle = [sizeStyles, styles]; + static css = [sizeStyles, styles]; /** The component's size. */ @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; diff --git a/packages/webawesome/src/components/mutation-observer/mutation-observer.ts b/packages/webawesome/src/components/mutation-observer/mutation-observer.ts index e25945842..f3312d553 100644 --- a/packages/webawesome/src/components/mutation-observer/mutation-observer.ts +++ b/packages/webawesome/src/components/mutation-observer/mutation-observer.ts @@ -17,7 +17,7 @@ import styles from './mutation-observer.css'; */ @customElement('wa-mutation-observer') export default class WaMutationObserver extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private mutationObserver: MutationObserver; diff --git a/packages/webawesome/src/components/option/option.ts b/packages/webawesome/src/components/option/option.ts index 356e41d2d..1badd483d 100644 --- a/packages/webawesome/src/components/option/option.ts +++ b/packages/webawesome/src/components/option/option.ts @@ -35,7 +35,7 @@ import styles from './option.css'; */ @customElement('wa-option') export default class WaOption extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; // @ts-expect-error - Controller is currently unused private readonly localize = new LocalizeController(this); @@ -130,9 +130,9 @@ export default class WaOption extends WebAwesomeElement { // We need this because Safari doesn't honor :hover styles while dragging // Test case: https://codepen.io/leaverou/pen/VYZOOjy if (event.type === 'mouseenter') { - this.toggleCustomState('hover', true); + this.customStates.set('hover', true); } else if (event.type === 'mouseleave') { - this.toggleCustomState('hover', false); + this.customStates.set('hover', false); } }; @@ -145,7 +145,7 @@ export default class WaOption extends WebAwesomeElement { if (changedProperties.has('selected')) { this.setAttribute('aria-selected', this.selected ? 'true' : 'false'); - this.toggleCustomState('selected', this.selected); + this.customStates.set('selected', this.selected); } if (changedProperties.has('value')) { @@ -165,7 +165,7 @@ export default class WaOption extends WebAwesomeElement { } if (changedProperties.has('current')) { - this.toggleCustomState('current', this.current); + this.customStates.set('current', this.current); } } diff --git a/packages/webawesome/src/components/page/page.ts b/packages/webawesome/src/components/page/page.ts index a3036aee8..6d698b144 100644 --- a/packages/webawesome/src/components/page/page.ts +++ b/packages/webawesome/src/components/page/page.ts @@ -128,7 +128,7 @@ function toLength(px: number | string): string { */ @customElement('wa-page') export default class WaPage extends WebAwesomeElement { - static shadowStyle = [visuallyHidden, styles]; + static css = [visuallyHidden, styles]; private headerResizeObserver = this.slotResizeObserver('header'); private subheaderResizeObserver = this.slotResizeObserver('subheader'); diff --git a/packages/webawesome/src/components/popover/popover.ts b/packages/webawesome/src/components/popover/popover.ts index 1b769b8f4..be37785c3 100644 --- a/packages/webawesome/src/components/popover/popover.ts +++ b/packages/webawesome/src/components/popover/popover.ts @@ -1,3 +1,4 @@ +import type { PropertyValues } from 'lit'; import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -40,10 +41,12 @@ const openPopovers = new Set(); * @cssproperty [--max-width=25rem] - The maximum width of the popover's body content. * @cssproperty [--show-duration=100ms] - The speed of the show animation. * @cssproperty [--hide-duration=100ms] - The speed of the hide animation. + * + * @cssstate open - Applied when the popover is open. */ @customElement('wa-popover') export default class WaPopover extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; static dependencies = { 'wa-popup': WaPopup }; @query('dialog') dialog: HTMLDialogElement; @@ -110,6 +113,12 @@ export default class WaPopover extends WebAwesomeElement { } } + updated(changedProperties: PropertyValues) { + if (changedProperties.has('open')) { + this.customStates.set('open', this.open); + } + } + private handleAnchorClick = () => { // Clicks on the anchor should toggle the popover this.open = !this.open; diff --git a/packages/webawesome/src/components/popup/popup.ts b/packages/webawesome/src/components/popup/popup.ts index 2c0f9417f..38e63032e 100644 --- a/packages/webawesome/src/components/popup/popup.ts +++ b/packages/webawesome/src/components/popup/popup.ts @@ -68,7 +68,7 @@ const SUPPORTS_POPOVER = globalThis?.HTMLElement?.prototype.hasOwnProperty('popo */ @customElement('wa-popup') export default class WaPopup extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private anchorEl: Element | VirtualElement | null; private cleanup: ReturnType | undefined; diff --git a/packages/webawesome/src/components/progress-bar/progress-bar.ts b/packages/webawesome/src/components/progress-bar/progress-bar.ts index 40b13d4f8..c61210d91 100644 --- a/packages/webawesome/src/components/progress-bar/progress-bar.ts +++ b/packages/webawesome/src/components/progress-bar/progress-bar.ts @@ -24,7 +24,7 @@ import styles from './progress-bar.css'; */ @customElement('wa-progress-bar') export default class WaProgressBar extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); /** The current progress as a percentage, 0 to 100. */ diff --git a/packages/webawesome/src/components/progress-ring/progress-ring.ts b/packages/webawesome/src/components/progress-ring/progress-ring.ts index 456f96398..954fcdde1 100644 --- a/packages/webawesome/src/components/progress-ring/progress-ring.ts +++ b/packages/webawesome/src/components/progress-ring/progress-ring.ts @@ -25,7 +25,7 @@ import styles from './progress-ring.css'; */ @customElement('wa-progress-ring') export default class WaProgressRing extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/qr-code/qr-code.ts b/packages/webawesome/src/components/qr-code/qr-code.ts index efa181afa..c1df3d2a8 100644 --- a/packages/webawesome/src/components/qr-code/qr-code.ts +++ b/packages/webawesome/src/components/qr-code/qr-code.ts @@ -18,7 +18,7 @@ let QrCreator: _QrCreator.default; */ @customElement('wa-qr-code') export default class WaQrCode extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @query('canvas') canvas: HTMLElement; diff --git a/packages/webawesome/src/components/radio-group/radio-group.test.ts b/packages/webawesome/src/components/radio-group/radio-group.test.ts index 5bb18186b..1f70c4f35 100644 --- a/packages/webawesome/src/components/radio-group/radio-group.test.ts +++ b/packages/webawesome/src/components/radio-group/radio-group.test.ts @@ -99,12 +99,12 @@ describe('', () => { const secondRadio = radioGroup.querySelectorAll('wa-radio')[1]; expect(radioGroup.checkValidity()).to.be.true; - expect(radioGroup.hasCustomState('required')).to.be.true; - expect(radioGroup.hasCustomState('optional')).to.be.false; - expect(radioGroup.hasCustomState('invalid')).to.be.false; - expect(radioGroup.hasCustomState('valid')).to.be.true; - expect(radioGroup.hasCustomState('user-invalid')).to.be.false; - expect(radioGroup.hasCustomState('user-valid')).to.be.false; + expect(radioGroup.customStates.has('required')).to.be.true; + expect(radioGroup.customStates.has('optional')).to.be.false; + expect(radioGroup.customStates.has('invalid')).to.be.false; + expect(radioGroup.customStates.has('valid')).to.be.true; + expect(radioGroup.customStates.has('user-invalid')).to.be.false; + expect(radioGroup.customStates.has('user-valid')).to.be.false; // TODO: Go back to clickOnElement when we can determine why CI is not cleaning up elements. // await clickOnElement(secondRadio); @@ -113,8 +113,8 @@ describe('', () => { await radioGroup.updateComplete expect(radioGroup.checkValidity()).to.be.true; - expect(radioGroup.hasCustomState('user-invalid')).to.be.false; - expect(radioGroup.hasCustomState('user-valid')).to.be.true; + expect(radioGroup.customStates.has('user-invalid')).to.be.false; + expect(radioGroup.customStates.has('user-valid')).to.be.true; }); it('should receive the correct validation attributes ("states") when invalid', async () => { @@ -126,12 +126,12 @@ describe('', () => { `); const secondRadio = radioGroup.querySelectorAll('wa-radio')[1]; - expect(radioGroup.hasCustomState('required')).to.be.true; - expect(radioGroup.hasCustomState('optional')).to.be.false; - expect(radioGroup.hasCustomState('invalid')).to.be.true; - expect(radioGroup.hasCustomState('valid')).to.be.false; - expect(radioGroup.hasCustomState('user-invalid')).to.be.false; - expect(radioGroup.hasCustomState('user-valid')).to.be.false; + expect(radioGroup.customStates.has('required')).to.be.true; + expect(radioGroup.customStates.has('optional')).to.be.false; + expect(radioGroup.customStates.has('invalid')).to.be.true; + expect(radioGroup.customStates.has('valid')).to.be.false; + expect(radioGroup.customStates.has('user-invalid')).to.be.false; + expect(radioGroup.customStates.has('user-valid')).to.be.false; // TODO: Go back to clickOnElement when we can determine why CI is not cleaning up elements. // await clickOnElement(secondRadio); @@ -140,8 +140,8 @@ describe('', () => { radioGroup.value = ''; await radioGroup.updateComplete; - expect(radioGroup.hasCustomState('user-invalid')).to.be.true; - expect(radioGroup.hasCustomState('user-valid')).to.be.false; + expect(radioGroup.customStates.has('user-invalid')).to.be.true; + expect(radioGroup.customStates.has('user-valid')).to.be.false; }); it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => { @@ -155,12 +155,12 @@ describe('', () => { `); const radioGroup = el.querySelector('wa-radio-group')!; - expect(radioGroup.hasCustomState('required')).to.be.true; - expect(radioGroup.hasCustomState('optional')).to.be.false; - expect(radioGroup.hasCustomState('invalid')).to.be.true; - expect(radioGroup.hasCustomState('valid')).to.be.false; - expect(radioGroup.hasCustomState('user-invalid')).to.be.false; - expect(radioGroup.hasCustomState('user-valid')).to.be.false; + expect(radioGroup.customStates.has('required')).to.be.true; + expect(radioGroup.customStates.has('optional')).to.be.false; + expect(radioGroup.customStates.has('invalid')).to.be.true; + expect(radioGroup.customStates.has('valid')).to.be.false; + expect(radioGroup.customStates.has('user-invalid')).to.be.false; + expect(radioGroup.customStates.has('user-valid')).to.be.false; }); it('should show a constraint validation error when setCustomValidity() is called', async () => { diff --git a/packages/webawesome/src/components/radio-group/radio-group.ts b/packages/webawesome/src/components/radio-group/radio-group.ts index 3f8a45f4c..e118c75ce 100644 --- a/packages/webawesome/src/components/radio-group/radio-group.ts +++ b/packages/webawesome/src/components/radio-group/radio-group.ts @@ -37,7 +37,7 @@ import styles from './radio-group.css'; */ @customElement('wa-radio-group') export default class WaRadioGroup extends WebAwesomeFormAssociatedElement { - static shadowStyle = [sizeStyles, formControlStyles, styles]; + static css = [sizeStyles, formControlStyles, styles]; static get validators() { const validators = isServer diff --git a/packages/webawesome/src/components/radio/radio.ts b/packages/webawesome/src/components/radio/radio.ts index a281af4df..cdec1799a 100644 --- a/packages/webawesome/src/components/radio/radio.ts +++ b/packages/webawesome/src/components/radio/radio.ts @@ -40,7 +40,7 @@ import styles from './radio.css'; */ @customElement('wa-radio') export default class WaRadio extends WebAwesomeFormAssociatedElement { - static shadowStyle = [formControlStyles, sizeStyles, styles]; + static css = [formControlStyles, sizeStyles, styles]; @state() checked = false; @@ -86,13 +86,13 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement { super.updated(changedProperties); if (changedProperties.has('checked')) { - this.toggleCustomState('checked', this.checked); + this.customStates.set('checked', this.checked); this.setAttribute('aria-checked', this.checked ? 'true' : 'false'); this.tabIndex = this.checked ? 0 : -1; } if (changedProperties.has('disabled')) { - this.toggleCustomState('disabled', this.disabled); + this.customStates.set('disabled', this.disabled); this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); } } diff --git a/packages/webawesome/src/components/rating/rating.ts b/packages/webawesome/src/components/rating/rating.ts index 1a5161ca2..e918289b3 100644 --- a/packages/webawesome/src/components/rating/rating.ts +++ b/packages/webawesome/src/components/rating/rating.ts @@ -33,7 +33,7 @@ import styles from './rating.css'; */ @customElement('wa-rating') export default class WaRating extends WebAwesomeElement { - static shadowStyle = [sizeStyles, styles]; + static css = [sizeStyles, styles]; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/resize-observer/resize-observer.ts b/packages/webawesome/src/components/resize-observer/resize-observer.ts index 40c17d2b3..f414a036a 100644 --- a/packages/webawesome/src/components/resize-observer/resize-observer.ts +++ b/packages/webawesome/src/components/resize-observer/resize-observer.ts @@ -17,7 +17,7 @@ import styles from './resize-observer.css'; */ @customElement('wa-resize-observer') export default class WaResizeObserver extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private resizeObserver: ResizeObserver; private observedElements: HTMLElement[] = []; diff --git a/packages/webawesome/src/components/scroller/scroller.ts b/packages/webawesome/src/components/scroller/scroller.ts index 2cb22b760..21a207cab 100644 --- a/packages/webawesome/src/components/scroller/scroller.ts +++ b/packages/webawesome/src/components/scroller/scroller.ts @@ -20,7 +20,7 @@ import styles from './scroller.css'; */ @customElement('wa-scroller') export default class WaScroller extends WebAwesomeElement { - static shadowStyle = [styles]; + static css = [styles]; private readonly localize = new LocalizeController(this); private resizeObserver = new ResizeObserver(() => this.updateScroll()); diff --git a/packages/webawesome/src/components/select/select.test.ts b/packages/webawesome/src/components/select/select.test.ts index c3221d428..972e0afc1 100644 --- a/packages/webawesome/src/components/select/select.test.ts +++ b/packages/webawesome/src/components/select/select.test.ts @@ -331,12 +331,12 @@ describe('', () => { const secondOption = el.querySelectorAll('wa-option')[1]; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.false; - expect(el.hasCustomState('valid')).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.false; + expect(el.customStates.has('valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; await el.show(); await clickOnElement(secondOption); @@ -345,8 +345,8 @@ describe('', () => { await el.updateComplete; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.true; }); it('should receive the correct validation attributes ("states") when invalid', async () => { @@ -359,12 +359,12 @@ describe('', () => { `); const secondOption = el.querySelectorAll('wa-option')[1]; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.true; - expect(el.hasCustomState('valid')).to.be.false; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.true; + expect(el.customStates.has('valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; await el.show(); await clickOnElement(secondOption); @@ -373,8 +373,8 @@ describe('', () => { el.blur(); await el.updateComplete; - expect(el.hasCustomState('user-invalid')).to.be.true; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.true; + expect(el.customStates.has('user-valid')).to.be.false; }); it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => { @@ -389,12 +389,12 @@ describe('', () => { `); const select = el.querySelector('wa-select')!; - expect(select.hasCustomState('required')).to.be.true; - expect(select.hasCustomState('optional')).to.be.false; - expect(select.hasCustomState('invalid')).to.be.true; - expect(select.hasCustomState('valid')).to.be.false; - expect(select.hasCustomState('user-invalid')).to.be.false; - expect(select.hasCustomState('user-valid')).to.be.false; + expect(select.customStates.has('required')).to.be.true; + expect(select.customStates.has('optional')).to.be.false; + expect(select.customStates.has('invalid')).to.be.true; + expect(select.customStates.has('valid')).to.be.false; + expect(select.customStates.has('user-invalid')).to.be.false; + expect(select.customStates.has('user-valid')).to.be.false; }); }); diff --git a/packages/webawesome/src/components/select/select.ts b/packages/webawesome/src/components/select/select.ts index c853db514..cf2daae41 100644 --- a/packages/webawesome/src/components/select/select.ts +++ b/packages/webawesome/src/components/select/select.ts @@ -85,7 +85,7 @@ import styles from './select.css'; */ @customElement('wa-select') export default class WaSelect extends WebAwesomeFormAssociatedElement { - static shadowStyle = [appearanceStyles, formControlStyles, sizeStyles, styles]; + static css = [appearanceStyles, formControlStyles, sizeStyles, styles]; static get validators() { const validators = isServer @@ -740,7 +740,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement { super.updated(changedProperties); if (changedProperties.has('value')) { - this.toggleCustomState('blank', !this.value); + this.customStates.set('blank', !this.value); } } diff --git a/packages/webawesome/src/components/skeleton/skeleton.ts b/packages/webawesome/src/components/skeleton/skeleton.ts index 2eb831057..b0ec24066 100644 --- a/packages/webawesome/src/components/skeleton/skeleton.ts +++ b/packages/webawesome/src/components/skeleton/skeleton.ts @@ -17,7 +17,7 @@ import styles from './skeleton.css'; */ @customElement('wa-skeleton') export default class WaSkeleton extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; /** Determines which effect the skeleton will use. */ @property({ reflect: true }) effect: 'pulse' | 'sheen' | 'none' = 'none'; diff --git a/packages/webawesome/src/components/slider/slider.test.ts b/packages/webawesome/src/components/slider/slider.test.ts index f3a6b517f..99c92c9c2 100644 --- a/packages/webawesome/src/components/slider/slider.test.ts +++ b/packages/webawesome/src/components/slider/slider.test.ts @@ -133,18 +133,18 @@ describe('', () => { await slider.updateComplete; expect(slider.checkValidity()).to.be.false; - expect(slider.hasCustomState('invalid')).to.be.true; - expect(slider.hasCustomState('valid')).to.be.false; - expect(slider.hasCustomState('user-invalid')).to.be.false; - expect(slider.hasCustomState('user-valid')).to.be.false; + expect(slider.customStates.has('invalid')).to.be.true; + expect(slider.customStates.has('valid')).to.be.false; + expect(slider.customStates.has('user-invalid')).to.be.false; + expect(slider.customStates.has('user-valid')).to.be.false; await clickOnElement(slider); await slider.updateComplete; slider.blur(); await slider.updateComplete; - expect(slider.hasCustomState('user-invalid')).to.be.true; - expect(slider.hasCustomState('user-valid')).to.be.false; + expect(slider.customStates.has('user-invalid')).to.be.true; + expect(slider.customStates.has('user-valid')).to.be.false; }); it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => { @@ -154,10 +154,10 @@ describe('', () => { slider.setCustomValidity('Invalid value'); await slider.updateComplete; - expect(slider.hasCustomState('invalid')).to.be.true; - expect(slider.hasCustomState('valid')).to.be.false; - expect(slider.hasCustomState('user-invalid')).to.be.false; - expect(slider.hasCustomState('user-valid')).to.be.false; + expect(slider.customStates.has('invalid')).to.be.true; + expect(slider.customStates.has('valid')).to.be.false; + expect(slider.customStates.has('user-invalid')).to.be.false; + expect(slider.customStates.has('user-valid')).to.be.false; }); it('should be present in form data when using the form attribute and located outside of a ', async () => { diff --git a/packages/webawesome/src/components/slider/slider.ts b/packages/webawesome/src/components/slider/slider.ts index aa7bdb17c..00a724fe2 100644 --- a/packages/webawesome/src/components/slider/slider.ts +++ b/packages/webawesome/src/components/slider/slider.ts @@ -45,7 +45,7 @@ import styles from './slider.css'; */ @customElement('wa-slider') export default class WaSlider extends WebAwesomeFormAssociatedElement { - static shadowStyle = [formControlStyles, styles]; + static css = [formControlStyles, styles]; static get validators() { return [...super.validators, MirrorValidator()]; diff --git a/packages/webawesome/src/components/spinner/spinner.ts b/packages/webawesome/src/components/spinner/spinner.ts index b9a0b0ea9..2f2120453 100644 --- a/packages/webawesome/src/components/spinner/spinner.ts +++ b/packages/webawesome/src/components/spinner/spinner.ts @@ -19,7 +19,7 @@ import styles from './spinner.css'; */ @customElement('wa-spinner') export default class WaSpinner extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/split-panel/split-panel.ts b/packages/webawesome/src/components/split-panel/split-panel.ts index 951e1345e..157775913 100644 --- a/packages/webawesome/src/components/split-panel/split-panel.ts +++ b/packages/webawesome/src/components/split-panel/split-panel.ts @@ -35,7 +35,7 @@ import styles from './split-panel.css'; */ @customElement('wa-split-panel') export default class WaSplitPanel extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private cachedPositionInPixels: number; private isCollapsed = false; diff --git a/packages/webawesome/src/components/switch/switch.test.ts b/packages/webawesome/src/components/switch/switch.test.ts index c99724a55..4b831955a 100644 --- a/packages/webawesome/src/components/switch/switch.test.ts +++ b/packages/webawesome/src/components/switch/switch.test.ts @@ -230,12 +230,12 @@ describe('', () => { const el = await fixture(html` `); const waSwitch = el.querySelector('wa-switch')!; - expect(waSwitch.hasCustomState('required')).to.be.true; - expect(waSwitch.hasCustomState('optional')).to.be.false; - expect(waSwitch.hasCustomState('invalid')).to.be.true; - expect(waSwitch.hasCustomState('valid')).to.be.false; - expect(waSwitch.hasCustomState('user-invalid')).to.be.false; - expect(waSwitch.hasCustomState('user-valid')).to.be.false; + expect(waSwitch.customStates.has('required')).to.be.true; + expect(waSwitch.customStates.has('optional')).to.be.false; + expect(waSwitch.customStates.has('invalid')).to.be.true; + expect(waSwitch.customStates.has('valid')).to.be.false; + expect(waSwitch.customStates.has('user-invalid')).to.be.false; + expect(waSwitch.customStates.has('user-valid')).to.be.false; }); }); diff --git a/packages/webawesome/src/components/switch/switch.ts b/packages/webawesome/src/components/switch/switch.ts index 60833a78e..086714d28 100644 --- a/packages/webawesome/src/components/switch/switch.ts +++ b/packages/webawesome/src/components/switch/switch.ts @@ -50,7 +50,7 @@ import styles from './switch.css'; @customElement('wa-switch') export default class WaSwitch extends WebAwesomeFormAssociatedElement { static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true }; - static shadowStyle = [formControlStyles, sizeStyles, styles]; + static css = [formControlStyles, sizeStyles, styles]; static get validators() { return [...super.validators, MirrorValidator()]; @@ -170,7 +170,7 @@ export default class WaSwitch extends WebAwesomeFormAssociatedElement { this.input.checked = this.checked; // force a sync update } - this.toggleCustomState('checked', this.checked); + this.customStates.set('checked', this.checked); this.updateValidity(); } diff --git a/packages/webawesome/src/components/tab-group/tab-group.ts b/packages/webawesome/src/components/tab-group/tab-group.ts index 20f2df239..604986438 100644 --- a/packages/webawesome/src/components/tab-group/tab-group.ts +++ b/packages/webawesome/src/components/tab-group/tab-group.ts @@ -46,7 +46,7 @@ import styles from './tab-group.css'; */ @customElement('wa-tab-group') export default class WaTabGroup extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private activeTab?: WaTab; private mutationObserver: MutationObserver; diff --git a/packages/webawesome/src/components/tab-panel/tab-panel.ts b/packages/webawesome/src/components/tab-panel/tab-panel.ts index 4daa33f64..8f20e7a37 100644 --- a/packages/webawesome/src/components/tab-panel/tab-panel.ts +++ b/packages/webawesome/src/components/tab-panel/tab-panel.ts @@ -21,7 +21,7 @@ let id = 0; */ @customElement('wa-tab-panel') export default class WaTabPanel extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly attrId = ++id; private readonly componentId = `wa-tab-panel-${this.attrId}`; diff --git a/packages/webawesome/src/components/tab/tab.ts b/packages/webawesome/src/components/tab/tab.ts index 9e415ae5f..f698367bc 100644 --- a/packages/webawesome/src/components/tab/tab.ts +++ b/packages/webawesome/src/components/tab/tab.ts @@ -23,7 +23,7 @@ let id = 0; */ @customElement('wa-tab') export default class WaTab extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; private readonly attrId = ++id; private readonly componentId = `wa-tab-${this.attrId}`; diff --git a/packages/webawesome/src/components/tag/tag.ts b/packages/webawesome/src/components/tag/tag.ts index 356f2974f..89296bef0 100644 --- a/packages/webawesome/src/components/tag/tag.ts +++ b/packages/webawesome/src/components/tag/tag.ts @@ -28,7 +28,7 @@ import styles from './tag.css'; */ @customElement('wa-tag') export default class WaTag extends WebAwesomeElement { - static shadowStyle = [sizeStyles, variantStyles, appearanceStyles, styles]; + static css = [sizeStyles, variantStyles, appearanceStyles, styles]; private readonly localize = new LocalizeController(this); diff --git a/packages/webawesome/src/components/textarea/textarea.test.ts b/packages/webawesome/src/components/textarea/textarea.test.ts index cc135c21f..c9c449654 100644 --- a/packages/webawesome/src/components/textarea/textarea.test.ts +++ b/packages/webawesome/src/components/textarea/textarea.test.ts @@ -144,12 +144,12 @@ describe('', () => { const el = await fixture(html` `); expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.false; - expect(el.hasCustomState('valid')).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.false; + expect(el.customStates.has('valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; el.focus(); await sendKeys({ press: 'b' }); @@ -158,19 +158,19 @@ describe('', () => { await el.updateComplete; expect(el.checkValidity()).to.be.true; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.true; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.true; }); it('should receive the correct validation attributes ("states") when invalid', async () => { const el = await fixture(html` `); - expect(el.hasCustomState('required')).to.be.true; - expect(el.hasCustomState('optional')).to.be.false; - expect(el.hasCustomState('invalid')).to.be.true; - expect(el.hasCustomState('valid')).to.be.false; - expect(el.hasCustomState('user-invalid')).to.be.false; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('required')).to.be.true; + expect(el.customStates.has('optional')).to.be.false; + expect(el.customStates.has('invalid')).to.be.true; + expect(el.customStates.has('valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.false; + expect(el.customStates.has('user-valid')).to.be.false; el.focus(); await sendKeys({ press: 'a' }); @@ -179,8 +179,8 @@ describe('', () => { el.blur(); await el.updateComplete; - expect(el.hasCustomState('user-invalid')).to.be.true; - expect(el.hasCustomState('user-valid')).to.be.false; + expect(el.customStates.has('user-invalid')).to.be.true; + expect(el.customStates.has('user-valid')).to.be.false; }); it('should receive validation attributes ("states") even when novalidate is used on the parent form', async () => { @@ -189,12 +189,12 @@ describe('', () => { `); const textarea = el.querySelector('wa-textarea')!; - expect(textarea.hasCustomState('required')).to.be.true; - expect(textarea.hasCustomState('optional')).to.be.false; - expect(textarea.hasCustomState('invalid')).to.be.true; - expect(textarea.hasCustomState('valid')).to.be.false; - expect(textarea.hasCustomState('user-invalid')).to.be.false; - expect(textarea.hasCustomState('user-valid')).to.be.false; + expect(textarea.customStates.has('required')).to.be.true; + expect(textarea.customStates.has('optional')).to.be.false; + expect(textarea.customStates.has('invalid')).to.be.true; + expect(textarea.customStates.has('valid')).to.be.false; + expect(textarea.customStates.has('user-invalid')).to.be.false; + expect(textarea.customStates.has('user-valid')).to.be.false; }); }); @@ -237,10 +237,10 @@ describe('', () => { await textarea.updateComplete; expect(textarea.checkValidity()).to.be.false; - expect(textarea.hasCustomState('invalid')).to.be.true; - expect(textarea.hasCustomState('valid')).to.be.false; - expect(textarea.hasCustomState('user-invalid')).to.be.false; - expect(textarea.hasCustomState('user-valid')).to.be.false; + expect(textarea.customStates.has('invalid')).to.be.true; + expect(textarea.customStates.has('valid')).to.be.false; + expect(textarea.customStates.has('user-invalid')).to.be.false; + expect(textarea.customStates.has('user-valid')).to.be.false; textarea.focus(); await sendKeys({ type: 'test' }); @@ -248,8 +248,8 @@ describe('', () => { textarea.blur(); await textarea.updateComplete; - expect(textarea.hasCustomState('user-invalid')).to.be.true; - expect(textarea.hasCustomState('user-valid')).to.be.false; + expect(textarea.customStates.has('user-invalid')).to.be.true; + expect(textarea.customStates.has('user-valid')).to.be.false; }); it('should be present in form data when using the form attribute and located outside of a
', async () => { diff --git a/packages/webawesome/src/components/textarea/textarea.ts b/packages/webawesome/src/components/textarea/textarea.ts index 6e66a1600..812aab7b2 100644 --- a/packages/webawesome/src/components/textarea/textarea.ts +++ b/packages/webawesome/src/components/textarea/textarea.ts @@ -43,7 +43,7 @@ import styles from './textarea.css'; */ @customElement('wa-textarea') export default class WaTextarea extends WebAwesomeFormAssociatedElement { - static shadowStyle = [formControlStyles, appearanceStyles, sizeStyles, styles]; + static css = [formControlStyles, appearanceStyles, sizeStyles, styles]; static get validators() { return [...super.validators, MirrorValidator()]; @@ -270,7 +270,7 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement { super.updated(changedProperties); if (changedProperties.has('value')) { - this.toggleCustomState('blank', !this.value); + this.customStates.set('blank', !this.value); } } diff --git a/packages/webawesome/src/components/tooltip/tooltip.ts b/packages/webawesome/src/components/tooltip/tooltip.ts index 6e516ce22..edfec17fd 100644 --- a/packages/webawesome/src/components/tooltip/tooltip.ts +++ b/packages/webawesome/src/components/tooltip/tooltip.ts @@ -40,7 +40,7 @@ import styles from './tooltip.css'; */ @customElement('wa-tooltip') export default class WaTooltip extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; static dependencies = { 'wa-popup': WaPopup }; private hoverTimeout: number; diff --git a/packages/webawesome/src/components/tree-item/tree-item.test.ts b/packages/webawesome/src/components/tree-item/tree-item.test.ts index 43314fca0..9afc21f92 100644 --- a/packages/webawesome/src/components/tree-item/tree-item.test.ts +++ b/packages/webawesome/src/components/tree-item/tree-item.test.ts @@ -128,7 +128,7 @@ describe('', () => { await leafItem.updateComplete; // Assert - expect(leafItem.hasCustomState('selected')).to.be.true; + expect(leafItem.customStates.has('selected')).to.be.true; }); }); @@ -150,7 +150,7 @@ describe('', () => { await leafItem.updateComplete; // Assert - expect(leafItem.hasCustomState('expanded')).to.be.true; + expect(leafItem.customStates.has('expanded')).to.be.true; }); }); diff --git a/packages/webawesome/src/components/tree-item/tree-item.ts b/packages/webawesome/src/components/tree-item/tree-item.ts index be8973198..d9c4f1464 100644 --- a/packages/webawesome/src/components/tree-item/tree-item.ts +++ b/packages/webawesome/src/components/tree-item/tree-item.ts @@ -70,7 +70,7 @@ import styles from './tree-item.css'; */ @customElement('wa-tree-item') export default class WaTreeItem extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; static isTreeItem(node: Node) { return node instanceof Element && node.getAttribute('role') === 'treeitem'; @@ -188,23 +188,23 @@ export default class WaTreeItem extends WebAwesomeElement { @watch('disabled') handleDisabledChange() { - this.toggleCustomState('disabled', this.disabled); + this.customStates.set('disabled', this.disabled); this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false'); } @watch('expanded') handleExpandedState() { - this.toggleCustomState('expanded', this.expanded); + this.customStates.set('expanded', this.expanded); } @watch('indeterminate') handleIndeterminateStateChange() { - this.toggleCustomState('indeterminate', this.indeterminate); + this.customStates.set('indeterminate', this.indeterminate); } @watch('selected') handleSelectedChange() { - this.toggleCustomState('selected', this.selected); + this.customStates.set('selected', this.selected); this.setAttribute('aria-selected', this.selected ? 'true' : 'false'); } diff --git a/packages/webawesome/src/components/tree/tree.ts b/packages/webawesome/src/components/tree/tree.ts index 5fd03c906..5ed183752 100644 --- a/packages/webawesome/src/components/tree/tree.ts +++ b/packages/webawesome/src/components/tree/tree.ts @@ -73,7 +73,7 @@ function syncCheckboxes(changedTreeItem: WaTreeItem, initialSync = false) { */ @customElement('wa-tree') export default class WaTree extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @query('slot:not([name])') defaultSlot: HTMLSlotElement; @query('slot[name=expand-icon]') expandedIconSlot: HTMLSlotElement; diff --git a/packages/webawesome/src/components/viewport-demo/viewport-demo.ts b/packages/webawesome/src/components/viewport-demo/viewport-demo.ts index dcd278d19..a9287cad2 100644 --- a/packages/webawesome/src/components/viewport-demo/viewport-demo.ts +++ b/packages/webawesome/src/components/viewport-demo/viewport-demo.ts @@ -70,7 +70,7 @@ export const viewportPropertyConverter = { */ @customElement('wa-viewport-demo') export default class WaViewportDemo extends WebAwesomeElement { - static shadowStyle = styles; + static css = styles; @query('[part~=frame]') private viewportElement: HTMLElement; diff --git a/packages/webawesome/src/internal/test/form-control-base-tests.ts b/packages/webawesome/src/internal/test/form-control-base-tests.ts index 59acc5af8..51c6daa8a 100644 --- a/packages/webawesome/src/internal/test/form-control-base-tests.ts +++ b/packages/webawesome/src/internal/test/form-control-base-tests.ts @@ -184,7 +184,7 @@ function runAllValidityTests( control.customError = 'MyError'; await control.updateComplete; expect(control.validity.valid).to.equal(false); - expect(control.hasCustomState('invalid')).to.equal(true); + expect(control.customStates.has('invalid')).to.equal(true); expect(control.validationMessage).to.equal('MyError'); }); @@ -193,7 +193,7 @@ function runAllValidityTests( // expect(control.validity.valid).to.equal(true) control.setAttribute('custom-error', 'MyError'); await control.updateComplete; - expect(control.hasCustomState('invalid')).to.equal(true); + expect(control.customStates.has('invalid')).to.equal(true); expect(control.validationMessage).to.equal('MyError'); }); @@ -207,7 +207,7 @@ function runAllValidityTests( expect(control.disabled).to.equal(true); // expect(control.hasAttribute("disabled")).to.equal(false) expect(control.matches(':disabled')).to.equal(true); - expect(control.hasCustomState('disabled')).to.equal(true); + expect(control.customStates.has('disabled')).to.equal(true); fieldset.disabled = false; @@ -215,7 +215,7 @@ function runAllValidityTests( expect(control.disabled).to.equal(false); expect(control.hasAttribute('disabled')).to.equal(false); expect(control.matches(':disabled')).to.equal(false); - expect(control.hasCustomState('disabled')).to.equal(false); + expect(control.customStates.has('disabled')).to.equal(false); }); // it("This is the one edge case with ':disabled'. If you disable a fieldset, and then disable the element directly, it will not reflect the disabled attribute.", async () => { @@ -246,7 +246,7 @@ function runAllValidityTests( expect(control.disabled).to.equal(true); expect(control.hasAttribute('disabled')).to.equal(true); expect(control.matches(':disabled')).to.equal(true); - expect(control.hasCustomState('disabled')).to.equal(true); + expect(control.customStates.has('disabled')).to.equal(true); control.disabled = false; await control.updateComplete; @@ -254,7 +254,7 @@ function runAllValidityTests( expect(control.disabled).to.equal(false); expect(control.hasAttribute('disabled')).to.equal(false); expect(control.matches(':disabled')).to.equal(false); - expect(control.hasCustomState('disabled')).to.equal(false); + expect(control.customStates.has('disabled')).to.equal(false); }); } }); diff --git a/packages/webawesome/src/internal/webawesome-element.ts b/packages/webawesome/src/internal/webawesome-element.ts index 7984afed2..541d21959 100644 --- a/packages/webawesome/src/internal/webawesome-element.ts +++ b/packages/webawesome/src/internal/webawesome-element.ts @@ -1,7 +1,7 @@ import type { CSSResult, CSSResultGroup, PropertyValues } from 'lit'; import { LitElement, isServer, unsafeCSS } from 'lit'; import { property } from 'lit/decorators.js'; -import componentStyles from '../styles/component/host.css'; +import hostStyles from '../styles/component/host.css'; // Augment Lit's module declare module 'lit' { @@ -15,6 +15,31 @@ declare module 'lit' { } export default class WebAwesomeElement extends LitElement { + /** + * One or more CSS files to include in the component's shadow root. Host styles are automatically prepended. We use + * this instead of Lit's styles property because we're importing CSS files as strings and need to convert them using + * unsafeCSS. + */ + static css?: CSSResultGroup | CSSResult | string | (CSSResult | string)[]; + + /** + * Override the default styles property to fetch and convert string CSS files. Components can override this behavior + * by setting their own `static styles = []` property. + */ + static get styles(): CSSResultGroup { + const styles = Array.isArray(this.css) ? this.css : this.css ? [this.css] : []; + return [hostStyles, ...styles].map(style => (typeof style === 'string' ? unsafeCSS(style) : style)); + } + + #hasRecordedInitialProperties = false; + initialReflectedProperties: Map = new Map(); + internals: ElementInternals; + + // Make localization attributes reactive + @property() dir: string; + @property() lang: string; + @property({ type: Boolean, reflect: true, attribute: 'did-ssr' }) didSSR = isServer || Boolean(this.shadowRoot); + constructor() { super(); @@ -26,52 +51,16 @@ export default class WebAwesomeElement extends LitElement { console.error('Element internals are not supported in your browser. Consider using a polyfill'); } - this.toggleCustomState('wa-defined'); + this.customStates.set('wa-defined', true); let Self = this.constructor as typeof WebAwesomeElement; for (let [property, spec] of Self.elementProperties) { if (spec.default === 'inherit' && spec.initial !== undefined && typeof property === 'string') { - this.toggleCustomState(`initial-${property}-${spec.initial}`); + this.customStates.set(`initial-${property}-${spec.initial}`, true); } } } - // Make localization attributes reactive - @property() dir: string; - @property() lang: string; - - /** - * One or more styles for the element’s own shadow DOM. - * Shared component styles will automatically be added. - * If that is not desirable, the subclass can define its own styles property. - */ - static shadowStyle?: CSSResultGroup | CSSResult | string | (CSSResult | string)[]; - - /** The base styles property will only get called if the subclass does not define a styles property of its own */ - static get styles(): CSSResultGroup { - const shadowStyle = this.shadowStyle - ? Array.isArray(this.shadowStyle) - ? this.shadowStyle - : [this.shadowStyle] - : []; - - // Convert any string styles to Lit’s CSSResult - const shadowStyles = [componentStyles, ...shadowStyle].map(style => - typeof style === 'string' ? unsafeCSS(style) : style, - ); - - return shadowStyles; - } - - @property({ type: Boolean, reflect: true, attribute: 'did-ssr' }) didSSR = isServer || Boolean(this.shadowRoot); - - #hasRecordedInitialProperties = false; - - // Store the constructor value of all `static properties = {}` - initialReflectedProperties: Map = new Map(); - - internals: ElementInternals; - attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) { if (!this.#hasRecordedInitialProperties) { (this.constructor as typeof WebAwesomeElement).elementProperties.forEach( @@ -131,43 +120,26 @@ export default class WebAwesomeElement extends LitElement { } } - /** Checks if states are supported by the element */ - private hasStatesSupport(): boolean { - return Boolean(this.internals?.states); - } - - /** Adds a custom state to the element. */ - addCustomState(state: string) { - if (this.hasStatesSupport()) { - this.internals.states.add(state); - } - } - - /** Removes a custom state from the element. */ - deleteCustomState(state: string) { - if (this.hasStatesSupport()) { - this.internals.states.delete(state); - } - } - - /** Toggles a custom state on the element. */ - toggleCustomState(state: string, force?: boolean) { - if (typeof force === 'boolean') { - if (force) { - this.addCustomState(state); + /** + * Methods for setting and checking custom states. + */ + public customStates = { + /** Adds or removes the specified custom state. */ + set: (customState: string, active: boolean) => { + if (!Boolean(this.internals?.states)) return; + if (active) { + this.internals.states.add(customState); } else { - this.deleteCustomState(state); + this.internals.states.delete(customState); } - return; - } + }, - this.toggleCustomState(state, !this.hasCustomState(state)); - } - - /** Determines if the element has the specified custom state. */ - hasCustomState(state: string): boolean { - return this.hasStatesSupport() ? this.internals.states.has(state) : false; - } + /** Determines whether or not the element currently has the specified state. */ + has: (customState: string) => { + if (!Boolean(this.internals?.states)) return false; + return this.internals.states.has(customState); + }, + }; /** * Given a native event, this function cancels it and dispatches it again from the host element using the desired diff --git a/packages/webawesome/src/internal/webawesome-form-associated-element.ts b/packages/webawesome/src/internal/webawesome-form-associated-element.ts index 0d30016fb..f84116325 100644 --- a/packages/webawesome/src/internal/webawesome-form-associated-element.ts +++ b/packages/webawesome/src/internal/webawesome-form-associated-element.ts @@ -172,7 +172,7 @@ export class WebAwesomeFormAssociatedElement } if (changedProperties.has('disabled')) { - this.toggleCustomState('disabled', this.disabled); + this.customStates.set('disabled', this.disabled); if (this.hasAttribute('disabled') || (!isServer && !this.matches(':disabled'))) { this.toggleAttribute('disabled', this.disabled); @@ -255,12 +255,12 @@ export class WebAwesomeFormAssociatedElement const isValid = this.internals.validity.valid; const hasInteracted = this.hasInteracted; - this.toggleCustomState('required', required); - this.toggleCustomState('optional', !required); - this.toggleCustomState('invalid', !isValid); - this.toggleCustomState('valid', isValid); - this.toggleCustomState('user-invalid', !isValid && hasInteracted); - this.toggleCustomState('user-valid', isValid && hasInteracted); + this.customStates.set('required', required); + this.customStates.set('optional', !required); + this.customStates.set('invalid', !isValid); + this.customStates.set('valid', isValid); + this.customStates.set('user-invalid', !isValid && hasInteracted); + this.customStates.set('user-valid', isValid && hasInteracted); } /**