remix 3.0.0-beta.3 → 3.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/accordion/primitives.d.ts +2 -0
- package/dist/ui/accordion/primitives.d.ts.map +1 -0
- package/dist/ui/accordion/primitives.js +2 -0
- package/dist/ui/button.d.ts +1 -0
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +1 -0
- package/dist/ui/checkbox.d.ts +3 -0
- package/dist/ui/checkbox.d.ts.map +1 -0
- package/dist/ui/checkbox.js +3 -0
- package/dist/ui/combobox/primitives.d.ts +2 -0
- package/dist/ui/combobox/primitives.d.ts.map +1 -0
- package/dist/ui/combobox/primitives.js +2 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.d.ts.map +1 -0
- package/dist/ui/input.js +3 -0
- package/dist/ui/menu/primitives.d.ts +2 -0
- package/dist/ui/menu/primitives.d.ts.map +1 -0
- package/dist/ui/{glyph.js → menu/primitives.js} +1 -1
- package/dist/ui/radio.d.ts +3 -0
- package/dist/ui/radio.d.ts.map +1 -0
- package/dist/ui/radio.js +3 -0
- package/dist/ui/select/primitives.d.ts +2 -0
- package/dist/ui/select/primitives.d.ts.map +1 -0
- package/dist/ui/select/primitives.js +2 -0
- package/dist/ui/tabs/primitives.d.ts +2 -0
- package/dist/ui/tabs/primitives.d.ts.map +1 -0
- package/dist/ui/{theme.js → tabs/primitives.js} +1 -1
- package/dist/ui/tabs.d.ts +2 -0
- package/dist/ui/tabs.d.ts.map +1 -0
- package/{src/ui/glyph.ts → dist/ui/tabs.js} +1 -1
- package/dist/ui/toggle/primitives.d.ts +2 -0
- package/dist/ui/toggle/primitives.d.ts.map +1 -0
- package/dist/ui/toggle/primitives.js +2 -0
- package/dist/ui/toggle.d.ts +3 -0
- package/dist/ui/toggle.d.ts.map +1 -0
- package/dist/ui/toggle.js +3 -0
- package/package.json +76 -47
- package/src/assert/README.md +11 -4
- package/src/data-table-mysql/README.md +25 -0
- package/src/data-table-postgres/README.md +26 -0
- package/src/fetch-router/README.md +115 -35
- package/src/form-data-parser/README.md +4 -4
- package/src/mime/README.md +8 -1
- package/src/node-fetch-server/README.md +28 -2
- package/src/route-pattern/README.md +51 -6
- package/src/session/README.md +1 -1
- package/src/test/README.md +27 -0
- package/src/ui/README.md +50 -164
- package/src/ui/accordion/README.md +50 -14
- package/src/ui/accordion/primitives/README.md +202 -0
- package/src/ui/accordion/primitives.ts +2 -0
- package/src/ui/anchor/README.md +37 -2
- package/src/ui/breadcrumbs/README.md +4 -4
- package/src/ui/button/README.md +26 -26
- package/src/ui/button.ts +1 -0
- package/src/ui/checkbox/README.md +59 -0
- package/src/ui/checkbox.ts +3 -0
- package/src/ui/combobox/README.md +58 -9
- package/src/ui/combobox/primitives/README.md +194 -0
- package/src/ui/combobox/primitives.ts +2 -0
- package/src/ui/input/README.md +52 -0
- package/src/ui/input.ts +3 -0
- package/src/ui/listbox/README.md +9 -41
- package/src/ui/menu/README.md +55 -14
- package/src/ui/menu/primitives/README.md +161 -0
- package/{dist/ui/scroll-lock.js → src/ui/menu/primitives.ts} +1 -1
- package/src/ui/popover/README.md +20 -39
- package/src/ui/radio/README.md +53 -0
- package/src/ui/radio.ts +3 -0
- package/src/ui/select/README.md +29 -19
- package/src/ui/select/primitives/README.md +117 -0
- package/src/ui/select/primitives.ts +2 -0
- package/src/ui/tabs/README.md +141 -0
- package/src/ui/tabs/primitives/README.md +141 -0
- package/{dist/ui/separator.js → src/ui/tabs/primitives.ts} +1 -1
- package/src/ui/{theme.ts → tabs.ts} +1 -1
- package/src/ui/toggle/README.md +56 -0
- package/src/ui/toggle/primitives/README.md +56 -0
- package/src/ui/toggle/primitives.ts +2 -0
- package/src/ui/toggle.ts +3 -0
- package/dist/ui/glyph.d.ts +0 -2
- package/dist/ui/glyph.d.ts.map +0 -1
- package/dist/ui/scroll-lock.d.ts +0 -2
- package/dist/ui/scroll-lock.d.ts.map +0 -1
- package/dist/ui/separator.d.ts +0 -2
- package/dist/ui/separator.d.ts.map +0 -1
- package/dist/ui/theme.d.ts +0 -2
- package/dist/ui/theme.d.ts.map +0 -1
- package/src/ui/glyph/README.md +0 -72
- package/src/ui/scroll-lock/README.md +0 -33
- package/src/ui/scroll-lock.ts +0 -2
- package/src/ui/separator.ts +0 -2
- package/src/ui/theme/README.md +0 -103
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# tabs
|
|
2
|
+
|
|
3
|
+
`Tabs` renders a tab control with one active tab and matching panels. Use it when related views share the same page space and the owning component may either control the active tab or let the tabs context manage it.
|
|
4
|
+
|
|
5
|
+
## Component Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
9
|
+
|
|
10
|
+
export function ProjectTabs() {
|
|
11
|
+
return (
|
|
12
|
+
<Tabs defaultActiveTab="overview">
|
|
13
|
+
<TabList aria-label="Project sections">
|
|
14
|
+
<Tab name="overview">Overview</Tab>
|
|
15
|
+
<Tab name="activity">Activity</Tab>
|
|
16
|
+
<Tab name="settings">Settings</Tab>
|
|
17
|
+
</TabList>
|
|
18
|
+
|
|
19
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
20
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
21
|
+
<TabPanel name="settings">Project settings.</TabPanel>
|
|
22
|
+
</Tabs>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Control the active tab when state should live in the owning component:
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import type { Handle } from 'remix/ui'
|
|
31
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
32
|
+
|
|
33
|
+
export function ControlledTabs(handle: Handle) {
|
|
34
|
+
let activeTab = 'overview'
|
|
35
|
+
|
|
36
|
+
return () => (
|
|
37
|
+
<Tabs
|
|
38
|
+
activeTab={activeTab}
|
|
39
|
+
onActiveTabChange={(nextActiveTab) => {
|
|
40
|
+
activeTab = nextActiveTab
|
|
41
|
+
void handle.update()
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<TabList aria-label="Project sections">
|
|
45
|
+
<Tab name="overview">Overview</Tab>
|
|
46
|
+
<Tab name="activity">Activity</Tab>
|
|
47
|
+
</TabList>
|
|
48
|
+
|
|
49
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
50
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
51
|
+
</Tabs>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Listen for bubbling `TabsChangeEvent` events with `onTabsChange` from `remix/ui/tabs/primitives`.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { onTabsChange } from 'remix/ui/tabs/primitives'
|
|
60
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
61
|
+
|
|
62
|
+
export function TrackedTabs() {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
mix={[
|
|
66
|
+
onTabsChange((event) => {
|
|
67
|
+
console.log(event.previousActiveTab, event.activeTab)
|
|
68
|
+
}),
|
|
69
|
+
]}
|
|
70
|
+
>
|
|
71
|
+
<Tabs defaultActiveTab="overview">
|
|
72
|
+
<TabList aria-label="Project sections">
|
|
73
|
+
<Tab name="overview">Overview</Tab>
|
|
74
|
+
<Tab name="activity">Activity</Tab>
|
|
75
|
+
</TabList>
|
|
76
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
77
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
78
|
+
</Tabs>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Primitive Usage
|
|
85
|
+
|
|
86
|
+
Use the lower-level primitives when app code owns the markup and styles:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import * as tabs from 'remix/ui/tabs/primitives'
|
|
90
|
+
import { listStyle, panelStyle, rootStyle, tabStyle } from './tabs.styles'
|
|
91
|
+
|
|
92
|
+
export function PrimitiveTabs() {
|
|
93
|
+
return (
|
|
94
|
+
<tabs.Context defaultActiveTab="overview">
|
|
95
|
+
<div mix={[rootStyle, tabs.root()]}>
|
|
96
|
+
<div mix={[listStyle, tabs.list()]} aria-label="Project sections">
|
|
97
|
+
<button mix={[tabStyle, tabs.tab({ name: 'overview' })]} type="button">
|
|
98
|
+
Overview
|
|
99
|
+
</button>
|
|
100
|
+
<button mix={[tabStyle, tabs.tab({ name: 'activity' })]} type="button">
|
|
101
|
+
Activity
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div mix={[panelStyle, tabs.panel({ name: 'overview' })]}>Project summary.</div>
|
|
106
|
+
<div mix={[panelStyle, tabs.panel({ name: 'activity' })]}>Recent changes.</div>
|
|
107
|
+
</div>
|
|
108
|
+
</tabs.Context>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## `remix/ui/tabs`
|
|
114
|
+
|
|
115
|
+
- `Tabs`: root component. Supports controlled `activeTab`, uncontrolled `defaultActiveTab`, `onActiveTabChange`, `disabled`, and `size: 'md' | 'lg'`.
|
|
116
|
+
- `TabList`: tablist wrapper that lays out the tabs in a track and applies the tablist primitive.
|
|
117
|
+
- `Tab`: button for one tab `name`. The active tab uses the toggle slider treatment and button-sized text. Pass `disabled` to prevent activation.
|
|
118
|
+
- `TabPanel`: panel for one tab `name`.
|
|
119
|
+
- `rootStyle`, `listStyle`, `tabStyle`, and `panelStyle`: flat style mixins used by the component markup.
|
|
120
|
+
- `onTabsChange` and `TabsChangeEvent`: re-exported primitive event helpers.
|
|
121
|
+
- `TabsProps`, `TabListProps`, `TabProps`, `TabPanelProps`, and `TabsSize`: public TypeScript types for the composed APIs.
|
|
122
|
+
|
|
123
|
+
## `remix/ui/tabs/primitives`
|
|
124
|
+
|
|
125
|
+
- `Context`: lower-level provider for custom tabs composition.
|
|
126
|
+
- `root()`: wires the root element and bubbling change events.
|
|
127
|
+
- `list()`: wires the tablist role and disabled state.
|
|
128
|
+
- `tab({ name, disabled })`: wires a tab button with selected state, ids, keyboard activation, and pointer activation.
|
|
129
|
+
- `panel({ name })`: wires the matching tab panel id, hidden state, inert state, and label relationship.
|
|
130
|
+
- `onTabsChange(...)`: event mixin for the bubbling `TabsChangeEvent`.
|
|
131
|
+
- `TabsChangeEvent`: bubbling event with `activeTab` and `previousActiveTab`.
|
|
132
|
+
- `TabsContextProps`, `TabsContextValue`, `TabsRegisteredTab`, `TabsActivationDirection`, `TabsRootOptions`, `TabListOptions`, `TabOptions`, and `TabPanelOptions`: primitive prop and option types for custom composition.
|
|
133
|
+
|
|
134
|
+
## Behavior Notes
|
|
135
|
+
|
|
136
|
+
- If neither `activeTab` nor `defaultActiveTab` is provided, the first enabled tab becomes active.
|
|
137
|
+
- Arrow keys activate the next or previous enabled tab. `Home` and `End` activate the first and last enabled tabs.
|
|
138
|
+
- `Enter`, `Space`, and pointer clicks activate the focused tab.
|
|
139
|
+
- Root `disabled` disables every tab. Tab `disabled` only disables that tab.
|
|
140
|
+
- Tabs and panels are linked with generated ids through `aria-controls`, `aria-labelledby`, and `aria-selected`.
|
|
141
|
+
- Inactive panels receive `hidden`, `inert`, and `data-state="inactive"`.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# tabs
|
|
2
|
+
|
|
3
|
+
`Tabs` renders a tab control with one active tab and matching panels. Use it when related views share the same page space and the owning component may either control the active tab or let the tabs context manage it.
|
|
4
|
+
|
|
5
|
+
## Component Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
9
|
+
|
|
10
|
+
export function ProjectTabs() {
|
|
11
|
+
return (
|
|
12
|
+
<Tabs defaultActiveTab="overview">
|
|
13
|
+
<TabList aria-label="Project sections">
|
|
14
|
+
<Tab name="overview">Overview</Tab>
|
|
15
|
+
<Tab name="activity">Activity</Tab>
|
|
16
|
+
<Tab name="settings">Settings</Tab>
|
|
17
|
+
</TabList>
|
|
18
|
+
|
|
19
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
20
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
21
|
+
<TabPanel name="settings">Project settings.</TabPanel>
|
|
22
|
+
</Tabs>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Control the active tab when state should live in the owning component:
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import type { Handle } from 'remix/ui'
|
|
31
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
32
|
+
|
|
33
|
+
export function ControlledTabs(handle: Handle) {
|
|
34
|
+
let activeTab = 'overview'
|
|
35
|
+
|
|
36
|
+
return () => (
|
|
37
|
+
<Tabs
|
|
38
|
+
activeTab={activeTab}
|
|
39
|
+
onActiveTabChange={(nextActiveTab) => {
|
|
40
|
+
activeTab = nextActiveTab
|
|
41
|
+
void handle.update()
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<TabList aria-label="Project sections">
|
|
45
|
+
<Tab name="overview">Overview</Tab>
|
|
46
|
+
<Tab name="activity">Activity</Tab>
|
|
47
|
+
</TabList>
|
|
48
|
+
|
|
49
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
50
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
51
|
+
</Tabs>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Listen for bubbling `TabsChangeEvent` events with `onTabsChange` from `remix/ui/tabs/primitives`.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { onTabsChange } from 'remix/ui/tabs/primitives'
|
|
60
|
+
import { Tabs, TabList, Tab, TabPanel } from 'remix/ui/tabs'
|
|
61
|
+
|
|
62
|
+
export function TrackedTabs() {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
mix={[
|
|
66
|
+
onTabsChange((event) => {
|
|
67
|
+
console.log(event.previousActiveTab, event.activeTab)
|
|
68
|
+
}),
|
|
69
|
+
]}
|
|
70
|
+
>
|
|
71
|
+
<Tabs defaultActiveTab="overview">
|
|
72
|
+
<TabList aria-label="Project sections">
|
|
73
|
+
<Tab name="overview">Overview</Tab>
|
|
74
|
+
<Tab name="activity">Activity</Tab>
|
|
75
|
+
</TabList>
|
|
76
|
+
<TabPanel name="overview">Project summary.</TabPanel>
|
|
77
|
+
<TabPanel name="activity">Recent changes.</TabPanel>
|
|
78
|
+
</Tabs>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Primitive Usage
|
|
85
|
+
|
|
86
|
+
Use the lower-level primitives when app code owns the markup and styles:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import * as tabs from 'remix/ui/tabs/primitives'
|
|
90
|
+
import { listStyle, panelStyle, rootStyle, tabStyle } from './tabs.styles'
|
|
91
|
+
|
|
92
|
+
export function PrimitiveTabs() {
|
|
93
|
+
return (
|
|
94
|
+
<tabs.Context defaultActiveTab="overview">
|
|
95
|
+
<div mix={[rootStyle, tabs.root()]}>
|
|
96
|
+
<div mix={[listStyle, tabs.list()]} aria-label="Project sections">
|
|
97
|
+
<button mix={[tabStyle, tabs.tab({ name: 'overview' })]} type="button">
|
|
98
|
+
Overview
|
|
99
|
+
</button>
|
|
100
|
+
<button mix={[tabStyle, tabs.tab({ name: 'activity' })]} type="button">
|
|
101
|
+
Activity
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div mix={[panelStyle, tabs.panel({ name: 'overview' })]}>Project summary.</div>
|
|
106
|
+
<div mix={[panelStyle, tabs.panel({ name: 'activity' })]}>Recent changes.</div>
|
|
107
|
+
</div>
|
|
108
|
+
</tabs.Context>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## `remix/ui/tabs`
|
|
114
|
+
|
|
115
|
+
- `Tabs`: root component. Supports controlled `activeTab`, uncontrolled `defaultActiveTab`, `onActiveTabChange`, `disabled`, and `size: 'md' | 'lg'`.
|
|
116
|
+
- `TabList`: tablist wrapper that lays out the tabs in a track and applies the tablist primitive.
|
|
117
|
+
- `Tab`: button for one tab `name`. The active tab uses the toggle slider treatment and button-sized text. Pass `disabled` to prevent activation.
|
|
118
|
+
- `TabPanel`: panel for one tab `name`.
|
|
119
|
+
- `rootStyle`, `listStyle`, `tabStyle`, and `panelStyle`: flat style mixins used by the component markup.
|
|
120
|
+
- `onTabsChange` and `TabsChangeEvent`: re-exported primitive event helpers.
|
|
121
|
+
- `TabsProps`, `TabListProps`, `TabProps`, `TabPanelProps`, and `TabsSize`: public TypeScript types for the composed APIs.
|
|
122
|
+
|
|
123
|
+
## `remix/ui/tabs/primitives`
|
|
124
|
+
|
|
125
|
+
- `Context`: lower-level provider for custom tabs composition.
|
|
126
|
+
- `root()`: wires the root element and bubbling change events.
|
|
127
|
+
- `list()`: wires the tablist role and disabled state.
|
|
128
|
+
- `tab({ name, disabled })`: wires a tab button with selected state, ids, keyboard activation, and pointer activation.
|
|
129
|
+
- `panel({ name })`: wires the matching tab panel id, hidden state, inert state, and label relationship.
|
|
130
|
+
- `onTabsChange(...)`: event mixin for the bubbling `TabsChangeEvent`.
|
|
131
|
+
- `TabsChangeEvent`: bubbling event with `activeTab` and `previousActiveTab`.
|
|
132
|
+
- `TabsContextProps`, `TabsContextValue`, `TabsRegisteredTab`, `TabsActivationDirection`, `TabsRootOptions`, `TabListOptions`, `TabOptions`, and `TabPanelOptions`: primitive prop and option types for custom composition.
|
|
133
|
+
|
|
134
|
+
## Behavior Notes
|
|
135
|
+
|
|
136
|
+
- If neither `activeTab` nor `defaultActiveTab` is provided, the first enabled tab becomes active.
|
|
137
|
+
- Arrow keys activate the next or previous enabled tab. `Home` and `End` activate the first and last enabled tabs.
|
|
138
|
+
- `Enter`, `Space`, and pointer clicks activate the focused tab.
|
|
139
|
+
- Root `disabled` disables every tab. Tab `disabled` only disables that tab.
|
|
140
|
+
- Tabs and panels are linked with generated ids through `aria-controls`, `aria-labelledby`, and `aria-selected`.
|
|
141
|
+
- Inactive panels receive `hidden`, `inert`, and `data-state="inactive"`.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// IMPORTANT: This file is auto-generated, please do not edit manually.
|
|
2
|
-
export * from '@remix-run/ui/
|
|
2
|
+
export * from '@remix-run/ui/tabs/primitives'
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// IMPORTANT: This file is auto-generated, please do not edit manually.
|
|
2
|
-
export * from '@remix-run/ui/
|
|
2
|
+
export * from '@remix-run/ui/tabs'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# toggle
|
|
2
|
+
|
|
3
|
+
`toggle` is a style mixin for checkbox inputs rendered as switches. Use native input props for normal form behavior, and compose it with `remix/ui/toggle/primitives` when you need the headless toggle state helpers or custom hosts.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import toggle from 'remix/ui/toggle'
|
|
9
|
+
|
|
10
|
+
function NotificationSetting() {
|
|
11
|
+
return () => (
|
|
12
|
+
<label>
|
|
13
|
+
<input mix={toggle({ size: 'lg' })} defaultChecked />
|
|
14
|
+
Email notifications
|
|
15
|
+
</label>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Primitive Usage
|
|
21
|
+
|
|
22
|
+
Use the lower-level primitive when app code needs normalized checked state, toggle change events, or a non-input host:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import toggle from 'remix/ui/toggle'
|
|
26
|
+
import * as togglePrimitive from 'remix/ui/toggle/primitives'
|
|
27
|
+
|
|
28
|
+
function CustomToggle() {
|
|
29
|
+
return () => (
|
|
30
|
+
<button
|
|
31
|
+
aria-label="Notifications"
|
|
32
|
+
mix={[...toggle(), togglePrimitive.control({ defaultChecked: true })]}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## `remix/ui/toggle`
|
|
39
|
+
|
|
40
|
+
- `toggle(options)`: styles a native checkbox input as a switch and supplies `type="checkbox"` plus `role="switch"` when the host is an `<input>` without an explicit non-checkbox `type`. Supports `size: 'md' | 'lg'` and defaults to `'md'`.
|
|
41
|
+
- `onToggleChange(handler)`: re-exported primitive event mixin.
|
|
42
|
+
- `ToggleChangeEvent`: re-exported primitive event class.
|
|
43
|
+
- `ToggleSize` and `ToggleOptions`: public TypeScript types for the style mixin.
|
|
44
|
+
|
|
45
|
+
## `remix/ui/toggle/primitives`
|
|
46
|
+
|
|
47
|
+
- `control(options)`: wires a boolean switch control with checked state, ARIA, keyboard, and native input behavior.
|
|
48
|
+
- `onToggleChange(handler)`: event mixin for bubbling toggle changes.
|
|
49
|
+
- `ToggleChangeEvent`: event class dispatched when a toggle changes.
|
|
50
|
+
- `ToggleControlOptions`: primitive options for controlled and uncontrolled state.
|
|
51
|
+
|
|
52
|
+
## Behavior Notes
|
|
53
|
+
|
|
54
|
+
- Checked styles apply through `:checked`, `[aria-checked="true"]`, or `[data-state="checked"]`.
|
|
55
|
+
- Native checkbox switches use the native `checked` attribute for state. Custom hosts use `role="switch"` and `aria-checked="true"` or `aria-checked="false"`.
|
|
56
|
+
- Every switch needs an accessible name, usually from visible label text, `aria-label`, or `aria-labelledby`.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# toggle
|
|
2
|
+
|
|
3
|
+
`toggle` is a style mixin for checkbox inputs rendered as switches. Use native input props for normal form behavior, and compose it with `remix/ui/toggle/primitives` when you need the headless toggle state helpers or custom hosts.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import toggle from 'remix/ui/toggle'
|
|
9
|
+
|
|
10
|
+
function NotificationSetting() {
|
|
11
|
+
return () => (
|
|
12
|
+
<label>
|
|
13
|
+
<input mix={toggle({ size: 'lg' })} defaultChecked />
|
|
14
|
+
Email notifications
|
|
15
|
+
</label>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Primitive Usage
|
|
21
|
+
|
|
22
|
+
Use the lower-level primitive when app code needs normalized checked state, toggle change events, or a non-input host:
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import toggle from 'remix/ui/toggle'
|
|
26
|
+
import * as togglePrimitive from 'remix/ui/toggle/primitives'
|
|
27
|
+
|
|
28
|
+
function CustomToggle() {
|
|
29
|
+
return () => (
|
|
30
|
+
<button
|
|
31
|
+
aria-label="Notifications"
|
|
32
|
+
mix={[...toggle(), togglePrimitive.control({ defaultChecked: true })]}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## `remix/ui/toggle`
|
|
39
|
+
|
|
40
|
+
- `toggle(options)`: styles a native checkbox input as a switch and supplies `type="checkbox"` plus `role="switch"` when the host is an `<input>` without an explicit non-checkbox `type`. Supports `size: 'md' | 'lg'` and defaults to `'md'`.
|
|
41
|
+
- `onToggleChange(handler)`: re-exported primitive event mixin.
|
|
42
|
+
- `ToggleChangeEvent`: re-exported primitive event class.
|
|
43
|
+
- `ToggleSize` and `ToggleOptions`: public TypeScript types for the style mixin.
|
|
44
|
+
|
|
45
|
+
## `remix/ui/toggle/primitives`
|
|
46
|
+
|
|
47
|
+
- `control(options)`: wires a boolean switch control with checked state, ARIA, keyboard, and native input behavior.
|
|
48
|
+
- `onToggleChange(handler)`: event mixin for bubbling toggle changes.
|
|
49
|
+
- `ToggleChangeEvent`: event class dispatched when a toggle changes.
|
|
50
|
+
- `ToggleControlOptions`: primitive options for controlled and uncontrolled state.
|
|
51
|
+
|
|
52
|
+
## Behavior Notes
|
|
53
|
+
|
|
54
|
+
- Checked styles apply through `:checked`, `[aria-checked="true"]`, or `[data-state="checked"]`.
|
|
55
|
+
- Native checkbox switches use the native `checked` attribute for state. Custom hosts use `role="switch"` and `aria-checked="true"` or `aria-checked="false"`.
|
|
56
|
+
- Every switch needs an accessible name, usually from visible label text, `aria-label`, or `aria-labelledby`.
|
package/src/ui/toggle.ts
ADDED
package/dist/ui/glyph.d.ts
DELETED
package/dist/ui/glyph.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["../../src/ui/glyph.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAA"}
|
package/dist/ui/scroll-lock.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-lock.d.ts","sourceRoot":"","sources":["../../src/ui/scroll-lock.ts"],"names":[],"mappings":"AACA,cAAc,2BAA2B,CAAA"}
|
package/dist/ui/separator.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"separator.d.ts","sourceRoot":"","sources":["../../src/ui/separator.ts"],"names":[],"mappings":"AACA,cAAc,yBAAyB,CAAA"}
|
package/dist/ui/theme.d.ts
DELETED
package/dist/ui/theme.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAA"}
|
package/src/ui/glyph/README.md
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# glyph
|
|
2
|
-
|
|
3
|
-
`Glyph` renders references into a shared SVG sprite sheet. Render a glyph sheet once, then render individual `Glyph` instances by name.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { Glyph } from 'remix/ui/glyph'
|
|
9
|
-
import { RMX_01_GLYPHS } from 'remix/ui/theme'
|
|
10
|
-
|
|
11
|
-
function Layout() {
|
|
12
|
-
return (
|
|
13
|
-
<html>
|
|
14
|
-
<body>
|
|
15
|
-
<RMX_01_GLYPHS />
|
|
16
|
-
<button aria-label="Delete">
|
|
17
|
-
<Glyph name="trash" />
|
|
18
|
-
</button>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
|
21
|
-
)
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Most glyphs are decorative because the surrounding control supplies the accessible name. `Glyph` sets `aria-hidden` by default in that case.
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
<button aria-label="Search">
|
|
29
|
-
<Glyph name="search" />
|
|
30
|
-
</button>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Give the glyph its own label only when the SVG itself is the accessible element.
|
|
34
|
-
|
|
35
|
-
```tsx
|
|
36
|
-
<Glyph aria-label="Search" name="search" viewBox="0 0 20 20" width="24" />
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Use `createGlyphSheet` when a theme or app provides its own complete glyph set. The generated sheet exposes the stable symbol ids and the original values for reuse.
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
import { createGlyphSheet, type GlyphValues } from 'remix/ui/glyph'
|
|
43
|
-
|
|
44
|
-
declare const glyphValues: GlyphValues
|
|
45
|
-
|
|
46
|
-
export const AppGlyphs = createGlyphSheet(glyphValues)
|
|
47
|
-
|
|
48
|
-
AppGlyphs.ids.trash
|
|
49
|
-
AppGlyphs.values.trash
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## `glyph.*`
|
|
53
|
-
|
|
54
|
-
- `Glyph`: renders an `<svg>` with a `<use>` element that points at the package-owned symbol id for `name`.
|
|
55
|
-
- `createGlyphSheet(values)`: creates a hidden SVG sprite sheet component from a complete glyph value set.
|
|
56
|
-
- `GlyphName`: typed union of supported glyph names.
|
|
57
|
-
- `GlyphProps`: props accepted by `Glyph`.
|
|
58
|
-
- `GlyphSheetProps`: props accepted by generated glyph sheet components.
|
|
59
|
-
- `GlyphSymbol`: SVG symbol value accepted by glyph value maps.
|
|
60
|
-
- `GlyphValues`: object shape expected by `createGlyphSheet`.
|
|
61
|
-
- `GlyphSheetComponent`: generated sprite sheet component with `ids` and `values` attached.
|
|
62
|
-
|
|
63
|
-
The built-in glyph names are `add`, `alert`, `check`, `chevronDown`, `chevronVertical`, `chevronUp`, `chevronRight`, `close`, `copy`, `edit`, `expand`, `info`, `menu`, `open`, `search`, `spinner`, and `trash`.
|
|
64
|
-
|
|
65
|
-
## Behavior Notes
|
|
66
|
-
|
|
67
|
-
- Render the glyph sheet once before rendering glyph instances that reference it.
|
|
68
|
-
- `createGlyphSheet` renders a hidden zero-size SVG and clones each provided `<symbol>` with the stable package id.
|
|
69
|
-
- `Glyph` is `aria-hidden` by default when no accessible label or labelled-by relationship is provided.
|
|
70
|
-
- Labeled glyphs keep their accessible label and do not force `aria-hidden`.
|
|
71
|
-
- Host SVG props such as `viewBox`, `width`, `mix`, and `aria-label` are preserved.
|
|
72
|
-
- `createGlyphSheet` throws if a provided glyph value is not a `<symbol>` element.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# scroll-lock
|
|
2
|
-
|
|
3
|
-
`scroll-lock` locks document scrolling while a floating or modal surface is open. Use `lockScroll` directly for imperative flows or `lockScrollOnToggle` for popover-style elements that emit `beforetoggle`.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { lockScroll, lockScrollOnToggle } from 'remix/ui/scroll-lock'
|
|
9
|
-
|
|
10
|
-
function DialogSurface() {
|
|
11
|
-
return <div popover="auto" mix={lockScrollOnToggle()} />
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function openModal() {
|
|
15
|
-
let unlock = lockScroll()
|
|
16
|
-
|
|
17
|
-
// Later, when the modal closes:
|
|
18
|
-
unlock()
|
|
19
|
-
}
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## API
|
|
23
|
-
|
|
24
|
-
- `lockScroll(document?)`: locks the target document and returns an idempotent unlock function.
|
|
25
|
-
- `lockScrollOnToggle()`: mixin that locks on `beforetoggle` open, unlocks on close, and releases the lock when the host unmounts.
|
|
26
|
-
|
|
27
|
-
## Behavior Notes
|
|
28
|
-
|
|
29
|
-
- The lock stores and restores the document element's inline `overflow` and `scrollbarGutter`.
|
|
30
|
-
- Scroll position is restored when the last active lock is released.
|
|
31
|
-
- Multiple locks are reference-counted, so the document stays locked until every unlock function has run.
|
|
32
|
-
- When a scrollbar is present and computed `scrollbar-gutter` is `auto`, the document reserves a stable gutter while locked.
|
|
33
|
-
- `lockScrollOnToggle` uses the host element's owner document.
|
package/src/ui/scroll-lock.ts
DELETED
package/src/ui/separator.ts
DELETED
package/src/ui/theme/README.md
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
# theme
|
|
2
|
-
|
|
3
|
-
`theme` provides Remix UI design tokens, theme creation, glyph contracts, and the built-in `RMX_01` preset. Use it to install CSS custom properties once and consume typed token references in component styles.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```tsx
|
|
8
|
-
import { createTheme, theme } from 'remix/ui/theme'
|
|
9
|
-
import { css } from 'remix/ui'
|
|
10
|
-
|
|
11
|
-
let Theme = createTheme({
|
|
12
|
-
space: {
|
|
13
|
-
none: '0px',
|
|
14
|
-
px: '1px',
|
|
15
|
-
xs: '2px',
|
|
16
|
-
sm: '4px',
|
|
17
|
-
md: '8px',
|
|
18
|
-
lg: '12px',
|
|
19
|
-
xl: '16px',
|
|
20
|
-
xxl: '24px',
|
|
21
|
-
},
|
|
22
|
-
radius: { none: '0px', sm: '4px', md: '8px', lg: '12px', xl: '16px', full: '9999px' },
|
|
23
|
-
fontFamily: { sans: 'Inter, sans-serif', mono: 'monospace' },
|
|
24
|
-
fontSize: {
|
|
25
|
-
xxxs: '10px',
|
|
26
|
-
xxs: '11px',
|
|
27
|
-
xs: '12px',
|
|
28
|
-
sm: '14px',
|
|
29
|
-
md: '16px',
|
|
30
|
-
lg: '18px',
|
|
31
|
-
xl: '20px',
|
|
32
|
-
xxl: '28px',
|
|
33
|
-
},
|
|
34
|
-
lineHeight: { tight: '1.2', normal: '1.5', relaxed: '1.7' },
|
|
35
|
-
letterSpacing: { tight: '-0.02em', normal: '0', meta: '0.06em', wide: '0.08em' },
|
|
36
|
-
fontWeight: { normal: '400', medium: '500', semibold: '600', bold: '700' },
|
|
37
|
-
control: { height: { sm: '28px', md: '32px', lg: '36px' } },
|
|
38
|
-
surface: { lvl0: '#fff', lvl1: '#f8fafc', lvl2: '#f5f5f5', lvl3: '#f1f5f9', lvl4: '#e9eef6' },
|
|
39
|
-
shadow: { xs: 'none', sm: 'none', md: 'none', lg: 'none', xl: 'none' },
|
|
40
|
-
colors: {
|
|
41
|
-
text: { primary: '#111827', secondary: '#374151', muted: '#6b7280', link: '#2563eb' },
|
|
42
|
-
border: { subtle: '#e5e7eb', default: '#d1d5db', strong: '#9ca3af' },
|
|
43
|
-
focus: { ring: '#3b82f6' },
|
|
44
|
-
overlay: { scrim: 'rgb(0 0 0 / 0.45)' },
|
|
45
|
-
action: {
|
|
46
|
-
primary: {
|
|
47
|
-
background: '#2563eb',
|
|
48
|
-
backgroundHover: '#1d4ed8',
|
|
49
|
-
backgroundActive: '#1e40af',
|
|
50
|
-
foreground: '#fff',
|
|
51
|
-
border: '#2563eb',
|
|
52
|
-
},
|
|
53
|
-
secondary: {
|
|
54
|
-
background: '#fff',
|
|
55
|
-
backgroundHover: '#f8fafc',
|
|
56
|
-
backgroundActive: '#f1f5f9',
|
|
57
|
-
foreground: '#111827',
|
|
58
|
-
border: '#d1d5db',
|
|
59
|
-
},
|
|
60
|
-
danger: {
|
|
61
|
-
background: '#dc2626',
|
|
62
|
-
backgroundHover: '#b91c1c',
|
|
63
|
-
backgroundActive: '#991b1b',
|
|
64
|
-
foreground: '#fff',
|
|
65
|
-
border: '#dc2626',
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
let card = css({
|
|
72
|
-
backgroundColor: theme.surface.lvl0,
|
|
73
|
-
color: theme.colors.text.primary,
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
function Layout() {
|
|
77
|
-
return (
|
|
78
|
-
<body>
|
|
79
|
-
<Theme />
|
|
80
|
-
<article mix={card}>Project status</article>
|
|
81
|
-
</body>
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## `theme.*`
|
|
87
|
-
|
|
88
|
-
- `theme`: typed CSS variable reference contract, such as `theme.space.md` and `theme.colors.text.primary`.
|
|
89
|
-
- `createTheme(values, options?)`: creates a style component with `cssText`, `selector`, `values`, `vars`, and `Style`.
|
|
90
|
-
- `RMX_01`: built-in theme component.
|
|
91
|
-
- `RMX_01_GLYPHS`: built-in glyph sheet component.
|
|
92
|
-
- `glyphContract` and `glyphNames`: stable glyph ids and supported glyph names.
|
|
93
|
-
- `ThemeValues`, `ThemeVars`, `ThemeComponent`, `ThemeStyleProps`, `CreateThemeOptions`, and `ThemeMix`: public TypeScript types for custom themes.
|
|
94
|
-
- `GlyphName`, `GlyphSymbol`, and `GlyphValues`: public TypeScript types for glyph contracts.
|
|
95
|
-
|
|
96
|
-
## Behavior Notes
|
|
97
|
-
|
|
98
|
-
- `theme` values are CSS variable references, not raw token values.
|
|
99
|
-
- `createTheme` serializes token values into CSS custom properties and renders a `<style data-rmx-theme>` tag.
|
|
100
|
-
- The default selector is `:root`; pass `selector` for scoped themes.
|
|
101
|
-
- The base reset is included by default, emitted in `rmx-reset`, and can be disabled with `reset: false`.
|
|
102
|
-
- The built-in components consume this token contract through their style mixins.
|
|
103
|
-
- Render `<RMX_01 />` and `<RMX_01_GLYPHS />` once when using the built-in theme and glyph preset.
|