You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
7.1 KiB
236 lines
7.1 KiB
/*
|
|
* GridList recipe — role="grid" list with interactive row children.
|
|
*
|
|
* [data-grid-list] → root container
|
|
* [data-grid-list-row] → row, focusable, [data-selected]
|
|
* [data-grid-list-cell] → cell slot
|
|
* [data-grid-list-selection-checkbox] → per-row selection box
|
|
*
|
|
* Sizes — xs..xl drive row height + font-size.
|
|
* Variant `'surface' | 'outline' | 'ghost'` (ControlVariant).
|
|
* Color cascades the accent for selected rows + focus ring.
|
|
*
|
|
* Cross-component reuse: SelectionCheckbox uses the menu-indicator
|
|
* recipe family (see `lib/menu-indicator.css`) — the indicator inside
|
|
* the soma part will pick up that visual when the row is selected.
|
|
* Row hover/highlight tokens mirror Combobox.Item + Listbox.Item.
|
|
*
|
|
* Disambiguation: use GridList for rows with interactive children
|
|
* (buttons / links / checkbox). Use Listbox for atomic text options
|
|
* (ARIA forbids interactive descendants inside role="listbox").
|
|
*/
|
|
|
|
[data-grid-list] {
|
|
--_grid-list-row-height: var(--control-height-md);
|
|
--_grid-list-row-px: var(--space-3);
|
|
--_grid-list-font-size: var(--font-size-sm);
|
|
--_grid-list-max-height: min(60vh, 22rem);
|
|
--_grid-list-accent: var(--color-primary-solid);
|
|
--_grid-list-accent-soft: var(--color-primary-element);
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 1px;
|
|
padding: var(--space-1);
|
|
border: 1px solid var(--color-border-default);
|
|
border-radius: var(--radius-md);
|
|
background: var(--color-surface-default);
|
|
color: var(--color-content-primary);
|
|
font-family: var(--font-ui);
|
|
font-size: var(--_grid-list-font-size);
|
|
line-height: var(--leading-ui);
|
|
outline: none;
|
|
max-block-size: var(--_grid-list-max-height);
|
|
overflow-y: auto;
|
|
overscroll-behavior: contain;
|
|
}
|
|
|
|
[data-grid-list][data-block] {
|
|
inline-size: 100%;
|
|
}
|
|
|
|
/* ── Variant ─ */
|
|
[data-grid-list][data-variant='outline'] {
|
|
background: transparent;
|
|
}
|
|
|
|
[data-grid-list][data-variant='ghost'] {
|
|
background: transparent;
|
|
border-color: transparent;
|
|
}
|
|
|
|
/* ── Sizes ─ */
|
|
[data-grid-list][data-size='xs'] {
|
|
--_grid-list-row-height: var(--control-height-xs);
|
|
--_grid-list-row-px: var(--space-2);
|
|
--_grid-list-font-size: var(--font-size-xs);
|
|
}
|
|
|
|
[data-grid-list][data-size='sm'] {
|
|
--_grid-list-row-height: var(--control-height-sm);
|
|
--_grid-list-row-px: var(--space-2);
|
|
--_grid-list-font-size: var(--font-size-sm);
|
|
}
|
|
|
|
[data-grid-list][data-size='lg'] {
|
|
--_grid-list-row-height: var(--control-height-lg);
|
|
--_grid-list-row-px: var(--space-4);
|
|
--_grid-list-font-size: var(--font-size-md);
|
|
}
|
|
|
|
[data-grid-list][data-size='xl'] {
|
|
--_grid-list-row-height: var(--control-height-xl);
|
|
--_grid-list-row-px: var(--space-5);
|
|
--_grid-list-font-size: var(--font-size-lg);
|
|
}
|
|
|
|
/* ── Color cascades ─ */
|
|
[data-grid-list][data-color='secondary'] {
|
|
--_grid-list-accent: var(--color-secondary-solid);
|
|
--_grid-list-accent-soft: var(--color-secondary-element);
|
|
}
|
|
[data-grid-list][data-color='affirm'] {
|
|
--_grid-list-accent: var(--color-affirm-solid);
|
|
--_grid-list-accent-soft: var(--color-affirm-element);
|
|
}
|
|
[data-grid-list][data-color='risk'] {
|
|
--_grid-list-accent: var(--color-risk-solid);
|
|
--_grid-list-accent-soft: var(--color-risk-element);
|
|
}
|
|
[data-grid-list][data-color='threat'] {
|
|
--_grid-list-accent: var(--color-threat-solid);
|
|
--_grid-list-accent-soft: var(--color-threat-element);
|
|
}
|
|
[data-grid-list][data-color='fulfill'] {
|
|
--_grid-list-accent: var(--color-fulfill-solid);
|
|
--_grid-list-accent-soft: var(--color-fulfill-element);
|
|
}
|
|
[data-grid-list][data-color='loss'] {
|
|
--_grid-list-accent: var(--color-loss-solid);
|
|
--_grid-list-accent-soft: var(--color-loss-element);
|
|
}
|
|
[data-grid-list][data-color='neutral'] {
|
|
--_grid-list-accent: var(--color-neutral-solid);
|
|
--_grid-list-accent-soft: var(--color-neutral-element);
|
|
}
|
|
|
|
[data-grid-list][data-disabled] {
|
|
opacity: 0.55;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
[data-grid-list][data-invalid] {
|
|
border-color: var(--color-threat-element);
|
|
}
|
|
|
|
[data-grid-list]:focus-visible,
|
|
[data-grid-list][data-focused] {
|
|
outline: var(--focus-ring-width) solid var(--focus-ring-color);
|
|
outline-offset: var(--focus-ring-offset);
|
|
}
|
|
|
|
/* ── Row ─ */
|
|
[data-grid-list-row] {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--space-2);
|
|
min-block-size: var(--_grid-list-row-height);
|
|
padding-block: var(--space-1);
|
|
padding-inline: var(--_grid-list-row-px);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--color-content-primary);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition:
|
|
background var(--duration-fast) var(--ease-default),
|
|
color var(--duration-fast) var(--ease-default);
|
|
}
|
|
|
|
[data-grid-list-row]:hover:not([data-disabled]),
|
|
[data-grid-list-row][data-highlighted]:not([data-disabled]) {
|
|
background: var(--color-surface-overlay);
|
|
}
|
|
|
|
[data-grid-list-row][data-selected]:not([data-disabled]) {
|
|
background: var(--_grid-list-accent-soft);
|
|
}
|
|
|
|
[data-grid-list-row][data-disabled] {
|
|
color: var(--color-content-muted);
|
|
cursor: default;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
[data-grid-list-row]:focus-visible {
|
|
outline: var(--focus-ring-width) solid var(--focus-ring-color);
|
|
outline-offset: -1px;
|
|
}
|
|
|
|
/* ── Cell ─ */
|
|
[data-grid-list-cell] {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
}
|
|
|
|
[data-grid-list-cell]:first-of-type {
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
[data-grid-list-cell]:nth-of-type(2) {
|
|
flex: 1 1 auto;
|
|
min-inline-size: 0;
|
|
}
|
|
|
|
[data-grid-list-cell]:last-of-type:not(:first-of-type):not(:nth-of-type(2)) {
|
|
flex: 0 0 auto;
|
|
margin-inline-start: auto;
|
|
}
|
|
|
|
/* ── SelectionCheckbox ─
|
|
*
|
|
* Soma renders a `[data-grid-list-selection-checkbox]` element with
|
|
* `data-state="checked"` / "unchecked". Reuse the menu-indicator visual
|
|
* pattern: empty outlined square → filled accent + white ✓.
|
|
*/
|
|
[data-grid-list-selection-checkbox] {
|
|
--_grid-list-checkbox-size: 0.875rem;
|
|
position: relative;
|
|
display: inline-flex;
|
|
flex: 0 0 auto;
|
|
inline-size: var(--_grid-list-checkbox-size);
|
|
block-size: var(--_grid-list-checkbox-size);
|
|
border: 1px solid var(--color-border-default);
|
|
border-radius: 0.2rem;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
outline: none;
|
|
transition:
|
|
background var(--duration-fast) var(--ease-default),
|
|
border-color var(--duration-fast) var(--ease-default);
|
|
}
|
|
|
|
[data-grid-list-selection-checkbox][data-state='checked'] {
|
|
border-color: var(--_grid-list-accent);
|
|
background: var(--_grid-list-accent);
|
|
}
|
|
|
|
[data-grid-list-selection-checkbox][data-state='checked']::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
background-color: var(--color-content-on-solid);
|
|
mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12.5L10 17.5L19 7'/></svg>");
|
|
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12.5L10 17.5L19 7'/></svg>");
|
|
mask-repeat: no-repeat;
|
|
mask-position: center;
|
|
mask-size: contain;
|
|
-webkit-mask-repeat: no-repeat;
|
|
-webkit-mask-position: center;
|
|
-webkit-mask-size: contain;
|
|
}
|
|
|
|
[data-grid-list-selection-checkbox]:focus-visible {
|
|
outline: var(--focus-ring-width) solid var(--focus-ring-color);
|
|
outline-offset: 1px;
|
|
}
|