@passui/react 0.1.44 → 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.
Files changed (140) 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 +32 -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 -398
  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 +279 -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 +334 -0
  72. package/src/components/popover/popover-fit.ts +58 -53
  73. package/src/components/popover/popover-root.tsx +97 -0
  74. package/src/components/popover/popover-trigger.tsx +71 -0
  75. package/src/components/profile-image/profile-image.tsx +80 -64
  76. package/src/components/progress-view/progress-view.tsx +61 -59
  77. package/src/components/progress-view/use-liquid-progress.ts +38 -38
  78. package/src/components/radio-group/radio-group.tsx +71 -68
  79. package/src/components/search-field/expanding-search-field.tsx +191 -177
  80. package/src/components/search-field/search-field.tsx +59 -50
  81. package/src/components/search-list/search-list.tsx +246 -236
  82. package/src/components/section/section.tsx +58 -58
  83. package/src/components/secure-field/secure-field.tsx +3 -3
  84. package/src/components/segmented-control/segmented-control.tsx +136 -136
  85. package/src/components/sheet/modal-environment.ts +71 -64
  86. package/src/components/sheet/sheet-portal.tsx +58 -53
  87. package/src/components/sheet/sheet.tsx +146 -141
  88. package/src/components/sheet/use-sheet-focus.ts +97 -82
  89. package/src/components/sidebar/sidebar.tsx +78 -78
  90. package/src/components/skeleton/skeleton.tsx +30 -21
  91. package/src/components/slider/slider.tsx +113 -104
  92. package/src/components/slosh-slider/liquid-step.ts +32 -31
  93. package/src/components/slosh-slider/slosh-slider.tsx +265 -228
  94. package/src/components/stat-tile/index.ts +1 -1
  95. package/src/components/stat-tile/stat-tile.tsx +79 -68
  96. package/src/components/status-indicator/status-indicator.tsx +40 -37
  97. package/src/components/stepper/rolling-digit.tsx +82 -68
  98. package/src/components/stepper/stepper.tsx +122 -113
  99. package/src/components/swatch-picker/swatch-picker.tsx +120 -120
  100. package/src/components/tab-bar/tab-bar.tsx +149 -148
  101. package/src/components/tab-view/tab-view.tsx +140 -137
  102. package/src/components/table/table.tsx +117 -98
  103. package/src/components/text-editor/text-editor.tsx +34 -29
  104. package/src/components/text-field/text-field.tsx +182 -180
  105. package/src/components/toast/toast-store.ts +127 -115
  106. package/src/components/toast/toaster.tsx +361 -347
  107. package/src/components/toggle/toggle.tsx +297 -282
  108. package/src/components/tooltip/tooltip-host.tsx +157 -150
  109. package/src/components/view-controller/index.ts +1 -1
  110. package/src/components/view-controller/view-controller.tsx +64 -53
  111. package/src/components/wake-slider/wake-slider.tsx +220 -205
  112. package/src/hooks/scroll/minimize-decision.ts +11 -7
  113. package/src/hooks/use-anchored-disclosure.ts +19 -19
  114. package/src/hooks/use-anchored-placement.ts +29 -25
  115. package/src/hooks/use-dismiss.ts +33 -29
  116. package/src/hooks/use-floating-dismiss.ts +24 -22
  117. package/src/hooks/use-media-query.ts +67 -60
  118. package/src/hooks/use-minimize-on-scroll.ts +69 -60
  119. package/src/hooks/use-visual-viewport.ts +63 -63
  120. package/src/hooks/viewport/types.ts +16 -16
  121. package/src/hooks/viewport/viewport-metrics.ts +16 -10
  122. package/src/icons/icons.tsx +440 -328
  123. package/src/index.ts +91 -91
  124. package/src/lib/anchored-placement.ts +70 -65
  125. package/src/lib/class-names.ts +14 -13
  126. package/src/lib/clipboard.ts +8 -7
  127. package/src/lib/date.ts +61 -60
  128. package/src/lib/floating-layers.ts +39 -24
  129. package/src/lib/haptics.ts +10 -10
  130. package/src/lib/language.ts +9 -9
  131. package/src/lib/range-value.ts +27 -21
  132. package/src/lib/screen-edges.ts +33 -30
  133. package/src/lib/shapes.ts +38 -34
  134. package/src/machines/popover.machine.ts +51 -0
  135. package/src/motion/transitions.ts +46 -43
  136. package/src/styles/code-block.css +69 -43
  137. package/src/styles/motion-controls.css +393 -191
  138. package/src/tokens.ts +1 -1
  139. package/dist/types/src/components/popover/popover.d.ts +0 -21
  140. package/src/components/popover/popover.tsx +0 -322
