@kanso-labs/kanso-ui 0.12.4 → 0.13.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.
@@ -1,6 +1,14 @@
1
- import { RenderComponentProps } from "../../render/useRender.js";
1
+ import { AriaAttributes, DOMAttributes, ReactNode } from "react";
2
+ import { ClassNameOrFunction, LinkProps, LinkRenderProps, StyleOrFunction } from "react-aria-components";
2
3
  //#region src/components/link/index.d.ts
3
- type LinkProps = {
4
+ type GlobalEventKey = Exclude<keyof DOMAttributes<HTMLElement> & keyof LinkProps, 'onBlur' | 'onClick' | 'onFocus'>;
5
+ type LinkDOMProps = Omit<LinkProps, 'children' | 'className' | 'style' | GlobalEventKey> & Pick<DOMAttributes<HTMLElement>, GlobalEventKey>;
6
+ type LinkProps$1 = {
7
+ children?: ReactNode;
8
+ /** A function may compute the class from the link's render state. */
9
+ className?: ClassNameOrFunction<LinkRenderProps>;
10
+ /** A function may compute the style from the link's render state. */
11
+ style?: StyleOrFunction<LinkRenderProps>;
4
12
  /**
5
13
  * Which colour role to render in. `primary` marks the link out from the
6
14
  * text around it; `inherit` takes the surrounding colour and leans on the
@@ -17,14 +25,23 @@ type LinkProps = {
17
25
  * @default 'always'
18
26
  */
19
27
  underline?: LinkUnderline;
20
- } & RenderComponentProps<'a'>;
28
+ } & AriaAttributes & LinkDOMProps;
21
29
  type LinkTone = 'inherit' | 'primary';
22
30
  type LinkUnderline = 'always' | 'hover' | 'none';
23
31
  /**
24
32
  * A navigational link. It renders an `<a>` and sets no type of its own, so it
25
- * takes the size and face of the text it sits in.
33
+ * takes the size and face of the text it sits in. Without `href`, or while
34
+ * disabled, it is a span announced as a link instead, since a disabled
35
+ * anchor is no link at all.
36
+ *
37
+ * Behaviour is React Aria's: `onPress` fires for pointer, touch and keyboard
38
+ * alike, a `RouterProvider` above it turns a navigation into a client-side
39
+ * one, and a `Breadcrumbs` or `Menu` around it reaches it through context.
40
+ * `render` is React Aria's function form, handed the anchor's props to spread
41
+ * onto an element of its own. Every `aria-*` prop is forwarded to the element;
42
+ * React Aria alone would keep only the labelling ones.
26
43
  */
