Merge branch 'kj/layout-patterns' of github.com:shoelace-style/webawesome into kj/layout-patterns

This commit is contained in:
Kelsey Jackson
2025-05-30 10:53:17 -05:00
269 changed files with 10465 additions and 12298 deletions

View File

@@ -15,16 +15,19 @@
"autoloading",
"autoplay",
"bezier",
"Blockquotes",
"boxicons",
"CACHEABLE",
"callout",
"callouts",
"canvastext",
"chatbubble",
"checkmark",
"Clippy",
"codebases",
"codepen",
"colocated",
"colorjs",
"colour",
"combobox",
"Commonmark",
@@ -131,6 +134,7 @@
"petabit",
"Preact",
"preconnect",
"prerendered",
"prismjs",
"progressbar",
"radiogroup",

View File

@@ -48,8 +48,6 @@
{% endif %}
<link rel="stylesheet" href="/dist/styles/webawesome.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Used by Web Awesome App to inject other assets into the head. #}
{% server "head" %}

View File

@@ -145,7 +145,6 @@
<a href="/docs/components/radio-group/">Radio Group</a>
<ul>
<li><a href="/docs/components/radio/">Radio</a></li>
<li><a href="/docs/components/radio-button/">Radio Button</a></li>
</ul>
</li>
<li><a href="/docs/components/rating/">Rating</a></li>
@@ -178,35 +177,6 @@
</ul>
</wa-details>
<!-- Native styles -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a href="/docs/native/" title="Overview">
Native Styles
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>
<li><a href="/docs/native/button/">Button</a></li>
<li><a href="/docs/native/callout/">Callout</a></li>
<li><a href="/docs/native/checkbox/">Checkbox</a></li>
<li><a href="/docs/native/content/">Content</a></li>
<li><a href="/docs/native/details/">Details</a></li>
<li><a href="/docs/native/dialog/">Dialog</a></li>
<li><a href="/docs/native/input/">Input</a></li>
<li><a href="/docs/native/lists/">Lists</a></li>
<li>
<a href="/docs/native/progress/">Progress Bar</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</li>
<li><a href="/docs/native/radio/">Radio</a></li>
<li><a href="/docs/native/select/">Select</a></li>
<li><a href="/docs/native/slider/">Slider</a></li>
<li><a href="/docs/native/table/">Table</a></li>
<li><a href="/docs/native/textarea/">Textarea</a></li>
</ul>
</wa-details>
<!-- Style utilities -->
<wa-details appearance="outlined">
<h2 slot="summary">
@@ -216,14 +186,10 @@
</a>
</h2>
<ul>
<li><a href="/docs/utilities/appearance/">Appearance</a></li>
<li><a href="/docs/utilities/native/">Native Styles</a></li>
<li><a href="/docs/utilities/color/">Color</a></li>
<li><a href="/docs/utilities/fouce/">Reduce FOUCE</a></li>
<li><a href="/docs/utilities/fouce/">Reducing FOUCE</a></li>
<li><a href="/docs/utilities/rounding/">Rounding</a></li>
<li>
<a href="/docs/utilities/size/">Size</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</li>
<li><a href="/docs/utilities/text/">Text</a></li>
<li><a href="/docs/utilities/visually-hidden/">Visually Hidden</a></li>
</ul>

View File

@@ -3,12 +3,7 @@
{% endif -%}
{%- if status %}
{%- if status == "wip" %}
<wa-badge variant="danger">
<wa-icon name="pickaxe"></wa-icon>
Work In Progress
</wa-badge>
{%- elif status == "experimental" %}
{%- if status == "experimental" %}
<wa-badge variant="warning">
<wa-icon name="flask"></wa-icon>
Experimental

View File

@@ -6,7 +6,6 @@
<th></th>
<th><code>&lt;wa-button&gt;</code></th>
<th><code>&lt;button&gt;</code></th>
<th><code>.wa-button</code></th>
</thead>
<tbody>
<tr>
@@ -17,306 +16,168 @@
<td>
<button>Button</button>
</td>
</tr>
<tr>
<th><code>accent</code> + <code>outlined</code></th>
<td>
<div class="wa-button">Button</div>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="accent outlined">Brand</wa-button>
<wa-button variant="neutral" appearance="accent outlined">Neutral</wa-button>
<wa-button variant="success" appearance="accent outlined">Success</wa-button>
<wa-button variant="warning" appearance="accent outlined">Warning</wa-button>
<wa-button variant="danger" appearance="accent outlined">Danger</wa-button>
</div>
</td>
<td>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-accent wa-outlined">Brand</button>
<button class="wa-neutral wa-accent wa-outlined">Neutral</button>
<button class="wa-success wa-accent wa-outlined">Success</button>
<button class="wa-warning wa-accent wa-outlined">Warning</button>
<button class="wa-danger wa-accent wa-outlined">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-brand</code></th>
<th><code>accent</code></th>
<td>
<wa-button class="wa-brand">Brand</wa-button>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="accent">Brand</wa-button>
<wa-button variant="neutral" appearance="accent">Neutral</wa-button>
<wa-button variant="success" appearance="accent">Success</wa-button>
<wa-button variant="warning" appearance="accent">Warning</wa-button>
<wa-button variant="danger" appearance="accent">Danger</wa-button>
</div>
</td>
<td>
<button class="wa-brand">Brand</button>
</td>
<td>
<div class="wa-button wa-brand">Brand</div>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-accent">Brand</button>
<button class="wa-neutral wa-accent">Neutral</button>
<button class="wa-success wa-accent">Success</button>
<button class="wa-warning wa-accent">Warning</button>
<button class="wa-danger wa-accent">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-neutral</code></th>
<th><code>filled</code> + <code>outlined</code></th>
<td>
<wa-button class="wa-neutral">Neutral</wa-button>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="filled outlined">Brand</wa-button>
<wa-button variant="neutral" appearance="filled outlined">Neutral</wa-button>
<wa-button variant="success" appearance="filled outlined">Success</wa-button>
<wa-button variant="warning" appearance="filled outlined">Warning</wa-button>
<wa-button variant="danger" appearance="filled outlined">Danger</wa-button>
</div>
</td>
<td>
<button class="wa-neutral">Neutral</button>
</td>
<td>
<div class="wa-button wa-neutral">Neutral</div>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-filled wa-outlined">Brand</button>
<button class="wa-neutral wa-filled wa-outlined">Neutral</button>
<button class="wa-success wa-filled wa-outlined">Success</button>
<button class="wa-warning wa-filled wa-outlined">Warning</button>
<button class="wa-danger wa-filled wa-outlined">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-success</code></th>
<th><code>filled</code></th>
<td>
<wa-button class="wa-success">Success</wa-button>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="filled">Brand</wa-button>
<wa-button variant="neutral" appearance="filled">Neutral</wa-button>
<wa-button variant="success" appearance="filled">Success</wa-button>
<wa-button variant="warning" appearance="filled">Warning</wa-button>
<wa-button variant="danger" appearance="filled">Danger</wa-button>
</div>
</td>
<td>
<button class="wa-success">Success</button>
</td>
<td>
<div class="wa-button wa-success">Success</div>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-filled">Brand</button>
<button class="wa-neutral wa-filled">Neutral</button>
<button class="wa-success wa-filled">Success</button>
<button class="wa-warning wa-filled">Warning</button>
<button class="wa-danger wa-filled">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-warning</code></th>
<th><code>outlined</code></th>
<td>
<wa-button class="wa-warning">Warning</wa-button>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="outlined">Brand</wa-button>
<wa-button variant="neutral" appearance="outlined">Neutral</wa-button>
<wa-button variant="success" appearance="outlined">Success</wa-button>
<wa-button variant="warning" appearance="outlined">Warning</wa-button>
<wa-button variant="danger" appearance="outlined">Danger</wa-button>
</div>
</td>
<td>
<button class="wa-warning">Warning</button>
</td>
<td>
<div class="wa-button wa-warning">Warning</div>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-outlined">Brand</button>
<button class="wa-neutral wa-outlined">Neutral</button>
<button class="wa-success wa-outlined">Success</button>
<button class="wa-warning wa-outlined">Warning</button>
<button class="wa-danger wa-outlined">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-danger</code></th>
<th><code>plain</code></th>
<td>
<wa-button class="wa-danger">Danger</wa-button>
<div class="wa-cluster wa-gap-2xs">
<wa-button variant="brand" appearance="plain">Brand</wa-button>
<wa-button variant="neutral" appearance="plain">Neutral</wa-button>
<wa-button variant="success" appearance="plain">Success</wa-button>
<wa-button variant="warning" appearance="plain">Warning</wa-button>
<wa-button variant="danger" appearance="plain">Danger</wa-button>
</div>
</td>
<td>
<button class="wa-danger">Danger</button>
</td>
<td>
<div class="wa-button wa-danger">Danger</div>
<div class="wa-cluster wa-gap-2xs">
<button class="wa-brand wa-plain">Brand</button>
<button class="wa-neutral wa-plain">Neutral</button>
<button class="wa-success wa-plain">Success</button>
<button class="wa-warning wa-plain">Warning</button>
<button class="wa-danger wa-plain">Danger</button>
</div>
</td>
</tr>
<tr>
<th><code>.wa-accent</code></th>
<th><code>small</code></th>
<td>
<wa-button class="wa-accent">Accent</wa-button>
</td>
<td>
<button class="wa-accent">Accent</button>
</td>
<td>
<div class="wa-button wa-accent">Accent</div>
</td>
</tr>
<tr>
<th><code>.wa-filled</code></th>
<td>
<wa-button class="wa-filled">Filled</wa-button>
</td>
<td>
<button class="wa-filled">Filled</button>
</td>
<td>
<div class="wa-button wa-filled">Filled</div>
</td>
</tr>
<tr>
<th><code>.wa-outlined</code></th>
<td>
<wa-button class="wa-outlined">Outlined</wa-button>
</td>
<td>
<button class="wa-outlined">Outlined</button>
</td>
<td>
<div class="wa-button wa-outlined">Outlined</div>
</td>
</tr>
<tr>
<th><code>.wa-plain</code></th>
<td>
<wa-button class="wa-plain">Plain</wa-button>
</td>
<td>
<button class="wa-plain">Plain</button>
</td>
<td>
<div class="wa-button wa-plain">Plain</div>
</td>
</tr>
<tr>
<th><code>.wa-size-s</code></th>
<td>
<wa-button class="wa-size-s">Small</wa-button>
<wa-button size="small">Small</wa-button>
</td>
<td>
<button class="wa-size-s">Small</button>
</td>
<td>
<div class="wa-button wa-size-s">Small</div>
</td>
</tr>
<tr>
<th><code>.wa-size-m</code></th>
<th><code>medium</code></th>
<td>
<wa-button class="wa-size-m">Medium</wa-button>
<wa-button size="medium">Medium</wa-button>
</td>
<td>
<button class="wa-size-m">Medium</button>
</td>
<td>
<div class="wa-button wa-size-m">Medium</div>
</td>
</tr>
<tr>
<th><code>.wa-size-l</code></th>
<th><code>large</code></th>
<td>
<wa-button class="wa-size-l">Large</wa-button>
<wa-button size="large">Large</wa-button>
</td>
<td>
<button class="wa-size-l">Large</button>
</td>
<td>
<div class="wa-button wa-size-l">Large</div>
</td>
</tr>
<tr>
<th><code>.wa-pill</code></th>
<th><code>pill</code></th>
<td>
<wa-button class="wa-pill">Pill</wa-button>
<wa-button pill>Pill</wa-button>
</td>
<td>
<button class="wa-pill">Pill</button>
</td>
<td>
<div class="wa-button wa-pill">Pill</div>
</td>
</tr>
</tbody>
</table>
</div>
<wa-divider></wa-divider>
<h3>Callout</h3>
<div class="table-scroll">
<table>
<thead>
<th></th>
<th><code>&lt;wa-callout&gt;</code></th>
<th><code>.wa-callout</code></th>
</thead>
<tbody>
<tr>
<th class="test-failure"><em>default</em></th>
<td>
<wa-callout>Callout</wa-callout>
</td>
<td>
<div class="wa-callout">Callout</div>
</td>
</tr>
<tr>
<th><code>.wa-brand</code></th>
<td>
<wa-callout class="wa-brand">Brand</wa-callout>
</td>
<td>
<div class="wa-callout wa-brand">Brand</div>
</td>
</tr>
<tr>
<th><code>.wa-neutral</code></th>
<td>
<wa-callout class="wa-neutral">Neutral</wa-callout>
</td>
<td>
<div class="wa-callout wa-neutral">Neutral</div>
</td>
</tr>
<tr>
<th><code>.wa-success</code></th>
<td>
<wa-callout class="wa-success">Success</wa-callout>
</td>
<td>
<div class="wa-callout wa-success">Success</div>
</td>
</tr>
<tr>
<th><code>.wa-warning</code></th>
<td>
<wa-callout class="wa-warning">Warning</wa-callout>
</td>
<td>
<div class="wa-callout wa-warning">Warning</div>
</td>
</tr>
<tr>
<th><code>.wa-danger</code></th>
<td>
<wa-callout class="wa-danger">Danger</wa-callout>
</td>
<td>
<div class="wa-callout wa-danger">Danger</div>
</td>
</tr>
<tr>
<th><code>.wa-accent</code></th>
<td>
<wa-callout class="wa-accent">Accent</wa-callout>
</td>
<td>
<div class="wa-callout wa-accent">Accent</div>
</td>
</tr>
<tr>
<th><code>.wa-filled</code></th>
<td>
<wa-callout class="wa-filled">Filled</wa-callout>
</td>
<td>
<div class="wa-callout wa-filled">Filled</div>
</td>
</tr>
<tr>
<th><code>.wa-outlined</code></th>
<td>
<wa-callout class="wa-outlined">Outlined</wa-callout>
</td>
<td>
<div class="wa-callout wa-outlined">Outlined</div>
</td>
</tr>
<tr>
<th><code>.wa-plain</code></th>
<td>
<wa-callout class="wa-plain">Plain</wa-callout>
</td>
<td>
<div class="wa-callout wa-plain">Plain</div>
</td>
</tr>
<tr>
<th><code>.wa-size-s</code></th>
<td>
<wa-callout class="wa-size-s">Small</wa-callout>
</td>
<td>
<div class="wa-callout wa-size-s">Small</div>
</td>
</tr>
<tr>
<th><code>.wa-size-m</code></th>
<td>
<wa-callout class="wa-size-m">Medium</wa-callout>
</td>
<td>
<div class="wa-callout wa-size-m">Medium</div>
</td>
</tr>
<tr>
<th><code>.wa-size-l</code></th>
<td>
<wa-callout class="wa-size-l">Large</wa-callout>
</td>
<td>
<div class="wa-callout wa-size-l">Large</div>
</td>
</tr>
<tr>
<th><code>.wa-pill</code></th>
<td>
<wa-callout class="wa-pill">Pill</wa-callout>
</td>
<td>
<div class="wa-callout wa-pill">Pill</div>
</td>
</tr>
</tbody>
</table>
@@ -425,7 +286,7 @@
</div>
<wa-divider></wa-divider>
<h3 class="test-failure">Input</h3>
<h3>Input</h3>
<div class="table-scroll">
<table>
@@ -472,36 +333,36 @@
</td>
</tr>
<tr>
<th><code>.wa-filled</code></th>
<th><code>filled</code></th>
<td>
<wa-input label="Input (filled)" placeholder="Placeholder" class="wa-filled"></wa-input>
<wa-input label="Input (filled)" placeholder="Placeholder" appearance="filled"></wa-input>
</td>
<td>
<label>Input (filled) <input type="text" placeholder="Placeholder" class="wa-filled"></input></label>
</td>
</tr>
<tr>
<th><code>.wa-size-s</code></th>
<th><code>small</code></th>
<td>
<wa-input label="Input (small)" placeholder="Placeholder" class="wa-size-s"></wa-input>
<wa-input label="Input (small)" placeholder="Placeholder" size="small"></wa-input>
</td>
<td>
<label class="wa-size-s">Input (small) <input type="text" placeholder="Placeholder"></input></label>
</td>
</tr>
<tr>
<th><code>.wa-size-m</code></th>
<th><code>medium</code></th>
<td>
<wa-input label="Input (medium)" placeholder="Placeholder" class="wa-size-m"></wa-input>
<wa-input label="Input (medium)" placeholder="Placeholder" size="medium"></wa-input>
</td>
<td>
<label class="wa-size-m">Input (medium) <input type="text" placeholder="Placeholder"></input></label>
</td>
</tr>
<tr>
<th><code>.wa-size-l</code></th>
<th><code>large</code></th>
<td>
<wa-input label="Input (large)" placeholder="Placeholder" class="wa-size-l"></wa-input>
<wa-input label="Input (large)" placeholder="Placeholder" size="large"></wa-input>
</td>
<td>
<label class="wa-size-l">Input (large) <input type="text" placeholder="Placeholder"></input></label>
@@ -597,9 +458,9 @@
</td>
</tr>
<tr>
<th><code>.wa-filled</code></th>
<th><code>filled</code></th>
<td>
<wa-select label="Select (filled)" value="1" class="wa-filled">
<wa-select label="Select (filled)" value="1" appearance="filled">
<wa-option value="1">Option</wa-option>
</wa-select>
</td>
@@ -612,9 +473,9 @@
</td>
</tr>
<tr>
<th><code>.wa-size-s</code></th>
<th><code>small</code></th>
<td>
<wa-select label="Select (small)" value="1" class="wa-size-s">
<wa-select label="Select (small)" value="1" size="small">
<wa-option value="1">Option</wa-option>
</wa-select>
</td>
@@ -627,9 +488,9 @@
</td>
</tr>
<tr>
<th><code>.wa-size-m</code></th>
<th><code>medium</code></th>
<td>
<wa-select label="Select (medium)" value="1" class="wa-size-m">
<wa-select label="Select (medium)" value="1" size="medium">
<wa-option value="1">Option</wa-option>
</wa-select>
</td>
@@ -642,9 +503,9 @@
</td>
</tr>
<tr>
<th><code>.wa-size-l</code></th>
<th><code>large</code></th>
<td>
<wa-select label="Select (large)" value="1" class="wa-size-l">
<wa-select label="Select (large)" value="1" size="large">
<wa-option value="1">Option</wa-option>
</wa-select>
</td>
@@ -661,7 +522,7 @@
</div>
<wa-divider></wa-divider>
<h3 class="test-failure">Slider</h3>
<h3>Slider</h3>
<div class="table-scroll">
<table>
@@ -685,7 +546,7 @@
</div>
<wa-divider></wa-divider>
<h3 class="test-failure">Textarea</h3>
<h3>Textarea</h3>
<div class="table-scroll">
<table>
@@ -705,36 +566,36 @@
</td>
</tr>
<tr>
<th><code>.wa-filled</code></th>
<th><code>filled</code></th>
<td>
<wa-textarea label="Textarea (filled)" placeholder="Placeholder" class="wa-filled" rows="2"></wa-textarea>
<wa-textarea label="Textarea (filled)" placeholder="Placeholder" appearance="filled" rows="2"></wa-textarea>
</td>
<td>
<label>Textarea (filled) <textarea placeholder="Placeholder" class="wa-filled" rows="2"></textarea></label>
</td>
</tr>
<tr>
<th><code>.wa-size-s</code></th>
<th><code>small</code></th>
<td>
<wa-textarea label="Textarea (small)" placeholder="Placeholder" class="wa-size-s" rows="2"></wa-textarea>
<wa-textarea label="Textarea (small)" placeholder="Placeholder" size="small" rows="2"></wa-textarea>
</td>
<td>
<label class="wa-size-s">Textarea (small) <textarea placeholder="Placeholder" rows="2"></textarea></label>
</td>
</tr>
<tr>
<th><code>.wa-size-m</code></th>
<th><code>medium</code></th>
<td>
<wa-textarea label="Textarea (medium)" placeholder="Placeholder" class="wa-size-m" rows="2"></wa-textarea>
<wa-textarea label="Textarea (medium)" placeholder="Placeholder" size="medium" rows="2"></wa-textarea>
</td>
<td>
<label class="wa-size-m">Textarea (medium) <textarea placeholder="Placeholder" rows="2"></textarea></label>
</td>
</tr>
<tr>
<th><code>.wa-size-l</code></th>
<th><code>large</code></th>
<td>
<wa-textarea label="Textarea (large)" placeholder="Placeholder" class="wa-size-l" rows="2"></wa-textarea>
<wa-textarea label="Textarea (large)" placeholder="Placeholder" size="large" rows="2"></wa-textarea>
</td>
<td>
<label class="wa-size-l">Textarea (large) <textarea placeholder="Placeholder" rows="2"></textarea></label>

View File

@@ -160,60 +160,6 @@
</div>
<wa-divider></wa-divider>
<h3>Card</h3>
<div class="table-scroll">
<table>
<thead>
<th></th>
<th><code>size=""</code></th>
<th><code>.wa-size-[s|m|l]</code></th>
</thead>
<tbody>
<tr>
<th><code>small</code>/<code>s</code></th>
<td>
<wa-card size="small">
Card
</wa-card>
</td>
<td>
<wa-card class="wa-size-s">
Card
</wa-card>
</td>
</tr>
<tr>
<th><code>medium</code>/<code>m</code></th>
<td>
<wa-card size="medium">
Card
</wa-card>
</td>
<td>
<wa-card class="wa-size-m">
Card
</wa-card>
</td>
</tr>
<tr>
<th><code>large</code>/<code>l</code></th>
<td>
<wa-card size="large">
Card
</wa-card>
</td>
<td>
<wa-card class="wa-size-l">
Card
</wa-card>
</td>
</tr>
</tbody>
</table>
</div>
<wa-divider></wa-divider>
<h3>Checkbox</h3>
<div class="table-scroll">
@@ -534,14 +480,14 @@
<th><code>small</code>/<code>s</code></th>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button size="small" value="1">Radio</wa-radio-button>
<wa-radio-button size="small" value="2">Button</wa-radio-button>
<wa-radio appearance="button" size="small" value="1">Radio</wa-radio>
<wa-radio appearance="button" size="small" value="2">Button</wa-radio>
</wa-radio-group>
</td>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button class="wa-size-s" value="1">Radio</wa-radio-button>
<wa-radio-button class="wa-size-s" value="2">Button</wa-radio-button>
<wa-radio appearance="button" class="wa-size-s" value="1">Radio</wa-radio>
<wa-radio appearance="button" class="wa-size-s" value="2">Button</wa-radio>
</wa-radio-group>
</td>
</tr>
@@ -549,14 +495,14 @@
<th><code>medium</code>/<code>m</code></th>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button size="medium" value="1">Radio</wa-radio-button>
<wa-radio-button size="medium" value="2">Button</wa-radio-button>
<wa-radio appearance="button" size="medium" value="1">Radio</wa-radio>
<wa-radio appearance="button" size="medium" value="2">Button</wa-radio>
</wa-radio-group>
</td>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button class="wa-size-m" value="1">Radio</wa-radio-button>
<wa-radio-button class="wa-size-m" value="2">Button</wa-radio-button>
<wa-radio appearance="button" class="wa-size-m" value="1">Radio</wa-radio>
<wa-radio appearance="button" class="wa-size-m" value="2">Button</wa-radio>
</wa-radio-group>
</td>
</tr>
@@ -564,14 +510,14 @@
<th><code>large</code>/<code>l</code></th>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button size="large" value="1">Radio</wa-radio-button>
<wa-radio-button size="large" value="2">Button</wa-radio-button>
<wa-radio appearance="button" size="large" value="1">Radio</wa-radio>
<wa-radio appearance="button" size="large" value="2">Button</wa-radio>
</wa-radio-group>
</td>
<td>
<wa-radio-group orientation="horizontal">
<wa-radio-button class="wa-size-l" value="1">Radio</wa-radio-button>
<wa-radio-button class="wa-size-l" value="2">Button</wa-radio-button>
<wa-radio appearance="button" class="wa-size-l" value="1">Radio</wa-radio>
<wa-radio appearance="button" class="wa-size-l" value="2">Button</wa-radio>
</wa-radio-group>
</td>
</tr>
@@ -599,8 +545,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" size="small">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>
@@ -611,8 +557,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" class="wa-size-s">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>
@@ -626,8 +572,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" size="medium">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>
@@ -638,8 +584,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" class="wa-size-m">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>
@@ -653,8 +599,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" size="large">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>
@@ -665,8 +611,8 @@
<wa-radio value="2">Radio 2</wa-radio>
</wa-radio-group>
<wa-radio-group orientation="horizontal" label="Radio Button Group" hint="Hint" class="wa-size-l">
<wa-radio-button value="1">Radio 1</wa-radio-button>
<wa-radio-button value="2">Radio 2</wa-radio-button>
<wa-radio appearance="button" value="1">Radio 1</wa-radio>
<wa-radio appearance="button" value="2">Radio 2</wa-radio>
</wa-radio-group>
</div>
</td>

