From 74ecc52a15c3bf34b530f3617cb80e0944d46b0f Mon Sep 17 00:00:00 2001 From: Lea Verou Date: Thu, 30 Jan 2025 15:56:32 -0800 Subject: [PATCH] Inheritable `size` (#593) Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com> Co-authored-by: lindsaym-fa --- docs/_includes/visual-tests/size.njk | 298 +++++++++++++++++- docs/docs/components/button-group.md | 77 +++-- docs/docs/components/card.md | 39 +++ docs/docs/components/radio-group.md | 45 ++- docs/docs/components/rating.md | 14 +- docs/docs/experimental/size.md | 75 +++++ docs/docs/resources/changelog.md | 6 +- src/components/button-group/button-group.ts | 11 +- src/components/button/button.test.ts | 2 +- src/components/button/button.ts | 2 +- src/components/callout/callout.ts | 2 +- src/components/card/card.css | 6 +- src/components/card/card.ts | 8 +- src/components/checkbox/checkbox.ts | 2 +- src/components/color-picker/color-picker.ts | 2 +- src/components/dropdown/dropdown.ts | 3 +- src/components/input/input.test.ts | 2 +- src/components/input/input.ts | 2 +- src/components/menu/menu.ts | 8 +- src/components/radio-button/radio-button.ts | 2 +- .../radio-group/radio-group.test.ts | 26 +- src/components/radio-group/radio-group.ts | 8 +- src/components/radio/radio.ts | 2 +- src/components/rating/rating.css | 8 +- src/components/rating/rating.ts | 7 +- src/components/select/select.ts | 2 +- src/components/switch/switch.ts | 2 +- src/components/tag/tag.test.ts | 2 +- src/components/tag/tag.ts | 2 +- src/components/textarea/textarea.test.ts | 2 +- src/components/textarea/textarea.ts | 2 +- src/styles/utilities/size.css | 78 +++-- 32 files changed, 614 insertions(+), 133 deletions(-) create mode 100644 docs/docs/experimental/size.md diff --git a/docs/_includes/visual-tests/size.njk b/docs/_includes/visual-tests/size.njk index 42ec56d62..884cdd0c2 100644 --- a/docs/_includes/visual-tests/size.njk +++ b/docs/_includes/visual-tests/size.njk @@ -40,6 +40,66 @@ +

Button Group

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

Callout

@@ -100,6 +160,60 @@
+

Card

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

Checkbox

@@ -184,6 +298,144 @@
+

Dropdown

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
size="".wa-size-[s|m|l]
small/s + + Dropdown + + Menu Item 1 + Menu Item 2 + + + + +
medium/m + + Dropdown + + Menu Item 1 + Menu Item 2 + + + + +
large/l + + Dropdown + + Menu Item 1 + Menu Item 2 + + + + +
+
+ + +

Menu

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

Input

@@ -274,7 +526,7 @@ - + @@ -335,7 +587,7 @@ - + @@ -424,6 +676,48 @@ +

Rating

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

Select

diff --git a/docs/docs/components/button-group.md b/docs/docs/components/button-group.md index f70bce8d5..264fce376 100644 --- a/docs/docs/components/button-group.md +++ b/docs/docs/components/button-group.md @@ -17,32 +17,39 @@ icon: button-group ### Button Sizes -All button sizes are supported, but avoid mixing sizes within the same button group. +Unless otherwise specified, +the size of [buttons](/docs/components/button) will be determined by the Button Group's `size` attribute. ```html {.example} - - Left - Center - Right + + Left + Center + Right

- - Left - Center - Right + + Left + Center + Right

- - Left - Center - Right + + Left + Center + Right ``` +:::info +While you can still set the size of [buttons](/docs/components/button) individually, +and it will override the inherited size, +it is rarely a good idea to mix sizes within the same button group. +::: + ### Vertical button groups Set the `orientation` attribute to `vertical` to make a vertical button group. @@ -70,21 +77,21 @@ Set the `orientation` attribute to `vertical` to make a vertical button group. ### Theme Buttons -Theme buttons are supported through the button's `variant` attribute. +Theme buttons are supported through the button group's `variant` attribute. ```html {.example} - - Left - Center - Right + + Left + Center + Right

- - Left - Center - Right + + Left + Center + Right

@@ -97,18 +104,28 @@ Theme buttons are supported through the button's `variant` attribute.

- - Left - Center - Right + + Left + Center + Right

- - Left - Center - Right + + Left + Center + Right + +``` + +You can still use the buttons’ own `variant` attribute to override the inherited variant. + +```html {.example} + + Left + Center + Right ``` diff --git a/docs/docs/components/card.md b/docs/docs/components/card.md index 6a3f4f791..222e5b8d5 100644 --- a/docs/docs/components/card.md +++ b/docs/docs/components/card.md @@ -143,3 +143,42 @@ If using SSR, you need to also use the `with-image` attribute to add an image to } ``` + +### Sizing + +Use the `size` attribute to change a card's size. + +```html {.example} + + +``` + + diff --git a/docs/docs/components/radio-group.md b/docs/docs/components/radio-group.md index bb4a6d0aa..935e26071 100644 --- a/docs/docs/components/radio-group.md +++ b/docs/docs/components/radio-group.md @@ -32,11 +32,11 @@ Add descriptive hint to a radio group with the `hint` attribute. For hints that [Radio buttons](/docs/components/radio-button) offer an alternate way to display radio controls. In this case, an internal [button group](/docs/components/button-group) is used to group the buttons into a single, cohesive control. ```html {.example} - Option 1 @@ -46,11 +46,11 @@ Add descriptive hint to a radio group with the `hint` attribute. For hints that
- @@ -77,11 +77,11 @@ Radios and radio buttons can be disabled by adding the `disabled` attribute to t The default orientation for radio items is `vertical`. Set the `orientation` to `horizontal` to items on the same row. ```html {.example} - Option 1 @@ -92,26 +92,19 @@ The default orientation for radio items is `vertical`. Set the `orientation` to ### Sizing Options -The size of [Radios](/docs/components/radio) and [Radio Buttons](/docs/components/radio-buttons) will be determined by the Radio Group's `size` attribute. +The size of [Radios](/docs/components/radio) and [Radio Buttons](/docs/components/radio-button) will be determined by the Radio Group's `size` attribute. -```html preview - +```html {.example} + Small Medium Large - - ``` :::info -[Radios](/docs/components/radio) and [Radio Buttons](/docs/components/radio-button) also have a `size` attribute. This can be useful in certain compositions, but it will be ignored when used inside of a Radio Group. +[Radios](/docs/components/radio) and [Radio Buttons](/docs/components/radio-button) also have a `size` attribute, +which will override the inherited size when used. ::: ### Validation diff --git a/docs/docs/components/rating.md b/docs/docs/components/rating.md index 41cb938d6..682fc1b4c 100644 --- a/docs/docs/components/rating.md +++ b/docs/docs/components/rating.md @@ -35,12 +35,20 @@ Use the `precision` attribute to let users select fractional ratings. ``` -### Symbol Sizes +### Sizing -Set the `--symbol-size` custom property to adjust the size. +Use the `size` attribute to adjust the size of the rating. ```html {.example} - +
+
+ +``` + +For more granular sizing, you can use the `font-size` property. + +```html {.example} + ``` ### Readonly diff --git a/docs/docs/experimental/size.md b/docs/docs/experimental/size.md new file mode 100644 index 000000000..992973bbb --- /dev/null +++ b/docs/docs/experimental/size.md @@ -0,0 +1,75 @@ +--- +title: Size tests +--- + +Button size should default to `medium`: + +```html {.example} +Small +Medium +Medium +Large +``` + +If no button size is specified, it should default to that of its ancestor: + +```html {.example} + + Small 1 + Small 2 + Small 3 + +

+ + Medium 1 + Medium 2 + Medium 3 + +

+ + Large 1 + Large 2 + Large 3 + +``` + +Dropdown: + +```html {.example} +

Small dropdown: + + Dropdown + + Dropdown Item 1 + Dropdown Item 2 + Dropdown Item 3 + + +

Small menu: + + Dropdown + + Dropdown Item 1 + Dropdown Item 2 + Dropdown Item 3 + + +

Small menu item: + + Dropdown + + Dropdown Item 1 + Dropdown Item 2 + Dropdown Item 3 + + +

No size: + + Dropdown + + Dropdown Item 1 + Dropdown Item 2 + Dropdown Item 3 + + +``` diff --git a/docs/docs/resources/changelog.md b/docs/docs/resources/changelog.md index 609a72d29..8b3dbd529 100644 --- a/docs/docs/resources/changelog.md +++ b/docs/docs/resources/changelog.md @@ -18,12 +18,14 @@ During the alpha period, things might break! We take breaking changes very serio - `wa-input` => `input` - `wa-change` => `change` - `wa-blur` => `blur` (this event will no longer bubble, use `focusout` for a bubbling version) - - `wa-focus` => `focus` (this event will no longer bubble) + - `wa-focus` => `focus` (this event will no longer bubble, use `focusin` for a bubbling version) - 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 +- Changed the behavior of the `variant` and `size` attributes so that nested components that support these attributes but do not have them set inherit the values set on their ancestors. Additionally: + - Added `size` attribute to ``, ``, ``, ``, `` + - Added `variant` attribute to `` - 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 diff --git a/src/components/button-group/button-group.ts b/src/components/button-group/button-group.ts index 3a7dba9a0..f2acf84c0 100644 --- a/src/components/button-group/button-group.ts +++ b/src/components/button-group/button-group.ts @@ -3,6 +3,8 @@ import { html } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; import buttonGroupStyles from '../../styles/utilities/button-group.css'; +import sizeStyles from '../../styles/utilities/size.css'; +import variantStyles from '../../styles/utilities/variants.css'; import styles from './button-group.css'; /** @@ -17,7 +19,7 @@ import styles from './button-group.css'; */ @customElement('wa-button-group') export default class WaButtonGroup extends WebAwesomeElement { - static shadowStyle = [buttonGroupStyles, styles]; + static shadowStyle = [sizeStyles, variantStyles, buttonGroupStyles, styles]; @query('slot') defaultSlot: HTMLSlotElement; @@ -33,6 +35,13 @@ export default class WaButtonGroup extends WebAwesomeElement { /** The button group's orientation. */ @property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal'; + /** The component's size. */ + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; + + /** The button group'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'; + updated(changedProperties: PropertyValues) { super.updated(changedProperties); diff --git a/src/components/button/button.test.ts b/src/components/button/button.test.ts index ef447f58a..f5a4be55e 100644 --- a/src/components/button/button.test.ts +++ b/src/components/button/button.test.ts @@ -114,7 +114,7 @@ describe('', () => { expect(el.title).to.equal(''); expect(el.variant).to.equal('inherit'); expect(el.appearance).to.equal('accent'); - expect(el.size).to.equal('medium'); + expect(el.size).to.equal('inherit'); expect(el.disabled).to.equal(false); expect(el.caret).to.equal(false); expect(el.loading).to.equal(false); diff --git a/src/components/button/button.ts b/src/components/button/button.ts index 07c1326e8..5c50484db 100644 --- a/src/components/button/button.ts +++ b/src/components/button/button.ts @@ -75,7 +75,7 @@ export default class WaButton extends WebAwesomeFormAssociatedElement { appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'accent'; /** The button's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Draws the button with a caret. Used to indicate that the button triggers a dropdown menu or similar behavior. */ @property({ type: Boolean, reflect: true }) caret = false; diff --git a/src/components/callout/callout.ts b/src/components/callout/callout.ts index 463c2bb59..7e17ef445 100644 --- a/src/components/callout/callout.ts +++ b/src/components/callout/callout.ts @@ -46,7 +46,7 @@ export default class WaCallout extends WebAwesomeElement { | 'outlined accent' = 'outlined filled'; /** The callout's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; render() { return html` diff --git a/src/components/card/card.css b/src/components/card/card.css index 19cecca1f..6943729ad 100644 --- a/src/components/card/card.css +++ b/src/components/card/card.css @@ -1,5 +1,9 @@ :host { - --spacing: var(--wa-space-xl); + --space-s: var(--wa-space-l); + --space-m: var(--wa-space-xl); + --space-l: var(--wa-space-2xl); + + --spacing: var(--wa-space); --border-width: var(--wa-panel-border-width); --border-radius: var(--wa-panel-border-radius); diff --git a/src/components/card/card.ts b/src/components/card/card.ts index 7d4f35509..1b8655c8a 100644 --- a/src/components/card/card.ts +++ b/src/components/card/card.ts @@ -1,6 +1,7 @@ import { html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; +import sizeStyles from '../../styles/utilities/size.css'; import styles from './card.css'; /** @@ -21,11 +22,14 @@ import styles from './card.css'; * * @cssproperty --border-radius - The radius for the card's corners. Expects a single value. Defaults to `var(--wa-panel-border-radius)`. * @cssproperty --border-width - The width of the card's borders. Expects a single value. Defaults to `var(--wa-panel-border-width)`. - * @cssproperty --spacing - The amount of space around and between sections of the card. Expects a single value. + * @cssproperty --spacing - The amount of space around and between sections of the card. Expects a single value. Defaults to `var(--wa-space)`. */ @customElement('wa-card') export default class WaCard extends WebAwesomeElement { - static shadowStyle = styles; + static shadowStyle = [sizeStyles, styles]; + + /** The component's size. Will be inherited by any descendants with a `size` attribute. */ + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Renders the card with a header. Only needed for SSR, otherwise is automatically added. */ @property({ attribute: 'with-header', type: Boolean }) withHeader = false; diff --git a/src/components/checkbox/checkbox.ts b/src/components/checkbox/checkbox.ts index 0284af71f..779f6be77 100644 --- a/src/components/checkbox/checkbox.ts +++ b/src/components/checkbox/checkbox.ts @@ -98,7 +98,7 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement { } /** The checkbox's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Disables the checkbox. */ @property({ type: Boolean }) disabled = false; diff --git a/src/components/color-picker/color-picker.ts b/src/components/color-picker/color-picker.ts index 9aa02d1ce..aae672b60 100644 --- a/src/components/color-picker/color-picker.ts +++ b/src/components/color-picker/color-picker.ts @@ -199,7 +199,7 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement { @property() format: 'hex' | 'rgb' | 'hsl' | 'hsv' = 'hex'; /** Determines the size of the color picker's trigger */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Removes the button that lets users toggle between format. */ @property({ attribute: 'no-format-toggle', type: Boolean }) noFormatToggle = false; diff --git a/src/components/dropdown/dropdown.ts b/src/components/dropdown/dropdown.ts index 9e50b9baa..15e0401c2 100644 --- a/src/components/dropdown/dropdown.ts +++ b/src/components/dropdown/dropdown.ts @@ -11,6 +11,7 @@ import { animateWithClass } from '../../internal/animate.js'; import { waitForEvent } from '../../internal/event.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; +import sizeStyles from '../../styles/utilities/size.css'; import type WaButton from '../button/button.js'; import type WaIconButton from '../icon-button/icon-button.js'; import type WaMenu from '../menu/menu.js'; @@ -43,7 +44,7 @@ import styles from './dropdown.css'; */ @customElement('wa-dropdown') export default class WaDropdown extends WebAwesomeElement { - static shadowStyle = styles; + static shadowStyle = [sizeStyles, styles]; @query('.dropdown') popup: WaPopup; @query('#trigger') trigger: HTMLSlotElement; diff --git a/src/components/input/input.test.ts b/src/components/input/input.test.ts index 1d5719109..7d9305d81 100644 --- a/src/components/input/input.test.ts +++ b/src/components/input/input.test.ts @@ -23,7 +23,7 @@ describe('', () => { const el = await fixture(html` `); expect(el.type).to.equal('text'); - expect(el.size).to.equal('medium'); + expect(el.size).to.equal('inherit'); expect(el.name).to.equal(null); expect(el.value).to.equal(null); expect(el.defaultValue).to.equal(null); diff --git a/src/components/input/input.ts b/src/components/input/input.ts index 912d9c897..446b35d05 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -115,7 +115,7 @@ export default class WaInput extends WebAwesomeFormAssociatedElement { @property({ attribute: 'value', reflect: true }) defaultValue: string | null = this.getAttribute('value') || null; /** The input's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** The input's visual appearance. */ @property({ reflect: true }) appearance: 'filled' | 'outlined' = 'outlined'; diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index a81255536..d6b0f5dfb 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -1,7 +1,8 @@ import { html } from 'lit'; -import { customElement, query } from 'lit/decorators.js'; +import { customElement, property, query } from 'lit/decorators.js'; import { WaSelectEvent } from '../../events/select.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; +import sizeStyles from '../../styles/utilities/size.css'; import '../menu-item/menu-item.js'; import type WaMenuItem from '../menu-item/menu-item.js'; import styles from './menu.css'; @@ -24,7 +25,10 @@ export interface MenuSelectEventDetail { */ @customElement('wa-menu') export default class WaMenu extends WebAwesomeElement { - static shadowStyle = styles; + static shadowStyle = [sizeStyles, styles]; + + /** The component's size. */ + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; @query('slot') defaultSlot: HTMLSlotElement; diff --git a/src/components/radio-button/radio-button.ts b/src/components/radio-button/radio-button.ts index 57514490c..23ad3dc6d 100644 --- a/src/components/radio-button/radio-button.ts +++ b/src/components/radio-button/radio-button.ts @@ -72,7 +72,7 @@ export default class WaRadioButton extends WebAwesomeFormAssociatedElement { * The radio button's size. When used inside a radio group, the size will be determined by the radio group's size so * this attribute can typically be omitted. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Draws a pill-style radio button with rounded edges. */ @property({ type: Boolean, reflect: true }) pill = false; diff --git a/src/components/radio-group/radio-group.test.ts b/src/components/radio-group/radio-group.test.ts index 0637f6f96..730394e51 100644 --- a/src/components/radio-group/radio-group.test.ts +++ b/src/components/radio-group/radio-group.test.ts @@ -259,8 +259,10 @@ describe('', () => { `); const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio'); - expect(radio1.size).to.equal('large'); - expect(radio2.size).to.equal('large'); + expect(radio1.size).to.equal('inherit'); + expect(radio1.getComputed('size')).to.equal('large'); + expect(radio2.size).to.equal('inherit'); + expect(radio2.getComputed('size')).to.equal('large'); }); it('should apply the same size to all radio buttons', async () => { @@ -272,11 +274,13 @@ describe('', () => { `); const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio-button'); - expect(radio1.size).to.equal('large'); - expect(radio2.size).to.equal('large'); + expect(radio1.size).to.equal('inherit'); + expect(radio1.getComputed('size')).to.equal('large'); + expect(radio2.size).to.equal('inherit'); + expect(radio2.getComputed('size')).to.equal('large'); }); - it('should update the size of all radio buttons when size changes', async () => { + it('should update the computed size of all radio buttons when size changes', async () => { const radioGroup = await fixture(html` @@ -285,14 +289,18 @@ describe('', () => { `); const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio-button'); - expect(radio1.size).to.equal('small'); - expect(radio2.size).to.equal('small'); + expect(radio1.size).to.equal('inherit'); + expect(radio1.getComputed('size')).to.equal('small'); + expect(radio2.size).to.equal('inherit'); + expect(radio2.getComputed('size')).to.equal('small'); radioGroup.size = 'large'; await radioGroup.updateComplete; - expect(radio1.size).to.equal('large'); - expect(radio2.size).to.equal('large'); + expect(radio1.size).to.equal('inherit'); + expect(radio1.getComputed('size')).to.equal('large'); + expect(radio2.size).to.equal('inherit'); + expect(radio2.getComputed('size')).to.equal('large'); }); }); diff --git a/src/components/radio-group/radio-group.ts b/src/components/radio-group/radio-group.ts index 8d55692d7..0426abb18 100644 --- a/src/components/radio-group/radio-group.ts +++ b/src/components/radio-group/radio-group.ts @@ -107,8 +107,8 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement { /** The default value of the form control. Primarily used for resetting the form control. */ @property({ attribute: 'value', reflect: true }) defaultValue: string | null = this.getAttribute('value') || null; - /** The radio group's size. This size will be applied to all child radios and radio buttons. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + /** The radio group's size. This size will be applied to all child radios and radio buttons, except when explicitly overridden. */ + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Ensures a child radio is checked before allowing the containing form to submit. */ @property({ type: Boolean, reflect: true }) required = false; @@ -187,7 +187,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement { // Sync the checked state and size radios.map(async radio => { await radio.updateComplete; - radio.size = this.size; if (!radio.disabled && radio.value === this.value) { radio.checked = true; @@ -329,9 +328,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement { part="form-control" class=${classMap({ 'form-control': true, - 'form-control--small': this.size === 'small', - 'form-control--medium': this.size === 'medium', - 'form-control--large': this.size === 'large', 'form-control--radio-group': true, 'form-control--has-label': hasLabel, 'form-control--has-radio-buttons': this.hasRadioButtons, diff --git a/src/components/radio/radio.ts b/src/components/radio/radio.ts index 5cddd5df4..11946b8ea 100644 --- a/src/components/radio/radio.ts +++ b/src/components/radio/radio.ts @@ -58,7 +58,7 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement { * The radio's size. When used inside a radio group, the size will be determined by the radio group's size so this * attribute can typically be omitted. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Disables the radio. */ @property({ type: Boolean }) disabled = false; diff --git a/src/components/rating/rating.css b/src/components/rating/rating.css index 17989edcd..d1f0b2e75 100644 --- a/src/components/rating/rating.css +++ b/src/components/rating/rating.css @@ -1,7 +1,12 @@ :host { + --size-xs: var(--wa-space-s); + --size-s: var(--wa-space-m); + --size-m: var(--wa-space-l); + --size-l: var(--wa-space-xl); + --symbol-color: var(--wa-color-neutral-fill-normal); --symbol-color-active: var(--wa-color-yellow-70); - --symbol-size: var(--wa-font-size-l); + --symbol-size: var(--wa-size); --symbol-spacing: var(--wa-space-3xs); display: inline-flex; @@ -26,7 +31,6 @@ .symbols { display: inline-flex; position: relative; - font-size: var(--symbol-size); line-height: 0; color: var(--symbol-color); white-space: nowrap; diff --git a/src/components/rating/rating.ts b/src/components/rating/rating.ts index 76fb39ce7..d492c727a 100644 --- a/src/components/rating/rating.ts +++ b/src/components/rating/rating.ts @@ -7,6 +7,7 @@ import { WaHoverEvent } from '../../events/hover.js'; import { clamp } from '../../internal/math.js'; import { watch } from '../../internal/watch.js'; import WebAwesomeElement from '../../internal/webawesome-element.js'; +import sizeStyles from '../../styles/utilities/size.css'; import { LocalizeController } from '../../utilities/localize.js'; import '../icon/icon.js'; import styles from './rating.css'; @@ -28,12 +29,11 @@ import styles from './rating.css'; * * @cssproperty --symbol-color - The inactive color for symbols. * @cssproperty --symbol-color-active - The active color for symbols. - * @cssproperty --symbol-size - The size of symbols. * @cssproperty --symbol-spacing - The spacing to use around symbols. */ @customElement('wa-rating') export default class WaRating extends WebAwesomeElement { - static shadowStyle = styles; + static shadowStyle = [sizeStyles, styles]; private readonly localize = new LocalizeController(this); @@ -71,6 +71,9 @@ export default class WaRating extends WebAwesomeElement { @property() getSymbol: (value: number) => string = () => ''; + /** The component's size. */ + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; + private getValueFromMousePosition(event: MouseEvent) { return this.getValueFromXCoordinate(event.clientX); } diff --git a/src/components/select/select.ts b/src/components/select/select.ts index 2dca03513..5e86e014f 100644 --- a/src/components/select/select.ts +++ b/src/components/select/select.ts @@ -162,7 +162,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement { @property({ attribute: false }) value: string | string[] | null = null; /** The select's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Placeholder text to show as a hint when the select is empty. */ @property() placeholder = ''; diff --git a/src/components/switch/switch.ts b/src/components/switch/switch.ts index 369521218..74d5a7fb7 100644 --- a/src/components/switch/switch.ts +++ b/src/components/switch/switch.ts @@ -77,7 +77,7 @@ export default class WaSwitch extends WebAwesomeFormAssociatedElement { } /** The switch's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Disables the switch. */ @property({ type: Boolean }) disabled = false; diff --git a/src/components/tag/tag.test.ts b/src/components/tag/tag.test.ts index 40419967a..b08571126 100644 --- a/src/components/tag/tag.test.ts +++ b/src/components/tag/tag.test.ts @@ -9,7 +9,7 @@ describe('', () => { describe(`with "${fixture.type}" rendering`, () => { it('should render default tag', async () => { const el = await fixture(html` Test `); - expect(el.getAttribute('size')).to.equal('medium'); + expect(el.getAttribute('size')).to.equal(null); expect(el.getAttribute('variant')).to.equal(null); expect(el.variant).to.equal('inherit'); }); diff --git a/src/components/tag/tag.ts b/src/components/tag/tag.ts index c1dbbfc52..02199579f 100644 --- a/src/components/tag/tag.ts +++ b/src/components/tag/tag.ts @@ -46,7 +46,7 @@ export default class WaTag extends WebAwesomeElement { 'outlined filled'; /** The tag's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** Draws a pill-style tag with rounded edges. */ @property({ type: Boolean, reflect: true }) pill = false; diff --git a/src/components/textarea/textarea.test.ts b/src/components/textarea/textarea.test.ts index cc135c21f..8dedd082e 100644 --- a/src/components/textarea/textarea.test.ts +++ b/src/components/textarea/textarea.test.ts @@ -20,7 +20,7 @@ describe('', () => { it('default properties', async () => { const el = await fixture(html` `); - expect(el.size).to.equal('medium'); + expect(el.size).to.equal('inherit'); expect(el.name).to.equal(null); expect(el.value).to.equal(''); expect(el.defaultValue).to.equal(''); diff --git a/src/components/textarea/textarea.ts b/src/components/textarea/textarea.ts index d92c6dc7a..8dcb1cee0 100644 --- a/src/components/textarea/textarea.ts +++ b/src/components/textarea/textarea.ts @@ -88,7 +88,7 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement { @property({ attribute: 'value', reflect: true }) defaultValue: string = this.getAttribute('value') ?? ''; /** The textarea's size. */ - @property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium'; + @property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit'; /** The textarea's visual appearance. */ @property({ reflect: true }) appearance: 'filled' | 'outlined' = 'outlined'; diff --git a/src/styles/utilities/size.css b/src/styles/utilities/size.css index ae49f2448..f93b47ae3 100644 --- a/src/styles/utilities/size.css +++ b/src/styles/utilities/size.css @@ -1,19 +1,10 @@ -/* Shadow styles for elements that have a size attribute. */ +/** + * Shadow styles for elements that have a size attribute and for the size utility classes. + */ :host, :where(.wa-size-s, .wa-size-m, .wa-size-l) { - /* Defaults. Components are expected to override these */ - --size-xs: var(--wa-font-size-xs, 0.75rem); /* Used for hints etc */ - --size-s: var(--wa-font-size-s, 0.875rem); /* size=small */ - --size-m: var(--wa-font-size-m, 1rem); /* default */ - --size-l: var(--wa-font-size-l, 1.25rem); /* size=large */ - - --space-xs: var(--wa-space-xs, 0.5rem); - --space-s: var(--wa-space-s, 0.75rem); - --space-m: var(--wa-space-m, 1rem); - --space-l: var(--wa-space-l, 1.25rem); - - font-size: var(--wa-size); + font-size: var(--wa-size, var(--wa-font-size-m)); } :where(:root), @@ -21,6 +12,35 @@ .wa-size-s, .wa-size-m, .wa-size-l { + --_wa-is-small: var(--wa-is-small, 0); + --_wa-is-medium: var(--wa-is-medium, 1); + --_wa-is-large: var(--wa-is-large, 0); + + --_size-xs: var(--size-xs, var(--wa-font-size-xs)); + --_size-s: var(--size-s, var(--wa-font-size-s)); + --_size-m: var(--size-m, var(--wa-font-size-m)); + --_size-l: var(--size-l, var(--wa-font-size-l)); + + --_space-xs: var(--space-xs, var(--wa-space-xs)); + --_space-s: var(--space-s, var(--wa-space-s)); + --_space-m: var(--space-m, var(--wa-space-m)); + --_space-l: var(--space-l, var(--wa-space-l)); + + --wa-size: calc( + var(--_wa-is-small) * var(--_size-s) + var(--_wa-is-medium) * var(--_size-m) + var(--_wa-is-large) * var(--_size-l) + ); + --wa-size-smaller: calc( + var(--_wa-is-small) * var(--_size-xs) + var(--_wa-is-medium) * var(--_size-s) + var(--_wa-is-large) * var(--_size-m) + ); + --wa-space: calc( + var(--_wa-is-small) * var(--_space-s) + var(--_wa-is-medium) * var(--_space-m) + var(--_wa-is-large) * + var(--_space-l) + ); + --wa-space-smaller: calc( + var(--_wa-is-small) * var(--_space-xs) + var(--_wa-is-medium) * var(--_space-s) + var(--_wa-is-large) * + var(--_space-m) + ); + --_wa-form-control-height: calc(2 * var(--wa-space-smaller) + 1em * var(--wa-form-control-value-line-height)); --wa-form-control-height: var(--_wa-form-control-height); @@ -29,27 +49,27 @@ } } -:host([size='small']), -.wa-size-s { - --wa-size: var(--size-s); - --wa-size-smaller: var(--size-xs); - --wa-space: var(--space-s); - --wa-space-smaller: var(--space-xs); +:host([size]), +.wa-size-s, +.wa-size-m, +.wa-size-l { + --wa-is-small: 0; + --wa-is-medium: 0; + --wa-is-large: 0; } -:root, /* Medium size is the default */ -:host, +:host([size='small']), +.wa-size-s { + --wa-is-small: 1; +} + +:where(:root), /* Medium size is the default */ +:host([size='medium']), .wa-size-m { - --wa-size: var(--size-m, var(--wa-font-size-m)); - --wa-size-smaller: var(--size-s, var(--wa-font-size-s)); - --wa-space: var(--space-m, var(--wa-space-m)); - --wa-space-smaller: var(--space-s, var(--wa-space-s)); + --wa-is-medium: 1; } :host([size='large']), .wa-size-l { - --wa-size: var(--size-l); - --wa-size-smaller: var(--size-m); - --wa-space: var(--space-l); - --wa-space-smaller: var(--space-m); + --wa-is-large: 1; }