@solidrt/components 0.0.50 → 0.0.52
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/AGENTS.md +93 -85
- package/README.md +421 -311
- package/demos/README.md +24 -0
- package/demos/assets/icon.png +0 -0
- package/demos/assets/icon.svg +23 -0
- package/demos/package.json +9 -0
- package/demos/src/gallery.tsx +866 -0
- package/demos/tsconfig.json +15 -0
- package/docs/badge.md +10 -0
- package/docs/button.md +21 -0
- package/docs/card.md +11 -0
- package/docs/checkbox.md +9 -0
- package/docs/context-menu.md +17 -0
- package/docs/density.md +13 -0
- package/docs/divider.md +10 -0
- package/docs/field.md +11 -0
- package/docs/focus-nav.md +18 -0
- package/docs/icon.md +13 -0
- package/docs/image.md +21 -0
- package/docs/index.md +13 -0
- package/docs/item.md +25 -0
- package/docs/modal.md +15 -0
- package/docs/nav-shell.md +18 -0
- package/docs/policy.md +21 -0
- package/docs/portal.md +15 -0
- package/docs/pressable.md +17 -0
- package/docs/progress-bar.md +10 -0
- package/docs/qrcode.md +10 -0
- package/docs/radio.md +13 -0
- package/docs/rich-text-document.md +5 -0
- package/docs/rich-text-editor.md +24 -0
- package/docs/safe-area.md +12 -0
- package/docs/scroll-view.md +35 -0
- package/docs/segmented-control.md +13 -0
- package/docs/select.md +15 -0
- package/docs/slider.md +9 -0
- package/docs/spacing.md +7 -0
- package/docs/spinner.md +10 -0
- package/docs/split-view.md +14 -0
- package/docs/switch.md +13 -0
- package/docs/text-input.md +23 -0
- package/docs/text.md +15 -0
- package/docs/theme.md +68 -0
- package/docs/tooltip.md +11 -0
- package/docs/types.md +9 -0
- package/docs/typography.md +5 -0
- package/docs/view.md +14 -0
- package/docs/window.md +15 -0
- package/package.json +8 -4
- package/src/badge.tsx +30 -21
- package/src/button.tsx +50 -32
- package/src/card.tsx +22 -13
- package/src/checkbox.tsx +29 -11
- package/src/context-menu.tsx +14 -9
- package/src/density.tsx +39 -0
- package/src/divider.tsx +11 -4
- package/src/editor-field.tsx +368 -0
- package/src/field.tsx +47 -0
- package/src/icon.tsx +8 -4
- package/src/image.tsx +10 -3
- package/src/index.ts +19 -2
- package/src/item.tsx +121 -0
- package/src/nav-shell.tsx +7 -17
- package/src/policy.ts +9 -12
- package/src/press.ts +37 -8
- package/src/pressable.tsx +15 -3
- package/src/progress-bar.tsx +8 -5
- package/src/qrcode.tsx +7 -5
- package/src/radio.tsx +26 -16
- package/src/rich-text-document.ts +247 -0
- package/src/rich-text-editor.tsx +151 -0
- package/src/scroll-view.tsx +76 -7
- package/src/segmented-control.tsx +33 -19
- package/src/select.tsx +59 -30
- package/src/slider.tsx +32 -6
- package/src/spacing.ts +1 -1
- package/src/spinner.tsx +11 -6
- package/src/split-view.tsx +3 -4
- package/src/switch.tsx +10 -3
- package/src/text-input.tsx +54 -264
- package/src/text.tsx +22 -2
- package/src/theme.ts +220 -81
- package/src/tooltip.tsx +23 -9
- package/src/types.ts +119 -1
- package/src/view.tsx +11 -2
package/src/select.tsx
CHANGED
|
@@ -5,9 +5,11 @@ import { theme } from "./theme"
|
|
|
5
5
|
import { policy } from "./policy"
|
|
6
6
|
import { space } from "./spacing"
|
|
7
7
|
import { typeStyle } from "./typography"
|
|
8
|
-
import type { Option, StyleProps } from "./types"
|
|
8
|
+
import type { Option, StyleProps, TransitionProps } from "./types"
|
|
9
|
+
import { splitTransition, transitionEndFor } from "./types"
|
|
10
|
+
import { Icon } from "./icon"
|
|
9
11
|
|
|
10
|
-
export interface SelectProps {
|
|
12
|
+
export interface SelectProps extends TransitionProps {
|
|
11
13
|
options: Option[]
|
|
12
14
|
// Controlled selected value. If omitted, the select is uncontrolled.
|
|
13
15
|
value?: unknown
|
|
@@ -20,9 +22,10 @@ export interface SelectProps {
|
|
|
20
22
|
style?: StyleProps
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
// Distance between the trigger and the dropdown.
|
|
26
|
+
let gap = () => theme.spacing.sm
|
|
24
27
|
// Minimum distance kept between the dropdown and the window edges.
|
|
25
|
-
|
|
28
|
+
let margin = () => theme.spacing.sm
|
|
26
29
|
|
|
27
30
|
/**
|
|
28
31
|
* A single-choice picker whose presentation forks on the interaction policy:
|
|
@@ -61,12 +64,15 @@ export function Select(props: SelectProps) {
|
|
|
61
64
|
paddingLeft={space("md")}
|
|
62
65
|
paddingRight={space("md")}
|
|
63
66
|
{...press.handlers}
|
|
67
|
+
focusable
|
|
64
68
|
>
|
|
65
69
|
<d-rect
|
|
66
70
|
color={
|
|
67
|
-
press.pressed()
|
|
68
|
-
? theme.color.
|
|
69
|
-
: "
|
|
71
|
+
press.pressed()
|
|
72
|
+
? theme.color.overlayPressed
|
|
73
|
+
: (press.hovered() && policy.interaction !== "touch") || (press.focused() && policy.focusRing)
|
|
74
|
+
? theme.color.overlayHover
|
|
75
|
+
: "transparent"
|
|
70
76
|
}
|
|
71
77
|
/>
|
|
72
78
|
<text {...bodyText(p.option.value === value() ? theme.color.primary : theme.color.text)}>{p.option.label}</text>
|
|
@@ -86,9 +92,9 @@ export function Select(props: SelectProps) {
|
|
|
86
92
|
let b = menu && getBoundingBox(menu)
|
|
87
93
|
if (!a || !b) return
|
|
88
94
|
if (a.width !== minWidth()) setMinWidth(a.width)
|
|
89
|
-
let x = Math.round(Math.min(Math.max(a.x,
|
|
90
|
-
let below = a.y + a.height +
|
|
91
|
-
let y = Math.round(below + b.height > env.windowSize.height -
|
|
95
|
+
let x = Math.round(Math.min(Math.max(a.x, margin()), env.windowSize.width - b.width - margin()))
|
|
96
|
+
let below = a.y + a.height + gap()
|
|
97
|
+
let y = Math.round(below + b.height > env.windowSize.height - margin() ? a.y - b.height - gap() : below)
|
|
92
98
|
let cur = pos()
|
|
93
99
|
if (!cur || cur.x !== x || cur.y !== y) setPos({ x, y })
|
|
94
100
|
})
|
|
@@ -147,21 +153,33 @@ export function Select(props: SelectProps) {
|
|
|
147
153
|
</view>,
|
|
148
154
|
)
|
|
149
155
|
|
|
150
|
-
let press = createPress({
|
|
156
|
+
let press = createPress({
|
|
157
|
+
onPress: () => {
|
|
158
|
+
setOpen(!open())
|
|
159
|
+
},
|
|
160
|
+
})
|
|
151
161
|
let style = () => ({
|
|
152
162
|
borderColor: theme.color.border,
|
|
153
163
|
borderWidth: theme.borderWidth.sm,
|
|
154
|
-
borderRadius: theme.radius.
|
|
164
|
+
borderRadius: theme.radius.md,
|
|
165
|
+
backgroundColor: theme.color.surface,
|
|
166
|
+
...theme.components.select,
|
|
155
167
|
...props.style,
|
|
156
|
-
|
|
157
|
-
props.style?.backgroundColor ??
|
|
158
|
-
(press.hovered() && !props.disabled && policy.interaction !== "touch"
|
|
159
|
-
? theme.color.surfaceHover
|
|
160
|
-
: theme.color.surface),
|
|
168
|
+
...(press.focused() && policy.focusRing ? { borderWidth: theme.borderWidth.focus, borderColor: theme.color.ring } : {}),
|
|
161
169
|
})
|
|
170
|
+
// Hover feedback: the theme overlay tint drawn over the trigger fill.
|
|
171
|
+
let overlay = () =>
|
|
172
|
+
press.hovered() && !props.disabled && policy.interaction !== "touch"
|
|
173
|
+
? theme.color.overlayHover
|
|
174
|
+
: "transparent"
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
let split = () => splitTransition(props.transition)
|
|
162
178
|
|
|
163
179
|
return (
|
|
164
180
|
<view
|
|
181
|
+
transition={split().root}
|
|
182
|
+
onTransitionEnd={transitionEndFor("root", props.onTransitionEnd)}
|
|
165
183
|
ref={(n: { id: number }) => {
|
|
166
184
|
press.ref(n)
|
|
167
185
|
trigger = n
|
|
@@ -171,8 +189,8 @@ export function Select(props: SelectProps) {
|
|
|
171
189
|
alignItems="center"
|
|
172
190
|
justifyContent="space-between"
|
|
173
191
|
gap={theme.spacing.md}
|
|
174
|
-
paddingTop={space("
|
|
175
|
-
paddingBottom={space("
|
|
192
|
+
paddingTop={space("md")}
|
|
193
|
+
paddingBottom={space("md")}
|
|
176
194
|
paddingLeft={space("md")}
|
|
177
195
|
paddingRight={space("md")}
|
|
178
196
|
{...props.layout}
|
|
@@ -182,25 +200,34 @@ export function Select(props: SelectProps) {
|
|
|
182
200
|
rotate={style().rotate}
|
|
183
201
|
opacity={style().opacity}
|
|
184
202
|
{...press.handlers}
|
|
203
|
+
focusable={!props.disabled}
|
|
185
204
|
pointerEvents={props.disabled ? "none" : undefined}
|
|
186
205
|
>
|
|
187
|
-
<d-rect color={style().backgroundColor ?? "transparent"} radius={style().borderRadius} />
|
|
206
|
+
<d-rect transition={split().background} onTransitionEnd={transitionEndFor("background", props.onTransitionEnd)} color={style().backgroundColor ?? "transparent"} radius={style().borderRadius} />
|
|
207
|
+
<d-rect color={overlay()} radius={style().borderRadius} />
|
|
188
208
|
<Show
|
|
189
209
|
when={selected()}
|
|
190
210
|
fallback={<text {...bodyText(theme.color.textMuted)}>{props.placeholder ?? ""}</text>}
|
|
191
211
|
>
|
|
192
212
|
<text {...bodyText(props.disabled ? theme.color.textMuted : theme.color.text)}>{selected()!.label}</text>
|
|
193
213
|
</Show>
|
|
194
|
-
<
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
214
|
+
<Show
|
|
215
|
+
when={theme.icons.chevronDown}
|
|
216
|
+
fallback={
|
|
217
|
+
<view width={12} height={8}>
|
|
218
|
+
<d-path
|
|
219
|
+
d="M 2 2 L 6 6 L 10 2"
|
|
220
|
+
drawStyle="stroke"
|
|
221
|
+
color={theme.color.textMuted}
|
|
222
|
+
strokeWidth={2}
|
|
223
|
+
strokeCap="round"
|
|
224
|
+
strokeJoin="round"
|
|
225
|
+
/>
|
|
226
|
+
</view>
|
|
227
|
+
}
|
|
228
|
+
>
|
|
229
|
+
<Icon src={theme.icons.chevronDown!} size={12} color={theme.color.textMuted} />
|
|
230
|
+
</Show>
|
|
204
231
|
<Show when={open()}>
|
|
205
232
|
<Show when={policy.interaction === "touch"} fallback={<Dropdown />}>
|
|
206
233
|
<Sheet />
|
|
@@ -209,6 +236,8 @@ export function Select(props: SelectProps) {
|
|
|
209
236
|
<Show when={(style().borderWidth ?? 0) > 0}>
|
|
210
237
|
<d-rect
|
|
211
238
|
drawStyle="stroke"
|
|
239
|
+
transition={split().border}
|
|
240
|
+
onTransitionEnd={transitionEndFor("border", props.onTransitionEnd)}
|
|
212
241
|
color={style().borderColor ?? "transparent"}
|
|
213
242
|
strokeWidth={style().borderWidth}
|
|
214
243
|
radius={style().borderRadius}
|
package/src/slider.tsx
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { arena, createSignal, getBoundingBox, onLayout, onSettled } from "@solidrt/core"
|
|
2
|
-
import type { LayoutProps, PointerEvent } from "@solidrt/core"
|
|
1
|
+
import { arena, createMemo, createSignal, focusedNode, getBoundingBox, onLayout, onSettled, Show } from "@solidrt/core"
|
|
2
|
+
import type { KeyEvent, LayoutProps, PointerEvent } from "@solidrt/core"
|
|
3
3
|
import { theme } from "./theme"
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { policy } from "./policy"
|
|
5
|
+
import { densityScale } from "./density"
|
|
6
|
+
import type { StyleProps, TransitionProps } from "./types"
|
|
7
|
+
import { splitTransition, transitionEndFor } from "./types"
|
|
6
8
|
|
|
7
|
-
export interface SliderProps {
|
|
9
|
+
export interface SliderProps extends TransitionProps {
|
|
8
10
|
// Controlled value. If omitted, the slider is uncontrolled.
|
|
9
11
|
value?: number
|
|
10
12
|
defaultValue?: number
|
|
@@ -27,6 +29,8 @@ let clamp = (x: number, lo: number, hi: number) => (x < lo ? lo : x > hi ? hi :
|
|
|
27
29
|
// A horizontal slider. The groove fills up to the thumb; dragging or pressing
|
|
28
30
|
// the track sets the value from the pointer x. Moves arrive on the frozen down
|
|
29
31
|
// path, so a drag keeps updating when the pointer drifts off the track.
|
|
32
|
+
// Focused (spatial nav), arrow keys step the value (by `step`, else 1% of the
|
|
33
|
+
// range) and the thumb draws the focus ring under the focusRing policy.
|
|
30
34
|
// Controlled via value/onChange, or uncontrolled via defaultValue.
|
|
31
35
|
export function Slider(props: SliderProps) {
|
|
32
36
|
let min = () => props.min ?? 0
|
|
@@ -95,14 +99,31 @@ export function Slider(props: SliderProps) {
|
|
|
95
99
|
if (active === e.pointerId) endDrag()
|
|
96
100
|
}
|
|
97
101
|
|
|
102
|
+
// focusedNode() is read first, unconditionally, so the memo depends on it
|
|
103
|
+
// even when the ref has not set `track` yet (see createPress).
|
|
104
|
+
let focused = createMemo(() => {
|
|
105
|
+
let id = focusedNode()
|
|
106
|
+
return id != null && id === track?.id
|
|
107
|
+
})
|
|
108
|
+
let handleKeyDown = (e: KeyEvent) => {
|
|
109
|
+
if (props.disabled) return
|
|
110
|
+
let dir = e.key === "ArrowRight" || e.key === "ArrowUp" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowDown" ? -1 : 0
|
|
111
|
+
if (dir === 0) return
|
|
112
|
+
e.stopPropagation()
|
|
113
|
+
let inc = props.step ?? (max() - min()) / 100
|
|
114
|
+
commit(clamp(value() + dir * inc, min(), max()))
|
|
115
|
+
}
|
|
116
|
+
|
|
98
117
|
return (
|
|
99
118
|
<view
|
|
119
|
+
transition={splitTransition(props.transition).root}
|
|
120
|
+
onTransitionEnd={transitionEndFor("root", props.onTransitionEnd)}
|
|
100
121
|
ref={(n: { id: number }) => (track = n)}
|
|
101
122
|
repaintBoundary
|
|
102
123
|
flexDirection="row"
|
|
103
124
|
alignItems="center"
|
|
104
125
|
height={height()}
|
|
105
|
-
width={
|
|
126
|
+
width={theme.size.slider}
|
|
106
127
|
{...props.layout}
|
|
107
128
|
x={props.style?.x}
|
|
108
129
|
y={props.style?.y}
|
|
@@ -110,15 +131,20 @@ export function Slider(props: SliderProps) {
|
|
|
110
131
|
rotate={props.style?.rotate}
|
|
111
132
|
opacity={props.style?.opacity}
|
|
112
133
|
pointerEvents={props.disabled ? "none" : "auto"}
|
|
134
|
+
focusable={!props.disabled}
|
|
113
135
|
onPointerDown={handleDown}
|
|
114
136
|
onPointerMove={handleMove}
|
|
115
137
|
onPointerUp={handleUp}
|
|
138
|
+
onKeyDown={handleKeyDown}
|
|
116
139
|
>
|
|
117
140
|
<view ref={(n: { id: number }) => (groove = n)} position="relative" flex={1} height={GROOVE}>
|
|
118
141
|
<d-rect color={theme.color.surfaceAlt} radius={GROOVE / 2} />
|
|
119
142
|
<d-rect color={theme.color.primary} w={fillPx()} h={GROOVE} radius={GROOVE / 2} />
|
|
120
143
|
<view position="absolute" left={0} top={(GROOVE - thumb()) / 2} x={fillPx() - thumb() / 2}>
|
|
121
144
|
<d-oval w={thumb()} h={thumb()} color={theme.color.primary} />
|
|
145
|
+
<Show when={focused() && policy.focusRing}>
|
|
146
|
+
<d-oval drawStyle="stroke" w={thumb()} h={thumb()} color={theme.color.ring} strokeWidth={theme.borderWidth.focus} />
|
|
147
|
+
</Show>
|
|
122
148
|
</view>
|
|
123
149
|
</view>
|
|
124
150
|
</view>
|
package/src/spacing.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { theme, type Theme } from "./theme"
|
|
2
|
-
import { densityScale } from "./
|
|
2
|
+
import { densityScale } from "./density"
|
|
3
3
|
|
|
4
4
|
// Density-scaled spacing: a theme.spacing token multiplied by the density
|
|
5
5
|
// policy's metric scale, rounded to whole pixels. Use it for gaps and paddings
|
package/src/spinner.tsx
CHANGED
|
@@ -2,9 +2,10 @@ import { createSignal, onFrame, Show } from "@solidrt/core"
|
|
|
2
2
|
import type { LayoutProps } from "@solidrt/core"
|
|
3
3
|
import { theme } from "./theme"
|
|
4
4
|
import { policy } from "./policy"
|
|
5
|
-
import type { StyleProps } from "./types"
|
|
5
|
+
import type { StyleProps, TransitionProps } from "./types"
|
|
6
|
+
import { splitTransition, transitionEndFor } from "./types"
|
|
6
7
|
|
|
7
|
-
export interface SpinnerProps {
|
|
8
|
+
export interface SpinnerProps extends TransitionProps {
|
|
8
9
|
// Overall diameter in pixels.
|
|
9
10
|
size?: number
|
|
10
11
|
// Arc stroke width in pixels.
|
|
@@ -24,7 +25,9 @@ const THICKNESS = 3
|
|
|
24
25
|
export function Spinner(props: SpinnerProps) {
|
|
25
26
|
let size = () => props.size ?? SIZE
|
|
26
27
|
let thickness = () => props.thickness ?? THICKNESS
|
|
27
|
-
|
|
28
|
+
// Theme-level per-component overrides merged under the instance style.
|
|
29
|
+
let styled = () => ({ ...theme.components.spinner, ...props.style })
|
|
30
|
+
let color = () => styled().color ?? theme.color.primary
|
|
28
31
|
let speed = () => props.speed ?? 1
|
|
29
32
|
|
|
30
33
|
// tick is in milliseconds (like performance.now()). The frame loop is mounted
|
|
@@ -51,13 +54,15 @@ export function Spinner(props: SpinnerProps) {
|
|
|
51
54
|
|
|
52
55
|
return (
|
|
53
56
|
<view
|
|
57
|
+
transition={splitTransition(props.transition).root}
|
|
58
|
+
onTransitionEnd={transitionEndFor("root", props.onTransitionEnd)}
|
|
54
59
|
width={size()}
|
|
55
60
|
height={size()}
|
|
56
61
|
{...props.layout}
|
|
57
62
|
rotate={angle()}
|
|
58
|
-
x={
|
|
59
|
-
y={
|
|
60
|
-
opacity={
|
|
63
|
+
x={styled().x}
|
|
64
|
+
y={styled().y}
|
|
65
|
+
opacity={styled().opacity}
|
|
61
66
|
>
|
|
62
67
|
<Show when={policy.motion !== "none"}>
|
|
63
68
|
<Animate />
|
package/src/split-view.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Show } from "@solidrt/core"
|
|
2
2
|
import type { LayoutProps } from "@solidrt/core"
|
|
3
3
|
import { policy } from "./policy"
|
|
4
|
+
import { theme } from "./theme"
|
|
4
5
|
|
|
5
6
|
export interface SplitViewProps {
|
|
6
7
|
// The list (or primary) pane.
|
|
@@ -10,13 +11,11 @@ export interface SplitViewProps {
|
|
|
10
11
|
// Single-pane mode only: show the detail instead of the list. The app owns
|
|
11
12
|
// this navigation state; two-pane mode ignores it.
|
|
12
13
|
showDetail?: boolean
|
|
13
|
-
// Width of the list pane in two-pane mode.
|
|
14
|
+
// Width of the list pane in two-pane mode; defaults to theme.size.splitViewList.
|
|
14
15
|
listWidth?: number
|
|
15
16
|
layout?: LayoutProps
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const LIST_WIDTH = 320
|
|
19
|
-
|
|
20
19
|
/**
|
|
21
20
|
* A list-detail container driven by the layout policy: two-pane shows the list
|
|
22
21
|
* beside the detail, single-pane shows one pane at a time per `showDetail`.
|
|
@@ -45,7 +44,7 @@ export function SplitView(props: SplitViewProps) {
|
|
|
45
44
|
}
|
|
46
45
|
>
|
|
47
46
|
<view flexDirection="row" {...props.layout}>
|
|
48
|
-
<view width={props.listWidth ??
|
|
47
|
+
<view width={props.listWidth ?? theme.size.splitViewList} flexDirection="column">
|
|
49
48
|
{props.list}
|
|
50
49
|
</view>
|
|
51
50
|
<view flex={1} flexDirection="column">
|
package/src/switch.tsx
CHANGED
|
@@ -2,10 +2,12 @@ import { createSignal, Show } from "@solidrt/core"
|
|
|
2
2
|
import type { LayoutProps } from "@solidrt/core"
|
|
3
3
|
import { createPress } from "./press"
|
|
4
4
|
import { theme } from "./theme"
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import { policy } from "./policy"
|
|
6
|
+
import { densityScale } from "./density"
|
|
7
|
+
import type { StyleProps, TransitionProps } from "./types"
|
|
8
|
+
import { splitTransition, transitionEndFor } from "./types"
|
|
7
9
|
|
|
8
|
-
export interface SwitchProps {
|
|
10
|
+
export interface SwitchProps extends TransitionProps {
|
|
9
11
|
// Controlled on/off. If omitted, the switch is uncontrolled.
|
|
10
12
|
value?: boolean
|
|
11
13
|
// Initial value for uncontrolled use.
|
|
@@ -43,11 +45,15 @@ export function Switch(props: SwitchProps) {
|
|
|
43
45
|
let style = () => ({
|
|
44
46
|
backgroundColor: on() ? theme.color.primary : theme.color.surfaceAlt,
|
|
45
47
|
borderRadius: h() / 2,
|
|
48
|
+
...theme.components.switch,
|
|
46
49
|
...props.style,
|
|
50
|
+
...(press.focused() && policy.focusRing ? { borderWidth: theme.borderWidth.focus, borderColor: theme.color.ring } : {}),
|
|
47
51
|
})
|
|
48
52
|
|
|
49
53
|
return (
|
|
50
54
|
<view
|
|
55
|
+
transition={splitTransition(props.transition).root}
|
|
56
|
+
onTransitionEnd={transitionEndFor("root", props.onTransitionEnd)}
|
|
51
57
|
ref={press.ref}
|
|
52
58
|
repaintBoundary
|
|
53
59
|
width={w()}
|
|
@@ -59,6 +65,7 @@ export function Switch(props: SwitchProps) {
|
|
|
59
65
|
rotate={style().rotate}
|
|
60
66
|
opacity={style().opacity}
|
|
61
67
|
{...press.handlers}
|
|
68
|
+
focusable={!props.disabled}
|
|
62
69
|
pointerEvents={props.disabled ? "none" : undefined}
|
|
63
70
|
>
|
|
64
71
|
<d-rect color={style().backgroundColor ?? "transparent"} radius={style().borderRadius} />
|