View File

@@ -1,17 +1,6 @@
{% extends '../_layouts/block.njk' %}
{% set component = components[page.fileSlug] %}
{# Component header #}
{% block notes %}
{% if native %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Just want the styles?
Check out the <a href="/docs/native/{{ native }}/">{{ ('/docs/native/' + native + '/') | getTitleFromUrl }} native styles</a>!
</wa-callout>
{% endif %}
{% endblock %}
{# Component API #}
{% block afterContent %}
{# Slots #}

View File

@@ -40,24 +40,6 @@ export const themeConfig = {
return this.base;
},
},
icon: {
library: {
cssProperty: '--wa-icon-library',
default: 'default',
},
family: {
cssProperty: '--wa-icon-family',
default(baseTheme) {
return baseTheme?.icon?.family ?? 'classic';
},
},
style: {
cssProperty: '--wa-icon-variant',
default(baseTheme) {
return baseTheme?.icon?.style ?? 'solid';
},
},
},
rounding: {
cssProperty: '--wa-border-radius-scale',
default(baseTheme) {

View File

@@ -4,14 +4,7 @@ const lunr = res[0].default;
const searchData = await res[1].json();
const searchIndex = lunr.Index.load(searchData.searchIndex);
const map = searchData.map;
const searchDebounce = 100;
const icons = {
component: 'puzzle-piece',
document: 'file',
home: 'house',
native: 'code',
theme: 'palette',
};
const searchDebounce = 200;
let searchTimeout;
// We're using Turbo, so references to these elements aren't guaranteed to remain intact
@@ -26,8 +19,12 @@ function getElements() {
// Show the search dialog when slash (or CMD+K) is pressed and focus is not inside a form element
document.addEventListener('keydown', event => {
if (
(event.key === '/' || (event.key === 'k' && (event.metaKey || event.ctrlKey))) &&
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
(event.key === 'k' && (event.metaKey || event.ctrlKey)) ||
(event.key === '/' &&
!event.composedPath().some(el => {
const tag = el?.tagName?.toLowerCase();
return tag === 'textarea' || (tag === 'input' && !['checkbox', 'radio'].includes(el.type));
}))
) {
event.preventDefault();
show();
@@ -48,7 +45,7 @@ function show() {
input.addEventListener('input', handleInput);
results.addEventListener('click', handleSelection);
dialog.addEventListener('keydown', handleKeyDown);
dialog.addEventListener('wa-hide', hide, { once: true });
dialog.addEventListener('wa-hide', handleClose);
dialog.open = true;
}
@@ -58,9 +55,17 @@ function hide() {
input.removeEventListener('input', handleInput);
results.removeEventListener('click', handleSelection);
dialog.removeEventListener('keydown', handleKeyDown);
dialog.removeEventListener('wa-hide', handleClose);
dialog.open = false;
}
function handleClose() {
const { input } = getElements();
input.value = '';
updateResults();
}
function handleInput() {
const { input } = getElements();
@@ -68,14 +73,6 @@ function handleInput() {
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
}
function handleClear() {
const { input } = getElements();
input.value = '';
input.focus();
updateResults();
}
function handleKeyDown(event) {
const { input, results } = getElements();
@@ -129,7 +126,12 @@ function handleSelection(event) {
if (link) {
event.preventDefault();
hide();
location.href = link.href;
if (window.Turbo) {
Turbo.visit(link.href);
} else {
location.href = link.href;
}
}
}
@@ -139,11 +141,40 @@ async function updateResults(query = '') {
try {
const hasQuery = query.length > 0;
const searchTokens = query
.split(' ')
.map((term, index, arr) => `${term}${index === arr.length - 1 ? `* ${term}~1` : '~1'}`)
.join(' ');
const matches = hasQuery ? searchIndex.search(`${query} ${searchTokens}`) : [];
let matches = [];
if (hasQuery) {
// Track seen refs to avoid duplicates
const seenRefs = new Set();
// Start with a standard search to get the best "exact match" result
searchIndex.search(`${query}`).forEach(match => {
matches.push(match);
seenRefs.add(match.ref);
});
// Add wildcard matches if not already included
searchIndex.search(`${query}*`).forEach(match => {
if (!seenRefs.has(match.ref)) {
matches.push(match);
seenRefs.add(match.ref);
}
});
// Add fuzzy search matches last
const fuzzyTokens = query
.split(' ')
.map(term => `${term}~1`)
.join(' ');
searchIndex.search(fuzzyTokens).forEach(match => {
if (!seenRefs.has(match.ref)) {
matches.push(match);
seenRefs.add(match.ref);
}
});
}
const hasResults = hasQuery && matches.length > 0;
dialog.classList.toggle('has-results', hasQuery && hasResults);
@@ -159,17 +190,17 @@ async function updateResults(query = '') {
const displayTitle = page.title ?? '';
const displayDescription = page.description ?? '';
const displayUrl = page.url.replace(/^\//, '');
let icon = icons.document;
let icon = 'file-text';
li.classList.add('site-search-result');
li.setAttribute('role', 'option');
li.setAttribute('id', `search-result-item-${match.ref}`);
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
if (page.url === '/') icon = icons.home;
if (page.url.startsWith('/docs/native')) icon = icons.native;
if (page.url.startsWith('/docs/components')) icon = icons.component;
if (page.url.startsWith('/docs/theme') || page.url.startsWith('/docs/restyle')) icon = icons.theme;
if (page.url === '/') icon = 'home';
if (page.url.startsWith('/docs/utilities/native')) icon = 'code';
if (page.url.startsWith('/docs/components')) icon = 'puzzle-piece';
if (page.url.startsWith('/docs/theme') || page.url.startsWith('/docs/restyle')) icon = 'palette';
a.href = page.url;
a.innerHTML = `

View File

@@ -5,7 +5,7 @@
*/
export function capitalize(str) {
str += '';
return str[0].toUpperCase() + str.slice(1);
return str[0]?.toUpperCase() + str.slice(1);
}
/**
@@ -29,7 +29,7 @@ export function slugify(str) {
* @returns {string} The camel case string.
*/
export function camelCase(str) {
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
return str.replace(/-([a-z])/g, (_, letter) => letter?.toUpperCase());
}
/**
@@ -38,5 +38,5 @@ export function camelCase(str) {
* @returns {string} The kebab case string.
*/
export function kebabCase(str) {
return str.replace(/([A-Z])/g, '-$1').toLowerCase();
return str.replace(/([A-Z])/g, '-$1')?.toLowerCase();
}

View File

@@ -16,13 +16,12 @@
padding: 2rem 3.25rem 2rem 2rem;
min-width: 20rem;
max-width: 100%;
overflow: hidden;
> :first-child {
> :first-child:not(dialog) {
margin-block-start: 0;
}
> :last-child {
> :last-child:not(dialog) {
margin-block-end: 0;
}
}

View File

@@ -93,15 +93,18 @@ wa-page > header {
margin: 0;
}
h2:not(:first-child),
wa-details:not(:first-child) {
h2:not(:first-child) {
margin-block-start: var(--wa-space-xs);
}
wa-details {
border: none;
background: none;
padding: 0;
--spacing: var(--wa-space-xs);
&::part(base) {
border: none;
background: none;
padding: 0;
}
}
ul {
@@ -302,6 +305,13 @@ h1.title {
}
}
@media print {
/* Show URLs for printed links */
a:not(.anchor-heading)[href]::after {
content: ' (' attr(href) ')';
}
}
/* Callouts */
.callout {
display: flex;
@@ -416,146 +426,6 @@ wa-card .page-name {
margin-block-start: var(--wa-space-2xl);
}
/* Interactive cards */
wa-card[role='button'][tabindex='0'],
button,
a[href],
wa-option,
wa-radio,
wa-checkbox {
/* Disabled state */
&:is(:disabled, [disabled], [aria-disabled='true']) {
&:is(wa-card, :has(> wa-card)) {
opacity: 60%;
cursor: not-allowed;
}
}
&:where(:not(:disabled, [disabled], [aria-disabled='true'])) {
&:has(> wa-card) {
/* Parents only (not interactive <wa-card>) */
margin: calc(var(--wa-border-width-m) + 1px);
padding: 0;
/* Hover state */
&:hover,
&:state(hover),
&:state(current) {
/* Do not change the parent background as a hover effect (we style the card instead) */
background: transparent !important;
}
&::part(control),
&:is(wa-option)::part(checked-icon) {
--background-color-checked: var(--wa-color-brand-fill-loud);
--checked-icon-scale: 0.5;
--offset: var(--wa-space-2xs);
position: absolute;
inset: calc(var(--offset) + var(--wa-border-width-m));
inset-block-end: auto;
inset-inline-start: auto;
z-index: 1;
margin: 0;
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
}
&::part(checked-icon) {
color: var(--wa-color-brand-on-loud);
}
&:is(wa-option)::part(checked-icon) {
inset-block-start: calc(var(--wa-space-smaller) - 0.5em);
inset-inline-end: calc(var(--wa-space-smaller) - 0.5em);
width: 1em;
height: 1em;
line-height: 1em;
padding: 0.4em;
border-radius: var(--wa-border-radius-circle);
text-align: center;
font-size: var(--wa-font-size-xs);
}
}
/* Hover state */
&:hover,
&:state(hover),
&:state(current) {
&:is(wa-card),
> wa-card {
--border-color: var(--wa-color-brand-border-loud);
border-color: var(--border-color);
box-shadow: 0 0 0 var(--wa-border-width-s) var(--border-color);
}
}
&:is(wa-card, :has(> wa-card)) {
/* Interactive card parent */
position: relative;
cursor: pointer;
/* Unselected state */
&:where(:not(:state(checked), :state(selected), [aria-checked='true'], [aria-selected='true'])) {
&::part(checked-icon),
&::part(control) {
display: none;
}
}
}
&:is(wa-card),
> wa-card {
/* The card itself */
box-shadow: none;
}
}
}
/* Selected cards */
:state(selected),
:state(checked),
[aria-checked='true'],
[aria-selected='true'] {
&:is(wa-card, :has(> wa-card)) {
background: transparent;
}
&:is(wa-card),
> wa-card {
--border-color: var(--wa-color-brand-border-loud);
box-shadow: 0 0 0 var(--wa-border-width-m) var(--border-color);
&::part(body) {
background: var(--wa-color-brand-fill-quiet);
}
}
}
wa-select:has(> wa-option > wa-card) {
&::part(listbox) {
--column-width: 1fr;
--columns: 1;
--gap: var(--wa-space-smaller);
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--column-width), 1fr));
width: calc(var(--columns) * var(--column-width) + (var(--columns) - 1) * var(--gap) + 2 * var(--wa-space));
max-width: var(--auto-size-available-width, 90vw);
gap: var(--gap);
padding: var(--wa-space-smaller) var(--wa-space);
}
> wa-option > wa-card {
--spacing: var(--wa-space-s);
}
}
wa-radio:has(> wa-card) {
grid-template-columns: 1fr;
width: auto;
}
/* Swatches */
.swatch {
position: relative;

View File

@@ -71,7 +71,8 @@ html.wa-theme-tailspin .preview-container {
.hero {
--hero-background-color: var(--wa-color-surface-default);
--hero-lines-color: color-mix(in oklab, var(--wa-color-neutral-fill-normal), transparent 30%);
background: linear-gradient(to top, var(--wa-color-surface-lowered), transparent 40%),
background:
linear-gradient(to top, var(--wa-color-surface-lowered), transparent 40%),
radial-gradient(circle at 10% 70%, color-mix(in oklab, var(--wa-color-red-50) 16%, transparent), transparent 30%),
radial-gradient(
circle at 40% 50%,

View File

@@ -74,7 +74,7 @@
.swatch-select {
padding: 2px;
wa-radio-button {
wa-radio {
--swatch-border-color: color-mix(in oklab, canvastext, transparent 80%);
&::part(base) {
@@ -93,7 +93,7 @@
--border-radius: var(--wa-border-radius-circle);
}
wa-radio-button:is([checked], :state(checked)) {
wa-radio:is([checked], :state(checked)) {
--swatch-border-color: var(--wa-color-surface-default);
&::part(base) {
box-shadow:

View File

@@ -90,7 +90,7 @@ export default {
let value = this.computed[key];
if (key === 'library') {
titles[key] = iconLibraries[value].title;
titles[key] = iconLibraries[value]?.title;
}
titles[key] ??= capitalize(value);
@@ -113,6 +113,7 @@ export default {
if (vary.length > 0) {
for (let param of vary) {
let allValues = library[param];
if (!allValues) return;
let random = (allValues.random ??= []);
while (random.length < TOTAL_ICONS) {

View File

@@ -5,7 +5,7 @@ import InfoTip from './info-tip.js';
const template = `
<wa-radio-group :label class="swatch-select" :class="'swatch-shape-' + shape" orientation="horizontal" :value @input="handleInput">
<info-tip v-for="value in values">
<wa-radio-button :value :label="getLabel(value)" :style="{'--color': getColor(value)}"></wa-radio-button>
<wa-radio appearance="button" :value :label="getLabel(value)" :style="{'--color': getColor(value)}"></wa-radio>
<template #content>
{{ getLabel(value) }}
</template>

View File

@@ -55,7 +55,7 @@ it is rarely a good idea to mix sizes within the same button group.
Set the `orientation` attribute to `vertical` to make a vertical button group.
```html {.example}
<wa-button-group orientation="vertical" label="Options" style="max-width: 80px;">
<wa-button-group orientation="vertical" label="Options" style="max-width: 120px;">
<wa-button>
<wa-icon slot="prefix" name="plus"></wa-icon>
New
@@ -157,16 +157,13 @@ Pill buttons are supported through the button's `pill` attribute.
</wa-button-group>
```
### Dropdowns and Native Buttons in Button Groups
### Dropdowns in Button Groups
Other elements can also be placed inside button groups:
- Native buttons as long as their [native styles](/docs/native/button) are included
- Dropdowns as long as the trigger is either a `<wa-button>`, or a `<button>` with [native styles](/docs/native/button) included.
Dropdowns can be placed into button groups.
```html {.example}
<wa-button-group label="Example Button Group">
<wa-button>Button</wa-button>
<button>Native Button</button>
<wa-dropdown>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
@@ -175,6 +172,7 @@ Other elements can also be placed inside button groups:
<wa-menu-item>Item 3</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-button>Button</wa-button>
</wa-button-group>
```

View File

@@ -110,15 +110,15 @@ Use the `appearance` attribute to change the callout's visual appearance (the de
Use the `size` attribute to change a callout's size.
```html {.example}
<wa-callout variant="brand" appearance="outlined accent" size="large">
<wa-icon slot="icon" name="circle-info" variant="solid"></wa-icon>
<wa-callout size="large">
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
This is meant to be very emphasized.
</wa-callout>
<wa-callout>
<wa-callout size="medium">
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
Normal-sized callout.
</wa-callout>
<wa-callout variant="plain" appearance="plain" size="small">
<wa-callout size="small">
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
Just a small tip!
</wa-callout>

View File

@@ -127,41 +127,6 @@ If using SSR, you need to also use the `with-media` attribute to add a media sec
</style>
```
### Sizing
Use the `size` attribute to change a card's size.
```html {.example}
<div class="wa-stack">
<wa-card size="small">
This is a small card.
<footer slot="footer" class="wa-split">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
<wa-card size="medium">
This is a medium card (default).
<footer slot="footer" class="wa-split">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
<wa-card size="large">
This is a large card.
<footer slot="footer" class="wa-split">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating></wa-rating>
</footer>
</wa-card>
</div>
```
### Appearance
Use the `appearance` attribute to change the card's visual appearance.

View File

@@ -27,86 +27,6 @@ Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regu
<wa-icon family="duotone" variant="regular" name="cake-slice"></wa-icon>
```
### Setting defaults via CSS
You can use certain CSS custom properties to set icon defaults, not just on the icon itself, but any ancestor.
This can be useful when you want certain parameters to vary based on context, e.g. icons inside callouts or all icons for a given theme.
:::warning
These CSS properties are intended to set **defaults**, and thus only make a difference when the corresponding attributes are not set.
In future versions of Web Awesome, we may change this behavior to allow CSS properties to override attributes if `!important` is used.
:::
For example, here is how you can use CSS custom properties to set a default icon for each type of callout:
```html {.example}
<wa-callout>
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
This is a normal callout.
</wa-callout>
<wa-callout variant="danger">
<wa-icon slot="icon" name="dumpster-fire" variant="solid"></wa-icon>
This is a callout with an explicit icon, which overrides these defaults.
</wa-callout>
<wa-callout variant="warning">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Here be dragons.
</wa-callout>
<wa-callout variant="danger">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Here be more dragons.
</wa-callout>
<wa-callout variant="success">
<!-- Look ma, no attributes! -->
<wa-icon slot="icon"></wa-icon>
Success!
</wa-callout>
<style>
wa-callout {
--wa-icon-variant: regular;
--wa-icon-name: info-circle;
&[variant="warning"] {
--wa-icon-name: triangle-exclamation;
}
&[variant="danger"] {
--wa-icon-name: circle-exclamation;
}
&[variant="success"] {
--wa-icon-name: circle-check;
}
}
</style>
```
You can even set icons dynamically, as a response to user interaction or media queries.
For example, here's how we can change the icon on hover:
```html {.example}
<wa-button class="github" href="https://github.com/webawesome/webawesome"><wa-icon slot="prefix" fixed-width></wa-icon> GitHub Repo</wa-button>
<style>
.github {
--wa-icon-name: github;
--wa-icon-family: brands;
&:hover {
--wa-icon-name: arrow-up-right-from-square;
--wa-icon-family: classic;
}
}
</style>
```
### Colors
Icons inherit their color from the current text color. Thus, you can set the `color` property on the `<wa-icon>` element or an ancestor to change the color.
@@ -222,17 +142,33 @@ This will register the [Bootstrap Icons](https://icons.getbootstrap.com/) librar
Icons in this library are licensed under the [MIT License](https://github.com/twbs/icons/blob/main/LICENSE).
```html
```html {.example}
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('default', {
registerIconLibrary('bootstrap', {
resolver: (name, family) => {
const suffix = family === 'filled' ? '-fill' : '';
return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/${name}${suffix}.svg`
}
});
</script>
<div style="font-size: 24px;">
<wa-icon library="bootstrap" name="backpack"></wa-icon>
<wa-icon library="bootstrap" name="cup-hot"></wa-icon>
<wa-icon library="bootstrap" name="envelope-heart"></wa-icon>
<wa-icon library="bootstrap" name="inboxes"></wa-icon>
<wa-icon library="bootstrap" name="lamp"></wa-icon>
<wa-icon library="bootstrap" name="piggy-bank"></wa-icon>
<br />
<wa-icon library="bootstrap" family="filled" name="backpack"></wa-icon>
<wa-icon library="bootstrap" family="filled" name="cup-hot"></wa-icon>
<wa-icon library="bootstrap" family="filled" name="envelope-heart"></wa-icon>
<wa-icon library="bootstrap" family="filled" name="inboxes"></wa-icon>
<wa-icon library="bootstrap" family="filled" name="lamp"></wa-icon>
<wa-icon library="bootstrap" family="filled" name="piggy-bank"></wa-icon>
</div>
```
### Boxicons
@@ -287,6 +223,18 @@ This will register the [Lucide](https://lucide.dev/) icon library using the jsDe
Icons in this library are licensed under the [MIT License](https://github.com/lucide-icons/lucide/blob/master/LICENSE).
```html {.example}
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('lucide', {
resolver: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`,
mutator: svg => svg.querySelectorAll('path').forEach(path => {
path.setAttribute('fill', 'none');
path.setAttribute('stroke', 'currentColor');
})
});
</script>
<div style="font-size: 24px;">
<wa-icon library="lucide" name="feather"></wa-icon>
<wa-icon library="lucide" name="pie-chart"></wa-icon>
@@ -295,14 +243,6 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
<wa-icon library="lucide" name="printer"></wa-icon>
<wa-icon library="lucide" name="shopping-cart"></wa-icon>
</div>
<script type="module">
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('lucide', {
resolver: name => `https://cdn.jsdelivr.net/npm/lucide-static@0.16.29/icons/${name}.svg`
});
</script>
```
### Heroicons
@@ -316,7 +256,11 @@ Icons in this library are licensed under the [MIT License](https://github.com/ta
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('heroicons', {
resolver: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`
resolver: name => `https://cdn.jsdelivr.net/npm/heroicons@2.0.1/24/outline/${name}.svg`,
mutator: svg => svg.querySelectorAll('path').forEach(path => {
path.setAttribute('fill', 'none');
path.setAttribute('stroke', 'currentColor');
})
});
</script>
@@ -341,7 +285,11 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('iconoir', {
resolver: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`
resolver: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`,
mutator: svg => svg.querySelectorAll('path').forEach(path => {
path.setAttribute('fill', 'none');
path.setAttribute('stroke', 'currentColor');
})
});
</script>

View File

@@ -41,7 +41,7 @@ body {
```
:::info
If you use [native styles](/docs/native/), this is already taken care of.
If you use [native styles](/docs/utilities/native/), this is already taken care of.
:::
## Examples
@@ -164,7 +164,7 @@ wa-page[view='desktop'] [data-toggle-nav] {
```
:::info
If you use [native styles](/docs/native/), this is already taken care for you, and the `data-toggle-nav` button is already hidden on wider screens.
If you use [native styles](/docs/utilities/native/), this is already taken care for you, and the `data-toggle-nav` button is already hidden on wider screens.
:::
#### Custom Widths
@@ -205,13 +205,7 @@ You can override the default spacing for each slot with your own CSS. In this ex
## Utility classes
[Native styles](/docs/native/) define a few useful defaults for `<wa-page>`, as well as two utility classes you can use for common responsive design tasks:
[Native styles](/docs/utilities/native/) define a few useful defaults for `<wa-page>`, as well as two utility classes you can use for common responsive design tasks:
- `.wa-mobile-only` hides an element on the desktop view
- `.wa-desktop-only` hides an element on the mobile view
If you dont want to use [native styles](/docs/native/), you can include this stylesheet in your project to use these:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/components/page.css' %}" />
```

View File

@@ -1,151 +0,0 @@
---
title: Radio Button
description: Radios buttons allow the user to select a single option from a group using a button-like control.
tags: forms
parent: radio-group
icon: radio-group
---
Radio buttons are designed to be used with [radio groups](/docs/components/radio-group). When a radio button has focus, the arrow keys can be used to change the selected option just like standard radio controls.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
## Examples
### Checked States
To set the initial value and checked state, use the `value` attribute on the containing radio group.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Disabled
Use the `disabled` attribute to disable a radio button.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2" disabled>Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Sizes
Use the `size` attribute to change a radio button's size.
```html {.example}
<wa-radio-group size="small" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="medium" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="large" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Pill Buttons
Use the `pill` attribute to give radio buttons rounded edges.
```html {.example}
<wa-radio-group size="small" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="medium" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
<br />
<wa-radio-group size="large" label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button pill value="1">Option 1</wa-radio-button>
<wa-radio-button pill value="2">Option 2</wa-radio-button>
<wa-radio-button pill value="3">Option 3</wa-radio-button>
</wa-radio-group>
```
### Prefix and Suffix Icons
Use the `prefix` and `suffix` slots to add icons.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="1">
<wa-radio-button value="1">
<wa-icon slot="prefix" name="archive" variant="solid"></wa-icon>
Option 1
</wa-radio-button>
<wa-radio-button value="2">
<wa-icon slot="suffix" name="bag-shopping" variant="solid"></wa-icon>
Option 2
</wa-radio-button>
<wa-radio-button value="3">
<wa-icon slot="prefix" name="gift" variant="solid"></wa-icon>
<wa-icon slot="suffix" name="shopping-cart" variant="solid"></wa-icon>
Option 3
</wa-radio-button>
</wa-radio-group>
```
### Buttons with Icons
You can omit button labels and use icons instead. Make sure to set a `label` attribute on each icon so screen readers will announce each option correctly.
```html {.example}
<wa-radio-group label="Select an option" orientation="horizontal" name="a" value="neutral">
<wa-radio-button value="angry">
<wa-icon name="face-angry" variant="solid" label="Angry"></wa-icon>
</wa-radio-button>
<wa-radio-button value="sad">
<wa-icon name="face-frown" variant="solid" label="Sad"></wa-icon>
</wa-radio-button>
<wa-radio-button value="neutral">
<wa-icon name="face-meh" variant="solid" label="Neutral"></wa-icon>
</wa-radio-button>
<wa-radio-button value="happy">
<wa-icon name="face-smile" variant="solid" label="Happy"></wa-icon>
</wa-radio-button>
<wa-radio-button value="laughing">
<wa-icon name="face-laugh" variant="solid" label="Laughing"></wa-icon>
</wa-radio-button>
</wa-radio-group>
```

View File

@@ -1,6 +1,6 @@
---
title: Radio Group
description: Radio groups are used to group multiple radios or radio buttons so they function as a single form control.
description: Radio groups are used to group multiple radios so they function as a single form control.
tags: [inputs, forms]
icon: radio-group
---
@@ -29,7 +29,7 @@ Add descriptive hint to a radio group with the `hint` attribute. For hints that
### Radio Buttons
[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.
Set the `appearance` attribute to `button` on all radios to render a radio button group.
```html {.example}
<wa-radio-group
@@ -39,9 +39,9 @@ Add descriptive hint to a radio group with the `hint` attribute. For hints that
name="a"
value="1"
>
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
<wa-radio appearance="button" value="1">Option 1</wa-radio>
<wa-radio appearance="button" value="2">Option 2</wa-radio>
<wa-radio appearance="button" value="3">Option 3</wa-radio>
</wa-radio-group>
<br>
@@ -54,9 +54,9 @@ Add descriptive hint to a radio group with the `hint` attribute. For hints that
value="1"
style="max-width: 300px;"
>
<wa-radio-button value="1">Option 1</wa-radio-button>
<wa-radio-button value="2">Option 2</wa-radio-button>
<wa-radio-button value="3">Option 3</wa-radio-button>
<wa-radio appearance="button" value="1">Option 1</wa-radio>
<wa-radio appearance="button" value="2">Option 2</wa-radio>
<wa-radio appearance="button" value="3">Option 3</wa-radio>
</wa-radio-group>
```
@@ -92,7 +92,7 @@ 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-button) will be determined by the Radio Group's `size` attribute.
The size of [Radios](/docs/components/radio) will be determined by the Radio Group's `size` attribute.
```html {.example}
<wa-radio-group label="Select an option" size="medium" value="medium" onchange="this.size = this.value">

View File

@@ -7,11 +7,7 @@ native: input
---
```html {.example}
<form action="about:blank" target="_blank">
<wa-textarea label="Type something', will ya" name="a"></wa-textarea>
<button type="submit">Submit</button>
</form>
<wa-textarea label="Type something', will ya"></wa-textarea>
```
:::info

View File

@@ -133,7 +133,7 @@ Most (but not all) components expose parts. You can find them in each component'
## Native Elements
If you're using [native styles](/docs/native), any custom styles added for a component should also target the corresponding native element. In general, the same styles you declare for components will work just the same to style their native counterparts.
If you're using [native styles](/docs/utilities/native), any custom styles added for a component should also target the corresponding native element. In general, the same styles you declare for components will work just the same to style their native counterparts.
For example, we can give `<input type="checkbox">` the same custom styles as `<wa-checkbox>` by using the custom properties required to style the component:
```html {.example}
@@ -196,10 +196,7 @@ For example, we can give all outlined callouts a thick left border, regardless o
</wa-callout>
<style>
wa-callout:is(
[appearance~="outlined"],
.wa-outlined
) {
wa-callout:is([appearance~="outlined"]) {
border-left-width: var(--wa-panel-border-radius);
}
</style>

View File

@@ -524,10 +524,10 @@ hasOutline: false
</div>
<div>
<wa-radio-group label="Need a logo?" name="project-logo-selector" value="shapes">
<wa-radio-button value="shapes"><wa-icon name="shapes"></wa-icon></wa-radio-button>
<wa-radio-button value="meteor"><wa-icon name="meteor"></wa-icon></wa-radio-button>
<wa-radio-button value="cat-space"><wa-icon name="cat-space"></wa-icon></wa-radio-button>
<wa-radio-button value="puzzle-piece"><wa-icon name="puzzle-piece"></wa-icon></wa-radio-button>
<wa-radio appearance="button" value="shapes"><wa-icon name="shapes"></wa-icon></wa-radio>
<wa-radio appearance="button" value="meteor"><wa-icon name="meteor"></wa-icon></wa-radio>
<wa-radio appearance="button" value="cat-space"><wa-icon name="cat-space"></wa-icon></wa-radio>
<wa-radio appearance="button" value="puzzle-piece"><wa-icon name="puzzle-piece"></wa-icon></wa-radio>
<wa-button value="[choose]" appearance="plain" id="icon-chooser-trigger" class="logo-chooser">
<wa-tooltip for="icon-chooser-trigger" distance="-3" hoist>Browse Icons</wa-tooltip>
<wa-icon name="ellipsis" library="fa-classic-regular"></wa-icon>
@@ -684,12 +684,12 @@ hasOutline: false
<div id="color-mode-selector">
<wa-radio-group class="hidden-label" label="Color mode" name="color-mode" value="light">
<wa-radio-button value="light">
<wa-radio appearance="button" value="light">
<wa-icon name="sun" library="fa-classic-regular"></wa-icon>
</wa-radio-button>
<wa-radio-button value="dark">
</wa-radio>
<wa-radio appearance="button" value="dark">
<wa-icon name="moon" library="fa-classic-regular"></wa-icon>
</wa-radio-button>
</wa-radio>
</wa-radio-group>
</div>
@@ -2239,10 +2239,10 @@ hasOutline: false
<div>
<div style="margin: var(--wa-space-3xl) 0">
<wa-radio-group label="Choose a finish" name="finish" value="Matte" class="product-finish">
<wa-radio-button value="Matte">Matte</wa-radio-button>
<wa-radio-button value="Glossy">Glossy</wa-radio-button>
<wa-radio-button value="Pebbled" disabled>Pebbled</wa-radio-button>
<wa-radio-button value="Holo">Holo</wa-radio-button>
<wa-radio appearance="button" value="Matte">Matte</wa-radio>
<wa-radio appearance="button" value="Glossy">Glossy</wa-radio>
<wa-radio appearance="button" value="Pebbled" disabled>Pebbled</wa-radio>
<wa-radio appearance="button" value="Holo">Holo</wa-radio>
</wa-radio-group>
</div>
<div style="display: flex; align-items: end; gap: 1rem;">

View File

@@ -32,7 +32,7 @@ To get everything included in Web Awesome, add the following code to the `<head>
This snippet includes three parts:
1. **The default theme**, a stylesheet that gives a cohesive look to Web Awesome components with both light and dark modes
2. **Web Awesome styles**, an optional stylesheet that [styles native HTML elements](/docs/native) and includes [utility classes](/docs/utilities) you can use in your project
2. **Web Awesome styles**, an optional stylesheet that [styles native HTML elements](/docs/utilities/native) and includes [utility classes](/docs/utilities) you can use in your project
3. **The autoloader**, a lightweight script watches the DOM for unregistered Web Awesome elements and lazy loads them for you — even if they're added dynamically
Now you can [start using Web Awesome!](/docs/usage)

View File

@@ -12,7 +12,7 @@ override:tags: []
Layout components are included in Web Awesome's [autoloader](/docs/#quick-start-autoloading-via-cdn). You can also import them individually via [cherry picking](/docs/#cherry-picking).
Layout utilities are bundled with all [style utilities](/docs/utilities). You can import all Web Awesome page styles (including [native styles](/docs/native/)) by including the following stylesheet in your project:
Layout utilities are bundled with all [style utilities](/docs/utilities). You can import all Web Awesome page styles (including [native styles](/docs/utilities/native/)) by including the following stylesheet in your project:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />

View File

@@ -1,144 +0,0 @@
---
title: Button
description: 'Button styles apply your Web Awesome theme to native HTML buttons. Buttons are activated by users to perform actions, such as submitting a form.'
tags: forms
component: button
icon: button
snippets:
'<button>': https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button
'.wa-button': false
file: styles/native/button.css
---
```html {.example}
<button>Button</button>
<input type="button" value="Input (button)">
<input type="reset" value="Input (reset)">
<input type="submit" value="Input (submit)">
```
## Examples
### Variants
Use the [variant utility classes](../utilities/color.md) to set the button's semantic variant.
```html {.example}
<button class="wa-neutral">Neutral</button>
<button class="wa-brand">Brand</button>
<button class="wa-success">Success</button>
<button class="wa-warning">Warning</button>
<button class="wa-danger">Danger</button>
```
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the button's visual appearance:
```html {.example}
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-neutral">A + O</button>
<button class="wa-accent wa-neutral">Accent</button>
<button class="wa-outlined wa-neutral">Outlined</button>
<button class="wa-filled wa-outlined wa-neutral">F + O</button>
<button class="wa-filled wa-neutral">Filled</button>
<button class="wa-plain wa-neutral">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-brand">A + O</button>
<button class="wa-accent wa-brand">Accent</button>
<button class="wa-outlined wa-brand">Outlined</button>
<button class="wa-filled wa-outlined wa-brand">F + O</button>
<button class="wa-filled wa-brand">Filled</button>
<button class="wa-plain wa-brand">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-success">A + O</button>
<button class="wa-accent wa-success">Accent</button>
<button class="wa-outlined wa-success">Outlined</button>
<button class="wa-filled wa-outlined wa-success">F + O</button>
<button class="wa-filled wa-success">Filled</button>
<button class="wa-plain wa-success">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-warning">A + O</button>
<button class="wa-accent wa-warning">Accent</button>
<button class="wa-outlined wa-warning">Outlined</button>
<button class="wa-filled wa-outlined wa-warning">F + O</button>
<button class="wa-filled wa-warning">Filled</button>
<button class="wa-plain wa-warning">Plain</button>
</div>
<div>
<button class="wa-accent wa-outlined wa-danger">A + O</button>
<button class="wa-accent wa-danger">Accent</button>
<button class="wa-outlined wa-danger">Outlined</button>
<button class="wa-filled wa-outlined wa-danger">F + O</button>
<button class="wa-filled wa-danger">Filled</button>
<button class="wa-plain wa-danger">Plain</button>
</div>
```
### Sizes
Use the [size utility classes](../utilities/size.md) to change a button's size.
```html {.example}
<button class="wa-size-s">Small</button>
<button class="wa-size-m">Medium</button>
<button class="wa-size-l">Large</button>
```
### Pill Buttons
Use the `wa-pill` class to give buttons rounded edges.
```html {.example}
<button class="wa-size-s wa-pill">Small</button>
<button class="wa-size-m wa-pill">Medium</button>
<button class="wa-size-l wa-pill">Large</button>
```
### Link Buttons
It's often helpful to have a link that looks like a button.
This is possible by adding a `wa-button` class to your link.
```html {.example}
<a href="https://example.com/" class="wa-button">Link</a>
<a href="https://example.com/" target="_blank" class="wa-button">New Window</a>
<a href="/assets/images/logo.svg" download="shoelace.svg" class="wa-button">Download</a>
```
### Setting a Custom Width
As expected, buttons can be given a custom width by setting the `width` CSS property. This is useful for making buttons span the full width of their container on smaller screens.
```html {.example}
<button class="wa-size-s" style="width: 100%; margin-bottom: 1rem;">Small</button>
<button class="wa-size-m" style="width: 100%; margin-bottom: 1rem;">Medium</button>
<button class="wa-size-l" style="width: 100%;">Large</button>
```
<!--
### Loading
Use the `loading` attribute to make a button busy. The width will remain the same as before, preventing adjacent elements from moving around.
```html {.example}
<button class="wa-brand" loading>Brand</button>
<button class="wa-success" loading>Success</button>
<button class="wa-neutral" loading>Neutral</button>
<button class="wa-warning" loading>Warning</button>
<button class="wa-danger" loading>Danger</button>
```
### Disabled
Use the `disabled` attribute to disable a button.
```html {.example}
<button class="wa-brand" disabled>Brand</button>
<button class="wa-success" disabled>Success</button>
<button class="wa-neutral" disabled>Neutral</button>
<button class="wa-warning" disabled>Warning</button>
``` -->

View File

@@ -1,117 +0,0 @@
---
title: Callout
description: Callouts are used to display important messages inline.
component: callout
icon: callout
snippets: '.wa-callout'
file: styles/native/callout.css
---
```html {.example}
<article class="wa-callout">
This is a callout style, applied to a standard article element.
</article>
```
## Examples
### Variants
Use the [variant utility classes](../utilities/color.md) to set the callout's color variant.
```html {.example}
<article class="wa-callout wa-brand">
<strong>This is super informative</strong><br />
You can tell by how pretty the callout is.
</article>
<br />
<article class="wa-callout wa-success">
<strong>Your changes have been saved</strong><br />
You can safely exit the app now.
</article>
<br />
<article class="wa-callout wa-neutral">
<strong>Your settings have been updated</strong><br />
Settings will take effect on next login.
</article>
<br />
<article class="wa-callout wa-warning">
<strong>Your session has ended</strong><br />
Please login again to continue.
</article>
<br />
<article class="wa-callout wa-danger">
<strong>Your account has been deleted</strong><br />
We're very sorry to see you go!
</article>
```
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the callout's visual appearance (the default is `outlined filled`).
```html {.example}
<article class="wa-callout wa-brand wa-outlined wa-accent">
This <strong>accent</strong> callout is also <strong>outlined</strong>
</article>
<br />
<article class="wa-callout wa-brand wa-accent">
This <strong>accent</strong> callout draws attention without an outline
</article>
<br />
<article class="wa-callout wa-brand wa-outlined wa-filled">
This callout is both <strong>filled</strong> and <strong>outlined</strong>
</article>
<br />
<article class="wa-callout wa-brand wa-filled">
This callout is only <strong>filled</strong>
</article>
<br />
<article class="wa-callout wa-brand wa-outlined">
Here's an <strong>outlined</strong> callout
</article>
<br />
<article class="wa-callout wa-brand wa-plain">
No bells and whistles on this <strong>plain</strong> callout
</article>
```
### Sizes
Use the [size utility classes](../utilities/size.md) to change a callout's size.
```html {.example}
<article class="wa-callout wa-brand wa-outlined wa-accent wa-size-l">
This is meant to be very emphasized.
</article>
<br />
<article class="wa-callout">
Normal-sized callout.
</article>
<br />
<article class="wa-callout wa-plain wa-plain wa-size-s">
Just a small tip!
</article>
```

View File

@@ -1,90 +0,0 @@
---
title: Checkbox
description: Checkboxes allow the user to toggle an option on or off.
tags: forms
component: checkbox
icon: checkbox
elements:
"<input type=checkbox>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox
file: styles/native/checkbox.css
---
```html {.example}
<label><input type="checkbox"> Checkbox</label>
```
## Examples
### Checked
Use the `checked` attribute to activate the checkbox.
```html {.example}
<label><input type="checkbox" checked> Checked</label>
```
<!--
### Indeterminate
Use the `indeterminate` JS property to make the checkbox indeterminate.
```html {.example}
<label><input type="checkbox" class="indeterminate"> Indeterminate</label>
<script>
document.querySelector(".indeterminate").indeterminate = true;
</script>
```
-->
### Disabled
Use the `disabled` attribute to disable the checkbox.
```html {.example}
<label><input type="checkbox" disabled> Disabled</label>
```
<!--
### Sizes
Use the [size utilities](/docs/utilities/size) to change a checkbox's size.
```html {.example}
<label><input type="checkbox" class="wa-size-s"> Small</label>
<br />
<label><input type="checkbox" class="wa-size-m"> Medium</label>
<br />
<label><input type="checkbox" class="wa-size-l"> Large</label>
```
-->
### Custom Validity
Use the `setCustomValidity()` method to set a custom validation message. This will prevent the form from submitting and make the browser display the error message you provide. To clear the error, call this function with an empty string.
```html {.example}
<form class="custom-validity">
<label><input type="checkbox"> Check me</label>
<br />
<button type="submit" variant="brand" style="margin-top: 1rem;">Submit</button>
</form>
<script>
const form = document.querySelector('.custom-validity');
const checkbox = form.querySelector('input[type=checkbox]');
const errorMessage = `Don't forget to check me!`;
// Set initial validity
checkbox.setCustomValidity(errorMessage);
// Update validity on change
checkbox.addEventListener('change', () => {
checkbox.setCustomValidity(checkbox.checked ? '' : errorMessage);
});
// Handle submit
form.addEventListener('submit', event => {
event.preventDefault();
alert('All fields are valid!');
});
</script>
```

View File

@@ -1,92 +0,0 @@
---
title: Content
description: 'Content styles apply your Web Awesome theme to HTML text content, code, and images.'
tags: content
layout: element
icon: skeleton
elements:
"<h1>-<h6>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements
"<blockquote>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote
"<strong>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong
"<em>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em
"<u>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u
"<del>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del
"<ins>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins
"<s>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s
"<small>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small
"<sub>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub
"<sup>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup
"<abbr>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr
"<kbd>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd
"<mark>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark
"<a>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
"<code>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code
"<img>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
file: styles/native/content.css
---
## Typography
Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Amet mauris commodo quis imperdiet. Bibendum ut tristique et egestas quis ipsum suspendisse. Sit amet nulla facilisi morbi tempus iaculis urna id volutpat.
Cras pulvinar mattis nunc sed blandit libero. Facilisis magna etiam tempor orci. Scelerisque eleifend donec pretium vulputate sapien nec. Donec et odio pellentesque diam volutpat commodo sed egestas egestas. Mauris rhoncus aenean vel elit scelerisque mauris pellentesque.
> What is a Web year now, about three months? And when people can browse around, discover new things, and download them fast, when we all have agents - then Web years could slip by before human beings can notice.
>
> — Tim Berners-Lee
## Inline Text
```html
Feugiat nisl pretium fusce id. Ipsum dolor sit amet consectetur adipiscing elit. Eget nunc lobortis mattis aliquam faucibus purus. Metus dictum at tempor commodo ullamcorper a lacus vestibulum. Urna condimentum mattis pellentesque id nibh tortor id.
```
<div class="two-columns">
<p><strong>Bold</strong></p>
<p><em>Italics</em></p>
<p><u>Underline</u></p>
<p><del>Deleted</del></p>
<p><ins>Inserted</ins></p>
<p><s>Strike-through</s></p>
<p><small>Small</small></p>
<p><span>Text <sub>Sub</sub></span></p>
<p><span>Text <sup>Sup</sup></span></p>
<p><abbr title="Abbreviation">Abbr.</abbr></p>
<p><kbd>Keyboard</kbd></p>
<p><mark>Highlighted</mark></p>
<p><a href="#">Link text</a></p>
<p><code>Inline code</code></p>
</div>
## Headings
### Heading 3
Feugiat nisl pretium fusce id. Ipsum dolor sit amet consectetur adipiscing elit. Eget nunc lobortis mattis aliquam faucibus purus. Metus dictum at tempor commodo ullamcorper a lacus vestibulum. Urna condimentum mattis pellentesque id nibh tortor id.
#### Heading 4
Gravida arcu ac tortor dignissim convallis aenean. Pellentesque pulvinar pellentesque habitant morbi tristique senectus et. Ipsum nunc aliquet bibendum enim facilisis gravida neque. Donec adipiscing tristique risus nec feugiat in.
##### Heading 5
Enim diam vulputate ut pharetra sit. Enim facilisis gravida neque convallis a cras. Enim neque volutpat ac tincidunt vitae semper. Sed egestas egestas fringilla phasellus faucibus scelerisque eleifend donec pretium.
###### Heading 6
Tincidunt ornare massa eget egestas purus viverra accumsan in nisl. Facilisis mauris sit amet massa vitae. Nunc faucibus a pellentesque sit amet porttitor. Adipiscing tristique risus nec feugiat in fermentum.
## Code Blocks
```
// do a thing
export function thing() {
return true;
}
```
## Images
![A gray kitten lays next to a toy](https://images.unsplash.com/photo-1620196244888-d31ff5bbf163?q=80&w=1000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D)

View File

@@ -1,82 +0,0 @@
---
title: Details
description: 'Details styles apply your Web Awesome theme to the HTML `<details>` element. Details show a brief summary and expand to show additional content.'
tags: apps
layout: element
component: details
icon: details
elements:
"<details>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details
file: styles/native/details.css
---
```html {.example}
<details>
<summary>Tincidunt nunc pulvinar</summary>
<p>Ut lectus arcu bibendum at varius. Convallis a cras semper auctor neque vitae. Odio pellentesque diam volutpat commodo sed egestas. Amet dictum sit amet justo donec enim diam vulputate ut.</p>
</details>
```
## Examples
### Appearance
Use the [appearance utility classes](/docs/utilities/appearance) to change the element's visual appearance:
```html {.example}
<div class="wa-stack">
<details>
<summary>Outlined (default)</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.
</details>
<details class="wa-filled">
<summary>Filled</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.
</details>
<details class="wa-filled wa-outlined">
<summary>Filled + Outlined</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.
</details>
<details class="wa-plain">
<summary>Plain</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.
</details>
</div>
```
### Right-to-Left Languages
The details styling automatically adapts to right-to-left languages:
```html {.example}
<details lang="ar" dir="rtl">
<summary>تبديلني</summary>
استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن
</details>
```
## Accordions
In [modern browsers](https://caniuse.com/mdn-html_elements_details_name),
grouping `<details>` elements via the `name` attribute provides accordion-style functionality:
```html {.example}
<details name="details-accordion">
<summary>Enim diam</summary>
<p>Nunc faucibus a pellentesque sit amet porttitor. Adipiscing tristique risus nec feugiat in fermentum. Leo duis ut diam quam nulla porttitor massa id. Mauris nunc congue nisi vitae.</p>
</details>
<details name="details-accordion">
<summary>Arcu non odio</summary>
<p>Sed libero enim sed faucibus turpis in eu mi bibendum. Nunc mi ipsum faucibus vitae aliquet nec. Ultricies tristique nulla aliquet enim tortor. Tellus at urna condimentum mattis pellentesque.</p>
</details>
<details name="details-accordion">
<summary>Ut porttitor</summary>
<p>Eu facilisis sed odio morbi quis commodo odio aenean sed. Sit amet purus gravida quis blandit turpis cursus. Eu consequat ac felis donec et odio pellentesque diam volutpat.</p>
</details>
```

View File

@@ -1,37 +0,0 @@
---
title: Dialog
description: 'Dialog styles apply your Web Awesome theme to the HTML `<dialog>` element. Dialogs, also called "modals", appear above the page and interrupt a user''s focus.'
tags: apps
icon: dialog
elements:
"<dialog>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog
component: dialog
file: styles/native/dialog.css
---
```html {.example}
<dialog id="dialog-overview">
<header>
<h2>Dialog</h2>
<button data-dialog="close" class="wa-plain">✖️</button>
</header>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<footer>
<button class="wa-brand" data-dialog="close">Close</button>
</footer>
</dialog>
<button>Open Dialog</button>
<script>
const dialog = document.querySelector('#dialog-overview');
const openButton = dialog.nextElementSibling;
openButton.addEventListener('click', () => dialog.showModal());
dialog.addEventListener('click', event => {
if (event.target.closest('[data-dialog="close"]')) {
dialog.close();
}
});
</script>
```

View File

@@ -1,86 +0,0 @@
---
title: Native Styles
description: Native styles apply your theme to native HTML elements so they match the look and feel of Web Awesome components.
See the [installation instructions](#installation) to use native styles in your project.
layout: overview
categories: ['forms', 'apps', 'content']
override:tags: []
---
{% markdown %}
Web Awesome works _with_ the platform, rather than trying to reinvent it.
If all you need is styles, you dont need to use new `<wa-*>` elements!
We also provide styles that make native HTML elements look good so you can continue using what you know and gradually adopt Web Awesome as you see fit.
## Installation
To use all Web Awesome page styles (including [utilities](/docs/utilities/)), include the following stylesheet in your project:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />
```
Or, to _only_ include styles for native elements:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/native.css' %}" />
```
## Opting Out of Native Styles
So you've decided to use Native Styles and now you need to style an element or a part of a page completely differently, what to do?
You can create an opt-out with the power of [CSS Cascade Layers](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers)!
Instead of including Native Styles with a `<link>` element, you can include it like this:
```html
<style>
@import url('{% cdnUrl 'styles/webawesome.css' %}') layer(wa);
@layer wa {
.wa-off,
.wa-off-deep,
.wa-off-deep * {
all: revert-layer;
}
}
</style>
```
Then you can opt-out of Native Styles styling by using a `wa-off` class on individual elements or `wa-off-deep` for entire subtrees:
```html
<p>
<button>Im Awesome</button>
<button class="wa-off">Im not</button>
</p>
<blockquote>
<p>Lorem Ipsum dolor sit amet</p>
<button>Im also awesome</button>
</blockquote>
<blockquote class="wa-off">
<p>Lorem Ipsum dolor sit amet</p>
<button >Im also not</button>
</blockquote>
<blockquote class="wa-off-deep">
<p>Lorem Ipsum dolor sit amet</p>
<button>Im also not</button>
</blockquote>
```
You could even design opt-outs for specific elements!
E.g. to opt-out of `<details>` styling:
```css
@layer wa {
details.wa-details-off,
.wa-details-off details,{
all: revert-layer;
}
}
```
If you find yourself opting out of entire element types too much, you could consider only including the parts of Native Styles you need instead of the whole thing.
You can find instructions for how to do that on the individual Native Styles pages.
{% endmarkdown %}

View File

@@ -1,85 +0,0 @@
---
title: Input
description: Inputs collect data from the user.
tags: forms
icon: input
component: input
elements:
"<input>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
file: styles/native/input.css
---
## Text Fields
```html {.example}
<label>Input (text) <input type="text" placeholder="placeholder"></label>
<wa-input label="WA Input (text)" type="text" placeholder="placeholder"></wa-input>
<label>Input (number) <input type="number"></label>
<wa-input label="WA Input (number)" type="number"></wa-input>
<label>Input (password) <input type="password" required></label>
<wa-input label="WA Input (password)" type="password" required></wa-input>
<label>Input (email) <input type="email"></label>
<wa-input label="WA Input (email)" type="email"></wa-input>
<label>Input (search) <input type="search"></label>
<wa-input label="WA Input (search)" type="search"></wa-input>
<label>Input (tel) <input type="tel"></label>
<wa-input label="WA Input (tel)" type="tel"></wa-input>
<label>Input (url) <input type="url"></label>
<wa-input label="WA Input (url)" type="url"></wa-input>
```
## Pill shaped text fields
Add the `wa-pill` class to an `<input>` to make it pill-shaped.
```html {.example}
<label>Input <input type="text" placeholder="placeholder" class="wa-pill"></label>
```
## Color Picker
Basic:
```html {.example}
<label>Input (color) <input type="color" value="#ff0066"></label>
<wa-color-picker label="WA Color Picker" value="#ff0066"></wa-color-picker>
```
With swatches:
```html {.example}
<label>Input (color) <input type="color" value="#ff0066" list="swatches"></label>
<datalist id="swatches">
<option value="#0070ef">Web Awesome Blue</option>
<option>#f5a623</option>
<option>#f8e71c</option>
<option>#8b572a</option>
<option>#7ed321</option>
<option>#417505</option>
<option>#bd10e0</option>
<option>#9013fe</option>
</datalist>
<wa-color-picker label="WA Color Picker" value="#ff0066"
swatches="#0070ef; #f5a623; #f8e71c; #8b572a; #7ed321; #417505; #bd10e0; #9013fe;"></wa-color-picker>
```
## Time and Date Pickers
```html {.example}
<label>Input (datetime-local) <input type="datetime-local"></label>
<wa-input label="WA Input (datetime-local)" type="datetime-local"></wa-input>
<label>Input (date) <input type="date"></label>
<wa-input label="WA Input (date)" type="date"></wa-input>
<label>Input (time) <input type="time"></label>
<wa-input label="WA Input (time)" type="time"></wa-input>
```

View File

@@ -1,38 +0,0 @@
---
title: Lists
description: 'List styles apply your Web Awesome theme to HTML lists, such as bulleted, numbered, or description lists.'
tags: content
layout: element
elements:
"<ul>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul
"<ol>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol
"<dl>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl
file: styles/native/lists.css
---
## Unordered Lists
- List item 1
- List item 2
- List item 3
- Subitem a
- Subitem b
## Ordered Lists
1. List item 1
2. List item 2
3. List item 3
- Subitem a
- Subitem b
## Definition Lists
<dl>
<dt>Definition 1</dt>
<dd>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.</dd>
<dt>Definition 2</dt>
<dd>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</dd>
<dt>Definition 3</dt>
<dd>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</dd>
</dl>

View File

@@ -1,4 +0,0 @@
{
"layout": "element.njk",
"tags": ["native"]
}

View File

@@ -1,31 +0,0 @@
---
title: Progress Bar
description: Progress bars are used to show the status of an ongoing operation.
tags: apps
icon: progress-bar
status: experimental
component: progress-bar
elements:
"<progress>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress
file: styles/native/progress.css
---
```html {.example}
<progress value="40" max="100"></progress>
```
Indeterminate:
```html {.example}
<progress></progress>
```
### Custom Height
Use the `height` CSS property to set the progress bar's height.
```html {.example}
<progress value="50" style="height: 6px;"></progress>
```

View File

@@ -1,93 +0,0 @@
---
title: Radio
description: Radios allow the user to select a single option from a group.
tags: forms
icon: radio-group
component: radio
elements:
"<input type=radio>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio
file: styles/native/radio.css
---
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="a" value="1" checked> Option 1</label>
<label><input type="radio" name="a" value="2"> Option 2</label>
</div>
```
## Examples
### Initial Value
To set the initial value and checked state, use the `checked` attribute on the corresponding radio.
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="b" value="1" checked> Option 1</label>
<label><input type="radio" name="b" value="2"> Option 2</label>
<label><input type="radio" name="b" value="3"> Option 3</label>
</div>
```
### Disabled
Use the `disabled` attribute to disable a radio.
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="c" value="1" checked> Option 1</label>
<label><input type="radio" name="c" value="2" disabled> Option 2</label>
<label><input type="radio" name="c" value="3"> Option 3</label>
</div>
```
### Sizes
Use the [size utilities](/docs/utilities/size) to change the radios' size.
```html {.example}
<fieldset class="wa-size-s wa-cluster">
<legend>Small</legend>
<label><input type="radio" name="d" value="1" checked> Option 1</label>
<label><input type="radio" name="d" value="2"> Option 2</label>
<label><input type="radio" name="d" value="3"> Option 3</label>
</fieldset>
<br />
<fieldset class="wa-size-m wa-cluster">
<legend>Medium</legend>
<label><input type="radio" name="e" value="1" checked> Option 1</label>
<label><input type="radio" name="e" value="2"> Option 2</label>
<label><input type="radio" name="e" value="3"> Option 3</label>
</fieldset>
<br />
<fieldset class="wa-size-l wa-cluster">
<legend>Large</legend>
<label><input type="radio" name="f" value="1" checked> Option 1</label>
<label><input type="radio" name="f" value="2"> Option 2</label>
<label><input type="radio" name="f" value="3"> Option 3</label>
</fieldset>
```
### Orientation
You can wrap native radios in a flex container to give them a horizontal or vertical orientation with even spacing. The convenience [`wa-cluster`](/docs/utilities/cluster) and [`wa-stack`](/docs/utilities/stack) utilities make this easy.
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="g" value="1" checked> Option 1</label>
<label><input type="radio" name="g" value="2"> Option 2</label>
<label><input type="radio" name="g" value="3"> Option 3</label>
</div>
```
```html {.example}
<div class="wa-stack">
<label><input type="radio" name="h" value="1" checked> Option 1</label>
<label><input type="radio" name="h" value="2"> Option 2</label>
<label><input type="radio" name="h" value="3"> Option 3</label>
</div>
```

View File

@@ -1,72 +0,0 @@
---
title: Select
description: Selects allow you to choose items from a menu of predefined options.
tags: forms
icon: select
component: select
elements:
"<select>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
file: styles/native/select.css
---
```html {.example}
<label>Select
<select id="select">
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
<option value="option-3">Option 3</option>
</select>
</label>
```
## Examples
### Appearance
Use the [appearance utilities](/docs/utilities/appearance/) to change the select's visual appearance.
```html {.example}
<label>Select
<select id="select" class="wa-filled">
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
<option value="option-3">Option 3</option>
</select>
</label>
```
### Grouping options
In [modern browsers](https://caniuse.com/mdn-html_elements_select_hr_in_select), you can use the `<hr>` element as a divider:
```html {.example}
<select>
<small>Section 1</small>
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
<option value="option-3">Option 3</option>
<hr />
<small>Section 2</small>
<option value="option-4">Option 4</option>
<option value="option-5">Option 5</option>
<option value="option-6">Option 6</option>
</select>
```
To provide labels, you can use the `<optgroup>` element (with or without dividers):
```html {.example}
<select>
<optgroup label="Section 1">
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
<option value="option-3">Option 3</option>
</optgroup>
<optgroup label="Section 2">
<option value="option-4">Option 4</option>
<option value="option-5">Option 5</option>
<hr />
<option value="option-6">Option 6</option>
</optgroup>
</select>
```

View File

@@ -1,54 +0,0 @@
---
title: Slider
description: Sliders allow the user to select a single value within a given range using a slider.
tags: forms
layout: element
icon: slider
component: slider
elements:
"<input type=range>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range
file: styles/native/slider.css
---
```html {.example}
<label>Select a value: <input type="range"></label>
```
### Min, Max, and Step
Use the `min` and `max` attributes to set the range's minimum and maximum values, respectively. The `step` attribute determines the value's interval when increasing and decreasing.
```html {.example}
<input type="range" min="0" max="10" step="1">
```
### Disabled
Use the `disabled` attribute to disable a slider.
```html {.example}
<input type="range" disabled>
```
<!--
### Custom Track Colors
You can customize the active and inactive portions of the track using the `--track-color-active` and `--track-color-inactive` custom properties.
```html {.example}
<input type="range"
style="
--track-color-active: var(--wa-color-brand-fill-loud);
--track-color-inactive: var(--wa-color-brand-fill-normal);
"
>
```
### Right-to-Left languages
The styles adapt to right-to-left (RTL) languages as you would expect.
```html {.example}
<input type="range" dir=rtl>
```
-->

View File

@@ -1,136 +0,0 @@
---
title: Table
description: 'Table styles apply your Web Awesome theme to the HTML table content. Tables structure data in rows and columns, making it easy to look up information in a complex data set.'
tags: content
elements:
"<table>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
file: styles/native/tables.css
---
```html {.example}
<table>
<caption>I'm just a table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
```
## Alternating Rows
You can use the `wa-zebra-rows` class to add alternating row colors to your table:
```html {.example}
<table class="wa-zebra-rows">
<caption>I'm just a table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
```
## Variants
You can use [color utility classes](/docs/utilities/colors) to apply different colors to your table:
```html {.example}
<table class="wa-zebra-rows wa-brand">
<caption>I'm just a table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
```

View File

@@ -1,38 +0,0 @@
---
title: Textarea
description: Textareas collect data from the user and allow multiple lines of text.
tags: forms
icon: textarea
component: textarea
elements:
"<textarea>": https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea
file: styles/native/input.css
---
```html {.example}
<label>Textarea <textarea></textarea></label>
```
### Placeholders
Use the `placeholder` attribute to add a placeholder.
```html {.example}
<textarea placeholder="Type something"></textarea>
```
### Appearance
Use the [appearence utilities](/docs/utilities/appearance/) to change the textarea's visual appearance.
```html {.example}
<textarea placeholder="Type something" class="wa-filled"></textarea>
```
### Expand with Content
You can use `field-sizing: content` in [browsers that support it](https://caniuse.com/mdn-css_properties_field-sizing) to make the textarea grow as the user types:
```html {.example}
<textarea placeholder="Type something" style="field-sizing: content"></textarea>
```

View File

@@ -23,7 +23,8 @@ wa-dropdown > .color.swatch {
--track-color-inactive: transparent;
--track-color-active: transparent;
--thumb-color: var(--color-tweaked, var(--color));
--thumb-shadow: 0 0 0 var(--thumb-gap) var(--wa-color-surface-default),
--thumb-shadow:
0 0 0 var(--thumb-gap) var(--wa-color-surface-default),
var(--wa-shadow-offset-x-m) var(--wa-shadow-offset-y-m) var(--wa-shadow-blur-m)
calc(var(--wa-shadow-offset-x-m) * -1 + var(--thumb-gap)) var(--wa-color-shadow);

View File

@@ -115,11 +115,11 @@ isPro: true
<h2 class="wa-heading-m">Manage Link</h2>
<wa-input label="Expiration Date" type="date"></wa-input>
<wa-radio-group label="Share Limit" orientation="horizontal" name="share-limit" value="0">
<wa-radio-button value="0">None</wa-radio-button>
<wa-radio-button value="5">5</wa-radio-button>
<wa-radio-button value="10">10</wa-radio-button>
<wa-radio-button value="50">50</wa-radio-button>
<wa-radio-button value="100">100</wa-radio-button>
<wa-radio appearance="button" value="0">None</wa-radio>
<wa-radio appearance="button" value="5">5</wa-radio>
<wa-radio appearance="button" value="10">10</wa-radio>
<wa-radio appearance="button" value="50">50</wa-radio>
<wa-radio appearance="button" value="100">100</wa-radio>
</wa-radio-group>
<wa-divider></wa-divider>
<wa-switch hint="Members are removed after logging out." checked>Temporary Access</wa-switch>

View File

@@ -153,29 +153,29 @@ isPro: true
</div>
<div class="wa-stack">
<wa-radio-group label="Color" name="color" value="black" orientation="horizontal">
<wa-radio-button id="radio-black" value="black">
<wa-radio appearance="button" id="radio-black" value="black">
<wa-icon name="square" label="Black" style="color: black;"></wa-icon>
<wa-tooltip for="radio-black">Black</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-gray" value="gray">
</wa-radio>
<wa-radio appearance="button" id="radio-gray" value="gray">
<wa-icon name="square" label="Gray" style="color: gray;"></wa-icon>
<wa-tooltip for="radio-gray">Gray</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-indigo" value="indigo">
</wa-radio>
<wa-radio appearance="button" id="radio-indigo" value="indigo">
<wa-icon name="square" label="Indigo" style="color: indigo;"></wa-icon>
<wa-tooltip for="radio-indigo">Indigo</wa-tooltip>
</wa-radio-button>
<wa-radio-button id="radio-olive" value="olive">
</wa-radio>
<wa-radio appearance="button" id="radio-olive" value="olive">
<wa-icon name="square" label="Olive" style="color: olive;"></wa-icon>
<wa-tooltip for="radio-olive">Olive</wa-tooltip>
</wa-radio-button>
</wa-radio>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
<wa-radio appearance="button" value="xs">XS</wa-radio>
<wa-radio appearance="button" value="s">S</wa-radio>
<wa-radio appearance="button" value="m">M</wa-radio>
<wa-radio appearance="button" value="l">L</wa-radio>
<wa-radio appearance="button" value="xl">XL</wa-radio>
</wa-radio-group>
<wa-button variant="brand">
<wa-icon slot="prefix" name="cart-plus" variant="solid"></wa-icon>
@@ -228,21 +228,21 @@ isPro: true
<a href="#">144 Reviews</a>
</div>
<wa-radio-group label="Color" name="color" value="black" orientation="horizontal">
<wa-radio-button value="black">
<wa-radio appearance="button" value="black">
<wa-icon slot="prefix" name="shirt" style="color: black;"></wa-icon>
Vintage Black
</wa-radio-button>
<wa-radio-button value="gray">
</wa-radio>
<wa-radio appearance="button" value="gray">
<wa-icon slot="prefix" name="shirt" style="color: gray;"></wa-icon>
Faded Gray
</wa-radio-button>
</wa-radio>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
<wa-radio appearance="button" value="xs">XS</wa-radio>
<wa-radio appearance="button" value="s">S</wa-radio>
<wa-radio appearance="button" value="m">M</wa-radio>
<wa-radio appearance="button" value="l">L</wa-radio>
<wa-radio appearance="button" value="xl">XL</wa-radio>
</wa-radio-group>
<wa-button variant="brand">
<wa-icon slot="prefix" name="bag-shopping" variant="solid"></wa-icon>
@@ -329,25 +329,25 @@ isPro: true
comfort. The relaxed fit and classic crew neckline make it a versatile staple for layering or wearing solo.
</p>
<wa-radio-group label="Color" name="color" value="sand" orientation="horizontal">
<wa-radio-button value="sand">
<wa-radio appearance="button" value="sand">
<wa-icon slot="prefix" name="circle" style="color: burlywood;"></wa-icon>
Sand
</wa-radio-button>
<wa-radio-button value="shale">
</wa-radio>
<wa-radio appearance="button" value="shale">
<wa-icon slot="prefix" name="circle" style="color: silver;"></wa-icon>
Shale
</wa-radio-button>
<wa-radio-button value="slate">
</wa-radio>
<wa-radio appearance="button" value="slate">
<wa-icon slot="prefix" name="circle" style="color: dimgray;"></wa-icon>
Slate
</wa-radio-button>
</wa-radio>
</wa-radio-group>
<wa-radio-group label="Size" name="size" value="s" orientation="horizontal">
<wa-radio-button value="xs">XS</wa-radio-button>
<wa-radio-button value="s">S</wa-radio-button>
<wa-radio-button value="m">M</wa-radio-button>
<wa-radio-button value="l">L</wa-radio-button>
<wa-radio-button value="xl">XL</wa-radio-button>
<wa-radio appearance="button" value="xs">XS</wa-radio>
<wa-radio appearance="button" value="s">S</wa-radio>
<wa-radio appearance="button" value="m">M</wa-radio>
<wa-radio appearance="button" value="l">L</wa-radio>
<wa-radio appearance="button" value="xl">XL</wa-radio>
</wa-radio-group>
<wa-button variant="brand">Add to Cart</wa-button>
</div>

View File

@@ -22,7 +22,7 @@ Patterns are written as standard HTML, so you can use them just as you would any
To use a pattern in your project, refer to each pattern's docs for a copyable code snippet. Paste the snippet wherever you'd like the pattern to appear in your project.
Because patterns use a combination of Web Awesome features, they work best when you have [native styles](/docs/native), [style utilities](/docs/utilities), and a [theme](/docs/themes) installed in addition to Web Awesome [components](/docs/components). Refer to the [Installation page](/docs/) to set up all of these features in your project.
Because patterns use a combination of Web Awesome features, they work best when you have [native styles](/docs/utilities/native), [style utilities](/docs/utilities), and a [theme](/docs/themes) installed in addition to Web Awesome [components](/docs/components). Refer to the [Installation page](/docs/) to set up all of these features in your project.
{% endmarkdown %}
</div>

View File

@@ -14,6 +14,10 @@ During the alpha period, things might break! We take breaking changes very serio
## Next
- 🚨 BREAKING: Greatly simplified how native styles work and removed redundant utilities
- Removed `.wa-button`, `.wa-callout` classes
- Removed `themes/native/*.css` files; use `native.css` to opt into native styles
- Clarified which utilities classes can be applied to which native elements
- 🚨 BREAKING: Removed the extra dash in the `<wa-carousel>` CSS part name `pagination-item--active` => `pagination-item-active`
- 🚨 BREAKING: Renamed the `classic` theme to `shoelace`
- 🚨 BREAKING: Renamed `pulse` attribute in `<wa-badge>` to `attention="pulse"` and added `attention="bounce"` [issue:#940]
@@ -26,9 +30,14 @@ During the alpha period, things might break! We take breaking changes very serio
- `<wa-select clearable>` => `<wa-select with-clear>`
- `<wa-tab-group no-scroll-controls>` => `<wa-tab-group without-scroll-controls>`
- `<wa-tag removable>` => `<wa-tag with-remove>`
- 🚨 BREAKING: removed the `size` attribute from `<wa-card>`; please set the size of child elements on the children directly
- Added a `min-block-size` to `<wa-divider orientation="vertical">` to ensure the divider is visible regardless of container height [issue:675]
- Fixed a bug in `<wa-radio-group>` that caused radios to uncheck when assigning a numeric value [issue:924]
- Fixed `<wa-button-group>` so dividers properly show between buttons
- Fixed the tooltip position in `<wa-slider>` when using RTL
- Fixed a bug in `<wa-details>` and native `<details>` styles that made the summary hard to click [issue:684]
- Improved CSS utilities and Native Styles to use [CSS layers](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) for easier end user customization (no more specificity conflicts  your CSS wins!)
- Improved native `<button>` styles to properly space icons
- Removed the experimental `<wa-code-demo>` component
## 3.0.0-alpha.13
@@ -53,7 +62,7 @@ During the alpha period, things might break! We take breaking changes very serio
### Enhancements
- Added `appearance` to [`<wa-details>`](/docs/components/details) and [`<wa-card>`](/docs/components/card) and support for the [appearance utilities](/docs/utilities/appearance/) in the [`<details>` native styles](/docs/native/details).
- Added `appearance` to [`<wa-details>`](/docs/components/details) and [`<wa-card>`](/docs/components/card) and support for the [appearance utilities](/docs/utilities/appearance/) in the [`<details>` native styles](/docs/utilities/native/details).
- Added an `orange` scale to all color palettes
- Added the [`.wa-cloak` utility](/docs/utilities/fouce) to prevent FOUCE
- Added the [`allDefined()` utility](/docs/usage/#all-defined) for awaiting component registration
@@ -78,7 +87,7 @@ During the alpha period, things might break! We take breaking changes very serio
- Revert `<wa-dialog>` structure and CSS to fix clipped content in dialogs (WA-A #123) and light dismiss in iOS Safari (WA-A #201)
- Fixed a bug in `<wa-color-picker>` that prevented light dismiss from working when clicking immediately above the color picker dropdown
- Fixed a bug in `<wa-progress>` that prevented Safari from animation progress changes
- Fixed the missing indeterminate icon in [native checkbox styles](/docs/native/checkbox)
- Fixed the missing indeterminate icon in [native checkbox styles](/docs/utilities/native/checkbox)
- Fixed a bug in `<wa-radio>` where elements would stack instead of display inline
- Docs fixes:
- Fixed the search dialog's styles so it doesn't jump around as you search
@@ -224,13 +233,13 @@ You can find them in the first column of each color palette.
### Native styles
- Added native styles for
[buttons](/docs/native/button),
[input fields](/docs/native/input),
[dialogs](/docs/native/dialog),
[details](/docs/native/details),
[tables](/docs/native/table),
[lists](/docs/native/lists),
and most [content elements](/docs/native/content).
[buttons](/docs/utilities/native/button),
[input fields](/docs/utilities/native/input),
[dialogs](/docs/utilities/native/dialog),
[details](/docs/utilities/native/details),
[tables](/docs/utilities/native/table),
[lists](/docs/utilities/native/lists),
and most [content elements](/docs/utilities/native/content).
### Style utilities

View File

@@ -355,13 +355,7 @@ TL;DR a component is a dependency if and only if it's rendered inside anothe
Many Web Awesome components use other Web Awesome components internally. For example, `<wa-button>` uses both `<wa-icon>` and `<wa-spinner>` for its caret icon and loading state, respectively. Since these components appear in the button's shadow root, they are considered dependencies of Button. Since dependencies are automatically loaded, users only need to import the button and everything will work as expected.
Contrast this to `<wa-select>` and `<wa-option>`. At first, one might assume that Option is a dependency of Select. After all, you can't really use Select without slotting in at least one Option. However, Option _is not_ a dependency of Select! The reason is because no Option is rendered in the Select's shadow root. Since the options are provided by the user, it's up to them to import both components independently.
People often suggest that Web Awesome should auto-load Select + Option, Menu + Menu Item, Breadcrumb + Breadcrumb Item, etc. Although some components are designed to work together, they're technically not dependencies so eagerly loading them may not be desirable. What if someone wants to roll their own component with a superset of features? They wouldn't be able to if Web Awesome automatically imported it!
Similarly, in the case of `<wa-radio-group>` there was originally only `<wa-radio>`, but now you can use either `<wa-radio>` or `<wa-radio-button>` as child elements. Which component(s) should be auto-loaded dependencies in this case? Had Radio been a dependency of Radio Group, users that only wanted Radio Buttons would be forced to register both with no way to opt out and no way to provide their own customized version.
For non-dependencies, _the user_ should decide what gets registered, even if it comes with a minor inconvenience.
The rule of thumb for dependencies is: if a component is rendered _inside_ a host element's shadow root OR if the component is required to be slotted in by the user (e.g. `<wa-radio-group>` + `<wa-radio>`), it's a dependency.
### Form Controls

View File

@@ -27,40 +27,18 @@ wide: true
--width: var(--wa-border-width-m);
--spacing: var(--wa-space-3xl);
}
.test-failure::before {
content: '\f071';
color: red;
font-family: 'Font Awesome 6 Duotone', 'Font Awesome 6 Free';
font-size: 1em;
font-weight: 900;
margin-inline-end: 0.5rem;
vertical-align: middle;
}
</style>
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 <wa-icon name="triangle-exclamation" family="duotone" style="color: red;" label="alert icon"></wa-icon> and will be addressed in a future release.
<wa-tab-group>
<wa-tab panel="appearance">Appearance</wa-tab>
<wa-tab panel="alignment">Alignment</wa-tab>
<wa-tab panel="native">Native</wa-tab>
<wa-tab panel="color">Color</wa-tab>
<wa-tab panel="harmony">Harmony</wa-tab>
<wa-tab panel="native">Native Styles</wa-tab>
<wa-tab panel="size">Size</wa-tab>
<wa-tab-panel name="appearance">
## 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' %}
</wa-tab-panel>
<wa-tab panel="alignment">Alignment</wa-tab>
<wa-tab panel="harmony">Harmony</wa-tab>
<wa-tab-panel name="alignment">
@@ -94,9 +72,9 @@ Harmony tests show how related components look together. These can help validate
<wa-tab-panel name="native">
## Native Styles
## Native
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.
Native style tests ensure that supported native elements and utilities look the same as their Web Awesome component counterparts. Native elements may also support the same appearance, color, and size utilities as components.
{% include 'visual-tests/native.njk' %}

View File

@@ -1,71 +0,0 @@
---
title: CSS Properties Benchmark
unlisted: true
wide: true
---
{% set icons = {
check: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>',
'chevron-down': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg>',
'chevron-left': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg>',
'chevron-right': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/></svg>',
circle: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg>',
'eye-dropper': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6v42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480h42.4c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7H96V379.9c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"/></svg>',
'grip-vertical': '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M40 352l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zm192 0l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 320c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 192l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 160c-22.1 0-40-17.9-40-40L0 72C0 49.9 17.9 32 40 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40z"/></svg>',
indeterminate: '<svg part="indeterminate-icon" class="icon" viewBox="0 0 16 16"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round"><g stroke="currentColor" stroke-width="2"><g transform="translate(2.285714, 6.857143)"><path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path></g></g></g></svg>',
minus: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>',
pause: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M48 64C21.5 64 0 85.5 0 112V400c0 26.5 21.5 48 48 48H80c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H48zm192 0c-26.5 0-48 21.5-48 48V400c0 26.5 21.5 48 48 48h32c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H240z"/></svg>',
play: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>',
star: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"/></svg>',
user: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>',
xmark: '<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>'
} %}
<style>
.icon-tests {
font-size: .5rem;
line-height: 1;
}
wa-icon {
transition: 1s font-size;
&:hover {
font-size: 1rem;
}
}
</style>
{% set repetitions = 200 %}
<h2>Setting everything via attributes</h2>
<div class="icon-tests">
{% for icon, svg in icons %}
{% for i in range(repetitions) %}
<wa-icon name="{{ icon }}" variant="solid" family="classic"></wa-icon>
{% endfor %}
{% endfor %}
</div>
<h2>Setting variant & family via CSS</h2>
<div class="icon-tests" style="--wa-icon-variant: regular; --wa-icon-family: classic">
{% for icon, svg in icons %}
{% for i in range(repetitions) %}
<wa-icon name="{{ icon }}"></wa-icon>
{% endfor %}
{% endfor %}
</div>
<h2>Setting name via CSS</h2>
<div class="icon-tests">
{% for icon, svg in icons %}
<span style="--wa-icon-name: {{ icon }}">
{% for i in range(repetitions) %}
<wa-icon variant="solid" family="classic"></wa-icon>
{% endfor %}
</span>
{% endfor %}
</div>

View File

@@ -74,7 +74,7 @@ If you want it to start from the position the button was clicked, you can use th
document.addEventListener("mousedown", evt => {
let target = evt.target;
if (!target.matches?.('wa-button, button, .wa-button')) {
if (!target.matches?.('wa-button, button')) {
return;
}

View File

@@ -1,99 +0,0 @@
---
title: Appearance Variants
description: Appearance utilities apply a collection of properties to achieve certain effects, like making elements accented, outlined, filled, or plain.
snippets:
- .wa-accent
- .wa-outlined
- .wa-filled
- .wa-plain
file: styles/utilities/appearance.css
---
Some Web Awesome components, like `<wa-button>`, allow you to change their overall style by using an `appearance` attribute:
{% for component in componentsBy.attribute.appearance %}
- <a href="../{{ component.url }}"><code>&lt;{{ component.tagName }}&gt;</code></a>
{%- endfor %}
You can create the same effect on any element by using the appearance utility classes:
- `.wa-accent`
- `.wa-outlined`
- `.wa-filled`
- `.wa-plain`
Using these classes is a two-way handshake:
they do not directly apply styles, but define custom properties that you can use in styles that should respond to these utilities:
- `--background-color`
- `--background-color-hover`
- `--background-color-active`
- `--border-color`
- `--border-color-hover`
- `--text-color`
- `--text-color-hover`
Then you can use (some of) these properties in any class that should respond to these.
For example, assume we wanted to make a custom `.badge` class with appearance variants.
This is all we need to do:
```html { .example }
<small class="badge wa-accent">Accent</small>
<small class="badge wa-outlined">Outlined</small>
<small class="badge wa-filled">Filled</small>
<small class="badge wa-plain">Plain</small>
<style>
.badge {
background-color: var(--background-color);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: var(--wa-space-2xs) var(--wa-space-xs);
border-radius: var(--wa-border-radius-s);
}
</style>
```
## With Color Variants
These properties also work well with the [color variants](/docs/utilities/color/) utility classes:
```html { .example }
<div class="wa-stack">
<div class="wa-brand">
<small class="badge wa-accent">Accent</small>
<small class="badge wa-outlined">Outlined</small>
<small class="badge wa-filled">Filled</small>
<small class="badge wa-plain">Plain</small>
</div>
<div class="wa-danger">
<small class="badge wa-accent">Accent</small>
<small class="badge wa-outlined">Outlined</small>
<small class="badge wa-filled">Filled</small>
<small class="badge wa-plain">Plain</small>
</div>
<div class="wa-warning">
<small class="badge wa-accent">Accent</small>
<small class="badge wa-outlined">Outlined</small>
<small class="badge wa-filled">Filled</small>
<small class="badge wa-plain">Plain</small>
</div>
<div class="wa-success">
<small class="badge wa-accent">Accent</small>
<small class="badge wa-outlined">Outlined</small>
<small class="badge wa-filled">Filled</small>
<small class="badge wa-plain">Plain</small>
</div>
</div>
<style>
.badge {
background-color: var(--background-color);
border: 1px solid var(--border-color);
color: var(--text-color);
padding: var(--wa-space-2xs) var(--wa-space-xs);
border-radius: var(--wa-border-radius-s);
}
</style>
```

View File

@@ -2,12 +2,6 @@
title: Color Variants
description: Color utilities allow you to apply the brand, neutral, success, warning, and danger colors from your theme to any element.
icon: tokens/color
snippets:
- .wa-brand
- .wa-neutral
- .wa-success
- .wa-warning
- .wa-danger
file: styles/utilities/variants.css
---
@@ -30,7 +24,7 @@ You can create the same effect on any element by using the color variant utility
Using these classes is a two-way handshake:
they do not directly apply styles, but define generic color tokens modeled after our [Semantic Colors](/docs/tokens/color/#semantic-colors) but *without* the group identifier (`neutral`, `brand`, `success`, `warning`, `danger`), defaulting to `neutral`.
This means that styles can be written to respond to variants by using e.g. `--wa-color-fill-loud` instead of e.g. `--wa-color-brand-fill-loud`,
and all of our [native styles](/docs/native/) do so (where it made sense).
and all of our [native styles](/docs/utilities/native/) do so (where it made sense).
For example, assume we wanted to make a custom `.callout` class with color variants.
This is all we need to do:

View File

@@ -1,5 +1,5 @@
---
title: Reduce FOUCE
title: Reducing FOUCE
description: Utility to improve the loading experience by hiding non-prerendered custom elements until they are registered.
file: styles/utilities/fouce.css
icon: spinner

View File

@@ -10,7 +10,7 @@ override:tags: []
{% markdown %}
## Installation
To use all Web Awesome page styles (including [native styles](/docs/native/)), include the following stylesheet in your project:
To use all Web Awesome page styles (including [native styles](/docs/utilities/native/)), include the following stylesheet in your project:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />

View File

@@ -0,0 +1,456 @@
---
title: Native Styles
description: Native styles apply your theme to native HTML elements so they match the look and feel of Web Awesome components.
layout: page-outline
---
# Web Awesome Native Styles
Web Awesome provides optional Native Styles that make native HTML elements look good so you can continue using what you know and gradually adopt Web Awesome as you see fit.
## Installation
To use all Web Awesome page styles (including [utilities](/docs/utilities/)), include the following stylesheet in your project:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/webawesome.css' %}" />
```
Or, to _only_ include styles for native elements:
```html
<link rel="stylesheet" href="{% cdnUrl 'styles/native.css' %}" />
```
## Elements
### Headings
Semantic heading elements with proper hierarchy and styling.
```html {.example}
<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<h5>Heading 5</h5>
<h6>Heading 6</h6>
```
### Paragraphs
Standard paragraph text with optimal spacing and readability.
```html {.example}
<p>Vel risus commodo viverra maecenas accumsan lacus vel facilisis volutpat. Amet mauris commodo quis imperdiet. Bibendum ut tristique et egestas quis ipsum suspendisse. Sit amet nulla facilisi morbi tempus iaculis urna id volutpat.</p>
<p>Cras pulvinar mattis nunc sed blandit libero. Facilisis magna etiam tempor orci. Scelerisque eleifend donec pretium vulputate sapien nec. Donec et odio pellentesque diam volutpat commodo sed egestas egestas. Mauris rhoncus aenean vel elit scelerisque mauris pellentesque.</p>
```
### Blockquotes
Styled quotations that stand out from regular text.
```html {.example}
<blockquote>
What is a Web year now, about three months? And when people can browse around, discover new things, and download them fast, when we all have agents - then Web years could slip by before human beings can notice.<br><br>
— Tim Berners-Lee
</blockquote>
```
### Lists
Organized content in bulleted or numbered format with proper nesting support.
```html {.example}
<ul>
<li>List item 1</li>
<li>List item 2
<ul>
<li>Subitem a</li>
<li>Subitem b</li>
</ul>
</li>
<li>List item 3</li>
</ul>
<ol>
<li>List item 1</li>
<li>List item 2
<ul>
<li>Subitem a</li>
<li>Subitem b</li>
</ul>
</li>
<li>List item 3</li>
</ol>
```
### Definition Lists
Term and definition pairs for glossaries and descriptions.
```html {.example}
<dl>
<dt>Definition 1</dt>
<dd>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.</dd>
<dt>Definition 2</dt>
<dd>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</dd>
<dt>Definition 3</dt>
<dd>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</dd>
</dl>
```
### Details
Collapsible content sections with expand/collapse functionality.
```html {.example}
<details>
<summary>Tincidunt nunc pulvinar</summary>
<p>Ut lectus arcu bibendum at varius. Convallis a cras semper auctor neque vitae. Odio pellentesque diam volutpat commodo sed egestas. Amet dictum sit amet justo donec enim diam vulputate ut.</p>
</details>
```
### Dialog
Modal dialog windows for alerts, confirmations, and overlays.
```html {.example}
<dialog id="dialog-example">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<button type="button">Close</button>
</dialog>
<button>Open Dialog</button>
<script>
const dialog = document.querySelector('#dialog-example');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('button');
openButton.addEventListener('click', () => dialog.showModal());
closeButton.addEventListener('click', () => dialog.close());
</script>
```
### Inline Text
Various text formatting elements for emphasis and semantic meaning.
```html {.example}
<div class="two-columns">
<p><strong>Bold</strong></p>
<p><em>Italics</em></p>
<p><u>Underline</u></p>
<p><del>Deleted</del></p>
<p><ins>Inserted</ins></p>
<p><s>Strike-through</s></p>
<p><small>Small</small></p>
<p><span>Text <sub>Sub</sub></span></p>
<p><span>Text <sup>Sup</sup></span></p>
<p><abbr title="Abbreviation">Abbr.</abbr></p>
<p><kbd>Keyboard</kbd></p>
<p><mark>Highlighted</mark></p>
<p><a href="#">Link text</a></p>
<p><code>Inline code</code></p>
</div>
```
### Code Blocks
Formatted code snippets with proper syntax styling.
```
// do a thing
export function thing() {
return true;
}
```
### Images
Responsive images with proper scaling and styling.
![A gray kitten lays next to a toy](https://images.unsplash.com/photo-1620196244888-d31ff5bbf163?q=80&w=1000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D)
### Progress Bars
Visual indicators for task completion and loading states.
```html {.example}
<progress value="40" max="100"></progress>
<br>
<progress></progress>
```
### Tables
Structured data presentation with clean styling and optional zebra striping.
```html {.example}
<table>
<caption>I'm just a table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
```
You can use the `wa-zebra-rows` class to add alternating row colors to your table:
```html {.example}
<table class="wa-zebra-rows">
<caption>I'm just a table</caption>
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
<th>Column 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
<tr>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
<td>Cell</td>
</tr>
</tbody>
</table>
```
## Form Controls
### Buttons
Use the [variant utility classes](../utilities/color.md) to set the button's semantic variant.
```html {.example}
<button class="wa-neutral"><wa-icon name="home"></wa-icon> Neutral</button>
<button class="wa-brand">Brand</button>
<button class="wa-success">Success</button>
<button class="wa-warning">Warning</button>
<button class="wa-danger">Danger</button>
```
Use the [appearance utility classes](/docs/utilities/appearance) to change the button's visual appearance:
```html {.example}
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-neutral">A + O</button>
<button class="wa-accent wa-neutral">Accent</button>
<button class="wa-outlined wa-neutral">Outlined</button>
<button class="wa-filled wa-outlined wa-neutral">F + O</button>
<button class="wa-filled wa-neutral">Filled</button>
<button class="wa-plain wa-neutral">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-brand">A + O</button>
<button class="wa-accent wa-brand">Accent</button>
<button class="wa-outlined wa-brand">Outlined</button>
<button class="wa-filled wa-outlined wa-brand">F + O</button>
<button class="wa-filled wa-brand">Filled</button>
<button class="wa-plain wa-brand">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-success">A + O</button>
<button class="wa-accent wa-success">Accent</button>
<button class="wa-outlined wa-success">Outlined</button>
<button class="wa-filled wa-outlined wa-success">F + O</button>
<button class="wa-filled wa-success">Filled</button>
<button class="wa-plain wa-success">Plain</button>
</div>
<div style="margin-block-end: 1rem;">
<button class="wa-accent wa-outlined wa-warning">A + O</button>
<button class="wa-accent wa-warning">Accent</button>
<button class="wa-outlined wa-warning">Outlined</button>
<button class="wa-filled wa-outlined wa-warning">F + O</button>
<button class="wa-filled wa-warning">Filled</button>
<button class="wa-plain wa-warning">Plain</button>
</div>
<div>
<button class="wa-accent wa-outlined wa-danger">A + O</button>
<button class="wa-accent wa-danger">Accent</button>
<button class="wa-outlined wa-danger">Outlined</button>
<button class="wa-filled wa-outlined wa-danger">F + O</button>
<button class="wa-filled wa-danger">Filled</button>
<button class="wa-plain wa-danger">Plain</button>
</div>
```
Use the [size utility classes](../utilities/size.md) to change a button's size.
```html {.example}
<button class="wa-size-s">Small</button>
<button class="wa-size-m">Medium</button>
<button class="wa-size-l">Large</button>
```
Use the `wa-pill` class to give buttons rounded edges.
```html {.example}
<button class="wa-size-s wa-pill">Small</button>
<button class="wa-size-m wa-pill">Medium</button>
<button class="wa-size-l wa-pill">Large</button>
```
### Checkboxes
Multi-select form controls with checked, indeterminate, and disabled states.
```html {.example}
<label><input type="checkbox" checked> Checked</label><br>
<label><input type="checkbox" class="indeterminate"> Indeterminate</label><br>
<label><input type="checkbox" disabled> Disabled</label>
<script>
document.querySelector(".indeterminate").indeterminate = true;
</script>
```
### Radios
Single-select form controls for mutually exclusive choices.
You can wrap native radios in a flex container to give them a horizontal or vertical orientation with even spacing. The convenience [`wa-cluster`](/docs/utilities/cluster) and [`wa-stack`](/docs/utilities/stack) utilities make this easy.
```html {.example}
<div class="wa-cluster">
<label><input type="radio" name="b" value="1" checked> Option 1</label>
<label><input type="radio" name="b" value="2"> Option 2</label>
<label><input type="radio" name="b" value="3"> Option 3</label>
</div>
<div class="wa-stack" style="margin-block-start: var(--wa-space-2xl);">
<label><input type="radio" name="g" value="1" checked> Option 1</label>
<label><input type="radio" name="g" value="2"> Option 2</label>
<label><input type="radio" name="g" value="3"> Option 3</label>
</div>
```
### Selects
Dropdown menus for choosing from a list of options.
```html {.example}
<label>Select
<select id="select">
<option value="option-1">Option 1</option>
<option value="option-2">Option 2</option>
<option value="option-3">Option 3</option>
</select>
</label>
```
### Sliders
Range inputs for selecting numeric values within a specified range.
```html {.example}
<label>Select a value: <input type="range"></label>
```
### Text Fields
Various input types for collecting user text and data.
```html {.example}
<label>Text <input type="text" placeholder="placeholder"></label>
<label>Number <input type="number"></label>
<label>Password <input type="password" required></label>
<label>Email <input type="email"></label>
<label>Search <input type="search"></label>
<label>Telephone <input type="tel"></label>
<label>URL <input type="url"></label>
```
Add the `wa-pill` class to an `<input>` to make it pill-shaped.
```html {.example}
<label>Input <input type="text" placeholder="placeholder" class="wa-pill"></label>
```
### Color Pickers
Visual color selection interface with hex value input.
```html {.example}
<label>Input (color) <input type="color" value="#ff0066"></label>
```
### Date & Time Pickers
Specialized inputs for selecting dates, times, and datetime values.
```html {.example}
<label>Input (datetime-local) <input type="datetime-local"></label>
<label>Input (date) <input type="date"></label>
<label>Input (time) <input type="time"></label>
```
### Textareas
Multi-line text input fields for longer content.
```html {.example}
<label>Textarea <textarea placeholder="Type something"></textarea></label>
```

View File

@@ -2,7 +2,6 @@
title: Rounding Utilities
description: Border radius utilities set an element's border radius property.
tags: ["utilities"]
status: wip
---
<style>

View File

@@ -1,165 +0,0 @@
---
title: Size
description: Size utilities give elements one of three preset sizes (small, medium, or large).
icon: tokens/space
status: experimental
snippets:
- .wa-size-s
- .wa-size-m
- .wa-size-l
---
Some Web Awesome components, like `<wa-button>`, allow you to change their size to one of three presets: `small`, `medium`, and `large` by using a `size` attribute:
{% for component in componentsBy.attribute.size %}
- <a href="../{{ component.url }}"><code>&lt;{{ component.tagName }}&gt;</code></a>
{%- endfor %}
You can create the same effect on any element by using the size utility classes:
- `.wa-size-s`
- `.wa-size-m` _(default)_
- `.wa-size-l`
Using these classes does two things:
- It sets `font-size` to one of the [size tokens](/docs/tokens/typography/#font-size).
You can use CSS `em` units to reference that size in other properties.
- It calculates `--wa-form-control-height` based on the applied size, supporting consistent heights for elements like inputs and buttons.
- It aliases a bunch of other properties that CSS can use:
| Custom Property | Small | Medium | Large |
| --------------- | ----- | ------ | ----- |
| `--wa-size` | `--wa-font-size-s` | `--wa-font-size-m` | `--wa-font-size-l` |
| `--wa-size-smaller` | `--wa-font-size-xs` | `--wa-font-size-s` | `--wa-font-size-m` |
| `--wa-space` | `--wa-space-s` | `--wa-space-m` | `--wa-space-l` |
| `--wa-space-smaller` | `--wa-space-xs` | `--wa-space-s` | `--wa-space-m` |
For example, assume we wanted to make a custom `.tag` class with size variants.
```html { .example }
<span class="tag wa-size-s">Small</span>
<span class="tag">Default</span>
<span class="tag wa-size-m">Medium</span>
<span class="tag wa-size-l">Large</span>
<style>
.tag {
display: inline-block;
padding: var(--wa-space-smaller) var(--wa-space);
border-radius: var(--wa-border-radius-m); /* usually fixed across sizes */
background-color: var(--wa-color-fill-quiet);
border: 1px solid var(--wa-color-border-quiet);
color: var(--wa-color-on-quiet);
}
</style>
```
## Advanced: Customizing Sizes
But what if you are creating a style that should **generally** be smaller (e.g. a badge) or larger (e.g. a pull quote)?
For example, suppose we wanted to define a custom `.tag2` class just like `.tag` in the previous section,
but with a different set of sizes.
This is possible, though a bit more involved.
The first thing you need to do is define these 8 properties in your CSS for your "breakpoints":
| Custom property | Default value |
| --------------- | ------------- |
| `--size-xs` | `var(--wa-font-size-xs)` |
| `--size-s` | `var(--wa-font-size-s)` |
| `--size-m` | `var(--wa-font-size-m)` |
| `--size-l` | `var(--wa-font-size-l)` |
| `--space-xs` | `var(--wa-space-xs)` |
| `--space-s` | `var(--wa-space-s)` |
| `--space-m` | `var(--wa-space-m)` |
| `--space-l` | `var(--wa-space-l)` |
It would look like this:
```css
.tag2 {
--size-xs: var(--wa-font-size-2xs);
--size-s: var(--wa-font-size-xs);
--size-m: var(--wa-font-size-s);
--size-l: var(--wa-font-size-m);
--space-xs: var(--wa-space-2xs);
--space-s: var(--wa-space-xs);
--space-m: var(--wa-space-s);
--space-l: var(--wa-space-m);
}
```
That by itself is sufficient to give you sizes when the utility classes are used, though no default size:
```html { .example }
<span class="tag2 wa-size-s">Small</span>
<span class="tag2">Default</span>
<span class="tag2 wa-size-m">Medium</span>
<span class="tag2 wa-size-l">Large</span>
<style>
.tag2 {
--size-xs: var(--wa-font-size-2xs);
--size-s: var(--wa-font-size-xs);
--size-m: var(--wa-font-size-s);
--size-l: var(--wa-font-size-m);
--space-xs: var(--wa-space-2xs);
--space-s: var(--wa-space-xs);
--space-m: var(--wa-space-s);
--space-l: var(--wa-space-m);
display: inline-block;
font-size: var(--wa-size); /* needed for the default size */
padding: var(--wa-space-smaller) var(--wa-space);
border-radius: var(--wa-border-radius-s); /* usually fixed across sizes */
background-color: var(--wa-color-fill-quiet);
border: 1px solid var(--wa-color-border-quiet);
color: var(--wa-color-on-quiet);
}
</style>
```
Supporting a default size as well requires a little bit more plumbing:
```html { .example }
<div>
<span class="tag3 wa-size-s">Small</span>
<span class="tag3">Default</span>
<span class="tag3 wa-size-m">Medium</span>
<span class="tag3 wa-size-l">Large</span>
</div>
<style>
.tag3 {
--size-xs: var(--wa-font-size-2xs);
--size-s: var(--wa-font-size-xs);
--size-m: var(--wa-font-size-s);
--size-l: var(--wa-font-size-m);
--space-xs: var(--wa-space-2xs);
--space-s: var(--wa-space-xs);
--space-m: var(--wa-space-s);
--space-l: var(--wa-space-m);
/* Default size assignments with 0 specificity */
:where(&) {
--wa-size: var(--size-m);
--wa-size-smaller: var(--size-s);
--wa-space: var(--space-m);
--wa-space-smaller: var(--space-s);
}
display: inline-block;
font-size: var(--wa-size); /* needed for the default size */
padding: var(--wa-space-smaller) var(--wa-space);
border-radius: var(--wa-border-radius-s); /* usually fixed across sizes */
background-color: var(--wa-color-fill-quiet);
border: 1px solid var(--wa-color-border-quiet);
color: var(--wa-color-on-quiet);
}
</style>
```

2
docs/src/env.d.ts vendored
View File

@@ -1,2 +0,0 @@
/// <reference types="astro/client" />
/// <reference path="../.astro/types.d.ts" />

1609
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -52,7 +52,7 @@
"create": "plop --plopfile scripts/plop/plopfile.js",
"test": "CSR_ONLY=\"true\" web-test-runner --group default",
"test:component": "CSR_ONLY=\"true\" web-test-runner -- --watch --group",
"test:contrast": "cd src/styles/color && node contrast.test.js",
"test:contrast": "node scripts/color-palette-contrast-test.js",
"test:watch": "web-test-runner --watch --group default",
"prettier": "prettier --check --log-level=warn .",
"prettier:fix": "prettier --write --log-level=warn .",
@@ -71,8 +71,7 @@
"@shoelace-style/localize": "^3.2.1",
"composed-offset-position": "^0.0.6",
"lit": "^3.2.1",
"qr-creator": "^1.0.0",
"style-observer": "^0.0.7"
"qr-creator": "^1.0.0"
},
"devDependencies": {
"@11ty/eleventy": "3.0.0",
@@ -117,6 +116,7 @@
"marked": "^11.1.0",
"node-html-parser": "^6.1.13",
"npm-check-updates": "^17.1.11",
"nunjucks": "^3.2.4",
"ora": "^8.1.1",
"pascal-case": "^3.1.2",
"playwright": "^1.49.1",

View File

@@ -1,7 +1,7 @@
// Get a list of all CSS files in repo
import chalk from 'chalk';
import Color from 'colorjs.io';
import palettes from './palettes.js';
import palettes from '../src/styles/color/scripts/palettes.js';
let targetContrasts = {
40: 3,

View File

@@ -23,8 +23,8 @@ describe('<wa-badge>', () => {
it('should default to square styling, with the brand color', async () => {
const el = await fixture<WaBadge>(html` <wa-badge>Badge</wa-badge> `);
expect(el.getAttribute('variant')).to.eq(null);
expect(el.variant).to.eq('inherit');
expect(el.getAttribute('variant')).to.eq('brand');
expect(el.variant).to.eq('brand');
});
});

View File

@@ -24,13 +24,7 @@ export default class WaBadge extends WebAwesomeElement {
static shadowStyle = [variantStyles, appearanceStyles, styles];
/** 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';
@property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' = 'brand';
/** The badge's visual appearance. */
@property({ reflect: true }) appearance: 'accent' | 'filled' | 'outlined' = 'accent';

View File

@@ -1,3 +1,43 @@
:host {
display: inline-flex;
}
.button-group {
display: flex;
position: relative;
isolation: isolate;
flex-wrap: wrap;
gap: 1px;
> :hover,
&::slotted(:hover) {
z-index: 1;
}
/* Focus and checked are always on top */
> :focus,
&::slotted(:focus),
> [aria-checked='true'],
&::slotted([aria-checked='true']),
> [checked],
&::slotted([checked]) {
z-index: 2 !important;
}
}
:host([orientation='vertical']) {
flex-direction: column;
}
/* Button groups with at least one outlined button will not have a gap and instead have borders overlap */
.button-group.has-outlined {
gap: 0;
&:not([aria-orientation='vertical']):not(.button-group-vertical)::slotted(:not(:first-child)) {
margin-inline-start: calc(-1 * var(--border-width));
}
&:is([aria-orientation='vertical'], .button-group-vertical)::slotted(:not(:first-child)) {
margin-block-start: calc(-1 * var(--border-width));
}
}

View File

@@ -3,11 +3,9 @@ import { html } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.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 type WaButton from '../button/button.js';
import type WaRadioButton from '../radio-button/radio-button.js';
import styles from './button-group.css';
/**
@@ -22,7 +20,7 @@ import styles from './button-group.css';
*/
@customElement('wa-button-group')
export default class WaButtonGroup extends WebAwesomeElement {
static shadowStyle = [sizeStyles, variantStyles, buttonGroupStyles, styles];
static shadowStyle = [sizeStyles, variantStyles, styles];
@query('slot') defaultSlot: HTMLSlotElement;
@@ -39,16 +37,10 @@ export default class WaButtonGroup extends WebAwesomeElement {
@property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal';
/** The component's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** 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';
@property({ reflect: true }) variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral';
updated(changedProperties: PropertyValues<this>) {
super.updated(changedProperties);
@@ -93,6 +85,7 @@ export default class WaButtonGroup extends WebAwesomeElement {
if (button) {
if ((button as WaButton).appearance === 'outlined') this.hasOutlined = true;
button.setAttribute('size', this.size);
button.classList.add('wa-button-group__button');
button.classList.toggle('wa-button-group__horizontal', this.orientation === 'horizontal');
button.classList.toggle('wa-button-group__vertical', this.orientation === 'vertical');
@@ -126,7 +119,7 @@ function findButton(el: HTMLElement) {
const selector = 'wa-button, wa-radio-button';
// The button could be the target element or a child of it (e.g. a dropdown or tooltip anchor)
return (el.closest(selector) ?? el.querySelector(selector)) as WaButton | WaRadioButton;
return (el.closest(selector) ?? el.querySelector(selector)) as WaButton;
}
declare global {

View File

@@ -1,7 +1,97 @@
:host {
--display: inline-flex;
@layer wa-component {
:host {
--background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
--background-color-hover: color-mix(in oklab, var(--background-color), var(--wa-color-mix-hover));
--background-color-active: color-mix(in oklab, var(--background-color), var(--wa-color-mix-active));
position: relative;
--border-color: transparent;
--border-color-hover: var(--border-color);
--border-color-active: var(--border-color);
--border-width: max(1px, var(--wa-form-control-border-width));
--box-shadow: initial;
--text-color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
--text-color-hover: var(--text-color);
--text-color-active: var(--text-color);
display: inline-block;
position: relative;
}
}
.button {
border-radius: var(--wa-form-control-border-radius);
border-style: var(--wa-border-style);
border-width: var(--border-width);
box-shadow: var(--box-shadow);
align-items: center;
justify-content: center;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
white-space: nowrap;
vertical-align: middle;
transition-property: background, border, box-shadow, color;
transition-duration: var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
cursor: pointer;
padding: 0 var(--wa-space, var(--wa-space-m));
font-family: inherit;
font-size: var(--wa-size, var(--wa-font-size-m));
font-weight: var(--wa-font-weight-action);
line-height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
height: var(--wa-form-control-height);
width: 100%;
display: inline-flex;
background-color: var(--background-color);
border-color: var(--border-color, var(--background-color));
color: var(--text-color);
}
/* Interactive states */
.button:not(.disabled):not(.loading):hover {
background-color: var(--background-color-hover, var(--background-color));
border-color: var(--border-color-hover, var(--border-color, var(--background-color-hover)));
color: var(--text-color-hover, var(--text-color));
}
.button:not(.disabled):not(.loading):active {
background-color: var(--background-color-active, var(--background-color));
border-color: var(--border-color-active, var(--border-color, var(--background-color-active)));
color: var(--text-color-active, var(--text-color));
}
/* Focus states */
.button:focus {
outline: none;
}
.button:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
/* Disabled state */
.button.disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* When disabled, prevent mouse events from bubbling up from children */
.button.disabled * {
pointer-events: none;
}
/* Keep it last so Safari doesn't stop parsing this block */
.button::-moz-focus-inner {
border: 0;
}
/* Pill modifier */
:host([pill]) .button {
border-radius: var(--wa-border-radius-pill);
}
/*
@@ -38,7 +128,7 @@ wa-icon[part~='caret'] {
height: 0.875em;
}
.wa-button:has(&) .suffix {
.button:has(&) .suffix {
display: none;
}
}
@@ -74,7 +164,6 @@ wa-icon[part~='caret'] {
/*
* Badges
*/
button ::slotted(wa-badge) {
border-color: var(--wa-color-surface-default);
position: absolute;
@@ -97,6 +186,67 @@ slot[name='prefix']::slotted(*) {
}
slot[name='suffix']::slotted(*),
.wa-button:not(.visually-hidden-label) [part~='caret'] {
.button:not(.visually-hidden-label) [part~='caret'] {
margin-inline-start: var(--wa-space);
}
/*
* Button group border radius modifications
*/
/* Remove border radius from all grouped buttons by default */
:host(.wa-button-group__button) .button {
border-radius: 0;
}
/* Horizontal orientation */
:host(.wa-button-group__horizontal.wa-button-group__button-first) .button {
border-start-start-radius: var(--wa-form-control-border-radius);
border-end-start-radius: var(--wa-form-control-border-radius);
}
:host(.wa-button-group__horizontal.wa-button-group__button-last) .button {
border-start-end-radius: var(--wa-form-control-border-radius);
border-end-end-radius: var(--wa-form-control-border-radius);
}
/* Vertical orientation */
:host(.wa-button-group__vertical) {
flex: 1 1 auto;
}
:host(.wa-button-group__vertical) .button {
width: 100%;
justify-content: start;
}
:host(.wa-button-group__vertical.wa-button-group__button-first) .button {
border-start-start-radius: var(--wa-form-control-border-radius);
border-start-end-radius: var(--wa-form-control-border-radius);
}
:host(.wa-button-group__vertical.wa-button-group__button-last) .button {
border-end-start-radius: var(--wa-form-control-border-radius);
border-end-end-radius: var(--wa-form-control-border-radius);
}
/* Handle pill modifier for button groups */
:host([pill]) .wa-button-group__horizontal.wa-button-group__button-first {
border-start-start-radius: var(--wa-border-radius-pill);
border-end-start-radius: var(--wa-border-radius-pill);
}
:host([pill]) .wa-button-group__horizontal.wa-button-group__button-last {
border-start-end-radius: var(--wa-border-radius-pill);
border-end-end-radius: var(--wa-border-radius-pill);
}
:host([pill]) .wa-button-group__vertical.wa-button-group__button-first {
border-start-start-radius: var(--wa-border-radius-pill);
border-start-end-radius: var(--wa-border-radius-pill);
}
:host([pill]) .wa-button-group__vertical.wa-button-group__button-last {
border-end-start-radius: var(--wa-border-radius-pill);
border-end-end-radius: var(--wa-border-radius-pill);
}

View File

@@ -44,100 +44,6 @@ describe('<wa-button>', () => {
});
});
describe('when an attribute is removed', () => {
it("should return to 'inherit' when attribute removed with no initial attribute", async () => {
const el = await fixture<WaButton>(html`<wa-button>Button label</wa-button>`);
expect(el.variant).to.equal('inherit');
expect(el.getAttribute('variant')).to.equal(null);
el.removeAttribute('variant');
await el.updateComplete;
expect(el.variant).to.equal('inherit');
expect(el.getAttribute('variant')).to.equal(null);
});
it("should return to 'inherit' when attribute removed with an initial attribute", async () => {
const el = await fixture<WaButton>(html`<wa-button variant="primary">Button label</wa-button>`);
expect(el.variant).to.equal('primary');
expect(el.getAttribute('variant')).to.equal('primary');
el.removeAttribute('variant');
await el.updateComplete;
expect(el.variant).to.equal('inherit');
expect(el.getAttribute('variant')).to.equal(null);
});
});
describe('when a property is set to null', () => {
it("should return to 'default' when property set to null with no initial attribute", async () => {
const el = await fixture<WaButton>(html`<wa-button>Button label</wa-button>`);
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('inherit');
expect(el.getAttribute('variant')).to.equal(null);
});
it("should return to 'default' when property set to null with an initial attribute", async () => {
const el = await fixture<WaButton>(html`<wa-button variant="primary">Button label</wa-button>`);
expect(el.variant).to.equal('primary');
expect(el.getAttribute('variant')).to.equal('primary');
// @ts-expect-error Its a test. Stop.
el.variant = null;
await el.updateComplete;
expect(el.variant).to.equal('inherit');
expect(el.getAttribute('variant')).to.equal(null);
});
});
describe('when provided no parameters', () => {
it('passes accessibility test', async () => {
const el = await fixture<WaButton>(html` <wa-button>Button Label</wa-button> `);
await expect(el).to.be.accessible();
});
it('default values are set correctly', async () => {
const el = await fixture<WaButton>(html` <wa-button>Button Label</wa-button> `);
expect(el.title).to.equal('');
expect(el.variant).to.equal('inherit');
expect(el.appearance).to.equal('accent');
expect(el.size).to.equal('inherit');
expect(el.disabled).to.equal(false);
expect(el.caret).to.equal(false);
expect(el.loading).to.equal(false);
expect(el.pill).to.equal(false);
});
it('should render as a <button>', async () => {
const el = await fixture<WaButton>(html` <wa-button>Button Label</wa-button> `);
expect(el.shadowRoot!.querySelector('button')).to.exist;
expect(el.shadowRoot!.querySelector('a')).not.to.exist;
});
it('should not have a spinner present', async () => {
const el = await fixture<WaButton>(html` <wa-button>Button Label</wa-button> `);
expect(el.shadowRoot!.querySelector('wa-spinner')).not.to.exist;
});
it('should not have a caret present', async () => {
const el = await fixture<WaButton>(html` <wa-button>Button Label</wa-button> `);
expect(el.shadowRoot?.querySelector('[part~="caret"]')).not.to.exist;
});
});
describe('when disabled', () => {
it('passes accessibility test', async () => {
const el = await fixture<WaButton>(html` <wa-button disabled>Button Label</wa-button> `);

View File

@@ -7,8 +7,6 @@ import { HasSlotController } from '../../internal/slot.js';
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import nativeStyles from '../../styles/native/button.css';
import passthroughStyles from '../../styles/shadow/passthrough.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import sizeStyles from '../../styles/utilities/size.css';
import variantStyles from '../../styles/utilities/variants.css';
@@ -48,14 +46,14 @@ import styles from './button.css';
* @cssproperty --border-color - The color of the button's border when the button is not being interacted with.
* @cssproperty --border-color-active - The color of the button's border when active.
* @cssproperty --border-color-hover - The color of the button's border on hover.
* @cssproperty --box-shadow - The shadow effects around the edges of the button.
* @cssproperty --text-color - The color of the button's label when the button is not being interacted with.
* @cssproperty --text-color-active - The color of the button's label when active.
* @cssproperty --text-color-hover - The color of the button's label on hover.
*/
@customElement('wa-button')
export default class WaButton extends WebAwesomeFormAssociatedElement {
static shadowStyle = [passthroughStyles, variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
static rectProxy = 'button';
static shadowStyle = [styles, variantStyles, sizeStyles, appearanceStyles];
static get validators() {
return [...super.validators, MirrorValidator()];
@@ -65,21 +63,20 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix');
private readonly localize = new LocalizeController(this);
@query('.wa-button') button: HTMLButtonElement | HTMLLinkElement;
@query('.button') button: HTMLButtonElement | HTMLLinkElement;
@state() invalid = false;
@property() title = ''; // make reactive to pass through
/** 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';
@property({ reflect: true })
variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral';
/** The button's visual appearance. */
@property({ reflect: true, default: 'accent' })
appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'accent';
@property({ reflect: true }) appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'accent';
/** The button's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** 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;
@@ -103,16 +100,16 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
* The name of the button, submitted as a name/value pair with form data, but only when this button is the submitter.
* This attribute is ignored when `href` is present.
*/
@property({ reflect: true }) name: string | null = null;
@property({ reflect: true }) name: string;
/**
* The value of the button, submitted as a pair with the button's name as part of the form data, but only when this
* button is the submitter. This attribute is ignored when `href` is present.
*/
@property({ reflect: true }) value: string | null = null;
@property({ reflect: true }) value: string;
/** When set, the underlying button will be rendered as an `<a>` with this `href` instead of a `<button>`. */
@property({ reflect: true }) href = null;
@property({ reflect: true }) href: string;
/** Tells the browser where to open the link. Only used when `href` is present. */
@property() target: '_blank' | '_parent' | '_self' | '_top';
@@ -230,7 +227,6 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
part="base"
class=${classMap({
button: true,
'wa-button': true,
caret: this.caret,
disabled: this.disabled,
loading: this.loading,

View File

@@ -1,8 +1,23 @@
:host {
--icon-color: currentColor;
--icon-color: var(--text-color);
--icon-size: var(--wa-font-size-l);
--spacing: var(--wa-space-m);
display: flex;
position: relative;
align-items: stretch;
border-radius: var(--wa-panel-border-radius);
background-color: var(--background-color, var(--wa-color-fill-quiet));
border-color: var(--border-color, transparent);
border-style: var(--wa-panel-border-style);
border-width: var(--wa-panel-border-width);
color: var(--wa-color-text-normal);
gap: var(--spacing);
padding: var(--spacing);
}
:host([appearance~='accent']) {
color: var(--text-color, var(--wa-color-text-normal));
}
[part~='icon'] {
@@ -11,10 +26,6 @@
align-items: center;
color: var(--icon-color);
font-size: var(--icon-size);
::slotted(*) {
margin-inline-end: var(--spacing);
}
}
[part~='message'] {

View File

@@ -1,7 +1,6 @@
import { html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import nativeStyles from '../../styles/native/callout.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import sizeStyles from '../../styles/utilities/size.css';
import variantStyles from '../../styles/utilities/variants.css';
@@ -25,16 +24,10 @@ import styles from './callout.css';
*/
@customElement('wa-callout')
export default class WaCallout extends WebAwesomeElement {
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
static shadowStyle = [variantStyles, appearanceStyles, sizeStyles, styles];
/** 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';
@property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' | 'brand' = 'brand';
/** The callout's visual appearance. */
@property({ reflect: true }) appearance:
@@ -46,7 +39,7 @@ export default class WaCallout extends WebAwesomeElement {
| 'outlined accent' = 'outlined filled';
/** The callout's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
render() {
return html`

View File

@@ -22,12 +22,11 @@
color: var(--wa-color-text-normal);
}
:host(:is([appearance~='accent'], .wa-accent)) {
:host(:is([appearance~='accent'])) {
color: var(--text-color, var(--wa-color-text-normal));
}
:host([appearance~='filled']),
:host(.wa-filled) {
:host([appearance~='filled']) {
--inner-border-color: oklab(from var(--outlined-border-color) l a b / 65%);
}

View File

@@ -34,9 +34,6 @@ export default class WaCard extends WebAwesomeElement {
private readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'media');
/** 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';
/** The card's visual appearance. */
@property({ reflect: true })
appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'outlined';

View File

@@ -1,9 +1,77 @@
[part~='base'] {
:host {
--background-color: var(--wa-form-control-background-color);
--background-color-checked: var(--wa-form-control-activated-color);
--border-color: var(--wa-form-control-border-color);
--border-color-checked: var(--wa-form-control-activated-color);
--border-radius: min(
calc(var(--toggle-size) * 0.375),
var(--wa-border-radius-s)
); /* min prevents entirely circular checkbox */
--border-style: var(--wa-border-style);
--border-width: var(--wa-form-control-border-width);
--box-shadow: none;
--checked-icon-color: var(--wa-color-brand-on-loud);
--toggle-size: 1lh;
color: var(--wa-form-control-value-color);
display: inline-flex;
font-family: inherit;
font-weight: var(--wa-form-control-value-font-weight);
line-height: var(--wa-form-control-value-line-height);
user-select: none;
-webkit-user-select: none;
}
:host [part~='control'] {
flex: 0 0 auto;
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--toggle-size);
height: var(--toggle-size);
border-color: var(--border-color);
border-radius: var(--border-radius);
border-style: var(--border-style);
border-width: var(--border-width);
background-color: var(--background-color);
box-shadow: var(--box-shadow);
transition:
background var(--wa-transition-normal),
border-color var(--wa-transition-fast),
box-shadow var(--wa-transition-fast),
color var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
margin-inline-end: var(--wa-space-xs);
}
:host [part~='base'] {
position: relative;
display: flex;
align-items: flex-start;
color: var(--wa-form-control-value-color);
vertical-align: middle;
cursor: pointer;
}
/* Checked */
[part~='base'] [part~="control"]:has(:checked, :indeterminate) /* scoping this rule to :host breaks in Firefox */ {
color: var(--checked-icon-color);
border-color: var(--border-color-checked);
background-color: var(--background-color-checked);
}
/* Focus */
[part~='base'] [part~="control"]:has(> input:focus-visible:not(:disabled)) /* scoping this rule to :host breaks in Firefox */ {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
/* Disabled */
:host [part~='base']:has(input:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
input {

View File

@@ -8,8 +8,7 @@ import { HasSlotController } from '../../internal/slot.js';
import { RequiredValidator } from '../../internal/validators/required-validator.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import nativeStyles from '../../styles/native/checkbox.css';
import formControlStyles from '../../styles/shadow/form-control.css';
import formControlStyles from '../../styles/component/form-control.css';
import sizeStyles from '../../styles/utilities/size.css';
import '../icon/icon.js';
import styles from './checkbox.css';
@@ -56,7 +55,7 @@ import styles from './checkbox.css';
*/
@customElement('wa-checkbox')
export default class WaCheckbox extends WebAwesomeFormAssociatedElement {
static shadowStyle = [formControlStyles, sizeStyles, nativeStyles, styles];
static shadowStyle = [formControlStyles, sizeStyles, styles];
static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true };
@@ -98,7 +97,7 @@ export default class WaCheckbox extends WebAwesomeFormAssociatedElement {
}
/** The checkbox's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** Disables the checkbox. */
@property({ type: Boolean }) disabled = false;

View File

@@ -30,7 +30,8 @@
.grid {
position: relative;
height: var(--grid-height);
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%),
background-image:
linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 100%),
linear-gradient(to right, #fff 0%, rgba(255, 255, 255, 0) 100%);
border-top-left-radius: calc(var(--border-radius) - var(--border-width));
border-top-right-radius: calc(var(--border-radius) - var(--border-width));
@@ -250,7 +251,8 @@
}
.transparent-bg {
background-image: linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%),
background-image:
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
linear-gradient(45deg, transparent 75%, var(--wa-color-neutral-fill-normal) 75%),
linear-gradient(45deg, var(--wa-color-neutral-fill-normal) 25%, transparent 25%);

View File

@@ -53,7 +53,7 @@ describe('<wa-color-picker>', () => {
expect(inputHandler).to.have.been.calledTwice;
});
it('should emit change and input when the hue slider is moved', async () => {
it.skip('should emit change and input when the hue slider is moved', async () => {
const el = await fixture<WaColorPicker>(html` <wa-color-picker></wa-color-picker> `);
const trigger = el.shadowRoot!.querySelector<HTMLButtonElement>('[part~="trigger"]')!;
const slider = el.shadowRoot!.querySelector<HTMLElement>('[part~="hue-slider"]')!;

View File

@@ -12,7 +12,7 @@ import { HasSlotController } from '../../internal/slot.js';
import { RequiredValidator } from '../../internal/validators/required-validator.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import formControlStyles from '../../styles/shadow/form-control.css';
import formControlStyles from '../../styles/component/form-control.css';
import sizeStyles from '../../styles/utilities/size.css';
import visuallyHidden from '../../styles/utilities/visually-hidden.css';
import { LocalizeController } from '../../utilities/localize.js';
@@ -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, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** Removes the button that lets users toggle between format. */
@property({ attribute: 'without-format-toggle', type: Boolean }) withoutFormatToggle = false;
@@ -520,32 +520,41 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
}
private parseColor(colorString: string) {
if (!colorString || colorString.trim() === '') {
return null;
}
const color = new TinyColor(colorString);
if (!color.isValid) {
return null;
}
const hslColor = color.toHsl();
const rgb = color.toRgb();
const hsvColor = color.toHsv();
// Checks for null RGB values
if (!rgb || rgb.r == null || rgb.g == null || rgb.b == null) {
return null;
}
// Adjust saturation and lightness from 0-1 to 0-100
const hsl = {
h: hslColor.h,
s: hslColor.s * 100,
l: hslColor.l * 100,
a: hslColor.a,
h: hslColor.h || 0,
s: (hslColor.s || 0) * 100,
l: (hslColor.l || 0) * 100,
a: hslColor.a || 0,
};
const rgb = color.toRgb();
const hex = color.toHexString();
const hexa = color.toHex8String();
const hsvColor = color.toHsv();
// Adjust saturation and value from 0-1 to 0-100
const hsv = {
h: hsvColor.h,
s: hsvColor.s * 100,
v: hsvColor.v * 100,
a: hsvColor.a,
h: hsvColor.h || 0,
s: (hsvColor.s || 0) * 100,
v: (hsvColor.v || 0) * 100,
a: hsvColor.a || 0,
};
return {
@@ -589,9 +598,9 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
r: rgb.r,
g: rgb.g,
b: rgb.b,
a: rgb.a,
a: rgb.a || 0,
string: this.setLetterCase(
`rgba(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}, ${rgb.a.toFixed(2).toString()})`,
`rgba(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}, ${(rgb.a || 0).toFixed(2).toString()})`,
),
},
hex: this.setLetterCase(hex),
@@ -991,7 +1000,7 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
autocorrect="off"
autocapitalize="off"
spellcheck="false"
value=${this.isEmpty ? '' : this.inputValue}
.value=${this.isEmpty ? '' : this.inputValue}
?required=${this.required}
?disabled=${this.disabled}
aria-label=${this.localize.term('currentValue')}

View File

@@ -1,23 +1,85 @@
:host {
--icon-color: var(--wa-color-text-quiet);
--spacing: var(--wa-space-m);
--show-duration: 200ms;
--hide-duration: 200ms;
--display: block;
--outlined-border-color: var(--wa-color-surface-border);
display: block;
}
:host([appearance='plain']) {
border-radius: 0;
}
:host summary {
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
-webkit-user-select: none;
cursor: pointer;
&::marker,
&::-webkit-details-marker {
display: none;
}
&:focus {
outline: none;
}
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: calc(var(--spacing) + var(--wa-focus-ring-offset));
}
}
details {
display: block;
overflow-anchor: none;
border: var(--wa-panel-border-width) var(--border-color) var(--wa-panel-border-style);
background-color: var(--background-color, var(--wa-color-surface-default));
border-radius: var(--wa-panel-border-radius);
color: var(--text-color, inherit);
/* Print styles */
@media print {
background: none;
border: solid var(--wa-border-width-s) var(--wa-color-surface-border);
summary {
list-style: none;
}
}
}
:host([disabled]) details {
opacity: 0.5;
cursor: not-allowed;
}
summary {
cursor: not-allowed;
:host summary {
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
-webkit-user-select: none;
cursor: pointer;
padding: var(--spacing); /* Add padding here */
&::marker,
&::-webkit-details-marker {
display: none;
}
summary:focus-visible {
&:focus {
outline: none;
box-shadow: none;
}
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: calc(var(--spacing) + var(--wa-focus-ring-offset));
}
}
@@ -50,6 +112,8 @@ details {
.content {
display: block;
padding-block-start: var(--spacing);
padding-inline: var(--spacing); /* Add horizontal padding */
padding-block-end: var(--spacing); /* Add bottom padding */
}
@keyframes show {

View File

@@ -8,8 +8,6 @@ import { animate, parseDuration } from '../../internal/animate.js';
import { getTargetElement, waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import nativeStyles from '../../styles/native/details.css';
import passthroughStyles from '../../styles/shadow/passthrough.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import { LocalizeController } from '../../utilities/localize.js';
import '../icon/icon.js';
@@ -48,7 +46,7 @@ import styles from './details.css';
*/
@customElement('wa-details')
export default class WaDetails extends WebAwesomeElement {
static shadowStyle = [passthroughStyles, appearanceStyles, nativeStyles, styles];
static shadowStyle = [appearanceStyles, styles];
private detailsObserver: MutationObserver;
private readonly localize = new LocalizeController(this);

View File

@@ -40,6 +40,19 @@
pointer-events: all;
}
/* Sizes */
:host([size='small']) ::slotted(wa-menu) {
font-size: var(--wa-font-size-s);
}
:host([size='medium']) ::slotted(wa-menu) {
font-size: var(--wa-font-size-m);
}
:host([size='large']) ::slotted(wa-menu) {
font-size: var(--wa-font-size-l);
}
/* When users slot a menu, make sure it conforms to the popup's auto-size */
::slotted(wa-menu) {
max-width: var(--auto-size-available-width) !important;

View File

@@ -43,26 +43,24 @@ interface IconSource {
export default class WaIcon extends WebAwesomeElement {
static shadowStyle = styles;
private initialRender = false;
@state() private svg: SVGElement | HTMLTemplateResult | null = null;
/** The name of the icon to draw. Available names depend on the icon library being used. */
@property({ cssProperty: '--wa-icon-name' }) name?: string;
@property() name?: string;
/**
* The family of icons to choose from. For Font Awesome Free (default), valid options include `classic` and `brands`.
* For Font Awesome Pro subscribers, valid options include, `classic`, `sharp`, `duotone`, and `brands`. Custom icon
* libraries may or may not use this property.
*/
@property({ cssProperty: '--wa-icon-family' }) family: string;
@property() family: string;
/**
* The name of the icon's variant. For Font Awesome, valid options include `thin`, `light`, `regular`, and `solid` for
* the `classic` and `sharp` families. Some variants require a Font Awesome Pro subscription. Custom icon libraries
* may or may not use this property.
*/
@property({ cssProperty: '--wa-icon-variant' }) variant: string;
@property() variant: string;
/** Draws the icon in a fixed-width both. */
@property({ attribute: 'fixed-width', type: Boolean, reflect: true }) fixedWidth: false;
@@ -80,7 +78,7 @@ export default class WaIcon extends WebAwesomeElement {
@property() label = '';
/** The name of a registered custom icon library. */
@property({ cssProperty: '--wa-icon-library', default: 'default' }) library = 'default';
@property() library = 'default';
connectedCallback() {
super.connectedCallback();
@@ -90,7 +88,6 @@ export default class WaIcon extends WebAwesomeElement {
firstUpdated(changedProperties: PropertyValues<this>) {
super.firstUpdated(changedProperties);
this.initialRender = true;
this.setIcon();
}
@@ -200,11 +197,6 @@ export default class WaIcon extends WebAwesomeElement {
iconCache.set(url, iconResolver);
}
// If we haven't rendered yet, exit early. This avoids unnecessary work due to watching multiple props.
if (!this.initialRender) {
return;
}
const svg = await iconResolver;
if (svg === RETRYABLE_ERROR) {
@@ -237,7 +229,7 @@ export default class WaIcon extends WebAwesomeElement {
updated(changedProperties: PropertyValues<this>) {
super.updated(changedProperties);
// Sometimes (like with SSR -> hydration) mutators dont get applied due to race conditions. This ensures mutators get re-applied.
// Sometimes (like with SSR -> hydration) mutators don't get applied due to race conditions. This ensures mutators get re-applied.
const library = getIconLibrary(this.library);
const svg = this.shadowRoot?.querySelector('svg');
@@ -251,7 +243,6 @@ export default class WaIcon extends WebAwesomeElement {
return this.svg;
}
// @TODO: 16x16 is generally a safe bet. Perhaps be user setable?? `size="16x16"`, size="20x16". We just want to avoid "blowouts" with SSR.
return html`<svg part="svg" fill="currentColor" width="16" height="16"></svg>`;
}
}

View File

@@ -4,12 +4,15 @@ function dataUri(svg: string) {
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
}
export const iconsByVariant: { [key: string]: { [key: string]: string } } = {
export const icons: { [key: string]: { [key: string]: string } } = {
//
// Solid variant
//
solid: {
check: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>`,
'chevron-down': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg>`,
'chevron-left': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg>`,
'chevron-right': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/></svg>`,
'chevron-right': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/></svg>`,
circle: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg>`,
'eye-dropper': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6v42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480h42.4c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7H96V379.9c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"/></svg>`,
'grip-vertical': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M40 352l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zm192 0l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 320c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 192l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 160c-22.1 0-40-17.9-40-40L0 72C0 49.9 17.9 32 40 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40z"/></svg>`,
@@ -21,7 +24,11 @@ export const iconsByVariant: { [key: string]: { [key: string]: string } } = {
user: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>`,
xmark: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>`,
},
//
// Regular variant
//
regular: {
'circle-question': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm169.8-90.7c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>`,
'circle-xmark': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"/></svg>`,
copy: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M384 336H192c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16l140.1 0L400 115.9V320c0 8.8-7.2 16-16 16zM192 384H384c35.3 0 64-28.7 64-64V115.9c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1H192c-35.3 0-64 28.7-64 64V320c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H256c35.3 0 64-28.7 64-64V416H272v32c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H96V128H64z"/></svg>`,
eye: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M288 80c-65.2 0-118.8 29.6-159.9 67.7C89.6 183.5 63 226 49.4 256c13.6 30 40.2 72.5 78.6 108.3C169.2 402.4 222.8 432 288 432s118.8-29.6 159.9-67.7C486.4 328.5 513 286 526.6 256c-13.6-30-40.2-72.5-78.6-108.3C406.8 109.6 353.2 80 288 80zM95.4 112.6C142.5 68.8 207.2 32 288 32s145.5 36.8 192.6 80.6c46.8 43.5 78.1 95.4 93 131.1c3.3 7.9 3.3 16.7 0 24.6c-14.9 35.7-46.2 87.7-93 131.1C433.5 443.2 368.8 480 288 480s-145.5-36.8-192.6-80.6C48.6 356 17.3 304 2.5 268.3c-3.3-7.9-3.3-16.7 0-24.6C17.3 208 48.6 156 95.4 112.6zM288 336c44.2 0 80-35.8 80-80s-35.8-80-80-80c-.7 0-1.3 0-2 0c1.3 5.1 2 10.5 2 16c0 35.3-28.7 64-64 64c-5.5 0-10.9-.7-16-2c0 .7 0 1.3 0 2c0 44.2 35.8 80 80 80zm0-208a128 128 0 1 1 0 256 128 128 0 1 1 0-256z"/></svg>`,
@@ -29,11 +36,6 @@ export const iconsByVariant: { [key: string]: { [key: string]: string } } = {
},
};
/**
* Union of all icons, across variants
*/
export const icons: { [key: string]: string } = Object.assign({}, ...Object.values(iconsByVariant));
//
// System icons are a separate library to ensure they're always available, regardless of how the default icon library is
// configured or if its icons resolve properly. All Web Awesome components must use the system library instead of the
@@ -42,14 +44,10 @@ export const icons: { [key: string]: string } = Object.assign({}, ...Object.valu
const systemLibrary: IconLibrary = {
name: 'system',
resolver: (name: string, _family = 'classic', variant = 'solid') => {
// family is ignored for now
// Default to `regular` for unknown variants
variant = variant in iconsByVariant ? variant : 'regular';
let collection = icons[variant];
let icons = iconsByVariant[variant];
// Fall back to other variants if icon is not found in the variant requested
let svg = icons[name] ?? iconsByVariant.regular[name] ?? iconsByVariant.solid[name];
// Fall back to a question mark if the icon is missing
let svg = collection[name] ?? icons.regular[name] ?? icons.regular['circle-question'];
if (svg) {
return dataUri(svg);

View File

@@ -1,21 +1,74 @@
:host {
--border-width: var(--wa-form-control-border-width);
--box-shadow: initial;
--outlined-background-color: var(--wa-form-control-background-color);
--outlined-border-color: var(--wa-form-control-border-color);
--outlined-text-color: var(--wa-form-control-value-color);
border-width: 0;
}
.wa-text-field {
.text-field {
flex: auto;
display: flex;
align-items: stretch;
justify-content: start;
position: relative;
border-color: inherit;
border-style: inherit;
border-radius: inherit;
transition: inherit;
height: var(--wa-form-control-height);
padding-block: 0;
border-color: var(--border-color, var(--wa-form-control-border-color));
border-radius: var(--wa-form-control-border-radius);
border-style: var(--wa-form-control-border-style);
border-width: var(--border-width);
cursor: text;
color: var(--wa-form-control-value-color);
font-size: var(--wa-size);
font-family: inherit;
font-weight: var(--wa-form-control-value-font-weight);
line-height: var(--wa-form-control-value-line-height);
vertical-align: middle;
width: 100%;
transition:
background-color var(--wa-transition-normal),
border var(--wa-transition-normal),
outline var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
background-color: var(--background-color, var(--wa-form-control-background-color));
box-shadow: var(--box-shadow);
padding: var(--wa-space-smaller) var(--wa-space);
&:focus-within {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
/* Style disabled inputs */
&:has(:disabled) {
cursor: not-allowed;
opacity: 0.5;
}
}
:host([pill]) .text-field {
border-radius: var(--wa-border-radius-pill) !important;
}
.text-field input,
.text-field textarea {
/*
Fixes an alignment issue with placeholders.
https://github.com/shoelace-style/webawesome/issues/342
*/
height: 100%;
padding: 0;
border: none;
outline: none;
box-shadow: none;
margin: 0;
cursor: inherit;
-webkit-appearance: none;
font: inherit;
}
input {
@@ -29,17 +82,51 @@ input {
height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
padding-block: 0;
color: inherit;
&:autofill {
&,
&:hover,
&:focus,
&:active {
box-shadow: none;
caret-color: var(--wa-form-control-value-color);
}
}
&::placeholder {
color: var(--wa-form-control-placeholder-color);
user-select: none;
-webkit-user-select: none;
}
&::-webkit-search-decoration,
&::-webkit-search-cancel-button,
&::-webkit-search-results-button,
&::-webkit-search-results-decoration {
-webkit-appearance: none;
}
&:focus {
outline: none;
}
}
input::-webkit-search-decoration,
input::-webkit-search-cancel-button,
input::-webkit-search-results-button,
input::-webkit-search-results-decoration {
-webkit-appearance: none;
}
textarea {
&:autofill {
&,
&:hover,
&:focus,
&:active {
box-shadow: none;
caret-color: var(--wa-form-control-value-color);
}
}
input:focus {
outline: none;
&::placeholder {
color: var(--wa-form-control-placeholder-color);
user-select: none;
-webkit-user-select: none;
}
}
.prefix,

View File

@@ -23,7 +23,7 @@ describe('<wa-input>', () => {
const el = await fixture<WaInput>(html` <wa-input></wa-input> `);
expect(el.type).to.equal('text');
expect(el.size).to.equal('inherit');
expect(el.size).to.equal('medium');
expect(el.name).to.equal(null);
expect(el.value).to.equal(null);
expect(el.defaultValue).to.equal(null);

View File

@@ -8,8 +8,7 @@ import { HasSlotController } from '../../internal/slot.js';
import { MirrorValidator } from '../../internal/validators/mirror-validator.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import nativeStyles from '../../styles/native/input.css';
import formControlStyles from '../../styles/shadow/form-control.css';
import formControlStyles from '../../styles/component/form-control.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import sizeStyles from '../../styles/utilities/size.css';
import { LocalizeController } from '../../utilities/localize.js';
@@ -58,7 +57,7 @@ import styles from './input.css';
*/
@customElement('wa-input')
export default class WaInput extends WebAwesomeFormAssociatedElement {
static shadowStyle = [sizeStyles, appearanceStyles, formControlStyles, nativeStyles, styles];
static shadowStyle = [sizeStyles, appearanceStyles, formControlStyles, styles];
static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true };
@@ -115,7 +114,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, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** The input's visual appearance. */
@property({ reflect: true }) appearance: 'filled' | 'outlined' = 'outlined';
@@ -400,7 +399,7 @@ export default class WaInput extends WebAwesomeFormAssociatedElement {
<slot name="label">${this.label}</slot>
</label>
<div part="input" class="wa-text-field">
<div part="input" class="text-field">
<slot name="prefix" part="prefix" class="prefix"></slot>
<input

View File

@@ -28,7 +28,7 @@ export default class WaMenu extends WebAwesomeElement {
static shadowStyle = [sizeStyles, styles];
/** The component's size. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
@query('slot') defaultSlot: HTMLSlotElement;

View File

@@ -1,19 +1,16 @@
import type { PropertyValues } from 'lit';
import { html, isServer } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { live } from 'lit/directives/live.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { toLength, toPx } from '../../internal/css-values.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import visuallyHidden from '../../styles/utilities/visually-hidden.css';
import styles from './page.css';
import mobileStyles from './page.mobile.styles.js';
import '../button/button.js';
import '../drawer/drawer.js';
import '../icon/icon.js';
import type { PropertyValues } from 'lit';
import type WaDrawer from '../drawer/drawer.js';
import '../icon/icon.js';
import styles from './page.css';
import mobileStyles from './page.mobile.styles.js';
if (typeof ResizeObserver === 'undefined') {
globalThis.ResizeObserver = class {
@@ -28,6 +25,58 @@ if (typeof ResizeObserver === 'undefined') {
};
}
//
// TODO - the toPx and toLength functions aren't used anywhere else, and they're not named or documented well enough to
// abstract into a utility as-is.
//
/** Converts a non-pixel value to a pixel value. */
function toPx(value: string | number, element: HTMLElement | SVGElement = document.documentElement): number {
if (!Number.isNaN(Number(value))) {
return Number(value);
}
// If CSS.registerProperty isn't supported, try to parse as-is
if (!window.CSS || !CSS.registerProperty) {
if (typeof value === 'string' && value.endsWith('px')) {
return parseFloat(value);
}
return Number(value) || 0;
}
const resolver = '--wa-length-resolver';
// Register the property if not already done
if (!CSS.registerProperty.toString().includes(resolver)) {
try {
CSS.registerProperty({
name: resolver,
syntax: '<length>',
inherits: false,
initialValue: '0px',
});
} catch (e) {
// Property might already be registered
}
}
const previousValue = element.style.getPropertyValue(resolver);
element.style.setProperty(resolver, value as string);
const computedValue = getComputedStyle(element)?.getPropertyValue(resolver);
element.style.setProperty(resolver, previousValue);
if (computedValue?.endsWith('px')) {
return parseFloat(computedValue);
}
return Number(computedValue) || 0;
}
/** Converts a number or string to a CSS px value. Not used anywhere else, so consolidated here for the time being. */
function toLength(px: number | string): string {
return Number.isNaN(Number(px)) ? (px as string) : `${px}px`;
}
/**
* @summary Pages offer an easy way to scaffold entire page layouts using minimal markup.
* @documentation https://backers.webawesome.com/docs/components/page
@@ -373,3 +422,34 @@ declare global {
'wa-page': WaPage;
}
}
//
// Append a supporting light DOM styles for <wa-page>
//
const stylesheet = new CSSStyleSheet();
stylesheet.replaceSync(`
:is(html, body):has(wa-page) {
min-height: 100%;
height: 100%;
padding: 0;
margin: 0;
}
/**
Because headers are sticky, this is needed to make sure page fragment anchors scroll down past the headers / subheaders and are visible.
IE: \`<a href="#id-for-h2">\` anchors.
*/
wa-page :is(*, *:after, *:before) {
scroll-margin-top: var(--scroll-margin-top);
}
wa-page[view='desktop'] [data-toggle-nav] {
display: none;
}
wa-page[view='mobile'] .wa-desktop-only, wa-page[view='desktop'] .wa-mobile-only {
display: none !important;
}
`);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];

View File

@@ -109,7 +109,7 @@ export default class WaPopup extends WebAwesomeElement {
| 'left-start'
| 'left-end' = 'top';
/** Which bounding box to use for flipping, shifting, and auto-sizing? */
/** The bounding box to use for flipping, shifting, and auto-sizing. */
@property() boundary: 'viewport' | 'scroll' = 'viewport';
/** The distance in pixels from which to offset the panel away from its anchor. */

View File

@@ -1,18 +1,20 @@
:host {
--indicator-color: var(--wa-color-brand-fill-loud);
--display: flex;
display: flex;
}
.progress-bar {
flex: 1 1 auto;
display: flex;
position: relative;
overflow: hidden;
height: 1.25rem;
border-radius: var(--wa-border-radius-pill);
background-color: var(--wa-color-neutral-fill-normal);
color: var(--wa-color-brand-on-loud);
}
.progress-bar {
position: relative;
overflow: hidden;
}
.indicator {
width: var(--percentage);
display: flex;

View File

@@ -4,7 +4,6 @@ import { customElement, property } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { clamp } from '../../internal/math.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import passthroughStyles from '../../styles/shadow/passthrough.css';
import { LocalizeController } from '../../utilities/localize.js';
import styles from './progress-bar.css';
@@ -25,7 +24,7 @@ import styles from './progress-bar.css';
*/
@customElement('wa-progress-bar')
export default class WaProgressBar extends WebAwesomeElement {
static shadowStyle = [passthroughStyles, styles];
static shadowStyle = styles;
private readonly localize = new LocalizeController(this);
/** The current progress as a percentage, 0 to 100. */

View File

@@ -1,77 +0,0 @@
:host {
--display: inline-flex;
}
.prefix,
.suffix,
.label {
display: inline-flex;
position: relative;
align-items: center;
}
/* We use a hidden input so constraint validation errors work, since they don't appear to show when used with buttons.
We can't actually hide it, though, otherwise the messages will be suppressed by the browser. */
.hidden-input {
all: unset;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
outline: dotted 1px red;
opacity: 0;
z-index: -1;
}
/*
* Checked buttons
*/
:host([checked]) {
--indicator-color: var(--wa-form-control-activated-color);
--indicator-width: var(--wa-border-width-s);
box-shadow: inset 0 0 0 var(--indicator-width) var(--indicator-color);
& button {
--border-color: var(--indicator-color);
}
}
/*
* Active buttons
*/
button:active {
--text-color-active: var(--wa-form-control-activated-color);
--border-color-active: var(--wa-form-control-activated-color);
}
/* Horizontal radio pill buttons */
:host([data-wa-radio-horizontal][data-wa-radio-first]:not([data-wa-radio-last])) .wa-pill {
border-start-end-radius: 0;
border-end-end-radius: 0;
}
:host([data-wa-radio-horizontal][data-wa-radio-inner]) .wa-pill {
border-radius: 0;
}
:host([data-wa-radio-horizontal][data-wa-radio-last]:not([data-wa-radio-first])) .wa-pill {
border-start-start-radius: 0;
border-end-start-radius: 0;
}
/* Vertical radio pill buttons */
:host([data-wa-radio-vertical][data-wa-radio-first]:not([data-wa-radio-last])) .wa-pill {
border-end-start-radius: 0;
border-end-end-radius: 0;
}
:host([data-wa-radio-vertical][data-wa-radio-inner]) .wa-pill {
border-radius: 0;
}
:host([data-wa-radio-vertical][data-wa-radio-last]:not([data-wa-radio-first])) .wa-pill {
border-start-start-radius: 0;
border-start-end-radius: 0;
}

View File

@@ -1,28 +0,0 @@
import { expect } from '@open-wc/testing';
import { html } from 'lit';
import { fixtures } from '../../internal/test/fixture.js';
import type WaRadioGroup from '../radio-group/radio-group.js';
import type WaRadioButton from './radio-button.js';
describe('<wa-radio-button>', () => {
for (const fixture of fixtures) {
describe(`with "${fixture.type}" rendering`, () => {
it('should not get checked when disabled', async () => {
const radioGroup = await fixture<WaRadioGroup>(html`
<wa-radio-group value="1">
<wa-radio-button id="radio-1" value="1"></wa-radio-button>
<wa-radio-button id="radio-2" value="2" disabled></wa-radio-button>
</wa-radio-group>
`);
const radio1 = radioGroup.querySelector<WaRadioButton>('#radio-1')!;
const radio2 = radioGroup.querySelector<WaRadioButton>('#radio-2')!;
radio2.click();
await Promise.all([radio1.updateComplete, radio2.updateComplete]);
expect(radio1.checked).to.be.true;
expect(radio2.checked).to.be.false;
});
});
}
});

View File

@@ -1,160 +0,0 @@
import { customElement, property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { html } from 'lit/static-html.js';
import { HasSlotController } from '../../internal/slot.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import nativeStyles from '../../styles/native/button.css';
import passthroughStyles from '../../styles/shadow/passthrough.css';
import appearanceStyles from '../../styles/utilities/appearance.css';
import sizeStyles from '../../styles/utilities/size.css';
import variantStyles from '../../styles/utilities/variants.css';
import styles from './radio-button.css';
/**
* @summary Radios buttons allow the user to select a single option from a group using a button-like control.
* @documentation https://backers.webawesome.com/docs/components/radio-button
* @status stable
* @since 2.0
*
* @slot - The radio button's label.
* @slot prefix - A presentational prefix icon or similar element.
* @slot suffix - A presentational suffix icon or similar element.
*
* @event blur - Emitted when the button loses focus.
* @event focus - Emitted when the button gains focus.
*
* @cssproperty --indicator-color - The color of the checked button indicator.
* @cssproperty --indicator-width - The width of the checked button indicator.
*
* @csspart base - The internal `<button>` element.
* @csspart checked - The internal button element when the radio button is checked.
* @csspart prefix - The container that wraps the prefix.
* @csspart label - The container that wraps the radio button's label.
* @csspart suffix - The container that wraps the suffix.
* @cssproperty --display - Set to `none` to hide the element, or any other valid `display` value to override the internal `display` value of the `base` part.
*/
@customElement('wa-radio-button')
export default class WaRadioButton extends WebAwesomeFormAssociatedElement {
static shadowStyle = [passthroughStyles, variantStyles, appearanceStyles, sizeStyles, nativeStyles, styles];
static rectProxy = 'input';
private readonly hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix');
@query('button') input: HTMLButtonElement;
@query('.hidden-input') hiddenInput: HTMLInputElement;
/**
* @internal The radio button's checked state. This is exposed as an "internal" attribute so we can reflect it, making
* it easier to style in button groups.
*/
@property({ type: Boolean, reflect: true }) checked = false;
/** The radio's value. When selected, the radio group will receive this value. */
@property({ reflect: true }) value: string;
/** Disables the radio button. */
@property({ type: Boolean }) disabled = false;
/**
* 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, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
/** Draws a pill-style radio button with rounded edges. */
@property({ type: Boolean, reflect: true }) pill = false;
/**
* The string pointing to a form's id.
*/
@property({ reflect: true }) form: string | null = null;
/**
* Used for SSR. if true, will show slotted prefix on initial render.
*/
@property({ type: Boolean, attribute: 'with-prefix' }) withPrefix = false;
/**
* Used for SSR. if true, will show slotted suffix on initial render.
*/
@property({ type: Boolean, attribute: 'with-suffix' }) withSuffix = false;
/**
* Used for SSR. if true, will show slotted suffix on initial render. (should this be withDefault, since its the default slot??)
*/
@property({ type: Boolean, attribute: 'with-label' }) withLabel = false;
// Needed for Form Validation. Without it we get a console error.
static shadowRootOptions = { ...WebAwesomeFormAssociatedElement.shadowRootOptions, delegatesFocus: true };
connectedCallback() {
super.connectedCallback();
this.setAttribute('role', 'presentation');
}
private handleClick(e: MouseEvent) {
if (this.disabled) {
e.preventDefault();
e.stopPropagation();
return;
}
this.checked = true;
}
@watch('disabled', { waitUntilFirstUpdate: true })
handleDisabledChange() {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
/** Sets focus on the radio button. */
focus(options?: FocusOptions) {
this.input.focus(options);
}
/** Removes focus from the radio button. */
blur() {
this.input.blur();
}
render() {
const hasLabel = this.hasUpdated ? this.hasSlotController.test('[default]') : this.withLabel;
const hasPrefix = this.hasUpdated ? this.hasSlotController.test('prefix') : this.withPrefix;
const hasSuffix = this.hasUpdated ? this.hasSlotController.test('suffix') : this.withSuffix;
return html`
<button
part="base${this.checked ? ' checked' : ''}"
role="radio"
aria-checked="${this.checked}"
class=${classMap({
'wa-neutral': !this.checked,
'wa-brand': this.checked,
disabled: this.disabled,
'wa-outlined': true,
'wa-filled': this.checked,
'wa-pill': this.pill,
'has-label': hasLabel,
'has-prefix': hasPrefix,
'has-suffix': hasSuffix,
})}
aria-disabled=${this.disabled}
type="button"
value=${ifDefined(this.value)}
@click=${this.handleClick}
>
<slot name="prefix" part="prefix" class="prefix"></slot>
<slot part="label" class="label"></slot>
<slot name="suffix" part="suffix" class="suffix"></slot>
</button>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'wa-radio-button': WaRadioButton;
}
}

View File

@@ -18,7 +18,7 @@
margin-inline-start: var(--wa-form-control-required-content-offset);
}
.wa-button-group {
.button-group {
display: flex;
}
@@ -35,13 +35,14 @@
gap: var(--wa-space-m);
}
/* When radio buttons are slotted */
:host([orientation]) .form-control-has-radio-buttons [part~='form-control-input'] {
gap: 0;
flex-wrap: nowrap;
}
/* Help text */
[part~='hint'] {
margin-block-start: var(--wa-space-xs);
}
/* Radios have the "button" appearance */
:host fieldset.has-radio-buttons {
[part~='form-control-input'] {
gap: 0;
}
}

View File

@@ -249,61 +249,6 @@ describe('<wa-radio-group>', () => {
});
});
describe('when a size is applied', () => {
it('should apply the same size to all radios', async () => {
const radioGroup = await fixture<WaRadioGroup>(html`
<wa-radio-group size="large">
<wa-radio id="radio-1" value="1"></wa-radio>
<wa-radio id="radio-2" value="2"></wa-radio>
</wa-radio-group>
`);
const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio');
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 () => {
const radioGroup = await fixture<WaRadioGroup>(html`
<wa-radio-group size="large">
<wa-radio-button id="radio-1" value="1"></wa-radio-button>
<wa-radio-button id="radio-2" value="2"></wa-radio-button>
</wa-radio-group>
`);
const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio-button');
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 computed size of all radio buttons when size changes', async () => {
const radioGroup = await fixture<WaRadioGroup>(html`
<wa-radio-group size="small">
<wa-radio-button id="radio-1" value="1"></wa-radio-button>
<wa-radio-button id="radio-2" value="2"></wa-radio-button>
</wa-radio-group>
`);
const [radio1, radio2] = radioGroup.querySelectorAll('wa-radio-button');
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('inherit');
expect(radio1.getComputed('size')).to.equal('large');
expect(radio2.size).to.equal('inherit');
expect(radio2.getComputed('size')).to.equal('large');
});
});
describe('when handling focus', () => {
const doAction = async (instance: WaRadioGroup, type: string) => {
if (type === 'focus') {

View File

@@ -6,25 +6,21 @@ import { HasSlotController } from '../../internal/slot.js';
import { RequiredValidator } from '../../internal/validators/required-validator.js';
import { watch } from '../../internal/watch.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import formControlStyles from '../../styles/shadow/form-control.css';
import buttonGroupStyles from '../../styles/utilities/button-group.css';
import formControlStyles from '../../styles/component/form-control.css';
import sizeStyles from '../../styles/utilities/size.css';
import '../radio-button/radio-button.js';
import type WaRadioButton from '../radio-button/radio-button.js';
import '../radio/radio.js';
import type WaRadio from '../radio/radio.js';
import styles from './radio-group.css';
/**
* @summary Radio groups are used to group multiple [radios](/docs/components/radio) or [radio buttons](/docs/components/radio-button) so they function as a single form control.
* @summary Radio groups are used to group multiple [radios](/docs/components/radio) so they function as a single form control.
* @documentation https://backers.webawesome.com/docs/components/radio-group
* @status stable
* @since 2.0
*
* @dependency wa-radio
* @dependency wa-radio-button
*
* @slot - The default slot where `<wa-radio>` or `<wa-radio-button>` elements are placed.
* @slot - The default slot where `<wa-radio>` elements are placed.
* @slot label - The radio group's label. Required for proper accessibility. Alternatively, you can use the `label`
* attribute.
* @slot hint - Text that describes how to use the radio group. Alternatively, you can use the `hint` attribute.
@@ -41,7 +37,7 @@ import styles from './radio-group.css';
*/
@customElement('wa-radio-group')
export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
static shadowStyle = [sizeStyles, buttonGroupStyles, formControlStyles, styles];
static shadowStyle = [sizeStyles, formControlStyles, styles];
static get validators() {
const validators = isServer
@@ -61,9 +57,9 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
private readonly hasSlotController = new HasSlotController(this, 'hint', 'label');
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
@state() hasRadioButtons = false;
@state() private hasRadioButtons = false;
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
/**
* The radio group's label. Required for proper accessibility. If you need to display HTML, use the `label` slot
@@ -102,7 +98,7 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
@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, except when explicitly overridden. */
@property({ reflect: true, initial: 'medium' }) size: 'small' | 'medium' | 'large' | 'inherit' = 'inherit';
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';
/** Ensures a child radio is checked before allowing the containing form to submit. */
@property({ type: Boolean, reflect: true }) required = false;
@@ -132,8 +128,29 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
}
}
/**
* We use the first available radio as the validationTarget similar to native HTML that shows the validation popup on
* the first radio element.
*/
get validationTarget() {
if (isServer) return undefined;
const radio = this.querySelector<WaRadio>(':is(wa-radio):not([disabled])');
if (!radio) return undefined;
return radio;
}
formResetCallback(...args: Parameters<WebAwesomeFormAssociatedElement['formResetCallback']>) {
this.value = this.defaultValue;
super.formResetCallback(...args);
this.syncRadioElements();
}
private handleRadioClick = (e: Event) => {
const clickedRadio = (e.target as HTMLElement).closest<WaRadio | WaRadioButton>('wa-radio, wa-radio-button');
const clickedRadio = (e.target as HTMLElement).closest<WaRadio>('wa-radio');
if (!clickedRadio || clickedRadio.disabled) {
return;
@@ -144,17 +161,13 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
clickedRadio.checked = true;
const radios = this.getAllRadios();
const hasRadioButtons = radios.some(radio => radio.tagName.toLowerCase() === 'wa-radio-button');
for (const radio of radios) {
if (clickedRadio === radio) {
continue;
}
radio.checked = false;
if (!hasRadioButtons) {
radio.setAttribute('tabindex', '-1');
}
radio.setAttribute('tabindex', '-1');
}
if (this.value !== oldValue) {
@@ -164,7 +177,7 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
};
private getAllRadios() {
return [...this.querySelectorAll<WaRadio | WaRadioButton>('wa-radio, wa-radio-button')];
return [...this.querySelectorAll<WaRadio>('wa-radio')];
}
private handleLabelClick() {
@@ -173,12 +186,12 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
private async syncRadioElements() {
const radios = this.getAllRadios();
// Detect the presence of radio buttons
this.hasRadioButtons = radios.some(radio => radio.localName === 'wa-radio-button');
let hasRadioButtons = false;
// Add data attributes to support styling
radios.forEach((radio, index) => {
if (radio.appearance === 'button') hasRadioButtons = true;
radio.setAttribute('size', this.size);
radio.toggleAttribute('data-wa-radio-horizontal', this.orientation !== 'vertical');
radio.toggleAttribute('data-wa-radio-vertical', this.orientation === 'vertical');
radio.toggleAttribute('data-wa-radio-first', index === 0);
@@ -186,8 +199,10 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
radio.toggleAttribute('data-wa-radio-last', index === radios.length - 1);
});
// If at least one radio button exists, we assume it's a radio button group
this.hasRadioButtons = hasRadioButtons;
await Promise.all(
// Sync the checked state and size
radios.map(async radio => {
await radio.updateComplete;
@@ -200,43 +215,8 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
);
if (radios.length > 0 && !radios.some(radio => radio.checked)) {
if (this.hasRadioButtons) {
const buttonRadio = radios[0].shadowRoot?.querySelector('button');
if (buttonRadio) {
buttonRadio.setAttribute('tabindex', '0');
}
} else {
radios[0].setAttribute('tabindex', '0');
}
radios[0].setAttribute('tabindex', '0');
}
if (this.hasRadioButtons) {
const buttonGroup = this.shadowRoot?.querySelector('wa-button-group');
if (buttonGroup) {
buttonGroup.disableRole = true;
}
}
}
/**
* We use the first available radio as the validationTarget similar to native HTML that shows the validation popup on
* the first radio element.
*/
get validationTarget() {
if (isServer) return undefined;
const radio = this.querySelector<WaRadio | WaRadioButton>(':is(wa-radio, wa-radio-button):not([disabled])');
if (!radio) return undefined;
// If it's a radio button, return the internal button element
if (radio.localName === 'wa-radio-button') {
return radio.input || radio;
}
// Otherwise return the radio itself
return radio;
}
@watch('value')
@@ -244,19 +224,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
this.syncRadioElements();
}
@watch('size', { waitUntilFirstUpdate: true })
handleSizeChange() {
this.syncRadioElements();
}
formResetCallback(...args: Parameters<WebAwesomeFormAssociatedElement['formResetCallback']>) {
this.value = this.defaultValue;
super.formResetCallback(...args);
this.syncRadioElements();
}
private handleKeyDown(event: KeyboardEvent) {
if (!['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(event.key)) {
return;
@@ -340,7 +307,7 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
'form-control': true,
'form-control-radio-group': true,
'form-control-has-label': hasLabel,
'form-control-has-radio-buttons': this.hasRadioButtons,
'has-radio-buttons': this.hasRadioButtons,
})}
role="radiogroup"
aria-labelledby="label"
@@ -358,14 +325,7 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
<slot name="label">${this.label}</slot>
</label>
<slot
part="form-control-input"
class=${classMap({
'wa-button-group': this.hasRadioButtons,
'wa-button-group-vertical': this.hasRadioButtons && this.orientation === 'vertical',
})}
@slotchange=${this.syncRadioElements}
></slot>
<slot part="form-control-input" @slotchange=${this.syncRadioElements}></slot>
<slot
name="hint"

View File

@@ -1,23 +1,31 @@
:host {
display: grid;
grid-template-columns: auto 1fr;
--background-color: var(--wa-form-control-background-color);
--background-color-checked: var(--background-color);
--border-color: var(--wa-form-control-border-color);
--border-color-checked: var(--wa-form-control-activated-color);
--border-style: var(--wa-border-style);
--border-width: var(--wa-form-control-border-width);
--box-shadow: none;
--checked-icon-color: var(--wa-form-control-activated-color);
--checked-icon-scale: 0.75;
--toggle-size: round(1lh, 1px);
color: var(--wa-form-control-value-color);
display: inline-flex;
flex-direction: row;
align-items: top;
vertical-align: middle;
font-family: inherit;
font-weight: var(--wa-form-control-value-font-weight);
line-height: var(--wa-form-control-value-line-height);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
:host(:focus-visible) {
:host(:focus) {
outline: none;
}
.checked-icon {
display: flex;
fill: currentColor;
width: var(--toggle-size);
height: var(--toggle-size);
scale: var(--checked-icon-scale);
}
/* When the control isn't checked, hide the circle for Windows High Contrast mode a11y */
:host(:not(:state(checked))) svg circle {
opacity: 0;
@@ -28,6 +36,146 @@
}
[part~='hint'] {
grid-column: 2;
margin-block-start: var(--wa-space-3xs);
}
/* Default appearance */
:host([appearance='default']) {
.control {
flex: 0 0 auto;
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--toggle-size);
height: var(--toggle-size);
border-color: var(--border-color);
border-radius: 50%;
border-style: var(--border-style);
border-width: var(--border-width);
background-color: var(--background-color);
box-shadow: var(--box-shadow);
color: transparent;
transition:
background var(--wa-transition-normal),
border-color var(--wa-transition-fast),
box-shadow var(--wa-transition-fast),
color var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
margin-inline-end: var(--wa-space-xs);
}
.checked-icon {
display: flex;
fill: currentColor;
width: var(--toggle-size);
height: var(--toggle-size);
scale: var(--checked-icon-scale);
}
}
/* Checked */
:host(:state(checked)) .control {
color: var(--checked-icon-color);
border-color: var(--border-color-checked);
background-color: var(--background-color-checked);
}
/* Focus */
:host(:focus-visible) .control {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
/* Disabled */
:host([disabled]) {
opacity: 0.5;
cursor: not-allowed;
}
/* Button appearance */
:host([appearance='button']) {
align-items: center;
min-height: var(--wa-form-control-height);
background-color: var(--wa-color-surface-default);
border: var(--border-width) var(--border-style) var(--wa-form-control-border-color);
border-radius: var(--wa-border-radius-m);
padding: 0 var(--wa-space);
transition:
background-color var(--wa-transition-fast),
border-color var(--wa-transition-fast);
.control {
display: none;
}
}
/* Horizontal grouping - remove inner border radius */
:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-inner]) {
border-radius: 0;
}
:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-first]) {
border-start-end-radius: 0;
border-end-end-radius: 0;
}
:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-last]) {
border-start-start-radius: 0;
border-end-start-radius: 0;
}
/* Vertical grouping - remove inner border radius */
:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-inner]) {
border-radius: 0;
}
:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-first]) {
border-end-start-radius: 0;
border-end-end-radius: 0;
}
:host([appearance='button'][data-wa-radio-vertical][data-wa-radio-last]) {
border-start-start-radius: 0;
border-start-end-radius: 0;
}
:host([appearance='button']:hover:not([disabled], :state(checked))) {
background-color: color-mix(in srgb, var(--wa-color-surface-default) 95%, var(--wa-color-mix-hover));
}
:host([appearance='button']:focus-visible) {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
:host([appearance='button']:state(checked)) {
border-color: var(--border-color-checked);
background-color: var(--wa-color-brand-fill-quiet);
}
:host([appearance='button']:state(checked):focus-visible) {
outline: var(--wa-focus-ring-style) var(--wa-focus-ring-width) var(--wa-color-brand-border-loud);
outline-offset: var(--wa-focus-ring-offset);
}
/* Remove inner borders and handle overlap */
:host([appearance='button'][data-wa-radio-horizontal]:not([data-wa-radio-first])) {
margin-inline-start: calc(-1 * var(--border-width));
}
:host([appearance='button'][data-wa-radio-vertical]:not([data-wa-radio-first])) {
margin-block-start: calc(-1 * var(--border-width));
}
/* Ensure interactive states are visible above adjacent buttons */
:host([appearance='button']:hover),
:host([appearance='button']:state(checked)) {
position: relative;
z-index: 1;
}
:host([appearance='button']:focus-visible) {
z-index: 2;
}

Some files were not shown because too many files have changed in this diff Show More