Compare commits

..

1 Commits

Author SHA1 Message Date
Lea Verou
f9982674c7 [WIP] Add size to badge 2025-02-04 10:58:24 -05:00
71 changed files with 440 additions and 1311 deletions

View File

@@ -13,4 +13,3 @@ package-lock.json
tsconfig.json
cdn
_site
docs/assets/scripts/prism.js

View File

@@ -1 +1 @@
export { default as default } from '../../src/styles/color/palettes-analyzed.js';
export { default as default } from '../../src/styles/color/palettes.js';

View File

@@ -15,8 +15,6 @@
{# Docs styles #}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{% block head %}{% endblock %}
</head>
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->

View File

@@ -1,4 +1,4 @@
<wa-tab-group class="import-stylesheet-code">
<wa-tab-group>
<wa-tab panel="html">In HTML</wa-tab>
<wa-tab panel="css">In CSS</wa-tab>
<wa-tab-panel name="html">

View File

@@ -5,9 +5,6 @@
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">{{ page.data.title }}</span>
{% if pageSubtitle -%}
<div class="wa-caption-s">{{ pageSubtitle }}</div>
{%- endif %}
</wa-card>
</a>
{% endif %}

View File

@@ -1,4 +1,4 @@
{% set paletteId = palette.fileSlug or page.fileSlug %}
{% set paletteId = page.fileSlug %}
{% set tints = [80, 60, 40, 20] %}
{% set width = 20 %}
{% set height = 13 %}

View File

@@ -1,24 +0,0 @@
{% set themeId = theme.fileSlug %}
<wa-isolate>
<template>
<link rel="stylesheet" href="/dist/styles/utilities.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/color.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
<div class="theme-color-icon wa-theme-{{ themeId }}">
<div class="wa-brand wa-accent">A</div>
<div class="wa-brand wa-outlined">A</div>
<div class="wa-brand wa-filled">A</div>
<div class="wa-brand wa-plain">A</div>
{# <div class="wa-danger wa-outlined wa-filled"><wa-icon slot="icon" name="circle-exclamation" variant="regular"></wa-icon></div> #}
<div class="wa-neutral wa-accent">A</div>
<div class="wa-neutral wa-outlined">A</div>
<div class="wa-neutral wa-filled">A</div>
<div class="wa-neutral wa-plain">A</div>
{# <div class="wa-warning wa-outlined wa-filled"><wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon></div> #}
</div>
</template>
</wa-isolate>

View File

@@ -1,16 +0,0 @@
{% set themeId = theme.fileSlug %}
<wa-isolate>
<template>
<link rel="stylesheet" href="/dist/styles/native/content.css">
<link rel="stylesheet" href="/dist/styles/native/blockquote.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ page.fileSlug or 'default' }}.css">
<link rel="stylesheet" href="/dist/styles/themes/{{ themeId }}/typography.css">
<link rel="stylesheet" href="/assets/styles/theme-icons.css">
<div class="theme-typography-icon wa-theme-{{ themeId }}" data-no-outline data-no-anchor role="presentation">
<h3>Title</h3>
<p>Body text</p>
</div>
</template>
</wa-isolate>

View File

@@ -93,7 +93,7 @@
</td>
</tr>
<tr>
<th><code>outlined</code></th>
<th class="test-failure"><code>outlined</code></th>
<td>
<div class="wa-cluster wa-gap-2xs">
<wa-badge variant="brand" appearance="outlined">Brand</wa-badge>
@@ -495,7 +495,7 @@
</td>
</tr>
<tr>
<th><code>outlined</code></th>
<th class="test-failure"><code>outlined</code></th>
<td>
<div class="wa-grid wa-gap-2xs">
<wa-callout variant="brand" appearance="outlined">
@@ -696,7 +696,7 @@
</td>
</tr>
<tr>
<th><code>outlined</code></th>
<th class="test-failure"><code>outlined</code></th>
<td>
<div class="wa-cluster wa-gap-2xs">
<wa-tag variant="brand" appearance="outlined">Brand</wa-tag>

View File

@@ -15,7 +15,6 @@
<thead>
<tr>
<th></th>
<th class="core-column">Core tint</th>
{% for tint in tints -%}
<th>{{ tint }}</th>
{%- endfor %}
@@ -24,12 +23,6 @@
{% for hue in hues -%}
<tr>
<th>{{ hue | capitalize }}</th>
<td class="core-column">
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}); color: var(--wa-color-{{ hue }}-{{ '05' if palettes[paletteId][hue].maxChromaTint > 60 else '95' }});">
{{ palettes[paletteId][hue].maxChromaTint }}
<wa-copy-button value="--wa-color-{{ hue }}" copy-label="--wa-color-{{ hue }}"></wa-copy-button>
</div>
</td>
{% for tint in tints -%}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint }})">

View File