@@ -1,198 +1,211 @@
1
- import { Sheet } from "../sheet/sheet"
2
- import { AnimatePresence, motion, useReducedMotion } from "motion/react"
3
- import { Button } from "../button/button"
4
- import { cn } from "../../lib/class-names"
5
- import { contentCrossfade, spring, zoomReveal } from "../../motion/transitions"
6
- import { createContext, useContext, useId, type FormEvent, type ReactNode } from "react"
1
+ import { Sheet } from "../sheet/sheet";
2
+ import { AnimatePresence, motion, useReducedMotion } from "motion/react";
3
+ import { Button } from "../button/button";
4
+ import { cn } from "../../lib/class-names";
5
+ import { contentCrossfade, spring } from "../../motion/transitions";
6
+ import {
7
+ createContext,
8
+ useContext,
9
+ useId,
10
+ type FormEvent,
11
+ type ReactNode,
12
+ } from "react";
7
13
 
8
- const CloseContext = createContext<() => void>(() => {})
9
- export type DialogPresentation = "drawer" | "center" | "inline"
10
- export type DialogTone = "default" | "destructive"
11
- export type DialogSize = "sm" | "md" | "lg"
14
+ const CloseContext = createContext<() => void>(() => {});
15
+ export type DialogPresentation = "drawer" | "center" | "inline";
16
+ export type DialogTone = "default" | "destructive";
17
+ export type DialogSize = "sm" | "md" | "lg";
12
18
 
13
19
  const titleText: Record<DialogSize, string> = {
14
- sm: "text-subheadline",
15
- md: "text-title3",
16
- lg: "text-title2",
17
- }
20
+ sm: "text-subheadline",
21
+ md: "text-title3",
22
+ lg: "text-title2",
23
+ };
18
24
  const descriptionText: Record<DialogSize, string> = {
19
- sm: "text-caption",
20
- md: "text-footnote",
21
- lg: "text-subheadline",
22
- }
25
+ sm: "text-caption",
26
+ md: "text-footnote",
27
+ lg: "text-subheadline",
28
+ };
23
29
  const bodySpacing: Record<DialogSize, string> = {
24
- sm: "gap-3 p-4",
25
- md: "gap-4 p-5",
26
- lg: "gap-5 p-6",
27
- }
30
+ sm: "gap-3 p-4",
31
+ md: "gap-4 p-5",
32
+ lg: "gap-5 p-6",
33
+ };
28
34
  const footerSpacing: Record<DialogSize, string> = {
29
- sm: "pt-2",
30
- md: "pt-3",
31
- lg: "pt-4",
32
- }
35
+ sm: "pt-2",
36
+ md: "pt-3",
37
+ lg: "pt-4",
38
+ };
33
39
 
