@glyphui/ui 0.2.0 → 0.4.0

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 (116) hide show
  1. package/README.md +65 -12
  2. package/dist/chart.d.ts +202 -0
  3. package/dist/chart.js +466 -0
  4. package/dist/color-mode-script-Bf7LYkOj.js +13 -0
  5. package/dist/color-mode-script-KdwItKN2.d.ts +16 -0
  6. package/dist/data-table.js +3 -2
  7. package/dist/{field-CCecIzdq.js → field-CVbywksE.js} +21 -5
  8. package/dist/{field-context-B6WOcK5m.js → field-context-7I-cWvvS.js} +3 -57
  9. package/dist/form.d.ts +11 -4
  10. package/dist/form.js +34 -8
  11. package/dist/glyph-context-DxGJrdvr.d.ts +50 -0
  12. package/dist/{index-BWK4czIG.d.ts → index-Bi7rZ6ba.d.ts} +11 -0
  13. package/dist/index.d.ts +2334 -283
  14. package/dist/index.js +2952 -326
  15. package/dist/react-router.d.ts +18 -0
  16. package/dist/react-router.js +44 -0
  17. package/dist/{states-Rp8wZ_jH.js → states-IvhjBgna.js} +2 -1
  18. package/dist/tv-DLbT66dC.js +70 -0
  19. package/dist/vite.d.ts +27 -0
  20. package/dist/vite.js +29 -0
  21. package/fonts.css +10 -0
  22. package/package.json +47 -5
  23. package/src/components/accordion/accordion.styles.ts +4 -4
  24. package/src/components/badge/badge.styles.ts +11 -16
  25. package/src/components/banner/banner.styles.ts +4 -4
  26. package/src/components/button/button.styles.ts +3 -1
  27. package/src/components/calendar/calendar.styles.ts +51 -0
  28. package/src/components/calendar/calendar.tsx +84 -0
  29. package/src/components/calendar/index.ts +3 -0
  30. package/src/components/carousel/carousel.styles.ts +43 -0
  31. package/src/components/carousel/carousel.tsx +278 -0
  32. package/src/components/carousel/index.ts +13 -0
  33. package/src/components/collapsible/collapsible.tsx +66 -0
  34. package/src/components/collapsible/index.ts +6 -0
  35. package/src/components/context-menu/context-menu.styles.ts +19 -0
  36. package/src/components/context-menu/context-menu.tsx +226 -0
  37. package/src/components/context-menu/index.ts +19 -0
  38. package/src/components/copy-button/copy-button.tsx +117 -0
  39. package/src/components/copy-button/index.ts +1 -0
  40. package/src/components/date-picker/date-picker.styles.ts +42 -0
  41. package/src/components/date-picker/date-picker.tsx +322 -0
  42. package/src/components/date-picker/index.ts +8 -0
  43. package/src/components/dropdown-menu/dropdown-menu.styles.ts +2 -2
  44. package/src/components/eyebrow/eyebrow.styles.ts +1 -1
  45. package/src/components/field/field-context.ts +2 -0
  46. package/src/components/field/field.styles.ts +4 -2
  47. package/src/components/field/field.tsx +25 -4
  48. package/src/components/file-upload/file-upload.styles.ts +43 -0
  49. package/src/components/file-upload/file-upload.tsx +343 -0
  50. package/src/components/file-upload/index.ts +10 -0
  51. package/src/components/hover-card/hover-card.tsx +41 -0
  52. package/src/components/hover-card/index.ts +1 -0
  53. package/src/components/input-otp/index.ts +10 -0
  54. package/src/components/input-otp/input-otp.styles.ts +38 -0
  55. package/src/components/input-otp/input-otp.tsx +116 -0
  56. package/src/components/link/link.styles.ts +1 -1
  57. package/src/components/modal/index.ts +2 -0
  58. package/src/components/modal/modal.styles.ts +20 -0
  59. package/src/components/modal/modal.tsx +111 -0
  60. package/src/components/navigation-menu/index.ts +14 -0
  61. package/src/components/navigation-menu/navigation-menu.styles.ts +48 -0
  62. package/src/components/navigation-menu/navigation-menu.tsx +208 -0
  63. package/src/components/number-input/index.ts +2 -0
  64. package/src/components/number-input/number-input.styles.ts +41 -0
  65. package/src/components/number-input/number-input.tsx +211 -0
  66. package/src/components/password-input/index.ts +7 -0
  67. package/src/components/password-input/password-input.styles.ts +30 -0
  68. package/src/components/password-input/password-input.tsx +127 -0
  69. package/src/components/prose/prose.tsx +1 -1
  70. package/src/components/resizable/index.ts +9 -0
  71. package/src/components/resizable/resizable.styles.ts +28 -0
  72. package/src/components/resizable/resizable.tsx +69 -0
  73. package/src/components/scroll-area/scroll-area.tsx +23 -1
  74. package/src/components/segmented-control/segmented-control.tsx +17 -2
  75. package/src/components/sheet/sheet.styles.ts +7 -7
  76. package/src/components/slider/slider.tsx +9 -2
  77. package/src/components/stepper/index.ts +2 -0
  78. package/src/components/stepper/stepper.styles.ts +74 -0
  79. package/src/components/stepper/stepper.tsx +138 -0
  80. package/src/components/tag-input/index.ts +2 -0
  81. package/src/components/tag-input/tag-input.styles.ts +39 -0
  82. package/src/components/tag-input/tag-input.tsx +198 -0
  83. package/src/components/text/text.styles.ts +4 -4
  84. package/src/components/timeline/index.ts +8 -0
  85. package/src/components/timeline/timeline.styles.ts +56 -0
  86. package/src/components/timeline/timeline.tsx +91 -0
  87. package/src/components/toggle/index.ts +9 -0
  88. package/src/components/toggle/toggle.styles.ts +39 -0
  89. package/src/components/toggle/toggle.tsx +61 -0
  90. package/src/components/tree-view/index.ts +2 -0
  91. package/src/components/tree-view/tree-view.styles.ts +42 -0
  92. package/src/components/tree-view/tree-view.tsx +274 -0
  93. package/src/components/visually-hidden/index.ts +1 -0
  94. package/src/components/visually-hidden/visually-hidden.tsx +10 -0
  95. package/src/index.ts +20 -0
  96. package/src/integrations/react-router.tsx +39 -0
  97. package/src/integrations/vite.test-d.ts +6 -0
  98. package/src/integrations/vite.test.ts +28 -0
  99. package/src/integrations/vite.ts +33 -0
  100. package/src/internal/dev.ts +12 -0
  101. package/src/patterns/app-shell/app-shell.styles.ts +1 -1
  102. package/src/patterns/app-shell/navbar.tsx +34 -16
  103. package/src/patterns/app-shell/sidebar.tsx +7 -2
  104. package/src/patterns/chart/chart-parts.tsx +179 -0
  105. package/src/patterns/chart/chart.styles.ts +35 -0
  106. package/src/patterns/chart/chart.tsx +386 -0
  107. package/src/patterns/chart/index.ts +13 -0
  108. package/src/patterns/form/form.tsx +48 -6
  109. package/src/patterns/form/index.ts +1 -0
  110. package/src/provider/color-mode-script.ts +28 -0
  111. package/src/provider/color-mode.tsx +14 -20
  112. package/src/provider/glyph-context.ts +38 -0
  113. package/src/provider/glyph-provider.tsx +16 -4
  114. package/src/provider/index.ts +4 -0
  115. package/src/provider/theme-scope.tsx +7 -3
  116. package/styles.css +88 -0
