@passui/react 0.1.45 → 0.1.46
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 +57 -46
- package/dist/types/src/components/accordion/accordion.d.ts +1 -1
- package/dist/types/src/components/breadcrumb/breadcrumb.d.ts +1 -1
- package/dist/types/src/components/inline-disclosure/inline-disclosure.d.ts +1 -1
- package/dist/types/src/components/popover/anchored-surface.d.ts +5 -1
- package/dist/types/src/components/popover/index.d.ts +41 -0
- package/dist/types/src/components/popover/popover-content.d.ts +32 -0
- package/dist/types/src/components/popover/popover-root.d.ts +22 -0
- package/dist/types/src/components/popover/popover-trigger.d.ts +23 -0
- package/dist/types/src/components/stepper/rolling-digit.d.ts +1 -1
- package/dist/types/src/components/table/table.d.ts +1 -1
- package/dist/types/src/components/view-controller/view-controller.d.ts +2 -2
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/machines/popover.machine.d.ts +30 -0
- package/package.json +307 -307
- package/src/appearance/index.ts +2 -2
- package/src/appearance/platform.tsx +76 -60
- package/src/appearance/theme.tsx +409 -377
- package/src/components/accordion/accordion.tsx +58 -49
- package/src/components/ambient/ambient.tsx +25 -25
- package/src/components/ambient/index.ts +1 -1
- package/src/components/aspect-ratio/aspect-ratio.tsx +21 -16
- package/src/components/breadcrumb/breadcrumb.tsx +63 -57
- package/src/components/button/button-styles.ts +39 -32
- package/src/components/button/button.tsx +91 -84
- package/src/components/button/icon-button.tsx +27 -25
- package/src/components/button/pending-spinner.tsx +8 -8
- package/src/components/button/use-pending-indicator.ts +11 -11
- package/src/components/chip/chip.tsx +35 -30
- package/src/components/code-block/code-block.tsx +40 -39
- package/src/components/combo-box/combo-box.tsx +5 -5
- package/src/components/command/command.tsx +124 -94
- package/src/components/compact-date-picker/calendar-month.ts +75 -53
- package/src/components/compact-date-picker/compact-date-picker.tsx +308 -289
- package/src/components/compact-time-picker/compact-time-picker.tsx +288 -281
- package/src/components/compact-time-picker/time-value.ts +32 -29
- package/src/components/content-unavailable-view/content-unavailable-view.tsx +64 -48
- package/src/components/content-view/content-view.tsx +168 -159
- package/src/components/content-view/index.ts +1 -1
- package/src/components/context-menu/conceal-menu-source.ts +25 -25
- package/src/components/context-menu/context-menu-host.tsx +439 -402
- package/src/components/context-menu/context-menu-store.ts +125 -123
- package/src/components/context-menu/menu-navigation.ts +25 -18
- package/src/components/context-menu/menu-position.ts +33 -29
- package/src/components/context-menu/menu-reveal.ts +32 -32
- package/src/components/context-menu/use-context-menu.ts +63 -56
- package/src/components/conversation/conversation.tsx +265 -263
- package/src/components/conversation/index.ts +1 -1
- package/src/components/date-picker/date-picker.tsx +95 -94
- package/src/components/date-picker/date-value.ts +20 -10
- package/src/components/dialog/dialog-host.tsx +105 -103
- package/src/components/dialog/dialog-store.ts +37 -36
- package/src/components/dialog/dialog.tsx +192 -179
- package/src/components/dialog/index.ts +1 -1
- package/src/components/disclosure-group/disclosure-group.tsx +93 -86
- package/src/components/divider/divider.tsx +24 -22
- package/src/components/inline-disclosure/inline-disclosure.tsx +40 -36
- package/src/components/keyboard-shortcut/keyboard-shortcut.tsx +23 -19
- package/src/components/labeled-content/labeled-content.tsx +68 -68
- package/src/components/locale-switcher/index.ts +1 -1
- package/src/components/locale-switcher/locale-switcher.tsx +279 -251
- package/src/components/menu/menu.tsx +75 -58
- package/src/components/morph/index.ts +2 -2
- package/src/components/morph/morph.tsx +227 -201
- package/src/components/morph/use-morph-disclosure.ts +19 -19
- package/src/components/one-time-code/one-time-code.tsx +216 -200
- package/src/components/picker/picker-trigger.ts +16 -13
- package/src/components/picker/picker.tsx +371 -345
- package/src/components/popover/anchored-surface.tsx +253 -229
- package/src/components/popover/index.ts +50 -0
- package/src/components/popover/popover-content.tsx +334 -0
- package/src/components/popover/popover-fit.ts +58 -53
- package/src/components/popover/popover-root.tsx +97 -0
- package/src/components/popover/popover-trigger.tsx +71 -0
- package/src/components/profile-image/profile-image.tsx +80 -64
- package/src/components/progress-view/progress-view.tsx +61 -59
- package/src/components/progress-view/use-liquid-progress.ts +38 -38
- package/src/components/radio-group/radio-group.tsx +71 -68
- package/src/components/search-field/expanding-search-field.tsx +191 -177
- package/src/components/search-field/search-field.tsx +59 -50
- package/src/components/search-list/search-list.tsx +246 -236
- package/src/components/section/section.tsx +58 -58
- package/src/components/secure-field/secure-field.tsx +3 -3
- package/src/components/segmented-control/segmented-control.tsx +136 -136
- package/src/components/sheet/modal-environment.ts +71 -64
- package/src/components/sheet/sheet-portal.tsx +58 -53
- package/src/components/sheet/sheet.tsx +146 -141
- package/src/components/sheet/use-sheet-focus.ts +97 -82
- package/src/components/sidebar/sidebar.tsx +78 -78
- package/src/components/skeleton/skeleton.tsx +30 -21
- package/src/components/slider/slider.tsx +113 -104
- package/src/components/slosh-slider/liquid-step.ts +32 -31
- package/src/components/slosh-slider/slosh-slider.tsx +265 -228
- package/src/components/stat-tile/index.ts +1 -1
- package/src/components/stat-tile/stat-tile.tsx +79 -68
- package/src/components/status-indicator/status-indicator.tsx +40 -37
- package/src/components/stepper/rolling-digit.tsx +82 -68
- package/src/components/stepper/stepper.tsx +122 -113
- package/src/components/swatch-picker/swatch-picker.tsx +120 -120
- package/src/components/tab-bar/tab-bar.tsx +149 -148
- package/src/components/tab-view/tab-view.tsx +140 -137
- package/src/components/table/table.tsx +117 -98
- package/src/components/text-editor/text-editor.tsx +34 -29
- package/src/components/text-field/text-field.tsx +182 -180
- package/src/components/toast/toast-store.ts +127 -115
- package/src/components/toast/toaster.tsx +361 -347
- package/src/components/toggle/toggle.tsx +297 -282
- package/src/components/tooltip/tooltip-host.tsx +157 -150
- package/src/components/view-controller/index.ts +1 -1
- package/src/components/view-controller/view-controller.tsx +64 -53
- package/src/components/wake-slider/wake-slider.tsx +220 -205
- package/src/hooks/scroll/minimize-decision.ts +11 -7
- package/src/hooks/use-anchored-disclosure.ts +19 -19
- package/src/hooks/use-anchored-placement.ts +29 -25
- package/src/hooks/use-dismiss.ts +33 -29
- package/src/hooks/use-floating-dismiss.ts +24 -22
- package/src/hooks/use-media-query.ts +67 -60
- package/src/hooks/use-minimize-on-scroll.ts +69 -60
- package/src/hooks/use-visual-viewport.ts +63 -63
- package/src/hooks/viewport/types.ts +16 -16
- package/src/hooks/viewport/viewport-metrics.ts +16 -10
- package/src/icons/icons.tsx +440 -328
- package/src/index.ts +91 -91
- package/src/lib/anchored-placement.ts +70 -65
- package/src/lib/class-names.ts +14 -13
- package/src/lib/clipboard.ts +8 -7
- package/src/lib/date.ts +61 -60
- package/src/lib/floating-layers.ts +39 -24
- package/src/lib/haptics.ts +10 -10
- package/src/lib/language.ts +9 -9
- package/src/lib/range-value.ts +27 -21
- package/src/lib/screen-edges.ts +33 -30
- package/src/lib/shapes.ts +38 -34
- package/src/machines/popover.machine.ts +51 -0
- package/src/motion/transitions.ts +46 -43
- package/src/styles/code-block.css +69 -43
- package/src/styles/motion-controls.css +393 -191
- package/src/tokens.ts +1 -1
- package/dist/types/src/components/popover/popover.d.ts +0 -21
- package/src/components/popover/popover.tsx +0 -334
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
import { useId, type ReactNode } from "react"
|
|
2
|
-
import { cn } from "../../lib/class-names"
|
|
1
|
+
import { useId, type ReactNode } from "react";
|
|
2
|
+
import { cn } from "../../lib/class-names";
|
|
3
3
|
|
|
4
4
|
export interface SidebarSectionProps {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/** Visible heading for this group of navigation rows. */
|
|
6
|
+
title: string;
|
|
7
|
+
children: ReactNode;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export interface SidebarItemContentProps {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
icon?: ReactNode;
|
|
12
|
+
/** Optional trailing count. */
|
|
13
|
+
count?: number;
|
|
14
|
+
/** Matches the router link's active state. */
|
|
15
|
+
active?: boolean;
|
|
16
|
+
children: ReactNode;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function SidebarSection({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
title,
|
|
21
|
+
children,
|
|
22
|
+
size = "md",
|
|
23
23
|
}: SidebarSectionProps & { size?: SidebarSize }) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
const headingId = useId();
|
|
25
|
+
return (
|
|
26
|
+
<section aria-labelledby={headingId} className="flex flex-col gap-0.5">
|
|
27
|
+
<h2 id={headingId} className={sidebarHeadingSizes[size]}>
|
|
28
|
+
{title}
|
|
29
|
+
</h2>
|
|
30
|
+
{children}
|
|
31
|
+
</section>
|
|
32
|
+
);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/** Classes for a sidebar row; apply to the app's router link. */
|
|
36
|
-
export type SidebarDensity = "regular" | "compact"
|
|
37
|
-
export type SidebarSize = "sm" | "md" | "lg"
|
|
36
|
+
export type SidebarDensity = "regular" | "compact";
|
|
37
|
+
export type SidebarSize = "sm" | "md" | "lg";
|
|
38
38
|
|
|
39
39
|
const sidebarItemSizes: Record<SidebarSize, string> = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
40
|
+
sm: "min-h-8 rounded-lg px-2 py-1 text-footnote [@media(pointer:coarse)]:min-h-10",
|
|
41
|
+
md: "rounded-2xl px-2.5 py-[7px] text-subheadline",
|
|
42
|
+
lg: "rounded-2xl px-3 py-2.5 text-body [@media(pointer:coarse)]:min-h-13",
|
|
43
|
+
};
|
|
44
44
|
const sidebarHeadingSizes: Record<SidebarSize, string> = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
45
|
+
sm: "px-2 pb-1 text-caption2 font-semibold text-label-tertiary",
|
|
46
|
+
md: "px-2.5 pb-1.5 text-caption font-semibold text-label-tertiary",
|
|
47
|
+
lg: "px-3 pb-2 text-subheadline font-semibold text-label-tertiary",
|
|
48
|
+
};
|
|
49
49
|
const sidebarCountSizes: Record<SidebarSize, string> = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
50
|
+
sm: "text-caption2 tabular-nums",
|
|
51
|
+
md: "text-footnote tabular-nums",
|
|
52
|
+
lg: "text-subheadline tabular-nums",
|
|
53
|
+
};
|
|
54
54
|
|
|
55
55
|
export function sidebarItemClass(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
active?: boolean,
|
|
57
|
+
density: SidebarDensity = "regular",
|
|
58
|
+
size?: SidebarSize,
|
|
59
59
|
): string {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
const resolved = size ?? (density === "compact" ? "sm" : "md");
|
|
61
|
+
return cn(
|
|
62
|
+
"group text-label duration-fast focus-visible:outline-accent-text flex w-full items-center gap-2.5 no-underline transition-colors focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
63
|
+
sidebarItemSizes[resolved],
|
|
64
|
+
active
|
|
65
|
+
? "bg-fill font-medium"
|
|
66
|
+
: "text-label-secondary hover:bg-fill/70 hover:text-label font-normal",
|
|
67
|
+
);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
export function SidebarItemContent({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
icon,
|
|
72
|
+
count,
|
|
73
|
+
active,
|
|
74
|
+
size = "md",
|
|
75
|
+
children,
|
|
76
76
|
}: SidebarItemContentProps & { size?: SidebarSize }) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
77
|
+
return (
|
|
78
|
+
<>
|
|
79
|
+
{icon && (
|
|
80
|
+
<span
|
|
81
|
+
className={cn(
|
|
82
|
+
"flex transition-colors",
|
|
83
|
+
active ? "text-accent-text" : "text-label-secondary",
|
|
84
|
+
)}
|
|
85
|
+
>
|
|
86
|
+
{icon}
|
|
87
|
+
</span>
|
|
88
|
+
)}
|
|
89
|
+
<span className="grow truncate">{children}</span>
|
|
90
|
+
{count !== undefined && (
|
|
91
|
+
<span
|
|
92
|
+
className={cn(
|
|
93
|
+
sidebarCountSizes[size],
|
|
94
|
+
active ? "text-accent-text" : "text-label-tertiary",
|
|
95
|
+
)}
|
|
96
|
+
>
|
|
97
|
+
{count}
|
|
98
|
+
</span>
|
|
99
|
+
)}
|
|
100
|
+
</>
|
|
101
|
+
);
|
|
102
102
|
}
|
|
@@ -1,29 +1,38 @@
|
|
|
1
|
-
import type { ComponentProps } from "react"
|
|
2
|
-
import { cn } from "../../lib/class-names"
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
import { cn } from "../../lib/class-names";
|
|
3
3
|
|
|
4
|
-
export type SkeletonSize = "sm" | "md" | "lg"
|
|
4
|
+
export type SkeletonSize = "sm" | "md" | "lg";
|
|
5
5
|
|
|
6
6
|
const minHeights: Record<SkeletonSize, string> = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
7
|
+
sm: "min-h-3 rounded-md",
|
|
8
|
+
md: "min-h-4 rounded-md",
|
|
9
|
+
lg: "min-h-6 rounded-lg",
|
|
10
|
+
};
|
|
11
11
|
|
|
12
12
|
export interface SkeletonProps extends ComponentProps<"div"> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
label?: string;
|
|
14
|
+
/** Minimum height and rounding. @default "md" */
|
|
15
|
+
size?: SkeletonSize;
|
|
16
16
|
}
|
|
17
17
|
/** A loading placeholder that becomes still when Reduce Motion is enabled. */
|
|
18
|
-
export function Skeleton({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
export function Skeleton({
|
|
19
|
+
label,
|
|
20
|
+
size = "md",
|
|
21
|
+
className,
|
|
22
|
+
...props
|
|
23
|
+
}: SkeletonProps) {
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
{...props}
|
|
27
|
+
role={label ? "status" : undefined}
|
|
28
|
+
aria-hidden={label ? undefined : true}
|
|
29
|
+
className={cn(
|
|
30
|
+
"bg-fill motion-safe:animate-pulse",
|
|
31
|
+
minHeights[size],
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
>
|
|
35
|
+
{label && <span className="sr-only">{label}</span>}
|
|
36
|
+
</div>
|
|
37
|
+
);
|
|
29
38
|
}
|
|
@@ -1,125 +1,134 @@
|
|
|
1
|
-
import { type ComponentProps, useId } from "react"
|
|
2
|
-
import { cn } from "../../lib/class-names"
|
|
3
|
-
import { clampRange } from "../../lib/range-value"
|
|
1
|
+
import { type ComponentProps, useId } from "react";
|
|
2
|
+
import { cn } from "../../lib/class-names";
|
|
3
|
+
import { clampRange } from "../../lib/range-value";
|
|
4
4
|
|
|
5
|
-
export type SliderSize = "sm" | "md" | "lg"
|
|
5
|
+
export type SliderSize = "sm" | "md" | "lg";
|
|
6
6
|
|
|
7
7
|
const labelSizes: Record<SliderSize, string> = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
8
|
+
sm: "text-footnote font-semibold text-label",
|
|
9
|
+
md: "text-subheadline font-semibold text-label",
|
|
10
|
+
lg: "text-body font-semibold text-label",
|
|
11
|
+
};
|
|
12
12
|
const inputHeights: Record<SliderSize, string> = {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
13
|
+
sm: "h-9",
|
|
14
|
+
md: "h-11",
|
|
15
|
+
lg: "h-13",
|
|
16
|
+
};
|
|
17
17
|
const descriptionSizes: Record<SliderSize, string> = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
18
|
+
sm: "text-caption2 text-label-secondary",
|
|
19
|
+
md: "text-footnote text-label-secondary",
|
|
20
|
+
lg: "text-subheadline text-label-secondary",
|
|
21
|
+
};
|
|
22
22
|
// Track height, thumb size, and the webkit thumb's -mt offset (derived from
|
|
23
23
|
// (thumb - track) / 2: md (20-6)/2=7, sm (16-4)/2=6, lg (24-8)/2=8).
|
|
24
24
|
const webkitTrack: Record<SliderSize, string> = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
sm: "[&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-separator",
|
|
26
|
+
md: "[&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-separator",
|
|
27
|
+
lg: "[&::-webkit-slider-runnable-track]:h-2 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-separator",
|
|
28
|
+
};
|
|
29
29
|
const webkitThumb: Record<SliderSize, string> = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
30
|
+
sm: "[&::-webkit-slider-thumb]:-mt-[6px] [&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-accent [&::-webkit-slider-thumb]:bg-elevated [&::-webkit-slider-thumb]:shadow-sm",
|
|
31
|
+
md: "[&::-webkit-slider-thumb]:-mt-[7px] [&::-webkit-slider-thumb]:size-5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-accent [&::-webkit-slider-thumb]:bg-elevated [&::-webkit-slider-thumb]:shadow-sm",
|
|
32
|
+
lg: "[&::-webkit-slider-thumb]:-mt-[8px] [&::-webkit-slider-thumb]:size-6 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-accent [&::-webkit-slider-thumb]:bg-elevated [&::-webkit-slider-thumb]:shadow-sm",
|
|
33
|
+
};
|
|
34
34
|
const mozTrack: Record<SliderSize, string> = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
35
|
+
sm: "[&::-moz-range-track]:h-1 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-separator",
|
|
36
|
+
md: "[&::-moz-range-track]:h-1.5 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-separator",
|
|
37
|
+
lg: "[&::-moz-range-track]:h-2 [&::-moz-range-track]:rounded-full [&::-moz-range-track]:bg-separator",
|
|
38
|
+
};
|
|
39
39
|
const mozProgress: Record<SliderSize, string> = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
40
|
+
sm: "[&::-moz-range-progress]:h-1 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-accent",
|
|
41
|
+
md: "[&::-moz-range-progress]:h-1.5 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-accent",
|
|
42
|
+
lg: "[&::-moz-range-progress]:h-2 [&::-moz-range-progress]:rounded-full [&::-moz-range-progress]:bg-accent",
|
|
43
|
+
};
|
|
44
44
|
const mozThumb: Record<SliderSize, string> = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
45
|
+
sm: "[&::-moz-range-thumb]:size-3 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-accent [&::-moz-range-thumb]:bg-elevated",
|
|
46
|
+
md: "[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-accent [&::-moz-range-thumb]:bg-elevated",
|
|
47
|
+
lg: "[&::-moz-range-thumb]:size-5 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-accent [&::-moz-range-thumb]:bg-elevated",
|
|
48
|
+
};
|
|
49
49
|
|
|
50
50
|
export interface SliderProps
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
extends Omit<
|
|
52
|
+
ComponentProps<"input">,
|
|
53
|
+
| "type"
|
|
54
|
+
| "value"
|
|
55
|
+
| "defaultValue"
|
|
56
|
+
| "onChange"
|
|
57
|
+
| "min"
|
|
58
|
+
| "max"
|
|
59
|
+
| "step"
|
|
60
|
+
| "size"
|
|
61
|
+
> {
|
|
62
|
+
value: number;
|
|
63
|
+
onChange: (value: number) => void;
|
|
64
|
+
label: string;
|
|
65
|
+
min?: number;
|
|
66
|
+
max?: number;
|
|
67
|
+
step?: number;
|
|
68
|
+
description?: string;
|
|
69
|
+
/** Provides a localized, spoken description of the current value. */
|
|
70
|
+
formatValue?: (value: number) => string;
|
|
71
|
+
/** Track height, thumb size and label/description text scale. @default "md" */
|
|
72
|
+
size?: SliderSize;
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
/** Native keyboard, touch and pointer behavior with Passui's control treatment. */
|
|
69
76
|
export function Slider({
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
value,
|
|
78
|
+
onChange,
|
|
79
|
+
label,
|
|
80
|
+
min = 0,
|
|
81
|
+
max = 100,
|
|
82
|
+
step = 1,
|
|
83
|
+
description,
|
|
84
|
+
formatValue,
|
|
85
|
+
size = "md",
|
|
86
|
+
id: suppliedId,
|
|
87
|
+
className,
|
|
88
|
+
disabled,
|
|
89
|
+
...props
|
|
83
90
|
}: SliderProps) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
const generatedId = useId();
|
|
92
|
+
const id = suppliedId ?? generatedId;
|
|
93
|
+
const upper = Math.max(min, max);
|
|
94
|
+
const current = clampRange(value, min, upper);
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
96
|
+
return (
|
|
97
|
+
<div
|
|
98
|
+
className={cn("flex min-w-0 flex-col gap-2", disabled && "opacity-45")}
|
|
99
|
+
>
|
|
100
|
+
<label htmlFor={id} className={labelSizes[size]}>
|
|
101
|
+
{label}
|
|
102
|
+
</label>
|
|
103
|
+
<input
|
|
104
|
+
{...props}
|
|
105
|
+
id={id}
|
|
106
|
+
type="range"
|
|
107
|
+
min={min}
|
|
108
|
+
max={upper}
|
|
109
|
+
step={step > 0 ? step : 1}
|
|
110
|
+
value={current}
|
|
111
|
+
disabled={disabled || upper === min}
|
|
112
|
+
aria-valuetext={formatValue?.(current)}
|
|
113
|
+
aria-describedby={description ? `${id}-description` : undefined}
|
|
114
|
+
onChange={(event) => onChange(Number(event.currentTarget.value))}
|
|
115
|
+
className={cn(
|
|
116
|
+
"accent-accent w-full min-w-0 cursor-pointer appearance-none bg-transparent",
|
|
117
|
+
inputHeights[size],
|
|
118
|
+
"focus-visible:outline-accent-text focus-visible:rounded-lg focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
119
|
+
webkitTrack[size],
|
|
120
|
+
webkitThumb[size],
|
|
121
|
+
mozTrack[size],
|
|
122
|
+
mozProgress[size],
|
|
123
|
+
mozThumb[size],
|
|
124
|
+
className,
|
|
125
|
+
)}
|
|
126
|
+
/>
|
|
127
|
+
{description && (
|
|
128
|
+
<p id={`${id}-description`} className={descriptionSizes[size]}>
|
|
129
|
+
{description}
|
|
130
|
+
</p>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
125
134
|
}
|
|
@@ -1,42 +1,43 @@
|
|
|
1
|
-
import { clampRange } from "../../lib/range-value"
|
|
1
|
+
import { clampRange } from "../../lib/range-value";
|
|
2
2
|
|
|
3
3
|
export interface LiquidState {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
fill: number;
|
|
5
|
+
velocity: number;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/** Bencho's frame-normalized liquid spring. See THIRD_PARTY_NOTICES.md. */
|
|
9
9
|
export function stepLiquid(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
state: LiquidState,
|
|
11
|
+
target: number,
|
|
12
|
+
viscosity: number,
|
|
13
|
+
dt: number,
|
|
14
14
|
): LiquidState {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const soft = clampRange(viscosity, 0, 100) / 100;
|
|
16
|
+
target = clampRange(target, 0, 100);
|
|
17
|
+
dt = clampRange(dt, 0, 2.5);
|
|
18
|
+
if (soft === 0) {
|
|
19
|
+
/* 0 is an ordinary slider and has to be exactly that,
|
|
20
20
|
not a very stiff spring that still rings. */
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
return { fill: target, velocity: 0 };
|
|
22
|
+
}
|
|
23
|
+
/* Stiffness falls and damping rises together: thin liquid is slow to
|
|
24
24
|
answer and slow to forget, which is why these are one knob. */
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const stiff = 0.34 - soft * 0.29;
|
|
26
|
+
const damp = 0.74 + soft * 0.22;
|
|
27
|
+
let velocity =
|
|
28
|
+
(state.velocity + (target - state.fill) * stiff * dt) * damp ** dt;
|
|
29
|
+
let fill = state.fill + velocity * dt;
|
|
30
|
+
/* The end stop is a wall, and a wall gives some back. Without this
|
|
30
31
|
the overshoot is swallowed exactly where you are looking at it. */
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
if (fill > 100) {
|
|
33
|
+
fill = 100;
|
|
34
|
+
velocity = -velocity * 0.42;
|
|
35
|
+
}
|
|
36
|
+
if (fill < 0) {
|
|
37
|
+
fill = 0;
|
|
38
|
+
velocity = -velocity * 0.42;
|
|
39
|
+
}
|
|
40
|
+
if (Math.abs(target - fill) < 0.02 && Math.abs(velocity) < 0.02)
|
|
41
|
+
return { fill: target, velocity: 0 };
|
|
42
|
+
return { fill, velocity };
|
|
42
43
|
}
|