@dashforge/tw 0.1.0-beta → 0.2.1-beta
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/A11Y.md +130 -0
- package/CHANGELOG.md +231 -0
- package/dist/index.d.ts +1 -82
- package/dist/index.esm.js +1608 -11
- package/dist/src/components/AspectRatio/AspectRatio.d.ts +36 -0
- package/dist/src/components/AspectRatio/AspectRatio.d.ts.map +1 -0
- package/dist/src/components/AspectRatio/aspectRatio.types.d.ts +50 -0
- package/dist/src/components/AspectRatio/aspectRatio.types.d.ts.map +1 -0
- package/dist/src/components/Box/Box.d.ts +36 -0
- package/dist/src/components/Box/Box.d.ts.map +1 -0
- package/dist/src/components/Box/box.types.d.ts +54 -0
- package/dist/src/components/Box/box.types.d.ts.map +1 -0
- package/dist/src/components/Box/box.variants.d.ts +402 -0
- package/dist/src/components/Box/box.variants.d.ts.map +1 -0
- package/dist/src/components/Button/Button.d.ts.map +1 -1
- package/dist/src/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/src/components/Container/Container.d.ts +35 -0
- package/dist/src/components/Container/Container.d.ts.map +1 -0
- package/dist/src/components/Container/container.types.d.ts +41 -0
- package/dist/src/components/Container/container.types.d.ts.map +1 -0
- package/dist/src/components/Container/container.variants.d.ts +93 -0
- package/dist/src/components/Container/container.variants.d.ts.map +1 -0
- package/dist/src/components/Divider/Divider.d.ts +50 -0
- package/dist/src/components/Divider/Divider.d.ts.map +1 -0
- package/dist/src/components/Divider/divider.types.d.ts +47 -0
- package/dist/src/components/Divider/divider.types.d.ts.map +1 -0
- package/dist/src/components/Divider/divider.variants.d.ts +129 -0
- package/dist/src/components/Divider/divider.variants.d.ts.map +1 -0
- package/dist/src/components/Grid/Grid.d.ts +32 -0
- package/dist/src/components/Grid/Grid.d.ts.map +1 -0
- package/dist/src/components/Grid/grid.types.d.ts +103 -0
- package/dist/src/components/Grid/grid.types.d.ts.map +1 -0
- package/dist/src/components/Grid/grid.variants.d.ts +453 -0
- package/dist/src/components/Grid/grid.variants.d.ts.map +1 -0
- package/dist/src/components/NumberField/NumberField.d.ts.map +1 -1
- package/dist/src/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/dist/src/components/Stack/Stack.d.ts +24 -0
- package/dist/src/components/Stack/Stack.d.ts.map +1 -0
- package/dist/src/components/Stack/stack.types.d.ts +61 -0
- package/dist/src/components/Stack/stack.types.d.ts.map +1 -0
- package/dist/src/components/Stack/stack.variants.d.ts +163 -0
- package/dist/src/components/Stack/stack.variants.d.ts.map +1 -0
- package/dist/src/components/Typography/Typography.d.ts +42 -0
- package/dist/src/components/Typography/Typography.d.ts.map +1 -0
- package/dist/src/components/Typography/typography.types.d.ts +61 -0
- package/dist/src/components/Typography/typography.types.d.ts.map +1 -0
- package/dist/src/components/Typography/typography.variants.d.ts +167 -0
- package/dist/src/components/Typography/typography.variants.d.ts.map +1 -0
- package/dist/src/components/VisuallyHidden/VisuallyHidden.d.ts +42 -0
- package/dist/src/components/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
- package/dist/src/components/VisuallyHidden/visuallyHidden.types.d.ts +42 -0
- package/dist/src/components/VisuallyHidden/visuallyHidden.types.d.ts.map +1 -0
- package/dist/src/index.d.ts +23 -1
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/AspectRatio/AspectRatio.test.tsx +173 -0
- package/src/components/AspectRatio/AspectRatio.tsx +73 -0
- package/src/components/AspectRatio/aspectRatio.types.ts +54 -0
- package/src/components/Box/Box.test.tsx +349 -0
- package/src/components/Box/Box.tsx +83 -0
- package/src/components/Box/box.types.ts +61 -0
- package/src/components/Box/box.variants.ts +211 -0
- package/src/components/Button/Button.tsx +11 -0
- package/src/components/Checkbox/Checkbox.tsx +26 -2
- package/src/components/Container/Container.test.tsx +209 -0
- package/src/components/Container/Container.tsx +74 -0
- package/src/components/Container/container.types.ts +45 -0
- package/src/components/Container/container.variants.ts +81 -0
- package/src/components/Divider/Divider.test.tsx +241 -0
- package/src/components/Divider/Divider.tsx +140 -0
- package/src/components/Divider/divider.types.ts +52 -0
- package/src/components/Divider/divider.variants.ts +115 -0
- package/src/components/Grid/Grid.test.tsx +321 -0
- package/src/components/Grid/Grid.tsx +148 -0
- package/src/components/Grid/grid.types.ts +112 -0
- package/src/components/Grid/grid.variants.ts +133 -0
- package/src/components/NumberField/NumberField.tsx +30 -2
- package/src/components/RadioGroup/RadioGroup.tsx +23 -1
- package/src/components/Stack/Stack.test.tsx +309 -0
- package/src/components/Stack/Stack.tsx +115 -0
- package/src/components/Stack/stack.types.ts +68 -0
- package/src/components/Stack/stack.variants.ts +80 -0
- package/src/components/Typography/Typography.test.tsx +230 -0
- package/src/components/Typography/Typography.tsx +112 -0
- package/src/components/Typography/typography.types.ts +65 -0
- package/src/components/Typography/typography.variants.ts +113 -0
- package/src/components/VisuallyHidden/VisuallyHidden.test.tsx +86 -0
- package/src/components/VisuallyHidden/VisuallyHidden.tsx +59 -0
- package/src/components/VisuallyHidden/visuallyHidden.types.ts +45 -0
- package/src/index.ts +50 -1
- package/LICENSE +0 -21
- package/dist/components/AppShell/AppShell.d.ts +0 -32
- package/dist/components/AppShell/AppShell.d.ts.map +0 -1
- package/dist/components/AppShell/appShell.types.d.ts +0 -62
- package/dist/components/AppShell/appShell.types.d.ts.map +0 -1
- package/dist/components/AppShell/appShell.variants.d.ts +0 -65
- package/dist/components/AppShell/appShell.variants.d.ts.map +0 -1
- package/dist/components/Autocomplete/Autocomplete.d.ts +0 -32
- package/dist/components/Autocomplete/Autocomplete.d.ts.map +0 -1
- package/dist/components/Autocomplete/autocomplete.types.d.ts +0 -214
- package/dist/components/Autocomplete/autocomplete.types.d.ts.map +0 -1
- package/dist/components/Autocomplete/autocomplete.variants.d.ts +0 -214
- package/dist/components/Autocomplete/autocomplete.variants.d.ts.map +0 -1
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +0 -23
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts.map +0 -1
- package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts +0 -98
- package/dist/components/Breadcrumbs/breadcrumbs.types.d.ts.map +0 -1
- package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts +0 -85
- package/dist/components/Breadcrumbs/breadcrumbs.variants.d.ts.map +0 -1
- package/dist/components/Button/Button.d.ts +0 -44
- package/dist/components/Button/Button.d.ts.map +0 -1
- package/dist/components/Button/button.types.d.ts +0 -66
- package/dist/components/Button/button.types.d.ts.map +0 -1
- package/dist/components/Button/button.variants.d.ts +0 -104
- package/dist/components/Button/button.variants.d.ts.map +0 -1
- package/dist/components/Checkbox/Checkbox.d.ts +0 -31
- package/dist/components/Checkbox/Checkbox.d.ts.map +0 -1
- package/dist/components/Checkbox/checkbox.types.d.ts +0 -86
- package/dist/components/Checkbox/checkbox.types.d.ts.map +0 -1
- package/dist/components/Checkbox/checkbox.variants.d.ts +0 -109
- package/dist/components/Checkbox/checkbox.variants.d.ts.map +0 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +0 -38
- package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +0 -1
- package/dist/components/ConfirmDialog/confirmDialog.types.d.ts +0 -80
- package/dist/components/ConfirmDialog/confirmDialog.types.d.ts.map +0 -1
- package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts +0 -90
- package/dist/components/ConfirmDialog/confirmDialog.variants.d.ts.map +0 -1
- package/dist/components/DateTimePicker/DateTimePicker.d.ts +0 -49
- package/dist/components/DateTimePicker/DateTimePicker.d.ts.map +0 -1
- package/dist/components/DateTimePicker/dateTimePicker.types.d.ts +0 -95
- package/dist/components/DateTimePicker/dateTimePicker.types.d.ts.map +0 -1
- package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts +0 -165
- package/dist/components/DateTimePicker/dateTimePicker.variants.d.ts.map +0 -1
- package/dist/components/LeftNav/LeftNav.d.ts +0 -34
- package/dist/components/LeftNav/LeftNav.d.ts.map +0 -1
- package/dist/components/LeftNav/leftNav.types.d.ts +0 -136
- package/dist/components/LeftNav/leftNav.types.d.ts.map +0 -1
- package/dist/components/LeftNav/leftNav.variants.d.ts +0 -143
- package/dist/components/LeftNav/leftNav.variants.d.ts.map +0 -1
- package/dist/components/NumberField/NumberField.d.ts +0 -18
- package/dist/components/NumberField/NumberField.d.ts.map +0 -1
- package/dist/components/NumberField/numberField.types.d.ts +0 -79
- package/dist/components/NumberField/numberField.types.d.ts.map +0 -1
- package/dist/components/NumberField/numberField.variants.d.ts +0 -169
- package/dist/components/NumberField/numberField.variants.d.ts.map +0 -1
- package/dist/components/OTPField/OTPField.d.ts +0 -25
- package/dist/components/OTPField/OTPField.d.ts.map +0 -1
- package/dist/components/OTPField/otpField.types.d.ts +0 -74
- package/dist/components/OTPField/otpField.types.d.ts.map +0 -1
- package/dist/components/OTPField/otpField.variants.d.ts +0 -105
- package/dist/components/OTPField/otpField.variants.d.ts.map +0 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts +0 -35
- package/dist/components/RadioGroup/RadioGroup.d.ts.map +0 -1
- package/dist/components/RadioGroup/radioGroup.types.d.ts +0 -103
- package/dist/components/RadioGroup/radioGroup.types.d.ts.map +0 -1
- package/dist/components/RadioGroup/radioGroup.variants.d.ts +0 -166
- package/dist/components/RadioGroup/radioGroup.variants.d.ts.map +0 -1
- package/dist/components/Snackbar/Snackbar.d.ts +0 -37
- package/dist/components/Snackbar/Snackbar.d.ts.map +0 -1
- package/dist/components/Snackbar/snackbar.types.d.ts +0 -86
- package/dist/components/Snackbar/snackbar.types.d.ts.map +0 -1
- package/dist/components/Snackbar/snackbar.variants.d.ts +0 -153
- package/dist/components/Snackbar/snackbar.variants.d.ts.map +0 -1
- package/dist/components/Switch/Switch.d.ts +0 -15
- package/dist/components/Switch/Switch.d.ts.map +0 -1
- package/dist/components/Switch/switch.types.d.ts +0 -47
- package/dist/components/Switch/switch.types.d.ts.map +0 -1
- package/dist/components/Switch/switch.variants.d.ts +0 -105
- package/dist/components/Switch/switch.variants.d.ts.map +0 -1
- package/dist/components/TextField/TextField.d.ts +0 -25
- package/dist/components/TextField/TextField.d.ts.map +0 -1
- package/dist/components/TextField/textField.types.d.ts +0 -72
- package/dist/components/TextField/textField.types.d.ts.map +0 -1
- package/dist/components/TextField/textField.variants.d.ts +0 -160
- package/dist/components/TextField/textField.variants.d.ts.map +0 -1
- package/dist/components/Textarea/Textarea.d.ts +0 -16
- package/dist/components/Textarea/Textarea.d.ts.map +0 -1
- package/dist/components/Textarea/textarea.types.d.ts +0 -63
- package/dist/components/Textarea/textarea.types.d.ts.map +0 -1
- package/dist/components/Textarea/textarea.variants.d.ts +0 -197
- package/dist/components/Textarea/textarea.variants.d.ts.map +0 -1
- package/dist/components/TopBar/TopBar.d.ts +0 -33
- package/dist/components/TopBar/TopBar.d.ts.map +0 -1
- package/dist/components/TopBar/topBar.types.d.ts +0 -49
- package/dist/components/TopBar/topBar.types.d.ts.map +0 -1
- package/dist/components/TopBar/topBar.variants.d.ts +0 -79
- package/dist/components/TopBar/topBar.variants.d.ts.map +0 -1
- package/dist/components/_shared/resolveValidationState.d.ts +0 -42
- package/dist/components/_shared/resolveValidationState.d.ts.map +0 -1
- package/dist/hooks/useAccessState.d.ts +0 -37
- package/dist/hooks/useAccessState.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/tsconfig.lib.tsbuildinfo +0 -1
- package/dist/utils/cn.d.ts +0 -26
- package/dist/utils/cn.d.ts.map +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { forwardRef, type ElementType, type ReactElement } from 'react';
|
|
2
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
+
import { cn } from '../../utils/cn.js';
|
|
4
|
+
import { containerVariants } from './container.variants.js';
|
|
5
|
+
import type { ContainerProps } from './container.types.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `<Container>` — centered max-width wrapper for page-level layouts.
|
|
9
|
+
*
|
|
10
|
+
* The pattern is universal: every page-root `<div>` in a non-trivial
|
|
11
|
+
* web app boils down to "mx-auto + max-w-X + responsive horizontal
|
|
12
|
+
* padding". Container collapses that into a typed prop set so the
|
|
13
|
+
* decision lives in ONE place per app section (the Container size),
|
|
14
|
+
* not scattered as utility chains across every page file.
|
|
15
|
+
*
|
|
16
|
+
* Default size is `'xl'` (1280px) — comfortable for full app shells
|
|
17
|
+
* with a left nav + main + optional right rail. Drop to `'lg'` (1024px)
|
|
18
|
+
* for content-heavy docs/marketing, jump to `'2xl'` (1536px) for wide
|
|
19
|
+
* dashboards.
|
|
20
|
+
*
|
|
21
|
+
* Composition pattern — Container at the page root, Stack/Grid inside:
|
|
22
|
+
*
|
|
23
|
+
* <Container size="lg" as="main">
|
|
24
|
+
* <Stack gap={8}>
|
|
25
|
+
* <Typography variant="h1">Page title</Typography>
|
|
26
|
+
* <Grid container spacing={6}>
|
|
27
|
+
* <Grid xs={12} md={6}>...</Grid>
|
|
28
|
+
* </Grid>
|
|
29
|
+
* </Stack>
|
|
30
|
+
* </Container>
|
|
31
|
+
*
|
|
32
|
+
* Container handles the page chrome (centered, padded, capped width);
|
|
33
|
+
* Stack/Grid handle the actual layout of children. Two concerns, two
|
|
34
|
+
* primitives.
|
|
35
|
+
*
|
|
36
|
+
* Polymorphism rule (same as Typography/Box/Stack/Grid): when both
|
|
37
|
+
* `as` and `asChild` are passed, `asChild` wins.
|
|
38
|
+
*/
|
|
39
|
+
export const Container = forwardRef<HTMLElement, ContainerProps>(
|
|
40
|
+
function Container(props, ref) {
|
|
41
|
+
const {
|
|
42
|
+
size,
|
|
43
|
+
px,
|
|
44
|
+
centerContent,
|
|
45
|
+
as,
|
|
46
|
+
asChild = false,
|
|
47
|
+
sx,
|
|
48
|
+
children,
|
|
49
|
+
...rest
|
|
50
|
+
} = props;
|
|
51
|
+
|
|
52
|
+
const classes = cn(
|
|
53
|
+
containerVariants({ size, px, centerContent }),
|
|
54
|
+
sx,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (asChild) {
|
|
58
|
+
return (
|
|
59
|
+
<Slot ref={ref} className={classes} {...rest}>
|
|
60
|
+
{children as ReactElement}
|
|
61
|
+
</Slot>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const Tag = (as ?? 'div') as ElementType;
|
|
66
|
+
return (
|
|
67
|
+
<Tag ref={ref as never} className={classes} {...rest}>
|
|
68
|
+
{children}
|
|
69
|
+
</Tag>
|
|
70
|
+
);
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
Container.displayName = 'Container';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ElementType, HTMLAttributes } from 'react';
|
|
2
|
+
import type { ContainerVariants } from './container.variants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for `<Container>` — page-level centered max-width wrapper.
|
|
6
|
+
*
|
|
7
|
+
* Use at the page-root level (or section-root) to constrain content
|
|
8
|
+
* width and apply the canonical responsive horizontal padding ramp.
|
|
9
|
+
* Compose Stack/Grid INSIDE Container for the actual layout work.
|
|
10
|
+
*
|
|
11
|
+
* Native attribute overrides:
|
|
12
|
+
* • `className` omitted in favour of `sx` (utility string, merged
|
|
13
|
+
* via tailwind-merge — same convention as Box/Stack/Grid/Typography).
|
|
14
|
+
*/
|
|
15
|
+
export interface ContainerProps
|
|
16
|
+
extends Omit<HTMLAttributes<HTMLDivElement>, 'className'>,
|
|
17
|
+
Pick<ContainerVariants, 'size' | 'px' | 'centerContent'> {
|
|
18
|
+
/**
|
|
19
|
+
* Override the rendered HTML tag. Defaults to `'div'`. Use
|
|
20
|
+
* `as="main"` for the primary content region of a page,
|
|
21
|
+
* `as="section"` for a named section, `as="article"` for a
|
|
22
|
+
* self-contained article shell.
|
|
23
|
+
*
|
|
24
|
+
* Ignored when `asChild` is true.
|
|
25
|
+
*/
|
|
26
|
+
as?: ElementType;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Render via Radix `Slot` — the Container styles paint onto the
|
|
30
|
+
* single React child instead of wrapping it. Useful for letting a
|
|
31
|
+
* router `<main>` element receive the Container chrome without
|
|
32
|
+
* adding an intermediate `<div>` in the tree.
|
|
33
|
+
*
|
|
34
|
+
* Mutually exclusive with `as` (when both are passed, `asChild` wins).
|
|
35
|
+
*/
|
|
36
|
+
asChild?: boolean;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Utility classes appended to the variant chain. Resolved via
|
|
40
|
+
* `tailwind-merge` so the consumer's classes always win over the
|
|
41
|
+
* variant defaults — useful for one-off vertical padding (`sx="py-8"`),
|
|
42
|
+
* custom max-width (`sx="max-w-3xl"`), etc.
|
|
43
|
+
*/
|
|
44
|
+
sx?: string;
|
|
45
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { tv, type VariantProps } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `containerVariants` — centered max-width wrapper for page layouts.
|
|
5
|
+
*
|
|
6
|
+
* Architectural role:
|
|
7
|
+
*
|
|
8
|
+
* Every web app has the same pattern at the page-root level: a div
|
|
9
|
+
* that's `mx-auto`, capped at some `max-w-*`, with responsive
|
|
10
|
+
* horizontal padding. Without Container, every page rewrites:
|
|
11
|
+
*
|
|
12
|
+
* <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
13
|
+
*
|
|
14
|
+
* Container collapses that into one typed prop set, with size names
|
|
15
|
+
* that mirror Tailwind's breakpoint vocabulary so the muscle memory
|
|
16
|
+
* carries over (`size="lg"` ↔ `max-w-screen-lg`).
|
|
17
|
+
*
|
|
18
|
+
* Size axis — maps to Tailwind's `max-w-screen-*` aliases:
|
|
19
|
+
* • sm → max-w-screen-sm (640px)
|
|
20
|
+
* • md → max-w-screen-md (768px)
|
|
21
|
+
* • lg → max-w-screen-lg (1024px) — most common doc/content cap
|
|
22
|
+
* • xl → max-w-screen-xl (1280px) — default; comfortable for full apps
|
|
23
|
+
* • 2xl → max-w-screen-2xl (1536px) — wide dashboards
|
|
24
|
+
* • fluid → no max-width at all (full bleed, padding still applies)
|
|
25
|
+
*
|
|
26
|
+
* Padding axis (`px`):
|
|
27
|
+
* • true (default) — responsive horizontal padding (px-4 sm:px-6 lg:px-8)
|
|
28
|
+
* The canonical Tailwind responsive padding ramp. Designed to keep
|
|
29
|
+
* edges from kissing the viewport on mobile and breathing more on
|
|
30
|
+
* larger screens.
|
|
31
|
+
* • false — no padding. Use when the consumer wants full bleed AND
|
|
32
|
+
* handles edge padding inside (e.g. a hero section with its own
|
|
33
|
+
* internal spacing scale).
|
|
34
|
+
*
|
|
35
|
+
* Center content axis (`centerContent`):
|
|
36
|
+
* • true — turns the Container into a flex column with items-center
|
|
37
|
+
* so the page content stacks centered horizontally. Common for
|
|
38
|
+
* marketing pages, sign-in flows, "single artifact" layouts.
|
|
39
|
+
* • false (default) — children flow normally (block stacking).
|
|
40
|
+
*/
|
|
41
|
+
export const containerVariants = tv({
|
|
42
|
+
base: 'mx-auto w-full',
|
|
43
|
+
|
|
44
|
+
variants: {
|
|
45
|
+
size: {
|
|
46
|
+
sm: 'max-w-screen-sm',
|
|
47
|
+
md: 'max-w-screen-md',
|
|
48
|
+
lg: 'max-w-screen-lg',
|
|
49
|
+
xl: 'max-w-screen-xl',
|
|
50
|
+
'2xl': 'max-w-screen-2xl',
|
|
51
|
+
fluid: '',
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/*
|
|
55
|
+
* Responsive padding ramp. `false` skips it entirely so the
|
|
56
|
+
* consumer can supply custom padding via `sx` when needed.
|
|
57
|
+
*/
|
|
58
|
+
px: {
|
|
59
|
+
true: 'px-4 sm:px-6 lg:px-8',
|
|
60
|
+
false: '',
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* Stacks children centered. Mutually compatible with all sizes —
|
|
65
|
+
* a fluid container with centerContent is the canonical "marketing
|
|
66
|
+
* hero" layout.
|
|
67
|
+
*/
|
|
68
|
+
centerContent: {
|
|
69
|
+
true: 'flex flex-col items-center',
|
|
70
|
+
false: '',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
defaultVariants: {
|
|
75
|
+
size: 'xl',
|
|
76
|
+
px: true,
|
|
77
|
+
centerContent: false,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export type ContainerVariants = VariantProps<typeof containerVariants>;
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import { Divider } from './Divider.js';
|
|
5
|
+
|
|
6
|
+
describe('<Divider>', () => {
|
|
7
|
+
// ─── Line-only mode ─────────────────────────────────────────────────
|
|
8
|
+
describe('line-only (no children)', () => {
|
|
9
|
+
it('renders <hr> for horizontal', () => {
|
|
10
|
+
const { container } = render(<Divider />);
|
|
11
|
+
expect(container.firstElementChild?.tagName).toBe('HR');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('renders <div role="separator"> for vertical', () => {
|
|
15
|
+
const { container } = render(<Divider orientation="vertical" />);
|
|
16
|
+
const el = container.firstElementChild;
|
|
17
|
+
expect(el?.tagName).toBe('DIV');
|
|
18
|
+
expect(el?.getAttribute('role')).toBe('separator');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('sets aria-orientation correctly', () => {
|
|
22
|
+
const { container: ch } = render(<Divider />);
|
|
23
|
+
expect(ch.firstElementChild?.getAttribute('aria-orientation')).toBe('horizontal');
|
|
24
|
+
|
|
25
|
+
const { container: cv } = render(<Divider orientation="vertical" />);
|
|
26
|
+
expect(cv.firstElementChild?.getAttribute('aria-orientation')).toBe('vertical');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('horizontal applies border-t (line carrier)', () => {
|
|
30
|
+
const { container } = render(<Divider />);
|
|
31
|
+
const cls = container.firstElementChild?.className ?? '';
|
|
32
|
+
expect(cls).toContain('border-t');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('vertical applies border-l', () => {
|
|
36
|
+
const { container } = render(<Divider orientation="vertical" />);
|
|
37
|
+
expect(container.firstElementChild?.className).toContain('border-l');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('strips <hr> UA default via border-0', () => {
|
|
41
|
+
const { container } = render(<Divider />);
|
|
42
|
+
expect(container.firstElementChild?.className).toContain('border-0');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ─── Variants — line style ──────────────────────────────────────────
|
|
47
|
+
describe('variant', () => {
|
|
48
|
+
it('default solid', () => {
|
|
49
|
+
const { container } = render(<Divider />);
|
|
50
|
+
expect(container.firstElementChild?.className).toContain('border-solid');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('dashed', () => {
|
|
54
|
+
const { container } = render(<Divider variant="dashed" />);
|
|
55
|
+
expect(container.firstElementChild?.className).toContain('border-dashed');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('dotted', () => {
|
|
59
|
+
const { container } = render(<Divider variant="dotted" />);
|
|
60
|
+
expect(container.firstElementChild?.className).toContain('border-dotted');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ─── Color intent ───────────────────────────────────────────────────
|
|
65
|
+
describe('color', () => {
|
|
66
|
+
it('default neutral', () => {
|
|
67
|
+
const { container } = render(<Divider />);
|
|
68
|
+
const cls = container.firstElementChild?.className ?? '';
|
|
69
|
+
expect(cls).toContain('border-neutral-200');
|
|
70
|
+
expect(cls).toContain('dark:border-neutral-800');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('color="primary"', () => {
|
|
74
|
+
const { container } = render(<Divider color="primary" />);
|
|
75
|
+
expect(container.firstElementChild?.className).toContain('border-primary-300');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('color="danger"', () => {
|
|
79
|
+
const { container } = render(<Divider color="danger" />);
|
|
80
|
+
expect(container.firstElementChild?.className).toContain('border-danger-300');
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ─── Labeled mode ───────────────────────────────────────────────────
|
|
85
|
+
describe('labeled (with children)', () => {
|
|
86
|
+
it('renders 3 children: line, label, line', () => {
|
|
87
|
+
const { container } = render(<Divider>OR</Divider>);
|
|
88
|
+
const root = container.firstElementChild;
|
|
89
|
+
expect(root?.children.length).toBe(3);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('label text is preserved', () => {
|
|
93
|
+
const { container } = render(<Divider>OR</Divider>);
|
|
94
|
+
expect(container.firstElementChild?.textContent).toBe('OR');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('root has role="separator" + aria-orientation', () => {
|
|
98
|
+
const { container } = render(<Divider>OR</Divider>);
|
|
99
|
+
const root = container.firstElementChild;
|
|
100
|
+
expect(root?.getAttribute('role')).toBe('separator');
|
|
101
|
+
expect(root?.getAttribute('aria-orientation')).toBe('horizontal');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('line segments are aria-hidden (separator role is on the root)', () => {
|
|
105
|
+
const { container } = render(<Divider>OR</Divider>);
|
|
106
|
+
const lines = container.firstElementChild?.querySelectorAll('span[aria-hidden]');
|
|
107
|
+
expect(lines?.length).toBe(2);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('center alignment: both segments flex-1', () => {
|
|
111
|
+
const { container } = render(<Divider align="center">OR</Divider>);
|
|
112
|
+
const lines = container.firstElementChild?.querySelectorAll('span[aria-hidden]');
|
|
113
|
+
lines?.forEach((line) => {
|
|
114
|
+
expect(line.className).toContain('flex-1');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('start alignment: left segment is short stub', () => {
|
|
119
|
+
const { container } = render(<Divider align="start">OR</Divider>);
|
|
120
|
+
const lines = container.firstElementChild?.querySelectorAll('span[aria-hidden]');
|
|
121
|
+
expect(lines?.[0].className).toContain('basis-8');
|
|
122
|
+
expect(lines?.[1].className).toContain('flex-1');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('end alignment: right segment is short stub', () => {
|
|
126
|
+
const { container } = render(<Divider align="end">OR</Divider>);
|
|
127
|
+
const lines = container.firstElementChild?.querySelectorAll('span[aria-hidden]');
|
|
128
|
+
expect(lines?.[0].className).toContain('flex-1');
|
|
129
|
+
expect(lines?.[1].className).toContain('basis-8');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('label gets shrink-0 + padding so it does not collapse', () => {
|
|
133
|
+
const { container } = render(<Divider>Hello</Divider>);
|
|
134
|
+
const label = container.firstElementChild?.children[1] as HTMLElement;
|
|
135
|
+
expect(label.className).toContain('shrink-0');
|
|
136
|
+
expect(label.className).toContain('px-3');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('color applies to both segments in labeled mode', () => {
|
|
140
|
+
const { container } = render(<Divider color="primary">OR</Divider>);
|
|
141
|
+
const lines = container.firstElementChild?.querySelectorAll('span[aria-hidden]');
|
|
142
|
+
lines?.forEach((line) => {
|
|
143
|
+
expect(line.className).toContain('border-primary-300');
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('renders complex children (JSX)', () => {
|
|
148
|
+
const { container } = render(
|
|
149
|
+
<Divider>
|
|
150
|
+
<strong>Section title</strong>
|
|
151
|
+
</Divider>,
|
|
152
|
+
);
|
|
153
|
+
const label = container.firstElementChild?.children[1];
|
|
154
|
+
expect(label?.querySelector('strong')?.textContent).toBe('Section title');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// ─── Override ───────────────────────────────────────────────────────
|
|
159
|
+
describe('override', () => {
|
|
160
|
+
it('sx wins over variant defaults', () => {
|
|
161
|
+
const { container } = render(<Divider sx="border-t-4" />);
|
|
162
|
+
const cls = container.firstElementChild?.className ?? '';
|
|
163
|
+
expect(cls).toContain('border-t-4');
|
|
164
|
+
// tailwind-merge collapses border-t → border-t-4
|
|
165
|
+
expect(cls).not.toMatch(/border-t (?!-)/);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('sx applies on root in labeled mode', () => {
|
|
169
|
+
const { container } = render(<Divider sx="my-8">OR</Divider>);
|
|
170
|
+
expect(container.firstElementChild?.className).toContain('my-8');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// ─── Pass-through ───────────────────────────────────────────────────
|
|
175
|
+
describe('pass-through', () => {
|
|
176
|
+
it('forwards data-* on root', () => {
|
|
177
|
+
const { container } = render(<Divider data-testid="d" />);
|
|
178
|
+
expect(container.firstElementChild?.getAttribute('data-testid')).toBe('d');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('forwards data-* in labeled mode too', () => {
|
|
182
|
+
const { container } = render(<Divider data-testid="d">OR</Divider>);
|
|
183
|
+
expect(container.firstElementChild?.getAttribute('data-testid')).toBe('d');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// ─── F11-bis edge cases ─────────────────────────────────────────────
|
|
188
|
+
describe('color — every intent', () => {
|
|
189
|
+
const INTENTS = ['secondary', 'success', 'warning', 'danger', 'info'] as const;
|
|
190
|
+
it.each(INTENTS)('color="%s" emits border-%s-300 with dark pair', (color) => {
|
|
191
|
+
const { container } = render(<Divider color={color} />);
|
|
192
|
+
const cls = container.firstElementChild?.className ?? '';
|
|
193
|
+
expect(cls).toContain(`border-${color}-300`);
|
|
194
|
+
expect(cls).toContain(`dark:border-${color}-700`);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('vertical labeled mode', () => {
|
|
199
|
+
it('vertical + label renders all 3 children with vertical layout', () => {
|
|
200
|
+
const { container } = render(
|
|
201
|
+
<Divider orientation="vertical">section</Divider>,
|
|
202
|
+
);
|
|
203
|
+
const root = container.firstElementChild;
|
|
204
|
+
expect(root?.tagName).toBe('DIV');
|
|
205
|
+
expect(root?.getAttribute('aria-orientation')).toBe('vertical');
|
|
206
|
+
expect(root?.className).toContain('flex-col');
|
|
207
|
+
expect(root?.children.length).toBe(3);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('label edge values', () => {
|
|
212
|
+
it('numeric label (0) renders correctly', () => {
|
|
213
|
+
const { container } = render(<Divider>{0}</Divider>);
|
|
214
|
+
// 0 is a valid React child, should render as "0"
|
|
215
|
+
expect(container.firstElementChild?.textContent).toBe('0');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('JSX with multiple elements as label', () => {
|
|
219
|
+
const { container } = render(
|
|
220
|
+
<Divider>
|
|
221
|
+
<strong>bold</strong>
|
|
222
|
+
<em> italic</em>
|
|
223
|
+
</Divider>,
|
|
224
|
+
);
|
|
225
|
+
const root = container.firstElementChild;
|
|
226
|
+
// root has 3 children (line + label-span + line); label-span has 2 nested
|
|
227
|
+
expect(root?.children.length).toBe(3);
|
|
228
|
+
expect(root?.querySelector('strong')?.textContent).toBe('bold');
|
|
229
|
+
expect(root?.querySelector('em')?.textContent).toBe(' italic');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe('flexItem (no-op forward-compat hook)', () => {
|
|
234
|
+
it('flexItem prop does not crash or leak as attribute', () => {
|
|
235
|
+
const { container } = render(<Divider flexItem />);
|
|
236
|
+
const el = container.firstElementChild as HTMLElement;
|
|
237
|
+
expect(el.hasAttribute('flexitem')).toBe(false);
|
|
238
|
+
expect(el.hasAttribute('flexItem')).toBe(false);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import { cn } from '../../utils/cn.js';
|
|
3
|
+
import { dividerVariants, dividerLineVariants } from './divider.variants.js';
|
|
4
|
+
import type { DividerProps } from './divider.types.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `<Divider>` — visual separator. Two modes:
|
|
8
|
+
*
|
|
9
|
+
* 1. Line-only (no children):
|
|
10
|
+
*
|
|
11
|
+
* <Divider />
|
|
12
|
+
* → <hr role="separator" aria-orientation="horizontal" />
|
|
13
|
+
*
|
|
14
|
+
* Renders a single horizontal line via `border-t-*` on an `<hr>`
|
|
15
|
+
* (which by default has no `display`, no margin in our reset, just
|
|
16
|
+
* acts as the border carrier).
|
|
17
|
+
*
|
|
18
|
+
* 2. Labeled (with children):
|
|
19
|
+
*
|
|
20
|
+
* <Divider><Typography variant="overline">OR</Typography></Divider>
|
|
21
|
+
* → <div role="separator" aria-orientation="horizontal">
|
|
22
|
+
* <span aria-hidden className="flex-1 border-t" />
|
|
23
|
+
* <span className="px-3">OR</span>
|
|
24
|
+
* <span aria-hidden className="flex-1 border-t" />
|
|
25
|
+
* </div>
|
|
26
|
+
*
|
|
27
|
+
* Two line segments share the available space; the label sits
|
|
28
|
+
* between them with horizontal padding for breathing room. Each
|
|
29
|
+
* line segment is `aria-hidden` (the role="separator" on the root
|
|
30
|
+
* conveys the separator semantics — duplicating it would confuse
|
|
31
|
+
* screen readers).
|
|
32
|
+
*
|
|
33
|
+
* Alignment:
|
|
34
|
+
* • align="start" → label hugs the left, right segment grows
|
|
35
|
+
* • align="center" (default) → both segments equal
|
|
36
|
+
* • align="end" → label hugs the right, left segment grows
|
|
37
|
+
*
|
|
38
|
+
* Implemented by setting `flex-basis: 0` to either segment to keep
|
|
39
|
+
* it minimal. We use `basis-[2rem]` (32px short stub) rather than
|
|
40
|
+
* `basis-0` so a tiny line still hints at the divider on the squashed
|
|
41
|
+
* side — pure flex-1 vs basis-0 would collapse it invisibly.
|
|
42
|
+
*
|
|
43
|
+
* Vertical orientation:
|
|
44
|
+
* The line orientation flips (border-l instead of border-t). Vertical
|
|
45
|
+
* labeled dividers are RARE in practice — supported for parity but
|
|
46
|
+
* the typical use is line-only between flex row items.
|
|
47
|
+
*
|
|
48
|
+
* a11y:
|
|
49
|
+
* • Root element gets `role="separator"` (or implicit via `<hr>`)
|
|
50
|
+
* • `aria-orientation` is set explicitly so AT knows the axis
|
|
51
|
+
* • Labeled mode: label has no extra role; the visual layout speaks
|
|
52
|
+
*/
|
|
53
|
+
export const Divider = forwardRef<HTMLElement, DividerProps>(
|
|
54
|
+
function Divider(props, ref) {
|
|
55
|
+
const {
|
|
56
|
+
orientation = 'horizontal',
|
|
57
|
+
align = 'center',
|
|
58
|
+
variant = 'solid',
|
|
59
|
+
color = 'neutral',
|
|
60
|
+
children,
|
|
61
|
+
flexItem, // currently a no-op (see types) — `self-stretch` is in TV base
|
|
62
|
+
sx,
|
|
63
|
+
...rest
|
|
64
|
+
} = props;
|
|
65
|
+
|
|
66
|
+
// Reference flexItem to silence unused-var lint while keeping it in the
|
|
67
|
+
// public API for parity with MUI Divider. Forward-compat hook.
|
|
68
|
+
void flexItem;
|
|
69
|
+
|
|
70
|
+
// ─── Mode 1: line-only (no children) ─────────────────────────────
|
|
71
|
+
if (children == null) {
|
|
72
|
+
const lineClasses = cn(
|
|
73
|
+
dividerLineVariants({ orientation, variant, color, segment: 'full' }),
|
|
74
|
+
sx,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Horizontal → <hr>: zero default styling once we strip the UA
|
|
78
|
+
// default `<hr>` border via `border-0` (in `dividerLineVariants`
|
|
79
|
+
// base) and apply our own `border-t-*`. Vertical → <div> because
|
|
80
|
+
// <hr> can't be vertical cross-browser-consistently.
|
|
81
|
+
if (orientation === 'horizontal') {
|
|
82
|
+
return (
|
|
83
|
+
<hr
|
|
84
|
+
ref={ref as never}
|
|
85
|
+
role="separator"
|
|
86
|
+
aria-orientation="horizontal"
|
|
87
|
+
className={cn('border-0', lineClasses)}
|
|
88
|
+
{...rest}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return (
|
|
93
|
+
<div
|
|
94
|
+
ref={ref as never}
|
|
95
|
+
role="separator"
|
|
96
|
+
aria-orientation="vertical"
|
|
97
|
+
className={lineClasses}
|
|
98
|
+
{...rest}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ─── Mode 2: labeled (with children) ─────────────────────────────
|
|
104
|
+
const rootClasses = cn(dividerVariants({ orientation, align }), sx);
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* Segment widths per `align`:
|
|
108
|
+
* • center → both flex-1 (equal share)
|
|
109
|
+
* • start → left short stub, right grows
|
|
110
|
+
* • end → left grows, right short stub
|
|
111
|
+
*
|
|
112
|
+
* "Short stub" = 2rem so the divider visually exists on the squashed
|
|
113
|
+
* side without dominating the label.
|
|
114
|
+
*/
|
|
115
|
+
const isHorizontal = orientation === 'horizontal';
|
|
116
|
+
const leftStubClass = align === 'start' ? (isHorizontal ? 'basis-8 grow-0' : 'basis-8 grow-0') : 'flex-1';
|
|
117
|
+
const rightStubClass = align === 'end' ? (isHorizontal ? 'basis-8 grow-0' : 'basis-8 grow-0') : 'flex-1';
|
|
118
|
+
|
|
119
|
+
const lineCommon = dividerLineVariants({ orientation, variant, color, segment: 'grow' });
|
|
120
|
+
const labelPadding = isHorizontal ? 'px-3' : 'py-3';
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div
|
|
124
|
+
ref={ref as never}
|
|
125
|
+
role="separator"
|
|
126
|
+
aria-orientation={orientation}
|
|
127
|
+
className={rootClasses}
|
|
128
|
+
{...rest}
|
|
129
|
+
>
|
|
130
|
+
<span aria-hidden="true" className={cn(lineCommon, leftStubClass)} />
|
|
131
|
+
<span className={cn('shrink-0 text-sm text-neutral-500 dark:text-neutral-400', labelPadding)}>
|
|
132
|
+
{children}
|
|
133
|
+
</span>
|
|
134
|
+
<span aria-hidden="true" className={cn(lineCommon, rightStubClass)} />
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
Divider.displayName = 'Divider';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import type { DividerVariants, DividerLineVariants } from './divider.variants.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for `<Divider>` — visual separator with optional inline label.
|
|
6
|
+
*
|
|
7
|
+
* Two rendering modes:
|
|
8
|
+
* • Line-only (no `children`) — renders an `<hr>` (horizontal) or
|
|
9
|
+
* `<div role="separator">` (vertical).
|
|
10
|
+
* • Labeled (with `children`) — renders a flex row: two line
|
|
11
|
+
* segments around the centered label.
|
|
12
|
+
* Canonical "OR" separator pattern.
|
|
13
|
+
*
|
|
14
|
+
* The user passes ONE consistent prop set; the implementation chooses
|
|
15
|
+
* the mode based on whether `children` is provided.
|
|
16
|
+
*/
|
|
17
|
+
export interface DividerProps
|
|
18
|
+
extends Omit<HTMLAttributes<HTMLElement>, 'className' | 'color' | 'children'>,
|
|
19
|
+
Pick<DividerVariants, 'orientation' | 'align'>,
|
|
20
|
+
Pick<DividerLineVariants, 'variant' | 'color'> {
|
|
21
|
+
/**
|
|
22
|
+
* Optional inline label. When present, the divider switches from
|
|
23
|
+
* "single line" to "two segments + label" layout — the canonical
|
|
24
|
+
* "OR" separator pattern between sign-in methods, section titled
|
|
25
|
+
* separators, etc.
|
|
26
|
+
*
|
|
27
|
+
* Accepts any node (string, Typography element, Stack with icon,
|
|
28
|
+
* etc.). Recommended: `<Typography variant="overline">OR</Typography>`
|
|
29
|
+
* for short uppercase labels.
|
|
30
|
+
*/
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* In a flex Stack `direction="row"`, a `<Divider orientation="vertical">`
|
|
35
|
+
* with `flexItem` stretches to the row's cross-axis height (via
|
|
36
|
+
* `self-stretch`). Without it, vertical dividers may collapse to
|
|
37
|
+
* 0 height because there's nothing to anchor them.
|
|
38
|
+
*
|
|
39
|
+
* Implementation note: `self-stretch` is already applied on the
|
|
40
|
+
* vertical line segment by default in the TV — this prop is a
|
|
41
|
+
* no-op for now, kept for API parity with MUI's same flag (and as
|
|
42
|
+
* a forward-compatibility hook if we ever change the default).
|
|
43
|
+
*/
|
|
44
|
+
flexItem?: boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Utility classes appended to the variant chain. Resolved via
|
|
48
|
+
* `tailwind-merge`. Useful for one-off margin (`sx="my-8"`) or
|
|
49
|
+
* a custom border weight (`sx="border-t-2"`).
|
|
50
|
+
*/
|
|
51
|
+
sx?: string;
|
|
52
|
+
}
|