34
40
  export type DialogProps = {
35
- open: boolean
36
- onOpenChange: (open: boolean) => void
37
- title: ReactNode
38
- description?: ReactNode
39
- children?: ReactNode
40
- footer?: ReactNode
41
- /** `drawer` (responsive sheet), `center` (floating panel), or `inline`. @default "drawer" */
42
- presentation?: DialogPresentation
43
- /** Title, description, body and footer density. @default "md" */
44
- size?: DialogSize
45
- className?: string
46
- onSubmit?: (event: FormEvent<HTMLFormElement>) => void
47
- }
41
+ open: boolean;
42
+ onOpenChange: (open: boolean) => void;
43
+ title: ReactNode;
44
+ description?: ReactNode;
45
+ children?: ReactNode;
46
+ footer?: ReactNode;
47
+ /** `drawer` (responsive sheet), `center` (floating panel), or `inline`. @default "drawer" */
48
+ presentation?: DialogPresentation;
49
+ /** Title, description, body and footer density. @default "md" */
50
+ size?: DialogSize;
51
+ className?: string;
52
+ onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
53
+ };
48
54
  type ActionsProps = {
49
- submitLabel: ReactNode
50
- cancelLabel: ReactNode
51
- pending?: boolean
52
- disabled?: boolean
53
- tone?: DialogTone
54
- onConfirm?: () => void
55
- }
55
+ submitLabel: ReactNode;
56
+ cancelLabel: ReactNode;
57
+ pending?: boolean;
58
+ disabled?: boolean;
59
+ tone?: DialogTone;
60
+ onConfirm?: () => void;
61
+ };
56
62
 
