@kanso-labs/kanso-ui 0.24.0 → 0.25.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.
@@ -49,12 +49,14 @@ type SegmentedButtonSegmentProps = Omit<ToggleButtonProps, 'children' | 'classNa
49
49
  * Name the set with `aria-label` or `aria-labelledby` — nothing here labels
50
50
  * it for you, and a set with no name is a group a screen reader cannot
51
51
  * announce. What it is announced as follows the selection mode: choosing one
52
- * is a radio group, choosing several a toolbar of two-state buttons.
52
+ * is a radio group, choosing several a toolbar of two-state buttons. So does
53
+ * how the chosen container moves: it slides between segments while one is
54
+ * chosen, and fades in place while several may be.
53
55
  *
54
56
  * The call site's `className` and `style` land on the track, which is the
55
57
  * element a layout positions.
56
58
  */
57
- declare function SegmentedButton({ showSelectedIcon, ...props }: SegmentedButtonProps): import("react").JSX.Element;
59
+ declare function SegmentedButton({ selectionMode, showSelectedIcon, ...props }: SegmentedButtonProps): import("react").JSX.Element;
58
60
  declare namespace SegmentedButton {
59
61
  var Segment: typeof SegmentedButtonSegment;
60
62
  }
@@ -1,72 +1,12 @@
1
- import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
1
  import { mergeStatefulStyles } from "../../styles/merge.js";
3
2
  import { CheckGlyph } from "../../glyphs/index.js";
4
3
  import { useRipple } from "../../hooks/useRipple.js";
5
4
  import { createContext, useContext } from "react";
6
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
- import { ToggleButton, ToggleButtonGroup } from "react-aria-components";
6
+ import { SelectionIndicator, ToggleButton, ToggleButtonGroup } from "react-aria-components";
8
7
  //#region src/components/segmented-button/index.tsx
9
8
  const ShowSelectedIconContext = createContext(true);
10
- const styles = {
11
- segment: {
12
- kGNEyG: "x6s0dn4",
13
- kZKoxP: "x1vqgdyp",
14
- kVAM5u: "x1fwvt7v",
15
- kT0f0o: "x1asv1gf xkducg2",
16
- kVL7Gh: "x15ku28o x1uwupfv",
17
- k2ei4v: "x120dh57 x14e42zd",
18
- kfmiAY: "x12k3b1q x1a37zkv",
19
- krdFHd: "x1f6vc7b xb01x1j",
20
- ksu8eU: "x1y0btm7",
21
- kMzoRj: "xmkeg23",
22
- kB7OPa: "x9f619",
23
- kkrTdU: "x1ypdohk",
24
- k1xSpc: "x3nfvp2",
25
- kMv6JI: "xkknnkr",
26
- kGuDYH: "x14zspaw",
27
- k63SB2: "x1v9cpvo",
28
- kOIVth: "x126z3so",
29
- kjj79g: "xl56j7k",
30
- kb6lSQ: "x155f00i",
31
- kLWn49: "x1lz68p4",
32
- k7Eaqz: "xeuugli",
33
- kjBf7l: "xrgy624",
34
- kInvED: "x1hl8ikr",
35
- k3XXqK: "x9v5kkp x1t137rt",
36
- kMeerF: "x1de99jn",
37
- k8WAf4: "xt970qd",
38
- kg3NbH: "x18fpw6u",
39
- kVAEAm: "x1n2onr6",
40
- kIyJzY: "x1qno0dh",
41
- k1ekBW: "xs2xxs2",
42
- kAMwcw: "xpc4ca7",
43
- $$css: true
44
- },
45
- segmentDisabled: {
46
- kVAM5u: "xrh88j3",
47
- kMwMTN: "x1xj74d8",
48
- kkrTdU: "x1h6gzvc",
49
- $$css: true
50
- },
51
- segmentDisabledSelected: {
52
- kWkggS: "xepofeg",
53
- $$css: true
54
- },
55
- segmentDisabledUnselected: {
56
- kWkggS: "xjbqb8w",
57
- $$css: true
58
- },
59
- segmentSelected: {
60
- kWkggS: "xnqsvhv xc87fxa xlizrex x15dekr4",
61
- kMwMTN: "x1sawysd",
62
- $$css: true
63
- },
64
- segmentUnselected: {
65
- kWkggS: "x83qkoq x10oam47 x1p2om7n xjbqb8w",
66
- kMwMTN: "x139gbkf",
67
- $$css: true
68
- }
69
- };
9
+ const SelectionModeContext = createContext("single");
70
10
  /**
71
11
  * The check on a chosen segment, or the segment's own icon. Returns a node
72
12
  * rather than letting the type be inferred, since `ReactNode` is a union
@@ -83,8 +23,31 @@ function glyphFor(state, icon, showSelectedIcon) {
83
23
  children: icon
84
24
  });
85
25
  }
86
- function segmentContent(children, icon, ripple, showSelectedIcon) {
26
+ function indicatorClassName(isDisabled, selectionMode) {
27
+ return (state) => ({
28
+ 0: { className: "x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd" },
29
+ 4: { className: "x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7" },
30
+ 2: { className: "xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xepofeg" },
31
+ 6: { className: "xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xepofeg" },
32
+ 1: { className: "x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xg01cxk" },
33
+ 5: { className: "x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xg01cxk" },
34
+ 3: { className: "xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xepofeg xg01cxk" },
35
+ 7: { className: "xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xepofeg xg01cxk" }
36
+ })[!!(selectionMode === "multiple") << 2 | !!isDisabled << 1 | !!(state.isEntering || state.isExiting) << 0].className ?? "";
37
+ }
38
+ function segmentContent(children, icon, ripple, selectionMode, showSelectedIcon) {
87
39
  return (state) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
40
+ /* @__PURE__ */ jsx(SelectionIndicator, { className: indicatorClassName(state.isDisabled, selectionMode) }),
41
+ /* @__PURE__ */ jsx("span", { ...{
42
+ 0: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi xg01cxk x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4" },
43
+ 4: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xe2qvxb" },
44
+ 2: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xcl2av" },
45
+ 6: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xcl2av" },
46
+ 1: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g" },
47
+ 5: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g" },
48
+ 3: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g" },
49
+ 7: { className: "xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g" }
50
+ }[!!state.isHovered << 2 | !!state.isFocusVisible << 1 | !!state.isPressed << 0] }),
88
51
  glyphFor(state, icon, showSelectedIcon),
