@kanso-labs/kanso-ui 0.11.21 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -8
- package/dist/components/app-bar/index.d.ts +2 -2
- package/dist/components/app-bar/index.js +1 -1
- package/dist/components/app-bar/index.js.map +1 -1
- package/dist/components/avatar/index.d.ts +4 -4
- package/dist/components/avatar/index.js +21 -15
- package/dist/components/avatar/index.js.map +1 -1
- package/dist/components/badge/index.d.ts +2 -2
- package/dist/components/badge/index.js +1 -1
- package/dist/components/badge/index.js.map +1 -1
- package/dist/components/button/index.d.ts +32 -21
- package/dist/components/button/index.js +75 -19
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/card/index.d.ts +2 -2
- package/dist/components/card/index.js +1 -1
- package/dist/components/card/index.js.map +1 -1
- package/dist/components/chip/index.d.ts +5 -5
- package/dist/components/chip/index.js +5 -5
- package/dist/components/chip/index.js.map +1 -1
- package/dist/components/code/index.d.ts +2 -2
- package/dist/components/code/index.js +1 -1
- package/dist/components/code/index.js.map +1 -1
- package/dist/components/container/index.d.ts +2 -2
- package/dist/components/container/index.js +1 -1
- package/dist/components/container/index.js.map +1 -1
- package/dist/components/copy-field/index.js +1 -1
- package/dist/components/currency/index.d.ts +2 -2
- package/dist/components/currency/index.js +1 -1
- package/dist/components/currency/index.js.map +1 -1
- package/dist/components/feed/index.d.ts +2 -2
- package/dist/components/feed/index.js +1 -1
- package/dist/components/feed/index.js.map +1 -1
- package/dist/components/icon-button/index.d.ts +24 -18
- package/dist/components/icon-button/index.js +62 -15
- package/dist/components/icon-button/index.js.map +1 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/keycap/index.d.ts +2 -2
- package/dist/components/keycap/index.js +1 -1
- package/dist/components/keycap/index.js.map +1 -1
- package/dist/components/link/index.d.ts +2 -2
- package/dist/components/link/index.js +1 -1
- package/dist/components/link/index.js.map +1 -1
- package/dist/components/list-detail/index.d.ts +2 -2
- package/dist/components/list-detail/index.js +1 -1
- package/dist/components/list-detail/index.js.map +1 -1
- package/dist/components/popover/index.d.ts +105 -0
- package/dist/components/popover/index.js +246 -0
- package/dist/components/popover/index.js.map +1 -0
- package/dist/components/product-icon/index.d.ts +3 -3
- package/dist/components/product-icon/index.js +23 -17
- package/dist/components/product-icon/index.js.map +1 -1
- package/dist/components/separator/index.d.ts +14 -4
- package/dist/components/separator/index.js +23 -9
- package/dist/components/separator/index.js.map +1 -1
- package/dist/components/sheet/index.d.ts +26 -28
- package/dist/components/sheet/index.js +47 -82
- package/dist/components/sheet/index.js.map +1 -1
- package/dist/components/stack/index.d.ts +2 -2
- package/dist/components/stack/index.js +1 -1
- package/dist/components/stack/index.js.map +1 -1
- package/dist/components/supporting-pane/index.d.ts +2 -2
- package/dist/components/supporting-pane/index.js +1 -1
- package/dist/components/supporting-pane/index.js.map +1 -1
- package/dist/components/tabs/index.d.ts +15 -8
- package/dist/components/tabs/index.js +133 -45
- package/dist/components/tabs/index.js.map +1 -1
- package/dist/components/text/index.d.ts +2 -2
- package/dist/components/text/index.js +1 -1
- package/dist/components/text/index.js.map +1 -1
- package/dist/components/text-field/index.d.ts +12 -5
- package/dist/components/text-field/index.js +48 -33
- package/dist/components/text-field/index.js.map +1 -1
- package/dist/hooks/useImageLoadingStatus.js +53 -0
- package/dist/hooks/useImageLoadingStatus.js.map +1 -0
- package/dist/hooks/useRipple.js +1 -1
- package/dist/hooks/useRipple.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/render/aria.js +66 -0
- package/dist/render/aria.js.map +1 -0
- package/dist/render/useRender.d.ts +28 -0
- package/dist/render/useRender.js +132 -0
- package/dist/render/useRender.js.map +1 -0
- package/dist/styles/merge.js +14 -8
- package/dist/styles/merge.js.map +1 -1
- package/dist/styles.css +88 -36
- package/package.json +4 -4
- package/dist/render/nativeButton.js +0 -26
- package/dist/render/nativeButton.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderComponentProps } from "../../render/useRender.js";
|
|
2
2
|
//#region src/components/link/index.d.ts
|
|
3
3
|
type LinkProps = {
|
|
4
4
|
/**
|
|
@@ -17,7 +17,7 @@ type LinkProps = {
|
|
|
17
17
|
* @default 'always'
|
|
18
18
|
*/
|
|
19
19
|
underline?: LinkUnderline;
|
|
20
|
-
} &
|
|
20
|
+
} & RenderComponentProps<'a'>;
|
|
21
21
|
type LinkTone = 'inherit' | 'primary';
|
|
22
22
|
type LinkUnderline = 'always' | 'hover' | 'none';
|
|
23
23
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
|
|
2
|
+
import { useRender } from "../../render/useRender.js";
|
|
2
3
|
import { mergeStyles } from "../../styles/merge.js";
|
|
3
|
-
import { useRender } from "@base-ui/react/use-render";
|
|
4
4
|
//#region src/components/link/index.tsx
|
|
5
5
|
const styles = { base: {
|
|
6
6
|
kaIpWk: "x1tfhd1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/link/index.tsx"],"sourcesContent":["import {
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderComponentProps } from "../../render/useRender.js";
|
|
2
2
|
import { ReactNode } from "react";
|
|
3
3
|
//#region src/components/list-detail/index.d.ts
|
|
4
4
|
type ListDetailProps = {
|
|
@@ -22,7 +22,7 @@ type ListDetailProps = {
|
|
|
22
22
|
* @default 'list'
|
|
23
23
|
*/
|
|
24
24
|
showing?: 'detail' | 'list';
|
|
25
|
-
} & Omit<
|
|
25
|
+
} & Omit<RenderComponentProps<'div'>, 'children'>;
|
|
26
26
|
/**
|
|
27
27
|
* Material 3's list-detail layout: a fixed list pane beside a flexible detail
|
|
28
28
|
* pane, collapsing to one pane at a time below the expanded breakpoint.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { useRender } from "../../render/useRender.js";
|
|
1
2
|
import { mergeStyles } from "../../styles/merge.js";
|
|
2
|
-
import { useRender } from "@base-ui/react/use-render";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/list-detail/index.tsx
|
|
5
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-detail/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/list-detail/index.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport * as stylex from '@stylexjs/stylex';\nimport type { RenderComponentProps } from '../../render/useRender';\nimport { useRender } from '../../render/useRender';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { media, spacing } from '../../tokens/design.tokens.stylex';\n\n// Material 3's recommended snap widths for a fixed pane. The list is the\n// fixed one here — M3 points a fixed pane at \"lists with light information\n// density\" — and the detail pane is the flexible one that absorbs whatever is\n// left, which satisfies the spec's rule that every layout carry at least one\n// flexible pane.\nconst LIST_PANE = '360px';\nconst LIST_PANE_EXTRA_LARGE = '412px';\n\n// One of Material 3's canonical layouts, and the fixed-and-flexible shape of\n// its two-pane layouts. Unlike SupportingPane, the detail pane here stands on\n// its own: a message, a product, a file. That is what makes showing it\n// *instead of* the list a coherent thing to do when only one pane fits, and\n// why this layout has to be told which pane is showing while SupportingPane\n// does not.\n//\n// M3 puts the second pane on screen from expanded up. Below that the spec\n// shows one pane at a time, with selecting an item swapping to the detail and\n// back returning to the list — app navigation rather than layout, which is\n// why `showing` is controlled rather than held here.\n\ntype ListDetailProps = {\n /**\n * The selected item's content. Stands on its own, and takes the flexible\n * pane.\n */\n detail?: ReactNode;\n /**\n * The items to choose between. Takes the fixed pane — 360px wide, 412px at\n * extra-large.\n */\n list?: ReactNode;\n /**\n * Which pane to show while only one fits, below the expanded breakpoint.\n * Both are shown from expanded up, where this is ignored.\n *\n * Controlled, with no uncontrolled fallback: the layout cannot know that an\n * item was selected or that the reader went back, so holding that state\n * here would only ever be wrong.\n * @default 'list'\n */\n showing?: 'detail' | 'list';\n} & Omit<RenderComponentProps<'div'>, 'children'>;\n\n/**\n * Material 3's list-detail layout: a fixed list pane beside a flexible detail\n * pane, collapsing to one pane at a time below the expanded breakpoint.\n *\n * Layout only — neither pane paints a surface of its own, so what goes inside\n * them is composed at the call site. `render` swaps the container's element,\n * for a layout that should be a `<main>` rather than a `<div>`.\n *\n * The panes are written to the DOM in the order they are shown, which is what\n * M3 asks of co-planar panes: focus order has to match the arrangement on\n * screen.\n */\nfunction ListDetail({\n detail,\n list,\n render,\n showing = 'list',\n ...props\n}: ListDetailProps) {\n return useRender({\n defaultTagName: 'div',\n props: {\n ...props,\n children: <>\n <div {...{\n 0: {\n className: \"x9f619 xeuugli\"\n },\n 1: {\n className: \"x9f619 xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'detail') << 0]}>\n {list}\n </div>\n <div {...{\n 0: {\n className: \"x9f619 xeuugli\"\n },\n 1: {\n className: \"x9f619 xeuugli x1s85apg x9a4l8x\"\n }\n }[!!(showing === 'list') << 0]}>\n {detail}\n </div>\n </>,\n ...mergeStyles({\n className: \"x9f619 xrvj5dj xj2l1yv x1mkdm3x xkgydl7 xxxc7o5\"\n }, props)\n },\n render\n });\n}\nexport type { ListDetailProps };\nexport default ListDetail;"],"mappings":";;;;;;;;;;;;;;;;AA+DA,SAAS,WAAW,EAClB,QACA,MACA,QACA,UAAU,QACV,GAAG,SACe;CAClB,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,UAAU,qBAAA,UAAA,EAAA,UAAA,CACN,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,iBACb;KACA,GAAG,EACD,WAAW,kCACb;IACF,EAAE,CAAC,EAAE,YAAY,aAAa;IACzB,UAAA;GACE,CAAA,GACL,oBAAC,OAAD;IAAK,GAAI;KACT,GAAG,EACD,WAAW,iBACb;KACA,GAAG,EACD,WAAW,kCACb;IACF,EAAE,CAAC,EAAE,YAAY,WAAW;IACvB,UAAA;GACE,CAAA,CACP,EAAA,CAAA;GACF,GAAG,YAAY,EACb,WAAW,kDACb,GAAG,KAAK;EACV;EACA;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ReactNode, RefObject } from "react";
|
|
2
|
+
import { ClassNameOrFunction, DialogProps, DialogTriggerProps, HeadingProps, PopoverRenderProps, StyleOrFunction, TextProps } from "react-aria-components";
|
|
3
|
+
//#region src/components/popover/index.d.ts
|
|
4
|
+
type PopoverAlign = 'center' | 'end' | 'start';
|
|
5
|
+
type PopoverSide = 'bottom' | 'left' | 'right' | 'top';
|
|
6
|
+
type PopoverSize = 'md' | 'sm';
|
|
7
|
+
type PopoverProps = Omit<DialogTriggerProps, 'children'> & {
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Blocks the page behind the panel while it is open, as a dialog would.
|
|
11
|
+
* Off by default: a popover leaves the page interactive, which is the
|
|
12
|
+
* difference from `Sheet`.
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
modal?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Panel width: `sm` caps at 240px, `md` at 320px. Either way the panel is
|
|
18
|
+
* only as wide as its contents, and never wider than the viewport.
|
|
19
|
+
* @default 'md'
|
|
20
|
+
*/
|
|
21
|
+
size?: PopoverSize;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* A panel anchored to the control that opened it. Open state is React Aria's:
|
|
25
|
+
* pass `isOpen` with `onOpenChange` to control it, or `defaultOpen` to let it
|
|
26
|
+
* keep its own.
|
|
27
|
+
*
|
|
28
|
+
* Non-modal by design — the page behind stays scrollable and clickable, which
|
|
29
|
+
* is the difference from `Sheet`. Pass `modal` to change that.
|
|
30
|
+
*
|
|
31
|
+
* Composed rather than configured by props, because a popover's contents are
|
|
32
|
+
* arbitrary — the parts are `Popover.Content`, `Popover.Title`, and
|
|
33
|
+
* `Popover.Description`. A `Button` or `IconButton` placed directly inside
|
|
34
|
+
* `Popover` opens it, and one given `slot="close"` inside the content closes
|
|
35
|
+
* it; neither needs a part of its own.
|
|
36
|
+
*/
|
|
37
|
+
declare function Popover$1({ children, modal, size, ...props }: PopoverProps): import("react").JSX.Element;
|
|
38
|
+
declare namespace Popover$1 {
|
|
39
|
+
var Content: typeof PopoverContent;
|
|
40
|
+
var Description: typeof PopoverDescription;
|
|
41
|
+
var Title: typeof PopoverTitle;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The panel itself. Everything the popover shows goes in here; the trigger
|
|
45
|
+
* stays outside it, since the trigger lives in the page while this is
|
|
46
|
+
* portalled out to the end of the body.
|
|
47
|
+
*
|
|
48
|
+
* Placement is React Aria's anchor positioning, so the panel flips to the
|
|
49
|
+
* opposite side and shifts along the edge of the viewport on its own rather
|
|
50
|
+
* than being clipped by it.
|
|
51
|
+
*/
|
|
52
|
+
declare function PopoverContent({ align, alignOffset, children, className, container, side, sideOffset, style, triggerRef, ...props }: PopoverContentProps): import("react").JSX.Element;
|
|
53
|
+
/**
|
|
54
|
+
* Supporting copy under the title. The panel's `aria-describedby` points at
|
|
55
|
+
* it — see DescriptionContext for why that is this component's doing.
|
|
56
|
+
*/
|
|
57
|
+
declare function PopoverDescription(props: PopoverDescriptionProps): import("react").JSX.Element;
|
|
58
|
+
/**
|
|
59
|
+
* Names the popover. Rendered through React Aria's title slot, which is what
|
|
60
|
+
* points the panel's `aria-labelledby` at it — a popover without one announces
|
|
61
|
+
* itself unnamed.
|
|
62
|
+
*/
|
|
63
|
+
declare function PopoverTitle(props: PopoverTitleProps): import("react").JSX.Element;
|
|
64
|
+
type PopoverContentProps = Omit<DialogProps, 'children' | 'className' | 'style'> & {
|
|
65
|
+
/**
|
|
66
|
+
* Where the panel sits along the side it opens on.
|
|
67
|
+
* @default 'center'
|
|
68
|
+
*/
|
|
69
|
+
align?: PopoverAlign;
|
|
70
|
+
/** Moves the panel along that side, in pixels. */
|
|
71
|
+
alignOffset?: number;
|
|
72
|
+
children?: ReactNode;
|
|
73
|
+
/** A function may compute the class from the panel's render state. */
|
|
74
|
+
className?: ClassNameOrFunction<PopoverRenderProps>;
|
|
75
|
+
/**
|
|
76
|
+
* Where to portal the panel. Defaults to the end of `<body>`, which is
|
|
77
|
+
* right for an app that sets its StyleX theme on `:root`. An app that
|
|
78
|
+
* scopes the theme to a subtree has to point this at an element inside it,
|
|
79
|
+
* or the popover renders outside the theme and falls back to the tokens'
|
|
80
|
+
* `prefers-color-scheme` default.
|
|
81
|
+
*/
|
|
82
|
+
container?: Element;
|
|
83
|
+
/**
|
|
84
|
+
* Which side of the trigger the panel opens on. It flips to the opposite
|
|
85
|
+
* side when there is no room.
|
|
86
|
+
* @default 'bottom'
|
|
87
|
+
*/
|
|
88
|
+
side?: PopoverSide;
|
|
89
|
+
/**
|
|
90
|
+
* The gap between the trigger and the panel, in pixels.
|
|
91
|
+
* @default 8
|
|
92
|
+
*/
|
|
93
|
+
sideOffset?: number;
|
|
94
|
+
/** A function may compute the style from the panel's render state. */
|
|
95
|
+
style?: StyleOrFunction<PopoverRenderProps>;
|
|
96
|
+
/**
|
|
97
|
+
* An element to anchor the panel to other than the trigger that opened it.
|
|
98
|
+
*/
|
|
99
|
+
triggerRef?: RefObject<Element | null>;
|
|
100
|
+
};
|
|
101
|
+
type PopoverDescriptionProps = TextProps;
|
|
102
|
+
type PopoverTitleProps = HeadingProps;
|
|
103
|
+
//#endregion
|
|
104
|
+
export { type PopoverAlign, type PopoverContentProps, type PopoverDescriptionProps, type PopoverProps, type PopoverSide, type PopoverSize, type PopoverTitleProps, Popover$1 as default };
|
|
105
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
|
|
2
|
+
import { mergeStatefulStyles, mergeStyles } from "../../styles/merge.js";
|
|
3
|
+
import { createContext, useCallback, useContext, useEffect, useId, useMemo, useState } from "react";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { c } from "react/compiler-runtime";
|
|
6
|
+
import { Dialog, DialogTrigger, Heading, Popover, Text } from "react-aria-components";
|
|
7
|
+
//#region src/components/popover/index.tsx
|
|
8
|
+
const DEFAULT_SIDE_OFFSET = 8;
|
|
9
|
+
const styles = {
|
|
10
|
+
description: {
|
|
11
|
+
kB7OPa: "x9f619",
|
|
12
|
+
kMwMTN: "x1w5n3ug",
|
|
13
|
+
kMv6JI: "xpo2rfv",
|
|
14
|
+
kGuDYH: "x193rfdd",
|
|
15
|
+
k63SB2: "x1hews6w",
|
|
16
|
+
kb6lSQ: "xn43zvd",
|
|
17
|
+
kLWn49: "xv61bfh",
|
|
18
|
+
kogj98: "x1ghz6dp",
|
|
19
|
+
$$css: true
|
|
20
|
+
},
|
|
21
|
+
dialog: {
|
|
22
|
+
kB7OPa: "x9f619",
|
|
23
|
+
k1xSpc: "x78zum5",
|
|
24
|
+
kXwgrk: "xdt5ytf",
|
|
25
|
+
kOIVth: "x126z3so",
|
|
26
|
+
kjBf7l: "xrgy624",
|
|
27
|
+
kInvED: "x1hl8ikr",
|
|
28
|
+
k3XXqK: "x9v5kkp x1t137rt",
|
|
29
|
+
kMeerF: "x1de99jn",
|
|
30
|
+
$$css: true
|
|
31
|
+
},
|
|
32
|
+
fromBottom: {
|
|
33
|
+
k3nNDw: "x18ouj0k",
|
|
34
|
+
$$css: true
|
|
35
|
+
},
|
|
36
|
+
fromLeft: {
|
|
37
|
+
k3nNDw: "x1nf803f",
|
|
38
|
+
$$css: true
|
|
39
|
+
},
|
|
40
|
+
fromRight: {
|
|
41
|
+
k3nNDw: "xyibjs4",
|
|
42
|
+
$$css: true
|
|
43
|
+
},
|
|
44
|
+
fromTop: {
|
|
45
|
+
k3nNDw: "x1dp6rp6",
|
|
46
|
+
$$css: true
|
|
47
|
+
},
|
|
48
|
+
md: {
|
|
49
|
+
ks0D6T: "x10u2fgw",
|
|
50
|
+
$$css: true
|
|
51
|
+
},
|
|
52
|
+
popup: {
|
|
53
|
+
k44tkh: "xvhm28k",
|
|
54
|
+
kKVMdj: "x97zbip",
|
|
55
|
+
kyAemX: "x16dv9tl",
|
|
56
|
+
kWkggS: "x1mjdul6",
|
|
57
|
+
kaIpWk: "x62ce2h",
|
|
58
|
+
kGVxlE: "x1os83gw",
|
|
59
|
+
kB7OPa: "x9f619",
|
|
60
|
+
kMwMTN: "x139gbkf",
|
|
61
|
+
kORKVm: "x1odjw0f",
|
|
62
|
+
kmVPX3: "xgc26li",
|
|
63
|
+
$$css: true
|
|
64
|
+
},
|
|
65
|
+
sm: {
|
|
66
|
+
ks0D6T: "xjjheoa",
|
|
67
|
+
$$css: true
|
|
68
|
+
},
|
|
69
|
+
title: {
|
|
70
|
+
kB7OPa: "x9f619",
|
|
71
|
+
kMwMTN: "x139gbkf",
|
|
72
|
+
kMv6JI: "x46eyla",
|
|
73
|
+
kGuDYH: "x5ehqhr",
|
|
74
|
+
k63SB2: "xrf6cl6",
|
|
75
|
+
kb6lSQ: "x1g135zh",
|
|
76
|
+
kLWn49: "x1ggk5va",
|
|
77
|
+
kogj98: "x1ghz6dp",
|
|
78
|
+
$$css: true
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const origins = {
|
|
82
|
+
bottom: styles.fromTop,
|
|
83
|
+
center: styles.fromTop,
|
|
84
|
+
left: styles.fromRight,
|
|
85
|
+
right: styles.fromLeft,
|
|
86
|
+
top: styles.fromBottom
|
|
87
|
+
};
|
|
88
|
+
const PopoverContext = createContext({
|
|
89
|
+
modal: false,
|
|
90
|
+
size: "md"
|
|
91
|
+
});
|
|
92
|
+
const DescriptionContext = createContext({
|
|
93
|
+
id: "",
|
|
94
|
+
register: () => () => {}
|
|
95
|
+
});
|
|
96
|
+
function placementOf(side, align) {
|
|
97
|
+
if (align === "center") return side;
|
|
98
|
+
if (side === "top" || side === "bottom") return `${side} ${align}`;
|
|
99
|
+
return `${side} ${align === "start" ? "top" : "bottom"}`;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A panel anchored to the control that opened it. Open state is React Aria's:
|
|
103
|
+
* pass `isOpen` with `onOpenChange` to control it, or `defaultOpen` to let it
|
|
104
|
+
* keep its own.
|
|
105
|
+
*
|
|
106
|
+
* Non-modal by design — the page behind stays scrollable and clickable, which
|
|
107
|
+
* is the difference from `Sheet`. Pass `modal` to change that.
|
|
108
|
+
*
|
|
109
|
+
* Composed rather than configured by props, because a popover's contents are
|
|
110
|
+
* arbitrary — the parts are `Popover.Content`, `Popover.Title`, and
|
|
111
|
+
* `Popover.Description`. A `Button` or `IconButton` placed directly inside
|
|
112
|
+
* `Popover` opens it, and one given `slot="close"` inside the content closes
|
|
113
|
+
* it; neither needs a part of its own.
|
|
114
|
+
*/
|
|
115
|
+
function Popover$1({ children, modal = false, size = "md", ...props }) {
|
|
116
|
+
const context = useMemo(() => ({
|
|
117
|
+
modal,
|
|
118
|
+
size
|
|
119
|
+
}), [modal, size]);
|
|
120
|
+
return /* @__PURE__ */ jsx(DialogTrigger, {
|
|
121
|
+
...props,
|
|
122
|
+
children: /* @__PURE__ */ jsx(PopoverContext, {
|
|
123
|
+
value: context,
|
|
124
|
+
children
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The panel itself. Everything the popover shows goes in here; the trigger
|
|
130
|
+
* stays outside it, since the trigger lives in the page while this is
|
|
131
|
+
* portalled out to the end of the body.
|
|
132
|
+
*
|
|
133
|
+
* Placement is React Aria's anchor positioning, so the panel flips to the
|
|
134
|
+
* opposite side and shifts along the edge of the viewport on its own rather
|
|
135
|
+
* than being clipped by it.
|
|
136
|
+
*/
|
|
137
|
+
function PopoverContent({ align = "center", alignOffset, children, className, container, side = "bottom", sideOffset = DEFAULT_SIDE_OFFSET, style, triggerRef, ...props$1 }) {
|
|
138
|
+
const { modal, size } = useContext(PopoverContext);
|
|
139
|
+
const descriptionId = useId();
|
|
140
|
+
const [described, setDescribed] = useState(false);
|
|
141
|
+
const register = useCallback(() => {
|
|
142
|
+
setDescribed(true);
|
|
143
|
+
return () => {
|
|
144
|
+
setDescribed(false);
|
|
145
|
+
};
|
|
146
|
+
}, []);
|
|
147
|
+
const description = useMemo(() => ({
|
|
148
|
+
id: descriptionId,
|
|
149
|
+
register
|
|
150
|
+
}), [descriptionId, register]);
|
|
151
|
+
return /* @__PURE__ */ jsx(Popover, {
|
|
152
|
+
crossOffset: alignOffset,
|
|
153
|
+
isNonModal: !modal,
|
|
154
|
+
offset: sideOffset,
|
|
155
|
+
placement: placementOf(side, align),
|
|
156
|
+
triggerRef,
|
|
157
|
+
UNSTABLE_portalContainer: container,
|
|
158
|
+
...mergeStatefulStyles((state) => props(styles.popup, styles[size], origins[state.placement ?? "bottom"]), {
|
|
159
|
+
className,
|
|
160
|
+
style
|
|
161
|
+
}),
|
|
162
|
+
children: /* @__PURE__ */ jsx(Dialog, {
|
|
163
|
+
"aria-describedby": described ? descriptionId : void 0,
|
|
164
|
+
...props$1,
|
|
165
|
+
className: "x9f619 x78zum5 xdt5ytf x126z3so xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn",
|
|
166
|
+
children: /* @__PURE__ */ jsx(DescriptionContext, {
|
|
167
|
+
value: description,
|
|
168
|
+
children
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Supporting copy under the title. The panel's `aria-describedby` points at
|
|
175
|
+
* it — see DescriptionContext for why that is this component's doing.
|
|
176
|
+
*/
|
|
177
|
+
function PopoverDescription(props) {
|
|
178
|
+
const $ = c(9);
|
|
179
|
+
const { id, register } = useContext(DescriptionContext);
|
|
180
|
+
let t0;
|
|
181
|
+
let t1;
|
|
182
|
+
if ($[0] !== register) {
|
|
183
|
+
t0 = () => register();
|
|
184
|
+
t1 = [register];
|
|
185
|
+
$[0] = register;
|
|
186
|
+
$[1] = t0;
|
|
187
|
+
$[2] = t1;
|
|
188
|
+
} else {
|
|
189
|
+
t0 = $[1];
|
|
190
|
+
t1 = $[2];
|
|
191
|
+
}
|
|
192
|
+
useEffect(t0, t1);
|
|
193
|
+
let t2;
|
|
194
|
+
if ($[3] !== props) {
|
|
195
|
+
t2 = mergeStyles({ className: "x9f619 x1w5n3ug xpo2rfv x193rfdd x1hews6w xn43zvd xv61bfh x1ghz6dp" }, props);
|
|
196
|
+
$[3] = props;
|
|
197
|
+
$[4] = t2;
|
|
198
|
+
} else t2 = $[4];
|
|
199
|
+
let t3;
|
|
200
|
+
if ($[5] !== id || $[6] !== props || $[7] !== t2) {
|
|
201
|
+
t3 = /* @__PURE__ */ jsx(Text, {
|
|
202
|
+
id,
|
|
203
|
+
slot: "description",
|
|
204
|
+
...props,
|
|
205
|
+
...t2
|
|
206
|
+
});
|
|
207
|
+
$[5] = id;
|
|
208
|
+
$[6] = props;
|
|
209
|
+
$[7] = t2;
|
|
210
|
+
$[8] = t3;
|
|
211
|
+
} else t3 = $[8];
|
|
212
|
+
return t3;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Names the popover. Rendered through React Aria's title slot, which is what
|
|
216
|
+
* points the panel's `aria-labelledby` at it — a popover without one announces
|
|
217
|
+
* itself unnamed.
|
|
218
|
+
*/
|
|
219
|
+
function PopoverTitle(props) {
|
|
220
|
+
const $ = c(5);
|
|
221
|
+
let t0;
|
|
222
|
+
if ($[0] !== props) {
|
|
223
|
+
t0 = mergeStyles({ className: "x9f619 x139gbkf x46eyla x5ehqhr xrf6cl6 x1g135zh x1ggk5va x1ghz6dp" }, props);
|
|
224
|
+
$[0] = props;
|
|
225
|
+
$[1] = t0;
|
|
226
|
+
} else t0 = $[1];
|
|
227
|
+
let t1;
|
|
228
|
+
if ($[2] !== props || $[3] !== t0) {
|
|
229
|
+
t1 = /* @__PURE__ */ jsx(Heading, {
|
|
230
|
+
slot: "title",
|
|
231
|
+
...props,
|
|
232
|
+
...t0
|
|
233
|
+
});
|
|
234
|
+
$[2] = props;
|
|
235
|
+
$[3] = t0;
|
|
236
|
+
$[4] = t1;
|
|
237
|
+
} else t1 = $[4];
|
|
238
|
+
return t1;
|
|
239
|
+
}
|
|
240
|
+
Popover$1.Content = PopoverContent;
|
|
241
|
+
Popover$1.Description = PopoverDescription;
|
|
242
|
+
Popover$1.Title = PopoverTitle;
|
|
243
|
+
//#endregion
|
|
244
|
+
export { Popover$1 as default };
|
|
245
|
+
|
|
246
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["id"],"sources":["../../../src/components/popover/index.tsx"],"sourcesContent":["import type { ReactNode, RefObject } from 'react';\nimport type { ClassNameOrFunction, DialogProps, DialogTriggerProps, HeadingProps, PopoverRenderProps, StyleOrFunction, TextProps } from 'react-aria-components';\nimport * as stylex from '@stylexjs/stylex';\nimport { createContext, useCallback, useContext, useEffect, useId, useMemo, useState } from 'react';\nimport { Dialog, DialogTrigger, Heading, Popover as RACPopover, Text } from 'react-aria-components';\nimport { mergeStatefulStyles, mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, motion, radii, shadows, spacing, typography } from '../../tokens/design.tokens.stylex';\n\n// The gap between the anchor and the panel, matching `spacing.sm`'s default.\n// A number rather than the token, because React Aria computes the position in\n// JavaScript and so cannot read a CSS custom property — this is the one place\n// in the component where a step of the spacing scale is spelled out. React\n// Aria's own default is 8 as well, but the value is this component's decision\n// rather than an inherited one.\nconst DEFAULT_SIDE_OFFSET = 8;\n\n// Growing from the edge the panel is anchored by, rather than from its own\n// centre, which is what makes it read as coming out of the trigger. React\n// Aria reports which side the panel landed on through its render state, so\n// the origin follows the placement it actually got rather than the one asked\n// for, and the same keyframes serve all four sides.\nconst scaleIn = \"x1k48ry3-B\";\n\n// Entry only, for the same reason Sheet's is: an exit animation is something\n// the panel has to stay mounted through, and a popover is dismissed far more\n// often than a modal panel — usually by pressing something else, where a\n// lingering panel is in the way of whatever the press was for.\n//\n// No arrow, and that is M3 rather than an omission: menus and rich tooltips\n// both sit as plain rounded surfaces offset from their anchor, with no caret\n// drawn between the two. React Aria has an `OverlayArrow` part for designs\n// that want one; nothing here renders it.\n//\n// React Aria's popover is two elements — the positioned panel and the dialog\n// inside it — so the styles are split the same way: `popup` and a size on\n// the panel, `dialog` on the element that carries the role.\nconst styles = {\n description: {\n kB7OPa: \"x9f619\",\n kMwMTN: \"x1w5n3ug\",\n kMv6JI: \"xpo2rfv\",\n kGuDYH: \"x193rfdd\",\n k63SB2: \"x1hews6w\",\n kb6lSQ: \"xn43zvd\",\n kLWn49: \"xv61bfh\",\n kogj98: \"x1ghz6dp\",\n $$css: true\n },\n dialog: {\n kB7OPa: \"x9f619\",\n k1xSpc: \"x78zum5\",\n kXwgrk: \"xdt5ytf\",\n kOIVth: \"x126z3so\",\n kjBf7l: \"xrgy624\",\n kInvED: \"x1hl8ikr\",\n k3XXqK: \"x9v5kkp x1t137rt\",\n kMeerF: \"x1de99jn\",\n $$css: true\n },\n fromBottom: {\n k3nNDw: \"x18ouj0k\",\n $$css: true\n },\n fromLeft: {\n k3nNDw: \"x1nf803f\",\n $$css: true\n },\n fromRight: {\n k3nNDw: \"xyibjs4\",\n $$css: true\n },\n fromTop: {\n k3nNDw: \"x1dp6rp6\",\n $$css: true\n },\n md: {\n ks0D6T: \"x10u2fgw\",\n $$css: true\n },\n popup: {\n k44tkh: \"xvhm28k\",\n kKVMdj: \"x97zbip\",\n kyAemX: \"x16dv9tl\",\n kWkggS: \"x1mjdul6\",\n kaIpWk: \"x62ce2h\",\n kGVxlE: \"x1os83gw\",\n kB7OPa: \"x9f619\",\n kMwMTN: \"x139gbkf\",\n kORKVm: \"x1odjw0f\",\n kmVPX3: \"xgc26li\",\n $$css: true\n },\n sm: {\n ks0D6T: \"xjjheoa\",\n $$css: true\n },\n title: {\n kB7OPa: \"x9f619\",\n kMwMTN: \"x139gbkf\",\n kMv6JI: \"x46eyla\",\n kGuDYH: \"x5ehqhr\",\n k63SB2: \"xrf6cl6\",\n kb6lSQ: \"x1g135zh\",\n kLWn49: \"x1ggk5va\",\n kogj98: \"x1ghz6dp\",\n $$css: true\n }\n};\ntype PopoverAlign = 'center' | 'end' | 'start';\ntype PopoverSide = 'bottom' | 'left' | 'right' | 'top';\ntype PopoverSize = 'md' | 'sm';\n\n// Which side the panel opens on, and the origin its entry grows from. Keyed\n// on the placement React Aria reports rather than the one asked for, since\n// the panel flips to the opposite side when there is no room on its own.\nconst origins = {\n bottom: styles.fromTop,\n center: styles.fromTop,\n left: styles.fromRight,\n right: styles.fromLeft,\n top: styles.fromBottom\n};\n\n// `size` and `modal` are declared on the root, where a reader expects to set\n// the shape of the whole popover, but it is `Popover.Content` that has to\n// apply them. Through context rather than making the call site repeat them —\n// the same arrangement Sheet uses, and worth keeping identical between the\n// two panels a consumer is most likely to reach for in the same afternoon.\nconst PopoverContext = createContext<{\n modal: boolean;\n size: PopoverSize;\n}>({\n modal: false,\n size: 'md'\n});\n\n// React Aria points a dialog's `aria-describedby` at its description slot\n// only for an alert dialog, on the grounds that an ordinary dialog's content\n// is read anyway. A popover's description names what the panel is for, so it\n// is pointed at here: the content hands the description an id, and the\n// description reports that it is mounted, since an `aria-describedby` with\n// nothing at the other end is an invalid reference rather than a harmless one.\nconst DescriptionContext = createContext<{\n id: string;\n register: () => () => void;\n}>({\n id: '',\n register: () => () => {}\n});\ntype PopoverProps = Omit<DialogTriggerProps, 'children'> & {\n children?: ReactNode;\n /**\n * Blocks the page behind the panel while it is open, as a dialog would.\n * Off by default: a popover leaves the page interactive, which is the\n * difference from `Sheet`.\n * @default false\n */\n modal?: boolean;\n /**\n * Panel width: `sm` caps at 240px, `md` at 320px. Either way the panel is\n * only as wide as its contents, and never wider than the viewport.\n * @default 'md'\n */\n size?: PopoverSize;\n};\n\n// React Aria names a placement by the side and, along it, the end the panel\n// is aligned to — `bottom start`, or `left top` on the sides where the axis\n// runs the other way.\nfunction placementOf(side: PopoverSide, align: PopoverAlign) {\n if (align === 'center') {\n return side;\n }\n if (side === 'top' || side === 'bottom') {\n return `${side} ${align}` as const;\n }\n return `${side} ${align === 'start' ? 'top' : 'bottom'}` as const;\n}\n\n/**\n * A panel anchored to the control that opened it. Open state is React Aria's:\n * pass `isOpen` with `onOpenChange` to control it, or `defaultOpen` to let it\n * keep its own.\n *\n * Non-modal by design — the page behind stays scrollable and clickable, which\n * is the difference from `Sheet`. Pass `modal` to change that.\n *\n * Composed rather than configured by props, because a popover's contents are\n * arbitrary — the parts are `Popover.Content`, `Popover.Title`, and\n * `Popover.Description`. A `Button` or `IconButton` placed directly inside\n * `Popover` opens it, and one given `slot=\"close\"` inside the content closes\n * it; neither needs a part of its own.\n */\nfunction Popover({\n children,\n modal = false,\n size = 'md',\n ...props\n}: PopoverProps) {\n const context = useMemo(() => ({\n modal,\n size\n }), [modal, size]);\n return <DialogTrigger {...props}>\n <PopoverContext value={context}>{children}</PopoverContext>\n </DialogTrigger>;\n}\n\n/**\n * The panel itself. Everything the popover shows goes in here; the trigger\n * stays outside it, since the trigger lives in the page while this is\n * portalled out to the end of the body.\n *\n * Placement is React Aria's anchor positioning, so the panel flips to the\n * opposite side and shifts along the edge of the viewport on its own rather\n * than being clipped by it.\n */\nfunction PopoverContent({\n align = 'center',\n alignOffset,\n children,\n className,\n container,\n side = 'bottom',\n sideOffset = DEFAULT_SIDE_OFFSET,\n style,\n triggerRef,\n ...props\n}: PopoverContentProps) {\n const {\n modal,\n size\n } = useContext(PopoverContext);\n const descriptionId = useId();\n const [described, setDescribed] = useState(false);\n const register = useCallback(() => {\n setDescribed(true);\n return () => {\n setDescribed(false);\n };\n }, []);\n const description = useMemo(() => ({\n id: descriptionId,\n register\n }), [descriptionId, register]);\n return <RACPopover crossOffset={alignOffset} isNonModal={!modal} offset={sideOffset} placement={placementOf(side, align)} triggerRef={triggerRef}\n // oxlint-disable-next-line typescript/no-deprecated -- its replacement, UNSAFE_PortalProvider, is not exported by react-aria-components\n UNSTABLE_portalContainer={container} {...mergeStatefulStyles((state: PopoverRenderProps) => stylex.props(styles.popup, styles[size], origins[state.placement ?? 'bottom']), {\n className,\n style\n })}>\n <Dialog aria-describedby={described ? descriptionId : undefined} {...props} className=\"x9f619 x78zum5 xdt5ytf x126z3so xrgy624 x1hl8ikr x9v5kkp x1t137rt x1de99jn\">\n <DescriptionContext value={description}>{children}</DescriptionContext>\n </Dialog>\n </RACPopover>;\n}\n\n/**\n * Supporting copy under the title. The panel's `aria-describedby` points at\n * it — see DescriptionContext for why that is this component's doing.\n */\nfunction PopoverDescription(props: PopoverDescriptionProps) {\n const {\n id,\n register\n } = useContext(DescriptionContext);\n useEffect(() => register(), [register]);\n return <Text id={id} slot=\"description\" {...props} {...mergeStyles({\n className: \"x9f619 x1w5n3ug xpo2rfv x193rfdd x1hews6w xn43zvd xv61bfh x1ghz6dp\"\n }, props)} />;\n}\n\n/**\n * Names the popover. Rendered through React Aria's title slot, which is what\n * points the panel's `aria-labelledby` at it — a popover without one announces\n * itself unnamed.\n */\nfunction PopoverTitle(props: PopoverTitleProps) {\n return <Heading slot=\"title\" {...props} {...mergeStyles({\n className: \"x9f619 x139gbkf x46eyla x5ehqhr xrf6cl6 x1g135zh x1ggk5va x1ghz6dp\"\n }, props)} />;\n}\nPopover.Content = PopoverContent;\nPopover.Description = PopoverDescription;\nPopover.Title = PopoverTitle;\n\n// The dialog's own props, plus the four that place the panel and its\n// styling. Those belong to the positioned panel rather than to the dialog,\n// but a call site has no reason to know there are two elements — `className`\n// and `style` reach the panel, which is the one worth restyling, and\n// everything else lands on the dialog.\ntype PopoverContentProps = Omit<DialogProps, 'children' | 'className' | 'style'> & {\n /**\n * Where the panel sits along the side it opens on.\n * @default 'center'\n */\n align?: PopoverAlign;\n /** Moves the panel along that side, in pixels. */\n alignOffset?: number;\n children?: ReactNode;\n /** A function may compute the class from the panel's render state. */\n className?: ClassNameOrFunction<PopoverRenderProps>;\n /**\n * Where to portal the panel. Defaults to the end of `<body>`, which is\n * right for an app that sets its StyleX theme on `:root`. An app that\n * scopes the theme to a subtree has to point this at an element inside it,\n * or the popover renders outside the theme and falls back to the tokens'\n * `prefers-color-scheme` default.\n */\n container?: Element;\n /**\n * Which side of the trigger the panel opens on. It flips to the opposite\n * side when there is no room.\n * @default 'bottom'\n */\n side?: PopoverSide;\n /**\n * The gap between the trigger and the panel, in pixels.\n * @default 8\n */\n sideOffset?: number;\n /** A function may compute the style from the panel's render state. */\n style?: StyleOrFunction<PopoverRenderProps>;\n /**\n * An element to anchor the panel to other than the trigger that opened it.\n */\n triggerRef?: RefObject<Element | null>;\n};\ntype PopoverDescriptionProps = TextProps;\ntype PopoverTitleProps = HeadingProps;\nexport type { PopoverAlign, PopoverContentProps, PopoverDescriptionProps, PopoverProps, PopoverSide, PopoverSize, PopoverTitleProps };\nexport default Popover;"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderComponentProps } from "../../render/useRender.js";
|
|
2
2
|
//#region src/components/product-icon/index.d.ts
|
|
3
|
-
type ProductIconProps = Omit<
|
|
3
|
+
type ProductIconProps = Omit<RenderComponentProps<'span'>, 'children'> & {
|
|
4
4
|
/**
|
|
5
5
|
* What this identifies. Supplies both the fallback initial and the
|
|
6
6
|
* accessible name, so a screen reader announces the thing rather than
|
|
@@ -33,7 +33,7 @@ type ProductIconProps = Omit<AvatarRootProps, 'children'> & {
|
|
|
33
33
|
* The mark is letterboxed rather than cropped, so a logo of any aspect ratio
|
|
34
34
|
* can be handed over as it was drawn.
|
|
35
35
|
*/
|
|
36
|
-
declare function ProductIcon({ name, size, src, tone, ...props }: ProductIconProps): import("react").
|
|
36
|
+
declare function ProductIcon({ name, render, size, src, tone, ...props }: ProductIconProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { type ProductIconProps, ProductIcon as default };
|
|
39
39
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { props } from "../../node_modules/@stylexjs/stylex/lib/es/stylex.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useRender } from "../../render/useRender.js";
|
|
3
|
+
import { mergeStyles } from "../../styles/merge.js";
|
|
4
|
+
import { useImageLoadingStatus } from "../../hooks/useImageLoadingStatus.js";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
//#region src/components/product-icon/index.tsx
|
|
6
7
|
const styles = {
|
|
7
8
|
base: {
|
|
@@ -86,20 +87,25 @@ function initialFrom(name) {
|
|
|
86
87
|
* The mark is letterboxed rather than cropped, so a logo of any aspect ratio
|
|
87
88
|
* can be handed over as it was drawn.
|
|
88
89
|
*/
|
|
89
|
-
function ProductIcon({ name, size = "md", src, tone = "primary", ...props$1 }) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
90
|
+
function ProductIcon({ name, render, size = "md", src, tone = "primary", ...props$1 }) {
|
|
91
|
+
const status = useImageLoadingStatus(src);
|
|
92
|
+
return useRender({
|
|
93
|
+
defaultTagName: "span",
|
|
94
|
+
props: {
|
|
95
|
+
"aria-label": name,
|
|
96
|
+
role: "img",
|
|
97
|
+
...props$1,
|
|
98
|
+
children: status === "loaded" ? /* @__PURE__ */ jsx("img", {
|
|
99
|
+
alt: "",
|
|
100
|
+
src,
|
|
101
|
+
className: "x5yr21d xh8yej3 x19kjcj4"
|
|
102
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
103
|
+
...props(styles.fallback, styles[tone]),
|
|
104
|
+
children: initialFrom(name)
|
|
105
|
+
}),
|
|
106
|
+
...mergeStyles(props(styles.base, styles[size]), props$1)
|
|
107
|
+
},
|
|
108
|
+
render
|
|
103
109
|
});
|
|
104
110
|
}
|
|
105
111
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/product-icon/index.tsx"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/product-icon/index.tsx"],"sourcesContent":["import * as stylex from '@stylexjs/stylex';\nimport type { RenderComponentProps } from '../../render/useRender';\nimport { useImageLoadingStatus } from '../../hooks/useImageLoadingStatus';\nimport { useRender } from '../../render/useRender';\nimport { mergeStyles } from '../../styles/merge';\nimport '../../tokens/design.tokens.stylex';\nimport { colors, radii, typography } from '../../tokens/design.tokens.stylex';\n\n// The counterpart to Avatar: Avatar stands for a person, this stands for\n// everything else — an application, a service, a brand. The two are the same\n// three sizes so either can fill a leading slot without moving what sits\n// beside it, and they differ in the two ways that matter for a mark rather\n// than a face.\n//\n// A rounded square rather than a circle. A logo is drawn to its own bounding\n// box, and a circle crops the corners it was composed with.\n//\n// `contain` rather than `cover`. Cropping a face to fill a circle loses\n// nothing anyone minds; cropping a wordmark loses the word. The cost is\n// letterboxing — a wide mark leaves space above and below — and that is the\n// right trade for a mark whose whole job is to be recognised.\n//\n// That cost is also why `tone` tints the fallback rather than the root. A mark\n// letterboxed into the square does not cover it, and neither does one drawn\n// with transparency, so a tint on the root showed as a coloured box around\n// every logo that was not an opaque square. On the fallback it is seen exactly\n// when it is meant to be: while there is no mark, or none has loaded.\nconst styles = {\n base: {\n kGNEyG: \"x6s0dn4\",\n kaIpWk: \"x1xdvaa9\",\n kB7OPa: \"x9f619\",\n k1xSpc: \"x3nfvp2\",\n kmuXW: \"x2lah0s\",\n kMv6JI: \"xkknnkr\",\n k63SB2: \"x1bf3uqz\",\n kjj79g: \"xl56j7k\",\n kVQacm: \"xb3r6kr\",\n kfSwDN: \"x87ps6o\",\n $$css: true\n },\n fallback: {\n kGNEyG: \"x6s0dn4\",\n kZKoxP: \"x5yr21d\",\n k1xSpc: \"x78zum5\",\n kzqmXN: \"xh8yej3\",\n kjj79g: \"xl56j7k\",\n $$css: true\n },\n image: {\n kZKoxP: \"x5yr21d\",\n kzqmXN: \"xh8yej3\",\n kVIFPx: \"x19kjcj4\",\n $$css: true\n },\n lg: {\n kZKoxP: \"xnnlda6\",\n kGuDYH: \"x1848etk\",\n kzqmXN: \"x15yg21f\",\n $$css: true\n },\n md: {\n kZKoxP: \"x1vqgdyp\",\n kGuDYH: \"x14zspaw\",\n kzqmXN: \"x100vrsf\",\n $$css: true\n },\n negative: {\n kWkggS: \"xkz0cvf\",\n kMwMTN: \"xylzu7l\",\n $$css: true\n },\n positive: {\n kWkggS: \"xa3zu90\",\n kMwMTN: \"x1di7zbg\",\n $$css: true\n },\n primary: {\n kWkggS: \"xp89om9\",\n kMwMTN: \"xscdzaa\",\n $$css: true\n },\n secondary: {\n kWkggS: \"x15dekr4\",\n kMwMTN: \"x1sawysd\",\n $$css: true\n },\n sm: {\n kZKoxP: \"xc9qbxq\",\n kGuDYH: \"xkucv67\",\n kzqmXN: \"x14qfxbe\",\n $$css: true\n },\n tertiary: {\n kWkggS: \"xs6yvni\",\n kMwMTN: \"x3cbcwg\",\n $$css: true\n }\n};\ntype ProductIconProps = Omit<RenderComponentProps<'span'>, 'children'> & {\n /**\n * What this identifies. Supplies both the fallback initial and the\n * accessible name, so a screen reader announces the thing rather than\n * reading a letter aloud.\n */\n name: string;\n /**\n * Edge length: `sm` 36px, `md` 40px, `lg` 56px. The same three Avatar uses,\n * so the two are interchangeable wherever one leads a row or a card.\n * @default 'md'\n */\n size?: 'lg' | 'md' | 'sm';\n /**\n * The mark to show in place of the initial. The initial stays until it has\n * loaded, and comes back if it fails.\n */\n src?: string;\n /**\n * Which container/on-container colour pair to tint the fallback with. It is\n * the fallback's own background, so it is gone once `src` has loaded rather\n * than sitting behind the mark.\n * @default 'primary'\n */\n tone?: 'negative' | 'positive' | 'primary' | 'secondary' | 'tertiary';\n};\n\n// One letter, where Avatar takes two. A person has a first name and a last\n// name to initialise; a thing usually has neither, so the same rule applied\n// to \"Second Item\" would produce \"SI\" — a pair of initials for something that\n// was never two words in that sense. Array.from rather than indexing, so a\n// name starting outside the Basic Multilingual Plane yields its whole first\n// character instead of half a surrogate pair.\nfunction initialFrom(name: string) {\n const trimmed = name.trim();\n return (Array.from(trimmed)[0] ?? '').toLocaleUpperCase();\n}\n\n/**\n * A small square mark identifying something that is not a person — an\n * application, a service, a brand. Reach for Avatar when it is a person.\n *\n * The mark is letterboxed rather than cropped, so a logo of any aspect ratio\n * can be handed over as it was drawn.\n */\nfunction ProductIcon({\n name,\n render,\n size = 'md',\n src,\n tone = 'primary',\n ...props\n}: ProductIconProps) {\n // The mark is shown only once it has loaded, and the letter stays until\n // then and comes back if it fails — see useImageLoadingStatus.\n const status = useImageLoadingStatus(src);\n\n // role/aria-label rather than letting the fallback letter be read: \"B\" is\n // not what anyone means to announce. Marking the root as an image also\n // makes its contents presentational, so neither the mark nor the letter\n // is announced a second time underneath the name. A span rather than an\n // <img>, which is void: this element's whole job is to hold the letter\n // shown when there is no mark, or none has loaded yet.\n return useRender({\n defaultTagName: 'span',\n props: {\n 'aria-label': name,\n role: 'img',\n ...props,\n children: status === 'loaded' ? <img alt=\"\" src={src} className=\"x5yr21d xh8yej3 x19kjcj4\" /> : <span {...stylex.props(styles.fallback, styles[tone])}>\n {initialFrom(name)}\n </span>,\n ...mergeStyles(stylex.props(styles.base, styles[size]), props)\n },\n render\n });\n}\nexport type { ProductIconProps };\nexport default ProductIcon;"],"mappings":";;;;;;AA2BA,MAAM,SAAS;CACb,MAAM;EACJ,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,OAAO;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,SAAS;EACP,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,WAAW;EACT,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,IAAI;EACF,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;CACA,UAAU;EACR,QAAQ;EACR,QAAQ;EACR,OAAO;CACT;AACF;AAkCA,SAAS,YAAY,MAAc;CACjC,MAAM,UAAU,KAAK,KAAK;CAC1B,QAAQ,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM,GAAA,CAAI,kBAAkB;AAC1D;;;;;;;;AASA,SAAS,YAAY,EACnB,MACA,QACA,OAAO,MACP,KACA,OAAO,WACP,GAAG,WACgB;CAGnB,MAAM,SAAS,sBAAsB,GAAG;CAQxC,OAAO,UAAU;EACf,gBAAgB;EAChB,OAAO;GACL,cAAc;GACd,MAAM;GACN,GAAG;GACH,UAAU,WAAW,WAAW,oBAAC,OAAD;IAAK,KAAI;IAAQ;IAAK,WAAU;GAA0B,CAAA,IAAM,oBAAC,QAAD;IAAM,GAAI,MAAa,OAAO,UAAU,OAAO,KAAK;IAC7I,UAAA,YAAY,IAAI;GACb,CAAA;GACV,GAAG,YAAY,MAAa,OAAO,MAAM,OAAO,KAAK,GAAG,OAAK;EAC/D;EACA;CACF,CAAC;AACH"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RenderComponentProps } from "../../render/useRender.js";
|
|
2
2
|
//#region src/components/separator/index.d.ts
|
|
3
|
-
type SeparatorProps
|
|
3
|
+
type SeparatorProps = RenderComponentProps<'div'> & {
|
|
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.
|
|
@@ -8,7 +8,17 @@ type SeparatorProps$1 = Omit<SeparatorProps, 'orientation'> & {
|
|
|
8
8
|
*/
|
|
9
9
|
orientation?: 'horizontal' | 'vertical';
|
|
10
10
|
};
|
|
11
|
-
|
|
11
|
+
/**
|
|
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.
|
|
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.
|
|
20
|
+
*/
|
|
21
|
+
declare function Separator({ orientation, render, ...props }: SeparatorProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
12
22
|
//#endregion
|
|
13
|
-
export { type SeparatorProps
|
|
23
|
+
export { type SeparatorProps, Separator as default };
|
|
14
24
|
//# sourceMappingURL=index.d.ts.map
|