57
63
  export function Dialog({
58
- open,
59
- onOpenChange,
60
- title,
61
- description,
62
- children,
63
- footer,
64
- presentation = "drawer",
65
- size = "md",
66
- className,
67
- onSubmit,
64
+ open,
65
+ onOpenChange,
66
+ title,
67
+ description,
68
+ children,
69
+ footer,
70
+ presentation = "drawer",
71
+ size = "md",
72
+ className,
73
+ onSubmit,
68
74
  }: DialogProps) {
69
- const titleId = useId()
70
- const reducedMotion = useReducedMotion()
71
- const close = () => onOpenChange(false)
72
- const content = (
73
- <>
74
- {presentation !== "inline" && (
75
- <h2 id={titleId} className={cn(titleText[size], "font-semibold")}>
76
- {title}
77
- </h2>
78
- )}
79
- {description && (
80
- <div className={cn(descriptionText[size], "text-label-secondary")}>
81
- {description}
82
- </div>
83
- )}
84
- {children && <div className="flex flex-col gap-4">{children}</div>}
85
- {footer && (
86
- <div className={cn("flex flex-wrap justify-end gap-2", footerSpacing[size])}>
87
- {footer}
88
- </div>
89
- )}
90
- </>
91
- )
92
- const body = (
93
- <CloseContext value={close}>
94
- {onSubmit ? (
95
- <form
96
- onSubmit={onSubmit}
97
- className={cn(
98
- "flex min-h-0 flex-col overflow-y-auto",
99
- bodySpacing[size],
100
- className
101
- )}
102
- >
103
- {content}
104
- </form>
105
- ) : (
106
- <div
107
- className={cn(
108
- "flex min-h-0 flex-col overflow-y-auto",
109
- bodySpacing[size],
110
- className
111
- )}
112
- >
113
- {content}
114
- </div>
115
- )}
116
- </CloseContext>
117
- )
118
- if (presentation === "inline")
119
- return (
120
- <AnimatePresence initial={false}>
121
- {open && (
122
- <motion.div
123
- key={titleId}
124
- initial={{
125
- height: reducedMotion ? "auto" : 0,
126
- opacity: 0,
127
- scale: reducedMotion ? 1 : 0.97,
128
- }}
129
- animate={{
130
- height: "auto",
131
- opacity: 1,
132
- scale: 1,
133
- }}
134
- exit={{
135
- height: reducedMotion ? "auto" : 0,
136
- opacity: 0,
137
- scale: reducedMotion ? 1 : 0.98,
138
- }}
139
- transition={reducedMotion ? { duration: 0 } : spring.bouncy}
140
- className="overflow-hidden"
141
- style={{ transformOrigin: "top center" }}
142
- >
143
- <motion.div
144
- initial={reducedMotion ? false : contentCrossfade.initial}
145
- animate={reducedMotion ? undefined : contentCrossfade.animate}
146
- transition={
147
- reducedMotion ? { duration: 0 } : contentCrossfade.transition
148
- }
149
- >
150
- {body}
151
- </motion.div>
152
- </motion.div>
153
- )}
154
- </AnimatePresence>
155
- )
156
- return (
157
- <Sheet
158
- open={open}
159
- onClose={close}
160
- label=""
161
- labelledBy={titleId}
162
- placement={presentation === "center" ? "center" : "adaptive"}
163
- >
164
- {body}
165
- </Sheet>
166
- )
75
+ const titleId = useId();
76
+ const reducedMotion = useReducedMotion();
77
+ const close = () => onOpenChange(false);
78
+ const content = (
79
+ <>
80
+ {presentation !== "inline" && (
81
+ <h2 id={titleId} className={cn(titleText[size], "font-semibold")}>
82
+ {title}
83
+ </h2>
84
+ )}
85
+ {description && (
86
+ <div className={cn(descriptionText[size], "text-label-secondary")}>
87
+ {description}
88
+ </div>
89
+ )}
90
+ {children && <div className="flex flex-col gap-4">{children}</div>}
91
+ {footer && (
92
+ <div
93
+ className={cn(
94
+ "flex flex-wrap justify-end gap-2",
95
+ footerSpacing[size],
96
+ )}
97
+ >
98
+ {footer}
99
+ </div>
100
+ )}
101
+ </>
102
+ );
103
+ const body = (
104
+ <CloseContext value={close}>
105
+ {onSubmit ? (
106
+ <form
107
+ onSubmit={onSubmit}
108
+ className={cn(
109
+ "flex min-h-0 flex-col overflow-y-auto",
110
+ bodySpacing[size],
111
+ className,
112
+ )}
113
+ >
114
+ {content}
115
+ </form>
116
+ ) : (
117
+ <div
118
+ className={cn(
119
+ "flex min-h-0 flex-col overflow-y-auto",
120
+ bodySpacing[size],
121
+ className,
122
+ )}
123
+ >
124
+ {content}
125
+ </div>
126
+ )}
127
+ </CloseContext>
128
+ );
129
+ if (presentation === "inline")
130
+ return (
131
+ <AnimatePresence initial={false}>
132
+ {open && (
133
+ <motion.div
134
+ key={titleId}
135
+ initial={{
136
+ height: reducedMotion ? "auto" : 0,
137
+ opacity: 0,
138
+ scale: reducedMotion ? 1 : 0.97,
139
+ }}
140
+ animate={{
141
+ height: "auto",
142
+ opacity: 1,
143
+ scale: 1,
144
+ }}
145
+ exit={{
146
+ height: reducedMotion ? "auto" : 0,
147
+ opacity: 0,
148
+ scale: reducedMotion ? 1 : 0.98,
149
+ }}
150
+ transition={reducedMotion ? { duration: 0 } : spring.bouncy}
151
+ className="overflow-hidden"
152
+ style={{ transformOrigin: "top center" }}
153
+ >
154
+ <motion.div
155
+ initial={reducedMotion ? false : contentCrossfade.initial}
156
+ animate={reducedMotion ? undefined : contentCrossfade.animate}
157
+ transition={
158
+ reducedMotion ? { duration: 0 } : contentCrossfade.transition
159
+ }
160
+ >
161
+ {body}
162
+ </motion.div>
163
+ </motion.div>
164
+ )}
165
+ </AnimatePresence>
166
+ );
167
+ return (
168
+ <Sheet
169
+ open={open}
170
+ onClose={close}
171
+ label=""
172
+ labelledBy={titleId}
173
+ placement={presentation === "center" ? "center" : "adaptive"}
174
+ >
175
+ {body}
176
+ </Sheet>
177
+ );
167
178
  }
168
179
 
169
180
  /** The standard footer: a primary action and a cancel that closes the dialog. */