89
52
  /* @__PURE__ */ jsx("span", {
90
53
  className: "xeuugli xb3r6kr xlyipyv xuxw1ft",
@@ -110,17 +73,23 @@ function segmentContent(children, icon, ripple, showSelectedIcon) {
110
73
  * Name the set with `aria-label` or `aria-labelledby` — nothing here labels
111
74
  * it for you, and a set with no name is a group a screen reader cannot
112
75
  * announce. What it is announced as follows the selection mode: choosing one
113
- * is a radio group, choosing several a toolbar of two-state buttons.
76
+ * is a radio group, choosing several a toolbar of two-state buttons. So does
77
+ * how the chosen container moves: it slides between segments while one is
78
+ * chosen, and fades in place while several may be.
114
79
  *
115
80
  * The call site's `className` and `style` land on the track, which is the
116
81
  * element a layout positions.
117
82
  */
118
- function SegmentedButton({ showSelectedIcon = true, ...props }) {
83
+ function SegmentedButton({ selectionMode = "single", showSelectedIcon = true, ...props }) {
119
84
  return /* @__PURE__ */ jsx(ShowSelectedIconContext, {
120
85
  value: showSelectedIcon,
121
- children: /* @__PURE__ */ jsx(ToggleButtonGroup, {
122
- ...props,
123
- ...mergeStatefulStyles({ className: "x9f619 xwz0xwf xu6a5m6 x1mt1orb" }, props)
86
+ children: /* @__PURE__ */ jsx(SelectionModeContext, {
87
+ value: selectionMode,
88
+ children: /* @__PURE__ */ jsx(ToggleButtonGroup, {
89
+ ...props,
90
+ selectionMode,
91
+ ...mergeStatefulStyles({ className: "x9f619 xwz0xwf xu6a5m6 x1mt1orb xc8icb0" }, props)
92
+ })
124
93
  })
125
94
  });
126
95
  }
@@ -130,17 +99,23 @@ function SegmentedButton({ showSelectedIcon = true, ...props }) {
130
99
  * unchosen one draws whatever `icon` holds, if anything.
131
100
  */
132
101
  function SegmentedButtonSegment({ children, disableRipple = false, icon, ...props }) {
102
+ const selectionMode = useContext(SelectionModeContext);
133
103
  const showSelectedIcon = useContext(ShowSelectedIconContext);
134
104
  const ripple = useRipple(!disableRipple && props.isDisabled !== true);
135
105
  return /* @__PURE__ */ jsx(ToggleButton, {
136
106
  ...props,
137
107
  ...ripple.handlers,
138
108
  ...mergeStatefulStyles(segmentStyles, props),
139
- children: segmentContent(children, icon, ripple, showSelectedIcon)
109
+ children: segmentContent(children, icon, ripple, selectionMode, showSelectedIcon)
140
110
  });
141
111
  }
142
112
  function segmentStyles(state) {
143
- return props(styles.segment, state.isSelected ? styles.segmentSelected : styles.segmentUnselected, state.isDisabled && styles.segmentDisabled, state.isDisabled && (state.isSelected ? styles.segmentDisabledSelected : styles.segmentDisabledUnselected));
113
+ return {
114
+ 0: { className: "x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1fwvt7v x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x1ypdohk x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 x139gbkf" },
115
+ 2: { className: "x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1fwvt7v x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x1ypdohk x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 x1sawysd" },
116
+ 1: { className: "x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 xrh88j3 x1xj74d8 x1h6gzvc" },
117
+ 3: { className: "x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 xrh88j3 x1xj74d8 x1h6gzvc" }
118
+ }[!!state.isSelected << 1 | !!state.isDisabled << 0];
144
119
  }
145
120
  SegmentedButton.Segment = SegmentedButtonSegment;
146
121
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/segmented-button/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { FocusableElement, ToggleButtonGroupProps as RACToggleButtonGroupProps, ToggleButtonProps as RACToggleButtonProps, ToggleButtonRenderProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { createContext, useContext } from 'react';\nimport { ToggleButton as RACToggleButton, ToggleButtonGroup as RACToggleButtonGroup } from 'react-aria-components';\nimport { CheckGlyph } 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 segmented buttons page's outlined segmented button: two to five\n// segments joined into one outlined track, of which one or several are\n// chosen. A segment is Button's default size and type role — a 40dp\n// container with a label-large label — which is what that page gives too.\n//\n// What a screen reader hears follows the selection mode, and React Aria\n// decides it rather than this component. Choosing one of the segments is a\n// radio group, so the track is a `radiogroup` and each segment a `radio`\n// reporting `aria-checked`; choosing several is a `toolbar` of buttons each\n// reporting `aria-pressed`. That is the right mapping for both, and it is\n// why the mode is a word on the group rather than two components.\n//\n// Four things are this component's own.\n//\n// **The segments are one track, not a row of buttons.** Every segment\n// carries the page's 1dp outline, and each one after the first drops its\n// leading edge so neighbours share a single rule rather than drawing two\n// against each other. The outer ends are the page's fully rounded shape and\n// the inner joins are square.\n//\n// **Every segment is the same width.** The page gives the segment width as\n// the container's divided by their number, so the track is a grid of equal\n// columns; the container itself is still as wide as its widest label asks.\n//\n// **A chosen segment says so with a check.** The page draws it in the icon\n// slot, so a segment given an `icon` shows the icon while unselected and the\n// check once chosen. `showSelectedIcon` turns it off for a set whose labels\n// already read as chosen or not.\n//\n// **Two of the page's values are the library's instead**, both for\n// consistency with the controls beside them: the focus ring, which is\n// primary at 2dp offset 2dp everywhere here rather than the page's secondary\n// at 3dp, and the press, which is the library's ripple rather than a flat\n// state layer. The page names a ripple as the pressed state, so the second\n// is a departure only in how it is drawn.\n//\n// **The density steps are not drawn.** The page removes 4dp of height per\n// step down, for denser interfaces; nothing else in the library takes a\n// density, and one component that did would be the odd one out. A shorter\n// track is a `className` away.\n//\n// Vertical is React Aria's and is not passed through, since the page draws\n// one row and a column of joined segments is a different shape — the outer\n// corners, the shared rule and the equal columns would all have to mean\n// something else.\n\n// Whether a chosen segment draws the check. A context rather than a prop on\n// each segment, since it is the set's decision and repeating it on every\n// segment is how the two drift.\nconst ShowSelectedIconContext = createContext(true);\ntype Ripple = ReturnType<typeof useRipple<FocusableElement>>;\nconst styles = {\n segment: {\n kGNEyG: \"x6s0dn4\",\n kZKoxP: \"x1vqgdyp\",\n kVAM5u: \"x1fwvt7v\",\n kT0f0o: \"x1asv1gf xkducg2\",\n kVL7Gh: \"x15ku28o x1uwupfv\",\n k2ei4v: \"x120dh57 x14e42zd\",\n kfmiAY: \"x12k3b1q x1a37zkv\",\n krdFHd: \"x1f6vc7b xb01x1j\",\n ksu8eU: \"x1y0btm7\",\n kMzoRj: \"xmkeg23\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n k1xSpc: \"x3nfvp2\",\n kMv6JI: \"xkknnkr\",\n kGuDYH: \"x14zspaw\",\n k63SB2: \"x1v9cpvo\",\n kOIVth: \"x126z3so\",\n kjj79g: \"xl56j7k\",\n kb6lSQ: \"x155f00i\",\n kLWn49: \"x1lz68p4\",\n k7Eaqz: \"xeuugli\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n k8WAf4: \"xt970qd\",\n kg3NbH: \"x18fpw6u\",\n kVAEAm: \"x1n2onr6\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xs2xxs2\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n },\n segmentDisabled: {\n kVAM5u: \"xrh88j3\",\n kMwMTN: \"x1xj74d8\",\n kkrTdU: \"x1h6gzvc\",\n $$css: true\n },\n segmentDisabledSelected: {\n kWkggS: \"xepofeg\",\n $$css: true\n },\n segmentDisabledUnselected: {\n kWkggS: \"xjbqb8w\",\n $$css: true\n },\n segmentSelected: {\n kWkggS: \"xnqsvhv xc87fxa xlizrex x15dekr4\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n segmentUnselected: {\n kWkggS: \"x83qkoq x10oam47 x1p2om7n xjbqb8w\",\n kMwMTN: \"x139gbkf\",\n $$css: true\n }\n};\ntype SegmentedButtonProps = Omit<RACToggleButtonGroupProps, 'className' | 'orientation' | 'style'> & {\n /** A function may compute the class from the set's render state. */\n className?: RACToggleButtonGroupProps['className'];\n /**\n * Whether a chosen segment draws a check before its label, as the page\n * has it. `false` leaves the segment's own icon in place while selected.\n * @default true\n */\n showSelectedIcon?: boolean;\n /** A function may compute the style from the set's render state. */\n style?: RACToggleButtonGroupProps['style'];\n};\ntype SegmentedButtonSegmentProps = Omit<RACToggleButtonProps, 'children' | 'className' | 'style'> & {\n /** The segment's label. */\n children?: ReactNode;\n /** A function may compute the class from the segment's render state. */\n className?: RACToggleButtonProps['className'];\n /**\n * Disables the press ripple. The hover and pressed state layers are\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * An icon before the label, in the page's 18dp size. Replaced by the check\n * while the segment is chosen, unless the set turns that off.\n */\n icon?: ReactNode;\n /** A function may compute the style from the segment's render state. */\n style?: RACToggleButtonProps['style'];\n};\n\n/**\n * The check on a chosen segment, or the segment's own icon. Returns a node\n * rather than letting the type be inferred, since `ReactNode` is a union\n * that includes a promise and an inferred one has to be `async`.\n */\nfunction glyphFor(state: ToggleButtonRenderProps, icon: ReactNode, showSelectedIcon: boolean): ReactNode {\n if (state.isSelected && showSelectedIcon) {\n return <span className=\"x6s0dn4 xmix8c7 x3nfvp2 x2lah0s xosj86m x1xp8n7a xl56j7k\">\n <CheckGlyph className=\"x5yr21d xh8yej3\" />\n </span>;\n }\n if (icon === undefined) {\n return null;\n }\n return <span className=\"x6s0dn4 xmix8c7 x3nfvp2 x2lah0s xosj86m x1xp8n7a xl56j7k\">{icon}</span>;\n}\n\n// What a segment draws, from React Aria's render state. Built by a call\n// rather than written inline at the prop, which is what react-perf's\n// no-new-function-as-prop is after; the React Compiler memoises the result\n// on its inputs.\nfunction segmentContent(children: ReactNode, icon: ReactNode, ripple: Ripple, showSelectedIcon: boolean) {\n return (state: ToggleButtonRenderProps) => <>\n {glyphFor(state, icon, showSelectedIcon)}\n <span className=\"xeuugli xb3r6kr xlyipyv xuxw1ft\">{children}</span>\n {ripple.surface}\n </>;\n}\n\n/**\n * A row of two to five joined segments, of which one — or with\n * `selectionMode=\"multiple\"`, several — is chosen. Selection is React Aria's:\n * pass `selectedKeys` with `onSelectionChange` to control it, or\n * `defaultSelectedKeys` to let it keep its own. Give every segment an `id`,\n * which is the key selection is reported by.\n *\n * ```tsx\n * <SegmentedButton aria-label=\"Label\" defaultSelectedKeys={['first']}>\n * <SegmentedButton.Segment id=\"first\">First item</SegmentedButton.Segment>\n * <SegmentedButton.Segment id=\"second\">Second item</SegmentedButton.Segment>\n * </SegmentedButton>\n * ```\n *\n * Name the set with `aria-label` or `aria-labelledby` — nothing here labels\n * it for you, and a set with no name is a group a screen reader cannot\n * announce. What it is announced as follows the selection mode: choosing one\n * is a radio group, choosing several a toolbar of two-state buttons.\n *\n * The call site's `className` and `style` land on the track, which is the\n * element a layout positions.\n */\nfunction SegmentedButton({\n showSelectedIcon = true,\n ...props\n}: SegmentedButtonProps) {\n return <ShowSelectedIconContext value={showSelectedIcon}>\n <RACToggleButtonGroup {...props} {...mergeStatefulStyles({\n className: \"x9f619 xwz0xwf xu6a5m6 x1mt1orb\"\n }, props)} />\n </ShowSelectedIconContext>;\n}\n\n/**\n * One segment. Its `id` is what selection is reported by, and its label is\n * what names it. A chosen segment draws a check before the label; an\n * unchosen one draws whatever `icon` holds, if anything.\n */\nfunction SegmentedButtonSegment({\n children,\n disableRipple = false,\n icon,\n ...props\n}: SegmentedButtonSegmentProps) {\n const showSelectedIcon = useContext(ShowSelectedIconContext);\n // Off while disabled, as in Button: a control that cannot be pressed\n // should not answer a press with an animation.\n const ripple = useRipple<FocusableElement>(!disableRipple && props.isDisabled !== true);\n return <RACToggleButton {...props} {...ripple.handlers} {...mergeStatefulStyles(segmentStyles, props)}>\n {segmentContent(children, icon, ripple, showSelectedIcon)}\n </RACToggleButton>;\n}\n\n// StyleX cannot target `[data-selected]` on the element it is styling, so a\n// segment's state comes from the render state React Aria hands its\n// className. `disabled` is applied last so it wins over both containers, and\n// StyleX replaces a property whole, so it takes their hover states with it.\nfunction segmentStyles(state: ToggleButtonRenderProps) {\n return stylex.props(styles.segment, state.isSelected ? styles.segmentSelected : styles.segmentUnselected, state.isDisabled && styles.segmentDisabled, state.isDisabled && (state.isSelected ? styles.segmentDisabledSelected : styles.segmentDisabledUnselected));\n}\nSegmentedButton.Segment = SegmentedButtonSegment;\nexport type { SegmentedButtonProps, SegmentedButtonSegmentProps };\nexport default SegmentedButton;"],"mappings":";;;;;;;;AA4DA,MAAM,0BAA0B,cAAc,IAAI;AAElD,MAAM,SAAS;CACb,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,iBAAiB;EACf,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,yBAAyB;EACvB,QAAQ;EACR,OAAO;CACT;CACA,2BAA2B;EACzB,QAAQ;EACR,OAAO;CACT;CACA,iBAAiB;EACf,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,mBAAmB;EACjB,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;;AAsCA,SAAS,SAAS,OAAgC,MAAiB,kBAAsC;CACvG,IAAI,MAAM,cAAc,kBACtB,OAAO,oBAAC,QAAD;EAAM,WAAU;EACnB,UAAA,oBAAC,YAAD,EAAY,WAAU,kBAAiB,CAAA;CACnC,CAAA;CAEV,IAAI,SAAS,KAAA,GACX,OAAO;CAET,OAAO,oBAAC,QAAD;EAAM,WAAU;EAA4D,UAAA;CAAW,CAAA;AAChG;AAMA,SAAS,eAAe,UAAqB,MAAiB,QAAgB,kBAA2B;CACvG,QAAQ,UAAmC,qBAAA,YAAA,EAAA,UAAA;EACtC,SAAS,OAAO,MAAM,gBAAgB;EACvC,oBAAC,QAAD;GAAM,WAAU;GAAmC;EAAe,CAAA;EACjE,OAAO;CACV,EAAA,CAAA;AACJ;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,gBAAgB,EACvB,mBAAmB,MACnB,GAAG,SACoB;CACvB,OAAO,oBAAC,yBAAD;EAAyB,OAAO;EACnC,UAAA,oBAAC,mBAAD;GAAsB,GAAI;GAAO,GAAI,oBAAoB,EACzD,WAAW,kCACb,GAAG,KAAK;EAAE,CAAA;CACe,CAAA;AAC7B;;;;;;AAOA,SAAS,uBAAuB,EAC9B,UACA,gBAAgB,OAChB,MACA,GAAG,SAC2B;CAC9B,MAAM,mBAAmB,WAAW,uBAAuB;CAG3D,MAAM,SAAS,UAA4B,CAAC,iBAAiB,MAAM,eAAe,IAAI;CACtF,OAAO,oBAAC,cAAD;EAAiB,GAAI;EAAO,GAAI,OAAO;EAAU,GAAI,oBAAoB,eAAe,KAAK;EAC/F,UAAA,eAAe,UAAU,MAAM,QAAQ,gBAAgB;CACzC,CAAA;AACrB;AAMA,SAAS,cAAc,OAAgC;CACrD,OAAO,MAAa,OAAO,SAAS,MAAM,aAAa,OAAO,kBAAkB,OAAO,mBAAmB,MAAM,cAAc,OAAO,iBAAiB,MAAM,eAAe,MAAM,aAAa,OAAO,0BAA0B,OAAO,0BAA0B;AAClQ;AACA,gBAAgB,UAAU"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/segmented-button/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { FocusableElement, ToggleButtonGroupProps as RACToggleButtonGroupProps, ToggleButtonProps as RACToggleButtonProps, SharedElementRenderProps, ToggleButtonRenderProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { createContext, useContext } from 'react';\nimport { SelectionIndicator as RACSelectionIndicator, ToggleButton as RACToggleButton, ToggleButtonGroup as RACToggleButtonGroup } from 'react-aria-components';\nimport { CheckGlyph } 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 segmented buttons page's outlined segmented button: two to five\n// segments joined into one outlined track, of which one or several are\n// chosen. A segment is Button's default size and type role — a 40dp\n// container with a label-large label — which is what that page gives too.\n//\n// What a screen reader hears follows the selection mode, and React Aria\n// decides it rather than this component. Choosing one of the segments is a\n// radio group, so the track is a `radiogroup` and each segment a `radio`\n// reporting `aria-checked`; choosing several is a `toolbar` of buttons each\n// reporting `aria-pressed`. That is the right mapping for both, and it is\n// why the mode is a word on the group rather than two components.\n//\n// Six things are this component's own.\n//\n// **The segments are one track, not a row of buttons.** Every segment\n// carries the page's 1dp outline, and each one after the first drops its\n// leading edge so neighbours share a single rule rather than drawing two\n// against each other. The outer ends are the page's fully rounded shape and\n// the inner joins are square.\n//\n// **Every segment is the same width.** The page gives the segment width as\n// the container's divided by their number, so the track is a grid of equal\n// columns; the container itself is still as wide as its widest label asks.\n//\n// **A chosen segment says so with a check.** The page draws it in the icon\n// slot, so a segment given an `icon` shows the icon while unselected and the\n// check once chosen. `showSelectedIcon` turns it off for a set whose labels\n// already read as chosen or not.\n//\n// **The chosen container is an element of its own, and it moves.** It is\n// React Aria's `SelectionIndicator`, a shared element rendered inside every\n// segment and drawn in the chosen one: on a change it keeps the old one\n// until it has finished moving, so two exist while it slides. No\n// `SharedElementTransition` is rendered here, because `ToggleButtonGroup`\n// wraps its children in one already — worth saying, since the primitive\n// throws outside a scope wherever else it is used.\n//\n// It is the page's chosen container rather than a smaller pill: it covers\n// the segment, which is the box a background painted, so the fill is all\n// that travels. Three things follow. It is drawn behind the segments rather\n// than inside one, or a container crossing a neighbour would pass over that\n// neighbour's label and the rule beside it. Its corners have to match\n// whichever segment it is in, which the segment hands down as a custom\n// property, because a child cannot read its own parent's place in the track.\n// And the state layers move onto a layer of their own above it, since a\n// container that slides away would otherwise take the hover with it and off\n// the segment under the pointer.\n//\n// **Choosing several animates differently, rather than the same way twice.**\n// A shared element is one element: it can move between segments, but with\n// several chosen there is no single segment for it to be at. So\n// `selectionMode=\"multiple\"` names only `opacity` in the transition, nothing\n// positional is snapshotted, and each container fades in and out where it\n// is; `single` names `translate` and `border-radius` as well, and the one\n// container travels between segments.\n//\n// **Two of the page's values are the library's instead**, both for\n// consistency with the controls beside them: the focus ring, which is\n// primary at 2dp offset 2dp everywhere here rather than the page's secondary\n// at 3dp, and the press, which is the library's ripple rather than a flat\n// state layer. The page names a ripple as the pressed state, so the second\n// is a departure only in how it is drawn.\n//\n// **The density steps are not drawn.** The page removes 4dp of height per\n// step down, for denser interfaces; nothing else in the library takes a\n// density, and one component that did would be the odd one out. A shorter\n// track is a `className` away.\n//\n// Vertical is React Aria's and is not passed through, since the page draws\n// one row and a column of joined segments is a different shape — the outer\n// corners, the shared rule and the equal columns would all have to mean\n// something else.\n\n// Whether a chosen segment draws the check. A context rather than a prop on\n// each segment, since it is the set's decision and repeating it on every\n// segment is how the two drift.\nconst ShowSelectedIconContext = createContext(true);\n\n// Which of the two animations the chosen container plays. Read from a\n// context for the same reason, and because React Aria's own state context\n// holds the mode in a shape this would have to narrow before using.\nconst SelectionModeContext = createContext<SelectionMode>('single');\ntype Ripple = ReturnType<typeof useRipple<FocusableElement>>;\ntype SelectionMode = NonNullable<RACToggleButtonGroupProps['selectionMode']>;\ntype SegmentedButtonProps = Omit<RACToggleButtonGroupProps, 'className' | 'orientation' | 'style'> & {\n /** A function may compute the class from the set's render state. */\n className?: RACToggleButtonGroupProps['className'];\n /**\n * Whether a chosen segment draws a check before its label, as the page\n * has it. `false` leaves the segment's own icon in place while selected.\n * @default true\n */\n showSelectedIcon?: boolean;\n /** A function may compute the style from the set's render state. */\n style?: RACToggleButtonGroupProps['style'];\n};\ntype SegmentedButtonSegmentProps = Omit<RACToggleButtonProps, 'children' | 'className' | 'style'> & {\n /** The segment's label. */\n children?: ReactNode;\n /** A function may compute the class from the segment's render state. */\n className?: RACToggleButtonProps['className'];\n /**\n * Disables the press ripple. The hover and pressed state layers are\n * unaffected.\n * @default false\n */\n disableRipple?: boolean;\n /**\n * An icon before the label, in the page's 18dp size. Replaced by the check\n * while the segment is chosen, unless the set turns that off.\n */\n icon?: ReactNode;\n /** A function may compute the style from the segment's render state. */\n style?: RACToggleButtonProps['style'];\n};\n\n/**\n * The check on a chosen segment, or the segment's own icon. Returns a node\n * rather than letting the type be inferred, since `ReactNode` is a union\n * that includes a promise and an inferred one has to be `async`.\n */\nfunction glyphFor(state: ToggleButtonRenderProps, icon: ReactNode, showSelectedIcon: boolean): ReactNode {\n if (state.isSelected && showSelectedIcon) {\n return <span className=\"x6s0dn4 xmix8c7 x3nfvp2 x2lah0s xosj86m x1xp8n7a xl56j7k\">\n <CheckGlyph className=\"x5yr21d xh8yej3\" />\n </span>;\n }\n if (icon === undefined) {\n return null;\n }\n return <span className=\"x6s0dn4 xmix8c7 x3nfvp2 x2lah0s xosj86m x1xp8n7a xl56j7k\">{icon}</span>;\n}\n\n// The chosen container's class, from the segment's own state and the shared\n// element's. A function, because React Aria hands the indicator the entering\n// and leaving states the fade is drawn from, and those are the only two the\n// element knows about itself.\nfunction indicatorClassName(isDisabled: boolean, selectionMode: SelectionMode): (state: SharedElementRenderProps) => string {\n return state => ({\n 0: {\n className: \"x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd\"\n },\n 4: {\n className: \"x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7\"\n },\n 2: {\n className: \"xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xepofeg\"\n },\n 6: {\n className: \"xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xepofeg\"\n },\n 1: {\n className: \"x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xg01cxk\"\n },\n 5: {\n className: \"x15dekr4 xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xg01cxk\"\n },\n 3: {\n className: \"xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk xioksi3 x1c42kcb x1seskgd xepofeg xg01cxk\"\n },\n 7: {\n className: \"xrldhhw x12tjb6f x1g25zgg xleywy5 x9f619 x1jz8bvi x47corl x10l6tqk x8knxv4 x12w9bfk x1qno0dh x19991ni xpc4ca7 xepofeg xg01cxk\"\n }\n })[!!(selectionMode === 'multiple') << 2 | !!isDisabled << 1 | !!(state.isEntering || state.isExiting) << 0].className ?? '';\n}\n\n// What a segment draws, from React Aria's render state. Built by a call\n// rather than written inline at the prop, which is what react-perf's\n// no-new-function-as-prop is after; the React Compiler memoises the result\n// on its inputs.\nfunction segmentContent(children: ReactNode, icon: ReactNode, ripple: Ripple, selectionMode: SelectionMode, showSelectedIcon: boolean) {\n return (state: ToggleButtonRenderProps) => <>\n <RACSelectionIndicator className={indicatorClassName(state.isDisabled, selectionMode)} />\n <span {...{\n 0: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi xg01cxk x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4\"\n },\n 4: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xe2qvxb\"\n },\n 2: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xcl2av\"\n },\n 6: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xcl2av\"\n },\n 1: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g\"\n },\n 5: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g\"\n },\n 3: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g\"\n },\n 7: {\n className: \"xtwfq29 x1pjcqnp x9f619 x1jz8bvi x47corl x10l6tqk x1qno0dh x19991ni xpc4ca7 x8knxv4 xjg27g\"\n }\n }[!!state.isHovered << 2 | !!state.isFocusVisible << 1 | !!state.isPressed << 0]} />\n {glyphFor(state, icon, showSelectedIcon)}\n <span className=\"xeuugli xb3r6kr xlyipyv xuxw1ft\">{children}</span>\n {ripple.surface}\n </>;\n}\n\n/**\n * A row of two to five joined segments, of which one — or with\n * `selectionMode=\"multiple\"`, several — is chosen. Selection is React Aria's:\n * pass `selectedKeys` with `onSelectionChange` to control it, or\n * `defaultSelectedKeys` to let it keep its own. Give every segment an `id`,\n * which is the key selection is reported by.\n *\n * ```tsx\n * <SegmentedButton aria-label=\"Label\" defaultSelectedKeys={['first']}>\n * <SegmentedButton.Segment id=\"first\">First item</SegmentedButton.Segment>\n * <SegmentedButton.Segment id=\"second\">Second item</SegmentedButton.Segment>\n * </SegmentedButton>\n * ```\n *\n * Name the set with `aria-label` or `aria-labelledby` — nothing here labels\n * it for you, and a set with no name is a group a screen reader cannot\n * announce. What it is announced as follows the selection mode: choosing one\n * is a radio group, choosing several a toolbar of two-state buttons. So does\n * how the chosen container moves: it slides between segments while one is\n * chosen, and fades in place while several may be.\n *\n * The call site's `className` and `style` land on the track, which is the\n * element a layout positions.\n */\nfunction SegmentedButton({\n selectionMode = 'single',\n showSelectedIcon = true,\n ...props\n}: SegmentedButtonProps) {\n return <ShowSelectedIconContext value={showSelectedIcon}>\n <SelectionModeContext value={selectionMode}>\n <RACToggleButtonGroup {...props} selectionMode={selectionMode} {...mergeStatefulStyles({\n className: \"x9f619 xwz0xwf xu6a5m6 x1mt1orb xc8icb0\"\n }, props)} />\n </SelectionModeContext>\n </ShowSelectedIconContext>;\n}\n\n/**\n * One segment. Its `id` is what selection is reported by, and its label is\n * what names it. A chosen segment draws a check before the label; an\n * unchosen one draws whatever `icon` holds, if anything.\n */\nfunction SegmentedButtonSegment({\n children,\n disableRipple = false,\n icon,\n ...props\n}: SegmentedButtonSegmentProps) {\n const selectionMode = useContext(SelectionModeContext);\n const showSelectedIcon = useContext(ShowSelectedIconContext);\n // Off while disabled, as in Button: a control that cannot be pressed\n // should not answer a press with an animation.\n const ripple = useRipple<FocusableElement>(!disableRipple && props.isDisabled !== true);\n return <RACToggleButton {...props} {...ripple.handlers} {...mergeStatefulStyles(segmentStyles, props)}>\n {segmentContent(children, icon, ripple, selectionMode, showSelectedIcon)}\n </RACToggleButton>;\n}\n\n// StyleX cannot target `[data-selected]` on the element it is styling, so a\n// segment's state comes from the render state React Aria hands its\n// className. `disabled` is applied last so its label colour wins over both\n// of the others.\nfunction segmentStyles(state: ToggleButtonRenderProps) {\n return {\n 0: {\n className: \"x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1fwvt7v x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x1ypdohk x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 x139gbkf\"\n },\n 2: {\n className: \"x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1fwvt7v x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x1ypdohk x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 x1sawysd\"\n },\n 1: {\n className: \"x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 xrh88j3 x1xj74d8 x1h6gzvc\"\n },\n 3: {\n className: \"x1qkl9vf x111hk5a x36wtw6 x1syycwj x6s0dn4 xjbqb8w x1vqgdyp x1asv1gf xkducg2 x15ku28o x1uwupfv x120dh57 x14e42zd x12k3b1q x1a37zkv x1f6vc7b xb01x1j x1y0btm7 xmkeg23 x9f619 x3nfvp2 xkknnkr x14zspaw x1v9cpvo x126z3so xl56j7k x155f00i x1lz68p4 xeuugli xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn xt970qd x18fpw6u x1n2onr6 x1qno0dh xt3l3uh xpc4ca7 xrh88j3 x1xj74d8 x1h6gzvc\"\n }\n }[!!state.isSelected << 1 | !!state.isDisabled << 0];\n}\nSegmentedButton.Segment = SegmentedButtonSegment;\nexport type { SegmentedButtonProps, SegmentedButtonSegmentProps };\nexport default SegmentedButton;"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from "react";
2
- import { TabListProps, TabPanelProps, TabProps, TabsProps } from "react-aria-components";
2
+ import { TabListProps, TabPanelProps, TabPanelsProps, TabProps, TabsProps } from "react-aria-components";
3
3
  //#region src/components/tabs/index.d.ts
4
4
  type TabsProps$1 = Omit<TabsProps, 'children'> & {
5
5
  children?: ReactNode;
@@ -18,14 +18,24 @@ declare function Tabs$1({ children, ...props }: TabsProps$1): import("react").JS
18
18
  declare namespace Tabs$1 {
19
19
  var List: typeof TabsList;
20
20
  var Panel: typeof TabsPanel;
21
+ var Panels: typeof TabsPanels;
21
22
  var Tab: typeof TabsTab;
22
23
  }
23
24
  declare function TabsList(props: TabsListProps): import("react").JSX.Element;
24
25
  declare function TabsPanel(props: TabsPanelProps): import("react").JSX.Element;
26
+ /**
27
+ * An optional box around the panels, which animates its height as one panel
28
+ * gives way to the next. Without it the panels still work; the box around
29
+ * them simply jumps from one height to the other.
30
+ */
31
+ declare function TabsPanels(props: TabsPanelsProps): import("react").JSX.Element;
25
32
  declare function TabsTab({ children, render, ...props }: TabsTabProps): import("react").JSX.Element;
26
33
  type TabsListProps = TabListProps<object>;
27
34
  type TabsPanelProps = TabPanelProps;
35
+ type TabsPanelsProps = Omit<TabPanelsProps<object>, 'children'> & {
36
+ children?: ReactNode;
37
+ };
28
38
  type TabsTabProps = TabProps;
29
39
  //#endregion
30
- export { type TabsListProps, type TabsPanelProps, type TabsProps$1 as TabsProps, type TabsTabProps, Tabs$1 as default };
40
+ export { type TabsListProps, type TabsPanelProps, type TabsPanelsProps, type TabsProps$1 as TabsProps, type TabsTabProps, Tabs$1 as default };
31
41
  //# sourceMappingURL=index.d.ts.map
@@ -1,8 +1,8 @@
1
- import { mergeStatefulStyles } from "../../styles/merge.js";
1
+ import { mergeStatefulStyles, mergeStyles } from "../../styles/merge.js";
2
2
  import { createContext, useContext, useEffect, useState } from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { c } from "react/compiler-runtime";
5
- import { SelectionIndicator, Tab, TabList, TabPanel, Tabs } from "react-aria-components";
5
+ import { SelectionIndicator, Tab, TabList, TabPanel, TabPanels, Tabs } from "react-aria-components";
6
6
  //#region src/components/tabs/index.tsx
7
7
  const NO_PANELS = /* @__PURE__ */ new Set();
8
8
  const PanelsContext = createContext(NO_PANELS);
@@ -153,6 +153,31 @@ function TabsPanel(props) {
153
153
  } else t3 = $[8];
154
154
  return t3;
155
155
  }
156
+ /**
157
+ * An optional box around the panels, which animates its height as one panel
158
+ * gives way to the next. Without it the panels still work; the box around
159
+ * them simply jumps from one height to the other.
160
+ */
161
+ function TabsPanels(props) {
162
+ const $ = c(5);
163
+ let t0;
164
+ if ($[0] !== props) {
165
+ t0 = mergeStyles({ className: "x12w9bfk x1t2j4n3 x9f619 xb3r6kr xioksi3 x1f55p5c x1seskgd" }, props);
166
+ $[0] = props;
167
+ $[1] = t0;
168
+ } else t0 = $[1];
169
+ let t1;
170
+ if ($[2] !== props || $[3] !== t0) {
171
+ t1 = /* @__PURE__ */ jsx(TabPanels, {
172
+ ...props,
173
+ ...t0
174
+ });
175
+ $[2] = props;
176
+ $[3] = t0;
177
+ $[4] = t1;
178
+ } else t1 = $[4];
179
+ return t1;
180
+ }
156
181
  function TabsTab(t0) {
157
182
  const $ = c(8);
158
183
  const { children, render, ...props } = t0;
@@ -194,6 +219,7 @@ function tabStyles(state) {
194
219
  }
195
220
  Tabs$1.List = TabsList;
196
221
  Tabs$1.Panel = TabsPanel;
222
+ Tabs$1.Panels = TabsPanels;
197
223
  Tabs$1.Tab = TabsTab;
198
224
  //#endregion
199
225
  export { Tabs$1 as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["previous","next","register","panels","children"],"sources":["../../../src/components/tabs/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { Key, TabsProps as RACTabsProps, TabListProps, TabPanelProps, TabProps, TabRenderProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { createContext, useCallback, useContext, useEffect, useState } from 'react';\nimport { SelectionIndicator as RACSelectionIndicator, Tabs as RACTabs, Tab, TabList, TabPanel } from 'react-aria-components';\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 tabs page's primary tabs: a 48dp bar on the surface, divided into equal\n// sections, with a 1dp outline-variant divider inside the bar along its\n// bottom edge and, under the active tab's label, a 3dp primary indicator\n// rounded along its top. The indicator follows the label rather than the\n// tab, inset 2dp from the label's ends and never shorter than 24dp, which is\n// what the page draws.\n//\n// The indicator is React Aria's `SelectionIndicator`, which is a shared\n// element: it is rendered inside every tab but drawn in the selected one,\n// and on a change it keeps the old one until it has finished moving to the\n// new one's place. No `SharedElementTransition` is rendered here — `Tab`\n// scopes its own, and one added around the list changes nothing, which is\n// worth knowing because the primitive throws outside a scope when it is put\n// anywhere else.\n//\n// The label is wrapped in a span of its own so the indicator has the label's\n// width to follow: it is the span's `::after`, and the span is as tall as the\n// tab so the indicator reaches the bottom of the bar. Which tab carries it\n// comes from React Aria's render state rather than a selector, since StyleX\n// cannot target [data-selected] on the element it is styling.\n\nconst NO_PANELS: ReadonlySet<Key> = new Set();\n\n// Which panels are mounted, by id. React Aria points a selected tab's\n// `aria-controls` at the panel it would control whether or not one exists,\n// and a strip used on its own — tabs that filter the content below rather\n// than swapping a panel — then references an id nothing carries, which axe\n// reports as an invalid attribute value. Each panel registers itself here so\n// a tab can leave the attribute off when its panel is not there.\nconst PanelsContext = createContext<ReadonlySet<Key>>(NO_PANELS);\nconst RegisterPanelContext = createContext<(id: Key) => () => void>(() => () => {});\n\n// `children` is narrowed to nodes. React Aria also accepts a function there,\n// to hand the children the tabs' render state, and that form cannot be\n// wrapped in a context provider without calling it first — which would be\n// doing React Aria's job with none of its state. Nothing here needs it, so\n// the narrower type says so rather than leaving a signature that type-checks\n// and then fails to render.\ntype TabsProps = Omit<RACTabsProps, 'children'> & {\n children?: ReactNode;\n};\n\n// The label, wrapped so the indicator has its width to follow. Built by a\n// call for the same reason as `tabRenderer` below; React Aria hands the\n// function the tab's state, and it is passed on when the children are a\n// function too.\nfunction tabContent(children: TabProps['children']) {\n return (state: TabRenderProps & {\n defaultChildren: ReactNode;\n }) => <span className=\"x6s0dn4 x5yr21d x9f619 x3nfvp2 x1n2onr6\">\n {typeof children === 'function' ? children(state) : children}\n <RACSelectionIndicator className=\"x12w9bfk xnety89 xuoj239 x13dhofw xz4iguh x9f619 x17v02zk x1ey2m1c x17y0mx6 xvueqy4 xnei2rj x10l6tqk xioksi3 x1mxbss1 x1seskgd\" />\n </span>;\n}\n\n// React Aria renders a tab with `href` as an anchor and any other as a div,\n// and expects a `render` function to return the same element it would have.\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 two inputs. See PanelsContext for why the attribute is\n// dropped.\nfunction tabRenderer(hasPanel: boolean, render: TabProps['render']): NonNullable<TabProps['render']> {\n return (domProps, state) => {\n const adjusted = hasPanel ? domProps : {\n ...domProps,\n 'aria-controls': undefined\n };\n if (render !== undefined) {\n return render(adjusted, state);\n }\n if ('href' in adjusted) {\n // oxlint-disable-next-line jsx-a11y/anchor-has-content -- filled by React Aria\n return <a {...adjusted} />;\n }\n return <div {...adjusted} />;\n };\n}\n\n/**\n * A tab bar and its panels. Selection is React Aria's `selectedKey`: pass\n * it with `onSelectionChange` to control it, or `defaultSelectedKey` to let\n * it keep its own. Each `Tabs.Tab` names the `Tabs.Panel` it controls through\n * a shared `id`, and a strip may stand alone without panels.\n *\n * Composed rather than configured by props, because the number of tabs and\n * what each panel holds are the call site's to decide — the parts are\n * `Tabs.List`, `Tabs.Tab`, and `Tabs.Panel`.\n */\nfunction Tabs({\n children,\n ...props\n}: TabsProps) {\n const [panels, setPanels] = useState<ReadonlySet<Key>>(NO_PANELS);\n const register = useCallback((id: Key) => {\n setPanels(previous => {\n if (previous.has(id)) {\n return previous;\n }\n const next = new Set(previous);\n next.add(id);\n return next;\n });\n return () => {\n setPanels(previous => {\n if (!previous.has(id)) {\n return previous;\n }\n const next = new Set(previous);\n next.delete(id);\n return next;\n });\n };\n }, []);\n return <RACTabs {...props}>\n <RegisterPanelContext value={register}>\n <PanelsContext value={panels}>{children}</PanelsContext>\n </RegisterPanelContext>\n </RACTabs>;\n}\nfunction TabsList(props: TabsListProps) {\n return <TabList {...props} {...mergeStatefulStyles({\n className: \"xp05xdj x9f619 x78zum5\"\n }, props)} />;\n}\nfunction TabsPanel(props: TabsPanelProps) {\n const register = useContext(RegisterPanelContext);\n const {\n id\n } = props;\n useEffect(() => {\n if (id === undefined) {\n return undefined;\n }\n return register(id);\n }, [id, register]);\n return <TabPanel {...props} {...mergeStatefulStyles({\n className: \"x9f619 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn\"\n }, props)} />;\n}\nfunction TabsTab({\n children,\n render,\n ...props\n}: TabsTabProps) {\n const panels = useContext(PanelsContext);\n const hasPanel = props.id !== undefined && panels.has(props.id);\n return <Tab {...props} render={tabRenderer(hasPanel, render)} {...mergeStatefulStyles(tabStyles, props)}>\n {tabContent(children)}\n </Tab>;\n}\n\n// StyleX cannot target [data-selected] on the element it is styling, so the\n// active tab cannot be chosen in CSS. React Aria's answer is a className that\n// is a function of the tab's own state, the same mechanism Chip uses —\n// mergeStatefulStyles wraps this one so a tab still keeps a className the call\n// site passed.\nfunction tabStyles(state: TabRenderProps) {\n return {\n 0: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x1ypdohk x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 x12vej0r x1p2om7n xjbqb8w x1w5n3ug\"\n },\n 2: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x1ypdohk x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 x12vej0r x14dcer4 xjbqb8w x1mxwv8y\"\n },\n 1: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 xjbqb8w x1xj74d8 x1h6gzvc\"\n },\n 3: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 xjbqb8w x1xj74d8 x1h6gzvc\"\n }\n }[!!state.isSelected << 1 | !!state.isDisabled << 0];\n}\nTabs.List = TabsList;\nTabs.Panel = TabsPanel;\nTabs.Tab = TabsTab;\ntype TabsListProps = TabListProps<object>;\ntype TabsPanelProps = TabPanelProps;\ntype TabsTabProps = TabProps;\nexport type { TabsListProps, TabsPanelProps, TabsProps, TabsTabProps };\nexport default Tabs;"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["previous","next","register","panels","children"],"sources":["../../../src/components/tabs/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { Key, TabsProps as RACTabsProps, TabListProps, TabPanelProps, TabPanelsProps, TabProps, TabRenderProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { createContext, useCallback, useContext, useEffect, useState } from 'react';\nimport { SelectionIndicator as RACSelectionIndicator, TabPanels as RACTabPanels, Tabs as RACTabs, Tab, TabList, TabPanel } from 'react-aria-components';\nimport { mergeStatefulStyles, mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, spacing, stateLayerOpacity, typography } from '../../tokens/design.tokens.stylex';\n\n// The tabs page's primary tabs: a 48dp bar on the surface, divided into equal\n// sections, with a 1dp outline-variant divider inside the bar along its\n// bottom edge and, under the active tab's label, a 3dp primary indicator\n// rounded along its top. The indicator follows the label rather than the\n// tab, inset 2dp from the label's ends and never shorter than 24dp, which is\n// what the page draws.\n//\n// The indicator is React Aria's `SelectionIndicator`, which is a shared\n// element: it is rendered inside every tab but drawn in the selected one,\n// and on a change it keeps the old one until it has finished moving to the\n// new one's place. No `SharedElementTransition` is rendered here — `Tab`\n// scopes its own, and one added around the list changes nothing, which is\n// worth knowing because the primitive throws outside a scope when it is put\n// anywhere else.\n//\n// The label is wrapped in a span of its own so the indicator has the label's\n// width to follow: it is the span's `::after`, and the span is as tall as the\n// tab so the indicator reaches the bottom of the bar. Which tab carries it\n// comes from React Aria's render state rather than a selector, since StyleX\n// cannot target [data-selected] on the element it is styling.\n\nconst NO_PANELS: ReadonlySet<Key> = new Set();\n\n// Which panels are mounted, by id. React Aria points a selected tab's\n// `aria-controls` at the panel it would control whether or not one exists,\n// and a strip used on its own — tabs that filter the content below rather\n// than swapping a panel — then references an id nothing carries, which axe\n// reports as an invalid attribute value. Each panel registers itself here so\n// a tab can leave the attribute off when its panel is not there.\nconst PanelsContext = createContext<ReadonlySet<Key>>(NO_PANELS);\nconst RegisterPanelContext = createContext<(id: Key) => () => void>(() => () => {});\n\n// `children` is narrowed to nodes. React Aria also accepts a function there,\n// to hand the children the tabs' render state, and that form cannot be\n// wrapped in a context provider without calling it first — which would be\n// doing React Aria's job with none of its state. Nothing here needs it, so\n// the narrower type says so rather than leaving a signature that type-checks\n// and then fails to render.\ntype TabsProps = Omit<RACTabsProps, 'children'> & {\n children?: ReactNode;\n};\n\n// The label, wrapped so the indicator has its width to follow. Built by a\n// call for the same reason as `tabRenderer` below; React Aria hands the\n// function the tab's state, and it is passed on when the children are a\n// function too.\nfunction tabContent(children: TabProps['children']) {\n return (state: TabRenderProps & {\n defaultChildren: ReactNode;\n }) => <span className=\"x6s0dn4 x5yr21d x9f619 x3nfvp2 x1n2onr6\">\n {typeof children === 'function' ? children(state) : children}\n <RACSelectionIndicator className=\"x12w9bfk xnety89 xuoj239 x13dhofw xz4iguh x9f619 x17v02zk x1ey2m1c x17y0mx6 xvueqy4 xnei2rj x10l6tqk xioksi3 x1mxbss1 x1seskgd\" />\n </span>;\n}\n\n// React Aria renders a tab with `href` as an anchor and any other as a div,\n// and expects a `render` function to return the same element it would have.\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 two inputs. See PanelsContext for why the attribute is\n// dropped.\nfunction tabRenderer(hasPanel: boolean, render: TabProps['render']): NonNullable<TabProps['render']> {\n return (domProps, state) => {\n const adjusted = hasPanel ? domProps : {\n ...domProps,\n 'aria-controls': undefined\n };\n if (render !== undefined) {\n return render(adjusted, state);\n }\n if ('href' in adjusted) {\n // oxlint-disable-next-line jsx-a11y/anchor-has-content -- filled by React Aria\n return <a {...adjusted} />;\n }\n return <div {...adjusted} />;\n };\n}\n\n/**\n * A tab bar and its panels. Selection is React Aria's `selectedKey`: pass\n * it with `onSelectionChange` to control it, or `defaultSelectedKey` to let\n * it keep its own. Each `Tabs.Tab` names the `Tabs.Panel` it controls through\n * a shared `id`, and a strip may stand alone without panels.\n *\n * Composed rather than configured by props, because the number of tabs and\n * what each panel holds are the call site's to decide — the parts are\n * `Tabs.List`, `Tabs.Tab`, and `Tabs.Panel`.\n */\nfunction Tabs({\n children,\n ...props\n}: TabsProps) {\n const [panels, setPanels] = useState<ReadonlySet<Key>>(NO_PANELS);\n const register = useCallback((id: Key) => {\n setPanels(previous => {\n if (previous.has(id)) {\n return previous;\n }\n const next = new Set(previous);\n next.add(id);\n return next;\n });\n return () => {\n setPanels(previous => {\n if (!previous.has(id)) {\n return previous;\n }\n const next = new Set(previous);\n next.delete(id);\n return next;\n });\n };\n }, []);\n return <RACTabs {...props}>\n <RegisterPanelContext value={register}>\n <PanelsContext value={panels}>{children}</PanelsContext>\n </RegisterPanelContext>\n </RACTabs>;\n}\nfunction TabsList(props: TabsListProps) {\n return <TabList {...props} {...mergeStatefulStyles({\n className: \"xp05xdj x9f619 x78zum5\"\n }, props)} />;\n}\nfunction TabsPanel(props: TabsPanelProps) {\n const register = useContext(RegisterPanelContext);\n const {\n id\n } = props;\n useEffect(() => {\n if (id === undefined) {\n return undefined;\n }\n return register(id);\n }, [id, register]);\n return <TabPanel {...props} {...mergeStatefulStyles({\n className: \"x9f619 xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn\"\n }, props)} />;\n}\n\n/**\n * An optional box around the panels, which animates its height as one panel\n * gives way to the next. Without it the panels still work; the box around\n * them simply jumps from one height to the other.\n */\nfunction TabsPanels(props: TabsPanelsProps) {\n return <RACTabPanels {...props} {...mergeStyles({\n className: \"x12w9bfk x1t2j4n3 x9f619 xb3r6kr xioksi3 x1f55p5c x1seskgd\"\n }, props)} />;\n}\nfunction TabsTab({\n children,\n render,\n ...props\n}: TabsTabProps) {\n const panels = useContext(PanelsContext);\n const hasPanel = props.id !== undefined && panels.has(props.id);\n return <Tab {...props} render={tabRenderer(hasPanel, render)} {...mergeStatefulStyles(tabStyles, props)}>\n {tabContent(children)}\n </Tab>;\n}\n\n// StyleX cannot target [data-selected] on the element it is styling, so the\n// active tab cannot be chosen in CSS. React Aria's answer is a className that\n// is a function of the tab's own state, the same mechanism Chip uses —\n// mergeStatefulStyles wraps this one so a tab still keeps a className the call\n// site passed.\nfunction tabStyles(state: TabRenderProps) {\n return {\n 0: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x1ypdohk x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 x12vej0r x1p2om7n xjbqb8w x1w5n3ug\"\n },\n 2: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x1ypdohk x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 x12vej0r x14dcer4 xjbqb8w x1mxwv8y\"\n },\n 1: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 xjbqb8w x1xj74d8 x1h6gzvc\"\n },\n 3: {\n className: \"x6s0dn4 xsdox4t xc342km x9f619 x78zum5 x1r8uery x1iyjqo2 xs83m0k xrgwony x12s497w x1szcwkt xl56j7k xo803ec xyl1r0q xeuugli xrgy624 x2ssjo2 x9v5kkp x1t137rt x1de99jn xt970qd x790zyz x1n2onr6 x1hl2dhg x1qno0dh xs2xxs2 xpc4ca7 xjbqb8w x1xj74d8 x1h6gzvc\"\n }\n }[!!state.isSelected << 1 | !!state.isDisabled << 0];\n}\nTabs.List = TabsList;\nTabs.Panel = TabsPanel;\nTabs.Panels = TabsPanels;\nTabs.Tab = TabsTab;\ntype TabsListProps = TabListProps<object>;\ntype TabsPanelProps = TabPanelProps;\ntype TabsPanelsProps = Omit<TabPanelsProps<object>, 'children'> & {\n children?: ReactNode;\n};\ntype TabsTabProps = TabProps;\nexport type { TabsListProps, TabsPanelProps, TabsPanelsProps, TabsProps, TabsTabProps };\nexport default Tabs;"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -70,6 +70,6 @@ import Tree, { TreeHeaderProps, TreeItemProps, TreeLoadMoreProps, TreeProps, Tre
70
70
  import "./components/index.js";
71
71
  import { collectionSizes } from "./layout.js";
72
72
  import { useDragAndDrop } from "./drag/hooks.js";
73
- import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, Key, ListLayout, PressEvent, Pressable, RouterProvider, Selection, SortDescriptor, TableLayout, TokenFieldValue, Virtualizer, VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter, useListData, useLocale, useTreeData } from "./react-aria.js";
73
+ import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, Key, ListLayout, PressEvent, Pressable, RouterProvider, Selection, SharedElement, SharedElementTransition, SortDescriptor, TableLayout, TokenFieldValue, Virtualizer, VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter, useListData, useLocale, useTreeData } from "./react-aria.js";
74
74
  import "./styles.css";
75
- export { AppBar, type AppBarProps, Autocomplete, type AutocompleteProps, Avatar, type AvatarProps, Breadcrumbs, type BreadcrumbsProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Chip, ChipGroup, type ChipGroupProps, type ChipProps, Code, type CodeProps, Collection, ColorArea, type ColorAreaProps, ColorField, type ColorFieldProps, ColorPicker, type ColorPickerProps, ColorSlider, type ColorSliderProps, ColorSwatch, ColorSwatchPicker, type ColorSwatchPickerProps, type ColorSwatchProps, ColorWheel, type ColorWheelProps, ComboBox, type ComboBoxProps, Container, type ContainerProps, CopyField, type CopyFieldProps, Currency, type CurrencyProps, DIRECTORY_DRAG_TYPE, DateField, type DateFieldProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, type DialogProps, Disclosure, DisclosureGroup, type DisclosureGroupProps, type DisclosureProps, DropZone, type DropZoneProps, Feed, type FeedProps, FileTrigger, type FileTriggerProps, Focusable, Form, type FormProps, GridLayout, I18nProvider, IconButton, type IconButtonProps, type Key, Keycap, type KeycapProps, Link, type LinkProps, List, ListBox, type ListBoxProps, ListDetail, type ListDetailProps, ListItem, type ListItemProps, ListLayout, type ListProps, Menu, type MenuProps, Meter, type MeterProps, NavigationTree, type NavigationTreeHeaderProps, type NavigationTreeItemProps, type NavigationTreeProps, type NavigationTreeSectionProps, NumberField, type NumberFieldProps, Popover, type PopoverProps, type PressEvent, Pressable, ProductIcon, type ProductIconProps, ProgressIndicator, type ProgressIndicatorProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, RangeCalendar, type RangeCalendarProps, RouterProvider, SearchField, type SearchFieldProps, SegmentedButton, type SegmentedButtonProps, type SegmentedButtonSegmentProps, Select, type SelectProps, type Selection, Separator, type SeparatorProps, Sheet, type SheetProps, Slider, type SliderProps, Snackbar, type SnackbarProps, type SortDescriptor, Stack, type StackAlign, type StackGap, type StackJustify, type StackProps, SupportingPane, type SupportingPaneProps, Switch, type SwitchProps, Table, type TableBodyProps, type TableCellProps, type TableColumnProps, type TableFooterProps, type TableHeaderProps, TableLayout, type TableProps, type TableRowProps, Tabs, type TabsProps, Tag, type TagProps, Text, TextArea, type TextAreaProps, TextField, type TextFieldProps, type TextProps, TimeField, type TimeFieldProps, TokenField, type TokenFieldProps, TokenFieldValue, Toolbar, type ToolbarProps, Tooltip, type TooltipProps, Tree, type TreeHeaderProps, type TreeItemProps, type TreeLoadMoreProps, type TreeProps, type TreeSectionProps, Virtualizer, VisuallyHidden, WaterfallLayout, collectionSizes, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop, useDrop, useFilter, useListData, useLocale, useTreeData };
75
+ export { AppBar, type AppBarProps, Autocomplete, type AutocompleteProps, Avatar, type AvatarProps, Breadcrumbs, type BreadcrumbsProps, Button, type ButtonProps, Calendar, type CalendarProps, Card, type CardProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Chip, ChipGroup, type ChipGroupProps, type ChipProps, Code, type CodeProps, Collection, ColorArea, type ColorAreaProps, ColorField, type ColorFieldProps, ColorPicker, type ColorPickerProps, ColorSlider, type ColorSliderProps, ColorSwatch, ColorSwatchPicker, type ColorSwatchPickerProps, type ColorSwatchProps, ColorWheel, type ColorWheelProps, ComboBox, type ComboBoxProps, Container, type ContainerProps, CopyField, type CopyFieldProps, Currency, type CurrencyProps, DIRECTORY_DRAG_TYPE, DateField, type DateFieldProps, DatePicker, type DatePickerProps, DateRangePicker, type DateRangePickerProps, Dialog, type DialogProps, Disclosure, DisclosureGroup, type DisclosureGroupProps, type DisclosureProps, DropZone, type DropZoneProps, Feed, type FeedProps, FileTrigger, type FileTriggerProps, Focusable, Form, type FormProps, GridLayout, I18nProvider, IconButton, type IconButtonProps, type Key, Keycap, type KeycapProps, Link, type LinkProps, List, ListBox, type ListBoxProps, ListDetail, type ListDetailProps, ListItem, type ListItemProps, ListLayout, type ListProps, Menu, type MenuProps, Meter, type MeterProps, NavigationTree, type NavigationTreeHeaderProps, type NavigationTreeItemProps, type NavigationTreeProps, type NavigationTreeSectionProps, NumberField, type NumberFieldProps, Popover, type PopoverProps, type PressEvent, Pressable, ProductIcon, type ProductIconProps, ProgressIndicator, type ProgressIndicatorProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, RangeCalendar, type RangeCalendarProps, RouterProvider, SearchField, type SearchFieldProps, SegmentedButton, type SegmentedButtonProps, type SegmentedButtonSegmentProps, Select, type SelectProps, type Selection, Separator, type SeparatorProps, SharedElement, SharedElementTransition, Sheet, type SheetProps, Slider, type SliderProps, Snackbar, type SnackbarProps, type SortDescriptor, Stack, type StackAlign, type StackGap, type StackJustify, type StackProps, SupportingPane, type SupportingPaneProps, Switch, type SwitchProps, Table, type TableBodyProps, type TableCellProps, type TableColumnProps, type TableFooterProps, type TableHeaderProps, TableLayout, type TableProps, type TableRowProps, Tabs, type TabsProps, Tag, type TagProps, Text, TextArea, type TextAreaProps, TextField, type TextFieldProps, type TextProps, TimeField, type TimeFieldProps, TokenField, type TokenFieldProps, TokenFieldValue, Toolbar, type ToolbarProps, Tooltip, type TooltipProps, Tree, type TreeHeaderProps, type TreeItemProps, type TreeLoadMoreProps, type TreeProps, type TreeSectionProps, Virtualizer, VisuallyHidden, WaterfallLayout, collectionSizes, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop, useDrop, useFilter, useListData, useLocale, useTreeData };
package/dist/index.js CHANGED
@@ -69,6 +69,6 @@ import Tooltip from "./components/tooltip/index.js";
69
69
  import Tree from "./components/tree/index.js";
70
70
  import { collectionSizes } from "./layout.js";
71
71
  import { useDragAndDrop } from "./drag/hooks.js";
72
- import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, TableLayout, TokenFieldValue, Virtualizer, VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter, useListData, useLocale, useTreeData } from "./react-aria.js";
72
+ import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, SharedElement, SharedElementTransition, TableLayout, TokenFieldValue, Virtualizer, VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter, useListData, useLocale, useTreeData } from "./react-aria.js";
73
73
  import "./styles.css";
74
- export { AppBar, Autocomplete, Avatar, Breadcrumbs, Button, Calendar, Card, Checkbox, CheckboxGroup, Chip, ChipGroup, Code, Collection, ColorArea, ColorField, ColorPicker, ColorSlider, ColorSwatch, ColorSwatchPicker, ColorWheel, ComboBox, Container, CopyField, Currency, DIRECTORY_DRAG_TYPE, DateField, DatePicker, DateRangePicker, Dialog, Disclosure, DisclosureGroup, DropZone, Feed, FileTrigger, Focusable, Form, GridLayout, I18nProvider, IconButton, Keycap, Link, List, ListBox, ListDetail, ListItem, ListLayout, Menu, Meter, NavigationTree, NumberField, Popover, Pressable, ProductIcon, ProgressIndicator, Radio, RadioGroup, RangeCalendar, RouterProvider, SearchField, SegmentedButton, Select, Separator, Sheet, Slider, Snackbar, Stack, SupportingPane, Switch, Table, TableLayout, Tabs, Tag, Text, TextArea, TextField, TimeField, TokenField, TokenFieldValue, Toolbar, Tooltip, Tree, Virtualizer, VisuallyHidden, WaterfallLayout, collectionSizes, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop, useDrop, useFilter, useListData, useLocale, useTreeData };
74
+ export { AppBar, Autocomplete, Avatar, Breadcrumbs, Button, Calendar, Card, Checkbox, CheckboxGroup, Chip, ChipGroup, Code, Collection, ColorArea, ColorField, ColorPicker, ColorSlider, ColorSwatch, ColorSwatchPicker, ColorWheel, ComboBox, Container, CopyField, Currency, DIRECTORY_DRAG_TYPE, DateField, DatePicker, DateRangePicker, Dialog, Disclosure, DisclosureGroup, DropZone, Feed, FileTrigger, Focusable, Form, GridLayout, I18nProvider, IconButton, Keycap, Link, List, ListBox, ListDetail, ListItem, ListLayout, Menu, Meter, NavigationTree, NumberField, Popover, Pressable, ProductIcon, ProgressIndicator, Radio, RadioGroup, RangeCalendar, RouterProvider, SearchField, SegmentedButton, Select, Separator, SharedElement, SharedElementTransition, Sheet, Slider, Snackbar, Stack, SupportingPane, Switch, Table, TableLayout, Tabs, Tag, Text, TextArea, TextField, TimeField, TokenField, TokenFieldValue, Toolbar, Tooltip, Tree, Virtualizer, VisuallyHidden, WaterfallLayout, collectionSizes, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop, useDrop, useFilter, useListData, useLocale, useTreeData };
@@ -1,3 +1,3 @@
1
1
  import { useDragAndDrop as useDragAndDrop$1 } from "./drag/hooks.js";
2
- import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, Key, ListLayout, PressEvent, Pressable, RouterProvider, Selection, SortDescriptor, TableLayout, TokenFieldValue as TokenFieldValue$1, Virtualizer, VisuallyHidden as VisuallyHidden$1, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter as useFilter$1, useListData, useLocale, useTreeData } from "react-aria-components";
3
- export { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, type Key, ListLayout, type PressEvent, Pressable, RouterProvider, type Selection, type SortDescriptor, TableLayout, TokenFieldValue$1 as TokenFieldValue, Virtualizer, VisuallyHidden$1 as VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop$1 as useDragAndDrop, useDrop, useFilter$1 as useFilter, useListData, useLocale, useTreeData };
2
+ import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, Key, ListLayout, PressEvent, Pressable, RouterProvider, Selection, SharedElement, SharedElementTransition, SortDescriptor, TableLayout, TokenFieldValue as TokenFieldValue$1, Virtualizer, VisuallyHidden as VisuallyHidden$1, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter as useFilter$1, useListData, useLocale, useTreeData } from "react-aria-components";
3
+ export { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, type Key, ListLayout, type PressEvent, Pressable, RouterProvider, type Selection, SharedElement, SharedElementTransition, type SortDescriptor, TableLayout, TokenFieldValue$1 as TokenFieldValue, Virtualizer, VisuallyHidden$1 as VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop$1 as useDragAndDrop, useDrop, useFilter$1 as useFilter, useListData, useLocale, useTreeData };
@@ -1,3 +1,3 @@
1
1
  import { useDragAndDrop as useDragAndDrop$1 } from "./drag/hooks.js";
2
- import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, TableLayout, TokenFieldValue as TokenFieldValue$1, Virtualizer, VisuallyHidden as VisuallyHidden$1, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter as useFilter$1, useListData, useLocale, useTreeData } from "react-aria-components";
3
- export { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, TableLayout, TokenFieldValue$1 as TokenFieldValue, Virtualizer, VisuallyHidden$1 as VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop$1 as useDragAndDrop, useDrop, useFilter$1 as useFilter, useListData, useLocale, useTreeData };
2
+ import { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, SharedElement, SharedElementTransition, TableLayout, TokenFieldValue as TokenFieldValue$1, Virtualizer, VisuallyHidden as VisuallyHidden$1, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDrop, useFilter as useFilter$1, useListData, useLocale, useTreeData } from "react-aria-components";
3
+ export { Collection, DIRECTORY_DRAG_TYPE, Focusable, GridLayout, I18nProvider, ListLayout, Pressable, RouterProvider, SharedElement, SharedElementTransition, TableLayout, TokenFieldValue$1 as TokenFieldValue, Virtualizer, VisuallyHidden$1 as VisuallyHidden, WaterfallLayout, getColorChannels, isDirectoryDropItem, isFileDropItem, isTextDropItem, parseColor, useAsyncList, useDrag, useDragAndDrop$1 as useDragAndDrop, useDrop, useFilter$1 as useFilter, useListData, useLocale, useTreeData };
package/dist/styles.css CHANGED
@@ -9,6 +9,10 @@
9
9
  grid-area: 1 / 1 / 2 / 2;
10
10
  }
11
11
 
12
+ .x1jz8bvi {
13
+ inset: -1px;
14
+ }
15
+
12
16
  .x1qx2jxi {
13
17
  inset: -6px;
14
18
  }
@@ -691,6 +695,10 @@
691
695
  border-end-end-radius: 2px;
692
696
  }
693
697
 
698
+ .xrldhhw {
699
+ border-end-end-radius: var(--segment-indicator-radius-end);
700
+ }
701
+
694
702
  .x1mh50ju {
695
703
  border-end-end-radius: var(--x1kmbna2);
696
704
  }
@@ -711,6 +719,10 @@
711
719
  border-end-start-radius: 2px;
712
720
  }
713
721
 
722
+ .x12tjb6f {
723
+ border-end-start-radius: var(--segment-indicator-radius-start);
724
+ }
725
+
714
726
  .xqmr837 {
715
727
  border-end-start-radius: var(--x1kmbna2);
716
728
  }
@@ -739,6 +751,10 @@
739
751
  border-start-end-radius: 2px;
740
752
  }
741
753
 
754
+ .x1g25zgg {
755
+ border-start-end-radius: var(--segment-indicator-radius-end);
756
+ }
757
+
742
758
  .x13dhofw {
743
759
  border-start-end-radius: var(--x1kmbna2);
744
760
  }
@@ -755,6 +771,10 @@
755
771
  border-start-start-radius: 2px;
756
772
  }
757
773
 
774
+ .xleywy5 {
775
+ border-start-start-radius: var(--segment-indicator-radius-start);
776
+ }
777
+
758
778
  .xz4iguh {
759
779
  border-start-start-radius: var(--x1kmbna2);
760
780
  }
@@ -1343,6 +1363,10 @@
1343
1363
  inset-inline-start: var(--x-insetInlineStart);
1344
1364
  }
