Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
- [add] `aspect-{ratio}` / `aspect-auto`, `object-{contain,cover,fill,none,scale-down}`, `flex--space-around-main` / `flex--space-evenly-main`, and transform utilities (`rotate{deg}`, `scale{percent}`).
- [breaking] `txt-break-word` uses `overflow-wrap: anywhere`, so words break only when they would overflow, instead of `word-break: break-all`.
- [add] `animation-shimmer`, `visible-on-parent-hover`, `bg-canvas`, and `bg-canvas--dark`.
- [add] `txt-wrap` to undo `white-space: nowrap`, such as on a `toggle`.
- [breaking] Restyle `.switch` and `.switch--l` to match input heights, with a borderless track and a white thumb.
- [add] `switch--s` for an 18px-tall switch.
- [breaking] Remove `switch--s-label`. Switches now center on their label.
- [add] Respect `prefers-reduced-motion: reduce` by making transitions instant.
- [style change] Toggle groups are restyled as segmented controls. `toggle` is now 24px tall, and its label no longer wraps.
- [add] `toggle--l` (36px).
- [breaking] Focus states use `:focus-visible` with a `--focus-outline` outline, replacing `--focus-shadow`. `assembly.js` focus control only affects selects.
- [internal] Assembly utilities are UnoCSS rules in `src/preset/`. Reset and component CSS live in `src/preset/base.css`. The package build is `src/build-*.js`. The documentation site is VitePress under `docs/`.
- [add] `building`, `clip`, `truck` icons
Expand Down
18 changes: 17 additions & 1 deletion docs/.vitepress/documentation-layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@ function wrapEntry(state, openIndex, md, usedIds) {
const exampleAt = inner.findIndex(token => isFence(token, 'example'));
const split = exampleAt === -1 ? inner.length : exampleAt;
const render = list => md.renderer.render(list, md.options, state.env);
const renderProse = list =>
list.length ? `<div class="mb24 prose">${render(list)}</div>` : '';
// Text between examples gets the same prose styling as the description.
const renderRest = list => {
let html = '';
let prose = [];
list.forEach(token => {
if (isFence(token, 'example')) {
html += renderProse(prose) + render([token]);
prose = [];
} else {
prose.push(token);
}
});
return html + renderProse(prose);
};
tokens.splice(
openIndex,
end - openIndex,
Expand All @@ -113,7 +129,7 @@ function wrapEntry(state, openIndex, md, usedIds) {
</div>
<div class="col w-2/3-mxl">
<div class="mb24 prose">${render(inner.slice(0, split))}</div>
${render(inner.slice(split))}
${renderRest(inner.slice(split))}
</div>
</div>
</div>\n`
Expand Down
47 changes: 36 additions & 11 deletions docs/.vitepress/theme/catalog/Toggles.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@ const colors = [null].concat(formColors.filter(color => !isLight(color)));
const lightenColors = formColors.filter(isLight);
const animals = ['cow', 'horse', 'pig'];

function toggleClass(color, activeColor) {
function toggleClass(color, activeColor, size) {
return [
'toggle',
color ? `toggle--${color}` : '',
activeColor ? `toggle--active-${activeColor}` : ''
activeColor ? `toggle--active-${activeColor}` : '',
size ? `toggle--${size}` : ''
]
.filter(Boolean)
.join(' ');
}

function groupClass(small) {
return small ? 'mb12 mr12 toggle-group toggle-group--s txt-s' : 'mb12 mr12 toggle-group';
}
const groupClass = 'mb12 mr12 toggle-group';

function groupName(prefix, color, extra) {
return `${prefix}-${color || 'default'}-${extra || 'on'}`;
Expand All @@ -41,7 +40,7 @@ function groupName(prefix, color, extra) {
<div
v-for="color in colors"
:key="`a-${active}-${color}`"
:class="groupClass(false)"
:class="groupClass"
>
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
Expand All @@ -57,7 +56,7 @@ function groupName(prefix, color, extra) {
</div>
<div class="mb12 txt-bold color-darken50 txt-uppercase txt-s">Disabled</div>
<div class="mb24">
<div v-for="color in colors" :key="`d-${color}`" :class="groupClass(false)">
<div v-for="color in colors" :key="`d-${color}`" :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
disabled
Expand All @@ -69,24 +68,50 @@ function groupName(prefix, color, extra) {
<div :class="toggleClass(color)">{{ label }}</div>
</label>
</div>
<div :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
disabled
:name="groupName('disabled', 'active', 'blue')"
:value="label"
:checked="index === 1"
type="radio"
/>
<div :class="toggleClass(null, 'blue')">{{ label }}</div>
</label>
</div>
</div>
<div class="mb12 txt-bold color-darken50 txt-uppercase txt-s">Small</div>
<div class="mb24">
<div v-for="color in colors" :key="`s-${color}`" :class="groupClass(true)">
<div v-for="color in colors" :key="`s-${color}`" :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
:name="groupName('small', color)"
:value="label"
:checked="index === 1"
type="radio"
/>
<div :class="toggleClass(color)">{{ label }}</div>
<div :class="toggleClass(color, null, 's')">{{ label }}</div>
</label>
</div>
</div>
<div class="mb12 txt-bold color-darken50 txt-uppercase txt-s">Large</div>
<div class="mb24">
<div v-for="color in colors" :key="`lg-${color}`" :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
:name="groupName('large', color)"
:value="label"
:checked="index === 1"
type="radio"
/>
<div :class="toggleClass(color, null, 'l')">{{ label }}</div>
</label>
</div>
</div>
<div class="mb12 txt-bold color-darken50 txt-uppercase txt-s">Light variations</div>
<div class="bg-gray round px12 py12 mt12">
<div v-for="color in lightenColors" :key="`l-${color}`" :class="groupClass(false)">
<div v-for="color in lightenColors" :key="`l-${color}`" :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
:name="groupName('light', color)"
Expand All @@ -102,7 +127,7 @@ function groupName(prefix, color, extra) {
Disabled and light
</div>
<div class="bg-gray round px12 py12 mt12">
<div v-for="color in lightenColors" :key="`ld-${color}`" :class="groupClass(false)">
<div v-for="color in lightenColors" :key="`ld-${color}`" :class="groupClass">
<label v-for="(label, index) in animals" :key="label" class="toggle-container">
<input
disabled
Expand Down
59 changes: 56 additions & 3 deletions docs/documentation/forms.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ The toggle group component styles a set of `<input type=radio'>` elements. The m
Style a toggle group.
Change the inactive toggle text color and the active toggle background color with a `toggle--{color}` modifier (`*-dark` colors are not available).
Change the active label color with a `toggle--active-{color}` modifier (`*-dark` colors are not available).
Change the border radiuses of toggle groups inside small text with `toggle-group--s` on the `toggle-container` element.
Change the group background color by adding a `bg-{color}` class to the `toggle-group` element.

```example
<div class='toggle-group mr18'>
Expand All @@ -434,16 +434,59 @@ Change the border radiuses of toggle groups inside small text with `toggle-group
<div class='toggle'>dog</div>
</label>
</div>
<div class='toggle-group bg-blue-faint'>
<label class='toggle-container'>
<input checked name='toggle-2' type='radio' />
<div class='toggle toggle--blue'>cat</div>
</label>
<label class='toggle-container'>
<input name='toggle-2' type='radio' />
<div class='toggle toggle--blue'>dog</div>
</label>
</div>
```

Toggle labels don't wrap. To fit a group with long labels to its container, add `wmax-full` to the `toggle-group`, then either:

- **Truncate:** add `wmin0` to the long label's `toggle-container` and `txt-truncate align-center py3` to its `toggle`. Add `flex-child-no-shrink` to other `toggle-container` elements to keep them whole.
- **Wrap:** add `flex` to each `toggle-container` and `txt-wrap align-center h-auto hmin24 py3` to each `toggle`. Use `hmin18` with `toggle--s` or `hmin36` with `toggle--l`.

```example
<div class='w240 mb12'>
<div class='toggle-group wmax-full'>
<label class='toggle-container wmin0'>
<input checked name='toggle-truncate' type='radio' />
<div class='toggle txt-truncate align-center py3'>The quick brown fox jumped over the lazy dog</div>
</label>
<label class='toggle-container flex-child-no-shrink'>
<input name='toggle-truncate' type='radio' />
<div class='toggle'>dog</div>
</label>
</div>
</div>
<div class='w240'>
<div class='toggle-group wmax-full'>
<label class='toggle-container flex'>
<input checked name='toggle-wrap' type='radio' />
<div class='toggle txt-wrap align-center h-auto hmin24 py3'>The quick brown fox jumped over the lazy dog</div>
</label>
<label class='toggle-container flex'>
<input name='toggle-wrap' type='radio' />
<div class='toggle txt-wrap align-center h-auto hmin24 py3'>dog</div>
</label>
</div>
</div>
```

```selectors
.toggle--s
.toggle--l
```

Make a toggle small.
Change the toggle height. `toggle--s` is 18px tall, the default `toggle` is 24px to match `input--s`, and `toggle--l` is 36px to match `input`.

```example
<div class='toggle-group'>
<div class='toggle-group mr18'>
<label class='toggle-container'>
<input checked name='toggle-small' type='radio' />
<div class='toggle toggle--s'>mouse</div>
Expand All @@ -453,6 +496,16 @@ Make a toggle small.
<div class='toggle toggle--s'>cricket</div>
</label>
</div>
<div class='toggle-group'>
<label class='toggle-container'>
<input checked name='toggle-large' type='radio' />
<div class='toggle toggle--l'>horse</div>
</label>
<label class='toggle-container'>
<input name='toggle-large' type='radio' />
<div class='toggle toggle--l'>ox</div>
</label>
</div>
```

```selectors
Expand Down
12 changes: 12 additions & 0 deletions docs/documentation/typography.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,18 @@ Prevent text from wrapping.
</div>
```

```selectors
.txt-wrap
```

Allow text to wrap, overriding `white-space: nowrap` set by a component or `txt-nowrap`.

```example
<div class='border border--gray w60 txt-nowrap'>
<span class='txt-wrap'>This text wraps inside its container</span>
</div>
```

```selectors
.txt-break-word
```
Expand Down
4 changes: 1 addition & 3 deletions src/preset/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -778,17 +778,15 @@ input:checked + .checkbox {
translate: 18px;
}
input:checked + .toggle {
background: var(--gray);
background: var(--gray-deep);
color: var(--white);
}
input:disabled + .toggle {
pointer-events: none;
color: var(--darken25);
border-color: var(--transparent);
}
input:checked:disabled + .toggle {
background-color: var(--disabled25);
color: var(--darken25);
}
body,
input,
Expand Down
20 changes: 19 additions & 1 deletion src/preset/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,30 @@ function colorRules(config) {
[s => s, { color: `var(--${color})` }],
[s => `input:checked + ${s}`, { background: `var(--${color})` }]
]);
if (color === 'white' || color.startsWith('lighten')) {
append(`toggle--${color}`, [
[
s => `.toggle-group:has(${s})`,
{ 'background-color': 'var(--lighten10)' }
],
[s => `input:checked + ${s}`, { color: 'var(--gray-dark)' }],
// `.toggle` outranks the checked color above for checked + disabled.
[s => `input:disabled + .toggle${s}`, { color: 'var(--lighten25)' }]
]);
} else if (color.startsWith('darken')) {
append(`toggle--${color}`, [
[
s => `.toggle-group:has(${s})`,
{ 'background-color': 'var(--darken5)' }
]
]);
}
});

colorsFor(resolved, 'toggleActive').forEach(color => {
if (isNotAccessibleForForms(color)) return;
append(`toggle--active-${color}`, [
[s => `input:checked + ${s}`, { color: `var(--${color})` }]
[s => `input:checked:enabled + ${s}`, { color: `var(--${color})` }]
]);
});

Expand Down
35 changes: 27 additions & 8 deletions src/preset/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,26 @@ const UTILITY_RULES = [
['switch--s', { width: '30px', height: '18px' }],
[
'toggle-group',
{ display: 'inline-flex', 'text-align': 'center', 'border-radius': '18px' }
{
display: 'inline-flex',
'background-color': 'var(--gray-faint)',
'border-radius': 'var(--border-radius)'
}
],
['toggle-container', { 'max-width': '100%' }],
[
'toggle',
{
'flex-shrink': '0',
display: 'flex',
'align-items': 'center',
'justify-content': 'center',
height: '24px',
padding: '0 18px',
cursor: 'pointer',
color: 'var(--gray)',
color: 'var(--gray-deep)',
'font-size': 'var(--font-size-s)',
padding: '3px 18px',
'border-radius': '15px',
'line-height': 'var(--line-height-s)',
'white-space': 'nowrap',
'border-radius': 'var(--border-radius)',
'background-color': 'var(--transparent)',
transition:
'color var(--transition),\n background-color var(--transition)'
Expand All @@ -176,9 +184,19 @@ const UTILITY_RULES = [
[
'toggle--s',
{
height: '18px',
padding: '0 12px',
'font-size': 'var(--font-size-xs)',
'line-height': 'var(--line-height-s)',
padding: '0 12px'
'line-height': 'var(--line-height-xs)'
}
],
[
'toggle--l',
{
height: '36px',
padding: '0 24px',
'font-size': 'var(--font-size-m)',
'line-height': 'var(--line-height-m)'
}
],
['txt-mono', { 'font-family': 'var(--font-stack-mono)', 'font-size': '90%' }],
Expand Down Expand Up @@ -260,6 +278,7 @@ const UTILITY_RULES = [
['txt-capitalize-first', { 'text-transform': 'lowercase !important' }],
['txt-underline', { 'text-decoration': 'underline !important' }],
['txt-nowrap', { 'white-space': 'nowrap !important' }],
['txt-wrap', { 'white-space': 'normal !important' }],
['txt-break-word', { 'overflow-wrap': 'anywhere !important' }],
[
'txt-truncate',
Expand Down
Loading
Loading