27
- declare function Link({ render, tone, underline, ...props }: LinkProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
44
+ declare function Link$1({ onKeyDown, onKeyUp, render, tone, underline, ...props }: LinkProps$1): import("react").JSX.Element;
28
45
  //#endregion
29
- export { type LinkProps, Link as default };
46
+ export { type LinkDOMProps, type LinkProps$1 as LinkProps, type LinkTone, type LinkUnderline, Link$1 as default };
30
47
  //# sourceMappingURL=index.d.ts.map
@@ -1,22 +1,32 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
- import { useRender } from "../../render/useRender.js";
3
- import { mergeStyles } from "../../styles/merge.js";
2
+ import { mergeStatefulStyles } from "../../styles/merge.js";
3
+ import { ariaAttributesOf, linkRenderer } from "../../render/aria.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Link } from "react-aria-components";
4
6
  //#region src/components/link/index.tsx
5
- const styles = { base: {
6
- kaIpWk: "x1tfhd1",
7
- kB7OPa: "x9f619",
8
- kkrTdU: "x1ypdohk",
9
- kjBf7l: "xrgy624",
10
- kInvED: "x1hl8ikr",
11
- k3XXqK: "x9v5kkp x1t137rt",
12
- kMeerF: "x1de99jn",
13
- kNySMw: "xyi4chj",
14
- kcSHmL: "x1ohr1zr",
15
- kIyJzY: "x1qno0dh",
16
- k1ekBW: "xz1df8t",
17
- kAMwcw: "xpc4ca7",
18
- $$css: true
19
- } };
7
+ const styles = {
8
+ base: {
9
+ kaIpWk: "x1tfhd1",
10
+ kB7OPa: "x9f619",
11
+ kkrTdU: "x1ypdohk",
12
+ kjBf7l: "xrgy624",
13
+ kInvED: "x1hl8ikr",
14
+ k3XXqK: "x9v5kkp x1t137rt",
15
+ kMeerF: "x1de99jn",
16
+ kNySMw: "xyi4chj",
17
+ kcSHmL: "x1ohr1zr",
18
+ kIyJzY: "x1qno0dh",
19
+ k1ekBW: "xz1df8t",
20
+ kAMwcw: "xpc4ca7",
21
+ $$css: true
22
+ },
23
+ disabled: {
24
+ kMwMTN: "x1xj74d8",
25
+ kkrTdU: "x1h6gzvc",
26
+ k1TLXF: "x1g6epwz",
27
+ $$css: true
28
+ }
29
+ };
20
30
  const tones = {
21
31
  inherit: {
22
32
  kMwMTN: "x1aetzt3 x1heor9g",
@@ -45,19 +55,30 @@ const underlines = {
45
55
  };
46
56
  /**
47
57
  * A navigational link. It renders an `<a>` and sets no type of its own, so it
48
- * takes the size and face of the text it sits in.
58
+ * takes the size and face of the text it sits in. Without `href`, or while
59
+ * disabled, it is a span announced as a link instead, since a disabled
60
+ * anchor is no link at all.
61
+ *
62
+ * Behaviour is React Aria's: `onPress` fires for pointer, touch and keyboard
63
+ * alike, a `RouterProvider` above it turns a navigation into a client-side
64
+ * one, and a `Breadcrumbs` or `Menu` around it reaches it through context.
65
+ * `render` is React Aria's function form, handed the anchor's props to spread
66
+ * onto an element of its own. Every `aria-*` prop is forwarded to the element;
67
+ * React Aria alone would keep only the labelling ones.
49
68
  */
50
- function Link({ render, tone = "primary", underline = "always", ...props$1 }) {
51
- return useRender({
52
- defaultTagName: "a",
53
- props: {
54
- ...props$1,
55
- ...mergeStyles(props(styles.base, tones[tone], underlines[underline]), props$1)
56
- },
57
- render
69
+ function Link$1({ onKeyDown, onKeyUp, render, tone = "primary", underline = "always", ...props$1 }) {
70
+ const element = {
71
+ aria: ariaAttributesOf(props$1),
72
+ onKeyDown,
73
+ onKeyUp
74
+ };
75
+ return /* @__PURE__ */ jsx(Link, {
76
+ render: linkRenderer(element, render),
77
+ ...props$1,
78
+ ...mergeStatefulStyles((state) => props(styles.base, tones[tone], underlines[underline], state.isDisabled && styles.disabled), props$1)
58
79
  });
59
80
  }
60
81
  //#endregion
61
- export { Link as default };
82
+ export { Link$1 as default };
62
83
 
63
84
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/link/index.tsx"],"sourcesContent":["import * 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, radii } from '../../tokens/design.tokens.stylex';\n\n// Deliberately sets no font size or family. A link is nearly always a run of\n// words inside something else — a paragraph, a list, a table cell — so its\n// type is the surrounding text's decision. What is here is only what makes it\n// read as a link: the colour, the rule under it, and the focus ring.\n//\n// The underline is on by default rather than an opt-in. Colour alone fails\n// anyone who cannot separate the two hues, so a link in prose that is not\n// underlined is only distinguishable to some readers.\nconst styles = {\n base: {\n kaIpWk: \"x1tfhd1\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kNySMw: \"xyi4chj\",\n kcSHmL: \"x1ohr1zr\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xz1df8t\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n }\n};\n\n// Each tone gets a hover that means something. `primary` is already the accent\n// colour, so hovering it deepens the rule instead of restating the colour;\n// `inherit` sits in body text, so hovering moves it to the accent — which is\n// what tells the reader the words are a link and not emphasis.\nconst tones = {\n inherit: {\n kMwMTN: \"x1aetzt3 x1heor9g\",\n k1TLXF: \"x1rdisx9 x1dbr5dg\",\n $$css: true\n },\n primary: {\n kMwMTN: \"x1mxwv8y\",\n k1TLXF: \"x1rdisx9 xfhk6l2\",\n $$css: true\n }\n};\nconst underlines = {\n always: {\n kMnn75: \"xujl8zx\",\n $$css: true\n },\n hover: {\n kMnn75: \"x1sur9pj xkrqix3\",\n $$css: true\n },\n none: {\n kMnn75: \"xkrqix3\",\n $$css: true\n }\n};\ntype LinkProps = {\n /**\n * Which colour role to render in. `primary` marks the link out from the\n * text around it; `inherit` takes the surrounding colour and leans on the\n * underline alone, for a link in a place already understood to be links —\n * a footer, a breadcrumb, a nav.\n * @default 'primary'\n */\n tone?: LinkTone;\n /**\n * When to draw the rule. Leave it at `always` in prose: without it, colour\n * is the only thing separating the link from the sentence, which some\n * readers cannot see. `hover` and `none` are for links whose position\n * already announces them, such as a row of footer links.\n * @default 'always'\n */\n underline?: LinkUnderline;\n} & RenderComponentProps<'a'>;\ntype LinkTone = 'inherit' | 'primary';\ntype LinkUnderline = 'always' | 'hover' | 'none';\n\n/**\n * A navigational link. It renders an `<a>` and sets no type of its own, so it\n * takes the size and face of the text it sits in.\n */\nfunction Link({\n render,\n tone = 'primary',\n underline = 'always',\n ...props\n}: LinkProps) {\n return useRender({\n defaultTagName: 'a',\n props: {\n ...props,\n ...mergeStyles(stylex.props(styles.base, tones[tone], underlines[underline]), props)\n },\n render\n });\n}\nexport type { LinkProps };\nexport default Link;"],"mappings":";;;;AAeA,MAAM,SAAS,EACb,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF;AAMA,MAAM,QAAQ;CACZ,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,aAAa;CACjB,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;CACT;AACF;;;;;AA0BA,SAAS,KAAK,EACZ,QACA,OAAO,WACP,YAAY,UACZ,GAAG,WACS;CACZ,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG,YAAY,MAAa,OAAO,MAAM,MAAM,OAAO,WAAW,UAAU,GAAG,OAAK;EACrF;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/link/index.tsx"],"sourcesContent":["import type { AriaAttributes, DOMAttributes, ReactNode } from 'react';\nimport type { ClassNameOrFunction, LinkRenderProps, LinkProps as RACLinkProps, StyleOrFunction } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { Link as RACLink } from 'react-aria-components';\nimport { ariaAttributesOf, linkRenderer } from '../../render/aria';\nimport { mergeStatefulStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, stateLayerOpacity } from '../../tokens/design.tokens.stylex';\nconst styles = {\n base: {\n kaIpWk: \"x1tfhd1\",\n kB7OPa: \"x9f619\",\n kkrTdU: \"x1ypdohk\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n kNySMw: \"xyi4chj\",\n kcSHmL: \"x1ohr1zr\",\n kIyJzY: \"x1qno0dh\",\n k1ekBW: \"xz1df8t\",\n kAMwcw: \"xpc4ca7\",\n $$css: true\n },\n disabled: {\n kMwMTN: \"x1xj74d8\",\n kkrTdU: \"x1h6gzvc\",\n k1TLXF: \"x1g6epwz\",\n $$css: true\n }\n};\nconst tones = {\n inherit: {\n kMwMTN: \"x1aetzt3 x1heor9g\",\n k1TLXF: \"x1rdisx9 x1dbr5dg\",\n $$css: true\n },\n primary: {\n kMwMTN: \"x1mxwv8y\",\n k1TLXF: \"x1rdisx9 xfhk6l2\",\n $$css: true\n }\n};\nconst underlines = {\n always: {\n kMnn75: \"xujl8zx\",\n $$css: true\n },\n hover: {\n kMnn75: \"x1sur9pj xkrqix3\",\n $$css: true\n },\n none: {\n kMnn75: \"xkrqix3\",\n $$css: true\n }\n};\n\n// React Aria types the global DOM events against the element it renders, and\n// a handler written for an <a> does not type-check against the <span> it\n// renders while disabled. The keys are retyped against HTMLElement here, as\n// Button's are, so one set of props serves both forms; the events React Aria\n// defines itself (press, hover, focus) keep its types, since it hands those\n// its own event objects.\ntype GlobalEventKey = Exclude<keyof DOMAttributes<HTMLElement> & keyof RACLinkProps, 'onBlur' | 'onClick' | 'onFocus'>;\ntype LinkDOMProps = Omit<RACLinkProps, 'children' | 'className' | 'style' | GlobalEventKey> & Pick<DOMAttributes<HTMLElement>, GlobalEventKey>;\ntype LinkProps = {\n children?: ReactNode;\n /** A function may compute the class from the link's render state. */\n className?: ClassNameOrFunction<LinkRenderProps>;\n /** A function may compute the style from the link's render state. */\n style?: StyleOrFunction<LinkRenderProps>;\n /**\n * Which colour role to render in. `primary` marks the link out from the\n * text around it; `inherit` takes the surrounding colour and leans on the\n * underline alone, for a link in a place already understood to be links —\n * a footer, a breadcrumb, a nav.\n * @default 'primary'\n */\n tone?: LinkTone;\n /**\n * When to draw the rule. Leave it at `always` in prose: without it, colour\n * is the only thing separating the link from the sentence, which some\n * readers cannot see. `hover` and `none` are for links whose position\n * already announces them, such as a row of footer links.\n * @default 'always'\n */\n underline?: LinkUnderline;\n} & AriaAttributes & LinkDOMProps;\ntype LinkTone = 'inherit' | 'primary';\ntype LinkUnderline = 'always' | 'hover' | 'none';\n\n/**\n * A navigational link. It renders an `<a>` and sets no type of its own, so it\n * takes the size and face of the text it sits in. Without `href`, or while\n * disabled, it is a span announced as a link instead, since a disabled\n * anchor is no link at all.\n *\n * Behaviour is React Aria's: `onPress` fires for pointer, touch and keyboard\n * alike, a `RouterProvider` above it turns a navigation into a client-side\n * one, and a `Breadcrumbs` or `Menu` around it reaches it through context.\n * `render` is React Aria's function form, handed the anchor's props to spread\n * onto an element of its own. Every `aria-*` prop is forwarded to the element;\n * React Aria alone would keep only the labelling ones.\n */\nfunction Link({\n onKeyDown,\n onKeyUp,\n render,\n tone = 'primary',\n underline = 'always',\n ...props\n}: LinkProps) {\n const element = {\n aria: ariaAttributesOf(props),\n onKeyDown,\n onKeyUp\n };\n return <RACLink render={linkRenderer(element, render)} {...props} {...mergeStatefulStyles((state: LinkRenderProps) => stylex.props(styles.base, tones[tone], underlines[underline], state.isDisabled && styles.disabled), props)} />;\n}\nexport type { LinkDOMProps, LinkProps, LinkTone, LinkUnderline };\nexport default Link;"],"mappings":";;;;;;AAQA,MAAM,SAAS;CACb,MAAM;EACJ,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,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,QAAQ;CACZ,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AACA,MAAM,aAAa;CACjB,QAAQ;EACN,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,OAAO;CACT;CACA,MAAM;EACJ,QAAQ;EACR,OAAO;CACT;AACF;;;;;;;;;;;;;;AAiDA,SAAS,OAAK,EACZ,WACA,SACA,QACA,OAAO,WACP,YAAY,UACZ,GAAG,WACS;CACZ,MAAM,UAAU;EACd,MAAM,iBAAiB,OAAK;EAC5B;EACA;CACF;CACA,OAAO,oBAAC,MAAD;EAAS,QAAQ,aAAa,SAAS,MAAM;EAAG,GAAI;EAAO,GAAI,qBAAqB,UAA2B,MAAa,OAAO,MAAM,MAAM,OAAO,WAAW,YAAY,MAAM,cAAc,OAAO,QAAQ,GAAG,OAAK;CAAE,CAAA;AACnO"}
@@ -1,6 +1,6 @@
1
- import { RenderComponentProps } from "../../render/useRender.js";
1
+ import { SeparatorProps } from "react-aria-components";
2
2
  //#region src/components/separator/index.d.ts
3
- type SeparatorProps = RenderComponentProps<'div'> & {
3
+ type SeparatorProps$1 = Omit<SeparatorProps, 'orientation'> & {
4
4
  /**
5
5
  * Which way the rule runs. A vertical separator takes its length from a
6
6
  * flex or grid parent and has none of its own.
@@ -10,15 +10,17 @@ type SeparatorProps = RenderComponentProps<'div'> & {
10
10
  };
11
11
  /**
12
12
  * A 1px rule between items. The orientation drives the accessibility tree as
13
- * well as which side the rule is drawn on: `aria-orientation` is spelled out
14
- * in both directions rather than leaving the horizontal case to the role's
15
- * implicit value.
13
+ * well as which side the rule is drawn on: horizontal renders an `<hr>`,
14
+ * whose role and orientation are implicit, and vertical a `<div>` given the
15
+ * separator role and `aria-orientation="vertical"`.
16
16
  *
17
- * A styled element rather than a primitive from the behaviour library: a
18
- * separator has no behaviour, and the library's own would drop the
19
- * `aria-orientation` written here on its way to the DOM.
17
+ * React Aria's rather than a styled element of the library's own, so a
18
+ * `Menu` or `Toolbar` around it reaches it through context a separator
19
+ * between menu items is part of the collection, and one in a toolbar takes
20
+ * the toolbar's orientation. `elementType` picks a different element, and
21
+ * `render` is React Aria's function form.
20
22
  */
21
- declare function Separator({ orientation, render, ...props }: SeparatorProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
23
+ declare function Separator$1({ orientation, ...props }: SeparatorProps$1): import("react").JSX.Element;
22
24
  //#endregion
23
- export { type SeparatorProps, Separator as default };
25
+ export { type SeparatorProps$1 as SeparatorProps, Separator$1 as default };
24
26
  //# sourceMappingURL=index.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
2
- import { useRender } from "../../render/useRender.js";
3
2
  import { mergeStyles } from "../../styles/merge.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { Separator } from "react-aria-components";
4
5
  //#region src/components/separator/index.tsx
5
6
  const styles = {
6
7
  base: {
@@ -24,27 +25,24 @@ const styles = {
24
25
  };
25
26
  /**
26
27
  * A 1px rule between items. The orientation drives the accessibility tree as
27
- * well as which side the rule is drawn on: `aria-orientation` is spelled out
28
- * in both directions rather than leaving the horizontal case to the role's
29
- * implicit value.
28
+ * well as which side the rule is drawn on: horizontal renders an `<hr>`,
29
+ * whose role and orientation are implicit, and vertical a `<div>` given the
30
+ * separator role and `aria-orientation="vertical"`.
30
31
  *
31
- * A styled element rather than a primitive from the behaviour library: a
32
- * separator has no behaviour, and the library's own would drop the
33
- * `aria-orientation` written here on its way to the DOM.
32
+ * React Aria's rather than a styled element of the library's own, so a
33
+ * `Menu` or `Toolbar` around it reaches it through context a separator
34
+ * between menu items is part of the collection, and one in a toolbar takes
35
+ * the toolbar's orientation. `elementType` picks a different element, and
36
+ * `render` is React Aria's function form.
34
37
  */
35
- function Separator({ orientation = "horizontal", render, ...props$1 }) {
36
- return useRender({
37
- defaultTagName: "div",
38
- props: {
39
- "aria-orientation": orientation,
40
- role: "separator",
41
- ...props$1,
42
- ...mergeStyles(props(styles.base, styles[orientation]), props$1)
43
- },
44
- render
38
+ function Separator$1({ orientation = "horizontal", ...props$1 }) {
39
+ return /* @__PURE__ */ jsx(Separator, {
40
+ orientation,
41
+ ...props$1,
42
+ ...mergeStyles(props(styles.base, styles[orientation]), props$1)
45
43
  });
46
44
  }
47
45
  //#endregion
48
- export { Separator as default };
46
+ export { Separator$1 as default };
49
47
 
50
48
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/separator/index.tsx"],"sourcesContent":["import * 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 } from '../../tokens/design.tokens.stylex';\n\n// A divider is the same colour as a border, so it draws from outlineVariant\n// rather than a role of its own — the design system treats the two as one\n// decision, and a separator that drifted from the borders around it would\n// read as a mistake.\n//\n// Drawn as a background on a 1px box rather than as a border, so the rule is\n// the element itself. A border would leave the element's own box at zero\n// size, which makes it invisible to flex `gap` and to anything measuring it.\n//\n// Vertical has no length of its own. `alignSelf: stretch` takes it from the\n// flex or grid parent, since a divider between two rows should match\n// whatever they turn out to be rather than being told a height at the call\n// site. In a plain block parent there is nothing to stretch to and it will\n// have no height — that is the documented cost of the prop.\nconst styles = {\n base: {\n kWkggS: \"x1l12bh\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kmuXW: \"x2lah0s\",\n kogj98: \"x1ghz6dp\",\n $$css: true\n },\n horizontal: {\n kZKoxP: \"xjm9jq1\",\n kzqmXN: \"xh8yej3\",\n $$css: true\n },\n vertical: {\n kSGwAc: \"xkh2ocl\",\n kzqmXN: \"x1i1rx1s\",\n $$css: true\n }\n};\ntype SeparatorProps = RenderComponentProps<'div'> & {\n /**\n * Which way the rule runs. A vertical separator takes its length from a\n * flex or grid parent and has none of its own.\n * @default 'horizontal'\n */\n orientation?: 'horizontal' | 'vertical';\n};\n\n/**\n * A 1px rule between items. The orientation drives the accessibility tree as\n * well as which side the rule is drawn on: `aria-orientation` is spelled out\n * in both directions rather than leaving the horizontal case to the role's\n * implicit value.\n *\n * A styled element rather than a primitive from the behaviour library: a\n * separator has no behaviour, and the library's own would drop the\n * `aria-orientation` written here on its way to the DOM.\n */\nfunction Separator({\n orientation = 'horizontal',\n render,\n ...props\n}: SeparatorProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n 'aria-orientation': orientation,\n role: 'separator',\n ...props,\n ...mergeStyles(stylex.props(styles.base, styles[orientation]), props)\n },\n render\n });\n}\nexport type { SeparatorProps };\nexport default Separator;"],"mappings":";;;;AAqBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,OAAO;CACT;CACA,YAAY;EACV,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;;;;;;;AAoBA,SAAS,UAAU,EACjB,cAAc,cACd,QACA,GAAG,WACc;CACjB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,oBAAoB;GACpB,MAAM;GACN,GAAG;GACH,GAAG,YAAY,MAAa,OAAO,MAAM,OAAO,YAAY,GAAG,OAAK;EACtE;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/separator/index.tsx"],"sourcesContent":["import type { SeparatorProps as RACSeparatorProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { Separator as RACSeparator } from 'react-aria-components';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors } from '../../tokens/design.tokens.stylex';\n\n// A divider is the same colour as a border, so it draws from outlineVariant\n// rather than a role of its own — the design system treats the two as one\n// decision, and a separator that drifted from the borders around it would\n// read as a mistake.\n//\n// Drawn as a background on a 1px box rather than as a border, so the rule is\n// the element itself. A border would leave the element's own box at zero\n// size, which makes it invisible to flex `gap` and to anything measuring it.\n// The horizontal element is an <hr>, which arrives with a border and a\n// margin of its own; both are zeroed here so it is the same 1px box a <div>\n// would be.\n//\n// Vertical has no length of its own. `alignSelf: stretch` takes it from the\n// flex or grid parent, since a divider between two rows should match\n// whatever they turn out to be rather than being told a height at the call\n// site. In a plain block parent there is nothing to stretch to and it will\n// have no height — that is the documented cost of the prop.\nconst styles = {\n base: {\n kWkggS: \"x1l12bh\",\n kMzoRj: \"xc342km\",\n kB7OPa: \"x9f619\",\n kmuXW: \"x2lah0s\",\n kogj98: \"x1ghz6dp\",\n $$css: true\n },\n horizontal: {\n kZKoxP: \"xjm9jq1\",\n kzqmXN: \"xh8yej3\",\n $$css: true\n },\n vertical: {\n kSGwAc: \"xkh2ocl\",\n kzqmXN: \"x1i1rx1s\",\n $$css: true\n }\n};\ntype SeparatorProps = Omit<RACSeparatorProps, 'orientation'> & {\n /**\n * Which way the rule runs. A vertical separator takes its length from a\n * flex or grid parent and has none of its own.\n * @default 'horizontal'\n */\n orientation?: 'horizontal' | 'vertical';\n};\n\n/**\n * A 1px rule between items. The orientation drives the accessibility tree as\n * well as which side the rule is drawn on: horizontal renders an `<hr>`,\n * whose role and orientation are implicit, and vertical a `<div>` given the\n * separator role and `aria-orientation=\"vertical\"`.\n *\n * React Aria's rather than a styled element of the library's own, so a\n * `Menu` or `Toolbar` around it reaches it through context — a separator\n * between menu items is part of the collection, and one in a toolbar takes\n * the toolbar's orientation. `elementType` picks a different element, and\n * `render` is React Aria's function form.\n */\nfunction Separator({\n orientation = 'horizontal',\n ...props\n}: SeparatorProps) {\n return <RACSeparator orientation={orientation} {...props} {...mergeStyles(stylex.props(styles.base, styles[orientation]), props)} />;\n}\nexport type { SeparatorProps };\nexport default Separator;"],"mappings":";;;;;AAwBA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,OAAO;CACT;CACA,YAAY;EACV,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;;;;;;;;;;;;;AAsBA,SAAS,YAAU,EACjB,cAAc,cACd,GAAG,WACc;CACjB,OAAO,oBAAC,WAAD;EAA2B;EAAa,GAAI;EAAO,GAAI,YAAY,MAAa,OAAO,MAAM,OAAO,YAAY,GAAG,OAAK;CAAE,CAAA;AACnI"}
@@ -30,6 +30,10 @@ type TextFieldProps$1 = {
30
30
  * `onChange` is handed the string, not the event. The call site's
31
31
  * `className` and `style` land on the field as a whole, which is the element
32
32
  * a layout positions.
33
+ *
34
+ * The box, label, input and message are the field chrome in `src/field`,
35
+ * shared with every other field; this component is what React Aria's
36
+ * `TextField` puts around them.
33
37
  */
34
38
  declare function TextField$1({ description, error, isDisabled, label, numeric, ...props }: TextFieldProps$1): import("react").JSX.Element;
35
39
  //#endregion
@@ -1,7 +1,9 @@
1
+ import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
1
2
  import { mergeStatefulStyles } from "../../styles/merge.js";
2
- import { useCallback, useState } from "react";
3
+ import { FieldBox, FieldInput, FieldMessage } from "../../field/index.js";
4
+ import { FIELD_VALIDATION_BEHAVIOR, fieldStyles } from "../../field/root.js";
3
5
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import { Input, Label, Text, TextField } from "react-aria-components";
6
+ import { TextField } from "react-aria-components";
5
7
  //#region src/components/text-field/index.tsx
6
8
  /**
7
9
  * A labelled single-line input. Its value is React Aria's: pass `value` with
@@ -9,57 +11,24 @@ import { Input, Label, Text, TextField } from "react-aria-components";
9
11
  * `onChange` is handed the string, not the event. The call site's
10
12
  * `className` and `style` land on the field as a whole, which is the element
11
13
  * a layout positions.
14
+ *
15
+ * The box, label, input and message are the field chrome in `src/field`,
16
+ * shared with every other field; this component is what React Aria's
17
+ * `TextField` puts around them.
12
18
  */
13
- function TextField$1({ description, error, isDisabled = false, label, numeric = false, ...props }) {
14
- const invalid = error !== void 0;
15
- const [focused, setFocused] = useState(false);
16
- const handleFocus = useCallback(() => {
17
- setFocused(true);
18
- }, []);
19
- const handleBlur = useCallback(() => {
20
- setFocused(false);
21
- }, []);
19
+ function TextField$1({ description, error, isDisabled = false, label, numeric = false, ...props$1 }) {
22
20
  return /* @__PURE__ */ jsxs(TextField, {
23
21
  isDisabled,
24
- isInvalid: invalid,
25
- validationBehavior: "aria",
26
- ...props,
27
- ...mergeStatefulStyles({ className: "x9f619 x78zum5 xdt5ytf" }, props),
28
- children: [/* @__PURE__ */ jsxs("div", {
29
- onBlur: handleBlur,
30
- onFocus: handleFocus,
31
- ...{
32
- 0: { className: "x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x89kqus x18rfq6m x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7" },
33
- 2: { className: "x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 x1lxxh4i x1d6xoej" },
34
- 1: { className: "xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1" },
35
- 3: { className: "xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1" }
36
- }[!!invalid << 1 | !!isDisabled << 0],
37
- children: [/* @__PURE__ */ jsx(Label, {
38
- ...{
39
- 0: { className: "x1w5n3ug xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7" },
40
- 4: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1xj74d8" },
41
- 2: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj" },
42
- 6: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj" },
43
- 1: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
44
- 5: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
45
- 3: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
46
- 7: { className: "xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" }
47
- }[!!isDisabled << 2 | !!invalid << 1 | !!(!isDisabled && !invalid && focused) << 0],
48
- children: label
49
- }), /* @__PURE__ */ jsx(Input, { ...{
50
- 0: { className: "xjbqb8w xc342km x9f619 x139gbkf x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv" },
51
- 2: { className: "xjbqb8w xc342km x9f619 x139gbkf x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b" },
52
- 1: { className: "xjbqb8w xc342km x9f619 x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv x1xj74d8" },
53
- 3: { className: "xjbqb8w xc342km x9f619 x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b x1xj74d8" }
54
- }[!!numeric << 1 | !!isDisabled << 0] })]
55
- }), invalid ? /* @__PURE__ */ jsx(Text, {
56
- slot: "errorMessage",
57
- className: "x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi x4ii1qj",
58
- children: error
59
- }) : description === void 0 ? null : /* @__PURE__ */ jsx(Text, {
60
- slot: "description",
61
- className: "x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi",
62
- children: description
22
+ isInvalid: error !== void 0,
23
+ validationBehavior: FIELD_VALIDATION_BEHAVIOR,
24
+ ...props$1,
25
+ ...mergeStatefulStyles(props(fieldStyles.root), props$1),
26
+ children: [/* @__PURE__ */ jsx(FieldBox, {
27
+ label,
28
+ children: /* @__PURE__ */ jsx(FieldInput, { numeric })
29
+ }), /* @__PURE__ */ jsx(FieldMessage, {
30
+ description,
31
+ error
63
32
  })]
64
33
  });
65
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/text-field/index.tsx"],"sourcesContent":["import type { TextFieldProps as RACTextFieldProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { useCallback, useState } from 'react';\nimport { Input, Label, TextField as RACTextField, Text } 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 focus indicator is an inset box-shadow on the bottom edge rather than a\n// border that thickens. A real border going 1px -> 2px on focus grows the\n// box, which pushes every sibling below it down by a pixel — so a form\n// twitches each time focus moves between its fields. A shadow is drawn inside\n// the box and changes nothing about its size.\n//\n// The label sits at a fixed size at the top rather than floating up out of\n// the input on focus: the design draws it small and in place at all times, so\n// there is no transition between two positions to get right.\n//\n// The label's colour follows the input's focus, which no selector on the\n// label alone can express — the label is the input's sibling, not its\n// ancestor. The box tracks whether focus is within it, through the focus\n// events React bubbles, and the label takes `labelFocused` from that state.\n\ntype TextFieldProps = {\n /**\n * A hint shown under the field. Replaced by `error` when there is one, so\n * the two never stack.\n */\n description?: string;\n /**\n * The problem with the current value, in words. Its presence is what puts\n * the field in its error state — the message, the red underline, and\n * `aria-invalid` all follow from it.\n */\n error?: string;\n /**\n * What the field is for. Required rather than optional: a text field with\n * no label is a box a screen reader cannot name.\n */\n label: string;\n /**\n * Renders the value in the mono face with tabular figures, for amounts and\n * other numbers meant to be compared down a column.\n * @default false\n */\n numeric?: boolean;\n} & Omit<RACTextFieldProps, 'children' | 'isInvalid' | 'validationBehavior'>;\n\n/**\n * A labelled single-line input. Its value is React Aria's: pass `value` with\n * `onChange` to control it, or `defaultValue` to let it keep its own — and\n * `onChange` is handed the string, not the event. The call site's\n * `className` and `style` land on the field as a whole, which is the element\n * a layout positions.\n */\nfunction TextField({\n description,\n error,\n isDisabled = false,\n label,\n numeric = false,\n ...props\n}: TextFieldProps) {\n const invalid = error !== undefined;\n\n // Focus events bubble in React, so the box hears its input gain and lose\n // focus without the input being told anything.\n const [focused, setFocused] = useState(false);\n const handleFocus = useCallback(() => {\n setFocused(true);\n }, []);\n const handleBlur = useCallback(() => {\n setFocused(false);\n }, []);\n return <RACTextField isDisabled={isDisabled} isInvalid={invalid}\n // The message is this component's to show, so validation only marks\n // the control rather than surfacing the browser's own constraint UI.\n validationBehavior=\"aria\" {...props} {...mergeStatefulStyles({\n className: \"x9f619 x78zum5 xdt5ytf\"\n }, props)}>\n <div onBlur={handleBlur} onFocus={handleFocus} {...{\n 0: {\n className: \"x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x89kqus x18rfq6m x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7\"\n },\n 2: {\n className: \"x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 x1lxxh4i x1d6xoej\"\n },\n 1: {\n className: \"xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1\"\n },\n 3: {\n className: \"xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1\"\n }\n }[!!invalid << 1 | !!isDisabled << 0]}>\n <Label {...{\n 0: {\n className: \"x1w5n3ug xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7\"\n },\n 4: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1xj74d8\"\n },\n 2: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj\"\n },\n 6: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj\"\n },\n 1: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 5: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 3: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 7: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x1we8soy x19v39ok x12utw95 xvzb9hk x10l6tqk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n }\n }[!!isDisabled << 2 | !!invalid << 1 | !!(!isDisabled && !invalid && focused) << 0]}>\n {label}\n </Label>\n <Input {...{\n 0: {\n className: \"xjbqb8w xc342km x9f619 x139gbkf x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv\"\n },\n 2: {\n className: \"xjbqb8w xc342km x9f619 x139gbkf x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b\"\n },\n 1: {\n className: \"xjbqb8w xc342km x9f619 x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv x1xj74d8\"\n },\n 3: {\n className: \"xjbqb8w xc342km x9f619 x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b x1xj74d8\"\n }\n }[!!numeric << 1 | !!isDisabled << 0]} />\n </div>\n {invalid ? <Text slot=\"errorMessage\" className=\"x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi x4ii1qj\">\n {error}\n </Text> : description === undefined ? null : <Text slot=\"description\" className=\"x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi\">\n {description}\n </Text>}\n </RACTextField>;\n}\nexport type { TextFieldProps };\nexport default TextField;"],"mappings":";;;;;;;;;;;;AAuDA,SAAS,YAAU,EACjB,aACA,OACA,aAAa,OACb,OACA,UAAU,OACV,GAAG,SACc;CACjB,MAAM,UAAU,UAAU,KAAA;CAI1B,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,cAAc,kBAAkB;EACpC,WAAW,IAAI;CACjB,GAAG,CAAA,CAAE;CACL,MAAM,aAAa,kBAAkB;EACnC,WAAW,KAAK;CAClB,GAAG,CAAA,CAAE;CACL,OAAO,qBAAC,WAAD;EAA0B;EAAY,WAAW;EAGxD,oBAAmB;EAAO,GAAI;EAAO,GAAI,oBAAoB,EAC3D,WAAW,yBACb,GAAG,KAAK;EALD,UAAA,CAMH,qBAAC,OAAD;GAAK,QAAQ;GAAY,SAAS;GAAa,GAAI;IACnD,GAAG,EACD,WAAW,uIACb;IACA,GAAG,EACD,WAAW,wIACb;IACA,GAAG,EACD,WAAW,8HACb;IACA,GAAG,EACD,WAAW,8HACb;GACF,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,cAAc;GAbjC,UAAA,CAcE,oBAAC,OAAD;IAAO,GAAI;KACX,GAAG,EACD,WAAW,yGACb;KACA,GAAG,EACD,WAAW,yGACb;KACA,GAAG,EACD,WAAW,wGACb;KACA,GAAG,EACD,WAAW,wGACb;KACA,GAAG,EACD,WAAW,yGACb;KACA,GAAG,EACD,WAAW,yGACb;KACA,GAAG,EACD,WAAW,yGACb;KACA,GAAG,EACD,WAAW,yGACb;IACF,EAAE,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,WAAW,YAAY;IAC5E,UAAA;GACI,CAAA,GACP,oBAAC,OAAD,EAAO,GAAI;IACX,GAAG,EACD,WAAW,iHACb;IACA,GAAG,EACD,WAAW,wHACb;IACA,GAAG,EACD,WAAW,iHACb;IACA,GAAG,EACD,WAAW,wHACb;GACF,EAAE,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,cAAc,GAAG,CAAA,CACjC;EACJ,CAAA,GAAA,UAAU,oBAAC,MAAD;GAAM,MAAK;GAAe,WAAU;GAC1C,UAAA;EACG,CAAA,IAAI,gBAAgB,KAAA,IAAY,OAAO,oBAAC,MAAD;GAAM,MAAK;GAAc,WAAU;GAC7E,UAAA;EACG,CAAA,CACI;;AAClB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/text-field/index.tsx"],"sourcesContent":["import type { TextFieldProps as RACTextFieldProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { TextField as RACTextField } from 'react-aria-components';\nimport { FieldBox, FieldInput, FieldMessage } from '../../field';\nimport { FIELD_VALIDATION_BEHAVIOR, fieldStyles } from '../../field/root';\nimport { mergeStatefulStyles } from '../../styles/merge';\ntype TextFieldProps = {\n /**\n * A hint shown under the field. Replaced by `error` when there is one, so\n * the two never stack.\n */\n description?: string;\n /**\n * The problem with the current value, in words. Its presence is what puts\n * the field in its error state — the message, the red underline, and\n * `aria-invalid` all follow from it.\n */\n error?: string;\n /**\n * What the field is for. Required rather than optional: a text field with\n * no label is a box a screen reader cannot name.\n */\n label: string;\n /**\n * Renders the value in the mono face with tabular figures, for amounts and\n * other numbers meant to be compared down a column.\n * @default false\n */\n numeric?: boolean;\n} & Omit<RACTextFieldProps, 'children' | 'isInvalid' | 'validationBehavior'>;\n\n/**\n * A labelled single-line input. Its value is React Aria's: pass `value` with\n * `onChange` to control it, or `defaultValue` to let it keep its own — and\n * `onChange` is handed the string, not the event. The call site's\n * `className` and `style` land on the field as a whole, which is the element\n * a layout positions.\n *\n * The box, label, input and message are the field chrome in `src/field`,\n * shared with every other field; this component is what React Aria's\n * `TextField` puts around them.\n */\nfunction TextField({\n description,\n error,\n isDisabled = false,\n label,\n numeric = false,\n ...props\n}: TextFieldProps) {\n return <RACTextField isDisabled={isDisabled} isInvalid={error !== undefined} validationBehavior={FIELD_VALIDATION_BEHAVIOR} {...props} {...mergeStatefulStyles(stylex.props(fieldStyles.root), props)}>\n <FieldBox label={label}>\n <FieldInput numeric={numeric} />\n </FieldBox>\n <FieldMessage description={description} error={error} />\n </RACTextField>;\n}\nexport type { TextFieldProps };\nexport default TextField;"],"mappings":";;;;;;;;;;;;;;;;;;AA0CA,SAAS,YAAU,EACjB,aACA,OACA,aAAa,OACb,OACA,UAAU,OACV,GAAG,WACc;CACjB,OAAO,qBAAC,WAAD;EAA0B;EAAY,WAAW,UAAU,KAAA;EAAW,oBAAoB;EAA2B,GAAI;EAAO,GAAI,oBAAoB,MAAa,YAAY,IAAI,GAAG,OAAK;EAA7L,UAAA,CACH,oBAAC,UAAD;GAAiB;GACf,UAAA,oBAAC,YAAD,EAAqB,QAAQ,CAAA;EACrB,CAAA,GACV,oBAAC,cAAD;GAA2B;GAAoB;EAAM,CAAA,CACzC;;AAClB"}
@@ -0,0 +1,157 @@
1
+ import { mergeStatefulStyles, mergeStyles } from "../styles/merge.js";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { c } from "react/compiler-runtime";
4
+ import { FieldError, Group, Input, Label, Text } from "react-aria-components";
5
+ //#region src/field/index.tsx
6
+ function boxContent(label, children) {
7
+ return (state) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(FieldLabel, {
8
+ state,
9
+ className: "x1we8soy x19v39ok x10l6tqk",
10
+ children: label
11
+ }), children] });
12
+ }
13
+ function boxStyles(state) {
14
+ return {
15
+ 0: { className: "x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x89kqus x18rfq6m x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7" },
16
+ 2: { className: "x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 x1lxxh4i x1d6xoej" },
17
+ 1: { className: "xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1" },
18
+ 3: { className: "xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1" }
19
+ }[!!state.isInvalid << 1 | !!state.isDisabled << 0];
20
+ }
21
+ /**
22
+ * The filled box a control sits in, with its label. React Aria's `Group`, so
23
+ * the field around it hands down `isDisabled` and `isInvalid` through context
24
+ * and the box reports focus within it as render state, which is what the
25
+ * label's colour follows. A field that provides no group context — one built
26
+ * on a button rather than an input — passes the two states itself.
27
+ */
28
+ function FieldBox(t0) {
29
+ const $ = c(14);
30
+ let T0;
31
+ let children;
32
+ let label;
33
+ let t1;
34
+ let t2;
35
+ if ($[0] !== t0) {
36
+ const { children: t3, label: t4, ...props } = t0;
37
+ children = t3;
38
+ label = t4;
39
+ T0 = Group;
40
+ t1 = props;
41
+ t2 = mergeStatefulStyles(boxStyles, props);
42
+ $[0] = t0;
43
+ $[1] = T0;
44
+ $[2] = children;
45
+ $[3] = label;
46
+ $[4] = t1;
47
+ $[5] = t2;
48
+ } else {
49
+ T0 = $[1];
50
+ children = $[2];
51
+ label = $[3];
52
+ t1 = $[4];
53
+ t2 = $[5];
54
+ }
55
+ let t3;
56
+ if ($[6] !== children || $[7] !== label) {
57
+ t3 = boxContent(label, children);
58
+ $[6] = children;
59
+ $[7] = label;
60
+ $[8] = t3;
61
+ } else t3 = $[8];
62
+ let t4;
63
+ if ($[9] !== T0 || $[10] !== t1 || $[11] !== t2 || $[12] !== t3) {
64
+ t4 = /* @__PURE__ */ jsx(T0, {
65
+ ...t1,
66
+ ...t2,
67
+ children: t3
68
+ });
69
+ $[9] = T0;
70
+ $[10] = t1;
71
+ $[11] = t2;
72
+ $[12] = t3;
73
+ $[13] = t4;
74
+ } else t4 = $[13];
75
+ return t4;
76
+ }
77
+ /**
78
+ * The text control inside a {@link FieldBox}. React Aria's `Input`, which
79
+ * takes its label association, value and validation from the field around it
80
+ * and reports its disabled state as render state.
81
+ */
82
+ function FieldInput({ numeric = false, ...props }) {
83
+ return /* @__PURE__ */ jsx(Input, {
84
+ ...props,
85
+ ...mergeStatefulStyles((state) => ({
86
+ 0: { className: "xjbqb8w xc342km x9f619 x139gbkf x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv" },
87
+ 2: { className: "xjbqb8w xc342km x9f619 x139gbkf x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b" },
88
+ 1: { className: "xjbqb8w xc342km x9f619 x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv x1xj74d8" },
89
+ 3: { className: "xjbqb8w xc342km x9f619 x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b x1xj74d8" }
90
+ })[!!numeric << 1 | !!state.isDisabled << 0], props)
91
+ });
92
+ }
93
+ /**
94
+ * A field's label: the type and colour alone, positioned by whatever renders
95
+ * it. React Aria's `Label`, which the field around it associates with its
96
+ * control through context.
97
+ */
98
+ const NO_STATE = {};
99
+ function FieldLabel({ state = NO_STATE, ...props }) {
100
+ const { isDisabled = false, isFocusWithin = false, isInvalid = false } = state;
101
+ return /* @__PURE__ */ jsx(Label, {
102
+ ...props,
103
+ ...mergeStyles({
104
+ 0: { className: "x1w5n3ug xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7" },
105
+ 4: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1xj74d8" },
106
+ 2: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj" },
107
+ 6: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj" },
108
+ 1: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
109
+ 5: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
110
+ 3: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" },
111
+ 7: { className: "xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y" }
112
+ }[!!isDisabled << 2 | !!isInvalid << 1 | !!(!isDisabled && !isInvalid && isFocusWithin) << 0], props)
113
+ });
114
+ }
115
+ /**
116
+ * The line under a field: the error while there is one, the description
117
+ * otherwise. The error goes through React Aria's `FieldError`, which renders
118
+ * only while the field is invalid and falls back to whatever validation
119
+ * errors the field carries when no message is given — which is how a `Form`
120
+ * with server-side errors will reach it without any field changing.
121
+ */
122
+ function FieldMessage(t0) {
123
+ const $ = c(8);
124
+ const { description, error } = t0;
125
+ let t1;
126
+ if ($[0] !== error) {
127
+ t1 = /* @__PURE__ */ jsx(FieldError, {
128
+ className: "x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi x4ii1qj",
129
+ children: error
130
+ });
131
+ $[0] = error;
132
+ $[1] = t1;
133
+ } else t1 = $[1];
134
+ let t2;
135
+ if ($[2] !== description || $[3] !== error) {
136
+ t2 = error === void 0 && description !== void 0 ? /* @__PURE__ */ jsx(Text, {
137
+ slot: "description",
138
+ className: "x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi",
139
+ children: description
140
+ }) : null;
141
+ $[2] = description;
142
+ $[3] = error;
143
+ $[4] = t2;
144
+ } else t2 = $[4];
145
+ let t3;
146
+ if ($[5] !== t1 || $[6] !== t2) {
147
+ t3 = /* @__PURE__ */ jsxs(Fragment, { children: [t1, t2] });
148
+ $[5] = t1;
149
+ $[6] = t2;
150
+ $[7] = t3;
151
+ } else t3 = $[7];
152
+ return t3;
153
+ }
154
+ //#endregion
155
+ export { FieldBox, FieldInput, FieldLabel, FieldMessage };
156
+
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["props","error","description"],"sources":["../../src/field/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport type { GroupProps, GroupRenderProps, InputProps, InputRenderProps, LabelProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { FieldError, Group, Input, Label, Text } 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 chrome every field shares: the filled box with its label at the top, the\n// control inside it, and the line of supporting text under it. TextField drew\n// all of it on its own until the coverage plan brought a dozen more fields,\n// each of which would otherwise have written the same box a second time.\n//\n// Not a component of the library's own and not exported. Each field is still\n// React Aria's field component — TextField, NumberField, DateField — and these\n// are the parts it renders inside, which is what keeps the label association,\n// the description and error wiring, and validation on React Aria's side.\n//\n// The focus indicator is an inset box-shadow on the bottom edge rather than a\n// border that thickens. A real border going 1px -> 2px on focus grows the\n// box, which pushes every sibling below it down by a pixel — so a form\n// twitches each time focus moves between its fields. A shadow is drawn inside\n// the box and changes nothing about its size.\n//\n// The label sits at a fixed size at the top rather than floating up out of\n// the control on focus: the design draws it small and in place at all times,\n// so there is no transition between two positions to get right.\n//\n// The label's colour follows the control's focus, which no selector on the\n// label alone can express — the label is the control's sibling, not its\n// ancestor. The box is React Aria's Group, which reports focus within it as\n// render state, and the label takes `labelFocused` from that.\n\ntype FieldBoxProps = Omit<GroupProps, 'children'> & {\n children?: ReactNode;\n /** What the field is for, drawn small at the top of the box. */\n label: string;\n};\ntype FieldInputProps = InputProps & {\n /**\n * Renders the value in the mono face with tabular figures, for amounts and\n * other numbers meant to be compared down a column.\n * @default false\n */\n numeric?: boolean;\n};\ntype FieldLabelProps = LabelProps & {\n /**\n * The states the colour follows. Disabled wins over error, and error over\n * focus, so a focused invalid field keeps its error colour.\n */\n state?: Partial<FieldLabelState>;\n};\ntype FieldLabelState = Pick<GroupRenderProps, 'isDisabled' | 'isFocusWithin' | 'isInvalid'>;\ninterface FieldMessageProps {\n /**\n * A hint shown under the field. Replaced by `error` when there is one, so\n * the two never stack.\n */\n description?: string | undefined;\n /** The problem with the current value, in words. */\n error?: string | undefined;\n}\n\n// Written as a call rather than a function literal 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.\nfunction boxContent(label: string, children: ReactNode) {\n return (state: GroupRenderProps) => <>\n <FieldLabel state={state} className=\"x1we8soy x19v39ok x10l6tqk\">\n {label}\n </FieldLabel>\n {children}\n </>;\n}\nfunction boxStyles(state: GroupRenderProps) {\n return {\n 0: {\n className: \"x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x89kqus x18rfq6m x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7\"\n },\n 2: {\n className: \"x1rrhr5q xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 x1lxxh4i x1d6xoej\"\n },\n 1: {\n className: \"xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1\"\n },\n 3: {\n className: \"xnnlda6 x16uus16 xbiv7yw xirz1nw xzcck0f x9f619 x18d9i69 xi7mcox x790zyz x1n2onr6 x1qno0dh xkdsq27 xpc4ca7 xepofeg x1pqbjc1\"\n }\n }[!!state.isInvalid << 1 | !!state.isDisabled << 0];\n}\n\n/**\n * The filled box a control sits in, with its label. React Aria's `Group`, so\n * the field around it hands down `isDisabled` and `isInvalid` through context\n * and the box reports focus within it as render state, which is what the\n * label's colour follows. A field that provides no group context — one built\n * on a button rather than an input — passes the two states itself.\n */\nfunction FieldBox({\n children,\n label,\n ...props\n}: FieldBoxProps) {\n return <Group {...props} {...mergeStatefulStyles(boxStyles, props)}>\n {boxContent(label, children)}\n </Group>;\n}\n\n/**\n * The text control inside a {@link FieldBox}. React Aria's `Input`, which\n * takes its label association, value and validation from the field around it\n * and reports its disabled state as render state.\n */\nfunction FieldInput({\n numeric = false,\n ...props\n}: FieldInputProps) {\n return <Input {...props} {...mergeStatefulStyles((state: InputRenderProps) => ({\n 0: {\n className: \"xjbqb8w xc342km x9f619 x139gbkf x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv\"\n },\n 2: {\n className: \"xjbqb8w xc342km x9f619 x139gbkf x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b\"\n },\n 1: {\n className: \"xjbqb8w xc342km x9f619 x16svsjw x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv x1xj74d8\"\n },\n 3: {\n className: \"xjbqb8w xc342km x9f619 x1848etk x1c52epr xh8yej3 x1qn8t5l xh7dzej x1hmvnq2 x1t137rt x1717udv xbppi91 xss6m8b x1xj74d8\"\n }\n })[!!numeric << 1 | !!state.isDisabled << 0], props)} />;\n}\n\n/**\n * A field's label: the type and colour alone, positioned by whatever renders\n * it. React Aria's `Label`, which the field around it associates with its\n * control through context.\n */\n// Hoisted rather than written as the parameter's default, which would be a\n// new object on every render.\nconst NO_STATE: Partial<FieldLabelState> = {};\nfunction FieldLabel({\n state = NO_STATE,\n ...props\n}: FieldLabelProps) {\n const {\n isDisabled = false,\n isFocusWithin = false,\n isInvalid = false\n } = state;\n return <Label {...props} {...mergeStyles({\n 0: {\n className: \"x1w5n3ug xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7\"\n },\n 4: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1xj74d8\"\n },\n 2: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj\"\n },\n 6: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x4ii1qj\"\n },\n 1: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 5: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 3: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n },\n 7: {\n className: \"xp6n8n2 xkucv67 x14hhc5u x12utw95 xvzb9hk x1qno0dh xt3l3uh xpc4ca7 x1mxwv8y\"\n }\n }[!!isDisabled << 2 | !!isInvalid << 1 | !!(!isDisabled && !isInvalid && isFocusWithin) << 0], props)} />;\n}\n\n/**\n * The line under a field: the error while there is one, the description\n * otherwise. The error goes through React Aria's `FieldError`, which renders\n * only while the field is invalid and falls back to whatever validation\n * errors the field carries when no message is given — which is how a `Form`\n * with server-side errors will reach it without any field changing.\n */\nfunction FieldMessage({\n description,\n error\n}: FieldMessageProps) {\n return <>\n <FieldError className=\"x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi x4ii1qj\">\n {error}\n </FieldError>\n {error === undefined && description !== undefined ? <Text slot=\"description\" className=\"x1w5n3ug x1yicsit x1b35g6e x9d6959 xwth0xh xybisxh x10im51j x1y88zpp xboopgi\">\n {description}\n </Text> : null}\n </>;\n}\nexport type { FieldBoxProps, FieldInputProps, FieldLabelProps, FieldLabelState, FieldMessageProps };\nexport { FieldBox, FieldInput, FieldLabel, FieldMessage };"],"mappings":";;;;;AAmEA,SAAS,WAAW,OAAe,UAAqB;CACtD,QAAQ,UAA4B,qBAAA,UAAA,EAAA,UAAA,CAChC,oBAAC,YAAD;EAAmB;EAAO,WAAU;EACjC,UAAA;CACS,CAAA,GACX,QACH,EAAA,CAAA;AACJ;AACA,SAAS,UAAU,OAAyB;CAC1C,OAAO;EACL,GAAG,EACD,WAAW,uIACb;EACA,GAAG,EACD,WAAW,wIACb;EACA,GAAG,EACD,WAAW,8HACb;EACA,GAAG,EACD,WAAW,8HACb;CACF,EAAE,CAAC,CAAC,MAAM,aAAa,IAAI,CAAC,CAAC,MAAM,cAAc;AACnD;;;;;;;;AASA,SAAA,SAAA,IAAA;CAAA,MAAA,IAAA,EAAA,EAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,IAAA;EAAkB,MAAA,EAAA,UAAA,IAAA,OAAA,IAAA,GAAA,UAAA;EAAA,WAAA;EAAA,QAAA;EAKR,KAAA;EAAUA,KAAA;EAAW,KAAA,oBAAoB,WAAW,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA;EAAA,KAAA,EAAA;EAAA,WAAA,EAAA;EAAA,QAAA,EAAA;EAAA,KAAA,EAAA;EAAA,KAAA,EAAA;CAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,YAAA,EAAA,OAAA,OAAA;EAC7D,KAAA,WAAW,OAAO,QAAQ;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,MAAA,EAAA,QAAA,IAAA;EADzB,KAAA,oBAAC,IAAD;GAAM,GAAKA;GAAK,GAAM;GACxB,UAAA;EADQ,CAAA;EAEH,EAAA,KAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAFH;AAEG;;;;;;AAQZ,SAAS,WAAW,EAClB,UAAU,OACV,GAAG,SACe;CAClB,OAAO,oBAAC,OAAD;EAAO,GAAI;EAAO,GAAI,qBAAqB,WAA6B;GAC7E,GAAG,EACD,WAAW,iHACb;GACA,GAAG,EACD,WAAW,wHACb;GACA,GAAG,EACD,WAAW,iHACb;GACA,GAAG,EACD,WAAW,wHACb;EACF,EAAA,CAAG,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,MAAM,cAAc,IAAI,KAAK;CAAE,CAAA;AACvD;;;;;;AASA,MAAM,WAAqC,CAAC;AAC5C,SAAS,WAAW,EAClB,QAAQ,UACR,GAAG,SACe;CAClB,MAAM,EACJ,aAAa,OACb,gBAAgB,OAChB,YAAY,UACV;CACJ,OAAO,oBAAC,OAAD;EAAO,GAAI;EAAO,GAAI,YAAY;GACvC,GAAG,EACD,WAAW,8EACb;GACA,GAAG,EACD,WAAW,8EACb;GACA,GAAG,EACD,WAAW,6EACb;GACA,GAAG,EACD,WAAW,6EACb;GACA,GAAG,EACD,WAAW,8EACb;GACA,GAAG,EACD,WAAW,8EACb;GACA,GAAG,EACD,WAAW,8EACb;GACA,GAAG,EACD,WAAW,8EACb;EACF,EAAE,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,EAAE,CAAC,cAAc,CAAC,aAAa,kBAAkB,IAAI,KAAK;CAAE,CAAA;AACxG;;;;;;;;AASA,SAAA,aAAA,IAAA;CAAA,MAAA,IAAA,EAAA,CAAA;CAAsB,MAAA,EAAA,aAAA,UAAA;CAGF,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EAEd,KAAA,oBAAC,YAAD;GAAsB,WAAA;GACnB,UAAA;EADQ,CAAA;EAEE,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,eAAA,EAAA,OAAA,OAAA;EACZ,KAAA,UAAU,KAAA,KAAa,gBAAgB,KAAA,IAAY,oBAAC,MAAD;GAAW,MAAA;GAAwB,WAAA;GAClF,UAAA;EADoD,CAAA,IAAxD;EAEe,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EANb,KAAA,qBAAA,UAAA,EAAA,UAAA,CACH,IAGC,EAEe,EAAA,CAAA;EACf,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OAPE;AAOF"}
@@ -0,0 +1,19 @@
1
+ //#region src/field/root.ts
2
+ /**
3
+ * What every field passes React Aria for `validationBehavior`. The message
4
+ * under a field is the library's to show, so validation only marks the control
5
+ * rather than surfacing the browser's own constraint UI; a `Form` may opt a
6
+ * field back into the native behaviour. One constant rather than a literal in
7
+ * each field, so the decision has one place to be changed.
8
+ */
9
+ const FIELD_VALIDATION_BEHAVIOR = "aria";
10
+ const fieldStyles = { root: {
11
+ kB7OPa: "x9f619",
12
+ k1xSpc: "x78zum5",
13
+ kXwgrk: "xdt5ytf",
14
+ $$css: true
15
+ } };
16
+ //#endregion
17
+ export { FIELD_VALIDATION_BEHAVIOR, fieldStyles };
18
+
19
+ //# sourceMappingURL=root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"root.js","names":[],"sources":["../../src/field/root.ts"],"sourcesContent":["import * as stylex from '@stylexjs/stylex';\n\n// What a field applies to its own root, which is React Aria's field element\n// rather than a part of the chrome. Apart from the parts in ./index.tsx so\n// that file exports components alone, which is what keeps fast refresh working\n// for it.\n\n/**\n * What every field passes React Aria for `validationBehavior`. The message\n * under a field is the library's to show, so validation only marks the control\n * rather than surfacing the browser's own constraint UI; a `Form` may opt a\n * field back into the native behaviour. One constant rather than a literal in\n * each field, so the decision has one place to be changed.\n */\nconst FIELD_VALIDATION_BEHAVIOR = 'aria';\nconst fieldStyles = {\n root: {\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kXwgrk: \"xdt5ytf\",\n $$css: true\n }\n};\nexport { FIELD_VALIDATION_BEHAVIOR, fieldStyles };"],"mappings":";;;;;;;;AAcA,MAAM,4BAA4B;AAClC,MAAM,cAAc,EAClB,MAAM;CACJ,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,OAAO;AACT,EACF"}
@@ -38,13 +38,18 @@ function chain(first, second) {
38
38
  };
39
39
  }
40
40
  /**
41
- * The same for a React Aria `Link`, which renders an anchor or, while
42
- * disabled, a span in its place, since a disabled anchor is no link at all.
41
+ * The same for a React Aria `Link`, handed on to the call site's own `render`
42
+ * when there is one. React Aria expects an anchor while the link is enabled
43
+ * and has somewhere to go, and a span in every other case — a disabled anchor
44
+ * is no link at all, and one without `href` is a placeholder — and it leaves
45
+ * `href` out of what it hands over in both span cases, which is what the
46
+ * element is chosen from.
43
47
  */
44
- function linkRenderer(element) {
48
+ function linkRenderer(element, render) {
45
49
  return (domProps, state) => {
46
50
  const merged = withElementProps(domProps, element);
47
- if (state.isDisabled) return createElement("span", {
51
+ if (render !== void 0) return render(merged, state);
52
+ if (state.isDisabled || !("href" in merged)) return createElement("span", {
48
53
  ...merged,
49
54
  href: void 0
50
55
  });
@@ -1 +1 @@
1
- {"version":3,"file":"aria.js","names":[],"sources":["../../src/render/aria.tsx"],"sourcesContent":["import type { AriaAttributes, KeyboardEventHandler } from 'react'\nimport type { ButtonProps, LinkProps } from 'react-aria-components'\n\nimport { createElement } from 'react'\n\n// The four React Aria forwards on its own, and may combine with what a parent\n// provides through context — a dialog's trigger names its dialog this way.\n// Everything else it drops, so those stay out of the spread below rather\n// than overriding a value React Aria computed.\nconst LABELLING = new Set([\n 'aria-describedby',\n 'aria-details',\n 'aria-label',\n 'aria-labelledby',\n])\n\n/**\n * What a component puts on the element itself, past React Aria: the `aria-*`\n * props it would drop, and the keyboard handlers it would wrap.\n *\n * React Aria forwards only the labelling attributes, which is right for the\n * states it manages but leaves a call site no way to mark a button as\n * expanded, pressed, or in control of something React Aria does not know\n * about. Its keyboard handlers stop propagation unless the handler asks\n * otherwise, which is its own convention rather than the DOM's; attached to\n * the element directly they bubble as a call site expects, and an Escape\n * pressed on a button inside a dialog still reaches the dialog.\n */\ninterface ElementProps {\n aria: AriaAttributes\n onKeyDown?: KeyboardEventHandler<HTMLElement> | undefined\n onKeyUp?: KeyboardEventHandler<HTMLElement> | undefined\n}\n\n/** The `aria-*` props React Aria would drop, collected for {@link ElementProps}. */\nfunction ariaAttributesOf(props: object): AriaAttributes {\n const aria: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(props)) {\n if (key.startsWith('aria-') && !LABELLING.has(key)) {\n aria[key] = value\n }\n }\n return aria\n}\n\n/**\n * The `render` function for a React Aria `Button`: the element it would have\n * rendered, plus {@link ElementProps}, handed on to the call site's own\n * `render` when there is one. Built by a call rather than written inline at\n * the prop, which is what react-perf's no-new-function-as-prop is after.\n *\n * `createElement` rather than JSX, here and below: React Aria types the\n * props it hands over as a union of the elements it might have rendered, and\n * a spread of that union onto one tag does not type-check, where the plain\n * call takes any props object.\n */\nfunction buttonRenderer(\n element: ElementProps,\n render: ButtonProps['render'],\n): NonNullable<ButtonProps['render']> {\n return (domProps, state) => {\n const merged = withElementProps(domProps, element)\n if (render !== undefined) {\n return render(merged, state)\n }\n return createElement('button', merged)\n }\n}\n\n// React Aria's own keyboard handling comes first, then the call site's.\nfunction chain<Event>(\n first: ((event: Event) => void) | undefined,\n second: ((event: Event) => void) | undefined,\n) {\n if (second === undefined) {\n return first\n }\n return (event: Event) => {\n first?.(event)\n second(event)\n }\n}\n\n/**\n * The same for a React Aria `Link`, which renders an anchor or, while\n * disabled, a span in its place, since a disabled anchor is no link at all.\n */\nfunction linkRenderer(element: ElementProps): NonNullable<LinkProps['render']> {\n return (domProps, state) => {\n const merged = withElementProps(domProps, element)\n if (state.isDisabled) {\n return createElement('span', { ...merged, href: undefined })\n }\n return createElement('a', merged)\n }\n}\n\nfunction withElementProps<Props extends object>(\n domProps: Props,\n element: ElementProps,\n) {\n const dom = domProps as Props & {\n onKeyDown?: KeyboardEventHandler<HTMLElement>\n onKeyUp?: KeyboardEventHandler<HTMLElement>\n }\n return {\n ...domProps,\n ...element.aria,\n onKeyDown: chain(dom.onKeyDown, element.onKeyDown),\n onKeyUp: chain(dom.onKeyUp, element.onKeyUp),\n }\n}\n\nexport type { ElementProps }\n\nexport { ariaAttributesOf, buttonRenderer, linkRenderer }\n"],"mappings":";;AASA,MAAM,4BAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;AAAiB,CAClB;;AAqBD,SAAS,iBAAiB,OAA+B;CACvD,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,IAAI,WAAW,OAAO,KAAK,CAAC,UAAU,IAAI,GAAG,GAC/C,KAAK,OAAO;CAGhB,OAAO;AACT;;;;;;;;;;;;AAaA,SAAS,eACP,SACA,QACoC;CACpC,QAAQ,UAAU,UAAU;EAC1B,MAAM,SAAS,iBAAiB,UAAU,OAAO;EACjD,IAAI,WAAW,KAAA,GACb,OAAO,OAAO,QAAQ,KAAK;EAE7B,OAAO,cAAc,UAAU,MAAM;CACvC;AACF;AAGA,SAAS,MACP,OACA,QACA;CACA,IAAI,WAAW,KAAA,GACb,OAAO;CAET,QAAQ,UAAiB;EACvB,QAAQ,KAAK;EACb,OAAO,KAAK;CACd;AACF;;;;;AAMA,SAAS,aAAa,SAAyD;CAC7E,QAAQ,UAAU,UAAU;EAC1B,MAAM,SAAS,iBAAiB,UAAU,OAAO;EACjD,IAAI,MAAM,YACR,OAAO,cAAc,QAAQ;GAAE,GAAG;GAAQ,MAAM,KAAA;EAAU,CAAC;EAE7D,OAAO,cAAc,KAAK,MAAM;CAClC;AACF;AAEA,SAAS,iBACP,UACA,SACA;CACA,MAAM,MAAM;CAIZ,OAAO;EACL,GAAG;EACH,GAAG,QAAQ;EACX,WAAW,MAAM,IAAI,WAAW,QAAQ,SAAS;EACjD,SAAS,MAAM,IAAI,SAAS,QAAQ,OAAO;CAC7C;AACF"}
1
+ {"version":3,"file":"aria.js","names":[],"sources":["../../src/render/aria.tsx"],"sourcesContent":["import type { AriaAttributes, KeyboardEventHandler } from 'react'\nimport type { ButtonProps, LinkProps } from 'react-aria-components'\n\nimport { createElement } from 'react'\n\n// The four React Aria forwards on its own, and may combine with what a parent\n// provides through context — a dialog's trigger names its dialog this way.\n// Everything else it drops, so those stay out of the spread below rather\n// than overriding a value React Aria computed.\nconst LABELLING = new Set([\n 'aria-describedby',\n 'aria-details',\n 'aria-label',\n 'aria-labelledby',\n])\n\n/**\n * What a component puts on the element itself, past React Aria: the `aria-*`\n * props it would drop, and the keyboard handlers it would wrap.\n *\n * React Aria forwards only the labelling attributes, which is right for the\n * states it manages but leaves a call site no way to mark a button as\n * expanded, pressed, or in control of something React Aria does not know\n * about. Its keyboard handlers stop propagation unless the handler asks\n * otherwise, which is its own convention rather than the DOM's; attached to\n * the element directly they bubble as a call site expects, and an Escape\n * pressed on a button inside a dialog still reaches the dialog.\n */\ninterface ElementProps {\n aria: AriaAttributes\n onKeyDown?: KeyboardEventHandler<HTMLElement> | undefined\n onKeyUp?: KeyboardEventHandler<HTMLElement> | undefined\n}\n\n/** The `aria-*` props React Aria would drop, collected for {@link ElementProps}. */\nfunction ariaAttributesOf(props: object): AriaAttributes {\n const aria: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(props)) {\n if (key.startsWith('aria-') && !LABELLING.has(key)) {\n aria[key] = value\n }\n }\n return aria\n}\n\n/**\n * The `render` function for a React Aria `Button`: the element it would have\n * rendered, plus {@link ElementProps}, handed on to the call site's own\n * `render` when there is one. Built by a call rather than written inline at\n * the prop, which is what react-perf's no-new-function-as-prop is after.\n *\n * `createElement` rather than JSX, here and below: React Aria types the\n * props it hands over as a union of the elements it might have rendered, and\n * a spread of that union onto one tag does not type-check, where the plain\n * call takes any props object.\n */\nfunction buttonRenderer(\n element: ElementProps,\n render: ButtonProps['render'],\n): NonNullable<ButtonProps['render']> {\n return (domProps, state) => {\n const merged = withElementProps(domProps, element)\n if (render !== undefined) {\n return render(merged, state)\n }\n return createElement('button', merged)\n }\n}\n\n// React Aria's own keyboard handling comes first, then the call site's.\nfunction chain<Event>(\n first: ((event: Event) => void) | undefined,\n second: ((event: Event) => void) | undefined,\n) {\n if (second === undefined) {\n return first\n }\n return (event: Event) => {\n first?.(event)\n second(event)\n }\n}\n\n/**\n * The same for a React Aria `Link`, handed on to the call site's own `render`\n * when there is one. React Aria expects an anchor while the link is enabled\n * and has somewhere to go, and a span in every other case a disabled anchor\n * is no link at all, and one without `href` is a placeholder — and it leaves\n * `href` out of what it hands over in both span cases, which is what the\n * element is chosen from.\n */\nfunction linkRenderer(\n element: ElementProps,\n render?: LinkProps['render'],\n): NonNullable<LinkProps['render']> {\n return (domProps, state) => {\n const merged = withElementProps(domProps, element)\n if (render !== undefined) {\n return render(merged, state)\n }\n if (state.isDisabled || !('href' in merged)) {\n return createElement('span', { ...merged, href: undefined })\n }\n return createElement('a', merged)\n }\n}\n\nfunction withElementProps<Props extends object>(\n domProps: Props,\n element: ElementProps,\n) {\n const dom = domProps as Props & {\n onKeyDown?: KeyboardEventHandler<HTMLElement>\n onKeyUp?: KeyboardEventHandler<HTMLElement>\n }\n return {\n ...domProps,\n ...element.aria,\n onKeyDown: chain(dom.onKeyDown, element.onKeyDown),\n onKeyUp: chain(dom.onKeyUp, element.onKeyUp),\n }\n}\n\nexport type { ElementProps }\n\nexport { ariaAttributesOf, buttonRenderer, linkRenderer }\n"],"mappings":";;AASA,MAAM,4BAAY,IAAI,IAAI;CACxB;CACA;CACA;CACA;AAAiB,CAClB;;AAqBD,SAAS,iBAAiB,OAA+B;CACvD,MAAM,OAAgC,CAAC;CACvC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,IAAI,WAAW,OAAO,KAAK,CAAC,UAAU,IAAI,GAAG,GAC/C,KAAK,OAAO;CAGhB,OAAO;AACT;;;;;;;;;;;;AAaA,SAAS,eACP,SACA,QACoC;CACpC,QAAQ,UAAU,UAAU;EAC1B,MAAM,SAAS,iBAAiB,UAAU,OAAO;EACjD,IAAI,WAAW,KAAA,GACb,OAAO,OAAO,QAAQ,KAAK;EAE7B,OAAO,cAAc,UAAU,MAAM;CACvC;AACF;AAGA,SAAS,MACP,OACA,QACA;CACA,IAAI,WAAW,KAAA,GACb,OAAO;CAET,QAAQ,UAAiB;EACvB,QAAQ,KAAK;EACb,OAAO,KAAK;CACd;AACF;;;;;;;;;AAUA,SAAS,aACP,SACA,QACkC;CAClC,QAAQ,UAAU,UAAU;EAC1B,MAAM,SAAS,iBAAiB,UAAU,OAAO;EACjD,IAAI,WAAW,KAAA,GACb,OAAO,OAAO,QAAQ,KAAK;EAE7B,IAAI,MAAM,cAAc,EAAE,UAAU,SAClC,OAAO,cAAc,QAAQ;GAAE,GAAG;GAAQ,MAAM,KAAA;EAAU,CAAC;EAE7D,OAAO,cAAc,KAAK,MAAM;CAClC;AACF;AAEA,SAAS,iBACP,UACA,SACA;CACA,MAAM,MAAM;CAIZ,OAAO;EACL,GAAG;EACH,GAAG,QAAQ;EACX,WAAW,MAAM,IAAI,WAAW,QAAQ,SAAS;EACjD,SAAS,MAAM,IAAI,SAAS,QAAQ,OAAO;CAC7C;AACF"}
package/dist/styles.css CHANGED
@@ -946,6 +946,11 @@
946
946
  text-decoration-color: color-mix(in srgb,var(--x1cjupv7) 45%,transparent);
947
947
  }
948
948
 
949
+ .x1g6epwz {
950
+ -webkit-text-decoration-color: color-mix(in srgb,var(--xn0syi6) calc(var(--xu361ij) * 100%),var(--x1dzgr7y));
951
+ text-decoration-color: color-mix(in srgb,var(--xn0syi6) calc(var(--xu361ij) * 100%),var(--x1dzgr7y));
952
+ }
953
+
949
954
  .x1dbr5dg {
950
955
  -webkit-text-decoration-color: var(--x1ridy1o);
951
956
  text-decoration-color: var(--x1ridy1o);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanso-labs/kanso-ui",
3
- "version": "0.12.4",
3
+ "version": "0.13.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",