1345
1365
 
1366
+ .xc8icb0 {
1367
+ isolation: isolate;
1368
+ }
1369
+
1346
1370
  .xl56j7k {
1347
1371
  justify-content: center;
1348
1372
  }
@@ -1548,6 +1572,14 @@
1548
1572
  opacity: 0;
1549
1573
  }
1550
1574
 
1575
+ .xcl2av {
1576
+ opacity: var(--x124j18r);
1577
+ }
1578
+
1579
+ .xe2qvxb {
1580
+ opacity: var(--x8z5t6h);
1581
+ }
1582
+
1551
1583
  .xjg27g {
1552
1584
  opacity: var(--xhaltwz);
1553
1585
  }
@@ -1847,6 +1879,10 @@
1847
1879
  transition-property: background-color;
1848
1880
  }
1849
1881
 
1882
+ .x1f55p5c {
1883
+ transition-property: block-size;
1884
+ }
1885
+
1850
1886
  .x1aqzbqr {
1851
1887
  transition-property: border-color, border-width;
1852
1888
  }
@@ -1907,6 +1943,10 @@
1907
1943
  transition-property: transform;
1908
1944
  }
1909
1945
 
1946
+ .x1c42kcb {
1947
+ transition-property: translate, border-radius, opacity;
1948
+ }
1949
+
1910
1950
  .x1mxbss1 {
1911
1951
  transition-property: translate, inline-size;
1912
1952
  }
