Skip to content

Commit d832b9d

Browse files
committed
Add the design-system controls the organization surface needs
New: Checkbox, MultiSelect, DatePicker, DateRangePicker, CopyField, SecretField, FileField, StatusTag, InlineNotice and Pagination. Extended, with existing callers unchanged: DataTable (custom cells, row target, row action, sort, paging, windowing), SearchableSelect (server search), RecipientField (controlled, validate, error), EmptyState graphic, SettingsRow leading art, Switch disabled, and text field hints and native attributes. The workbench's controls page consumes each new export until feature routes do.
1 parent 8b65e98 commit d832b9d

38 files changed

Lines changed: 2413 additions & 185 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { Metadata } from 'next'
2+
import { ControlsWorkbench } from '@/platform/preview/controls-workbench'
3+
4+
export const metadata: Metadata = {
5+
title: 'Platform form and data controls',
6+
description: 'Exercise the form, status and data table controls in either theme.',
7+
}
8+
9+
interface ControlsPageProps {
10+
searchParams: Promise<Record<string, string | string[] | undefined>>
11+
}
12+
13+
export default async function Page({ searchParams }: ControlsPageProps) {
14+
const { theme } = await searchParams
15+
return <ControlsWorkbench theme={theme === 'dark' ? 'dark' : 'light'} />
16+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.checkbox {
2+
display: inline-flex;
3+
align-items: flex-start;
4+
min-inline-size: 0;
5+
gap: var(--ui-row-gap);
6+
color: var(--ui-ink);
7+
cursor: pointer;
8+
}
9+
10+
.checkbox[data-disabled] {
11+
opacity: var(--opacity-disabled);
12+
cursor: default;
13+
}
14+
15+
.box {
16+
display: inline-grid;
17+
flex: none;
18+
place-items: center;
19+
inline-size: var(--spacing-16);
20+
block-size: var(--spacing-16);
21+
margin-block-start: var(--spacing-2);
22+
border: var(--spacing-stroke-default) solid var(--ui-border);
23+
border-radius: var(--radius-4);
24+
background: var(--ui-reading);
25+
}
26+
27+
.checkbox:not([data-disabled]):hover .box:not([data-checked], [data-indeterminate]) {
28+
border-color: var(--control-hover-border);
29+
}
30+
31+
.box:is([data-checked], [data-indeterminate]) {
32+
border-color: var(--control-primary-fill);
33+
background: var(--control-primary-fill);
34+
}
35+
36+
.indicator {
37+
display: inline-grid;
38+
place-items: center;
39+
}
40+
41+
.dash {
42+
inline-size: var(--spacing-8);
43+
block-size: var(--spacing-stroke-default);
44+
background: var(--control-on-solid);
45+
}
46+
47+
.copy {
48+
display: grid;
49+
min-inline-size: 0;
50+
gap: var(--ui-stack-gap);
51+
overflow-wrap: anywhere;
52+
}
53+
54+
.description {
55+
color: var(--ui-secondary);
56+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use client'
2+
3+
import { useId } from 'react'
4+
import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox'
5+
import styles from '@/platform/design-system/components/checkbox/checkbox.module.css'
6+
import { Icon } from '@/platform/design-system/components/icon/icon'
7+
8+
interface CheckboxProps {
9+
label: string
10+
description?: string
11+
/** Name the box for assistive technology only, for a grid or table that labels it visually. */
12+
labelHidden?: boolean
13+
checked?: boolean
14+
defaultChecked?: boolean
15+
indeterminate?: boolean
16+
disabled?: boolean
17+
name?: string
18+
value?: string
19+
onCheckedChange?: (checked: boolean) => void
20+
}
21+
22+
export function Checkbox({
23+
label,
24+
description,
25+
labelHidden,
26+
checked,
27+
defaultChecked,
28+
indeterminate,
29+
disabled,
30+
name,
31+
value,
32+
onCheckedChange,
33+
}: CheckboxProps) {
34+
const id = useId()
35+
return (
36+
<label htmlFor={id} className={styles.checkbox} data-disabled={disabled || undefined}>
37+
<BaseCheckbox.Root
38+
id={id}
39+
className={styles.box}
40+
checked={checked}
41+
defaultChecked={defaultChecked}
42+
indeterminate={indeterminate}
43+
disabled={disabled}
44+
name={name}
45+
value={value}
46+
onCheckedChange={onCheckedChange}
47+
>
48+
<BaseCheckbox.Indicator className={styles.indicator} data-solid data-type='T050'>
49+
{indeterminate ? <span className={styles.dash} /> : <Icon name='I072' />}
50+
</BaseCheckbox.Indicator>
51+
</BaseCheckbox.Root>
52+
<span className={styles.copy} data-visually-hidden={labelHidden || undefined}>
53+
<span data-type='T043'>{label}</span>
54+
{description && (
55+
<span className={styles.description} data-type='T060'>
56+
{description}
57+
</span>
58+
)}
59+
</span>
60+
</label>
61+
)
62+
}

‎apps/sim/platform/design-system/components/data-display/data-display.module.css‎

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
inline-size: calc(var(--ui-table-wide) + var(--spacing-16));
6767
}
6868
.table th {
69-
height: var(--spacing-app-control-md);
69+
height: var(--ui-table-head);
7070
}
7171
.table td {
7272
height: var(--spacing-40);
@@ -76,6 +76,56 @@
7676
background: var(--ui-hover);
7777
clip-path: inset(0 round var(--radius-item));
7878
}
79+
.table tbody tr.spacer:hover {
80+
background: transparent;
81+
}
82+
.table .spacer td {
83+
height: auto;
84+
padding: 0;
85+
}
86+
.table tr[data-openable] {
87+
position: relative;
88+
cursor: pointer;
89+
}
90+
.rowTarget {
91+
display: block;
92+
inline-size: 100%;
93+
color: inherit;
94+
text-align: inherit;
95+
cursor: pointer;
96+
}
97+
.rowTarget::after {
98+
position: absolute;
99+
inset: 0;
100+
content: "";
101+
}
102+
.table [data-kind="action"] {
103+
position: relative;
104+
inline-size: calc(var(--spacing-app-control-sm) + var(--spacing-16));
105+
padding-inline: 0;
106+
text-align: end;
107+
}
108+
.sort {
109+
display: inline-flex;
110+
align-items: center;
111+
gap: var(--ui-action-gap);
112+
color: inherit;
113+
cursor: pointer;
114+
}
115+
.virtualViewport {
116+
max-block-size: calc(100dvh - var(--ui-table-viewport-offset));
117+
overflow: auto;
118+
overscroll-behavior: contain;
119+
}
120+
.virtualViewport .table {
121+
inline-size: 100%;
122+
}
123+
.virtualViewport th {
124+
position: sticky;
125+
inset-block-start: 0;
126+
z-index: 1;
127+
background: var(--ui-canvas);
128+
}
79129
@container (width < 48rem) {
80130
.table [data-from="wide"] {
81131
display: none;
@@ -102,7 +152,6 @@
102152
.header {
103153
min-block-size: var(--spacing-app-touch-target);
104154
}
105-
.table th,
106155
.table td {
107156
height: var(--spacing-app-touch-target);
108157
}

0 commit comments

Comments
 (0)