170
181
  function Actions({
171
- submitLabel,
172
- cancelLabel,
173
- pending = false,
174
- disabled = false,
175
- tone = "default",
176
- onConfirm,
182
+ submitLabel,
183
+ cancelLabel,
184
+ pending = false,
185
+ disabled = false,
186
+ tone = "default",
187
+ onConfirm,
177
188
  }: ActionsProps) {
178
- const close = useContext(CloseContext)
179
- return (
180
- <>
181
- <Button
182
- type={onConfirm ? "button" : "submit"}
183
- variant={tone === "destructive" ? "ghost" : "default"}
184
- className={tone === "destructive" ? "bg-danger/10 text-danger" : undefined}
185
- isPending={pending}
186
- disabled={disabled}
187
- onClick={onConfirm}
188
- >
189
- {submitLabel}
190
- </Button>
191
- <Button type="button" variant="secondary" onClick={close}>
192
- {cancelLabel}
193
- </Button>
194
- </>
195
- )
189
+ const close = useContext(CloseContext);
190
+ return (
191
+ <>
192
+ <Button
193
+ type={onConfirm ? "button" : "submit"}
194
+ variant={tone === "destructive" ? "ghost" : "default"}
195
+ className={
196
+ tone === "destructive" ? "bg-danger/10 text-danger" : undefined
197
+ }
198
+ isPending={pending}
199
+ disabled={disabled}
200
+ onClick={onConfirm}
201
+ >
202
+ {submitLabel}
203
+ </Button>
204
+ <Button type="button" variant="secondary" onClick={close}>
205
+ {cancelLabel}
206
+ </Button>
207
+ </>
208
+ );
196
209
  }
197
210
 
198
- Dialog.Actions = Actions
211
+ Dialog.Actions = Actions;
@@ -1 +1 @@
1
- export * from "./dialog"
1
+ export * from "./dialog";
@@ -1,101 +1,108 @@
1
- import { Button } from "../button/button"
2
- import { type ReactNode, useId } from "react"
3
- import { ChevronDownIcon } from "../../icons/icons"
4
- import { cn } from "../../lib/class-names"
5
- import { InlineDisclosure } from "../inline-disclosure/inline-disclosure"
1
+ import { Button } from "../button/button";
2
+ import { type ReactNode, useId } from "react";
3
+ import { ChevronDownIcon } from "../../icons/icons";
4
+ import { cn } from "../../lib/class-names";
5
+ import { InlineDisclosure } from "../inline-disclosure/inline-disclosure";
6
6
 
7
- export type DisclosureGroupSize = "sm" | "md" | "lg"
7
+ export type DisclosureGroupSize = "sm" | "md" | "lg";
8
8
 
9
9
  const triggerSizes: Record<DisclosureGroupSize, string> = {
10
- sm: "h-auto min-h-9 w-full rounded-lg px-3 py-2 text-start text-footnote active:scale-100",
11
- md: "h-auto min-h-11 w-full rounded-xl px-4 py-3 text-start text-subheadline active:scale-100",
12
- lg: "h-auto min-h-13 w-full rounded-2xl px-5 py-4 text-start text-body active:scale-100",
13
- }
10
+ sm: "h-auto min-h-9 w-full rounded-lg px-3 py-2 text-start text-footnote active:scale-100",
11
+ md: "h-auto min-h-11 w-full rounded-xl px-4 py-3 text-start text-subheadline active:scale-100",
12
+ lg: "h-auto min-h-13 w-full rounded-2xl px-5 py-4 text-start text-body active:scale-100",
13
+ };
14
14
  const descriptionSizes: Record<DisclosureGroupSize, string> = {
15
- sm: "text-caption2 leading-caption2 font-normal break-words whitespace-normal text-label-secondary",
16
- md: "text-footnote leading-footnote font-normal break-words whitespace-normal text-label-secondary",
17
- lg: "text-subheadline leading-subheadline font-normal break-words whitespace-normal text-label-secondary",
18
- }
15
+ sm: "text-caption2 leading-caption2 font-normal break-words whitespace-normal text-label-secondary",
16
+ md: "text-footnote leading-footnote font-normal break-words whitespace-normal text-label-secondary",
17
+ lg: "text-subheadline leading-subheadline font-normal break-words whitespace-normal text-label-secondary",
18
+ };
19
19
  const contentSizes: Record<DisclosureGroupSize, string> = {
20
- sm: "min-w-0 px-3 pb-3 text-footnote leading-footnote text-label-secondary [overflow-wrap:anywhere]",
21
- md: "min-w-0 px-4 pb-4 text-subheadline leading-subheadline text-label-secondary [overflow-wrap:anywhere]",
22
- lg: "min-w-0 px-5 pb-5 text-body leading-body text-label-secondary [overflow-wrap:anywhere]",
23
- }
20
+ sm: "min-w-0 px-3 pb-3 text-footnote leading-footnote text-label-secondary [overflow-wrap:anywhere]",
21
+ md: "min-w-0 px-4 pb-4 text-subheadline leading-subheadline text-label-secondary [overflow-wrap:anywhere]",
22
+ lg: "min-w-0 px-5 pb-5 text-body leading-body text-label-secondary [overflow-wrap:anywhere]",
23
+ };
24
24
  const chevronSizes: Record<DisclosureGroupSize, number> = {
25
- sm: 15,
26
- md: 17,
27
- lg: 19,
28
- }
25
+ sm: 15,
26
+ md: 17,
27
+ lg: 19,
28
+ };
29
29
 
