@preset.nz/ux-kit 0.1.0 → 0.1.1
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/README.md +27 -0
- package/THIRD_PARTY_NOTICES.md +253 -0
- package/package.json +9 -10
- package/src/chat/index.ts +9 -0
- package/src/chat/message.tsx +80 -0
- package/src/chat/prompt-input.tsx +121 -0
- package/src/chat/reasoning.tsx +182 -0
- package/src/chat/scroller.tsx +147 -0
- package/src/chat/suggestion.tsx +65 -0
- package/src/chat/tool.tsx +143 -0
- package/src/chat/types.ts +8 -0
- package/src/components/avatar.tsx +1 -1
- package/src/components/badge.tsx +4 -6
- package/src/components/breadcrumb.tsx +8 -10
- package/src/components/button.tsx +1 -1
- package/src/components/card.tsx +4 -21
- package/src/components/checkbox.tsx +3 -5
- package/src/components/color-field.tsx +20 -7
- package/src/components/color-swatch.tsx +3 -3
- package/src/components/context-menu.tsx +13 -13
- package/src/components/dialog.tsx +5 -9
- package/src/components/dropdown-menu.tsx +13 -13
- package/src/components/empty-state.tsx +6 -3
- package/src/components/input.tsx +2 -2
- package/src/components/label.tsx +3 -2
- package/src/components/navigation-menu.tsx +16 -10
- package/src/components/number-field.tsx +30 -26
- package/src/components/popover.tsx +3 -10
- package/src/components/select.tsx +16 -28
- package/src/components/separator.tsx +2 -6
- package/src/components/sheet.tsx +16 -8
- package/src/components/side-panel.tsx +31 -8
- package/src/components/sidebar.tsx +15 -52
- package/src/components/skeleton.tsx +1 -1
- package/src/components/slider.tsx +4 -8
- package/src/components/snackbar.tsx +36 -34
- package/src/components/status-bar.tsx +10 -3
- package/src/components/tabs.tsx +3 -6
- package/src/components/textarea.tsx +2 -2
- package/src/components/toggle-group.tsx +4 -4
- package/src/components/toggle.tsx +1 -1
- package/src/components/toolbar.tsx +8 -11
- package/src/components/tooltip.tsx +1 -1
- package/src/graphics/adsr.ts +21 -13
- package/src/graphics/curve-editor.tsx +56 -14
- package/src/graphics/curve-edits.ts +20 -3
- package/src/graphics/index.ts +6 -6
- package/src/graphics/scale.ts +4 -1
- package/src/graphics/use-canvas.ts +1 -1
- package/src/graphics/use-tokens.ts +4 -1
- package/src/index.css +1 -1
- package/src/index.ts +3 -5
- package/src/lib/use-mobile.ts +1 -1
- package/src/lib/utils.ts +1 -1
- package/src/shadcn-tailwind.css +665 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
1
|
import { NumberField as NumberFieldPrimitive } from "@base-ui/react/number-field"
|
|
3
|
-
|
|
4
|
-
import { cn } from "../lib/utils"
|
|
2
|
+
import * as React from "react"
|
|
5
3
|
import { ArrowsHorizontalIcon } from "../icons"
|
|
4
|
+
import { cn } from "../lib/utils"
|
|
6
5
|
|
|
7
6
|
// NumberField: a number you can drag. The label is the scrub handle (Base UI's ScrubArea);
|
|
8
7
|
// click it, or tab in, to type. Behaviour is Oblique's InputNumber on Base UI's NumberField:
|
|
@@ -29,10 +28,7 @@ interface NumberChange {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
interface NumberFieldProps
|
|
32
|
-
extends Omit<
|
|
33
|
-
React.ComponentProps<"div">,
|
|
34
|
-
"onChange" | "defaultValue" | "children" | "value"
|
|
35
|
-
> {
|
|
31
|
+
extends Omit<React.ComponentProps<"div">, "onChange" | "defaultValue" | "children" | "value"> {
|
|
36
32
|
value: number
|
|
37
33
|
onValueChange?: (value: number, details: NumberChange) => void
|
|
38
34
|
min?: number
|
|
@@ -112,7 +108,7 @@ function NumberField({
|
|
|
112
108
|
const digits = integer ? 0 : (precision ?? placesOf(small))
|
|
113
109
|
const options = React.useMemo<Intl.NumberFormatOptions>(
|
|
114
110
|
() => ({ maximumFractionDigits: digits, useGrouping: false, ...format }),
|
|
115
|
-
[digits, format]
|
|
111
|
+
[digits, format],
|
|
116
112
|
)
|
|
117
113
|
|
|
118
114
|
// The field's own value, so a scrub follows the pointer without waiting for the app's round
|
|
@@ -165,6 +161,7 @@ function NumberField({
|
|
|
165
161
|
})
|
|
166
162
|
}
|
|
167
163
|
|
|
164
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: the effect follows `value` alone; `show` and `clearSettle` are per-render closures over refs and state setters
|
|
168
165
|
React.useEffect(() => {
|
|
169
166
|
valueRef.current = value
|
|
170
167
|
if (scrub.current.started) return
|
|
@@ -174,15 +171,17 @@ function NumberField({
|
|
|
174
171
|
show(value)
|
|
175
172
|
}, [value])
|
|
176
173
|
|
|
174
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: unmount cleanup only; `clearSettle` is a per-render closure over refs
|
|
177
175
|
React.useEffect(
|
|
178
176
|
() => () => {
|
|
179
177
|
clearSettle()
|
|
180
178
|
cancelAnimationFrame(pending.current.raf)
|
|
181
179
|
},
|
|
182
|
-
[]
|
|
180
|
+
[],
|
|
183
181
|
)
|
|
184
182
|
|
|
185
183
|
// Escape while scrubbing. Captured so the app's own Escape (clear selection) doesn't also run.
|
|
184
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: the listener lives while a scrub does; `show` and `dropPending` are per-render closures over refs
|
|
186
185
|
React.useEffect(() => {
|
|
187
186
|
if (!scrubbing || !onScrubCancel) return
|
|
188
187
|
const onKey = (e: KeyboardEvent) => {
|
|
@@ -297,7 +296,10 @@ function NumberField({
|
|
|
297
296
|
/>
|
|
298
297
|
)
|
|
299
298
|
const unit = suffix != null && (
|
|
300
|
-
<span
|
|
299
|
+
<span
|
|
300
|
+
data-slot="number-field-suffix"
|
|
301
|
+
className="flex shrink-0 items-center pr-2 text-muted-foreground select-none"
|
|
302
|
+
>
|
|
301
303
|
{suffix}
|
|
302
304
|
</span>
|
|
303
305
|
)
|
|
@@ -322,9 +324,10 @@ function NumberField({
|
|
|
322
324
|
className={cn(
|
|
323
325
|
"min-w-0",
|
|
324
326
|
!outside && `group/number-field relative ${boxClass}`,
|
|
325
|
-
labelPlacement === "column" &&
|
|
327
|
+
labelPlacement === "column" &&
|
|
328
|
+
"col-span-2 grid grid-cols-subgrid items-center data-disabled:opacity-50",
|
|
326
329
|
labelPlacement === "above" && "flex flex-col gap-1 data-disabled:opacity-50",
|
|
327
|
-
className
|
|
330
|
+
className,
|
|
328
331
|
)}
|
|
329
332
|
{...props}
|
|
330
333
|
>
|
|
@@ -340,8 +343,8 @@ function NumberField({
|
|
|
340
343
|
? "cursor-default"
|
|
341
344
|
: cn(
|
|
342
345
|
"cursor-ew-resize hover:text-foreground data-scrubbing:text-foreground",
|
|
343
|
-
!outside && "hover:bg-muted data-scrubbing:bg-selection/20"
|
|
344
|
-
)
|
|
346
|
+
!outside && "hover:bg-muted data-scrubbing:bg-selection/20",
|
|
347
|
+
),
|
|
345
348
|
)}
|
|
346
349
|
>
|
|
347
350
|
{label}
|
|
@@ -367,10 +370,7 @@ function NumberField({
|
|
|
367
370
|
const AXES = ["X", "Y", "Z", "W"]
|
|
368
371
|
|
|
369
372
|
interface VectorFieldProps
|
|
370
|
-
extends Omit<
|
|
371
|
-
NumberFieldProps,
|
|
372
|
-
"value" | "onValueChange" | "label" | "className"
|
|
373
|
-
> {
|
|
373
|
+
extends Omit<NumberFieldProps, "value" | "onValueChange" | "label" | "className"> {
|
|
374
374
|
value: number[]
|
|
375
375
|
/** The whole vector with the changed component replaced. */
|
|
376
376
|
onValueChange?: (value: number[], details: NumberChange) => void
|
|
@@ -393,20 +393,20 @@ function VectorField({
|
|
|
393
393
|
return (
|
|
394
394
|
<div
|
|
395
395
|
data-slot="vector-field"
|
|
396
|
-
className={cn(
|
|
397
|
-
"flex min-w-0 gap-1",
|
|
398
|
-
orientation === "column" && "flex-col",
|
|
399
|
-
className
|
|
400
|
-
)}
|
|
396
|
+
className={cn("flex min-w-0 gap-1", orientation === "column" && "flex-col", className)}
|
|
401
397
|
>
|
|
402
398
|
{value.map((x, i) => (
|
|
403
399
|
<NumberField
|
|
400
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: one field per axis; the index is the axis
|
|
404
401
|
key={i}
|
|
405
402
|
{...props}
|
|
406
403
|
label={labels?.[i] ?? (value.length <= AXES.length ? AXES[i] : String(i + 1))}
|
|
407
404
|
value={x}
|
|
408
405
|
onValueChange={(n, d) =>
|
|
409
|
-
onValueChange?.(
|
|
406
|
+
onValueChange?.(
|
|
407
|
+
value.map((v, j) => (j === i ? n : v)),
|
|
408
|
+
d,
|
|
409
|
+
)
|
|
410
410
|
}
|
|
411
411
|
/>
|
|
412
412
|
))}
|
|
@@ -414,15 +414,19 @@ function VectorField({
|
|
|
414
414
|
)
|
|
415
415
|
}
|
|
416
416
|
|
|
417
|
-
export { NumberField, VectorField }
|
|
418
417
|
export type { NumberChange, NumberFieldProps, VectorFieldProps }
|
|
418
|
+
export { NumberField, VectorField }
|
|
419
419
|
|
|
420
420
|
/**
|
|
421
421
|
* Pixels of drag per step, so a full-range scrub is about 300px whatever the step: a 0–8 field
|
|
422
422
|
* with 0.25 steps moves one step per ~9px instead of per pixel, which read as jumping.
|
|
423
423
|
* Unbounded ranges keep one step per pixel.
|
|
424
424
|
*/
|
|
425
|
-
function pixelsPerStep(
|
|
425
|
+
function pixelsPerStep(
|
|
426
|
+
min: number | undefined,
|
|
427
|
+
max: number | undefined,
|
|
428
|
+
step: number | undefined,
|
|
429
|
+
): number {
|
|
426
430
|
if (min == null || max == null || !step || max <= min) return 1
|
|
427
431
|
return Math.min(12, Math.max(1, Math.round((300 * step) / (max - min))))
|
|
428
432
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
1
|
import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
|
|
2
|
+
import type * as React from "react"
|
|
3
3
|
|
|
4
4
|
import { cn } from "../lib/utils"
|
|
5
5
|
|
|
@@ -33,7 +33,7 @@ function PopoverContent({
|
|
|
33
33
|
data-slot="popover-content"
|
|
34
34
|
className={cn(
|
|
35
35
|
"z-50 flex w-72 origin-(--transform-origin) flex-col gap-4 rounded-md bg-popover p-4 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
36
|
-
className
|
|
36
|
+
className,
|
|
37
37
|
)}
|
|
38
38
|
{...props}
|
|
39
39
|
/>
|
|
@@ -72,11 +72,4 @@ function PopoverDescription({ className, ...props }: PopoverPrimitive.Descriptio
|
|
|
72
72
|
)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export {
|
|
76
|
-
Popover,
|
|
77
|
-
PopoverContent,
|
|
78
|
-
PopoverDescription,
|
|
79
|
-
PopoverHeader,
|
|
80
|
-
PopoverTitle,
|
|
81
|
-
PopoverTrigger,
|
|
82
|
-
}
|
|
75
|
+
export { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger }
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import * as React from "react"
|
|
4
3
|
import { Select as SelectPrimitive } from "@base-ui/react/select"
|
|
5
|
-
|
|
4
|
+
import { CaretDownIcon, CaretUpIcon, CheckIcon } from "@phosphor-icons/react"
|
|
5
|
+
import type * as React from "react"
|
|
6
6
|
import { cn } from "../lib/utils"
|
|
7
|
-
import { CaretDownIcon, CheckIcon, CaretUpIcon } from "@phosphor-icons/react"
|
|
8
7
|
|
|
9
8
|
const Select = SelectPrimitive.Root
|
|
10
9
|
|
|
@@ -42,15 +41,13 @@ function SelectTrigger({
|
|
|
42
41
|
data-size={size}
|
|
43
42
|
className={cn(
|
|
44
43
|
"flex w-fit items-center justify-between gap-1.5 rounded-none border border-input bg-transparent py-2 pr-2 pl-2.5 text-xs whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-none *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
45
|
-
className
|
|
44
|
+
className,
|
|
46
45
|
)}
|
|
47
46
|
{...props}
|
|
48
47
|
>
|
|
49
48
|
{children}
|
|
50
49
|
<SelectPrimitive.Icon
|
|
51
|
-
render={
|
|
52
|
-
<CaretDownIcon className="pointer-events-none size-4 text-muted-foreground" />
|
|
53
|
-
}
|
|
50
|
+
render={<CaretDownIcon className="pointer-events-none size-4 text-muted-foreground" />}
|
|
54
51
|
/>
|
|
55
52
|
</SelectPrimitive.Trigger>
|
|
56
53
|
)
|
|
@@ -83,7 +80,10 @@ function SelectContent({
|
|
|
83
80
|
<SelectPrimitive.Popup
|
|
84
81
|
data-slot="select-content"
|
|
85
82
|
data-align-trigger={alignItemWithTrigger}
|
|
86
|
-
className={cn(
|
|
83
|
+
className={cn(
|
|
84
|
+
"relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-none bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
85
|
+
className,
|
|
86
|
+
)}
|
|
87
87
|
{...props}
|
|
88
88
|
>
|
|
89
89
|
<SelectScrollUpButton />
|
|
@@ -95,10 +95,7 @@ function SelectContent({
|
|
|
95
95
|
)
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
function SelectLabel({
|
|
99
|
-
className,
|
|
100
|
-
...props
|
|
101
|
-
}: SelectPrimitive.GroupLabel.Props) {
|
|
98
|
+
function SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {
|
|
102
99
|
return (
|
|
103
100
|
<SelectPrimitive.GroupLabel
|
|
104
101
|
data-slot="select-label"
|
|
@@ -108,17 +105,13 @@ function SelectLabel({
|
|
|
108
105
|
)
|
|
109
106
|
}
|
|
110
107
|
|
|
111
|
-
function SelectItem({
|
|
112
|
-
className,
|
|
113
|
-
children,
|
|
114
|
-
...props
|
|
115
|
-
}: SelectPrimitive.Item.Props) {
|
|
108
|
+
function SelectItem({ className, children, ...props }: SelectPrimitive.Item.Props) {
|
|
116
109
|
return (
|
|
117
110
|
<SelectPrimitive.Item
|
|
118
111
|
data-slot="select-item"
|
|
119
112
|
className={cn(
|
|
120
113
|
"relative flex w-full cursor-default items-center gap-2 rounded-none py-2 pr-8 pl-2 text-xs outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
121
|
-
className
|
|
114
|
+
className,
|
|
122
115
|
)}
|
|
123
116
|
{...props}
|
|
124
117
|
>
|
|
@@ -136,10 +129,7 @@ function SelectItem({
|
|
|
136
129
|
)
|
|
137
130
|
}
|
|
138
131
|
|
|
139
|
-
function SelectSeparator({
|
|
140
|
-
className,
|
|
141
|
-
...props
|
|
142
|
-
}: SelectPrimitive.Separator.Props) {
|
|
132
|
+
function SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {
|
|
143
133
|
return (
|
|
144
134
|
<SelectPrimitive.Separator
|
|
145
135
|
data-slot="select-separator"
|
|
@@ -158,12 +148,11 @@ function SelectScrollUpButton({
|
|
|
158
148
|
data-slot="select-scroll-up-button"
|
|
159
149
|
className={cn(
|
|
160
150
|
"top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
161
|
-
className
|
|
151
|
+
className,
|
|
162
152
|
)}
|
|
163
153
|
{...props}
|
|
164
154
|
>
|
|
165
|
-
<CaretUpIcon
|
|
166
|
-
/>
|
|
155
|
+
<CaretUpIcon />
|
|
167
156
|
</SelectPrimitive.ScrollUpArrow>
|
|
168
157
|
)
|
|
169
158
|
}
|
|
@@ -177,12 +166,11 @@ function SelectScrollDownButton({
|
|
|
177
166
|
data-slot="select-scroll-down-button"
|
|
178
167
|
className={cn(
|
|
179
168
|
"bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
180
|
-
className
|
|
169
|
+
className,
|
|
181
170
|
)}
|
|
182
171
|
{...props}
|
|
183
172
|
>
|
|
184
|
-
<CaretDownIcon
|
|
185
|
-
/>
|
|
173
|
+
<CaretDownIcon />
|
|
186
174
|
</SelectPrimitive.ScrollDownArrow>
|
|
187
175
|
)
|
|
188
176
|
}
|
|
@@ -4,18 +4,14 @@ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
|
|
|
4
4
|
|
|
5
5
|
import { cn } from "../lib/utils"
|
|
6
6
|
|
|
7
|
-
function Separator({
|
|
8
|
-
className,
|
|
9
|
-
orientation = "horizontal",
|
|
10
|
-
...props
|
|
11
|
-
}: SeparatorPrimitive.Props) {
|
|
7
|
+
function Separator({ className, orientation = "horizontal", ...props }: SeparatorPrimitive.Props) {
|
|
12
8
|
return (
|
|
13
9
|
<SeparatorPrimitive
|
|
14
10
|
data-slot="separator"
|
|
15
11
|
orientation={orientation}
|
|
16
12
|
className={cn(
|
|
17
13
|
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
|
18
|
-
className
|
|
14
|
+
className,
|
|
19
15
|
)}
|
|
20
16
|
{...props}
|
|
21
17
|
/>
|
package/src/components/sheet.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
1
|
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
|
|
3
2
|
import { XIcon } from "@phosphor-icons/react"
|
|
3
|
+
import type * as React from "react"
|
|
4
4
|
|
|
5
5
|
import { cn } from "../lib/utils"
|
|
6
6
|
import { Button } from "./button"
|
|
@@ -28,7 +28,7 @@ function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
|
|
|
28
28
|
data-slot="sheet-overlay"
|
|
29
29
|
className={cn(
|
|
30
30
|
"fixed inset-0 z-50 bg-foreground/40 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
31
|
-
className
|
|
31
|
+
className,
|
|
32
32
|
)}
|
|
33
33
|
{...props}
|
|
34
34
|
/>
|
|
@@ -61,7 +61,7 @@ function SheetContent({
|
|
|
61
61
|
"inset-x-0 top-0 h-auto border-b data-closed:slide-out-to-top data-open:slide-in-from-top",
|
|
62
62
|
side === "bottom" &&
|
|
63
63
|
"inset-x-0 bottom-0 h-auto border-t data-closed:slide-out-to-bottom data-open:slide-in-from-bottom",
|
|
64
|
-
className
|
|
64
|
+
className,
|
|
65
65
|
)}
|
|
66
66
|
{...props}
|
|
67
67
|
>
|
|
@@ -82,13 +82,21 @@ function SheetContent({
|
|
|
82
82
|
|
|
83
83
|
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
84
84
|
return (
|
|
85
|
-
<div
|
|
85
|
+
<div
|
|
86
|
+
data-slot="sheet-header"
|
|
87
|
+
className={cn("flex flex-col gap-1.5 p-4", className)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
86
90
|
)
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
90
94
|
return (
|
|
91
|
-
<div
|
|
95
|
+
<div
|
|
96
|
+
data-slot="sheet-footer"
|
|
97
|
+
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
92
100
|
)
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -114,11 +122,11 @@ function SheetDescription({ className, ...props }: SheetPrimitive.Description.Pr
|
|
|
114
122
|
|
|
115
123
|
export {
|
|
116
124
|
Sheet,
|
|
117
|
-
SheetTrigger,
|
|
118
125
|
SheetClose,
|
|
119
126
|
SheetContent,
|
|
120
|
-
|
|
127
|
+
SheetDescription,
|
|
121
128
|
SheetFooter,
|
|
129
|
+
SheetHeader,
|
|
122
130
|
SheetTitle,
|
|
123
|
-
|
|
131
|
+
SheetTrigger,
|
|
124
132
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as React from "react"
|
|
1
|
+
import type * as React from "react"
|
|
2
2
|
|
|
3
3
|
import { cn } from "../lib/utils"
|
|
4
4
|
import { buttonVariants } from "./button"
|
|
@@ -58,7 +58,12 @@ function SidePanel({
|
|
|
58
58
|
data-slot="side-panel"
|
|
59
59
|
data-state="closed"
|
|
60
60
|
aria-label={title}
|
|
61
|
-
className={cn(
|
|
61
|
+
className={cn(
|
|
62
|
+
"flex w-10 shrink-0 flex-col items-center bg-sidebar py-2 text-sidebar-foreground",
|
|
63
|
+
border,
|
|
64
|
+
"border-sidebar-border",
|
|
65
|
+
className,
|
|
66
|
+
)}
|
|
62
67
|
{...props}
|
|
63
68
|
>
|
|
64
69
|
<Tooltip>
|
|
@@ -77,7 +82,10 @@ function SidePanel({
|
|
|
77
82
|
<TooltipContent side={side === "left" ? "right" : "left"}>
|
|
78
83
|
<span>Show {title}</span>
|
|
79
84
|
{shortcut ? (
|
|
80
|
-
<kbd
|
|
85
|
+
<kbd
|
|
86
|
+
data-slot="kbd"
|
|
87
|
+
className="rounded-sm bg-background/20 px-1 font-sans text-[11px]"
|
|
88
|
+
>
|
|
81
89
|
{shortcut}
|
|
82
90
|
</kbd>
|
|
83
91
|
) : null}
|
|
@@ -121,10 +129,16 @@ function SidePanel({
|
|
|
121
129
|
data-state="open"
|
|
122
130
|
aria-label={title}
|
|
123
131
|
style={{ width: w }}
|
|
124
|
-
className={cn(
|
|
132
|
+
className={cn(
|
|
133
|
+
"relative flex shrink-0 flex-col overflow-hidden bg-sidebar text-sidebar-foreground",
|
|
134
|
+
border,
|
|
135
|
+
"border-sidebar-border",
|
|
136
|
+
className,
|
|
137
|
+
)}
|
|
125
138
|
{...props}
|
|
126
139
|
>
|
|
127
140
|
{children}
|
|
141
|
+
{/* biome-ignore lint/a11y/useSemanticElements: a focusable, keyboard-operable splitter (WAI-ARIA window splitter); <hr> is not focusable */}
|
|
128
142
|
<div
|
|
129
143
|
role="separator"
|
|
130
144
|
aria-orientation="vertical"
|
|
@@ -137,7 +151,7 @@ function SidePanel({
|
|
|
137
151
|
onKeyDown={onKey}
|
|
138
152
|
className={cn(
|
|
139
153
|
"absolute inset-y-0 z-10 w-1 cursor-col-resize touch-none hover:bg-primary/30 focus-visible:bg-primary/40 focus-visible:outline-none",
|
|
140
|
-
side === "left" ? "right-0" : "left-0"
|
|
154
|
+
side === "left" ? "right-0" : "left-0",
|
|
141
155
|
)}
|
|
142
156
|
/>
|
|
143
157
|
</aside>
|
|
@@ -149,7 +163,10 @@ function SidePanelHeader({ className, children, ...props }: React.ComponentProps
|
|
|
149
163
|
return (
|
|
150
164
|
<div
|
|
151
165
|
data-slot="side-panel-header"
|
|
152
|
-
className={cn(
|
|
166
|
+
className={cn(
|
|
167
|
+
"flex h-9 shrink-0 items-center gap-2 border-b border-sidebar-border px-3 text-xs font-medium uppercase tracking-wide text-muted-foreground",
|
|
168
|
+
className,
|
|
169
|
+
)}
|
|
153
170
|
{...props}
|
|
154
171
|
>
|
|
155
172
|
{children}
|
|
@@ -159,8 +176,14 @@ function SidePanelHeader({ className, children, ...props }: React.ComponentProps
|
|
|
159
176
|
|
|
160
177
|
/** The scrolling body under the header. */
|
|
161
178
|
function SidePanelContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
162
|
-
return
|
|
179
|
+
return (
|
|
180
|
+
<div
|
|
181
|
+
data-slot="side-panel-content"
|
|
182
|
+
className={cn("min-h-0 flex-1 overflow-auto", className)}
|
|
183
|
+
{...props}
|
|
184
|
+
/>
|
|
185
|
+
)
|
|
163
186
|
}
|
|
164
187
|
|
|
165
|
-
export { SidePanel, SidePanelContent, SidePanelHeader, clampWidth }
|
|
166
188
|
export type { SidePanelProps }
|
|
189
|
+
export { clampWidth, SidePanel, SidePanelContent, SidePanelHeader }
|
|
@@ -1,29 +1,18 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import * as React from "react"
|
|
4
3
|
import { useRender } from "@base-ui/react/use-render"
|
|
5
|
-
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
4
|
import { SidebarSimpleIcon } from "@phosphor-icons/react"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
import * as React from "react"
|
|
7
7
|
|
|
8
8
|
import { useIsMobile } from "../lib/use-mobile"
|
|
9
9
|
import { cn } from "../lib/utils"
|
|
10
10
|
import { Button } from "./button"
|
|
11
11
|
import { Input } from "./input"
|
|
12
12
|
import { Separator } from "./separator"
|
|
13
|
-
import {
|
|
14
|
-
Sheet,
|
|
15
|
-
SheetContent,
|
|
16
|
-
SheetDescription,
|
|
17
|
-
SheetHeader,
|
|
18
|
-
SheetTitle,
|
|
19
|
-
} from "./sheet"
|
|
13
|
+
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "./sheet"
|
|
20
14
|
import { Skeleton } from "./skeleton"
|
|
21
|
-
import {
|
|
22
|
-
Tooltip,
|
|
23
|
-
TooltipContent,
|
|
24
|
-
TooltipProvider,
|
|
25
|
-
TooltipTrigger,
|
|
26
|
-
} from "./tooltip"
|
|
15
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip"
|
|
27
16
|
|
|
28
17
|
// Base UI's replacement for Radix's asChild: pass `render={<a href="..." />}`
|
|
29
18
|
// to swap the element, props and ref are merged onto it.
|
|
@@ -93,6 +82,7 @@ function SidebarProvider({
|
|
|
93
82
|
}
|
|
94
83
|
|
|
95
84
|
// This sets the cookie to keep the sidebar state.
|
|
85
|
+
// biome-ignore lint/suspicious/noDocumentCookie: the Cookie Store API is not in every webview, and the cookie is written for hosts that read it server-side
|
|
96
86
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
|
97
87
|
},
|
|
98
88
|
[setOpenProp, open],
|
|
@@ -101,15 +91,12 @@ function SidebarProvider({
|
|
|
101
91
|
// Helper to toggle the sidebar.
|
|
102
92
|
const toggleSidebar = React.useCallback(() => {
|
|
103
93
|
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
|
|
104
|
-
}, [isMobile, setOpen
|
|
94
|
+
}, [isMobile, setOpen])
|
|
105
95
|
|
|
106
96
|
// Adds a keyboard shortcut to toggle the sidebar.
|
|
107
97
|
React.useEffect(() => {
|
|
108
98
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
109
|
-
if (
|
|
110
|
-
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
|
|
111
|
-
(event.metaKey || event.ctrlKey)
|
|
112
|
-
) {
|
|
99
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
113
100
|
event.preventDefault()
|
|
114
101
|
toggleSidebar()
|
|
115
102
|
}
|
|
@@ -133,7 +120,7 @@ function SidebarProvider({
|
|
|
133
120
|
setOpenMobile,
|
|
134
121
|
toggleSidebar,
|
|
135
122
|
}),
|
|
136
|
-
[state, open, setOpen, isMobile, openMobile,
|
|
123
|
+
[state, open, setOpen, isMobile, openMobile, toggleSidebar],
|
|
137
124
|
)
|
|
138
125
|
|
|
139
126
|
return (
|
|
@@ -263,11 +250,7 @@ function Sidebar({
|
|
|
263
250
|
)
|
|
264
251
|
}
|
|
265
252
|
|
|
266
|
-
function SidebarTrigger({
|
|
267
|
-
className,
|
|
268
|
-
onClick,
|
|
269
|
-
...props
|
|
270
|
-
}: React.ComponentProps<typeof Button>) {
|
|
253
|
+
function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<typeof Button>) {
|
|
271
254
|
const { toggleSidebar } = useSidebar()
|
|
272
255
|
|
|
273
256
|
return (
|
|
@@ -328,10 +311,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
|
|
328
311
|
)
|
|
329
312
|
}
|
|
330
313
|
|
|
331
|
-
function SidebarInput({
|
|
332
|
-
className,
|
|
333
|
-
...props
|
|
334
|
-
}: React.ComponentProps<typeof Input>) {
|
|
314
|
+
function SidebarInput({ className, ...props }: React.ComponentProps<typeof Input>) {
|
|
335
315
|
return (
|
|
336
316
|
<Input
|
|
337
317
|
data-slot="sidebar-input"
|
|
@@ -364,10 +344,7 @@ function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
|
364
344
|
)
|
|
365
345
|
}
|
|
366
346
|
|
|
367
|
-
function SidebarSeparator({
|
|
368
|
-
className,
|
|
369
|
-
...props
|
|
370
|
-
}: React.ComponentProps<typeof Separator>) {
|
|
347
|
+
function SidebarSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
|
|
371
348
|
return (
|
|
372
349
|
<Separator
|
|
373
350
|
data-slot="sidebar-separator"
|
|
@@ -447,10 +424,7 @@ function SidebarGroupAction({
|
|
|
447
424
|
)
|
|
448
425
|
}
|
|
449
426
|
|
|
450
|
-
function SidebarGroupContent({
|
|
451
|
-
className,
|
|
452
|
-
...props
|
|
453
|
-
}: React.ComponentProps<"div">) {
|
|
427
|
+
function SidebarGroupContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
454
428
|
return (
|
|
455
429
|
<div
|
|
456
430
|
data-slot="sidebar-group-content"
|
|
@@ -588,10 +562,7 @@ function SidebarMenuAction({
|
|
|
588
562
|
)
|
|
589
563
|
}
|
|
590
564
|
|
|
591
|
-
function SidebarMenuBadge({
|
|
592
|
-
className,
|
|
593
|
-
...props
|
|
594
|
-
}: React.ComponentProps<"div">) {
|
|
565
|
+
function SidebarMenuBadge({ className, ...props }: React.ComponentProps<"div">) {
|
|
595
566
|
return (
|
|
596
567
|
<div
|
|
597
568
|
data-slot="sidebar-menu-badge"
|
|
@@ -627,12 +598,7 @@ function SidebarMenuSkeleton({
|
|
|
627
598
|
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
|
|
628
599
|
{...props}
|
|
629
600
|
>
|
|
630
|
-
{showIcon &&
|
|
631
|
-
<Skeleton
|
|
632
|
-
className="size-4 rounded-md"
|
|
633
|
-
data-sidebar="menu-skeleton-icon"
|
|
634
|
-
/>
|
|
635
|
-
)}
|
|
601
|
+
{showIcon && <Skeleton className="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
|
|
636
602
|
<Skeleton
|
|
637
603
|
className="h-4 max-w-(--skeleton-width) flex-1"
|
|
638
604
|
data-sidebar="menu-skeleton-text"
|
|
@@ -661,10 +627,7 @@ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
|
|
|
661
627
|
)
|
|
662
628
|
}
|
|
663
629
|
|
|
664
|
-
function SidebarMenuSubItem({
|
|
665
|
-
className,
|
|
666
|
-
...props
|
|
667
|
-
}: React.ComponentProps<"li">) {
|
|
630
|
+
function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
668
631
|
return (
|
|
669
632
|
<li
|
|
670
633
|
data-slot="sidebar-menu-sub-item"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
1
|
import { Slider as SliderPrimitive } from "@base-ui/react/slider"
|
|
2
|
+
import * as React from "react"
|
|
3
3
|
|
|
4
4
|
import { cn } from "../lib/utils"
|
|
5
5
|
|
|
@@ -21,13 +21,8 @@ function Slider({
|
|
|
21
21
|
const [live, setLive] = React.useState<typeof valueProp | null>(null)
|
|
22
22
|
const value = live ?? valueProp
|
|
23
23
|
const _values = React.useMemo(
|
|
24
|
-
() =>
|
|
25
|
-
|
|
26
|
-
? value
|
|
27
|
-
: Array.isArray(defaultValue)
|
|
28
|
-
? defaultValue
|
|
29
|
-
: [min],
|
|
30
|
-
[value, defaultValue, min]
|
|
24
|
+
() => (Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min]),
|
|
25
|
+
[value, defaultValue, min],
|
|
31
26
|
)
|
|
32
27
|
|
|
33
28
|
return (
|
|
@@ -62,6 +57,7 @@ function Slider({
|
|
|
62
57
|
{Array.from({ length: _values.length }, (_, index) => (
|
|
63
58
|
<SliderPrimitive.Thumb
|
|
64
59
|
data-slot="slider-thumb"
|
|
60
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: thumbs are positional; the count is fixed by the value array and they have no identity
|
|
65
61
|
key={index}
|
|
66
62
|
index={index}
|
|
67
63
|
className="block h-4 w-2 shrink-0 rounded-[1px] border border-muted-foreground bg-background ring-ring/50 transition-[color,box-shadow] select-none hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden has-[:focus-visible]:ring-4 data-disabled:pointer-events-none data-disabled:opacity-50"
|