@passui/react 0.1.45 → 0.1.47

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