@@ -4,143 +4,100 @@
{% extends '../_includes/base.njk' %}
{% block head %}
<script>
globalThis.wa_data ??= {};
wa_data.baseTheme = "{{ page.fileSlug }}";
wa_data.themes = {
{% for theme in collections.theme -%}
"{{ theme.fileSlug }}": {
"title": "{{ theme.data.title }}",
"palette": "{{ theme.data.palette }}",
"brand": "{{ theme.data.brand }}"
},
{% endfor %}
};
wa_data.palettes = {
{% for palette in collections.palette -%}
"{{ palette.fileSlug }}": {
"title": "{{ palette.data.title }}",
},
{% endfor %}
};
</script>
<link href="{{ page.url }}../remix.css" rel="stylesheet">
<script src="{{ page.url }}../remix.js" type="module"></script>
{% endblock %}
{% block header %}
<iframe src='{{ page.url }}demo.html' id="demo"></iframe>
<wa-details id="mix_and_match" class="wa-gap-m" >
<h4 slot="summary" data-no-anchor data-no-outline id="remix">
<wa-icon name="arrows-rotate"></wa-icon>
Remix this theme
<wa-icon id="what-is-remixing" href="#remixing" name="circle-question" slot="suffix" variant="regular"></wa-icon>
<wa-tooltip for="what-is-remixing">Customize this theme by changing its colors and/or remixing it with design elements from other themes!</wa-tooltip>
</h4>
<wa-select name="colors" label="Colors from…" value="" clearable>
<p id="mix_and_match" class="wa-gap-m">
<strong>
<wa-icon name="merge" slot="prefix"></wa-icon>
Remix
<wa-icon-button href="#remixing" name="circle-question" slot="suffix" variant="regular" label="How to use?"></wa-icon-button>
</strong>
<wa-select name="colors" label="Colors from…" size="small">
<wa-icon name="palette" slot="prefix" variant="regular"></wa-icon>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for theme in collections.theme | sort %}
{% set currentTheme = theme.fileSlug == page.fileSlug %}
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/theme-color.njk" %}
</div>
<span class="page-name">
{{ theme.data.title }}
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% if theme.fileSlug !== page.fileSlug %}
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
<wa-select name="palette" label="Palette" clearable>
<wa-select name="palette" label="Palette" size="small">
<wa-icon name="swatchbook" slot="prefix" variant="regular"></wa-icon>
{% set defaultPalette = palette %}
{% for palette in collections.palette | sort %}
{% set currentPalette = palette.fileSlug == defaultPalette %}
<wa-option label="{{ palette.data.title }}" value="{{ palette.fileSlug if not currentPalette }}" {{ (palette.fileSlug if currentPalette) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (palette.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">
{{ palette.data.title }}
{% if palette.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentPalette %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% endfor %}
{% set palette = defaultPalette %}
</wa-select>
<wa-select name="brand" label="Brand color" value="" clearable>
<div class="selected-swatch" slot="prefix"></div>
{% for hue in hues %}
{% set currentBrand = hue == brand %}
<wa-option label="{{ hue | capitalize }}" value="{{ hue if not currentBrand }}" {{ (hue if currentBrand) | attr('data-id') }} style="--color: var(--wa-color-{{ hue }})">
{{ hue | capitalize }}
{% if currentBrand %}<wa-badge variant="neutral" appearance="outlined">Theme default</wa-badge>{% endif %}
</wa-option>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for p in collections.palette | sort %}
{% if p.fileSlug !== palette %}
<wa-option value="{{ p.fileSlug }}">{{ p.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
<wa-select name="typography" label="Typography from…" clearable>
<wa-select name="typography" label="Typography from…" size="small">
<wa-icon name="font-case" slot="prefix"></wa-icon>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for theme in collections.theme | sort %}
{% set currentTheme = theme.fileSlug == page.fileSlug %}
<wa-option label="{{ theme.data.title }}" value="{{ theme.fileSlug if not currentTheme }}" {{ (theme.fileSlug if currentTheme) | attr('data-id') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/theme-typography.njk" %}
</div>
<span class="page-name">
{{ theme.data.title }}
{% if theme.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% if currentTheme %}<wa-badge variant="neutral" appearance="outlined">This theme</wa-badge>{% endif %}
</span>
</wa-card>
</wa-option>
{% if theme.fileSlug !== page.fileSlug %}
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
</wa-details>
<h2>Color</h2>
</p>
<script>
document.querySelector('#mix_and_match').addEventListener('change', function(event) {
let selects = document.querySelectorAll('#mix_and_match wa-select');
let url = new URL(demo.src);
for (let select of selects) {
url.searchParams.set(select.name, select.value);
}
demo.src = url;
});
</script>
<h2>Default Color Palette</h2>
{% set paletteURL = '/docs/palettes/' + palette + '/' %}
{% set themePage = page %}
{% set page = paletteURL | getCollectionItemFromUrl %}
<div class="index-grid">
{% set themePage = page %}
{% set page = paletteURL | getCollectionItemFromUrl %}
{% set pageSubtitle = "Default color palette" %}
{% include 'page-card.njk' %}
{% set page = themePage %}
<wa-card style="--header-background: var(--wa-color-{{ brand }})" class="wa-palette-{{ palette }}">
<div slot="header"></div>
<div class="page-name">{{ brand | capitalize }}</div>
<div class="wa-caption-s">Default brand color</div>
</wa-card>
{% include 'page-card.njk' %}
</div>
{% set page = themePage %}
{% endblock %}
{% block afterContent %}
<h2 id="usage">How to use this theme</h2>
{% markdown %}
## How to use this theme
You can import this theme from the Web Awesome CDN.
{% set stylesheet = 'styles/themes/' + page.fileSlug + '.css' %}
{% include 'import-stylesheet-code.md.njk' %}
### Remixing { #remixing }
If you want to combine the **colors** from this theme with another theme, you can import this CSS file *after* the other themes CSS file:
{% set stylesheet = 'styles/themes/' + page.fileSlug + '/color.css' %}
{% include 'import-stylesheet-code.md.njk' %}
To use the **typography** from this theme with another theme, you can import this CSS file *after* the other themes CSS file:
{% set stylesheet = 'styles/themes/' + page.fileSlug + '/typography.css' %}
{% include 'import-stylesheet-code.md.njk' %}
<wa-callout variant="warning">
<wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon>
Please note that not all combinations will look good — once youre mixing and matching, youre on your own!
</wa-callout>
## Dark mode
To activate the dark color scheme of the theme on any element and its contents, apply the class `wa-dark` to it.

View File

@@ -37,8 +37,7 @@ export function anchorHeadingsPlugin(options = {}) {
}
// Look for headings
let selector = `:is(${options.headingSelector}):not([data-no-anchor], [data-no-anchor] *)`;
container.querySelectorAll(selector).forEach(heading => {
container.querySelectorAll(options.headingSelector).forEach(heading => {
const hasAnchor = heading.querySelector('a');
const existingId = heading.getAttribute('id');
const clone = parse(heading.outerHTML);

File diff suppressed because one or more lines are too long

View File

@@ -1,37 +0,0 @@
/**
* Get import code for remixed themes.
*/
export const urls = {
colors: id => `styles/themes/${id}/color.css`,
palette: id => `styles/color/${id}.css`,
brand: id => `styles/brand/${id}.css`,
typography: id => `styles/themes/${id}/typography.css`,
};
function getImport(url, options = {}) {
let { language = 'html', cdnUrl = '/dist/', attributes } = options;
url = cdnUrl + url;
if (language === 'css') {
return `@import url('${url}');`;
} else {
attributes = attributes ? ` ${attributes}` : '';
return `<link rel="stylesheet" href="${url}"${attributes} />`;
}
}
export function getCode(base, params, options) {
let ret = [];
if (base) {
ret.push(`styles/themes/${base}.css`);
}
ret.push(
...Object.entries(params)
.filter(([aspect, id]) => Boolean(id))
.map(([aspect, id]) => urls[aspect](id)),
);
return ret.map(url => getImport(url, options)).join('\n');
}

View File

@@ -360,7 +360,7 @@ wa-page > main:has(> .index-grid) {
}
&::part(header) {
background-color: var(--header-background, var(--wa-color-neutral-fill-quiet));
background-color: var(--wa-color-neutral-fill-quiet);
border-bottom: none;
display: flex;
align-items: center;
@@ -437,7 +437,6 @@ table.colors {
padding-block: 0;
}
}
tbody {
tr {
border: none;
@@ -457,10 +456,6 @@ table.colors {
padding-block: var(--wa-space-s);
}
}
.core-column {
padding-inline-end: var(--wa-space-xl);
}
}
/* Layout Examples */
@@ -543,4 +538,23 @@ table.colors {
height: 65vh;
max-height: 21lh;
}
#mix_and_match {
strong {
display: flex;
align-items: center;
gap: var(--wa-space-2xs);
margin-top: 1.2em;
}
wa-select::part(label) {
margin-block-end: 0;
}
wa-select[value='']::part(display-input),
wa-option[value=''] {
font-style: italic;
color: var(--wa-color-text-quiet);
}
}
}

View File

@@ -1,34 +0,0 @@
.theme-color-icon {
display: grid;
gap: var(--wa-space-xs);
grid-template-columns: repeat(4, auto);
div {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-radius: var(--wa-border-radius-m);
background-color: var(--background-color);
border: var(--wa-border-width-s) var(--wa-border-style) var(--border-color);
padding: var(--wa-space-2xs) var(--wa-space-xs);
color: var(--text-color);
font-weight: var(--wa-font-weight-semibold);
&.plain {
font-weight: var(--wa-font-weight-bold);
}
}
}
.theme-typography-icon {
display: flex;
flex-direction: column;
gap: var(--wa-space-xs);
h3,
p {
margin-block: 0;
padding: 0;
}
}

View File

@@ -77,6 +77,16 @@ Use the `pill` attribute to give badges rounded edges.
<wa-badge variant="danger" pill>Danger</wa-badge>
```
### Sizes
Use the `size` attribute to change a badge's size.
```html {.example}
<wa-badge size="small">Small</wa-badge>
<wa-badge size="medium">Medium</wa-badge>
<wa-badge size="large">Large</wa-badge>
```
### Pulsating Badges
Use the `pulse` attribute to draw attention to the badge with a subtle animation.

View File

@@ -9,10 +9,6 @@ icon: copy-button
<wa-copy-button value="Web Awesome rocks!"></wa-copy-button>
```
:::info
Copy buttons use the browser's [`clipboard.writeText()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) method, which requires a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts) (HTTPS) in most browsers.
:::
## Examples
### Custom Labels

View File

@@ -130,15 +130,6 @@ Note that multi-select options may wrap, causing the control to expand verticall
Use the `value` attribute to set the initial selection.
```html {.example}
<wa-select value="option-1">
<wa-option value="option-1">Option 1</wa-option>
<wa-option value="option-2">Option 2</wa-option>
<wa-option value="option-3">Option 3</wa-option>
<wa-option value="option-4">Option 4</wa-option>
</wa-select>
```
When using `multiple`, the `value` _attribute_ uses space-delimited values to select more than one option. Because of this, `<wa-option>` values cannot contain spaces. If you're accessing the `value` _property_ through Javascript, it will be an array.
```html {.example}
@@ -303,7 +294,7 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
return `
<wa-tag removable>
<wa-icon name="${name}" style="padding-inline-end: .5rem;"></wa-icon>
${option.label}
${option.getTextLabel()}
</wa-tag>
`;
};

View File

@@ -3,7 +3,6 @@
"tags": ["palettes", "palette"],
"eleventyComputed": {
"snippet": ".wa-palette-{{ page.fileSlug }}",
"icon": "palette",
"file": "styles/color/{{ page.fileSlug }}.css"
"icon": "palette"
}
}

View File

@@ -4,5 +4,4 @@ description: Energetic and tactile, always in motion.
isPro: true
tags: pro
palette: rudimentary
brand: green
---

View File

@@ -3,5 +3,4 @@ title: Awesome
description: Punchy and vibrant, the rockstar of themes.
order: 0.2
palette: bright
brand: blue
---

View File

@@ -4,5 +4,4 @@ description: Sharp, square, and unapologetically bold.
isPro: true
tags: pro
palette: default
brand: blue
---

View File

@@ -3,5 +3,4 @@ title: Default
description: Your trusty companion, like a perfectly broken-in pair of jeans.
order: 0
palette: default
brand: blue
---

View File

@@ -11,6 +11,7 @@ eleventyComputed:
forceTheme: "{{ theme.fileSlug }}"
---
<link rel="stylesheet" href="/dist/styles/themes/{{ theme.fileSlug }}.css" />
<link rel="stylesheet" href="/docs/themes/showcase.css" />
{% set content %}
@@ -33,45 +34,35 @@ eleventyComputed:
</div>
</wa-image-comparer>
<script type="module">
import { getCode, urls as stylesheetURLs } from "/assets/scripts/remix.js";
<script>
function updateTheme() {
let params = new URLSearchParams(window.location.search);
params = Object.fromEntries(params.entries());
const docsURLs = {
colors: '/docs/themes/',
palette: '/docs/palettes/',
typography: '/docs/themes/'
let script = document.currentScript;
const stylesheetURLs = {
colors: id => `/dist/styles/themes/${ id }/color.css`,
palette: id => `/dist/styles/color/${ id }.css`,
typography: id => `/dist/styles/themes/${ id }/typography.css`
};
const icons = {
colors: 'palette',
palette: 'swatchbook',
brand: 'droplet',
typography: 'font-case'
};
}
for (let link of document.querySelectorAll('link.mix-and-match')) {
link.remove();
}
let msgs = [];
let code = getCode("{{ theme.fileSlug }}", params, {attributes: 'class="mix-and-match"'});
document.head.insertAdjacentHTML('beforeend', code);
for (let name in stylesheetURLs) {
let override = params[name];
if (override) {
let docsURL = docsURLs[name] ? docsURLs[name] + override + '/' : '';
let title = override.replace(/^[a-z]/g, c => c.toUpperCase());
if (docsURL) {
title = `<a href="${ docsURL }">${ title }</a>`;
}
if (params.get(name)) {
let url = stylesheetURLs[name](params.get(name));
script.insertAdjacentHTML('afterend', `<link rel="stylesheet" href="${ url }" class="mix-and-match" />`);
let docsURL = (name === 'palette' ? '/docs/palettes/' : '/docs/themes/') + params.get(name) + '/';
let title = params.get(name).replace(/^[a-z]/g, c => c.toUpperCase());
let icon = icons[name];
msgs.push(`<wa-icon name="${icon}" variant="regular"></wa-icon> ${ title }`);
msgs.push(`<wa-icon name="${icon}" variant="regular"></wa-icon> <a href="${ docsURL }">${ title }</a>`);
}
}
@@ -79,7 +70,7 @@ function updateTheme() {
p.hidden = msgs.length === 0;
if (msgs.length) {
let icon =
p.innerHTML = `<strong><wa-icon name="arrows-rotate"></wa-icon> Remixed</strong> ` + msgs.map(msg => `<wa-badge appearance=outlined>
p.innerHTML = `<strong><wa-icon name="merge"></wa-icon> Remixed</strong> ` + msgs.map(msg => `<wa-badge appearance=outlined>
${ msg }</wa-badge>`).join(' ');
}
}

View File

@@ -4,5 +4,4 @@ description: Bustling with plenty of luster and shine.
isPro: true
tags: pro
palette: elegant
brand: indigo
---

View File

@@ -4,7 +4,6 @@ description: Digital design inspired by the real world.
isPro: true
tags: pro
palette: mild
brand: indigo
---
Set the page theme to "{{ title }}" from the top right to preview the following examples.

View File

@@ -4,5 +4,4 @@ description: Cheerful and engaging, like a playground on screen.
isPro: true
tags: pro
palette: rudimentary
brand: purple
---

View File

@@ -4,5 +4,4 @@ description: The ultimate in sophistication and style.
isPro: true
tags: pro
palette: anodized
brand: cyan
---

View File

@@ -1,127 +0,0 @@
#mix_and_match {
margin-block-end: var(--wa-space-2xl);
&::part(content) {
display: flex;
gap: var(--wa-space-xl);
padding-block-start: var(--wa-space-m);
}
> [slot='summary'] {
margin: 0;
wa-icon:first-of-type {
vertical-align: -0.15em;
color: var(--wa-color-text-quiet);
}
wa-icon#what-is-remixing {
vertical-align: -0.1em;
font-size: var(--wa-font-size-s);
color: var(--wa-color-text-quiet);
}
}
wa-select {
&::part(label) {
margin-block-end: 0;
}
}
wa-select:has(> wa-option > wa-card) {
&::part(listbox) {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
width: min(90vw, 800px);
}
&:state(blank)::part(display-input) {
font-style: italic;
color: var(--wa-color-text-quiet);
}
}
wa-option:has(> wa-card) {
position: relative;
padding: var(--wa-space-smaller);
&::part(checked-icon) {
position: absolute;
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;
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
font-size: var(--wa-font-size-xs);
}
wa-card {
--spacing: var(--wa-space-smaller);
&::part(body) {
background: var(--wa-color-neutral-fill-quiet);
padding-block: var(--wa-space-s);
}
}
&:state(current),
&:state(hover),
&:state(selected),
&:hover {
background: transparent;
}
&:hover {
wa-card {
border-color: var(--wa-color-brand-border-loud);
box-shadow: 0 0 0 var(--wa-border-width-m) var(--wa-color-brand-border-normal);
}
}
&[aria-selected='true'] {
wa-card {
--border-color: var(--wa-color-brand-border-loud);
box-shadow: 0 0 0 var(--wa-border-width-m) var(--wa-color-brand-border-loud);
&::part(body) {
background: var(--wa-color-brand-fill-quiet);
}
}
}
}
.selected-swatch,
wa-select[name='brand'] wa-option::before {
content: '';
display: inline-block;
width: 1.2em;
aspect-ratio: 1;
flex: none;
border-radius: var(--wa-border-radius-m);
background: var(--color);
border: 1px solid var(--wa-color-surface-default);
}
wa-select[name='brand'] wa-option {
white-space: nowrap;
&::before {
width: 1em;
margin-inline: var(--wa-space-xs);
}
&::part(checked-icon) {
order: 2;
}
}
}
#test_select wa-option:state(selected) {
outline: 2px solid red;
background: yellow;
}

View File

@@ -1,171 +0,0 @@
import { getCode } from '/assets/scripts/remix.js';
await Promise.all(['wa-select', 'wa-option', 'wa-details'].map(tag => customElements.whenDefined(tag)));
globalThis.Prism = globalThis.Prism || {};
globalThis.Prism.manual = true;
await import('/assets/scripts/prism.js');
Prism.plugins.customClass.prefix('code-');
const cdnUrl = document.documentElement.dataset.cdnUrl;
const domChange = document.startViewTransition ? document.startViewTransition.bind(document) : fn => fn();
let selects, data, codeSnippets;
let computed = {
get isRemixed() {
return Object.values(data.params).filter(Boolean).length > 0;
},
get palette() {
return data.params.palette || data.defaultParams.palette;
},
get brand() {
return data.params.brand || data.defaultParams.brand;
},
};
function selectsChanged(event) {
data.params[event.target.name] = event.target.value;
render(event.target.name);
}
function init() {
selects = Object.fromEntries(
[...document.querySelectorAll('#mix_and_match wa-select')].map(select => [select.getAttribute('name'), select]),
);
codeSnippets = document.querySelector('#usage ~ wa-tab-group.import-stylesheet-code:first-of-type');
codeSnippets = {
html: codeSnippets.querySelector('code.language-html'),
css: codeSnippets.querySelector('code.language-css'),
};
data = {
baseTheme: wa_data.baseTheme,
themes: wa_data.themes,
palettes: wa_data.palettes,
defaultParams: {
colors: '',
get palette() {
let colors = data.params.colors || data.baseTheme;
return data.themes[colors].palette;
},
get brand() {
let colors = data.params.colors || data.baseTheme;
return data.themes[colors].brand;
},
typography: '',
},
params: { colors: '', palette: '', brand: '', typography: '' },
urlParams: new URLSearchParams(location.search),
};
// Read URL params and apply them. This facilitates permalinks.
if (location.search) {
for (let aspect in data.params) {
if (data.urlParams.has(aspect)) {
data.params[aspect] = data.urlParams.get(aspect);
}
}
}
if (computed.isRemixed) {
// Start with the remixing UI open if the theme has been remixed
mix_and_match.setAttribute('open', '');
mix_and_match.open = true;
}
for (let name in selects) {
selects[name].addEventListener('change', selectsChanged);
}
Promise.all(Object.values(selects).map(select => select.updateComplete)).then(() => render());
return { selects, codeSnippets, data, computed, render };
}
globalThis.remixApp = init();
// Async load CSS for other themes *before* current theme stylesheet
let themeStylesheet = document.querySelector('#theme-stylesheet');
for (const theme in data.themes) {
themeStylesheet.insertAdjacentHTML(
'beforebegin',
`<link rel="preload" as="style" href="/dist/styles/themes/${theme}/color.css" onload="this.rel = 'stylesheet'" />
<link rel="preload" as="style" href="/dist/styles/themes/${theme}/typography.css" onload="this.rel = 'stylesheet'" />`,
);
}
for (const palette in data.palettes) {
themeStylesheet.insertAdjacentHTML(
'beforebegin',
`<link rel="preload" as="style" href="/dist/styles/color/${palette}.css" onload="this.rel = 'stylesheet'" />`,
);
}
function setDefault(select, value) {
let oldDefaultOption = select.querySelector(`wa-option[value=""]:not([data-id="${value}"])`);
let newDefaultOption = select.querySelector(`wa-option[value="${value}"]`);
if (oldDefaultOption) {
oldDefaultOption.value = oldDefaultOption.dataset.id;
}
if (newDefaultOption) {
newDefaultOption.dataset.id ??= newDefaultOption.value;
newDefaultOption.value = '';
}
}
function render(changedAspect) {
let url = new URL(demo.src);
if (!changedAspect || changedAspect === 'colors') {
// Update the default palette when the theme colors change to the default palette of that theme
setDefault(selects.palette, data.defaultParams.palette);
setDefault(selects.brand, data.defaultParams.brand);
}
let brand = data.params.brand || data.defaultParams.brand;
selects.brand.style.setProperty('--color', `var(--wa-color-${brand})`);
selects.brand.className = `wa-palette-${computed.palette}`;
for (let aspect in data.params) {
let value = data.params[aspect];
if (value) {
data.urlParams.set(aspect, value);
} else {
data.urlParams.delete(aspect);
}
selects[aspect].value = value;
}
// Update demo URL
domChange(() => {
url.search = data.urlParams;
demo.src = url;
return new Promise(resolve => (demo.onload = resolve));
});
// Update page URL. If theres already a search, replace it.
// We dont want to clog the users history while they iterate
let historyAction = location.search ? 'replaceState' : 'pushState';
history[historyAction](null, '', `?${data.urlParams}`);
// Update code snippets
for (let language in codeSnippets) {
let codeSnippet = codeSnippets[language];
let copyButton = codeSnippet.previousElementSibling;
let code = getCode(data.baseTheme, data.params, { language, cdnUrl });
codeSnippet.textContent = code;
copyButton.value = code;
Prism.highlightElement(codeSnippet);
}
}
addEventListener('turbo:render', event => {
remixApp = init();
});

View File

@@ -14,18 +14,7 @@ body,
color: var(--wa-color-text-quiet);
wa-icon {
vertical-align: -0.15em;
}
> strong {
margin-inline-end: var(--wa-space-2xs);
}
wa-badge {
> a {
text-decoration: none;
color: inherit;
}
vertical-align: middle;
}
}

View File

@@ -4,5 +4,4 @@ description: Like a bird in flight, guiding you from there to here.
isPro: true
tags: pro
palette: vogue
brand: indigo
---

View File

@@ -1,9 +1,5 @@
{
"layout": "theme.njk",
"wide": true,
"tags": ["themes", "theme"],
"brand": "blue",
"eleventyComputed": {
"file": "styles/themes/{{ page.fileSlug }}.css"
}
"tags": ["themes", "theme"]
}

View File

@@ -1,9 +1,10 @@
import { html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import nativeStyles from '../../styles/native/badge.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 './badge.css';
/**
* @summary Badges are used to draw attention and display statuses or counts.
@@ -24,7 +25,7 @@ import styles from './badge.css';
*/
@customElement('wa-badge')
export default class WaBadge extends WebAwesomeElement {
static shadowStyle = [variantStyles, appearanceStyles, styles];
static shadowStyle = [variantStyles, sizeStyles, appearanceStyles, nativeStyles];
/** The badge's theme variant. Defaults to `brand` if not within another element with a variant. */
@property({ reflect: true, initial: 'brand' }) variant:

View File

@@ -5,7 +5,6 @@
--spacing: var(--wa-space);
--border-width: var(--wa-panel-border-width);
--border-color: var(--wa-color-surface-border);
--border-radius: var(--wa-panel-border-radius);
--inner-border-radius: calc(var(--border-radius) - var(--border-width));
@@ -13,7 +12,7 @@
display: flex;
flex-direction: column;
background-color: var(--wa-color-surface-default);
border-color: var(--border-color);
border-color: var(--wa-color-surface-border);
border-radius: var(--border-radius);
border-style: var(--wa-panel-border-style);
box-shadow: var(--wa-shadow-s);
@@ -21,20 +20,12 @@
color: var(--wa-color-text-normal);
}
/* Take care of top and bottom radii */
.image,
:host(:not([with-image])) .header,
:host(:not([with-image], [with-header])) .body {
:host(:not([with-image])) .header {
border-start-start-radius: var(--inner-border-radius);
border-start-end-radius: var(--inner-border-radius);
}
:host(:not([with-footer])) .body,
.footer {
border-end-start-radius: var(--inner-border-radius);
border-end-end-radius: var(--inner-border-radius);
}
.image {
display: flex;
@@ -48,9 +39,7 @@
.header {
display: block;
border-block-end-style: inherit;
border-block-end-color: var(--border-color);
border-block-end-width: var(--border-width);
border-bottom: inherit;
padding: calc(var(--spacing) / 2) var(--spacing);
}
@@ -61,9 +50,9 @@
.footer {
display: block;
border-block-start-style: inherit;
border-block-start-color: var(--border-color);
border-block-start-width: var(--border-width);
border-top: inherit;
border-end-start-radius: var(--inner-border-radius);
border-end-end-radius: var(--inner-border-radius);
padding: var(--spacing);
}

View File

@@ -21,10 +21,9 @@ import styles from './card.css';
* @csspart body - The container that wraps the card's main content.
* @csspart footer - The container that wraps the card's footer.
*
* @cssproperty [--border-radius=var(--wa-panel-border-radius)] - The radius for the card's corners. Expects a single value.
* @cssproperty [--border-color=var(--wa-color-surface-border)] - The color of the card's borders, including inner borders. Expects a single value.
* @cssproperty [--border-width=var(--wa-panel-border-width)] - The width of the card's borders. Expects a single value.
* @cssproperty [--spacing=var(--wa-space)] - The amount of space around and between sections of the card. Expects a single value.
* @cssproperty --border-radius - The radius for the card's corners. Expects a single value. Defaults to `var(--wa-panel-border-radius)`.
* @cssproperty --border-width - The width of the card's borders. Expects a single value. Defaults to `var(--wa-panel-border-width)`.
* @cssproperty --spacing - The amount of space around and between sections of the card. Expects a single value. Defaults to `var(--wa-space)`.
*/
@customElement('wa-card')
export default class WaCard extends WebAwesomeElement {

View File

@@ -1,7 +1,6 @@
import { html } from 'lit';
import { customElement, property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import recursiveQSA from '../../internal/recursive-qsa.js';
import { HasSlotController, getInnerHTML } from '../../internal/slot.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import '../icon/icon.js';
@@ -326,6 +325,25 @@ function absolutizeURLs(root: Element | DocumentFragment, base = location.href)
}
}
/**
* Get elements that match a selector within an elements shadow tree
* and any parent shadow trees, all the way up to the light DOM
* @param selector
* @param node - The node to start the search from
*/
function recursiveQSA(selector: string, node: Node) {
const ret: Element[] = [];
for (let root = node; root.nodeType !== Node.DOCUMENT_NODE; ) {
root = root.getRootNode();
const elements = (root as ShadowRoot | Document).querySelectorAll(selector);
ret.push(...elements);
}
return ret;
}
function dedent(code: string) {
// Remove blank lines at the start and end
code = code.replace(/^\s*\n|\n\s*$/g, '');

View File

@@ -1,48 +0,0 @@
import { customElement, property } from 'lit/decorators.js';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import recursiveQSA from '../../internal/recursive-qsa.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
/**
* @summary Render a piece of code in shadow DOM. An alternative to DSD that plays nicely with DOM operations like cloning etc.
* @documentation https://backers.webawesome.com/docs/components/isolate
* @status experimental
* @since 3.0
*
*/
@customElement('wa-isolate')
export default class WaIsolate extends WebAwesomeElement {
/** Includes resources and other elements from the surrounding page */
@property({ reflect: true }) include?: string;
render() {
return unsafeHTML(this.getShadowHTML());
}
// TODO memoize this and only update if:
// - this.include changes
// - elements have been added/removed that match the selector
// - Element contents have changed
private getShadowHTML(): string {
let html = '';
if (this.ownerDocument) {
if (this.include) {
let includedElements = recursiveQSA(this.include, this);
html += includedElements.map(el => el.outerHTML).join('\n');
}
// Get template elements from the light DOM
const templates = Array.from(this.querySelectorAll(':scope > template'));
html += templates.map(template => template.innerHTML).join('\n');
}
return html;
}
}
declare global {
interface HTMLElementTagNameMap {
'wa-isolate': WaIsolate;
}
}

View File

@@ -60,16 +60,9 @@ describe('<wa-menu-item>', () => {
});
});
it('defaultLabel should return a text label', async () => {
it('should return a text label when calling getTextLabel()', async () => {
const el = await fixture<WaMenuItem>(html` <wa-menu-item>Test</wa-menu-item> `);
expect(el.defaultLabel).to.equal('Test');
expect(el.label).to.equal('Test');
});
it('label attribute should override default label', async () => {
const el = await fixture<WaMenuItem>(html` <wa-menu-item label="Manual label">Text content</wa-menu-item> `);
expect(el.defaultLabel).to.equal('Text content');
expect(el.label).to.equal('Manual label');
expect(el.getTextLabel()).to.equal('Test');
});
it('should emit the slotchange event when the label changes', async () => {
@@ -114,7 +107,7 @@ describe('<wa-menu-item>', () => {
expect(submenuSlot.hidden).to.be.true;
});
it('should render a wa-popup if the slot="submenu" attribute is present', async () => {
it('should render an wa-popup if the slot="submenu" attribute is present', async () => {
const menu = await fixture<WaMenuItem>(html`
<wa-menu>
<wa-menu-item id="test">

View File

@@ -1,8 +1,9 @@
import type { PropertyValues } from 'lit';
import { html } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { customElement, property, query } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import getText from '../../internal/get-text.js';
import { getTextContent } from '../../internal/slot.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import { LocalizeController } from '../../utilities/localize.js';
import '../icon/icon.js';
@@ -42,6 +43,7 @@ import { SubmenuController } from './submenu-controller.js';
export default class WaMenuItem extends WebAwesomeElement {
static shadowStyle = styles;
private cachedTextLabel: string;
private readonly localize = new LocalizeController(this);
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
@@ -62,36 +64,6 @@ export default class WaMenuItem extends WebAwesomeElement {
/** Draws the menu item in a disabled state, preventing selection. */
@property({ type: Boolean, reflect: true }) disabled = false;
_label: string = '';
/**
* The options plain text label.
* Usually automatically generated, but can be useful to provide manually for cases involving complex content.
*/
@property()
set label(value) {
const oldValue = this._label;
this._label = value || '';
if (this._label !== oldValue) {
this.requestUpdate('label', oldValue);
}
}
get label(): string {
if (this._label) {
return this._label;
}
if (!this.defaultLabel) {
this.updateDefaultLabel();
}
return this.defaultLabel;
}
/** The default label, generated from the element contents. Will be equal to `label` in most cases. */
@state() defaultLabel = '';
/**
* Used for SSR purposes. If true, will render a ">" caret icon for showing that it has a submenu, but will be non-interactive.
*/
@@ -103,7 +75,6 @@ export default class WaMenuItem extends WebAwesomeElement {
super.connectedCallback();
this.addEventListener('click', this.handleHostClick);
this.addEventListener('mouseover', this.handleMouseOver);
this.updateDefaultLabel();
}
disconnectedCallback() {
@@ -122,10 +93,17 @@ export default class WaMenuItem extends WebAwesomeElement {
}
private handleDefaultSlotChange() {
let labelChanged = this.updateDefaultLabel();
const textLabel = this.getTextLabel();
// Ignore the first time the label is set
if (typeof this.cachedTextLabel === 'undefined') {
this.cachedTextLabel = textLabel;
return;
}
// When the label changes, emit a slotchange event so parent controls see it
if (labelChanged) {
if (textLabel !== this.cachedTextLabel) {
this.cachedTextLabel = textLabel;
/** @internal - prevent the CEM from recording this event */
this.dispatchEvent(new Event('slotchange', { bubbles: true, composed: false, cancelable: false }));
}
@@ -144,48 +122,41 @@ export default class WaMenuItem extends WebAwesomeElement {
event.stopPropagation();
};
updated(changedProperties: PropertyValues<this>) {
if (changedProperties.has('checked')) {
// For proper accessibility, users have to use type="checkbox" to use the checked attribute
if (this.checked && this.type !== 'checkbox') {
this.checked = false;
return;
}
// Only checkbox types can receive the aria-checked attribute
if (this.type === 'checkbox') {
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
} else {
this.removeAttribute('aria-checked');
}
@watch('checked')
handleCheckedChange() {
// For proper accessibility, users have to use type="checkbox" to use the checked attribute
if (this.checked && this.type !== 'checkbox') {
this.checked = false;
return;
}
if (changedProperties.has('disabled')) {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
if (changedProperties.has('type')) {
if (this.type === 'checkbox') {
this.setAttribute('role', 'menuitemcheckbox');
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
} else {
this.setAttribute('role', 'menuitem');
this.removeAttribute('aria-checked');
}
// Only checkbox types can receive the aria-checked attribute
if (this.type === 'checkbox') {
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
} else {
this.removeAttribute('aria-checked');
}
}
private updateDefaultLabel() {
let oldValue = this.defaultLabel;
this.defaultLabel = getText(this).trim();
let changed = this.defaultLabel !== oldValue;
@watch('disabled')
handleDisabledChange() {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
if (!this._label && changed) {
// Uses default label, and it has changed
this.requestUpdate('label', oldValue);
@watch('type')
handleTypeChange() {
if (this.type === 'checkbox') {
this.setAttribute('role', 'menuitemcheckbox');
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
} else {
this.setAttribute('role', 'menuitem');
this.removeAttribute('aria-checked');
}
}
return changed;
/** Returns a text label based on the contents of the menu item's default slot. */
getTextLabel() {
return getTextContent(this.defaultSlot);
}
isSubmenu() {

View File

@@ -8,7 +8,13 @@
color: var(--wa-color-text-normal);
-webkit-user-select: none;
user-select: none;
}
:host(:focus) {
outline: none;
}
.option {
position: relative;
display: flex;
align-items: center;
@@ -19,23 +25,19 @@
cursor: pointer;
}
:host(:focus) {
outline: none;
}
:host(:not([disabled], :state(current)):is(:state(hover), :hover)) {
:host(:not([disabled])) .option--hover:not(.option--current) {
background-color: var(--background-color-hover);
color: var(--text-color-hover);
}
:host(:state(current)),
:host([disabled]:state(current)) {
.option--current,
:host([disabled]) .option--current {
background-color: var(--background-color-current);
color: var(--text-color-current);
opacity: 1;
}
:host([disabled]) {
:host([disabled]) .option {
outline: none;
opacity: 0.5;
cursor: not-allowed;
@@ -46,7 +48,7 @@
display: inline-block;
}
.check {
.option .check {
flex: 0 0 auto;
display: flex;
align-items: center;
@@ -56,7 +58,7 @@
width: var(--wa-space-xl);
}
:host(:state(selected)) .check {
.option--selected .check {
visibility: visible;
}
@@ -76,7 +78,7 @@
}
@media (forced-colors: active) {
:host(:hover:not([aria-disabled='true'])) {
:host(:hover:not([aria-disabled='true'])) .option {
outline: dashed 1px SelectedItem;
outline-offset: -1px;
}

View File

@@ -23,7 +23,6 @@ describe('<wa-option>', () => {
expect(el.value).to.equal('');
expect(el.disabled).to.be.false;
expect(el.label).to.equal('Test');
expect(el.getAttribute('aria-disabled')).to.equal('false');
});
@@ -45,16 +44,9 @@ describe('<wa-option>', () => {
expect(el.value).to.equal('10');
});
it('defaultLabel should escape HTML', async () => {
it('should escape HTML when calling getTextLabel()', async () => {
const el = await fixture<WaOption>(html` <wa-option><strong>Option</strong></wa-option> `);
expect(el.defaultLabel).to.equal('Option');
expect(el.label).to.equal('Option');
});
it('label attribute should override default label', async () => {
const el = await fixture<WaOption>(html` <wa-option label="Manual label">Text content</wa-option> `);
expect(el.defaultLabel).to.equal('Text content');
expect(el.label).to.equal('Manual label');
expect(el.getTextLabel()).to.equal('Option');
});
});
}

View File

@@ -1,7 +1,7 @@
import type { PropertyValues } from 'lit';
import { html } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import getText from '../../internal/get-text.js';
import { classMap } from 'lit/directives/class-map.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import { LocalizeController } from '../../utilities/localize.js';
import '../icon/icon.js';
@@ -25,13 +25,10 @@ import styles from './option.css';
* @cssproperty --text-color-hover - The label color on hover.
*
* @csspart checked-icon - The checked icon, a `<wa-icon>` element.
* @csspart base - The component's base wrapper.
* @csspart label - The option's label.
* @csspart prefix - The container that wraps the prefix.
* @csspart suffix - The container that wraps the suffix.
*
* @cssstate current - The user has keyed into the option, but hasn't selected it yet (shows a highlight)
* @cssstate selected - The option is selected and has aria-selected="true"
* @cssstate hover - Like `:hover` but works while dragging in Safari
*/
@customElement('wa-option')
export default class WaOption extends WebAwesomeElement {
@@ -43,10 +40,9 @@ export default class WaOption extends WebAwesomeElement {
@query('.label') defaultSlot: HTMLSlotElement;
// Set via the parent select
@state() current = false;
@state() selected = false;
@state() current = false; // the user has keyed into the option, but hasn't selected it yet (shows a highlight)
@state() selected = false; // the option is selected and has aria-selected="true"
@state() hasHover = false; // we need this because Safari doesn't honor :hover styles while dragging
/**
* The option's value. When selected, the containing form control will receive this value. The value must be unique
@@ -58,56 +54,13 @@ export default class WaOption extends WebAwesomeElement {
/** Draws the option in a disabled state, preventing selection. */
@property({ type: Boolean, reflect: true }) disabled = false;
_label: string = '';
/**
* The options plain text label.
* Usually automatically generated, but can be useful to provide manually for cases involving complex content.
*/
@property()
set label(value) {
const oldValue = this._label;
this._label = value || '';
if (this._label !== oldValue) {
this.requestUpdate('label', oldValue);
}
}
get label(): string {
if (this._label) {
return this._label;
}
if (!this.defaultLabel) {
this.updateDefaultLabel();
}
return this.defaultLabel;
}
/** The default label, generated from the element contents. Will be equal to `label` in most cases. */
@state() defaultLabel = '';
connectedCallback() {
super.connectedCallback();
this.setAttribute('role', 'option');
this.setAttribute('aria-selected', 'false');
this.addEventListener('mouseenter', this.handleHover);
this.addEventListener('mouseleave', this.handleHover);
this.updateDefaultLabel();
}
disconnectedCallback(): void {
super.disconnectedCallback();
this.removeEventListener('mouseenter', this.handleHover);
this.removeEventListener('mouseleave', this.handleHover);
}
private handleDefaultSlotChange() {
this.updateDefaultLabel();
if (this.isInitialized) {
// When the label changes, tell the controller to update
customElements.whenDefined('wa-select').then(() => {
@@ -121,75 +74,84 @@ export default class WaOption extends WebAwesomeElement {
}
}
private handleHover = (event: Event) => {
// We need this because Safari doesn't honor :hover styles while dragging
// Testcase: https://codepen.io/leaverou/pen/VYZOOjy
if (event.type === 'mouseenter') {
this.toggleCustomState('hover', true);
} else if (event.type === 'mouseleave') {
this.toggleCustomState('hover', false);
}
};
private handleMouseEnter() {
this.hasHover = true;
}
updated(changedProperties: PropertyValues<this>) {
super.updated(changedProperties);
private handleMouseLeave() {
this.hasHover = false;
}
if (changedProperties.has('disabled')) {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
@watch('disabled')
handleDisabledChange() {
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
}
@watch('selected')
handleSelectedChange() {
this.setAttribute('aria-selected', this.selected ? 'true' : 'false');
}
@watch('value')
handleValueChange() {
// Ensure the value is a string. This ensures the next line doesn't error and allows framework users to pass numbers
// instead of requiring them to cast the value to a string.
if (typeof this.value !== 'string') {
this.value = String(this.value);
}
if (changedProperties.has('selected')) {
this.setAttribute('aria-selected', this.selected ? 'true' : 'false');
this.toggleCustomState('selected', this.selected);
}
if (changedProperties.has('value')) {
// Ensure the value is a string. This ensures the next line doesn't error and allows framework users to pass numbers
// instead of requiring them to cast the value to a string.
if (typeof this.value !== 'string') {
this.value = String(this.value);
}
if (this.value.includes(' ')) {
// eslint-disable-next-line no-console
console.error(`Option values cannot include a space. All spaces have been replaced with underscores.`, this);
this.value = this.value.replace(/ /g, '_');
}
this.handleDefaultSlotChange();
}
if (changedProperties.has('current')) {
this.toggleCustomState('current', this.current);
if (this.value.includes(' ')) {
// eslint-disable-next-line no-console
console.error(`Option values cannot include a space. All spaces have been replaced with underscores.`, this);
this.value = this.value.replace(/ /g, '_');
}
}
private updateDefaultLabel() {
let oldValue = this.defaultLabel;
this.defaultLabel = getText(this).trim();
let changed = this.defaultLabel !== oldValue;
/** Returns a plain text label based on the option's content. */
getTextLabel() {
const nodes = this.childNodes;
let label = '';
if (!this._label && changed) {
// Uses default label, and it has changed
this.requestUpdate('label', oldValue);
}
[...nodes].forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (!(node as HTMLElement).hasAttribute('slot')) {
label += (node as HTMLElement).textContent;
}
}
return changed;
if (node.nodeType === Node.TEXT_NODE) {
label += node.textContent;
}
});
return label.trim();
}
render() {
return html`
<wa-icon
part="checked-icon"
class="check"
name="check"
library="system"
variant="solid"
aria-hidden="true"
></wa-icon>
<slot part="prefix" name="prefix" class="prefix"></slot>
<slot part="label" class="label" @slotchange=${this.handleDefaultSlotChange}></slot>
<slot part="suffix" name="suffix" class="suffix"></slot>
<div
part="base"
class=${classMap({
option: true,
'option--current': this.current,
'option--selected': this.selected,
'option--hover': this.hasHover,
})}
@mouseenter=${this.handleMouseEnter}
@mouseleave=${this.handleMouseLeave}
>
<wa-icon
part="checked-icon"
class="check"
name="check"
library="system"
variant="solid"
aria-hidden="true"
></wa-icon>
<slot part="prefix" name="prefix" class="prefix"></slot>
<slot part="label" class="label" @slotchange=${this.handleDefaultSlotChange}></slot>
<slot part="suffix" name="suffix" class="suffix"></slot>
</div>
`;
}
}

View File

@@ -252,7 +252,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
removable
@wa-remove=${(event: WaRemoveEvent) => this.handleTagRemove(event, option)}
>
${option.label}
${option.getTextLabel()}
</wa-tag>
`;
};
@@ -437,7 +437,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
}
for (const option of allOptions) {
const label = option.label.toLowerCase();
const label = option.getTextLabel().toLowerCase();
if (label.startsWith(this.typeToSelectString)) {
this.setCurrentOption(option);
@@ -642,7 +642,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
} else {
const selectedOption = this.selectedOptions[0];
this.value = selectedOption?.value ?? '';
this.displayLabel = selectedOption?.label ?? '';
this.displayLabel = selectedOption?.getTextLabel?.() ?? '';
}
// Update validity

View File

@@ -1,46 +0,0 @@
/**
* Like textContent, but better:
* - Uses assignedNodes to get text content from slots (and falls back to content if nothing is slotted)
* - Ignores script and style elements
* @param root - One or more nodes to get text content from.
* @param depth - By default, will just return element.textContent for any child elements instead of calling the function recursively.
* Set to a positive integer to recurse that many levels. Generally a tradeoff between performance and accuracy.
* @returns
*/
export default function getText(root: Node | Iterable<Node>, depth = 0): string {
if (!root || !globalThis.Node) {
return '';
}
if (typeof (root as any)[Symbol.iterator] === 'function') {
let nodes = Array.isArray(root) ? root : [...(root as Iterable<Node>)];
return nodes.map(node => getText(node, --depth)).join('');
}
let node = root as Node;
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent ?? '';
}
if (node.nodeType === Node.ELEMENT_NODE) {
let element = node as HTMLElement;
if (element.hasAttribute('slot') || element.matches('style, script')) {
return '';
}
if (element instanceof HTMLSlotElement) {
let assignedNodes = element.assignedNodes({ flatten: true });
if (assignedNodes.length > 0) {
// If no assigned nodes, we still want the slot contents
return getText(assignedNodes, --depth);
}
}
return depth > -1 ? getText(element, --depth) : (element.textContent ?? '');
}
return node.hasChildNodes() ? getText(node.childNodes, --depth) : '';
}

View File

@@ -1,18 +0,0 @@
/**
* Get elements that match a selector within an elements shadow tree
* and any parent shadow trees, all the way up to the light DOM
* @param selector
* @param node - The node to start the search from
*/
export default function recursiveQSA(selector: string, node: Node) {
const ret: Element[] = [];
for (let root = node; root.nodeType !== Node.DOCUMENT_NODE; ) {
root = root.getRootNode();
const elements = (root as ShadowRoot | Document).querySelectorAll(selector);
ret.push(...elements);
}
return ret;
}

View File

@@ -12,11 +12,11 @@ export class HasSlotController implements ReactiveController {
private hasDefaultSlot() {
return [...this.host.childNodes].some(node => {
if (node.nodeType === Node.TEXT_NODE && node.textContent!.trim() !== '') {
if (node.nodeType === node.TEXT_NODE && node.textContent!.trim() !== '') {
return true;
}
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.nodeType === node.ELEMENT_NODE) {
const el = node as HTMLElement;
const tagName = el.tagName.toLowerCase();
@@ -90,3 +90,23 @@ export function getInnerHTML(nodes: Iterable<Node>, callback?: (node: Node) => s
return html;
}
/**
* Given a slot, this function iterates over all of its assigned text nodes and returns the concatenated text as a
* string. This is useful because we can't use slot.textContent as an alternative.
*/
export function getTextContent(slot: HTMLSlotElement | undefined | null): string {
if (!slot) {
return '';
}
const nodes = slot.assignedNodes({ flatten: true });
let text = '';
[...nodes].forEach(node => {
if (node.nodeType === Node.TEXT_NODE) {
text += node.textContent;
}
});
return text;
}

View File

@@ -14,5 +14,4 @@
--wa-color-brand-10: var(--wa-color-blue-10);
--wa-color-brand-05: var(--wa-color-blue-05);
--wa-color-brand: var(--wa-color-blue);
--wa-color-brand-key: var(--wa-color-blue-key);
}

View File

@@ -14,5 +14,4 @@
--wa-color-brand-10: var(--wa-color-cyan-10);
--wa-color-brand-05: var(--wa-color-cyan-05);
--wa-color-brand: var(--wa-color-cyan);
--wa-color-brand-key: var(--wa-color-cyan-key);
}

View File

@@ -1,18 +0,0 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
--wa-color-brand-95: var(--wa-color-gray-95);
--wa-color-brand-90: var(--wa-color-gray-90);
--wa-color-brand-80: var(--wa-color-gray-80);
--wa-color-brand-70: var(--wa-color-gray-70);
--wa-color-brand-60: var(--wa-color-gray-60);
--wa-color-brand-50: var(--wa-color-gray-50);
--wa-color-brand-40: var(--wa-color-gray-40);
--wa-color-brand-30: var(--wa-color-gray-30);
--wa-color-brand-20: var(--wa-color-gray-20);
--wa-color-brand-10: var(--wa-color-gray-10);
--wa-color-brand-05: var(--wa-color-gray-05);
--wa-color-brand: var(--wa-color-gray);
--wa-color-brand-key: var(--wa-color-gray-key);
}

View File

@@ -14,5 +14,4 @@
--wa-color-brand-10: var(--wa-color-green-10);
--wa-color-brand-05: var(--wa-color-green-05);
--wa-color-brand: var(--wa-color-green);
--wa-color-brand-key: var(--wa-color-green-key);
}

View File

@@ -14,5 +14,4 @@
--wa-color-brand-10: var(--wa-color-indigo-10);
--wa-color-brand-05: var(--wa-color-indigo-05);
--wa-color-brand: var(--wa-color-indigo);
--wa-color-brand-key: var(--wa-color-indigo-key);
}

View File

@@ -1,18 +0,0 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
--wa-color-brand-95: var(--wa-color-orange-95);
--wa-color-brand-90: var(--wa-color-orange-90);
--wa-color-brand-80: var(--wa-color-orange-80);
--wa-color-brand-70: var(--wa-color-orange-70);
--wa-color-brand-60: var(--wa-color-orange-60);
--wa-color-brand-50: var(--wa-color-orange-50);
--wa-color-brand-40: var(--wa-color-orange-40);
--wa-color-brand-30: var(--wa-color-orange-30);
--wa-color-brand-20: var(--wa-color-orange-20);
--wa-color-brand-10: var(--wa-color-orange-10);
--wa-color-brand-05: var(--wa-color-orange-05);
--wa-color-brand: var(--wa-color-orange);
--wa-color-brand-key: var(--wa-color-orange-key);
}

View File

@@ -1,18 +0,0 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
--wa-color-brand-95: var(--wa-color-pink-95);
--wa-color-brand-90: var(--wa-color-pink-90);
--wa-color-brand-80: var(--wa-color-pink-80);
--wa-color-brand-70: var(--wa-color-pink-70);
--wa-color-brand-60: var(--wa-color-pink-60);
--wa-color-brand-50: var(--wa-color-pink-50);
--wa-color-brand-40: var(--wa-color-pink-40);
--wa-color-brand-30: var(--wa-color-pink-30);
--wa-color-brand-20: var(--wa-color-pink-20);
--wa-color-brand-10: var(--wa-color-pink-10);
--wa-color-brand-05: var(--wa-color-pink-05);
--wa-color-brand: var(--wa-color-pink);
--wa-color-brand-key: var(--wa-color-pink-key);
}

View File

@@ -14,5 +14,4 @@
--wa-color-brand-10: var(--wa-color-purple-10);
--wa-color-brand-05: var(--wa-color-purple-05);
--wa-color-brand: var(--wa-color-purple);
--wa-color-brand-key: var(--wa-color-purple-key);
}

View File

@@ -1,18 +0,0 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
--wa-color-brand-95: var(--wa-color-red-95);
--wa-color-brand-90: var(--wa-color-red-90);
--wa-color-brand-80: var(--wa-color-red-80);
--wa-color-brand-70: var(--wa-color-red-70);
--wa-color-brand-60: var(--wa-color-red-60);
--wa-color-brand-50: var(--wa-color-red-50);
--wa-color-brand-40: var(--wa-color-red-40);
--wa-color-brand-30: var(--wa-color-red-30);
--wa-color-brand-20: var(--wa-color-red-20);
--wa-color-brand-10: var(--wa-color-red-10);
--wa-color-brand-05: var(--wa-color-red-05);
--wa-color-brand: var(--wa-color-red);
--wa-color-brand-key: var(--wa-color-red-key);
}

View File

@@ -1,18 +0,0 @@
:where(:root),
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
:where([class^='wa-palette-'], [class*=' wa-palette-']) {
--wa-color-brand-95: var(--wa-color-yellow-95);
--wa-color-brand-90: var(--wa-color-yellow-90);
--wa-color-brand-80: var(--wa-color-yellow-80);
--wa-color-brand-70: var(--wa-color-yellow-70);
--wa-color-brand-60: var(--wa-color-yellow-60);
--wa-color-brand-50: var(--wa-color-yellow-50);
--wa-color-brand-40: var(--wa-color-yellow-40);
--wa-color-brand-30: var(--wa-color-yellow-30);
--wa-color-brand-20: var(--wa-color-yellow-20);
--wa-color-brand-10: var(--wa-color-yellow-10);
--wa-color-brand-05: var(--wa-color-yellow-05);
--wa-color-brand: var(--wa-color-yellow);
--wa-color-brand-key: var(--wa-color-yellow-key);
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #36130a /* oklch(23.979% 0.05887 35.518) */;
--wa-color-red-05: #240a05 /* oklch(18.708% 0.04625 34.412) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fff2b8 /* oklch(95.764% 0.07527 96.955) */;
--wa-color-yellow-90: #ffe578 /* oklch(92.163% 0.13215 96.194) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #2c1912 /* oklch(23.678% 0.03339 40.974) */;
--wa-color-yellow-05: #1d0e0a /* oklch(18.423% 0.02718 35.681) */;
--wa-color-yellow: var(--wa-color-yellow-90);
--wa-color-yellow-key: 90;
--wa-color-green-95: #dcf8ea /* oklch(95.5% 0.03463 164.16) */;
--wa-color-green-90: #bcf1d8 /* oklch(91.473% 0.06399 164.58) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #00231b /* oklch(22.853% 0.04344 174.1) */;
--wa-color-green-05: #001610 /* oklch(17.856% 0.03405 173.73) */;
--wa-color-green: var(--wa-color-green-60);
--wa-color-green-key: 60;
--wa-color-cyan-95: #cbfaf9 /* oklch(95.226% 0.04791 194.77) */;
--wa-color-cyan-90: #9ff4f3 /* oklch(91.294% 0.08228 194.86) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #04221f /* oklch(22.881% 0.03588 185.7) */;
--wa-color-cyan-05: #021513 /* oklch(17.794% 0.0276 186.43) */;
--wa-color-cyan: var(--wa-color-cyan-80);
--wa-color-cyan-key: 80;
--wa-color-blue-95: #ecf3ff /* oklch(96.238% 0.01777 261.34) */;
--wa-color-blue-90: #d9e7ff /* oklch(92.484% 0.03602 261.3) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #101d35 /* oklch(23.292% 0.05008 261.75) */;
--wa-color-blue-05: #0a1222 /* oklch(18.375% 0.0352 263.19) */;
--wa-color-blue: var(--wa-color-blue-60);
--wa-color-blue-key: 60;
--wa-color-indigo-95: #f5efff /* oklch(96.142% 0.02215 302.94) */;
--wa-color-indigo-90: #ede0ff /* oklch(92.64% 0.04374 304.51) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #210e53 /* oklch(24.589% 0.11518 287.13) */;
--wa-color-indigo-05: #150739 /* oklch(19.258% 0.08946 287.81) */;
--wa-color-indigo: var(--wa-color-indigo-50);
--wa-color-indigo-key: 50;
--wa-color-purple-95: #fbedfd /* oklch(96.172% 0.02584 321.94) */;
--wa-color-purple-90: #f7defa /* oklch(92.922% 0.04588 322.59) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #340d36 /* oklch(24.532% 0.08615 325.79) */;
--wa-color-purple-05: #210822 /* oklch(19.065% 0.0603 326.11) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f1f2f4 /* oklch(96.095% 0.00288 264.54) */;
--wa-color-gray-90: #e2e5e8 /* oklch(92.046% 0.00521 247.88) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #012034 /* oklch(23.295% 0.05299 241.23) */;
--wa-color-gray-05: #001421 /* oklch(18.122% 0.03959 237.04) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #450000 /* oklch(24.517% 0.1006 29.234) */;
--wa-color-red-05: #300000 /* oklch(19.415% 0.07967 29.234) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fef3c1 /* oklch(96.062% 0.06532 97.08) */;
--wa-color-yellow-90: #fee682 /* oklch(92.403% 0.1233 96.206) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #341500 /* oklch(23.823% 0.06026 53.274) */;
--wa-color-yellow-05: #220c00 /* oklch(18.585% 0.04625 54.588) */;
--wa-color-yellow: var(--wa-color-yellow-60);
--wa-color-yellow-key: 60;
--wa-color-green-95: #d8fbf0 /* oklch(96.011% 0.03902 174.52) */;
--wa-color-green-90: #a4f5dd /* oklch(91.124% 0.08611 173.73) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #022319 /* oklch(22.882% 0.04342 168.87) */;
--wa-color-green-05: #01160f /* oklch(17.9% 0.03352 169.84) */;
--wa-color-green: var(--wa-color-green-70);
--wa-color-green-key: 70;
--wa-color-cyan-95: #dcf9fc /* oklch(96.213% 0.03042 204.23) */;
--wa-color-cyan-90: #aff0f6 /* oklch(91.368% 0.06543 203.24) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #032127 /* oklch(22.892% 0.03684 213.41) */;
--wa-color-cyan-05: #021518 /* oklch(18.045% 0.02758 207.97) */;
--wa-color-cyan: var(--wa-color-cyan-70);
--wa-color-cyan-key: 70;
--wa-color-blue-95: #e7f5ff /* oklch(96.268% 0.02005 238.66) */;
--wa-color-blue-90: #ceeaff /* oklch(92.321% 0.04119 240.38) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #071f35 /* oklch(23.365% 0.05197 249.19) */;
--wa-color-blue-05: #051321 /* oklch(18.208% 0.03553 248.92) */;
--wa-color-blue: var(--wa-color-blue-60);
--wa-color-blue-key: 60;
--wa-color-indigo-95: #edf2ff /* oklch(96.116% 0.01824 269.09) */;
--wa-color-indigo-90: #dce5ff /* oklch(92.306% 0.03671 270.47) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #121a43 /* oklch(23.813% 0.07786 271) */;
--wa-color-indigo-05: #0b102a /* oklch(18.556% 0.05298 272.08) */;
--wa-color-indigo: var(--wa-color-indigo-50);
--wa-color-indigo-key: 50;
--wa-color-purple-95: #f3f0ff /* oklch(96.181% 0.02019 295.19) */;
--wa-color-purple-90: #eae2ff /* oklch(92.785% 0.03984 298.23) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #211544 /* oklch(24.211% 0.08441 290.44) */;
--wa-color-purple-05: #150d2a /* oklch(18.859% 0.05661 292.88) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f1f2f4 /* oklch(96.095% 0.00288 264.54) */;
--wa-color-gray-90: #e3e5ea /* oklch(92.181% 0.00709 268.54) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #0e1e35 /* oklch(23.442% 0.04969 257.55) */;
--wa-color-gray-05: #081220 /* oklch(18.072% 0.03272 256.72) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -2,103 +2,96 @@
:host,
:where([class^='wa-theme-'], [class*=' wa-theme-']),
.wa-palette-classic {
--wa-color-red-95: #fff0ef /* oklch(96.667% 0.01632 22.08) */;
--wa-color-red-90: #ffdedc /* oklch(92.735% 0.03679 21.966) */;
--wa-color-red-80: #ffb8b4 /* oklch(84.753% 0.08313 22.598) */;
--wa-color-red-70: #fd908e /* oklch(76.913% 0.13219 21.705) */;
--wa-color-red-60: #f46766 /* oklch(68.945% 0.17423 23.179) */;
--wa-color-red-50: #df2f2e /* oklch(58.922% 0.21141 26.911) */;
--wa-color-red-40: #b60000 /* oklch(48.747% 0.20003 29.234) */;
--wa-color-red-30: #910000 /* oklch(41.235% 0.16921 29.234) */;
--wa-color-red-20: #6d0000 /* oklch(33.581% 0.1378 29.234) */;
--wa-color-red-10: #450000 /* oklch(24.517% 0.1006 29.234) */;
--wa-color-red-05: #2f0000 /* oklch(19.165% 0.07864 29.234) */;
--wa-color-red-95: #feeeee /* oklch(96.175% 0.01736 17.459) */;
--wa-color-red-90: #fedede /* oklch(92.701% 0.03551 17.81) */;
--wa-color-red-80: #fdb8b8 /* oklch(84.646% 0.08038 18.878) */;
--wa-color-red-70: #fa9292 /* oklch(76.951% 0.12587 20.376) */;
--wa-color-red-60: #ee6c6c /* oklch(68.861% 0.16125 22.227) */;
--wa-color-red-50: #d43c3c /* oklch(58.269% 0.18916 25.263) */;
--wa-color-red-40: #ac1e1e /* oklch(48.229% 0.17712 27.066) */;
--wa-color-red-30: #640f0f /* oklch(32.787% 0.11797 26.73) */;
--wa-color-red-20: #631111 /* oklch(32.78% 0.11503 26.34) */;
--wa-color-red-10: #3b0d0d /* oklch(24.059% 0.07249 24.391) */;
--wa-color-red-05: #260606 /* oklch(18.371% 0.05502 24.325) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fef2bf /* oklch(95.823% 0.06674 96.369) */;
--wa-color-yellow-90: #fde588 /* oklch(92.2% 0.11633 95.327) */;
--wa-color-yellow-80: #f4c34e /* oklch(83.998% 0.14252 85.76) */;
--wa-color-yellow-70: #e9a010 /* oklch(75.825% 0.15689 75.537) */;
--wa-color-yellow-60: #de7c00 /* oklch(68.073% 0.15991 59.827) */;
--wa-color-yellow-50: #bc5908 /* oklch(57.654% 0.1491 50.241) */;
--wa-color-yellow-40: #934107 /* oklch(47.603% 0.12628 47.819) */;
--wa-color-yellow-30: #763104 /* oklch(40.324% 0.1093 46.564) */;
--wa-color-yellow-20: #572301 /* oklch(32.677% 0.08796 47.926) */;
--wa-color-yellow-10: #371300 /* oklch(24.001% 0.06559 47.77) */;
--wa-color-yellow-05: #250a00 /* oklch(18.773% 0.0519 47.039) */;
--wa-color-yellow: var(--wa-color-yellow-60);
--wa-color-yellow-key: 60;
--wa-color-yellow-95: #fef2c4 /* oklch(95.928% 0.0607 95.131) */;
--wa-color-yellow-90: #fde494 /* oklch(92.185% 0.10303 92.708) */;
--wa-color-yellow-80: #fbc129 /* oklch(84.088% 0.16334 85.185) */;
--wa-color-yellow-70: #f29c0b /* oklch(76.145% 0.1631 70.065) */;
--wa-color-yellow-60: #db7e13 /* oklch(68.058% 0.15388 60.67) */;
--wa-color-yellow-50: #af6005 /* oklch(56.918% 0.13324 58.984) */;
--wa-color-yellow-40: #904207 /* oklch(47.288% 0.12241 49.414) */;
--wa-color-yellow-30: #713406 /* oklch(40.01% 0.10093 50.35) */;
--wa-color-yellow-20: #532408 /* oklch(32.223% 0.07974 47.215) */;
--wa-color-yellow-10: #321606 /* oklch(23.771% 0.05225 48.671) */;
--wa-color-yellow-05: #1f0c01 /* oklch(18.046% 0.04102 55.818) */;
--wa-color-yellow: var(--wa-color-yellow-80);
--wa-color-green-95: #d4fce1 /* oklch(95.554% 0.05477 155.71) */;
--wa-color-green-90: #a4f8c2 /* oklch(91.11% 0.1107 155.35) */;
--wa-color-green-80: #6ae095 /* oklch(81.924% 0.15151 153.52) */;
--wa-color-green-70: #44c670 /* oklch(73.506% 0.16742 151) */;
--wa-color-green-60: #21ab52 /* oklch(65.151% 0.17062 149.59) */;
--wa-color-green-50: #0d873f /* oklch(54.644% 0.14593 150.18) */;
--wa-color-green-40: #166635 /* oklch(45.105% 0.10874 151.56) */;
--wa-color-green-30: #115029 /* oklch(38.182% 0.09049 151.63) */;
--wa-color-green-20: #0a3a1c /* oklch(30.854% 0.07315 151.48) */;
--wa-color-green-10: #04230f /* oklch(22.692% 0.05324 151.92) */;
--wa-color-green-05: #021608 /* oklch(17.756% 0.04076 152.68) */;
--wa-color-green-95: #e9f5ed /* oklch(95.897% 0.01651 156.91) */;
--wa-color-green-90: #cfedd9 /* oklch(91.883% 0.04142 156.31) */;
--wa-color-green-80: #a2d5b4 /* oklch(82.826% 0.07031 156.17) */;
--wa-color-green-70: #6cc08a /* oklch(73.992% 0.11416 154.35) */;
--wa-color-green-60: #38a961 /* oklch(65.365% 0.14702 151.78) */;
--wa-color-green-50: #178640 /* oklch(54.51% 0.14175 149.98) */;
--wa-color-green-40: #006823 /* oklch(45.073% 0.13335 147.17) */;
--wa-color-green-30: #0d5026 /* oklch(38.028% 0.09504 150.7) */;
--wa-color-green-20: #0c391d /* oklch(30.614% 0.06954 152.08) */;
--wa-color-green-10: #082213 /* oklch(22.658% 0.04352 155.31) */;
--wa-color-green-05: #02140a /* oklch(17.084% 0.03423 159.06) */;
--wa-color-green: var(--wa-color-green-60);
--wa-color-green-key: 60;
--wa-color-cyan-95: #d8fafc /* oklch(96.149% 0.03524 200.93) */;
--wa-color-cyan-90: #a3f2f7 /* oklch(91.187% 0.07744 200.93) */;
--wa-color-cyan-80: #67dbe2 /* oklch(82.721% 0.1051 200.68) */;
--wa-color-cyan-70: #29c0ca /* oklch(73.859% 0.11825 201.93) */;
--wa-color-cyan-60: #0ca4ae /* oklch(65.523% 0.10997 202.61) */;
--wa-color-cyan-50: #0c828c /* oklch(55.424% 0.09237 204.53) */;
--wa-color-cyan-40: #0a626b /* oklch(45.428% 0.07504 206.17) */;
--wa-color-cyan-30: #084d55 /* oklch(38.542% 0.06312 207.36) */;
--wa-color-cyan-20: #06383f /* oklch(31.335% 0.05062 209.3) */;
--wa-color-cyan-10: #002127 /* oklch(22.739% 0.03961 211.94) */;
--wa-color-cyan-05: #00151b /* oklch(18.055% 0.03231 217.31) */;
--wa-color-cyan-95: #d0fbf3 /* oklch(95.575% 0.04532 182.8) */;
--wa-color-cyan-90: #a9f4e8 /* oklch(91.479% 0.07585 183.56) */;
--wa-color-cyan-80: #5bdecd /* oklch(82.349% 0.1175 183.5) */;
--wa-color-cyan-70: #36c2b3 /* oklch(73.796% 0.11779 184.4) */;
--wa-color-cyan-60: #12a797 /* oklch(65.522% 0.11415 182.81) */;
--wa-color-cyan-50: #0b8278 /* oklch(54.658% 0.09409 185.3) */;
--wa-color-cyan-40: #09635b /* oklch(45.055% 0.07686 185.06) */;
--wa-color-cyan-30: #0a4e49 /* oklch(38.363% 0.06313 187.15) */;
--wa-color-cyan-20: #0a3835 /* oklch(30.997% 0.04799 188.56) */;
--wa-color-cyan-10: #082120 /* oklch(22.8% 0.03074 191.62) */;
--wa-color-cyan-05: #021413 /* oklch(17.442% 0.02643 190.53) */;
--wa-color-cyan: var(--wa-color-cyan-70);
--wa-color-cyan-key: 70;
--wa-color-blue-95: #e2f6ff /* oklch(96.112% 0.0243 226.47) */;
--wa-color-blue-90: #c0ecff /* oklch(91.822% 0.0523 226) */;
--wa-color-blue-80: #7fd4fc /* oklch(83.068% 0.09979 229.91) */;
--wa-color-blue-70: #48b9f4 /* oklch(74.644% 0.13162 235.42) */;
--wa-color-blue-60: #1f9de2 /* oklch(66.419% 0.14398 240.02) */;
--wa-color-blue-50: #007bbc /* oklch(55.956% 0.1346 242.72) */;
--wa-color-blue-40: #005d93 /* oklch(46.121% 0.11438 244.28) */;
--wa-color-blue-30: #004975 /* oklch(39.093% 0.09705 244.33) */;
--wa-color-blue-20: #003558 /* oklch(31.8% 0.08026 245.13) */;
--wa-color-blue-10: #001f36 /* oklch(23.093% 0.05763 244.59) */;
--wa-color-blue-05: #001325 /* oklch(18.113% 0.04675 246.17) */;
--wa-color-blue-95: #e5f4fe /* oklch(95.896% 0.02085 236.75) */;
--wa-color-blue-90: #c8ebfd /* oklch(92.061% 0.04406 230.21) */;
--wa-color-blue-80: #80d4fc /* oklch(83.114% 0.09915 230.17) */;
--wa-color-blue-70: #37bbf5 /* oklch(74.731% 0.13762 232.44) */;
--wa-color-blue-60: #0d9ee0 /* oklch(66.354% 0.14388 237.59) */;
--wa-color-blue-50: #027ab9 /* oklch(55.557% 0.13184 242.23) */;
--wa-color-blue-40: #015d8d /* oklch(45.762% 0.10698 241.38) */;
--wa-color-blue-30: #024970 /* oklch(38.805% 0.0903 241.59) */;
--wa-color-blue-20: #04354f /* oklch(31.306% 0.06703 238.73) */;
--wa-color-blue-10: #05202f /* oklch(23.154% 0.04349 236.83) */;
--wa-color-blue-05: #04121b /* oklch(17.393% 0.0282 236.81) */;
--wa-color-blue: var(--wa-color-blue-60);
--wa-color-blue-key: 60;
--wa-color-indigo-95: #eff2ff /* oklch(96.265% 0.01769 275.64) */;
--wa-color-indigo-90: #e0e5ff /* oklch(92.602% 0.03569 277.03) */;
--wa-color-indigo-80: #bec7ff /* oklch(84.198% 0.07895 277.45) */;
--wa-color-indigo-70: #9da9fc /* oklch(75.797% 0.11994 276.85) */;
--wa-color-indigo-60: #808bf8 /* oklch(67.752% 0.15983 276.9) */;
--wa-color-indigo-50: #6163f0 /* oklch(57.814% 0.20686 277.14) */;
--wa-color-indigo-40: #4a41d4 /* oklch(48.413% 0.21583 277.35) */;
--wa-color-indigo-30: #3b369d /* oklch(40.562% 0.16149 278.54) */;
--wa-color-indigo-20: #2b2872 /* oklch(32.937% 0.12339 278.99) */;
--wa-color-indigo-10: #191748 /* oklch(24.174% 0.08853 279.28) */;
--wa-color-indigo-05: #0e0d31 /* oklch(18.772% 0.06933 278.6) */;
--wa-color-indigo-95: #eef2ff /* oklch(96.191% 0.01793 272.31) */;
--wa-color-indigo-90: #dee5fd /* oklch(92.388% 0.03348 272.78) */;
--wa-color-indigo-80: #bec8f2 /* oklch(83.901% 0.05981 274.54) */;
--wa-color-indigo-70: #9dabf0 /* oklch(75.639% 0.10065 274.93) */;
--wa-color-indigo-60: #818cf7 /* oklch(67.953% 0.15693 276.94) */;
--wa-color-indigo-50: #6063eb /* oklch(57.366% 0.20061 277.06) */;
--wa-color-indigo-40: #4941d3 /* oklch(48.251% 0.21482 277.09) */;
--wa-color-indigo-30: #3930ad /* oklch(40.969% 0.18954 277.17) */;
--wa-color-indigo-20: #29247a /* oklch(32.82% 0.14032 277.91) */;
--wa-color-indigo-10: #191843 /* oklch(23.918% 0.07895 279.64) */;
--wa-color-indigo-05: #0f0e26 /* oklch(18.064% 0.04799 282.35) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #f6f0ff /* oklch(96.412% 0.02086 304.04) */;
--wa-color-purple-90: #eee0ff /* oklch(92.72% 0.04406 305.89) */;
--wa-color-purple-80: #dcbdff /* oklch(84.694% 0.09583 305.85) */;
--wa-color-purple-70: #ca99ff /* oklch(76.728% 0.14961 305.27) */;
--wa-color-purple-60: #b874ff /* oklch(69.085% 0.2024 304.19) */;
--wa-color-purple-50: #9f46ee /* oklch(59.304% 0.23941 304.1) */;
--wa-color-purple-40: #7e2ac2 /* oklch(49.181% 0.21892 304.24) */;
--wa-color-purple-30: #632198 /* oklch(41.448% 0.18071 304.64) */;
--wa-color-purple-20: #4a1574 /* oklch(33.839% 0.15043 304.56) */;
--wa-color-purple-10: #2e094b /* oklch(24.855% 0.11212 304.52) */;
--wa-color-purple-05: #1e0433 /* oklch(19.319% 0.0877 304.85) */;
--wa-color-purple-95: #f7efff /* oklch(96.298% 0.02281 308.2) */;
--wa-color-purple-90: #efe0ff /* oklch(92.801% 0.0444 307.25) */;
--wa-color-purple-80: #dcbdfe /* oklch(84.655% 0.09457 306.19) */;
--wa-color-purple-70: #cb9afd /* oklch(76.897% 0.14583 306.03) */;
--wa-color-purple-60: #b976f9 /* oklch(69.137% 0.19284 305.56) */;
--wa-color-purple-50: #9d46ec /* oklch(58.928% 0.237 303.82) */;
--wa-color-purple-40: #7d22cc /* oklch(49.256% 0.23487 302) */;
--wa-color-purple-30: #631f9c /* oklch(41.597% 0.18675 303.6) */;
--wa-color-purple-20: #48176e /* oklch(33.244% 0.14133 305.45) */;
--wa-color-purple-10: #2e054e /* oklch(24.726% 0.11996 303.55) */;
--wa-color-purple-05: #1d0331 /* oklch(18.767% 0.08707 305.63) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f2f2f3 /* oklch(96.143% 0.00133 286.37) */;
--wa-color-gray-90: #e5e5e8 /* oklch(92.276% 0.00403 286.32) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1d1d20 /* oklch(23.201% 0.00571 285.95) */;
--wa-color-gray-05: #101113 /* oklch(17.739% 0.00442 264.46) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #400712 /* oklch(24.506% 0.08542 15.881) */;
--wa-color-red-05: #2a030a /* oklch(18.798% 0.06593 14.104) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fdf3ba /* oklch(95.838% 0.07362 99.275) */;
--wa-color-yellow-90: #fee590 /* oklch(92.407% 0.10827 93.577) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #361300 /* oklch(23.81% 0.06438 48.467) */;
--wa-color-yellow-05: #240b00 /* oklch(18.767% 0.04963 49.978) */;
--wa-color-yellow: var(--wa-color-yellow-70);
--wa-color-yellow-key: 70;
--wa-color-green-95: #e2f9e2 /* oklch(95.91% 0.03884 145.26) */;
--wa-color-green-90: #c2f2c1 /* oklch(91.494% 0.08233 144.35) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #002400 /* oklch(22.556% 0.07675 142.5) */;
--wa-color-green-05: #001700 /* oklch(17.73% 0.06033 142.5) */;
--wa-color-green: var(--wa-color-green-60);
--wa-color-green-key: 60;
--wa-color-cyan-95: #e3f7f5 /* oklch(96.09% 0.02114 189.57) */;
--wa-color-cyan-90: #c6eeeb /* oklch(91.997% 0.04158 190.86) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #002220 /* oklch(22.721% 0.03935 189.11) */;
--wa-color-cyan-05: #001513 /* oklch(17.625% 0.03077 187.05) */;
--wa-color-cyan: var(--wa-color-cyan-70);
--wa-color-cyan-key: 70;
--wa-color-blue-95: #ebf4ff /* oklch(96.361% 0.01763 253.34) */;
--wa-color-blue-90: #d4e7ff /* oklch(92.129% 0.03859 254.29) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #001c45 /* oklch(23.545% 0.08493 257.39) */;
--wa-color-blue-05: #00112f /* oklch(18.443% 0.06618 257.27) */;
--wa-color-blue: var(--wa-color-blue-50);
--wa-color-blue-key: 50;
--wa-color-indigo-95: #f0f2fe /* oklch(96.311% 0.01617 278.51) */;
--wa-color-indigo-90: #e2e4fc /* oklch(92.459% 0.03255 281.95) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #1c006a /* oklch(25.437% 0.15565 278.46) */;
--wa-color-indigo-05: #130049 /* oklch(19.925% 0.11977 280.89) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #f9effd /* oklch(96.395% 0.02131 316.46) */;
--wa-color-purple-90: #f4defb /* oklch(92.703% 0.04524 317.99) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #330940 /* oklch(24.654% 0.10189 316.7) */;
--wa-color-purple-05: #22042b /* oklch(19.232% 0.08005 317.42) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f1f2f3 /* oklch(96.067% 0.00172 247.84) */;
--wa-color-gray-90: #e4e5e9 /* oklch(92.228% 0.0055 274.96) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1b1d26 /* oklch(23.277% 0.01762 275.14) */;
--wa-color-gray-05: #101219 /* oklch(18.342% 0.01472 272.42) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #44000d /* oklch(24.5% 0.09818 18.249) */;
--wa-color-red-05: #2e0006 /* oklch(19.077% 0.07648 18.657) */;
--wa-color-red: var(--wa-color-red-40);
--wa-color-red-key: 40;
--wa-color-yellow-95: #f5f2e5 /* oklch(95.994% 0.01748 96.105) */;
--wa-color-yellow-90: #ece6cc /* oklch(92.281% 0.03499 96.315) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #2b1a02 /* oklch(23.457% 0.04659 73.352) */;
--wa-color-yellow-05: #191008 /* oklch(18.243% 0.02161 62.915) */;
--wa-color-yellow: var(--wa-color-yellow-60);
--wa-color-yellow-key: 60;
--wa-color-green-95: #ecf4f1 /* oklch(96.029% 0.00935 171.8) */;
--wa-color-green-90: #dae9e3 /* oklch(92.11% 0.01786 170.06) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #002316 /* oklch(22.679% 0.04824 164.14) */;
--wa-color-green-05: #00160d /* oklch(17.744% 0.03707 165.47) */;
--wa-color-green: var(--wa-color-green-40);
--wa-color-green-key: 40;
--wa-color-cyan-95: #ebf4f4 /* oklch(96.04% 0.00955 197) */;
--wa-color-cyan-90: #d9e9e9 /* oklch(92.209% 0.01702 196.86) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #002223 /* oklch(22.861% 0.03889 197.63) */;
--wa-color-cyan-05: #001415 /* oklch(17.367% 0.02953 198.81) */;
--wa-color-cyan: var(--wa-color-cyan-50);
--wa-color-cyan-key: 50;
--wa-color-blue-95: #ebf3fa /* oklch(96.015% 0.01271 244.25) */;
--wa-color-blue-90: #d8e8f5 /* oklch(92.295% 0.02463 242.35) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #001f37 /* oklch(23.169% 0.0591 245.63) */;
--wa-color-blue-05: #001221 /* oklch(17.475% 0.04178 242.4) */;
--wa-color-blue: var(--wa-color-blue-50);
--wa-color-blue-key: 50;
--wa-color-indigo-95: #f1f1fa /* oklch(96.073% 0.01199 286.17) */;
--wa-color-indigo-90: #e4e4f6 /* oklch(92.422% 0.02428 285.92) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #171844 /* oklch(23.835% 0.08107 277.33) */;
--wa-color-indigo-05: #0d0e27 /* oklch(17.951% 0.0503 278.32) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #f6f0f9 /* oklch(96.235% 0.01349 314.76) */;
--wa-color-purple-90: #eee2f2 /* oklch(92.695% 0.0249 317.72) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #300e3b /* oklch(24.365% 0.08778 316.83) */;
--wa-color-purple-05: #1c0823 /* oklch(18.278% 0.05827 316.48) */;
--wa-color-purple: var(--wa-color-purple-40);
--wa-color-purple-key: 40;
--wa-color-gray-95: #f2f2f3 /* oklch(96.143% 0.00133 286.37) */;
--wa-color-gray-90: #e6e5e8 /* oklch(92.354% 0.00415 301.42) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1f1c23 /* oklch(23.288% 0.01397 304.73) */;
--wa-color-gray-05: #131115 /* oklch(18.185% 0.00865 307.93) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #450002 /* oklch(24.549% 0.10017 27.414) */;
--wa-color-red-05: #2f0001 /* oklch(19.191% 0.07829 27.331) */;
--wa-color-red: var(--wa-color-red-40);
--wa-color-red-key: 40;
--wa-color-yellow-95: #fff4b3 /* oklch(96.064% 0.08319 99.657) */;
--wa-color-yellow-90: #fee58c /* oklch(92.346% 0.11242 94.205) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #251d00 /* oklch(23.339% 0.04787 94.382) */;
--wa-color-yellow-05: #171200 /* oklch(18.295% 0.03771 96.891) */;
--wa-color-yellow: var(--wa-color-yellow-80);
--wa-color-yellow-key: 80;
--wa-color-green-95: #e1f9e1 /* oklch(95.814% 0.04053 145.25) */;
--wa-color-green-90: #bff2c0 /* oklch(91.282% 0.08527 145.33) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #01230a /* oklch(22.432% 0.06139 149.06) */;
--wa-color-green-05: #001701 /* oklch(17.759% 0.05792 143.81) */;
--wa-color-green: var(--wa-color-green-80);
--wa-color-green-key: 80;
--wa-color-cyan-95: #edf3f3 /* oklch(95.962% 0.00639 197.05) */;
--wa-color-cyan-90: #dbe8e7 /* oklch(92.095% 0.01393 191.38) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #002220 /* oklch(22.721% 0.03935 189.11) */;
--wa-color-cyan-05: #001514 /* oklch(17.672% 0.03043 190.87) */;
--wa-color-cyan: var(--wa-color-cyan-40);
--wa-color-cyan-key: 40;
--wa-color-blue-95: #eaf5ff /* oklch(96.485% 0.01782 245.38) */;
--wa-color-blue-90: #d5e7ff /* oklch(92.2% 0.03803 255.61) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #011f39 /* oklch(23.373% 0.0615 248.28) */;
--wa-color-blue-05: #001327 /* oklch(18.28% 0.04995 248.62) */;
--wa-color-blue: var(--wa-color-blue-40);
--wa-color-blue-key: 40;
--wa-color-indigo-95: #f7efff /* oklch(96.298% 0.02281 308.2) */;
--wa-color-indigo-90: #ede1ff /* oklch(92.831% 0.04213 303.7) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #24045f /* oklch(25.226% 0.1388 287.21) */;
--wa-color-indigo-05: #180044 /* oklch(19.806% 0.11332 288.23) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #ffedff /* oklch(96.554% 0.03048 325.81) */;
--wa-color-purple-90: #fbdbff /* oklch(92.864% 0.05886 322.51) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #310c40 /* oklch(24.665% 0.097 314.25) */;
--wa-color-purple-05: #22042d /* oklch(19.41% 0.08225 315.39) */;
--wa-color-purple: var(--wa-color-purple-40);
--wa-color-purple-key: 40;
--wa-color-gray-95: #f4f3f4 /* oklch(96.52% 0.00169 325.59) */;
--wa-color-gray-90: #e7e5e8 /* oklch(92.431% 0.00454 314.8) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1f1d22 /* oklch(23.51% 0.0099 303.74) */;
--wa-color-gray-05: #121214 /* oklch(18.309% 0.00404 285.99) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #36130b /* oklch(23.996% 0.05851 34.254) */;
--wa-color-red-05: #240a05 /* oklch(18.708% 0.04625 34.412) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #f5f0e8 /* oklch(95.682% 0.01193 79.784) */;
--wa-color-yellow-90: #ede4d5 /* oklch(92.192% 0.0223 80.684) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #2a1b00 /* oklch(23.521% 0.04872 79.998) */;
--wa-color-yellow-05: #1b1000 /* oklch(18.327% 0.03796 79.944) */;
--wa-color-yellow: var(--wa-color-yellow-50);
--wa-color-yellow-key: 50;
--wa-color-green-95: #edf2ee /* oklch(95.624% 0.00749 151.89) */;
--wa-color-green-90: #dde8df /* oklch(92.017% 0.01681 151.09) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #0c2212 /* oklch(22.839% 0.04191 150.74) */;
--wa-color-green-05: #051509 /* oklch(17.675% 0.03381 151.11) */;
--wa-color-green: var(--wa-color-green-50);
--wa-color-green-key: 50;
--wa-color-cyan-95: #eff3f4 /* oklch(96.14% 0.00448 214.33) */;
--wa-color-cyan-90: #dee7e9 /* oklch(92.173% 0.01004 212.52) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #022125 /* oklch(22.735% 0.03682 207.1) */;
--wa-color-cyan-05: #011518 /* oklch(17.963% 0.02908 207.19) */;
--wa-color-cyan: var(--wa-color-cyan-40);
--wa-color-cyan-key: 40;
--wa-color-blue-95: #eef1f5 /* oklch(95.7% 0.00626 255.48) */;
--wa-color-blue-90: #e1e6ef /* oklch(92.375% 0.01334 262.38) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #101e34 /* oklch(23.495% 0.04695 259.11) */;
--wa-color-blue-05: #081223 /* oklch(18.293% 0.03819 260.22) */;
--wa-color-blue: var(--wa-color-blue-40);
--wa-color-blue-key: 40;
--wa-color-indigo-95: #f2f2f7 /* oklch(96.257% 0.00665 286.27) */;
--wa-color-indigo-90: #e6e5f1 /* oklch(92.619% 0.01616 289.92) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #1e1a32 /* oklch(23.531% 0.04547 290.1) */;
--wa-color-indigo-05: #121021 /* oklch(18.511% 0.03422 287.97) */;
--wa-color-indigo: var(--wa-color-indigo-50);
--wa-color-indigo-key: 50;
--wa-color-purple-95: #f4f1f6 /* oklch(96.187% 0.00734 312.3) */;
--wa-color-purple-90: #eae4ef /* oklch(92.675% 0.01603 310.1) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #26182f /* oklch(23.839% 0.04672 311.22) */;
--wa-color-purple-05: #180e1f /* oklch(18.634% 0.03651 310.29) */;
--wa-color-purple: var(--wa-color-purple-40);
--wa-color-purple-key: 40;
--wa-color-gray-95: #f1f1f0 /* oklch(95.787% 0.00133 106.42) */;
--wa-color-gray-90: #e7e6e4 /* oklch(92.515% 0.0029 84.559) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1f1d1a /* oklch(23.185% 0.00644 78.196) */;
--wa-color-gray-05: #131210 /* oklch(18.257% 0.00432 84.592) */;
--wa-color-gray: var(--wa-color-gray-50);
--wa-color-gray-key: 50;
}

View File

@@ -1,66 +0,0 @@
/**
* Analyze palettes and export the results.
* ✅ Convert colors to OKLCH
* ✅ Find accent tint (real and clamped)
* More later.
*/
import rawPalettes from './palettes.js';
// Default accent tint if all chromas are 0, but also the tint accent colors will be nudged towards (see chromaTolerance)
const DEFAULT_ACCENT = 60;
// Min and max allowed tints
const MIN_ACCENT = 40;
const MAX_ACCENT = 90;
// Chroma tolerance: Chroma will need to differ more than this to gravitate away from defaultAccent
const CHROMA_TOLERANCE = 0.000001;
const palettes = Object.assign({}, rawPalettes);
for (let paletteId in palettes) {
const tokens = Object.assign({}, palettes[paletteId]);
palettes[paletteId] = tokens;
for (let hue in tokens) {
let tints = Object.assign({}, tokens[hue]);
tokens[hue] = tints;
let maxChromaTint = DEFAULT_ACCENT;
let maxChroma = tints[DEFAULT_ACCENT].c || 0;
for (let tint in tints) {
let color = tints[tint].to('oklch');
tints[tint] = color;
if (tint === '05') {
// The object has both '5' and '05' keys, but '05' is out of order
continue;
}
tint = tint.padStart(2, '0');
if (color.c > maxChroma + CHROMA_TOLERANCE) {
maxChroma = color.c;
maxChromaTint = tint;
}
}
tints['05'] = tints['5'];
tints.maxChroma = tints.maxChromaRaw = maxChroma;
tints.maxChromaTint = tints.maxChromaTintRaw = maxChromaTint;
if (maxChromaTint < MIN_ACCENT || maxChromaTint > MAX_ACCENT) {
tints.maxChromaTint = clamp(MIN_ACCENT, maxChromaTint, MAX_ACCENT);
tints.maxChroma = tints[maxChromaTint].c;
}
}
}
function clamp(min, value, max) {
return Math.min(Math.max(min, value), max);
}
export default palettes;
export { rawPalettes };

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #3d0d00 /* oklch(24.253% 0.07888 38.298) */;
--wa-color-red-05: #290600 /* oklch(18.868% 0.06197 37.848) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fff497 /* oklch(95.586% 0.11473 102.45) */;
--wa-color-yellow-90: #ffe571 /* oklch(92.08% 0.13847 96.881) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #311613 /* oklch(23.859% 0.04441 27.497) */;
--wa-color-yellow-05: #1f0d0b /* oklch(18.561% 0.0315 27.209) */;
--wa-color-yellow: var(--wa-color-yellow-80);
--wa-color-yellow-key: 80;
--wa-color-green-95: #dafadc /* oklch(95.411% 0.05194 146.87) */;
--wa-color-green-90: #b9f4bc /* oklch(91.261% 0.09639 146.02) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #00230e /* oklch(22.462% 0.05754 153.24) */;
--wa-color-green-05: #001607 /* oklch(17.557% 0.04482 153.41) */;
--wa-color-green: var(--wa-color-green-70);
--wa-color-green-key: 70;
--wa-color-cyan-95: #d1f9f1 /* oklch(95.167% 0.04252 181.91) */;
--wa-color-cyan-90: #a9f4e6 /* oklch(91.421% 0.07655 181.59) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #002129 /* oklch(22.851% 0.04085 217.17) */;
--wa-color-cyan-05: #00151b /* oklch(18.055% 0.03231 217.31) */;
--wa-color-cyan: var(--wa-color-cyan-70);
--wa-color-cyan-key: 70;
--wa-color-blue-95: #e1f4ff /* oklch(95.642% 0.02496 232.97) */;
--wa-color-blue-90: #caebff /* oklch(92.258% 0.04407 234.57) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #001a4e /* oklch(23.965% 0.10161 260.68) */;
--wa-color-blue-05: #000f36 /* oklch(18.68% 0.08063 260.98) */;
--wa-color-blue: var(--wa-color-blue-50);
--wa-color-blue-key: 50;
--wa-color-indigo-95: #f1efff /* oklch(95.834% 0.02142 291.74) */;
--wa-color-indigo-90: #e7e3ff /* oklch(92.744% 0.03793 292.2) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #220064 /* oklch(25.227% 0.14791 284.49) */;
--wa-color-indigo-05: #160046 /* oklch(19.835% 0.11578 285.15) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #f8edfd /* oklch(95.934% 0.02417 315.47) */;
--wa-color-purple-90: #f2e0fc /* oklch(92.948% 0.04198 313.7) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #310a42 /* oklch(24.603% 0.10191 313.12) */;
--wa-color-purple-05: #20052d /* oklch(19.24% 0.07931 312.44) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f2f2f2 /* oklch(96.115% 0 none) */;
--wa-color-gray-90: #e6e6e6 /* oklch(92.494% 0 none) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #1d1d1d /* oklch(23.075% 0 none) */;
--wa-color-gray-05: #131313 /* oklch(18.674% 0 none) */;
--wa-color-gray: var(--wa-color-gray-60);
--wa-color-gray-key: 60;
}

View File

@@ -7,7 +7,7 @@ import chalk from 'chalk';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import palettes, { rawPalettes } from './palettes-analyzed.js';
import palettes from './palettes.js';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
@@ -19,6 +19,9 @@ const selector = paletteId =>
// Default accent tint if all chromas are 0, but also the tint accent colors will be nudged towards (see chromaTolerance)
const defaultAccent = 60;
// Chroma tolerance: Chroma will need to differ more than this to gravitate away from defaultAccent
const chromaTolerance = 0.000001;
// Min and max allowed tints
const minAccentTint = 40;
const maxAccentTint = 90;
@@ -39,29 +42,40 @@ for (let paletteId in palettes) {
for (let hue in tokens) {
let tints = tokens[hue];
let maxChromaTint = defaultAccent;
let maxChroma = tints[defaultAccent].get('oklch.c');
let tintCSS = '';
for (let tint in tints) {
if (tint === '05' || !(tint > 0)) {
if (tint === '05') {
// The object has both '5' and '05' keys, but '05' is out of order
// Also ignore non-tints
continue;
}
let color = tints[tint];
let lchColor = color.to('oklch');
tint = tint.padStart(2, '0');
tintCSS =
`--wa-color-${hue}-${tint}: ${color.toString({ format: 'hex' })} /* ${color.toString()} */;\n` + tintCSS;
if (lchColor.c > maxChroma + chromaTolerance) {
maxChroma = lchColor.c;
maxChromaTint = tint;
}
let lchComment = `/* ${lchColor.toString()} */`;
tintCSS = `--wa-color-${hue}-${tint}: ${color} ${lchComment};\n` + tintCSS;
}
if (tints.maxChromaTint != tints.maxChromaTintRaw) {
if (maxChromaTint < minAccentTint || maxChromaTint > maxAccentTint) {
let fakeMaxChromaTint = clamp(minAccentTint, maxChromaTint, maxAccentTint);
let huePrefix = hueToChalk(hue)(hue.padEnd(hueMaxChars + 2));
console.warn(
`${prefix} ${huePrefix}: Clamping accent color to ${chalk.bold(tints.maxChromaTint)}, but peak chroma is in ${chalk.bold(tints.maxChromaTintRaw)} (${formatComparison(tints[tints.maxChromaTintRaw].c, tints[tints.maxChromaTint].c)})`,
`${prefix} ${huePrefix}: Clamping accent color to ${chalk.bold(fakeMaxChromaTint)}, but peak chroma is in ${chalk.bold(maxChromaTint)} (${formatComparison(tints[maxChromaTint].get('oklch.c'), tints[fakeMaxChromaTint].get('oklch.c'))})`,
);
issueCount++;
maxChromaTint = fakeMaxChromaTint;
if (prefix.trim()) {
// First time encountering an issue with this palette
@@ -72,8 +86,7 @@ for (let paletteId in palettes) {
}
}
tintCSS += `--wa-color-${hue}: var(--wa-color-${hue}-${tints.maxChromaTint});\n`;
tintCSS += `--wa-color-${hue}-key: ${tints.maxChromaTint};\n`;
tintCSS += `--wa-color-${hue}: var(--wa-color-${hue}-${maxChromaTint});\n`;
css += tintCSS + '\n';
}
@@ -88,6 +101,10 @@ console.info(
(issueCount > 0 ? ` ${chalk.bold(issueCount)} issues found across ${chalk.bold(issuePaletteCount)} palettes.` : ''),
);
function clamp(min, value, max) {
return Math.min(Math.max(min, value), max);
}
/**
* Format a comparison by rounding numbers to the lowest number of significant digits that still shows a difference.
* @param {number} a

View File

@@ -14,7 +14,6 @@
--wa-color-red-10: #400809 /* oklch(24.44% 0.08486 25.315) */;
--wa-color-red-05: #2b0404 /* oklch(19.055% 0.06569 26.078) */;
--wa-color-red: var(--wa-color-red-50);
--wa-color-red-key: 50;
--wa-color-yellow-95: #fef6ab /* oklch(96.234% 0.09455 102.83) */;
--wa-color-yellow-90: #ffe759 /* oklch(92.242% 0.15928 99.624) */;
@@ -28,7 +27,6 @@
--wa-color-yellow-10: #311704 /* oklch(23.775% 0.05173 54.627) */;
--wa-color-yellow-05: #1f0e02 /* oklch(18.545% 0.03815 59.032) */;
--wa-color-yellow: var(--wa-color-yellow-80);
--wa-color-yellow-key: 80;
--wa-color-green-95: #d6fbe3 /* oklch(95.529% 0.04989 156.89) */;
--wa-color-green-90: #acf5c6 /* oklch(90.962% 0.09709 155.72) */;
@@ -42,7 +40,6 @@
--wa-color-green-10: #032311 /* oklch(22.69% 0.05156 154.92) */;
--wa-color-green-05: #02160a /* oklch(17.815% 0.03799 156.47) */;
--wa-color-green: var(--wa-color-green-70);
--wa-color-green-key: 70;
--wa-color-cyan-95: #d1fbf2 /* oklch(95.61% 0.04472 180.87) */;
--wa-color-cyan-90: #9bf6e4 /* oklch(91.092% 0.09113 180.19) */;
@@ -56,7 +53,6 @@
--wa-color-cyan-10: #022222 /* oklch(22.914% 0.03701 194.88) */;
--wa-color-cyan-05: #011515 /* oklch(17.806% 0.02865 194.89) */;
--wa-color-cyan: var(--wa-color-cyan-80);
--wa-color-cyan-key: 80;
--wa-color-blue-95: #ebf3ff /* oklch(96.164% 0.01825 258.35) */;
--wa-color-blue-90: #d6e7fe /* oklch(92.238% 0.03631 255.96) */;
@@ -70,7 +66,6 @@
--wa-color-blue-10: #101b41 /* oklch(23.741% 0.07371 268.19) */;
--wa-color-blue-05: #09102c /* oklch(18.584% 0.05736 269.49) */;
--wa-color-blue: var(--wa-color-blue-40);
--wa-color-blue-key: 40;
--wa-color-indigo-95: #eef2ff /* oklch(96.191% 0.01793 272.31) */;
--wa-color-indigo-90: #dde5ff /* oklch(92.379% 0.03641 272.07) */;
@@ -84,7 +79,6 @@
--wa-color-indigo-10: #1b1842 /* oklch(24.014% 0.0769 282.14) */;
--wa-color-indigo-05: #100f29 /* oklch(18.672% 0.05145 281.93) */;
--wa-color-indigo: var(--wa-color-indigo-40);
--wa-color-indigo-key: 40;
--wa-color-purple-95: #f7efff /* oklch(96.298% 0.02281 308.2) */;
--wa-color-purple-90: #efe0ff /* oklch(92.801% 0.0444 307.25) */;
@@ -98,7 +92,6 @@
--wa-color-purple-10: #2f0451 /* oklch(25.081% 0.12442 302.96) */;
--wa-color-purple-05: #1e0238 /* oklch(19.51% 0.09712 301.8) */;
--wa-color-purple: var(--wa-color-purple-50);
--wa-color-purple-key: 50;
--wa-color-gray-95: #f1f2f4 /* oklch(96.095% 0.00288 264.54) */;
--wa-color-gray-90: #e3e5e9 /* oklch(92.152% 0.00582 264.53) */;
@@ -112,5 +105,4 @@
--wa-color-gray-10: #161e2d /* oklch(23.484% 0.03142 262.56) */;
--wa-color-gray-05: #0c1220 /* oklch(18.396% 0.03036 265.82) */;
--wa-color-gray: var(--wa-color-gray-40);
--wa-color-gray-key: 40;
}

View File

@@ -1,8 +1,14 @@
:host {
:host,
.wa-badge {
--size-xs: var(--wa-font-size-2xs);
--size-s: var(--wa-font-size-2xs);
--size-m: var(--wa-font-size-2xs);
--size-l: var(--wa-font-size-xs);
display: inline-flex;
align-items: center;
justify-content: center;
font-size: max(var(--wa-font-size-2xs), 0.75em);
font-size: max(var(--wa-size), 0.75em);
font-weight: var(--wa-font-weight-semibold);
line-height: 1;
background-color: var(--background-color, var(--wa-color-fill-loud));
@@ -18,19 +24,15 @@
cursor: inherit;
}
/* Pill modifier */
:host([pill]) {
border-radius: var(--wa-border-radius-pill);
::slotted(wa-icon),
.wa-badge > wa-icon {
margin-inline-end: var(--wa-space-2xs, 0.25em);
opacity: 90%;
line-height: 1;
height: 0.85em;
}
/* Pulse modifier */
:host([pulse]) {
--pulse-color: var(--background-color);
animation: pulse 1.5s infinite;
}
@keyframes pulse {
@keyframes wa-pulse {
0% {
box-shadow: 0 0 0 0 var(--pulse-color);
}
@@ -42,9 +44,16 @@
}
}
::slotted(wa-icon) {
margin-inline-end: var(--wa-space-2xs, 0.25em);
opacity: 90%;
line-height: 1;
height: 0.85em;
/* Pill modifier */
.wa-pill,
:host([pill]) {
border-radius: var(--wa-border-radius-pill);
}
/* Pulse modifier */
:host([pulse]),
.wa-badge.wa-pulse {
--pulse-color: var(--background-color);
animation: wa-pulse 1.5s infinite;
}

View File

@@ -1,11 +1,9 @@
/* 0 specificity. Safari doesn't like :where(:host()) so we need a separate rule. */
:where(.wa-filled, .wa-plain, .wa-accent, .wa-outlined),
.wa-filled,
.wa-plain,
.wa-accent,
:host {
--border-color: transparent;
--outlined-border-color: initial;
--outlined-border-color-hover: initial;
--outlined-text-color: initial;
--outlined-text-color-hover: initial;
}
.wa-outlined,