@@ -1956,6 +1996,10 @@
1956
1996
  white-space: pre-wrap;
1957
1997
  }
1958
1998
 
1999
+ .x8knxv4 {
2000
+ z-index: -1;
2001
+ }
2002
+
1959
2003
  .x1vjfegm {
1960
2004
  z-index: 1;
1961
2005
  }
@@ -1988,10 +2032,6 @@
1988
2032
  background-color: color-mix(in srgb,var(--x28n2pw) calc(var(--x124j18r) * 100%),transparent);
1989
2033
  }
1990
2034
 
1991
- .x10oam47:focus-visible {
1992
- background-color: color-mix(in srgb,var(--xn0syi6) calc(var(--x124j18r) * 100%),transparent);
1993
- }
1994
-
1995
2035
  .x1lxxh4i:focus-within {
1996
2036
  box-shadow: inset 0 -2px 0 0 var(--x12p1wyw);
1997
2037
  }
@@ -2457,6 +2497,10 @@
2457
2497
  height: auto;
2458
2498
  }
2459
2499
 
2500
+ .x1t2j4n3 {
2501
+ height: var(--tab-panel-height, auto);
2502
+ }
2503
+
2460
2504
  .xyq6l7l {
2461
2505
  height: var(--x-blockSize);
2462
2506
  }
@@ -3674,3 +3718,19 @@
3674
3718
  --x9erpvp: #ffd8e4;
3675
3719
  --x1or1uxx: #efb8c8;
3676
3720
  }
3721
+
3722
+ .x111hk5a {
3723
+ --segment-indicator-radius-end: var(--x1lckk6t);
3724
+ }
3725
+
3726
+ .x1syycwj {
3727
+ --segment-indicator-radius-start: var(--x1lckk6t);
3728
+ }
3729
+
3730
+ .x36wtw6:first-child {
3731
+ --segment-indicator-radius-start: min(var(--x1kmbna2),20px);
3732
+ }
3733
+
3734
+ .x1qkl9vf:last-child {
3735
+ --segment-indicator-radius-end: min(var(--x1kmbna2),20px);
3736
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanso-labs/kanso-ui",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "A React component library built on React Aria Components primitives and styled with StyleX, with design tokens sourced from a single W3C DTCG file and compiled via Style Dictionary",
5
5
  "keywords": [
6
6
  "react",