30
30
  export interface DisclosureGroupProps {
31
- label: string
32
- open: boolean
33
- onOpenChange: (open: boolean) => void
34
- children: ReactNode
35
- disabled?: boolean
36
- className?: string
37
- /** Trigger layout when composed inside a shared surface such as Accordion. */
38
- triggerClassName?: string
39
- /** Supporting text beneath the title. */
40
- description?: string
41
- /** Trigger, description and content density. @default "md" */
42
- size?: DisclosureGroupSize
31
+ label: string;
32
+ open: boolean;
33
+ onOpenChange: (open: boolean) => void;
34
+ children: ReactNode;
35
+ disabled?: boolean;
36
+ className?: string;
37
+ /** Trigger layout when composed inside a shared surface such as Accordion. */
38
+ triggerClassName?: string;
39
+ /** Supporting text beneath the title. */
40
+ description?: string;
41
+ /** Trigger, description and content density. @default "md" */
42
+ size?: DisclosureGroupSize;
43
43
  }
44
44
 
45
45
  /** A controlled, accessible disclosure row with the shared inline reveal. */
46
46
  export function DisclosureGroup({
47
- label,
48
- open,
49
- onOpenChange,
50
- children,
51
- disabled = false,
52
- className,
53
- triggerClassName,
54
- description,
55
- size = "md",
47
+ label,
48
+ open,
49
+ onOpenChange,
50
+ children,
51
+ disabled = false,
52
+ className,
53
+ triggerClassName,
54
+ description,
55
+ size = "md",
56
56
  }: DisclosureGroupProps) {
57
- const id = useId()
57
+ const id = useId();
58
58
 
59
- return (
60
- <div className={cn("w-full min-w-0", className)}>
61
- <h3 className="m-0">
62
- <Button
63
- variant="ghost"
64
- contentClassName="w-full min-w-0 justify-between gap-3"
65
- type="button"
66
- id={`${id}-trigger`}
67
- aria-expanded={open}
68
- aria-controls={id}
69
- disabled={disabled}
70
- onClick={() => onOpenChange(!open)}
71
- className={cn(
72
- triggerSizes[size],
73
- "font-normal text-label hover:bg-fill/60 focus-visible:ring-inset focus-visible:ring-offset-0",
74
- "focus-visible:outline-accent-text disabled:cursor-not-allowed disabled:opacity-40",
75
- triggerClassName
76
- )}
77
- >
78
- <span className="flex min-w-0 flex-col gap-0.5">
79
- <span className="font-medium break-words whitespace-normal">{label}</span>
80
- {description && (
81
- <span className={descriptionSizes[size]}>{description}</span>
82
- )}
83
- </span>
84
- <ChevronDownIcon
85
- size={chevronSizes[size]}
86
- aria-hidden="true"
87
- className={cn(
88
- "shrink-0 text-label-tertiary transition-transform duration-normal motion-reduce:transition-none",
89
- open && "rotate-180"
90
- )}
91
- />
92
- </Button>
93
- </h3>
94
- <section id={id} aria-labelledby={`${id}-trigger`} aria-hidden={!open} inert={!open}>
95
- <InlineDisclosure open={open}>
96
- <div className={contentSizes[size]}>{children}</div>
97
- </InlineDisclosure>
98
- </section>
99
- </div>
100
- )
59
+ return (
60
+ <div className={cn("w-full min-w-0", className)}>
61
+ <h3 className="m-0">
62
+ <Button
63
+ variant="ghost"
64
+ contentClassName="w-full min-w-0 justify-between gap-3"
65
+ type="button"
66
+ id={`${id}-trigger`}
67
+ aria-expanded={open}
68
+ aria-controls={id}
69
+ disabled={disabled}
70
+ onClick={() => onOpenChange(!open)}
71
+ className={cn(
72
+ triggerSizes[size],
73
+ "text-label hover:bg-fill/60 font-normal focus-visible:ring-offset-0 focus-visible:ring-inset",
74
+ "focus-visible:outline-accent-text disabled:cursor-not-allowed disabled:opacity-40",
75
+ triggerClassName,
76
+ )}
77
+ >
78
+ <span className="flex min-w-0 flex-col gap-0.5">
79
+ <span className="font-medium break-words whitespace-normal">
80
+ {label}
81
+ </span>
82
+ {description && (
83
+ <span className={descriptionSizes[size]}>{description}</span>
84
+ )}
85
+ </span>
86
+ <ChevronDownIcon
87
+ size={chevronSizes[size]}
88
+ aria-hidden="true"
89
+ className={cn(
90
+ "text-label-tertiary duration-normal shrink-0 transition-transform motion-reduce:transition-none",
91
+ open && "rotate-180",
92
+ )}
93
+ />
94
+ </Button>
95
+ </h3>
96
+ <section
97
+ id={id}
98
+ aria-labelledby={`${id}-trigger`}
99
+ aria-hidden={!open}
100
+ inert={!open}
101
+ >
102
+ <InlineDisclosure open={open}>
103
+ <div className={contentSizes[size]}>{children}</div>
104
+ </InlineDisclosure>
105
+ </section>
106
+ </div>
107
+ );
101
108
  }
