@kanso-labs/kanso-ui 0.15.0 → 0.17.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.
- package/README.md +21 -0
- package/dist/components/app-bar/index.d.ts +17 -18
- package/dist/components/app-bar/index.js +2 -2
- package/dist/components/app-bar/index.js.map +1 -1
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/checkbox/index.d.ts +35 -0
- package/dist/components/checkbox/index.js +221 -0
- package/dist/components/checkbox/index.js.map +1 -0
- package/dist/components/checkbox-group/index.d.ts +38 -0
- package/dist/components/checkbox-group/index.js +79 -0
- package/dist/components/checkbox-group/index.js.map +1 -0
- package/dist/components/code/index.js.map +1 -1
- package/dist/components/container/index.js +1 -1
- package/dist/components/container/index.js.map +1 -1
- package/dist/components/copy-field/index.js.map +1 -1
- package/dist/components/currency/index.js.map +1 -1
- package/dist/components/feed/index.d.ts +8 -7
- package/dist/components/feed/index.js +1 -1
- package/dist/components/feed/index.js.map +1 -1
- package/dist/components/form/index.d.ts +31 -0
- package/dist/components/form/index.js +27 -0
- package/dist/components/form/index.js.map +1 -0
- package/dist/components/icon-button/index.js +7 -5
- package/dist/components/icon-button/index.js.map +1 -1
- package/dist/components/index.d.ts +11 -2
- package/dist/components/keycap/index.js.map +1 -1
- package/dist/components/list-detail/index.d.ts +4 -4
- package/dist/components/list-detail/index.js +4 -4
- package/dist/components/list-detail/index.js.map +1 -1
- package/dist/components/number-field/index.d.ts +75 -0
- package/dist/components/number-field/index.js +158 -0
- package/dist/components/number-field/index.js.map +1 -0
- package/dist/components/popover/index.js +10 -8
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/product-icon/index.js.map +1 -1
- package/dist/components/radio-group/index.d.ts +57 -0
- package/dist/components/radio-group/index.js +205 -0
- package/dist/components/radio-group/index.js.map +1 -0
- package/dist/components/search-field/index.d.ts +44 -0
- package/dist/components/search-field/index.js +64 -0
- package/dist/components/search-field/index.js.map +1 -0
- package/dist/components/sheet/index.d.ts +2 -9
- package/dist/components/sheet/index.js +28 -96
- package/dist/components/sheet/index.js.map +1 -1
- package/dist/components/slider/index.d.ts +36 -0
- package/dist/components/slider/index.js +206 -0
- package/dist/components/slider/index.js.map +1 -0
- package/dist/components/stack/index.d.ts +1 -1
- package/dist/components/stack/index.js.map +1 -1
- package/dist/components/supporting-pane/index.d.ts +9 -6
- package/dist/components/supporting-pane/index.js +4 -4
- package/dist/components/supporting-pane/index.js.map +1 -1
- package/dist/components/switch/index.d.ts +41 -0
- package/dist/components/switch/index.js +347 -0
- package/dist/components/switch/index.js.map +1 -0
- package/dist/components/tabs/index.d.ts +2 -2
- package/dist/components/tabs/index.js +35 -18
- package/dist/components/tabs/index.js.map +1 -1
- package/dist/components/tag/index.d.ts +27 -0
- package/dist/components/{badge → tag}/index.js +3 -3
- package/dist/components/tag/index.js.map +1 -0
- package/dist/components/text-area/index.d.ts +69 -0
- package/dist/components/text-area/index.js +47 -0
- package/dist/components/text-area/index.js.map +1 -0
- package/dist/components/text-field/index.d.ts +51 -2
- package/dist/components/text-field/index.js +22 -6
- package/dist/components/text-field/index.js.map +1 -1
- package/dist/field/index.d.ts +7 -0
- package/dist/field/index.js +470 -115
- package/dist/field/index.js.map +1 -1
- package/dist/field/root.js +29 -6
- package/dist/field/root.js.map +1 -1
- package/dist/glyphs/index.js +113 -0
- package/dist/glyphs/index.js.map +1 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +12 -2
- package/dist/react-aria.d.ts +2 -0
- package/dist/react-aria.js +2 -0
- package/dist/styles.css +766 -18
- package/dist/tokens/design.tokens.stylex.js +16 -0
- package/dist/tokens/design.tokens.stylex.js.map +1 -0
- package/package.json +5 -4
- package/dist/components/badge/index.d.ts +0 -27
- package/dist/components/badge/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -50,6 +50,27 @@ StyleX compiles the library's own rules into a CSS `@layer`, and your app's
|
|
|
50
50
|
stylesheet is unlayered, so your rules win the cascade wherever the two meet —
|
|
51
51
|
no specificity contest, and no `!important`.
|
|
52
52
|
|
|
53
|
+
### React Aria utilities
|
|
54
|
+
|
|
55
|
+
The components are built on
|
|
56
|
+
[React Aria Components](https://react-aria.adobe.com), and the utilities an app
|
|
57
|
+
needs around them come from this package too: `I18nProvider` and
|
|
58
|
+
`RouterProvider`, `Collection`, `VisuallyHidden`, `Focusable` and `Pressable`,
|
|
59
|
+
`Virtualizer` with its layouts, the `useFilter`, `useListData`, `useTreeData`
|
|
60
|
+
and `useAsyncList` hooks, `useDragAndDrop` with `useDrag`, `useDrop` and the
|
|
61
|
+
drop item guards, `useLocale`, `parseColor` and `getColorChannels`, and the
|
|
62
|
+
`Key`, `Selection`, `SortDescriptor` and `PressEvent` types.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { I18nProvider, useListData } from '@kanso-labs/kanso-ui'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Do not install `react-aria-components` alongside this package.** A second copy
|
|
69
|
+
of the library carries a second set of contexts, and the two never meet: a
|
|
70
|
+
`Button` placed inside a `Sheet` from this package opens nothing when the
|
|
71
|
+
trigger context it looks for belongs to your copy. Everything above is the same
|
|
72
|
+
object the components use, which is what keeps them talking to each other.
|
|
73
|
+
|
|
53
74
|
### Layout
|
|
54
75
|
|
|
55
76
|
`Container` centres content at a measure, and `Stack` puts one gap from the
|
|
@@ -3,16 +3,16 @@ import { ReactNode } from "react";
|
|
|
3
3
|
//#region src/components/app-bar/index.d.ts
|
|
4
4
|
type AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {
|
|
5
5
|
/**
|
|
6
|
-
* Which of
|
|
7
|
-
* that replaced the old center-aligned variant.
|
|
6
|
+
* Which of Material Design's alignments the text takes. `center` is the
|
|
7
|
+
* configuration that replaced the old center-aligned variant.
|
|
8
8
|
* @default 'start'
|
|
9
9
|
*/
|
|
10
10
|
align?: 'center' | 'start';
|
|
11
11
|
/**
|
|
12
12
|
* Collapses a flexible bar to the height and headline of the small one, for
|
|
13
|
-
* a pinned bar over content that has been scrolled.
|
|
14
|
-
* flexible sizes, and without it a pinned `large` costs
|
|
15
|
-
* viewport for as long as the page is open.
|
|
13
|
+
* a pinned bar over content that has been scrolled. Material Design
|
|
14
|
+
* specifies it for the flexible sizes, and without it a pinned `large` costs
|
|
15
|
+
* 152px of the viewport for as long as the page is open.
|
|
16
16
|
*
|
|
17
17
|
* Controlled, and for the same reason `scrolled` is: only the app knows
|
|
18
18
|
* which element scrolls, and how far into it the bar should have finished
|
|
@@ -42,12 +42,12 @@ type AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {
|
|
|
42
42
|
/**
|
|
43
43
|
* Where the bar's content starts, measured to the headline. A leading slot
|
|
44
44
|
* sits 12px before that, which is the room an icon button's own padding
|
|
45
|
-
* fills around its glyph —
|
|
46
|
-
* icon and one without start their text in the same place.
|
|
45
|
+
* fills around its glyph — Material Design's arrangement, and what makes a
|
|
46
|
+
* bar with an icon and one without start their text in the same place.
|
|
47
47
|
*
|
|
48
|
-
* The default is
|
|
49
|
-
* margin it gives body content, so a bar and the page beneath line
|
|
50
|
-
* without either being told about the other. Set it to the page's gutter
|
|
48
|
+
* The default is Material Design's own margin for a top app bar, which is
|
|
49
|
+
* also the margin it gives body content, so a bar and the page beneath line
|
|
50
|
+
* up without either being told about the other. Set it to the page's gutter
|
|
51
51
|
* where that differs.
|
|
52
52
|
* @default '16px'
|
|
53
53
|
*/
|
|
@@ -67,9 +67,9 @@ type AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {
|
|
|
67
67
|
/** Usually a back or menu icon button. Sits before the text. */
|
|
68
68
|
leading?: ReactNode;
|
|
69
69
|
/**
|
|
70
|
-
* Whether the content beneath has been scrolled.
|
|
71
|
-
* scrolled content with a fill colour rather than a shadow, and
|
|
72
|
-
* applies it.
|
|
70
|
+
* Whether the content beneath has been scrolled. Material Design separates
|
|
71
|
+
* a bar from scrolled content with a fill colour rather than a shadow, and
|
|
72
|
+
* this is what applies it.
|
|
73
73
|
*
|
|
74
74
|
* Controlled, with no listener of its own: only the app knows which element
|
|
75
75
|
* scrolls, and a bar that watched the window would be wrong inside every
|
|
@@ -78,9 +78,8 @@ type AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {
|
|
|
78
78
|
*/
|
|
79
79
|
scrolled?: boolean;
|
|
80
80
|
/**
|
|
81
|
-
* Height and headline size. `medium` and `large` are
|
|
82
|
-
* flexible bars, which hug their text
|
|
83
|
-
* are no longer recommended and are not offered.
|
|
81
|
+
* Height and headline size. `medium` and `large` are Material Design's
|
|
82
|
+
* flexible bars, which hug their text.
|
|
84
83
|
* @default 'small'
|
|
85
84
|
*/
|
|
86
85
|
size?: 'large' | 'medium' | 'small';
|
|
@@ -90,8 +89,8 @@ type AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {
|
|
|
90
89
|
trailing?: ReactNode;
|
|
91
90
|
};
|
|
92
91
|
/**
|
|
93
|
-
* Material
|
|
94
|
-
* one or two actions, and the way back out.
|
|
92
|
+
* Material Design's app bar: the container at the top of a page carrying its
|
|
93
|
+
* title, one or two actions, and the way back out.
|
|
95
94
|
*
|
|
96
95
|
* Three sizes. `small` is a fixed 64px bar for a page whose title is a label;
|
|
97
96
|
* `medium` and `large` are the flexible bars, which give the headline a larger
|
|
@@ -69,8 +69,8 @@ const rowStyles = { root: (contentInset, maxInlineSize) => [_temp2, {
|
|
|
69
69
|
"--x-paddingInline": ((val) => typeof val === "number" ? val + "px" : val != null ? val : void 0)(`calc(${contentInset} - ${HEADLINE_OFFSET})`)
|
|
70
70
|
}] };
|
|
71
71
|
/**
|
|
72
|
-
* Material
|
|
73
|
-
* one or two actions, and the way back out.
|
|
72
|
+
* Material Design's app bar: the container at the top of a page carrying its
|
|
73
|
+
* title, one or two actions, and the way back out.
|
|
74
74
|
*
|
|
75
75
|
* Three sizes. `small` is a fixed 64px bar for a page whose title is a label;
|
|
76
76
|
* `medium` and `large` are the flexible bars, which give the headline a larger
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/app-bar/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport type { RenderComponentProps } from '../../render/useRender';\nimport { useRender } from '../../render/useRender';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, spacing } from '../../tokens/design.tokens.stylex';\nimport Text from '../text';\n\n// Material 3's app bar, in the three sizes M3 Expressive recommends.\n//\n// The spec offers four variants. `search` is absent because it opens M3's\n// search view when selected, and that is a component in its own right that\n// this library does not have — half of a search bar would be worse than none.\n// The other three are here.\n//\n// `medium` and `large` are M3 Expressive's *flexible* bars. The baseline\n// medium and large ones they replaced are marked \"not recommended\" in the\n// spec, so there is no ambiguity to protect against and the shorter names are\n// the ones worth having at a call site.\n//\n// M3 also merged the old center-aligned variant into small as a configuration\n// rather than a variant, which is why alignment is a prop here and applies to\n// every size.\n//\n// Heights are M3's, and they are minimums rather than fixed. The spec says the\n// flexible bars \"hug the text contents\", and Expressive added multi-line\n// support and text wrapping, so a headline long enough to wrap has to be able\n// to make its bar taller. Fixing the height would truncate exactly the case\n// the variant was redesigned for.\n\n// How far the headline sits inside whatever comes before it, and the figure\n// an icon button's glyph is inset from the edge of its own touch target. M3\n// leans on the two agreeing, which is what makes a bar with a leading icon\n// and one without start their text in the same place.\nconst HEADLINE_OFFSET = '12px';\n\n// Where the bar's visible content starts by default, which is M3's own\n// margin for a top app bar and the same margin its body content takes.\nconst DEFAULT_CONTENT_INSET = '16px';\nconst HEIGHTS = {\n large: {\n plain: '120px',\n withSubtitle: '152px'\n },\n medium: {\n plain: '112px',\n withSubtitle: '136px'\n },\n small: {\n plain: '64px',\n withSubtitle: '64px'\n }\n} as const;\n\n// What a flexible bar collapses to, which is the small bar exactly. M3 does\n// not describe the collapsed large bar as a state of its own — it describes it\n// as becoming the small bar, which is why this reads off the same table rather\n// than being a fourth height.\nconst COLLAPSED_HEIGHT = HEIGHTS.small.plain;\nconst styles = {\n root: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"x14s9m32\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kjj79g: \"xl56j7k\",\n kIyJzY: \"xioksi3\",\n k1ekBW: \"x8u3r54\",\n kAMwcw: \"x1seskgd\",\n $$css: true\n },\n row: {\n kGNEyG: \"x6s0dn4\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kOIVth: \"xzoy561\",\n kzqmXN: \"xh8yej3\",\n kUOVxO: \"xvueqy4\",\n $$css: true\n },\n scrolled: {\n kWkggS: \"x1mjdul6\",\n $$css: true\n }\n};\n\n// One entry per size, and each names a type role rather than a figure. M3's\n// own tokens are `md.comp.app-bar.<size>.title.font`, aliases onto the type\n// scale rather than sizes of their own, so this maps to the scale the same\n// way and lets Text apply it.\nconst HEADLINE_VARIANT = {\n large: 'headlineMedium',\n medium: 'headlineSmall',\n small: 'titleLarge'\n} as const;\n\n// The headline is the page's title in M3's model, so it is the page's <h1>.\n// A bar nested somewhere that already has one can pass its own heading as\n// `headline` instead.\n// oxlint-disable-next-line jsx-a11y/heading-has-content -- filled by useRender\nconst HEADING_1 = <h1 />;\nconst PARAGRAPH = <p />;\n\n// Height is the one value the call site does not choose, and it depends on two\n// props at once, so it is a function style rather than one key per\n// combination. StyleX writes it to a custom property inline, the same\n// mechanism Feed uses for its cell minimum.\nconst _temp = {\n kAzted: \"x1chvrdh\",\n \"$$css\": true\n};\nconst heightStyles = {\n root: (minBlockSize: string) => [_temp, {\n \"--x-minBlockSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(minBlockSize)\n }]\n};\n\n// The row's measure and inset both come from the call site, so both are\n// function styles too. The inset is where the bar's visible content starts,\n// and the row carries `contentInset` minus the offset the text block already\n// holds — which is what keeps a leading icon's glyph and a headline with no\n// icon before it starting in the same place.\nconst _temp2 = {\n ks0D6T: \"x13i5qev\",\n kg3NbH: \"x30g6up\",\n \"$$css\": true\n};\nconst rowStyles = {\n root: (contentInset: string, maxInlineSize: string) => [_temp2, {\n \"--x-maxInlineSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(maxInlineSize),\n \"--x-paddingInline\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(`calc(${contentInset} - ${HEADLINE_OFFSET})`)\n }]\n};\ntype AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {\n /**\n * Which of M3's alignments the text takes. `center` is the configuration\n * that replaced the old center-aligned variant.\n * @default 'start'\n */\n align?: 'center' | 'start';\n /**\n * Collapses a flexible bar to the height and headline of the small one, for\n * a pinned bar over content that has been scrolled. M3 specifies it for the\n * flexible sizes, and without it a pinned `large` costs 152px of the\n * viewport for as long as the page is open.\n *\n * Controlled, and for the same reason `scrolled` is: only the app knows\n * which element scrolls, and how far into it the bar should have finished\n * collapsing. Usually set from the same handler.\n *\n * Ignored on `small`, which is already the height this collapses to. The\n * subtitle goes with the height, since there is no room for a second line\n * in the small bar.\n *\n * **The scroll container needs `overflow-anchor: none`.** Collapsing hands\n * the page back the height the bar gives up, and browsers answer a change\n * in height above the viewport by moving the scroll offset by exactly that\n * amount, so the content underneath stays where it was. That offset is\n * what the call site derived `collapsed` from, so it lands back under the\n * threshold, the bar expands, the offset is restored, and the two take\n * turns for as long as the reader stays in that band. Turning anchoring off\n * is what breaks the loop, and it is also the movement you want: the\n * content follows the bar's bottom edge up rather than standing still while\n * the bar shrinks behind it.\n *\n * No threshold avoids this on its own. The unstable band is as tall as the\n * height the bar gives back and it sits directly above wherever the\n * threshold is put, so moving the threshold moves the band with it.\n * @default false\n */\n collapsed?: boolean;\n /**\n * Where the bar's content starts, measured to the headline. A leading slot\n * sits 12px before that, which is the room an icon button's own padding\n * fills around its glyph — M3's arrangement, and what makes a bar with an\n * icon and one without start their text in the same place.\n *\n * The default is M3's own margin for a top app bar, which is also the\n * margin it gives body content, so a bar and the page beneath line up\n * without either being told about the other. Set it to the page's gutter\n * where that differs.\n * @default '16px'\n */\n contentInset?: string;\n /**\n * How wide the bar's contents may run before they stop growing, with the\n * row centred in whatever is left. The bar's own surface still paints edge\n * to edge.\n *\n * This is what lines a full-bleed bar up with a page whose content sits in\n * a measure: give it the page's measure, and `contentInset` the page's\n * gutter. Unset, the row is as wide as the bar.\n */\n contentMaxInlineSize?: string;\n /** The page's title. Wraps rather than truncating, and grows the bar with it. */\n headline?: ReactNode;\n /** Usually a back or menu icon button. Sits before the text. */\n leading?: ReactNode;\n /**\n * Whether the content beneath has been scrolled. M3 separates a bar from\n * scrolled content with a fill colour rather than a shadow, and this is what\n * applies it.\n *\n * Controlled, with no listener of its own: only the app knows which element\n * scrolls, and a bar that watched the window would be wrong inside every\n * pane and dialog that scrolls independently.\n * @default false\n */\n scrolled?: boolean;\n /**\n * Height and headline size. `medium` and `large` are M3 Expressive's\n * flexible bars, which hug their text — the baseline variants they replaced\n * are no longer recommended and are not offered.\n * @default 'small'\n */\n size?: 'large' | 'medium' | 'small';\n /** A second line under the headline. Makes `medium` and `large` taller. */\n subtitle?: ReactNode;\n /** Actions, at the far end. Usually icon buttons. */\n trailing?: ReactNode;\n};\n\n/**\n * Material 3's app bar: the container at the top of a page carrying its title,\n * one or two actions, and the way back out.\n *\n * Three sizes. `small` is a fixed 64px bar for a page whose title is a label;\n * `medium` and `large` are the flexible bars, which give the headline a larger\n * type role and grow to fit a subtitle or a headline that wraps.\n *\n * It paints its own surface, unlike the layout components, because separating\n * itself from the content beneath is the job — which is also why `scrolled`\n * and `collapsed` exist. Neither watches the page: only the app knows which\n * element scrolls, so both are set from its own scroll handler.\n */\nfunction AppBar({\n align = 'start',\n collapsed = false,\n contentInset = DEFAULT_CONTENT_INSET,\n contentMaxInlineSize = 'none',\n headline,\n leading,\n render,\n scrolled = false,\n size = 'small',\n subtitle,\n trailing,\n ...props\n}: AppBarProps) {\n // `small` is already what the flexible bars collapse to, so collapsing it is\n // a no-op rather than an error. A bar whose size is chosen at the call site\n // from a breakpoint would otherwise have to guard the prop as well.\n const collapse = collapsed && size !== 'small';\n const expandedHeight = subtitle === undefined || subtitle === null ? HEIGHTS[size].plain : HEIGHTS[size].withSubtitle;\n const height = collapse ? COLLAPSED_HEIGHT : expandedHeight;\n return useRender({\n defaultTagName: 'header',\n props: {\n ...props,\n children: <div {...stylex.props(styles.row, rowStyles.root(contentInset, contentMaxInlineSize))}>\n {leading === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{leading}</div>}\n <div {...{\n 0: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll xaope02\"\n },\n 1: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll xaope02 x2b8uid\"\n }\n }[!!(align === 'center') << 0]}>\n {headline === undefined ? null : <Text className=\"xioksi3 x1nxaspg x1seskgd\" render={HEADING_1} variant={collapse ? HEADLINE_VARIANT.small : HEADLINE_VARIANT[size]}>\n {headline}\n </Text>}\n {subtitle === undefined || collapse ? null : <Text render={PARAGRAPH} tone=\"muted\" variant=\"bodyMedium\">\n {subtitle}\n </Text>}\n </div>\n {trailing === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{trailing}</div>}\n </div>,\n ...mergeStyles(stylex.props(styles.root, heightStyles.root(height), scrolled && styles.scrolled), props)\n },\n render\n });\n}\nexport type { AppBarProps };\nexport default AppBar;"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/app-bar/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport type { RenderComponentProps } from '../../render/useRender';\nimport { useRender } from '../../render/useRender';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, spacing } from '../../tokens/design.tokens.stylex';\nimport Text from '../text';\n\n// Material Design's app bar, in the three sizes the spec recommends.\n//\n// `medium` and `large` are Material Design's *flexible* bars, the newer of the\n// two sets the spec gives and the one it recommends, which is why the short\n// names are theirs.\n//\n// Material Design also merged the old center-aligned variant into small as a\n// configuration rather than a variant, which is why alignment is a prop here\n// and applies to every size.\n//\n// Heights are Material Design's, and they are minimums rather than fixed. The\n// spec says the flexible bars \"hug the text contents\" and gives them multi-line\n// support and text wrapping, so a headline long enough to wrap has to be able\n// to make its bar taller. Fixing the height would truncate exactly the case\n// the variant was redesigned for.\n\n// How far the headline sits inside whatever comes before it, and the figure\n// an icon button's glyph is inset from the edge of its own touch target.\n// Material Design leans on the two agreeing, which is what makes a bar with a\n// leading icon and one without start their text in the same place.\nconst HEADLINE_OFFSET = '12px';\n\n// Where the bar's visible content starts by default, which is Material\n// Design's own margin for a top app bar and the same margin its body content\n// takes.\nconst DEFAULT_CONTENT_INSET = '16px';\nconst HEIGHTS = {\n large: {\n plain: '120px',\n withSubtitle: '152px'\n },\n medium: {\n plain: '112px',\n withSubtitle: '136px'\n },\n small: {\n plain: '64px',\n withSubtitle: '64px'\n }\n} as const;\n\n// What a flexible bar collapses to, which is the small bar exactly. Material\n// Design does not describe the collapsed large bar as a state of its own — it\n// describes it as becoming the small bar, which is why this reads off the same\n// table rather than being a fourth height.\nconst COLLAPSED_HEIGHT = HEIGHTS.small.plain;\nconst styles = {\n root: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"x14s9m32\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kjj79g: \"xl56j7k\",\n kIyJzY: \"xioksi3\",\n k1ekBW: \"x8u3r54\",\n kAMwcw: \"x1seskgd\",\n $$css: true\n },\n row: {\n kGNEyG: \"x6s0dn4\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kOIVth: \"xzoy561\",\n kzqmXN: \"xh8yej3\",\n kUOVxO: \"xvueqy4\",\n $$css: true\n },\n scrolled: {\n kWkggS: \"x1mjdul6\",\n $$css: true\n }\n};\n\n// One entry per size, and each names a type role rather than a figure.\n// Material Design's own tokens are `md.comp.app-bar.<size>.title.font`,\n// aliases onto the type scale rather than sizes of their own, so this maps to\n// the scale the same way and lets Text apply it.\nconst HEADLINE_VARIANT = {\n large: 'headlineMedium',\n medium: 'headlineSmall',\n small: 'titleLarge'\n} as const;\n\n// The headline is the page's title in Material Design's model, so it is the\n// page's <h1>. A bar nested somewhere that already has one can pass its own\n// heading as `headline` instead.\n// oxlint-disable-next-line jsx-a11y/heading-has-content -- filled by useRender\nconst HEADING_1 = <h1 />;\nconst PARAGRAPH = <p />;\n\n// Height is the one value the call site does not choose, and it depends on two\n// props at once, so it is a function style rather than one key per\n// combination. StyleX writes it to a custom property inline, the same\n// mechanism Feed uses for its cell minimum.\nconst _temp = {\n kAzted: \"x1chvrdh\",\n \"$$css\": true\n};\nconst heightStyles = {\n root: (minBlockSize: string) => [_temp, {\n \"--x-minBlockSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(minBlockSize)\n }]\n};\n\n// The row's measure and inset both come from the call site, so both are\n// function styles too. The inset is where the bar's visible content starts,\n// and the row carries `contentInset` minus the offset the text block already\n// holds — which is what keeps a leading icon's glyph and a headline with no\n// icon before it starting in the same place.\nconst _temp2 = {\n ks0D6T: \"x13i5qev\",\n kg3NbH: \"x30g6up\",\n \"$$css\": true\n};\nconst rowStyles = {\n root: (contentInset: string, maxInlineSize: string) => [_temp2, {\n \"--x-maxInlineSize\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(maxInlineSize),\n \"--x-paddingInline\": (val => typeof val === \"number\" ? val + \"px\" : val != null ? val : undefined)(`calc(${contentInset} - ${HEADLINE_OFFSET})`)\n }]\n};\ntype AppBarProps = Omit<RenderComponentProps<'header'>, 'children'> & {\n /**\n * Which of Material Design's alignments the text takes. `center` is the\n * configuration that replaced the old center-aligned variant.\n * @default 'start'\n */\n align?: 'center' | 'start';\n /**\n * Collapses a flexible bar to the height and headline of the small one, for\n * a pinned bar over content that has been scrolled. Material Design\n * specifies it for the flexible sizes, and without it a pinned `large` costs\n * 152px of the viewport for as long as the page is open.\n *\n * Controlled, and for the same reason `scrolled` is: only the app knows\n * which element scrolls, and how far into it the bar should have finished\n * collapsing. Usually set from the same handler.\n *\n * Ignored on `small`, which is already the height this collapses to. The\n * subtitle goes with the height, since there is no room for a second line\n * in the small bar.\n *\n * **The scroll container needs `overflow-anchor: none`.** Collapsing hands\n * the page back the height the bar gives up, and browsers answer a change\n * in height above the viewport by moving the scroll offset by exactly that\n * amount, so the content underneath stays where it was. That offset is\n * what the call site derived `collapsed` from, so it lands back under the\n * threshold, the bar expands, the offset is restored, and the two take\n * turns for as long as the reader stays in that band. Turning anchoring off\n * is what breaks the loop, and it is also the movement you want: the\n * content follows the bar's bottom edge up rather than standing still while\n * the bar shrinks behind it.\n *\n * No threshold avoids this on its own. The unstable band is as tall as the\n * height the bar gives back and it sits directly above wherever the\n * threshold is put, so moving the threshold moves the band with it.\n * @default false\n */\n collapsed?: boolean;\n /**\n * Where the bar's content starts, measured to the headline. A leading slot\n * sits 12px before that, which is the room an icon button's own padding\n * fills around its glyph — Material Design's arrangement, and what makes a\n * bar with an icon and one without start their text in the same place.\n *\n * The default is Material Design's own margin for a top app bar, which is\n * also the margin it gives body content, so a bar and the page beneath line\n * up without either being told about the other. Set it to the page's gutter\n * where that differs.\n * @default '16px'\n */\n contentInset?: string;\n /**\n * How wide the bar's contents may run before they stop growing, with the\n * row centred in whatever is left. The bar's own surface still paints edge\n * to edge.\n *\n * This is what lines a full-bleed bar up with a page whose content sits in\n * a measure: give it the page's measure, and `contentInset` the page's\n * gutter. Unset, the row is as wide as the bar.\n */\n contentMaxInlineSize?: string;\n /** The page's title. Wraps rather than truncating, and grows the bar with it. */\n headline?: ReactNode;\n /** Usually a back or menu icon button. Sits before the text. */\n leading?: ReactNode;\n /**\n * Whether the content beneath has been scrolled. Material Design separates\n * a bar from scrolled content with a fill colour rather than a shadow, and\n * this is what applies it.\n *\n * Controlled, with no listener of its own: only the app knows which element\n * scrolls, and a bar that watched the window would be wrong inside every\n * pane and dialog that scrolls independently.\n * @default false\n */\n scrolled?: boolean;\n /**\n * Height and headline size. `medium` and `large` are Material Design's\n * flexible bars, which hug their text.\n * @default 'small'\n */\n size?: 'large' | 'medium' | 'small';\n /** A second line under the headline. Makes `medium` and `large` taller. */\n subtitle?: ReactNode;\n /** Actions, at the far end. Usually icon buttons. */\n trailing?: ReactNode;\n};\n\n/**\n * Material Design's app bar: the container at the top of a page carrying its\n * title, one or two actions, and the way back out.\n *\n * Three sizes. `small` is a fixed 64px bar for a page whose title is a label;\n * `medium` and `large` are the flexible bars, which give the headline a larger\n * type role and grow to fit a subtitle or a headline that wraps.\n *\n * It paints its own surface, unlike the layout components, because separating\n * itself from the content beneath is the job — which is also why `scrolled`\n * and `collapsed` exist. Neither watches the page: only the app knows which\n * element scrolls, so both are set from its own scroll handler.\n */\nfunction AppBar({\n align = 'start',\n collapsed = false,\n contentInset = DEFAULT_CONTENT_INSET,\n contentMaxInlineSize = 'none',\n headline,\n leading,\n render,\n scrolled = false,\n size = 'small',\n subtitle,\n trailing,\n ...props\n}: AppBarProps) {\n // `small` is already what the flexible bars collapse to, so collapsing it is\n // a no-op rather than an error. A bar whose size is chosen at the call site\n // from a breakpoint would otherwise have to guard the prop as well.\n const collapse = collapsed && size !== 'small';\n const expandedHeight = subtitle === undefined || subtitle === null ? HEIGHTS[size].plain : HEIGHTS[size].withSubtitle;\n const height = collapse ? COLLAPSED_HEIGHT : expandedHeight;\n return useRender({\n defaultTagName: 'header',\n props: {\n ...props,\n children: <div {...stylex.props(styles.row, rowStyles.root(contentInset, contentMaxInlineSize))}>\n {leading === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{leading}</div>}\n <div {...{\n 0: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll xaope02\"\n },\n 1: {\n className: \"x9f619 x78zum5 xdt5ytf x1iyjqo2 xl56j7k xeuugli x1cmllll xaope02 x2b8uid\"\n }\n }[!!(align === 'center') << 0]}>\n {headline === undefined ? null : <Text className=\"xioksi3 x1nxaspg x1seskgd\" render={HEADING_1} variant={collapse ? HEADLINE_VARIANT.small : HEADLINE_VARIANT[size]}>\n {headline}\n </Text>}\n {subtitle === undefined || collapse ? null : <Text render={PARAGRAPH} tone=\"muted\" variant=\"bodyMedium\">\n {subtitle}\n </Text>}\n </div>\n {trailing === undefined ? null : <div className=\"x6s0dn4 x78zum5 x2lah0s xzoy561\">{trailing}</div>}\n </div>,\n ...mergeStyles(stylex.props(styles.root, heightStyles.root(height), scrolled && styles.scrolled), props)\n },\n render\n });\n}\nexport type { AppBarProps };\nexport default AppBar;"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.tsx"],"sourcesContent":["import type { DOMAttributes, ReactNode } from 'react';\nimport type { ButtonRenderProps, ClassNameOrFunction, FocusableElement, ButtonProps as RACButtonProps, StyleOrFunction } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { Button as RACButton, Link as RACLink } from 'react-aria-components';\nimport { useRipple } from '../../hooks/useRipple';\nimport { ariaAttributesOf, buttonRenderer, linkRenderer } from '../../render/aria';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites its label colour over its container at the\n// interaction state's opacity, rather than swapping in a separate\n// hover/pressed color: filled and tonal paint the 'on-color' over the\n// container, outlined and text paint the label colour over a transparent\n// one. The pairs are the buttons spec page's, Expressive column: tonal on\n// secondary container, outlined with an outline variant border and an\n// on-surface-variant label, text on primary.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values, and a call to an externally-defined function\n// isn't one of them.\n//\n// Disabled is a style of its own per variant rather than a `:disabled`\n// branch inside each property: a button given `href` renders as a link,\n// which React Aria turns into a <span> while disabled, and neither matches\n// the pseudo-class. The disabled styles are applied last from the render\n// state's `isDisabled`, and StyleX replaces a property whole, so they also\n// take the hover and pressed branches with them — which is what keeps a\n// hovered disabled button from lighting up.\n//\n// Two independent axes, applied base -> variant -> size. The order is what\n// lets `text` keep its tighter inline padding at the default size while the\n// other sizes still set their own: `md` deliberately declares no\n// paddingInline, so a medium button falls through to whatever its variant\n// asked for, and every other size overrides it. That mirrors the source\n// design's own cascade, where the size classes are declared after the\n// variant ones and win on padding for exactly the same reason.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kMv6JI: \"xkknnkr\",\n kGuDYH: \"x14zspaw\",\n k63SB2: \"x1v9cpvo\",\n kOIVth: \"x126z3so\",\n kb6lSQ: \"x155f00i\",\n kLWn49: \"x1lz68p4\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n $$css: true\n },\n disabled: {\n kkrTdU: \"x1h6gzvc\",\n $$css: true\n },\n filled: {\n kWkggS: \"xpky1to x16z974x xyf7a0q xnety89\",\n kGVxlE: \"xpk4wdd x1955hzl x1gnnqk1\",\n kMwMTN: \"xwjo7ld\",\n $$css: true\n },\n filledDisabled: {\n kWkggS: \"xepofeg\",\n kGVxlE: \"x1gnnqk1\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kMv6JI: \"x46eyla\",\n kGuDYH: \"x5ehqhr\",\n k63SB2: \"xrf6cl6\",\n kb6lSQ: \"x1g135zh\",\n kLWn49: \"x1ggk5va\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x1dg9itu x1yu1589 x1728qcm xjbqb8w\",\n kVAM5u: \"x133yhug\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n outlinedDisabled: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"xrh88j3\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n text: {\n kWkggS: \"x12vej0r x598nmq x14dcer4 xjbqb8w\",\n kMwMTN: \"x1mxwv8y\",\n $$css: true\n },\n textDisabled: {\n kWkggS: \"xjbqb8w\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n tonal: {\n kWkggS: \"xnqsvhv xc87fxa xlizrex x15dekr4\",\n kGVxlE: \"xpk4wdd x1955hzl x1gnnqk1\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n tonalDisabled: {\n kWkggS: \"xepofeg\",\n kGVxlE: \"x1gnnqk1\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n xl: {\n kZKoxP: \"xjp8j0k\",\n kMv6JI: \"x1fz0g89\",\n kGuDYH: \"xkb6epg\",\n k63SB2: \"x76yrz5\",\n kOIVth: \"x1gka490\",\n kb6lSQ: \"x1s1qhaa\",\n kLWn49: \"x1voeury\",\n kg3NbH: \"x1sdxjpb\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n xxl: {\n kZKoxP: \"xn866dk\",\n kMv6JI: \"x1vsmgmf\",\n kGuDYH: \"xh9c4x\",\n k63SB2: \"x1y15vu6\",\n kOIVth: \"xxj4525\",\n kb6lSQ: \"xoqu3bc\",\n kLWn49: \"x10x9d6x\",\n kg3NbH: \"x1dao9b2\",\n $$css: true\n }\n};\n\n// The outlined button's border thickens with the size, as the page's size\n// tokens have it: 1dp up to M, 2dp at L, 3dp at XL. A style per size rather\n// than a value in the size style, since a border on a filled button would\n// draw in the label colour.\nconst outlineWidths = {\n lg: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n md: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n xl: {\n kMzoRj: \"xdh2fpr\",\n $$css: true\n },\n xs: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n xxl: {\n kMzoRj: \"x9r2w2z\",\n $$css: true\n }\n};\nconst disabledStyles = {\n filled: styles.filledDisabled,\n outlined: styles.outlinedDisabled,\n text: styles.textDisabled,\n tonal: styles.tonalDisabled\n};\ntype ButtonDOMProps = Omit<RACButtonProps, 'children' | 'className' | 'style' | GlobalEventKey> & Pick<DOMAttributes<HTMLElement>, GlobalEventKey>;\ntype ButtonProps = {\n children?: ReactNode;\n /** A function may compute the class from the button's render state. */\n className?: ClassNameOrFunction<ButtonState>;\n /**\n * Disables the press ripple. The hover/pressed background state layer is\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * Where the button leads. Given one, the button is rendered as a link —\n * an `<a>`, announced as the link it is — with the same styles and ripple.\n * `render`, `type`, and the form and pending props apply to the button\n * form only.\n */\n href?: string;\n /** The link's `rel`, when `href` is set. */\n rel?: string;\n /**\n * Control height: `xs` 32px, `md` 40px, `lg` 56px, `xl` 96px, `xxl` 136px —\n * the buttons spec page's XS, S, M, L and XL, each with its own inline\n * padding and type role. `md` is the page's default.\n * @default 'md'\n */\n size?: ButtonSize;\n /** A function may compute the style from the button's render state. */\n style?: StyleOrFunction<ButtonState>;\n /** The link's `target`, when `href` is set. */\n target?: string;\n /** @default 'filled' */\n variant?: ButtonVariant;\n} & ButtonDOMProps;\ntype ButtonSize = 'lg' | 'md' | 'xl' | 'xs' | 'xxl';\n\n// The render state both of React Aria's elements share. A className or\n// style function written against it serves the button and the link alike;\n// `isPending` belongs to the button alone, and `isCurrent` to the link.\ntype ButtonState = Pick<ButtonRenderProps, 'isDisabled' | 'isFocused' | 'isFocusVisible' | 'isHovered' | 'isPressed'>;\ntype ButtonVariant = 'filled' | 'outlined' | 'text' | 'tonal';\n\n// React Aria types the global DOM events — pointer, mouse, touch, wheel and\n// the rest — against the element each component renders, and a handler\n// written for a <button> does not type-check against an <a>. The keys are\n// retyped against HTMLElement here so one set of props serves both forms;\n// the events React Aria defines itself (press, focus, keyboard) keep its\n// types, since it hands those its own event objects.\ntype GlobalEventKey = Exclude<keyof DOMAttributes<HTMLElement> & keyof RACButtonProps, 'onBlur' | 'onClick' | 'onFocus'>;\n\n/**\n * The design's button, at four emphasis levels and five control heights.\n * Given `href` it is a link with the same appearance. Every `aria-*` prop is\n * forwarded to the element; React Aria alone would keep only the labelling\n * ones.\n */\nfunction Button({\n children,\n disableRipple = false,\n href,\n isDisabled = false,\n onClick,\n onContextMenu,\n onKeyDown,\n onKeyUp,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n rel,\n render,\n size = 'md',\n target,\n variant = 'filled',\n ...props\n}: ButtonProps) {\n // `props` (className/style, etc.) is spread separately: `className` and\n // `style` there may be functions of render state, which ripple's own\n // handler-only merge doesn't need to know about. It is also why the styles\n // below merge through mergeStatefulStyles rather than the plain\n // mergeStyles. The ripple is off while disabled: React Aria still forwards\n // pointer events to a disabled element, and a press that changes nothing\n // should not look like one.\n const ripple = useRipple<FocusableElement>(!disableRipple && !isDisabled, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n const styleProps = mergeStatefulStyles((state: ButtonState) => stylex.props(styles.base, styles[variant], styles[size], variant === 'outlined' && outlineWidths[size], state.isDisabled && styles.disabled, state.isDisabled && disabledStyles[variant]), props);\n const element = {\n aria: ariaAttributesOf(props),\n onKeyDown,\n onKeyUp\n };\n if (href !== undefined) {\n return <RACLink href={href} isDisabled={isDisabled} rel={rel} render={linkRenderer(element)} target={target} {...ripple.handlers} {...props} {...styleProps}>\n {children}\n {ripple.surface}\n </RACLink>;\n }\n return <RACButton isDisabled={isDisabled} render={buttonRenderer(element, render)} {...ripple.handlers} {...props} {...styleProps}>\n {children}\n {ripple.surface}\n </RACButton>;\n}\nexport type { ButtonDOMProps, ButtonProps, ButtonSize, ButtonState, ButtonVariant };\nexport default Button;"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/button/index.tsx"],"sourcesContent":["import type { DOMAttributes, ReactNode } from 'react';\nimport type { ButtonRenderProps, ClassNameOrFunction, FocusableElement, ButtonProps as RACButtonProps, StyleOrFunction } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { Button as RACButton, Link as RACLink } from 'react-aria-components';\nimport { useRipple } from '../../hooks/useRipple';\nimport { ariaAttributesOf, buttonRenderer, linkRenderer } from '../../render/aria';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, shadows, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// Each variant composites its label colour over its container at the\n// interaction state's opacity, rather than swapping in a separate\n// hover/pressed color: filled and tonal paint the 'on-color' over the\n// container, outlined and text paint the label colour over a transparent\n// one. The pairs are the buttons spec page's newer values: tonal on\n// secondary container, outlined with an outline variant border and an\n// on-surface-variant label, text on primary.\n// calc(<opacity> * 100%) turns the token's unitless 0-1 ratio into the\n// percentage color-mix() takes. Inlined rather than factored into a helper:\n// @stylexjs/babel-plugin only statically recognizes expressions written\n// directly as property values, and a call to an externally-defined function\n// isn't one of them.\n//\n// Disabled is a style of its own per variant rather than a `:disabled`\n// branch inside each property: a button given `href` renders as a link,\n// which React Aria turns into a <span> while disabled, and neither matches\n// the pseudo-class. The disabled styles are applied last from the render\n// state's `isDisabled`, and StyleX replaces a property whole, so they also\n// take the hover and pressed branches with them — which is what keeps a\n// hovered disabled button from lighting up.\n//\n// Two independent axes, applied base -> variant -> size. The order is what\n// lets `text` keep its tighter inline padding at the default size while the\n// other sizes still set their own: `md` deliberately declares no\n// paddingInline, so a medium button falls through to whatever its variant\n// asked for, and every other size overrides it. That mirrors the source\n// design's own cascade, where the size classes are declared after the\n// variant ones and win on padding for exactly the same reason.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x3y1ksm\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kMv6JI: \"xkknnkr\",\n kGuDYH: \"x14zspaw\",\n k63SB2: \"x1v9cpvo\",\n kOIVth: \"x126z3so\",\n kb6lSQ: \"x155f00i\",\n kLWn49: \"x1lz68p4\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kVAEAm: \"x1n2onr6\",\n kybGjl: \"x1hl2dhg\",\n $$css: true\n },\n disabled: {\n kkrTdU: \"x1h6gzvc\",\n $$css: true\n },\n filled: {\n kWkggS: \"xpky1to x16z974x xyf7a0q xnety89\",\n kGVxlE: \"xpk4wdd x1955hzl x1gnnqk1\",\n kMwMTN: \"xwjo7ld\",\n $$css: true\n },\n filledDisabled: {\n kWkggS: \"xepofeg\",\n kGVxlE: \"x1gnnqk1\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kMv6JI: \"x46eyla\",\n kGuDYH: \"x5ehqhr\",\n k63SB2: \"xrf6cl6\",\n kb6lSQ: \"x1g135zh\",\n kLWn49: \"x1ggk5va\",\n kg3NbH: \"xg0ps1x\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n outlined: {\n kWkggS: \"x1dg9itu x1yu1589 x1728qcm xjbqb8w\",\n kVAM5u: \"x133yhug\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kMwMTN: \"x1w5n3ug\",\n $$css: true\n },\n outlinedDisabled: {\n kWkggS: \"xjbqb8w\",\n kVAM5u: \"xrh88j3\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n text: {\n kWkggS: \"x12vej0r x598nmq x14dcer4 xjbqb8w\",\n kMwMTN: \"x1mxwv8y\",\n $$css: true\n },\n textDisabled: {\n kWkggS: \"xjbqb8w\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n tonal: {\n kWkggS: \"xnqsvhv xc87fxa xlizrex x15dekr4\",\n kGVxlE: \"xpk4wdd x1955hzl x1gnnqk1\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n tonalDisabled: {\n kWkggS: \"xepofeg\",\n kGVxlE: \"x1gnnqk1\",\n kMwMTN: \"x1xj74d8\",\n $$css: true\n },\n xl: {\n kZKoxP: \"xjp8j0k\",\n kMv6JI: \"x1fz0g89\",\n kGuDYH: \"xkb6epg\",\n k63SB2: \"x76yrz5\",\n kOIVth: \"x1gka490\",\n kb6lSQ: \"x1s1qhaa\",\n kLWn49: \"x1voeury\",\n kg3NbH: \"x1sdxjpb\",\n $$css: true\n },\n xs: {\n kZKoxP: \"x10w6t97\",\n kg3NbH: \"x790zyz\",\n $$css: true\n },\n xxl: {\n kZKoxP: \"xn866dk\",\n kMv6JI: \"x1vsmgmf\",\n kGuDYH: \"xh9c4x\",\n k63SB2: \"x1y15vu6\",\n kOIVth: \"xxj4525\",\n kb6lSQ: \"xoqu3bc\",\n kLWn49: \"x10x9d6x\",\n kg3NbH: \"x1dao9b2\",\n $$css: true\n }\n};\n\n// The outlined button's border thickens with the size, as the page's size\n// tokens have it: 1dp up to M, 2dp at L, 3dp at XL. A style per size rather\n// than a value in the size style, since a border on a filled button would\n// draw in the label colour.\nconst outlineWidths = {\n lg: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n md: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n xl: {\n kMzoRj: \"xdh2fpr\",\n $$css: true\n },\n xs: {\n kMzoRj: \"xmkeg23\",\n $$css: true\n },\n xxl: {\n kMzoRj: \"x9r2w2z\",\n $$css: true\n }\n};\nconst disabledStyles = {\n filled: styles.filledDisabled,\n outlined: styles.outlinedDisabled,\n text: styles.textDisabled,\n tonal: styles.tonalDisabled\n};\ntype ButtonDOMProps = Omit<RACButtonProps, 'children' | 'className' | 'style' | GlobalEventKey> & Pick<DOMAttributes<HTMLElement>, GlobalEventKey>;\ntype ButtonProps = {\n children?: ReactNode;\n /** A function may compute the class from the button's render state. */\n className?: ClassNameOrFunction<ButtonState>;\n /**\n * Disables the press ripple. The hover/pressed background state layer is\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * Where the button leads. Given one, the button is rendered as a link —\n * an `<a>`, announced as the link it is — with the same styles and ripple.\n * `render`, `type`, and the form and pending props apply to the button\n * form only.\n */\n href?: string;\n /** The link's `rel`, when `href` is set. */\n rel?: string;\n /**\n * Control height: `xs` 32px, `md` 40px, `lg` 56px, `xl` 96px, `xxl` 136px —\n * the buttons spec page's XS, S, M, L and XL, each with its own inline\n * padding and type role. `md` is the page's default.\n * @default 'md'\n */\n size?: ButtonSize;\n /** A function may compute the style from the button's render state. */\n style?: StyleOrFunction<ButtonState>;\n /** The link's `target`, when `href` is set. */\n target?: string;\n /** @default 'filled' */\n variant?: ButtonVariant;\n} & ButtonDOMProps;\ntype ButtonSize = 'lg' | 'md' | 'xl' | 'xs' | 'xxl';\n\n// The render state both of React Aria's elements share. A className or\n// style function written against it serves the button and the link alike;\n// `isPending` belongs to the button alone, and `isCurrent` to the link.\ntype ButtonState = Pick<ButtonRenderProps, 'isDisabled' | 'isFocused' | 'isFocusVisible' | 'isHovered' | 'isPressed'>;\ntype ButtonVariant = 'filled' | 'outlined' | 'text' | 'tonal';\n\n// React Aria types the global DOM events — pointer, mouse, touch, wheel and\n// the rest — against the element each component renders, and a handler\n// written for a <button> does not type-check against an <a>. The keys are\n// retyped against HTMLElement here so one set of props serves both forms;\n// the events React Aria defines itself (press, focus, keyboard) keep its\n// types, since it hands those its own event objects.\ntype GlobalEventKey = Exclude<keyof DOMAttributes<HTMLElement> & keyof RACButtonProps, 'onBlur' | 'onClick' | 'onFocus'>;\n\n/**\n * The design's button, at four emphasis levels and five control heights.\n * Given `href` it is a link with the same appearance. Every `aria-*` prop is\n * forwarded to the element; React Aria alone would keep only the labelling\n * ones.\n */\nfunction Button({\n children,\n disableRipple = false,\n href,\n isDisabled = false,\n onClick,\n onContextMenu,\n onKeyDown,\n onKeyUp,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp,\n rel,\n render,\n size = 'md',\n target,\n variant = 'filled',\n ...props\n}: ButtonProps) {\n // `props` (className/style, etc.) is spread separately: `className` and\n // `style` there may be functions of render state, which ripple's own\n // handler-only merge doesn't need to know about. It is also why the styles\n // below merge through mergeStatefulStyles rather than the plain\n // mergeStyles. The ripple is off while disabled: React Aria still forwards\n // pointer events to a disabled element, and a press that changes nothing\n // should not look like one.\n const ripple = useRipple<FocusableElement>(!disableRipple && !isDisabled, {\n onClick,\n onContextMenu,\n onPointerCancel,\n onPointerDown,\n onPointerLeave,\n onPointerUp\n });\n const styleProps = mergeStatefulStyles((state: ButtonState) => stylex.props(styles.base, styles[variant], styles[size], variant === 'outlined' && outlineWidths[size], state.isDisabled && styles.disabled, state.isDisabled && disabledStyles[variant]), props);\n const element = {\n aria: ariaAttributesOf(props),\n onKeyDown,\n onKeyUp\n };\n if (href !== undefined) {\n return <RACLink href={href} isDisabled={isDisabled} rel={rel} render={linkRenderer(element)} target={target} {...ripple.handlers} {...props} {...styleProps}>\n {children}\n {ripple.surface}\n </RACLink>;\n }\n return <RACButton isDisabled={isDisabled} render={buttonRenderer(element, render)} {...ripple.handlers} {...props} {...styleProps}>\n {children}\n {ripple.surface}\n </RACButton>;\n}\nexport type { ButtonDOMProps, ButtonProps, ButtonSize, ButtonState, ButtonVariant };\nexport default Button;"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { CheckboxFieldProps } from "react-aria-components";
|
|
3
|
+
//#region src/components/checkbox/index.d.ts
|
|
4
|
+
type CheckboxProps = {
|
|
5
|
+
/**
|
|
6
|
+
* The label, beside the box. A checkbox that a row labels some other way
|
|
7
|
+
* leaves it out and passes `aria-label` instead.
|
|
8
|
+
*/
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* A hint under the label. Replaced by `error` when there is one, so the
|
|
12
|
+
* two never stack.
|
|
13
|
+
*/
|
|
14
|
+
description?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The problem with the current value, in words. Its presence is what puts
|
|
17
|
+
* the checkbox in its error state — the message, the error colours and
|
|
18
|
+
* `aria-invalid` all follow from it.
|
|
19
|
+
*/
|
|
20
|
+
error?: string;
|
|
21
|
+
} & Omit<CheckboxFieldProps, 'children' | 'isInvalid' | 'validationBehavior'>;
|
|
22
|
+
/**
|
|
23
|
+
* A checkbox with its label, and optionally a description or an error under
|
|
24
|
+
* it. Its state is React Aria's: pass `isSelected` with `onChange` to
|
|
25
|
+
* control it, or `defaultSelected` to let it keep its own; `isIndeterminate`
|
|
26
|
+
* draws the dash for a box that stands for a partly selected set. Inside a
|
|
27
|
+
* `CheckboxGroup` it takes its `value` and the group's selection instead.
|
|
28
|
+
*
|
|
29
|
+
* The call site's `className` and `style` land on the field as a whole,
|
|
30
|
+
* which is the element a layout positions.
|
|
31
|
+
*/
|
|
32
|
+
declare function Checkbox({ children, description, error, ...props }: CheckboxProps): import("react").JSX.Element;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { type CheckboxProps, Checkbox as default };
|
|
35
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
|
|
2
|
+
import { mergeStatefulStyles } from "../../styles/merge.js";
|
|
3
|
+
import { useRipple } from "../../hooks/useRipple.js";
|
|
4
|
+
import { FieldMessage } from "../../field/index.js";
|
|
5
|
+
import { invalidFrom, useFieldValidationBehavior } from "../../field/root.js";
|
|
6
|
+
import { CheckGlyph, IndeterminateGlyph } from "../../glyphs/index.js";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { c } from "react/compiler-runtime";
|
|
9
|
+
import { CheckboxButton, CheckboxField } from "react-aria-components";
|
|
10
|
+
//#region src/components/checkbox/index.tsx
|
|
11
|
+
const styles = {
|
|
12
|
+
box: {
|
|
13
|
+
kGNEyG: "x6s0dn4",
|
|
14
|
+
kWkggS: "xjbqb8w",
|
|
15
|
+
kZKoxP: "xmix8c7",
|
|
16
|
+
kVAM5u: "x1is7jjm",
|
|
17
|
+
kaIpWk: "x1cum3z5",
|
|
18
|
+
ksu8eU: "x1y0btm7",
|
|
19
|
+
kMzoRj: "xdh2fpr",
|
|
20
|
+
kB7OPa: "x9f619",
|
|
21
|
+
kMwMTN: "xwjo7ld",
|
|
22
|
+
k1xSpc: "x78zum5",
|
|
23
|
+
kzqmXN: "x1xp8n7a",
|
|
24
|
+
kjj79g: "xl56j7k",
|
|
25
|
+
kIyJzY: "x1qno0dh",
|
|
26
|
+
k1ekBW: "xts7igz",
|
|
27
|
+
kAMwcw: "xpc4ca7",
|
|
28
|
+
$$css: true
|
|
29
|
+
},
|
|
30
|
+
boxMarked: {
|
|
31
|
+
kWkggS: "xnety89",
|
|
32
|
+
kVAM5u: "x9r1u3d",
|
|
33
|
+
$$css: true
|
|
34
|
+
},
|
|
35
|
+
boxMarkedDisabled: {
|
|
36
|
+
kWkggS: "x1crcgwy",
|
|
37
|
+
kVAM5u: "x9r1u3d",
|
|
38
|
+
kMwMTN: "xrpadme",
|
|
39
|
+
$$css: true
|
|
40
|
+
},
|
|
41
|
+
boxMarkedError: {
|
|
42
|
+
kWkggS: "xwi4nbo",
|
|
43
|
+
kVAM5u: "x9r1u3d",
|
|
44
|
+
kMwMTN: "x1l7c2jh",
|
|
45
|
+
$$css: true
|
|
46
|
+
},
|
|
47
|
+
boxUnmarkedActive: {
|
|
48
|
+
kVAM5u: "x1pacwz9",
|
|
49
|
+
$$css: true
|
|
50
|
+
},
|
|
51
|
+
boxUnmarkedDisabled: {
|
|
52
|
+
kVAM5u: "xp1r3on",
|
|
53
|
+
$$css: true
|
|
54
|
+
},
|
|
55
|
+
boxUnmarkedError: {
|
|
56
|
+
kVAM5u: "xx78ee7",
|
|
57
|
+
$$css: true
|
|
58
|
+
},
|
|
59
|
+
control: {
|
|
60
|
+
kGNEyG: "x6s0dn4",
|
|
61
|
+
kWkggS: "xjbqb8w",
|
|
62
|
+
kZKoxP: "x1vqgdyp",
|
|
63
|
+
kaIpWk: "x3y1ksm",
|
|
64
|
+
kB7OPa: "x9f619",
|
|
65
|
+
kMwMTN: "x139gbkf",
|
|
66
|
+
kkrTdU: "x1ypdohk",
|
|
67
|
+
k1xSpc: "x78zum5",
|
|
68
|
+
kmuXW: "x2lah0s",
|
|
69
|
+
kzqmXN: "x100vrsf",
|
|
70
|
+
kjj79g: "xl56j7k",
|
|
71
|
+
kVAEAm: "x1n2onr6",
|
|
72
|
+
kIyJzY: "x1qno0dh",
|
|
73
|
+
k1ekBW: "x15406qy",
|
|
74
|
+
kAMwcw: "xpc4ca7",
|
|
75
|
+
$$css: true
|
|
76
|
+
},
|
|
77
|
+
controlDisabled: {
|
|
78
|
+
kkrTdU: "x1h6gzvc",
|
|
79
|
+
$$css: true
|
|
80
|
+
},
|
|
81
|
+
controlFocused: {
|
|
82
|
+
kjBf7l: "xrgy624",
|
|
83
|
+
kInvED: "x1hl8ikr",
|
|
84
|
+
k3XXqK: "xaatb59",
|
|
85
|
+
kMeerF: "x1de99jn",
|
|
86
|
+
$$css: true
|
|
87
|
+
},
|
|
88
|
+
controlReadOnly: {
|
|
89
|
+
kkrTdU: "xt0e3qv",
|
|
90
|
+
$$css: true
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const hoverLayers = {
|
|
94
|
+
error: {
|
|
95
|
+
kWkggS: "x55e1u4",
|
|
96
|
+
$$css: true
|
|
97
|
+
},
|
|
98
|
+
marked: {
|
|
99
|
+
kWkggS: "x659ado",
|
|
100
|
+
$$css: true
|
|
101
|
+
},
|
|
102
|
+
unmarked: {
|
|
103
|
+
kWkggS: "x1b18xnh",
|
|
104
|
+
$$css: true
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const pressedLayers = {
|
|
108
|
+
error: {
|
|
109
|
+
kWkggS: "x3czxiy",
|
|
110
|
+
$$css: true
|
|
111
|
+
},
|
|
112
|
+
marked: {
|
|
113
|
+
kWkggS: "xjeeohs",
|
|
114
|
+
$$css: true
|
|
115
|
+
},
|
|
116
|
+
unmarked: {
|
|
117
|
+
kWkggS: "x1dvjsmr",
|
|
118
|
+
$$css: true
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
function buttonContent(children, ripple) {
|
|
122
|
+
return (state) => {
|
|
123
|
+
const marked = state.isSelected || state.isIndeterminate;
|
|
124
|
+
const interactive = !state.isDisabled && !state.isReadOnly;
|
|
125
|
+
const tone = state.isInvalid ? "error" : marked ? "marked" : "unmarked";
|
|
126
|
+
const active = state.isHovered || state.isPressed || state.isFocusVisible;
|
|
127
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
|
|
128
|
+
...interactive ? ripple.handlers : {},
|
|
129
|
+
...props(styles.control, state.isReadOnly && styles.controlReadOnly, state.isDisabled && styles.controlDisabled, interactive && state.isHovered && hoverLayers[tone], interactive && state.isPressed && pressedLayers[tone], state.isFocusVisible && styles.controlFocused),
|
|
130
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
131
|
+
...props(styles.box, marked && styles.boxMarked, !marked && state.isInvalid && styles.boxUnmarkedError, !marked && !state.isInvalid && interactive && active && styles.boxUnmarkedActive, marked && state.isInvalid && styles.boxMarkedError, state.isDisabled && (marked ? styles.boxMarkedDisabled : styles.boxUnmarkedDisabled)),
|
|
132
|
+
children: state.isIndeterminate ? /* @__PURE__ */ jsx(IndeterminateGlyph, { className: "xmix8c7 x1lliihq x1xp8n7a" }) : state.isSelected ? /* @__PURE__ */ jsx(CheckGlyph, { className: "xmix8c7 x1lliihq x1xp8n7a" }) : null
|
|
133
|
+
}), interactive ? ripple.surface : null]
|
|
134
|
+
}), children === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
135
|
+
...{
|
|
136
|
+
0: { className: "x9f619 x139gbkf x1ypdohk x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll" },
|
|
137
|
+
2: { className: "x9f619 x139gbkf x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll xt0e3qv" },
|
|
138
|
+
1: { className: "x9f619 x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll x1xj74d8 x1h6gzvc" },
|
|
139
|
+
3: { className: "x9f619 x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll x1xj74d8 x1h6gzvc" }
|
|
140
|
+
}[!!state.isReadOnly << 1 | !!state.isDisabled << 0],
|
|
141
|
+
children
|
|
142
|
+
})] });
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A checkbox with its label, and optionally a description or an error under
|
|
147
|
+
* it. Its state is React Aria's: pass `isSelected` with `onChange` to
|
|
148
|
+
* control it, or `defaultSelected` to let it keep its own; `isIndeterminate`
|
|
149
|
+
* draws the dash for a box that stands for a partly selected set. Inside a
|
|
150
|
+
* `CheckboxGroup` it takes its `value` and the group's selection instead.
|
|
151
|
+
*
|
|
152
|
+
* The call site's `className` and `style` land on the field as a whole,
|
|
153
|
+
* which is the element a layout positions.
|
|
154
|
+
*/
|
|
155
|
+
function Checkbox(t0) {
|
|
156
|
+
const $ = c(18);
|
|
157
|
+
const { children, description, error, ...props } = t0;
|
|
158
|
+
const ripple = useRipple();
|
|
159
|
+
const validationBehavior = useFieldValidationBehavior();
|
|
160
|
+
const T0 = CheckboxField;
|
|
161
|
+
let t1;
|
|
162
|
+
if ($[0] !== error) {
|
|
163
|
+
t1 = invalidFrom(error);
|
|
164
|
+
$[0] = error;
|
|
165
|
+
$[1] = t1;
|
|
166
|
+
} else t1 = $[1];
|
|
167
|
+
const t2 = mergeStatefulStyles({ className: "x7a106z x9f619 xpr5407 xrvj5dj x1pmbctz" }, props);
|
|
168
|
+
let t3;
|
|
169
|
+
if ($[2] !== children || $[3] !== ripple) {
|
|
170
|
+
t3 = buttonContent(children, ripple);
|
|
171
|
+
$[2] = children;
|
|
172
|
+
$[3] = ripple;
|
|
173
|
+
$[4] = t3;
|
|
174
|
+
} else t3 = $[4];
|
|
175
|
+
let t4;
|
|
176
|
+
if ($[5] !== t3) {
|
|
177
|
+
t4 = /* @__PURE__ */ jsx(CheckboxButton, {
|
|
178
|
+
className: "xjp7ctv",
|
|
179
|
+
children: t3
|
|
180
|
+
});
|
|
181
|
+
$[5] = t3;
|
|
182
|
+
$[6] = t4;
|
|
183
|
+
} else t4 = $[6];
|
|
184
|
+
let t5;
|
|
185
|
+
if ($[7] !== description || $[8] !== error) {
|
|
186
|
+
t5 = /* @__PURE__ */ jsx("div", {
|
|
187
|
+
className: "x1xdureb",
|
|
188
|
+
children: /* @__PURE__ */ jsx(FieldMessage, {
|
|
189
|
+
description,
|
|
190
|
+
error,
|
|
191
|
+
inset: false
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
$[7] = description;
|
|
195
|
+
$[8] = error;
|
|
196
|
+
$[9] = t5;
|
|
197
|
+
} else t5 = $[9];
|
|
198
|
+
let t6;
|
|
199
|
+
if ($[10] !== T0 || $[11] !== props || $[12] !== t1 || $[13] !== t2 || $[14] !== t4 || $[15] !== t5 || $[16] !== validationBehavior) {
|
|
200
|
+
t6 = /* @__PURE__ */ jsxs(T0, {
|
|
201
|
+
isInvalid: t1,
|
|
202
|
+
validationBehavior,
|
|
203
|
+
...props,
|
|
204
|
+
...t2,
|
|
205
|
+
children: [t4, t5]
|
|
206
|
+
});
|
|
207
|
+
$[10] = T0;
|
|
208
|
+
$[11] = props;
|
|
209
|
+
$[12] = t1;
|
|
210
|
+
$[13] = t2;
|
|
211
|
+
$[14] = t4;
|
|
212
|
+
$[15] = t5;
|
|
213
|
+
$[16] = validationBehavior;
|
|
214
|
+
$[17] = t6;
|
|
215
|
+
} else t6 = $[17];
|
|
216
|
+
return t6;
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { Checkbox as default };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["description","error","validationBehavior"],"sources":["../../../src/components/checkbox/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { CheckboxButtonRenderProps, CheckboxFieldProps as RACCheckboxFieldProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { CheckboxButton, CheckboxField } from 'react-aria-components';\nimport { FieldMessage } from '../../field';\nimport { invalidFrom, useFieldValidationBehavior } from '../../field/root';\nimport { CheckGlyph, IndeterminateGlyph } from '../../glyphs';\nimport { useRipple } from '../../hooks/useRipple';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// The checkbox page: an 18dp box with a 2dp corner and an 18dp glyph, inside\n// a 40dp state layer, with a 48dp target. Unselected, the box is a 2dp rule\n// in on surface variant that turns on surface while hovered, pressed or\n// focused; selected or indeterminate, it fills with primary and the glyph\n// takes on primary. The error pair is error and on error, and disabled is\n// on surface at the disabled opacity for the rule or the fill, with the\n// glyph in surface. The state layer is on surface over an unselected box and\n// primary over a selected one while hovered, and the two swap once pressed.\n//\n// React Aria's `CheckboxField` is the root, a div holding the description\n// and error slots; its `CheckboxButton` is the label around a visually\n// hidden input, and everything drawn is that label's children, chosen from\n// the render state React Aria hands them. The field is a two-column grid —\n// the control, then the text — and the label is `display: contents`, so the\n// control and the label text each take a column and the description and\n// error line up under the text rather than under the box.\n//\n// The adjacent label is body-large on surface, which the page keeps the same\n// whether or not the box is selected. The corner is a literal: the page's\n// 2dp is a step the shape scale does not carry.\nconst styles = {\n box: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"xjbqb8w\",\n kZKoxP: \"xmix8c7\",\n kVAM5u: \"x1is7jjm\",\n kaIpWk: \"x1cum3z5\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xdh2fpr\",\n kB7OPa: \"x9f619\",\n kMwMTN: \"xwjo7ld\",\n k1xSpc: \"x78zum5\",\n kzqmXN: \"x1xp8n7a\",\n kjj79g: \"xl56j7k\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xts7igz\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n },\n boxMarked: {\n kWkggS: \"xnety89\",\n kVAM5u: \"x9r1u3d\",\n $$css: true\n },\n boxMarkedDisabled: {\n kWkggS: \"x1crcgwy\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"xrpadme\",\n $$css: true\n },\n boxMarkedError: {\n kWkggS: \"xwi4nbo\",\n kVAM5u: \"x9r1u3d\",\n kMwMTN: \"x1l7c2jh\",\n $$css: true\n },\n boxUnmarkedActive: {\n kVAM5u: \"x1pacwz9\",\n $$css: true\n },\n boxUnmarkedDisabled: {\n kVAM5u: \"xp1r3on\",\n $$css: true\n },\n boxUnmarkedError: {\n kVAM5u: \"xx78ee7\",\n $$css: true\n },\n control: {\n kGNEyG: \"x6s0dn4\",\n kWkggS: \"xjbqb8w\",\n kZKoxP: \"x1vqgdyp\",\n kaIpWk: \"x3y1ksm\",\n kB7OPa: \"x9f619\",\n kMwMTN: \"x139gbkf\",\n kkrTdU: \"x1ypdohk\",\n k1xSpc: \"x78zum5\",\n kmuXW: \"x2lah0s\",\n kzqmXN: \"x100vrsf\",\n kjj79g: \"xl56j7k\",\n kVAEAm: \"x1n2onr6\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"x15406qy\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n },\n controlDisabled: {\n kkrTdU: \"x1h6gzvc\",\n $$css: true\n },\n controlFocused: {\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"xaatb59\",\n kMeerF: \"x1de99jn\",\n $$css: true\n },\n controlReadOnly: {\n kkrTdU: \"xt0e3qv\",\n $$css: true\n }\n};\n\n// The state layer's colour follows the box: on surface over an unmarked box\n// and primary over a marked one while hovered, the two swapped once pressed,\n// and error throughout while invalid.\nconst hoverLayers = {\n error: {\n kWkggS: \"x55e1u4\",\n $$css: true\n },\n marked: {\n kWkggS: \"x659ado\",\n $$css: true\n },\n unmarked: {\n kWkggS: \"x1b18xnh\",\n $$css: true\n }\n};\nconst pressedLayers = {\n error: {\n kWkggS: \"x3czxiy\",\n $$css: true\n },\n marked: {\n kWkggS: \"xjeeohs\",\n $$css: true\n },\n unmarked: {\n kWkggS: \"x1dvjsmr\",\n $$css: true\n }\n};\ntype CheckboxProps = {\n /**\n * The label, beside the box. A checkbox that a row labels some other way\n * leaves it out and passes `aria-label` instead.\n */\n children?: ReactNode;\n /**\n * A hint under the label. Replaced by `error` when there is one, so the\n * two never stack.\n */\n description?: string;\n /**\n * The problem with the current value, in words. Its presence is what puts\n * the checkbox in its error state — the message, the error colours and\n * `aria-invalid` all follow from it.\n */\n error?: string;\n} & Omit<RACCheckboxFieldProps, 'children' | 'isInvalid' | 'validationBehavior'>;\ntype Ripple = ReturnType<typeof useRipple<HTMLSpanElement>>;\ntype Tone = 'error' | 'marked' | 'unmarked';\n\n// What the label draws, chosen from the render state React Aria hands it.\n// Built by a call rather than written inline at the prop, which is what\n// react-perf's no-new-function-as-prop is after; the React Compiler memoises\n// the result on its inputs. The ripple's handlers and surface go on the\n// control while the checkbox can change, and are left off while it cannot,\n// since a press that changes nothing should not look like one.\nfunction buttonContent(children: ReactNode, ripple: Ripple) {\n return (state: CheckboxButtonRenderProps) => {\n const marked = state.isSelected || state.isIndeterminate;\n const interactive = !state.isDisabled && !state.isReadOnly;\n const tone: Tone = state.isInvalid ? 'error' : marked ? 'marked' : 'unmarked';\n const active = state.isHovered || state.isPressed || state.isFocusVisible;\n return <>\n <span {...interactive ? ripple.handlers : {}} {...stylex.props(styles.control, state.isReadOnly && styles.controlReadOnly, state.isDisabled && styles.controlDisabled, interactive && state.isHovered && hoverLayers[tone], interactive && state.isPressed && pressedLayers[tone], state.isFocusVisible && styles.controlFocused)}>\n <span {...stylex.props(styles.box, marked && styles.boxMarked, !marked && state.isInvalid && styles.boxUnmarkedError, !marked && !state.isInvalid && interactive && active && styles.boxUnmarkedActive, marked && state.isInvalid && styles.boxMarkedError, state.isDisabled && (marked ? styles.boxMarkedDisabled : styles.boxUnmarkedDisabled))}>\n {state.isIndeterminate ? <IndeterminateGlyph className=\"xmix8c7 x1lliihq x1xp8n7a\" /> : state.isSelected ? <CheckGlyph className=\"xmix8c7 x1lliihq x1xp8n7a\" /> : null}\n </span>\n {interactive ? ripple.surface : null}\n </span>\n {children === undefined ? null : <span {...{\n 0: {\n className: \"x9f619 x139gbkf x1ypdohk x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll\"\n },\n 2: {\n className: \"x9f619 x139gbkf x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll xt0e3qv\"\n },\n 1: {\n className: \"x9f619 x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll x1xj74d8 x1h6gzvc\"\n },\n 3: {\n className: \"x9f619 x16svsjw x1848etk x1c52epr x1qn8t5l xh7dzej x1cmllll x1xj74d8 x1h6gzvc\"\n }\n }[!!state.isReadOnly << 1 | !!state.isDisabled << 0]}>\n {children}\n </span>}\n </>;\n };\n}\n\n/**\n * A checkbox with its label, and optionally a description or an error under\n * it. Its state is React Aria's: pass `isSelected` with `onChange` to\n * control it, or `defaultSelected` to let it keep its own; `isIndeterminate`\n * draws the dash for a box that stands for a partly selected set. Inside a\n * `CheckboxGroup` it takes its `value` and the group's selection instead.\n *\n * The call site's `className` and `style` land on the field as a whole,\n * which is the element a layout positions.\n */\nfunction Checkbox({\n children,\n description,\n error,\n ...props\n}: CheckboxProps) {\n const ripple = useRipple<HTMLSpanElement>();\n const validationBehavior = useFieldValidationBehavior();\n return <CheckboxField isInvalid={invalidFrom(error)} validationBehavior={validationBehavior} {...props} {...mergeStatefulStyles({\n className: \"x7a106z x9f619 xpr5407 xrvj5dj x1pmbctz\"\n }, props)}>\n <CheckboxButton className=\"xjp7ctv\">\n {buttonContent(children, ripple)}\n </CheckboxButton>\n <div className=\"x1xdureb\">\n <FieldMessage description={description} error={error} inset={false} />\n </div>\n </CheckboxField>;\n}\nexport type { CheckboxProps };\nexport default Checkbox;"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { CheckboxGroupProps } from "react-aria-components";
|
|
3
|
+
//#region src/components/checkbox-group/index.d.ts
|
|
4
|
+
type CheckboxGroupProps$1 = {
|
|
5
|
+
/** The checkboxes, each with a `value` of its own. */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
/**
|
|
8
|
+
* A hint under the group. Replaced by `error` when there is one, so the
|
|
9
|
+
* two never stack.
|
|
10
|
+
*/
|
|
11
|
+
description?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The problem with the current selection, in words. Its presence is what
|
|
14
|
+
* puts the group in its error state — the message, the boxes' error
|
|
15
|
+
* colours and `aria-invalid` all follow from it.
|
|
16
|
+
*/
|
|
17
|
+
error?: string;
|
|
18
|
+
/**
|
|
19
|
+
* What the group is for. Required rather than optional: a group of
|
|
20
|
+
* checkboxes with no name is a set of boxes a screen reader cannot
|
|
21
|
+
* introduce.
|
|
22
|
+
*/
|
|
23
|
+
label: string;
|
|
24
|
+
} & Omit<CheckboxGroupProps, 'children' | 'isInvalid' | 'validationBehavior'>;
|
|
25
|
+
/**
|
|
26
|
+
* A labelled set of checkboxes with one value between them. The value is
|
|
27
|
+
* React Aria's: pass `value` with `onChange` to control it, or
|
|
28
|
+
* `defaultValue` to let the group keep its own, and each `Checkbox` inside
|
|
29
|
+
* names the entry it stands for with `value`. Disabled, read-only and the
|
|
30
|
+
* error state reach every checkbox from here.
|
|
31
|
+
*
|
|
32
|
+
* The call site's `className` and `style` land on the group as a whole,
|
|
33
|
+
* which is the element a layout positions.
|
|
34
|
+
*/
|
|
35
|
+
declare function CheckboxGroup$1({ children, description, error, label, ...props }: CheckboxGroupProps$1): import("react").JSX.Element;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { type CheckboxGroupProps$1 as CheckboxGroupProps, CheckboxGroup$1 as default };
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|