@@ -1,6 +1,6 @@
1
1
  import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
2
2
  import type { StandardSchemaV1 } from '@standard-schema/spec'
3
- import type { ComponentProps, ReactNode } from 'react'
3
+ import { type ComponentProps, type MouseEvent, type ReactNode, useCallback } from 'react'
4
4
  import {
5
5
  type Control,
6
6
  Controller,
@@ -11,6 +11,7 @@ import {
11
11
  type Resolver,
12
12
  type UseFormProps,
13
13
  type UseFormReturn,
14
+ useFormContext,
14
15
  useFormState,
15
16
  useForm as useHookForm,
16
17
  } from 'react-hook-form'
@@ -62,12 +63,29 @@ export interface FormProps<TInput extends FieldValues, TOutput>
62
63
  onSubmit: (values: TOutput) => SubmitResult<TInput> | Promise<SubmitResult<TInput>>
63
64
  }
64
65
 
66
+ // biome-ignore lint/suspicious/noExplicitAny: keyed by any form's control object
67
+ type AnyControl = Control<any, any, any>
68
+
69
+ /** The rendered `<form>` of each form, so a FormSubmit outside it can submit it. */
70
+ const formElements = new WeakMap<AnyControl, HTMLFormElement>()
71
+
65
72
  export function Form<TInput extends FieldValues, TOutput>({
66
73
  form,
67
74
  onSubmit,
68
75
  children,
76
+ ref,
69
77
  ...props
70
78
  }: FormProps<TInput, TOutput>) {
79
+ const control = form.control as AnyControl
80
+ const registerElement = useCallback(
81
+ (element: HTMLFormElement | null) => {
82
+ if (element) formElements.set(control, element)
83
+ else formElements.delete(control)
84
+ if (typeof ref === 'function') ref(element)
85
+ else if (ref) ref.current = element
86
+ },
87
+ [control, ref],
88
+ )
71
89
  const submit = form.handleSubmit(async (values) => {
72
90
  try {
73
91
  const result = await onSubmit(values)
@@ -85,7 +103,7 @@ export function Form<TInput extends FieldValues, TOutput>({
85
103
 
86
104
  return (
87
105
  <FormProvider {...form}>
88
- <form noValidate onSubmit={submit} {...props}>
106
+ <form noValidate onSubmit={submit} ref={registerElement} {...props}>
89
107
  {children}
90
108
  </form>
91
109
  </FormProvider>
@@ -122,15 +140,39 @@ export function FormField<TInput extends FieldValues, TName extends FieldPath<TI
122
140
  )
123
141
  }
124
142
 
143
+ export interface FormSubmitProps extends Omit<ButtonProps, 'type' | 'form'> {
144
+ /**
145
+ * The form to submit, for a button outside `<Form>` such as a Modal footer:
146
+ * `<FormSubmit form={form}>`. Not needed inside `<Form>`.
147
+ */
148
+ // biome-ignore lint/suspicious/noExplicitAny: accepts any form regardless of its value types
149
+ form?: UseFormReturn<any, any, any>
150
+ }
151
+
125
152
  /** Submit button that shows progress while the form submits. */
126
- export function FormSubmit(props: Omit<ButtonProps, 'type'>) {
127
- const { isSubmitting } = useFormState()
128
- return <Button type="submit" loading={isSubmitting} {...props} />
153
+ export function FormSubmit({ form, onClick, ...props }: FormSubmitProps) {
154
+ const context = useFormContext()
155
+ const control = (form ?? context)?.control
156
+ if (!control) {
157
+ throw new Error(
158
+ 'FormSubmit must be inside <Form> or receive form={form}, e.g. <FormSubmit form={form}> in a Modal footer.',
159
+ )
160
+ }
161
+ const { isSubmitting } = useFormState({ control })
162
+
163
+ if (!form) return <Button type="submit" loading={isSubmitting} onClick={onClick} {...props} />
164
+
165
+ // Outside <Form>, submit its element explicitly so validation and onSubmit run as usual.
166
+ const submitOutside = (event: MouseEvent<HTMLButtonElement>) => {
167
+ onClick?.(event)
168
+ if (!event.defaultPrevented) formElements.get(control)?.requestSubmit()
169
+ }
170
+ return <Button type="button" loading={isSubmitting} onClick={submitOutside} {...props} />
129
171
  }
130
172
 
131
173
  export const formErrorStyles = tv({
132
174
  slots: {
133
- base: 'flex items-start gap-2 rounded-md border border-danger/30 bg-danger/8 px-3 py-2.5 text-small text-danger',
175
+ base: 'flex items-start gap-2 rounded-md border border-danger/30 bg-danger/8 px-3 py-2.5 text-small text-danger-text',
134
176
  icon: 'mt-0.5 size-4 shrink-0',
135
177
  },
136
178
  })
@@ -6,6 +6,7 @@ export {
6
6
  type FormFieldProps,
7
7
  type FormProps,
8
8
  FormSubmit,
9
+ type FormSubmitProps,
9
10
  formErrorStyles,
10
11
  type SubmitResult,
11
12
  type UseFormOptions,
@@ -0,0 +1,28 @@
1
+ import type { ColorMode } from '@glyphui/tokens'
2
+
3
+ // React-free on purpose: the Vite plugin imports this module in Node.
4
+
5
+ export type ColorModePreference = ColorMode | 'system'
6
+
7
+ export interface ColorModeOptions {
8
+ /** Used when nothing is stored yet. */
9
+ defaultMode?: ColorModePreference
10
+ /** localStorage key. Set to `null` to disable persistence. */
11
+ storageKey?: string | null
12
+ }
13
+
14
+ export const DARK_QUERY = '(prefers-color-scheme: dark)'
15
+ export const DEFAULT_STORAGE_KEY = 'glyph-mode'
16
+
17
+ /**
18
+ * A tiny inline script that sets `data-mode` on `<html>` before first paint, so dark-mode
19
+ * visitors never see a light flash. Use the same options as `GlyphProvider`.
20
+ */
21
+ export function getColorModeScript({
22
+ defaultMode = 'system',
23
+ storageKey = DEFAULT_STORAGE_KEY,
24
+ }: ColorModeOptions = {}): string {
25
+ return `(function(){try{var d=${JSON.stringify(defaultMode)},m=null;${
26
+ storageKey ? `m=localStorage.getItem(${JSON.stringify(storageKey)});` : ''
27
+ }if(m!=='light'&&m!=='dark'&&m!=='system')m=d;if(m==='system')m=matchMedia('${DARK_QUERY}').matches?'dark':'light';var r=document.documentElement;r.dataset.mode=m;r.style.colorScheme=m}catch(e){}})()`
28
+ }
@@ -8,8 +8,19 @@ import {
8
8
  useMemo,
9
9
  useState,
10
10
  } from 'react'
11
-
12
- export type ColorModePreference = ColorMode | 'system'
11
+ import {
12
+ type ColorModeOptions,
13
+ type ColorModePreference,
14
+ DARK_QUERY,
15
+ DEFAULT_STORAGE_KEY,
16
+ getColorModeScript,
17
+ } from './color-mode-script'
18
+
19
+ export {
20
+ type ColorModeOptions,
21
+ type ColorModePreference,
22
+ getColorModeScript,
23
+ } from './color-mode-script'
13
24
 
14
25
  export interface ColorModeContextValue {
15
26
  /** What the user chose. */
@@ -21,16 +32,8 @@ export interface ColorModeContextValue {
21
32
 
22
33
  const ColorModeContext = createContext<ColorModeContextValue | null>(null)
23
34
 
24
- const DARK_QUERY = '(prefers-color-scheme: dark)'
25
35
  const isBrowser = typeof window !== 'undefined'
26
36
 
27
- export interface ColorModeOptions {
28
- /** Used when nothing is stored yet. */
29
- defaultMode?: ColorModePreference
30
- /** localStorage key. Set to `null` to disable persistence. */
31
- storageKey?: string | null
32
- }
33
-
34
37
  function readStoredMode(storageKey: string | null): ColorModePreference | null {
35
38
  if (!isBrowser || !storageKey) return null
36
39
  try {
@@ -59,7 +62,7 @@ function suppressTransitions(): () => void {
59
62
  export function ColorModeProvider({
60
63
  children,
61
64
  defaultMode = 'system',
62
- storageKey = 'glyph-mode',
65
+ storageKey = DEFAULT_STORAGE_KEY,
63
66
  }: ColorModeOptions & { children: ReactNode }) {
64
67
  const [mode, setModeState] = useState<ColorModePreference>(
65
68
  () => readStoredMode(storageKey) ?? defaultMode,
@@ -112,15 +115,6 @@ export function useColorMode(): ColorModeContextValue {
112
115
  * Inline script that sets `data-mode` on `<html>` before first paint, so a dark-mode
113
116
  * visitor never sees a light flash. Put it in `<head>`.
114
117
  */
115
- export function getColorModeScript({
116
- defaultMode = 'system',
117
- storageKey = 'glyph-mode',
118
- }: ColorModeOptions = {}): string {
119
- return `(function(){try{var d=${JSON.stringify(defaultMode)},m=null;${
120
- storageKey ? `m=localStorage.getItem(${JSON.stringify(storageKey)});` : ''
121
- }if(m!=='light'&&m!=='dark'&&m!=='system')m=d;if(m==='system')m=matchMedia('${DARK_QUERY}').matches?'dark':'light';var r=document.documentElement;r.dataset.mode=m;r.style.colorScheme=m}catch(e){}})()`
122
- }
123
-
124
118
  /** `<script>` element version of `getColorModeScript` for SSR frameworks. */
125
119
  export function ColorModeScript(props: ColorModeOptions) {
126
120
  return (
@@ -22,9 +22,29 @@ export interface LinkComponentProps {
22
22
  */
23
23
  export type LinkComponent = ElementType<LinkComponentProps>
24
24
 
25
+ export interface IsActiveOptions {
26
+ /** Match only this exact path, not its children. Default false. */
27
+ end?: boolean
28
+ }
29
+
30
+ /**
31
+ * A hook that reports whether `href` is the current location. Glyph calls it once per
32
+ * navigation item on every render, so it must follow the rules of hooks.
33
+ */
34
+ export type UseIsActive = (href: string, options?: IsActiveOptions) => boolean
35
+
36
+ /** Connects Glyph's navigation components to your router. */
37
+ export interface GlyphRouter {
38
+ /** Renders links client-side. */
39
+ Link: LinkComponent
40
+ /** Marks Sidebar, Navbar and NavigationMenu items active automatically. */
41
+ useIsActive?: UseIsActive
42
+ }
43
+
25
44
  export interface GlyphContextValue {
26
45
  theme: Theme
27
46
  linkComponent: LinkComponent
47
+ useIsActive: UseIsActive
28
48
  }
29
49
 
30
50
  export const GlyphContext = createContext<GlyphContextValue | null>(null)
@@ -40,3 +60,21 @@ export function useGlyph(): GlyphContextValue {
40
60
  export function useLinkComponent(): LinkComponent {
41
61
  return useContext(GlyphContext)?.linkComponent ?? 'a'
42
62
  }
63
+
64
+ export const neverActive: UseIsActive = () => false
65
+
66
+ /**
67
+ * Whether `href` is the current page, using the router passed to `GlyphProvider`.
68
+ * Returns `explicit` when it is set, so an `active` prop always wins.
69
+ */
70
+ export function useIsActive(
71
+ href: string | undefined,
72
+ options?: IsActiveOptions & { explicit?: boolean | undefined },
73
+ ): boolean {
74
+ const isActive = useContext(GlyphContext)?.useIsActive ?? neverActive
75
+ const { explicit, ...matchOptions } = options ?? {}
76
+ // Always call the router hook so the hook order never changes between renders.
77
+ const matched = isActive(href ?? '', matchOptions)
78
+ if (explicit !== undefined) return explicit
79
+ return href ? matched : false
80
+ }
@@ -5,7 +5,7 @@ import { ConfirmProvider } from '../components/alert-dialog/confirm'
5
5
  import { Toaster, type ToasterProps } from '../components/toast/toast'
6
6
  import { glyph } from '../themes'
7
7
  import { type ColorModePreference, ColorModeProvider } from './color-mode'
8
- import { GlyphContext, type LinkComponent } from './glyph-context'
8
+ import { GlyphContext, type GlyphRouter, type LinkComponent, neverActive } from './glyph-context'
9
9
  import { ThemeStyle } from './theme-style'
10
10
 
11
11
  export interface GlyphProviderProps {
@@ -16,7 +16,13 @@ export interface GlyphProviderProps {
16
16
  defaultMode?: ColorModePreference
17
17
  /** localStorage key for the user's color mode. `null` disables persistence. */
18
18
  storageKey?: string | null
19
- /** Your router's link, used by Navbar, Sidebar and other navigation components. */
19
+ /**
20
+ * Your router: its link component, plus an optional `useIsActive` hook that marks the
21
+ * current page in Sidebar, Navbar and NavigationMenu. React Router:
22
+ * `import { reactRouter } from '@glyphui/ui/react-router'`.
23
+ */
24
+ router?: GlyphRouter
25
+ /** Your router's link only. Prefer `router`, which also handles active items. */
20
26
  linkComponent?: LinkComponent
21
27
  /**
22
28
  * Mounts a themed `<Toaster />` so `toast()` works anywhere. `true` for defaults, or pass
@@ -31,10 +37,16 @@ export function GlyphProvider({
31
37
  theme = glyph,
32
38
  defaultMode,
33
39
  storageKey,
34
- linkComponent = 'a',
40
+ router,
41
+ linkComponent,
35
42
  toaster = false,
36
43
  }: GlyphProviderProps) {
37
- const value = useMemo(() => ({ theme, linkComponent }), [theme, linkComponent])
44
+ const Link = router?.Link ?? linkComponent ?? 'a'
45
+ const useIsActive = router?.useIsActive ?? neverActive
46
+ const value = useMemo(
47
+ () => ({ theme, linkComponent: Link, useIsActive }),
48
+ [theme, Link, useIsActive],
49
+ )
38
50
  return (
39
51
  <ColorModeProvider
40
52
  {...(defaultMode !== undefined && { defaultMode })}
@@ -9,9 +9,13 @@ export {
9
9
  } from './color-mode'
10
10
  export {
11
11
  type GlyphContextValue,
12
+ type GlyphRouter,
13
+ type IsActiveOptions,
12
14
  type LinkComponent,
13
15
  type LinkComponentProps,
16
+ type UseIsActive,
14
17
  useGlyph,
18
+ useIsActive,
15
19
  useLinkComponent,
16
20
  } from './glyph-context'
17
21
  export { GlyphProvider, type GlyphProviderProps } from './glyph-provider'
@@ -2,7 +2,7 @@ import { type ColorMode, scopeSelector, type Theme } from '@glyphui/tokens'
2
2
  import { Slot } from 'radix-ui'
3
3
  import { type ComponentProps, useContext, useMemo } from 'react'
4
4
  import { cn } from '../utils/cn'
5
- import { GlyphContext } from './glyph-context'
5
+ import { GlyphContext, neverActive } from './glyph-context'
6
6
  import { ThemeStyle } from './theme-style'
7
7
 
8
8
  export interface ThemeScopeProps extends ComponentProps<'div'> {
@@ -16,8 +16,12 @@ export interface ThemeScopeProps extends ComponentProps<'div'> {
16
16
  export function ThemeScope({ theme, mode, asChild, children, ...props }: ThemeScopeProps) {
17
17
  const parent = useContext(GlyphContext)
18
18
  const value = useMemo(
19
- () => ({ theme, linkComponent: parent?.linkComponent ?? 'a' }),
20
- [theme, parent?.linkComponent],
19
+ () => ({
20
+ theme,
21
+ linkComponent: parent?.linkComponent ?? 'a',
22
+ useIsActive: parent?.useIsActive ?? neverActive,
23
+ }),
24
+ [theme, parent?.linkComponent, parent?.useIsActive],
21
25
  )
22
26
  const Comp = asChild ? Slot.Root : 'div'
23
27
  return (
package/styles.css CHANGED
@@ -39,7 +39,17 @@
39
39
  --color-danger-foreground: var(--glyph-danger-foreground);
40
40
  --color-info: var(--glyph-info);
41
41
  --color-info-foreground: var(--glyph-info-foreground);
42
+ --color-primary-text: var(--glyph-primary-text);
43
+ --color-success-text: var(--glyph-success-text);
44
+ --color-warning-text: var(--glyph-warning-text);
45
+ --color-danger-text: var(--glyph-danger-text);
46
+ --color-info-text: var(--glyph-info-text);
42
47
  --color-overlay: var(--glyph-overlay);
48
+ --color-chart-1: var(--glyph-chart-1);
49
+ --color-chart-2: var(--glyph-chart-2);
50
+ --color-chart-3: var(--glyph-chart-3);
51
+ --color-chart-4: var(--glyph-chart-4);
52
+ --color-chart-5: var(--glyph-chart-5);
43
53
 
44
54
  --radius-xs: var(--glyph-radius-xs);
45
55
  --radius-sm: var(--glyph-radius-sm);
@@ -102,6 +112,22 @@
102
112
  --animate-fade-in: glyph-fade-in var(--glyph-duration-base) var(--glyph-ease-standard);
103
113
  --animate-slide-in-left: glyph-slide-in-left var(--glyph-duration-slow) var(--glyph-ease-standard);
104
114
  --animate-slide-in-top: glyph-slide-in-top var(--glyph-duration-slow) var(--glyph-ease-standard);
115
+ --animate-fade-out: glyph-fade-out var(--glyph-duration-fast) var(--glyph-ease-standard);
116
+ --animate-sheet-in-right: glyph-sheet-in-right var(--glyph-duration-slow)
117
+ var(--glyph-ease-standard);
118
+ --animate-sheet-out-right: glyph-sheet-out-right var(--glyph-duration-base)
119
+ var(--glyph-ease-standard);
120
+ --animate-sheet-in-left: glyph-sheet-in-left var(--glyph-duration-slow) var(--glyph-ease-standard);
121
+ --animate-sheet-out-left: glyph-sheet-out-left var(--glyph-duration-base)
122
+ var(--glyph-ease-standard);
123
+ --animate-sheet-in-top: glyph-sheet-in-top var(--glyph-duration-slow) var(--glyph-ease-standard);
124
+ --animate-sheet-out-top: glyph-sheet-out-top var(--glyph-duration-base) var(--glyph-ease-standard);
125
+ --animate-sheet-in-bottom: glyph-sheet-in-bottom var(--glyph-duration-slow)
126
+ var(--glyph-ease-standard);
127
+ --animate-sheet-out-bottom: glyph-sheet-out-bottom var(--glyph-duration-base)
128
+ var(--glyph-ease-standard);
129
+ --animate-collapse-down: glyph-collapse-down var(--glyph-duration-base) var(--glyph-ease-standard);
130
+ --animate-collapse-up: glyph-collapse-up var(--glyph-duration-base) var(--glyph-ease-standard);
105
131
  }
106
132
 
107
133
  @keyframes glyph-pop-in {
@@ -126,6 +152,68 @@
126
152
  transform: translateY(-8px);
127
153
  }
128
154
  }
155
+ @keyframes glyph-fade-out {
156
+ to {
157
+ opacity: 0;
158
+ }
159
+ }
160
+ @keyframes glyph-sheet-in-right {
161
+ from {
162
+ transform: translateX(100%);
163
+ }
164
+ }
165
+ @keyframes glyph-sheet-out-right {
166
+ to {
167
+ transform: translateX(100%);
168
+ }
169
+ }
170
+ @keyframes glyph-sheet-in-left {
171
+ from {
172
+ transform: translateX(-100%);
173
+ }
174
+ }
175
+ @keyframes glyph-sheet-out-left {
176
+ to {
177
+ transform: translateX(-100%);
178
+ }
179
+ }
180
+ @keyframes glyph-sheet-in-top {
181
+ from {
182
+ transform: translateY(-100%);
183
+ }
184
+ }
185
+ @keyframes glyph-sheet-out-top {
186
+ to {
187
+ transform: translateY(-100%);
188
+ }
189
+ }
190
+ @keyframes glyph-sheet-in-bottom {
191
+ from {
192
+ transform: translateY(100%);
193
+ }
194
+ }
195
+ @keyframes glyph-sheet-out-bottom {
196
+ to {
197
+ transform: translateY(100%);
198
+ }
199
+ }
200
+ /* Radix sets the content height variable on Accordion and Collapsible content. */
201
+ @keyframes glyph-collapse-down {
202
+ from {
203
+ height: 0;
204
+ }
205
+ to {
206
+ height: var(--radix-accordion-content-height, var(--radix-collapsible-content-height));
207
+ }
208
+ }
209
+ @keyframes glyph-collapse-up {
210
+ from {
211
+ height: var(--radix-accordion-content-height, var(--radix-collapsible-content-height));
212
+ }
213
+ to {
214
+ height: 0;
215
+ }
216
+ }
129
217
 
130
218
  @layer base {
131
219
  *,