From e1bf5471bf56254a46466d1b8321dbe490c91e21 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Thu, 23 Jan 2025 17:52:41 -0500 Subject: [PATCH 001/194] Use native events when possible (#590) * fix filename * input + change (change not working) * compose that horribly misleading change event * use native blur/focus events * update checkbox * update color picker events * update color picker events * update radio group events * update button events * remove event options * update select events * update image comparer events * update icon button events * update slider events * update rating events * update radio events * update switch event * update textarea events * update radio button events * remove unused events * cleanup * fix react wrappers * fix react events for real this time * update changelog * add note * Update src/components/input/input.ts Co-authored-by: Lea Verou * delete unused close event * use same event type * fix tests * remove wa- from events in docs and examples * fix comment * Update docs/docs/resources/changelog.md Co-authored-by: Lea Verou --------- Co-authored-by: Lea Verou --- docs/_layouts/theme.njk | 2 +- docs/assets/scripts/filter.js | 2 +- docs/assets/scripts/theme-picker.js | 2 +- docs/docs/components/animation.md | 6 +- docs/docs/components/carousel.md | 4 +- docs/docs/components/cheatsheet/cheatsheet.js | 2 +- docs/docs/components/checkbox.md | 2 +- docs/docs/components/format-bytes.md | 2 +- docs/docs/components/format-number.md | 2 +- docs/docs/components/popup.md | 42 ++++----- docs/docs/components/qr-code.md | 2 +- docs/docs/components/radio-group.md | 4 +- docs/docs/components/split-panel.md | 2 +- docs/docs/components/tree.md | 2 +- docs/docs/experimental/themer.md | 40 ++++---- docs/docs/form-controls.md | 2 +- docs/docs/resources/changelog.md | 5 + docs/docs/usage.md | 17 +--- scripts/make-react.js | 10 +- src/components/button/button.test.ts | 6 +- src/components/button/button.ts | 18 +--- src/components/checkbox/checkbox.test.ts | 18 ++-- src/components/checkbox/checkbox.ts | 31 ++---- .../color-picker/color-picker.test.ts | 94 +++++++++---------- src/components/color-picker/color-picker.ts | 82 ++++++++-------- .../icon-button/icon-button.test.ts | 6 +- src/components/icon-button/icon-button.ts | 18 +--- .../image-comparer/image-comparer.test.ts | 2 +- .../image-comparer/image-comparer.ts | 5 +- src/components/input/input.test.ts | 32 +++---- src/components/input/input.ts | 35 ++----- src/components/radio-button/radio-button.ts | 18 +--- .../radio-group/radio-group.test.ts | 31 +++--- src/components/radio-group/radio-group.ts | 16 ++-- src/components/radio/radio.ts | 18 +--- src/components/rating/rating.test.ts | 16 ++-- src/components/rating/rating.ts | 9 +- src/components/select/select.test.ts | 38 ++++---- src/components/select/select.ts | 38 +++----- src/components/slider/slider.test.ts | 24 ++--- src/components/slider/slider.ts | 21 ++--- src/components/switch/switch.test.ts | 30 +++--- src/components/switch/switch.ts | 39 ++------ src/components/textarea/textarea.test.ts | 20 ++-- src/components/textarea/textarea.ts | 27 ++---- src/events/blur.ts | 11 --- src/events/change.ts | 11 --- src/events/close.ts | 11 --- src/events/events.ts | 5 - src/events/focus.ts | 11 --- src/events/input.ts | 11 --- src/internal/test/form-control-base-tests.ts | 2 +- .../validators/custom-error-validator.ts | 2 +- src/internal/validators/mirror-validator.ts | 2 +- src/internal/validators/required-validator.ts | 2 +- src/internal/webawesome-element.ts | 11 +++ ... => webawesome-form-associated-element.ts} | 4 +- 57 files changed, 365 insertions(+), 560 deletions(-) delete mode 100644 src/events/blur.ts delete mode 100644 src/events/change.ts delete mode 100644 src/events/close.ts delete mode 100644 src/events/focus.ts delete mode 100644 src/events/input.ts rename src/internal/{webawesome-formassociated-element.ts => webawesome-form-associated-element.ts} (99%) diff --git a/docs/_layouts/theme.njk b/docs/_layouts/theme.njk index d890c2406..dfa90a01c 100644 --- a/docs/_layouts/theme.njk +++ b/docs/_layouts/theme.njk @@ -49,7 +49,7 @@

+ +``` \ No newline at end of file diff --git a/docs/_includes/visual-tests/appearance.njk b/docs/_includes/visual-tests/appearance.njk new file mode 100644 index 000000000..d42c2c935 --- /dev/null +++ b/docs/_includes/visual-tests/appearance.njk @@ -0,0 +1,799 @@ +

Badge

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appearance="".wa-[appearance]
accent + outlined + + + +
accent + + + +
filled + outlined + + + +
filled + + + +
outlined + + + +
plain + + + +
+
+ + +

Button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appearance="".wa-[appearance]
accent + outlined + + + +
accent + + + +
filled + outlined + + + +
filled + + + +
outlined + + + +
plain + + + +
+
+ + +

Callout

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appearance="".wa-[appearance]
accent + outlined + + + +
accent + + + +
filled + outlined + + + +
filled + + + +
outlined + + + +
plain + + + +
+
+ + +

Tag

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
appearance="".wa-[appearance]
accent + outlined + + + +
accent + + + +
filled + outlined + + + +
filled + + + +
outlined + + + +
plain + + + +
+
+ + +

Form Controls

+ +
+ + + + + + + + + + + + + + + + + + +
appearance="".wa-[appearance]
outlined + + + +
filled + + + +
+
\ No newline at end of file diff --git a/docs/_includes/visual-tests/color.njk b/docs/_includes/visual-tests/color.njk new file mode 100644 index 000000000..ca06fcbf5 --- /dev/null +++ b/docs/_includes/visual-tests/color.njk @@ -0,0 +1,698 @@ +

Badge

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variant="".wa-[variant]
brand + + + +
neutral + + + +
success + + + +
warning + + + +
danger + + + +
+
+ + +

Button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variant="".wa-[variant]
brand + + + +
neutral + + + +
success + + + +
warning + + + +
danger + + + +
+
+ + +

Callout

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variant="".wa-[variant]
brand + + + +
neutral + + + +
success + + + +
warning + + + +
danger + + + +
+
+ + +

Tag

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variant="".wa-[variant]
brand + + + +
neutral + + + +
success + + + +
warning + + + +
danger + + + +
+
\ No newline at end of file diff --git a/docs/_includes/visual-tests/harmony.njk b/docs/_includes/visual-tests/harmony.njk new file mode 100644 index 000000000..e6c58112f --- /dev/null +++ b/docs/_includes/visual-tests/harmony.njk @@ -0,0 +1,32 @@ +

Form Controls

+ +```html {.example} + +``` + +

Progress

+ +```html {.example} + +``` \ No newline at end of file diff --git a/docs/_includes/visual-tests/native.njk b/docs/_includes/visual-tests/native.njk new file mode 100644 index 000000000..789d29337 --- /dev/null +++ b/docs/_includes/visual-tests/native.njk @@ -0,0 +1,745 @@ +

Button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<wa-button><button>.wa-button
default + Button + + + + +
.wa-brand + + + + + +
.wa-neutral + + + + + +
.wa-success + + + + + +
.wa-warning + + + + + +
.wa-danger + + + + + +
.wa-accent + + + + + +
.wa-filled + + + + + +
.wa-outlined + + + + + +
.wa-plain + + + + + +
.wa-size-s + + + + + +
.wa-size-m + + + + + +
.wa-size-l + + + + + +
.wa-pill + + + + + +
+
+ + +

Callout

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<wa-callout>.wa-callout
default + Callout + + +
.wa-brand + + + +
.wa-neutral + + + +
.wa-success + + + +
.wa-warning + + + +
.wa-danger + + + +
.wa-accent + + + +
.wa-filled + + + +
.wa-outlined + + + +
.wa-plain + + + +
.wa-size-s + + + +
.wa-size-m + + + +
.wa-size-l + + + +
.wa-pill + + + +
+
+ + +

Checkbox

+ +
+ + + + + + + + + + + + + + + + + + +
<wa-checkbox><input type="checkbox">
default + Checkbox + + +
checked + Checkbox + + +
+
+ + +

Color Picker

+ +
+ + + + + + + + + + + + + +
<wa-color-picker><input type="color">
default + + + +
+
+ + +

Details

+ +
+ + + + + + + + + + + + + + + + + + +
<wa-details><details>
default + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + + +
+ Summary +

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

+
+
dir="rtl" + + استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن + + +
+ تبديلني +

استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن

+
+
+
+ + +

Input

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<wa-input><input>
default + + + +
type="password" + + + +
type="date" + + + +
type="time" + + + +
.wa-filled + + + +
.wa-size-s + + + +
.wa-size-m + + + +
.wa-size-l + + + +
+
+ + +

Progress Bar

+ +
+ + + + + + + + + + + + + +
<wa-progress-bar><progress>
default + + + +
+
+ + +

Radio

+ +
+ + + + + + + + + + + + + + + + + + +
<wa-radio><input type="radio">
default + Radio + + +
checked + + Radio + + + +
+
+ + +

Select

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<wa-select><select>
default + + Option + + + +
.wa-filled + + + +
.wa-size-s + + + +
.wa-size-m + + + +
.wa-size-l + + + +
+
+ + +

Slider

+ +
+ + + + + + + + + + + + + +
<wa-slider><input type="range">
default + + + +
+
+ + +

Textarea

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
<wa-textarea><textarea>
default + + + +
.wa-filled + + + +
.wa-size-s + + + +
.wa-size-m + + + +
.wa-size-l + + + +
+
\ No newline at end of file diff --git a/docs/_includes/visual-tests/size.njk b/docs/_includes/visual-tests/size.njk new file mode 100644 index 000000000..42ec56d62 --- /dev/null +++ b/docs/_includes/visual-tests/size.njk @@ -0,0 +1,562 @@ +

Button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + Button + + +
medium/m + Button + + +
large/l + Button + + +
+
+ + +

Callout

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + + Callout + + + +
medium/m + + + Callout + + + +
large/l + + + Callout + + + +
+
+ + +

Checkbox

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + Checkbox + + +
medium/m + Checkbox + + +
large/l + Checkbox + + +
+
+ + +

Color Picker

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + + +
medium/m + + + +
large/l + + + +
+
+ + +

Input

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + + +
medium/m + + + +
large/l + + + +
+
+ + +

Radio

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + Radio + + +
medium/m + Radio + + +
large/l + Radio + + +
+
+ + +

Radio Button

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + Radio + Button + + + + + + +
medium/m + + Radio + Button + + + + + + +
large/l + + Radio + Button + + + + + + +
+
+ + +

Radio Group

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + + +
medium/m + + + +
large/l + + + +
+
+ + +

Select

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + Option + + + +
medium/m + + Option + + + +
large/l + + Option + + + +
+
+ + +

Switch

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + Switch + + +
medium/m + Switch + + +
large/l + Switch + + +
+
+ + +

Textarea

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + + +
medium/m + + + +
large/l + + + +
+
\ No newline at end of file diff --git a/docs/docs/experimental/sandbox.md b/docs/docs/experimental/sandbox.md deleted file mode 100644 index 39617cfc5..000000000 --- a/docs/docs/experimental/sandbox.md +++ /dev/null @@ -1,352 +0,0 @@ ---- -title: Theming Sandbox -description: TODO -layout: page-outline ---- - -## Card - -```html {.example} - - A kitten sits patiently between a terracotta pot and decorative grasses. - - Mittens
- This kitten is as cute as he is playful. Bring him home today!
- 6 weeks old - -
- More Info - -
-
- - -``` - -## Alerts - -```html {.example} - - - This is super informative
- You can tell by how pretty the alert is. -
-
- - - Your changes have been saved
- You can safely exit the app now. -
-
- - - Your settings have been updated
- Settings will take affect on next login. -
-
- - - Your session has ended
- Please login again to continue. -
-
- - - Your account has been deleted
- We're very sorry to see you go! -
-``` - -## Badges and Tags - -```html {.example} -Brand -Success -Neutral -Warning -Danger -
-Brand -Success -Neutral -Warning -Danger -``` - -## Buttons - -```html {.example} -Brand -Success -Neutral -Warning -Danger -

-Brand -Success -Neutral -Warning -Danger -

-Text -

- - Option 1 - Option 2 - Option 3 - -``` - -## Form controls - -```html {.example} -Unchecked -
-Checked -

- - Option 1 - Option 2 - Option 3 - -
-Switch off -
-Switch on -

- -

- -
- - Option 1 - Option 2 - Option 3 - Option 4 - Option 5 - Option 6 - -``` - -## Progress - -```html {.example} - - - -``` - -## Shadows - -```html {.example} - -
-
-
-``` - -## Alignment Tests - -```html {.example} - -
-
- OCBS - OCBS - OCBS -
-
- OCBS - OCBS - OCBS -
-
- OCBS - OCBS - OCBS -
-
- - - OCBS - - - OCBS -
-
- - - OCBS - - - OCBS -
-
- - - OCBS - - - OCBS -
-
- OCBS - - - - - - -
-
- - - OCBS - - -
-
-``` - -## Custom Property Tests - -```html {.example} - - - -``` - -## Text Controls Tests - -```html {.example} -
- - - - - - Option 1 - Option 2 - Option 3 - Option 4 - - - - -
-``` \ No newline at end of file diff --git a/docs/docs/resources/visual-tests.md b/docs/docs/resources/visual-tests.md new file mode 100644 index 000000000..2be337617 --- /dev/null +++ b/docs/docs/resources/visual-tests.md @@ -0,0 +1,115 @@ +--- +title: Visual Tests +description: TODO +layout: page +wide: true +--- + + + +With so many ways to build with and use Web Awesome components, visual tests help ensure consistency and prevent broken styles from leaking into production. + +These tests can come in handy when creating or customizing your own theme. Look through each test case to make sure that custom styles in your theme cover all of the attributes, utilities, and built-in styles Web Awesome offers. + +Known test failures that affect the entire library, regardless of theme, are indicated by and will be addressed in a future release. + + + Appearance + Alignment + Color + Harmony + Native Styles + Size + + + +## Appearance + +Appearance tests ensure that both the `appearance` attribute and `.wa-[appearance]` classes have identical results for components that support them. Developers should be able to use both of these interchangeably on components to get the intended look and feel. + +{% include 'visual-tests/appearance.njk' %} + + + + + +## Alignment + +Alignment tests reveal the top boundary, vertical center, and bottom boundary of components. These help to evaluate how well components align with one another when arranged horizontally. + +{% include 'visual-tests/alignment.njk' %} + + + + + +## Color + +Color tests ensure that both the `variant` attribute and `.wa-[variant]` classes have identical results for components that support them. Developers should be able to use both of these interchangeably to give the component the intended semantic color. + +{% include 'visual-tests/color.njk' %} + + + + + +## Harmony + +Harmony tests show how related components look together. These can help validate design choices or reveal where design intervention is needed to get a consistent, harmonious look and feel. + +{% include 'visual-tests/harmony.njk' %} + + + + + +## Native Styles + +Native styles tests ensure that supported native elements and component utilities look the same as their Web Awesome component counterparts. Native elements and component utilities may also support the same [appearance](/docs/utilities/appearance/), [color](/docs/utilities/color/), and [size](/docs/utilities/size/) utilities as components. + +{% include 'visual-tests/native.njk' %} + + + + + +## Size + +Size tests ensure that both the `size` attribute and `.wa-size-[s|m|l]` classes have identical results for components that support them. Developers should be able to use both of these interchangeably on components to get the intended size. + +{% include 'visual-tests/size.njk' %} + + + + \ No newline at end of file From 3c70c44b8a1c3a6007452e6c33778181a1842e41 Mon Sep 17 00:00:00 2001 From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:56:09 -0500 Subject: [PATCH 011/194] Use flex columns for form controls, fixes #629 (#636) * Use flex columns for form controls * Touch up spacing in color picker example * Use consistent `display` for related form controls --- docs/docs/components/color-picker.md | 8 +++++--- src/components/color-picker/color-picker.css | 2 -- src/components/input/input.css | 2 -- src/components/select/select.css | 4 ---- src/components/switch/switch.css | 2 +- src/components/textarea/textarea.css | 1 - src/styles/shadow/form-control.css | 5 +++++ 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/docs/components/color-picker.md b/docs/docs/components/color-picker.md index b002366d7..2bce6504d 100644 --- a/docs/docs/components/color-picker.md +++ b/docs/docs/components/color-picker.md @@ -66,9 +66,11 @@ Use the `swatches` attribute to add convenient presets to the color picker. Any Use the `size` attribute to change the color picker's trigger size. ```html {.example} - - - + ``` ### Disabled diff --git a/src/components/color-picker/color-picker.css b/src/components/color-picker/color-picker.css index d1ce7a419..fa7e6ad18 100644 --- a/src/components/color-picker/color-picker.css +++ b/src/components/color-picker/color-picker.css @@ -15,8 +15,6 @@ --swatch-border-radius: var(--wa-border-radius-m); --swatch-size: 1.5rem; --trigger-border-radius: var(--wa-border-radius-circle); - - display: inline-block; } .color-picker { diff --git a/src/components/input/input.css b/src/components/input/input.css index 2b0c96392..15ad742e9 100644 --- a/src/components/input/input.css +++ b/src/components/input/input.css @@ -1,6 +1,4 @@ :host { - display: flex; - flex-flow: column; border-width: 0; } diff --git a/src/components/select/select.css b/src/components/select/select.css index b0e45537a..7c6f166d2 100644 --- a/src/components/select/select.css +++ b/src/components/select/select.css @@ -1,7 +1,3 @@ -:host { - display: block; -} - /** The popup */ .select { flex: 1 1 auto; diff --git a/src/components/switch/switch.css b/src/components/switch/switch.css index 6a8107dce..7651f5cee 100644 --- a/src/components/switch/switch.css +++ b/src/components/switch/switch.css @@ -13,7 +13,7 @@ --thumb-size: calc((var(--height) - var(--border-width) * 2) * 0.75); --width: calc(var(--height) * 1.75); - display: inline-block; + display: inline-flex; } label { diff --git a/src/components/textarea/textarea.css b/src/components/textarea/textarea.css index 413e53aaf..338240a1b 100644 --- a/src/components/textarea/textarea.css +++ b/src/components/textarea/textarea.css @@ -1,5 +1,4 @@ :host { - display: block; border-width: 0; } diff --git a/src/styles/shadow/form-control.css b/src/styles/shadow/form-control.css index ed8ebc08d..02ec67ce1 100644 --- a/src/styles/shadow/form-control.css +++ b/src/styles/shadow/form-control.css @@ -1,3 +1,8 @@ +:host { + display: flex; + flex-direction: column; +} + /* Label */ :is([part~='form-control-label'], [part~='label']):has(*:not(:empty)) { display: inline-block; From b89ee673e6698325adf71a9103cd100ac58ac146 Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Wed, 29 Jan 2025 17:57:16 -0500 Subject: [PATCH 012/194] Fix `` form submit behavior (#637) * fix textarea form submit behavior * add test --- docs/docs/components/textarea.md | 6 +++++- docs/docs/resources/changelog.md | 1 + src/components/textarea/textarea.test.ts | 15 +++++++++++++++ src/components/textarea/textarea.ts | 6 +++--- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/docs/components/textarea.md b/docs/docs/components/textarea.md index c86c7dd24..7af557eba 100644 --- a/docs/docs/components/textarea.md +++ b/docs/docs/components/textarea.md @@ -7,7 +7,11 @@ native: input --- ```html {.example} - +
+ + + +
``` :::info diff --git a/docs/docs/resources/changelog.md b/docs/docs/resources/changelog.md index 8ed6d487b..fa5919efd 100644 --- a/docs/docs/resources/changelog.md +++ b/docs/docs/resources/changelog.md @@ -23,6 +23,7 @@ During the alpha period, things might break! We take breaking changes very serio - Added the `orientation` attribute to `` to support vertical and horizontal radio items - Fixed a bug in `` that prevented nested tab groups from working properly - Fixed slot names for `show-password-icon` and `hide-password-icon` in `` to more intuitively represent their functions +- Fixed a bug in `` that caused empty controls to submit a value if the initial value was deleted a certain way ## 3.0.0-alpha.9 diff --git a/src/components/textarea/textarea.test.ts b/src/components/textarea/textarea.test.ts index b5339e8f5..cc135c21f 100644 --- a/src/components/textarea/textarea.test.ts +++ b/src/components/textarea/textarea.test.ts @@ -199,6 +199,21 @@ describe('', () => { }); describe('when submitting a form', () => { + it('should submit an empty value when initial value is set and then deleted', async () => { + const form = await fixture(html` +
+ `); + const textarea = form.querySelector('wa-textarea')!; + + textarea.focus(); + textarea.select(); + await sendKeys({ press: 'Backspace' }); + await textarea.updateComplete; + + const formData = new FormData(form); + expect(formData.get('a')).to.equal(''); + }); + it('should serialize its name and value with FormData', async () => { const form = await fixture(html`
diff --git a/src/components/textarea/textarea.ts b/src/components/textarea/textarea.ts index cb2c3a1b1..d92c6dc7a 100644 --- a/src/components/textarea/textarea.ts +++ b/src/components/textarea/textarea.ts @@ -63,7 +63,7 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement { /** The name of the textarea, submitted as a name/value pair with form data. */ @property({ reflect: true }) name: string | null = null; - private _value: string = ''; + private _value: string | null = null; /** The current value of the input, submitted as a name/value pair with form data. */ get value() { @@ -71,11 +71,11 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement { return this._value; } - return this._value || this.defaultValue; + return this._value ?? this.defaultValue; } @state() - set value(val: string) { + set value(val: string | null) { if (this._value === val) { return; } From aeb25f3a7d44e74d3d3ae2c170d6b96b88166ca2 Mon Sep 17 00:00:00 2001 From: Lea Verou Date: Wed, 29 Jan 2025 16:22:50 -0800 Subject: [PATCH 013/194] Infrastructure for inheritable props, make `variant` inherit (#582) Fixes #454, fixes #592 Co-authored-by: lindsaym-fa --- docs/docs/experimental/inherit.md | 84 ++++++++++++++++++ src/components/badge/badge.test.ts | 3 +- src/components/badge/badge.ts | 10 ++- src/components/button/button.test.ts | 30 +++---- src/components/button/button.ts | 5 +- src/components/callout/callout.ts | 10 ++- src/components/tag/tag.test.ts | 3 +- src/components/tag/tag.ts | 10 ++- src/internal/webawesome-element.ts | 84 +++++++++++++----- src/styles/utilities/variants.css | 127 ++++++++++++++++++++++++--- src/styles/utilities/variants.css.js | 68 ++++++++++++++ 11 files changed, 374 insertions(+), 60 deletions(-) create mode 100644 docs/docs/experimental/inherit.md create mode 100644 src/styles/utilities/variants.css.js diff --git a/docs/docs/experimental/inherit.md b/docs/docs/experimental/inherit.md new file mode 100644 index 000000000..88d5788d0 --- /dev/null +++ b/docs/docs/experimental/inherit.md @@ -0,0 +1,84 @@ +--- +title: Inheritance & Default value tests +wide: true +--- + +## Variant + +{%- set variantDefaults = { + button: 'neutral', + tag: 'neutral', + badge: 'brand', + callout: 'brand' +} %} +{%- set variants = ['', 'neutral', 'brand'] %} + +### Defaults + +```html {.example} + + + + + + + + + + {% for element, default in variantDefaults %} + + + + + + + {% endfor %} +
ElementDefaultNeutralBrand
{{ element | capitalize }}{{ default | capitalize }}NeutralBrand
+``` + +### Nested elements + +{% set containers = [ + {parent: 'callout', child: 'button'}, + {parent: 'callout', child: 'callout'}, + {parent: 'button', child: 'badge'} +] %} + +{% for container in containers %} +{% set parent = container.parent %} +{% set child = container.child %} + +#### {{ child | capitalize }} in {{ parent | capitalize }} + +```html {.example} + + + + {% if parent == child -%} + + {% else %} + + {%- endif %} + + + + + + {% for parentVariant in variants %} + {% set parentContent = (parentVariant | capitalize or 'Default') if parent == 'button' %} + + + + {% for childVariant in variants -%} + {% set childContent = (childVariant or parentVariant or variantDefaults[child]) | capitalize %} + {% set childContent = childContent[0] if child == 'badge' else childContent %} + + {% endfor %} + + {% endfor %} +
👇 Parent / Child 👉👇 {{ parent | capitalize }} / {{ child | capitalize }} 👉DefaultNeutralBrand
{{ parentVariant | capitalize or 'Default' }} + {{ parentContent }} + {{ childContent }} +
+``` +{% endfor %} diff --git a/src/components/badge/badge.test.ts b/src/components/badge/badge.test.ts index 868f68531..034955f14 100644 --- a/src/components/badge/badge.test.ts +++ b/src/components/badge/badge.test.ts @@ -23,7 +23,8 @@ describe('', () => { it('should default to square styling, with the brand color', async () => { const el = await fixture(html` Badge `); - expect(el.getAttribute('variant')).to.eq('brand'); + expect(el.getAttribute('variant')).to.eq(null); + expect(el.variant).to.eq('inherit'); }); }); diff --git a/src/components/badge/badge.ts b/src/components/badge/badge.ts index ee0736dd8..8d6d8413e 100644 --- a/src/components/badge/badge.ts +++ b/src/components/badge/badge.ts @@ -26,8 +26,14 @@ import styles from './badge.css'; export default class WaBadge extends WebAwesomeElement { static shadowStyle = [variantStyles, appearanceStyles, styles]; - /** The badge's theme variant. */ - @property({ reflect: true }) variant: 'brand' | 'success' | 'neutral' | 'warning' | 'danger' = 'brand'; + /** The badge's theme variant. Defaults to `brand` if not within another element with a variant. */ + @property({ reflect: true, initial: 'brand' }) variant: + | 'brand' + | 'neutral' + | 'success' + | 'warning' + | 'danger' + | 'inherit' = 'inherit'; /** The badge's visual appearance. */ @property({ reflect: true }) appearance: 'accent' | 'filled' | 'outlined' = 'accent'; diff --git a/src/components/button/button.test.ts b/src/components/button/button.test.ts index b2e2e0328..ef447f58a 100644 --- a/src/components/button/button.test.ts +++ b/src/components/button/button.test.ts @@ -45,20 +45,20 @@ describe('', () => { }); describe('when an attribute is removed', () => { - it("should return to 'neutral' when attribute removed with no initial attribute", async () => { + it("should return to 'inherit' when attribute removed with no initial attribute", async () => { const el = await fixture(html`Button label`); - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); el.removeAttribute('variant'); await el.updateComplete; - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); }); - it("should return to 'neutral' when attribute removed with an initial attribute", async () => { + it("should return to 'inherit' when attribute removed with an initial attribute", async () => { const el = await fixture(html`Button label`); expect(el.variant).to.equal('primary'); @@ -67,8 +67,8 @@ describe('', () => { el.removeAttribute('variant'); await el.updateComplete; - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); }); }); @@ -76,15 +76,15 @@ describe('', () => { it("should return to 'default' when property set to null with no initial attribute", async () => { const el = await fixture(html`Button label`); - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); // @ts-expect-error Its a test. Stop. el.variant = null; await el.updateComplete; - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); }); it("should return to 'default' when property set to null with an initial attribute", async () => { @@ -97,8 +97,8 @@ describe('', () => { el.variant = null; await el.updateComplete; - expect(el.variant).to.equal('neutral'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); + expect(el.getAttribute('variant')).to.equal(null); }); }); @@ -112,7 +112,7 @@ describe('', () => { const el = await fixture(html` Button Label `); expect(el.title).to.equal(''); - expect(el.variant).to.equal('neutral'); + expect(el.variant).to.equal('inherit'); expect(el.appearance).to.equal('accent'); expect(el.size).to.equal('medium'); expect(el.disabled).to.equal(false); diff --git a/src/components/button/button.ts b/src/components/button/button.ts index 0344c07c4..07c1326e8 100644 --- a/src/components/button/button.ts +++ b/src/components/button/button.ts @@ -66,8 +66,9 @@ export default class WaButton extends WebAwesomeFormAssociatedElement { @state() invalid = false; @property() title = ''; // make reactive to pass through - /** The button's theme variant. */ - @property({ reflect: true }) variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral'; + /** The button's theme variant. Defaults to `neutral` if not within another element with a variant. */ + @property({ reflect: true, initial: 'neutral' }) + variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' | 'inherit' = 'inherit'; /** The button's visual appearance. */ @property({ reflect: true, default: 'accent' }) diff --git a/src/components/callout/callout.ts b/src/components/callout/callout.ts index c04bb9d31..463c2bb59 100644 --- a/src/components/callout/callout.ts +++ b/src/components/callout/callout.ts @@ -27,8 +27,14 @@ import styles from './callout.css'; export default class WaCallout extends WebAwesomeElement { static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles]; - /** The callout's theme variant. */ - @property({ reflect: true }) variant: 'brand' | 'success' | 'neutral' | 'warning' | 'danger' = 'brand'; + /** The callout's theme variant. Defaults to `brand` if not within another element with a variant. */ + @property({ reflect: true, initial: 'brand' }) variant: + | 'brand' + | 'neutral' + | 'success' + | 'warning' + | 'danger' + | 'inherit' = 'inherit'; /** The callout's visual appearance. */ @property({ reflect: true }) appearance: diff --git a/src/components/tag/tag.test.ts b/src/components/tag/tag.test.ts index 74d054427..40419967a 100644 --- a/src/components/tag/tag.test.ts +++ b/src/components/tag/tag.test.ts @@ -10,7 +10,8 @@ describe('', () => { it('should render default tag', async () => { const el = await fixture(html` Test `); expect(el.getAttribute('size')).to.equal('medium'); - expect(el.getAttribute('variant')).to.equal('neutral'); + expect(el.getAttribute('variant')).to.equal(null); + expect(el.variant).to.equal('inherit'); }); it('should set variant by attribute', async () => { diff --git a/src/components/tag/tag.ts b/src/components/tag/tag.ts index 97353e89a..c1dbbfc52 100644 --- a/src/components/tag/tag.ts +++ b/src/components/tag/tag.ts @@ -32,8 +32,14 @@ export default class WaTag extends WebAwesomeElement { private readonly localize = new LocalizeController(this); - /** The tag's theme variant. */ - @property({ reflect: true }) variant: 'brand' | 'success' | 'neutral' | 'warning' | 'danger' | 'text' = 'neutral'; + /** The tag's theme variant. Defaults to `neutral` if not within another element with a variant. */ + @property({ reflect: true, initial: 'neutral' }) variant: + | 'brand' + | 'neutral' + | 'success' + | 'warning' + | 'danger' + | 'inherit' = 'inherit'; /** The tag's visual appearance. */ @property({ reflect: true }) appearance: 'accent' | 'outlined accent' | 'filled' | 'outlined' | 'outlined filled' = diff --git a/src/internal/webawesome-element.ts b/src/internal/webawesome-element.ts index 199d81db5..6d5775ea8 100644 --- a/src/internal/webawesome-element.ts +++ b/src/internal/webawesome-element.ts @@ -10,6 +10,7 @@ declare module 'lit' { * Specifies the property’s default value */ default?: any; + initial?: any; } } @@ -24,6 +25,13 @@ export default class WebAwesomeElement extends LitElement { /* eslint-disable-next-line */ console.error('Element internals are not supported in your browser. Consider using a polyfill'); } + + 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}`); + } + } } // Make localization attributes reactive @@ -159,6 +167,26 @@ export default class WebAwesomeElement extends LitElement { return this.hasStatesSupport() ? this.internals.states.has(state) : false; } + getComputed(prop: PropertyKey) { + let value = this[prop as keyof this]; + if (value !== 'inherit') { + return value; + } + + let Self = this.constructor as typeof WebAwesomeElement; + let options = Self.elementProperties.get(prop as string); + + for (let element: Node = this; element.parentElement; element = element.parentElement) { + value = (element as any)[prop as PropertyKey]; + if (value !== 'inherit') { + return value; + } + } + + // If we've reached this point and we still have `inherit`, we just ran out of parents + return options?.initial ?? options?.default ?? value; + } + /** * Given a native event, this function cancels it and dispatches it again from the host element using the desired * event options. @@ -175,36 +203,46 @@ export default class WebAwesomeElement extends LitElement { } static createProperty(name: PropertyKey, options?: PropertyDeclaration): void { - if (options && options.default !== undefined && options.converter === undefined) { - // Wrap the default converter to remove the attribute if the value is the default - // This effectively prevents the component sprouting attributes that have not been specified - let converter = { - ...defaultConverter, - toAttribute(value: string, type: unknown): unknown { - if (value === options!.default) { - return null; - } - return defaultConverter.toAttribute!(value, type); - }, - }; - options = { ...options, converter }; + if (options) { + if (options.initial !== undefined && options.default === undefined) { + // Set "inherit" value as default if no default is specified but the initial value is + // This saves us having to tediously specify default: "inherit", initial: "foo" for every property + options.default = 'inherit'; + } + + if (options.default !== undefined && options.converter === undefined) { + // Wrap the default converter to remove the attribute if the value is the default + // This effectively prevents the component sprouting attributes that have not been specified + let converter = { + ...defaultConverter, + toAttribute(value: string, type: unknown): unknown { + if (value === options!.default) { + return null; + } + return defaultConverter.toAttribute!(value, type); + }, + }; + options = { ...options, converter }; + } } super.createProperty(name, options); // Wrap the default accessor with logic to return the default value if the value is null - if (options && options.default !== undefined) { - const descriptor = Object.getOwnPropertyDescriptor(this.prototype, name as string); + if (options) { + if (options.default !== undefined) { + const descriptor = Object.getOwnPropertyDescriptor(this.prototype, name as string); - if (descriptor?.get) { - const getter = descriptor.get; + if (descriptor?.get) { + const getter = descriptor.get; - Object.defineProperty(this.prototype, name, { - ...descriptor, - get() { - return getter.call(this) ?? options.default; - }, - }); + Object.defineProperty(this.prototype, name, { + ...descriptor, + get() { + return getter.call(this) ?? options.default; + }, + }); + } } } } diff --git a/src/styles/utilities/variants.css b/src/styles/utilities/variants.css index 475b681ef..f44bf729e 100644 --- a/src/styles/utilities/variants.css +++ b/src/styles/utilities/variants.css @@ -1,14 +1,116 @@ +/** + * Do not edit this file directly. It is generated via variants.css.js + */ + +/** + * Register color properties so that the space toggle hack can work. + */ + +@property --wa-color-fill-loud { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-fill-normal { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-fill-quiet { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-border-loud { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-border-normal { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-border-quiet { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-on-loud { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-on-normal { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +@property --wa-color-on-quiet { + syntax: ''; + inherits: true; + initial-value: transparent; +} + +/** + * Element defaults. + We want these to resolve to inherit when inside a variant, and only be applied when not inside an explicit variant. + */ + +:host(wa-button), +.wa-button, +button, +input[type='button'], +input[type='submit'], +:host(wa-tag), +.wa-tag { + --wa-color-fill-loud: var(--wa-no-variant, var(--wa-color-neutral-fill-loud)); + --wa-color-fill-normal: var(--wa-no-variant, var(--wa-color-neutral-fill-normal)); + --wa-color-fill-quiet: var(--wa-no-variant, var(--wa-color-neutral-fill-quiet)); + --wa-color-border-loud: var(--wa-no-variant, var(--wa-color-neutral-border-loud)); + --wa-color-border-normal: var(--wa-no-variant, var(--wa-color-neutral-border-normal)); + --wa-color-border-quiet: var(--wa-no-variant, var(--wa-color-neutral-border-quiet)); + --wa-color-on-loud: var(--wa-no-variant, var(--wa-color-neutral-on-loud)); + --wa-color-on-normal: var(--wa-no-variant, var(--wa-color-neutral-on-normal)); + --wa-color-on-quiet: var(--wa-no-variant, var(--wa-color-neutral-on-quiet)); +} + +:host(wa-callout), +.wa-callout, +:host(wa-badge), +.wa-badge { + --wa-color-fill-loud: var(--wa-no-variant, var(--wa-color-brand-fill-loud)); + --wa-color-fill-normal: var(--wa-no-variant, var(--wa-color-brand-fill-normal)); + --wa-color-fill-quiet: var(--wa-no-variant, var(--wa-color-brand-fill-quiet)); + --wa-color-border-loud: var(--wa-no-variant, var(--wa-color-brand-border-loud)); + --wa-color-border-normal: var(--wa-no-variant, var(--wa-color-brand-border-normal)); + --wa-color-border-quiet: var(--wa-no-variant, var(--wa-color-brand-border-quiet)); + --wa-color-on-loud: var(--wa-no-variant, var(--wa-color-brand-on-loud)); + --wa-color-on-normal: var(--wa-no-variant, var(--wa-color-brand-on-normal)); + --wa-color-on-quiet: var(--wa-no-variant, var(--wa-color-brand-on-quiet)); +} + +/** + * Variants + */ + +:root, .wa-neutral, -:host([variant='neutral']), -:root { +:host([variant='neutral']) { --wa-color-fill-loud: var(--wa-color-neutral-fill-loud); --wa-color-fill-normal: var(--wa-color-neutral-fill-normal); --wa-color-fill-quiet: var(--wa-color-neutral-fill-quiet); - --wa-color-border-loud: var(--wa-color-neutral-border-loud); --wa-color-border-normal: var(--wa-color-neutral-border-normal); --wa-color-border-quiet: var(--wa-color-neutral-border-quiet); - --wa-color-on-loud: var(--wa-color-neutral-on-loud); --wa-color-on-normal: var(--wa-color-neutral-on-normal); --wa-color-on-quiet: var(--wa-color-neutral-on-quiet); @@ -19,11 +121,9 @@ --wa-color-fill-loud: var(--wa-color-brand-fill-loud); --wa-color-fill-normal: var(--wa-color-brand-fill-normal); --wa-color-fill-quiet: var(--wa-color-brand-fill-quiet); - --wa-color-border-loud: var(--wa-color-brand-border-loud); --wa-color-border-normal: var(--wa-color-brand-border-normal); --wa-color-border-quiet: var(--wa-color-brand-border-quiet); - --wa-color-on-loud: var(--wa-color-brand-on-loud); --wa-color-on-normal: var(--wa-color-brand-on-normal); --wa-color-on-quiet: var(--wa-color-brand-on-quiet); @@ -34,11 +134,9 @@ --wa-color-fill-loud: var(--wa-color-success-fill-loud); --wa-color-fill-normal: var(--wa-color-success-fill-normal); --wa-color-fill-quiet: var(--wa-color-success-fill-quiet); - --wa-color-border-loud: var(--wa-color-success-border-loud); --wa-color-border-normal: var(--wa-color-success-border-normal); --wa-color-border-quiet: var(--wa-color-success-border-quiet); - --wa-color-on-loud: var(--wa-color-success-on-loud); --wa-color-on-normal: var(--wa-color-success-on-normal); --wa-color-on-quiet: var(--wa-color-success-on-quiet); @@ -49,11 +147,9 @@ --wa-color-fill-loud: var(--wa-color-warning-fill-loud); --wa-color-fill-normal: var(--wa-color-warning-fill-normal); --wa-color-fill-quiet: var(--wa-color-warning-fill-quiet); - --wa-color-border-loud: var(--wa-color-warning-border-loud); --wa-color-border-normal: var(--wa-color-warning-border-normal); --wa-color-border-quiet: var(--wa-color-warning-border-quiet); - --wa-color-on-loud: var(--wa-color-warning-on-loud); --wa-color-on-normal: var(--wa-color-warning-on-normal); --wa-color-on-quiet: var(--wa-color-warning-on-quiet); @@ -64,12 +160,19 @@ --wa-color-fill-loud: var(--wa-color-danger-fill-loud); --wa-color-fill-normal: var(--wa-color-danger-fill-normal); --wa-color-fill-quiet: var(--wa-color-danger-fill-quiet); - --wa-color-border-loud: var(--wa-color-danger-border-loud); --wa-color-border-normal: var(--wa-color-danger-border-normal); --wa-color-border-quiet: var(--wa-color-danger-border-quiet); - --wa-color-on-loud: var(--wa-color-danger-on-loud); --wa-color-on-normal: var(--wa-color-danger-on-normal); --wa-color-on-quiet: var(--wa-color-danger-on-quiet); } + +.wa-neutral, +.wa-brand, +.wa-success, +.wa-warning, +.wa-danger, +:host([variant]) { + --wa-no-variant: /* space toggle */; +} diff --git a/src/styles/utilities/variants.css.js b/src/styles/utilities/variants.css.js new file mode 100644 index 000000000..1881b5ff2 --- /dev/null +++ b/src/styles/utilities/variants.css.js @@ -0,0 +1,68 @@ +/** + * Generate variants.css + * To use: node variants.css.js > variants.css + */ +const variants = ['neutral', 'brand', 'success', 'warning', 'danger']; +const roles = ['fill', 'border', 'on']; +const noise = ['loud', 'normal', 'quiet']; +const defaults = { + neutral: [ + [':host(wa-button)', '.wa-button', 'button', "input[type='button']", "input[type='submit']"], + [':host(wa-tag)', '.wa-tag'], + ], + brand: [ + [':host(wa-callout)', '.wa-callout'], + [':host(wa-badge)', '.wa-badge'], + ], +}; +const types = roles.map(layer => noise.map(priority => layer + '-' + priority)).flat(); + +let ret = comment('Do not edit this file directly. It is generated via variants.css.js').trimStart(); + +ret += comment('Register color properties so that the space toggle hack can work.'); + +for (let type of types) { + ret += cssRule(`@property --wa-color-${type}`, [ + `syntax: '';`, + 'inherits: true;', + 'initial-value: transparent;', + ]); +} + +ret += comment(`Element defaults. + We want these to resolve to inherit when inside a variant, and only be applied when not inside an explicit variant.`); + +for (let variant in defaults) { + let selector = defaults[variant]; + let declarations = types.map(type => `--wa-color-${type}: var(--wa-no-variant, var(--wa-color-${variant}-${type}));`); + + ret += cssRule(selector, declarations); +} + +ret += comment('Variants'); + +for (let variant of variants) { + let selector = [`.wa-${variant}`, `:host([variant='${variant}'])`]; + + if (variant === 'neutral') { + selector.unshift(':root'); + } + + let declarations = types.map(type => `--wa-color-${type}: var(--wa-color-${variant}-${type});`); + ret += cssRule(selector, declarations); +} + +ret += cssRule([variants.map(variant => `.wa-${variant}`), ':host([variant])'], '--wa-no-variant: /* space toggle */;'); + +console.log(ret.trimEnd()); + +function cssRule(selector, declarations) { + selector = Array.isArray(selector) ? selector.flat().join(',\n') : selector; + declarations = Array.isArray(declarations) ? declarations.flat().join('\n') : declarations; + declarations = declarations.replace(/^/gm, ' '); + return `\n${selector} {\n${declarations}\n}\n`; +} + +function comment(text) { + return ['\n/**', ` * ${text}`, ' */\n'].join('\n'); +} From 4f9af1e871b6994e9c993764720767b2a6f70d07 Mon Sep 17 00:00:00 2001 From: Lea Verou Date: Sat, 25 Jan 2025 14:52:53 -0500 Subject: [PATCH 014/194] Add JS snppet for setting `wa-dark` based on OS default --- docs/_layouts/theme.njk | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/_layouts/theme.njk b/docs/_layouts/theme.njk index dfa90a01c..03be52f24 100644 --- a/docs/_layouts/theme.njk +++ b/docs/_layouts/theme.njk @@ -138,6 +138,7 @@ You can apply the class to the `` element on your page to activate the dar Web Awesome's themes have both light and dark styles built in. However, Web Awesome doesn't try to auto-detect the user's light/dark mode preference. This should be done at the application level. + As a best practice, to provide a dark theme in your app, you should: - Check for [`prefers-color-scheme`](https://stackoverflow.com/a/57795495/567486) and use its value by default @@ -146,5 +147,18 @@ As a best practice, to provide a dark theme in your app, you should: Web Awesome avoids using the `prefers-color-scheme` media query because not all apps support dark mode, and it would break things for the ones that don't. +Assuming the user's preference is in a variable called `colorScheme` (values: `auto`, `light`, `dark`), +you can use the following JS snippet to apply the `wa-dark` class to the `` element accordingly: + +```js +const systemDark = window.matchMedia('(prefers-color-scheme: dark)'); +const applyDark = function (event = systemDark) { + const isDark = colorScheme === 'auto' ? event.matches : colorScheme === 'dark'; + document.documentElement.classList.toggle('wa-dark', isDark); +}; +systemDark.addEventListener('change', applyDark); +applyDark(); +``` + {% endmarkdown %} {% endblock %} From c5f91ec2f72a056d27de43f289a999eae4fecc72 Mon Sep 17 00:00:00 2001 From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com> Date: Thu, 30 Jan 2025 11:51:57 -0500 Subject: [PATCH 015/194] Add missing changelog entries (#639) * Add logs for visual tests, `variant` inheritance, and missing bug fixes * Update logs on docs changes --- docs/docs/resources/changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/docs/resources/changelog.md b/docs/docs/resources/changelog.md index fa5919efd..609a72d29 100644 --- a/docs/docs/resources/changelog.md +++ b/docs/docs/resources/changelog.md @@ -21,9 +21,15 @@ During the alpha period, things might break! We take breaking changes very serio - `wa-focus` => `focus` (this event will no longer bubble) - Added `.wa-callout` utility class - Added the `orientation` attribute to `` to support vertical and horizontal radio items +- Added docs for visual tests +- Added docs on how to cherry-pick native styles +- Changed `variant` behavior so that nested components with `variant` support inherit the `variant` set on their ancestor - Fixed a bug in `` that prevented nested tab groups from working properly - Fixed slot names for `show-password-icon` and `hide-password-icon` in `` to more intuitively represent their functions - Fixed a bug in `` that caused empty controls to submit a value if the initial value was deleted a certain way +- Fixed a bug in ``, `