@@ -1,31 +1,33 @@
1
- import type { HTMLAttributes } from "react"
2
- import { cn } from "../../lib/class-names"
1
+ import type { HTMLAttributes } from "react";
2
+ import { cn } from "../../lib/class-names";
3
3
 
4
- export type DividerOrientation = "horizontal" | "vertical"
4
+ export type DividerOrientation = "horizontal" | "vertical";
5
5
 
6
6
  export interface DividerProps extends HTMLAttributes<HTMLHRElement> {
7
- orientation?: DividerOrientation
8
- /** Decorative separators are omitted from the accessibility tree. @default true */
9
- decorative?: boolean
7
+ orientation?: DividerOrientation;
8
+ /** Decorative separators are omitted from the accessibility tree. @default true */
9
+ decorative?: boolean;
10
10
  }
11
11
 
12
12
  /** A semantic separator using the shared surface color. */
13
13
  export function Divider({
14
- orientation = "horizontal",
15
- decorative = true,
16
- className,
17
- ...props
14
+ orientation = "horizontal",
15
+ decorative = true,
16
+ className,
17
+ ...props
18
18
  }: DividerProps) {
19
- return (
20
- <hr
21
- {...props}
22
- role={decorative ? "none" : "separator"}
23
- aria-orientation={decorative ? undefined : orientation}
24
- className={cn(
25
- "shrink-0 border-0 bg-separator",
26
- orientation === "horizontal" ? "h-px w-full" : "h-full w-px self-stretch",
27
- className
28
- )}
29
- />
30
- )
19
+ return (
20
+ <hr
21
+ {...props}
22
+ role={decorative ? "none" : "separator"}
23
+ aria-orientation={decorative ? undefined : orientation}
24
+ className={cn(
25
+ "bg-separator shrink-0 border-0",
26
+ orientation === "horizontal"
27
+ ? "h-px w-full"
28
+ : "h-full w-px self-stretch",
29
+ className,
30
+ )}
31
+ />
32
+ );
31
33
  }