@financedistrict/apps-ui 0.1.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/LICENSE +19 -0
- package/README.md +119 -0
- package/dist/Radio-BYWz1n7p.d.cts +32 -0
- package/dist/Radio-BYWz1n7p.d.ts +32 -0
- package/dist/SelectTrigger-By0iPBI3.d.cts +78 -0
- package/dist/SelectTrigger-By0iPBI3.d.ts +78 -0
- package/dist/accordion.cjs +322 -0
- package/dist/accordion.d.cts +156 -0
- package/dist/accordion.d.ts +156 -0
- package/dist/accordion.js +2 -0
- package/dist/apps-ui.umd.js +1 -0
- package/dist/button.cjs +366 -0
- package/dist/button.d.cts +52 -0
- package/dist/button.d.ts +52 -0
- package/dist/button.js +3 -0
- package/dist/checkbox.cjs +74 -0
- package/dist/checkbox.d.cts +63 -0
- package/dist/checkbox.d.ts +63 -0
- package/dist/checkbox.js +2 -0
- package/dist/chunk-3RU7JMFE.js +27 -0
- package/dist/chunk-5TWRK4NW.js +783 -0
- package/dist/chunk-7EOSDFS3.js +9 -0
- package/dist/chunk-AIQ4UOGK.js +142 -0
- package/dist/chunk-B3MMGTPV.js +200 -0
- package/dist/chunk-DAHQYLUI.js +146 -0
- package/dist/chunk-DGBXADSS.js +1 -0
- package/dist/chunk-E6KPNTWW.js +295 -0
- package/dist/chunk-EOAB6G2D.js +149 -0
- package/dist/chunk-FAOVKDVM.js +32 -0
- package/dist/chunk-FV76Z4Z2.js +78 -0
- package/dist/chunk-GLTLBUZ7.js +285 -0
- package/dist/chunk-GTZFV43T.js +154 -0
- package/dist/chunk-HRGZNL4A.js +88 -0
- package/dist/chunk-IEVN3J2F.js +98 -0
- package/dist/chunk-IRS3T6LF.js +352 -0
- package/dist/chunk-IYYHCQXG.js +146 -0
- package/dist/chunk-JIXW3455.js +89 -0
- package/dist/chunk-N4VAP2GB.js +77 -0
- package/dist/chunk-SJ2ZRYVV.js +167 -0
- package/dist/chunk-SNU4YXOR.js +66 -0
- package/dist/chunk-TT6JQATV.js +99 -0
- package/dist/chunk-UPQ3ZPCO.js +66 -0
- package/dist/chunk-UVUSVFOH.js +264 -0
- package/dist/chunk-WJFPGGJB.js +255 -0
- package/dist/chunk-WXEBQA7A.js +371 -0
- package/dist/chunk-Y2O4YYZQ.js +184 -0
- package/dist/cut-corner.cjs +111 -0
- package/dist/cut-corner.d.cts +49 -0
- package/dist/cut-corner.d.ts +49 -0
- package/dist/cut-corner.js +1 -0
- package/dist/dialog.cjs +441 -0
- package/dist/dialog.d.cts +240 -0
- package/dist/dialog.d.ts +240 -0
- package/dist/dialog.js +3 -0
- package/dist/feature-card.cjs +182 -0
- package/dist/feature-card.d.cts +54 -0
- package/dist/feature-card.d.ts +54 -0
- package/dist/feature-card.js +2 -0
- package/dist/filter.cjs +873 -0
- package/dist/filter.d.cts +129 -0
- package/dist/filter.d.ts +129 -0
- package/dist/filter.js +6 -0
- package/dist/index.cjs +4583 -0
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +27 -0
- package/dist/inline-select.cjs +856 -0
- package/dist/inline-select.d.cts +92 -0
- package/dist/inline-select.d.ts +92 -0
- package/dist/inline-select.js +6 -0
- package/dist/input.cjs +263 -0
- package/dist/input.d.cts +157 -0
- package/dist/input.d.ts +157 -0
- package/dist/input.js +4 -0
- package/dist/panel.cjs +185 -0
- package/dist/panel.d.cts +103 -0
- package/dist/panel.d.ts +103 -0
- package/dist/panel.js +2 -0
- package/dist/property-grid.cjs +110 -0
- package/dist/property-grid.d.cts +56 -0
- package/dist/property-grid.d.ts +56 -0
- package/dist/property-grid.js +2 -0
- package/dist/radio.cjs +74 -0
- package/dist/radio.d.cts +39 -0
- package/dist/radio.d.ts +39 -0
- package/dist/radio.js +2 -0
- package/dist/scrollbar.cjs +34 -0
- package/dist/scrollbar.d.cts +35 -0
- package/dist/scrollbar.d.ts +35 -0
- package/dist/scrollbar.js +1 -0
- package/dist/search-bar.cjs +408 -0
- package/dist/search-bar.d.cts +42 -0
- package/dist/search-bar.d.ts +42 -0
- package/dist/search-bar.js +4 -0
- package/dist/select.cjs +998 -0
- package/dist/select.d.cts +357 -0
- package/dist/select.d.ts +357 -0
- package/dist/select.js +5 -0
- package/dist/selectable-feature-card.cjs +159 -0
- package/dist/selectable-feature-card.d.cts +74 -0
- package/dist/selectable-feature-card.d.ts +74 -0
- package/dist/selectable-feature-card.js +3 -0
- package/dist/sidebar-item.cjs +175 -0
- package/dist/sidebar-item.d.cts +75 -0
- package/dist/sidebar-item.d.ts +75 -0
- package/dist/sidebar-item.js +2 -0
- package/dist/switch.cjs +86 -0
- package/dist/switch.d.cts +72 -0
- package/dist/switch.d.ts +72 -0
- package/dist/switch.js +2 -0
- package/dist/table-cell.cjs +196 -0
- package/dist/table-cell.d.cts +76 -0
- package/dist/table-cell.d.ts +76 -0
- package/dist/table-cell.js +2 -0
- package/dist/table-title.cjs +34 -0
- package/dist/table-title.d.cts +16 -0
- package/dist/table-title.d.ts +16 -0
- package/dist/table-title.js +2 -0
- package/dist/tabs.cjs +299 -0
- package/dist/tabs.d.cts +116 -0
- package/dist/tabs.d.ts +116 -0
- package/dist/tabs.js +2 -0
- package/dist/toast.cjs +87 -0
- package/dist/toast.d.cts +48 -0
- package/dist/toast.d.ts +48 -0
- package/dist/toast.js +2 -0
- package/dist/token-input.cjs +415 -0
- package/dist/token-input.d.cts +90 -0
- package/dist/token-input.d.ts +90 -0
- package/dist/token-input.js +3 -0
- package/dist/tooltip.cjs +384 -0
- package/dist/tooltip.d.cts +142 -0
- package/dist/tooltip.d.ts +142 -0
- package/dist/tooltip.js +2 -0
- package/package.json +200 -0
- package/src/fonts.css +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 First Digital Trust Limited ("FD"). All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and the accompanying files (the "Software") are proprietary and
|
|
4
|
+
confidential to FD. The Software is published to a public package registry
|
|
5
|
+
solely to allow installation and use by FD's own applications and by prototypes
|
|
6
|
+
authorized in writing by FD. Publication to that registry does NOT place the
|
|
7
|
+
Software in the public domain and does NOT grant any license under FD's
|
|
8
|
+
copyright or other rights.
|
|
9
|
+
|
|
10
|
+
Except as expressly permitted by a separate written agreement with FD, no
|
|
11
|
+
person or entity may use, copy, reproduce, modify, adapt, merge, publish,
|
|
12
|
+
redistribute, sublicense, or sell the Software or any portion of it, or create
|
|
13
|
+
derivative works from it.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL FD BE LIABLE
|
|
18
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN
|
|
19
|
+
CONNECTION WITH THE SOFTWARE OR ITS USE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# @financedistrict/apps-ui
|
|
2
|
+
|
|
3
|
+
The **single shared base-component library** for all FD apps (Button, Input, Modal, DataTable, etc.). App-specific _semantic_ components do NOT live here — they live in each app.
|
|
4
|
+
|
|
5
|
+
**React + Tailwind v4** (ADR-0001), styled via Tailwind utility classes — semantic tokens from `@financedistrict/apps-tokens` where a value is meant to be shared, plain Tailwind utilities and arbitrary values for everything component-specific (see Authoring rules below). Components are authored RSC-safe **unless they measure their own geometry** — anything with a cut corner (`clip-path` measured via `useLayoutEffect`/`ResizeObserver`) is `"use client"` (a standard RSC opt-out, not a framework-specific API). See ADR-0009.
|
|
6
|
+
|
|
7
|
+
## Components
|
|
8
|
+
|
|
9
|
+
### Button (`@financedistrict/apps-ui/button`)
|
|
10
|
+
|
|
11
|
+
`cva` variant table + `cn`, bound to the `--button-*` semantic tokens (ADR-0009). Cut corners via `@financedistrict/apps-ui/cut-corner`.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Button } from "@financedistrict/apps-ui/button";
|
|
15
|
+
import { PlusIcon } from "@phosphor-icons/react";
|
|
16
|
+
|
|
17
|
+
<Button variation="primary" size="lg" onClick={...}>Save</Button>
|
|
18
|
+
<Button variation="secondary" leftSlot={<PlusIcon />}>Add</Button>
|
|
19
|
+
<Button variation="brand" loading>Submitting</Button>
|
|
20
|
+
<Button variation="ghost" iconOnly aria-label="More"><PlusIcon /></Button>
|
|
21
|
+
<Button asChild variation="primary"><a href="/x">Link</a></Button>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- **`variation`**: `primary` (black) · `secondary` (outline) · `brand` (purple) · `ghost` · `destructive`. **`size`**: `sm` · `lg`. Plus `iconOnly`, `loading`, `asChild`, `leftSlot`/`rightSlot`.
|
|
25
|
+
- Cut corners on every variation except `ghost`; the `secondary` border follows the chamfer as an SVG stroke.
|
|
26
|
+
|
|
27
|
+
## Storybook
|
|
28
|
+
|
|
29
|
+
Local authoring environment (never a CI gate):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run storybook # from the repo root (or this package) — http://localhost:6006
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **Framework: `@storybook/nextjs-vite`** (Vite under the hood). **Preview = an app's CSS entry:** `.storybook/preview.css` runs Tailwind v4 and imports `@financedistrict/apps-ui/fonts.css` + `@financedistrict/apps-tokens/theme.css`, so Archivo / Chakra Petch resolve through the portable `@fontsource` default (ADR-0008) exactly as in an app.
|
|
36
|
+
- **Theme toolbar** toggles the `light`/`dark` ancestor class — the same mechanism apps use, so stories need no `dark:` variants.
|
|
37
|
+
- Stories are colocated: `src/<component>/<Component>.stories.tsx`.
|
|
38
|
+
|
|
39
|
+
## Fonts
|
|
40
|
+
|
|
41
|
+
This package doesn't own font _loading_ — only `@financedistrict/apps-tokens`
|
|
42
|
+
`theme.css`'s CSS variable contract (`--font-archivo`, `--font-chakra-petch`), which
|
|
43
|
+
is all it actually reads (see [ADR-0008](../../docs/adr/0008-framework-agnostic-fonts.md)).
|
|
44
|
+
`fonts.css` is one _optional_ way to satisfy that contract, using
|
|
45
|
+
[`@fontsource`](https://fontsource.org/) — self-hosted `@font-face` rules, no
|
|
46
|
+
compiler-specific transform, so it works identically under Vite, Next, a UMD build,
|
|
47
|
+
or a plain static HTML file with no build step.
|
|
48
|
+
|
|
49
|
+
```css
|
|
50
|
+
/* app's main CSS entry */
|
|
51
|
+
@import "@financedistrict/apps-ui/fonts.css";
|
|
52
|
+
@import "@financedistrict/apps-tokens/theme.css";
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That's it — no JS wrapper, no root-element `className` to apply. Importing the CSS
|
|
56
|
+
registers the `@font-face` rules and defines the two variables globally.
|
|
57
|
+
|
|
58
|
+
Any app is free to load these fonts a different way instead — a plain Google Fonts
|
|
59
|
+
`<link>` tag (what zero-build CDN prototypes already do), `next/font/google` in a
|
|
60
|
+
Next app's own root layout, whatever fits — as long as it ends up defining the same
|
|
61
|
+
two variable names.
|
|
62
|
+
|
|
63
|
+
## Icons
|
|
64
|
+
|
|
65
|
+
Phosphor only — see `.claude/rules/icons.md` (regular + fill weights, no inline SVG).
|
|
66
|
+
|
|
67
|
+
## Authoring rules
|
|
68
|
+
|
|
69
|
+
This package ships two builds from one source (see
|
|
70
|
+
[`docs/guides/standalone-prototype-consumption.md`](../../docs/guides/standalone-prototype-consumption.md))
|
|
71
|
+
— a normal ESM/CJS build for the four apps, and a UMD bundle for zero-build CDN
|
|
72
|
+
prototypes. A few rules exist specifically so both builds stay possible from the same
|
|
73
|
+
component code:
|
|
74
|
+
|
|
75
|
+
- **Style entirely through Tailwind utility classes in `className` — not through a
|
|
76
|
+
separate CSS file or CSS-in-JS.** This is _not_ "everything must be a shared
|
|
77
|
+
token." Three tiers, all fine, all just utility classes:
|
|
78
|
+
1. Shared semantic tokens for values that repeat across components/apps and need
|
|
79
|
+
to change consistently (`bg-card-background`, `text-focus`) — these come from
|
|
80
|
+
`@financedistrict/apps-tokens`.
|
|
81
|
+
2. Plain Tailwind utilities that aren't tokens at all (`flex`, `gap-2`,
|
|
82
|
+
`items-center`, `rounded-md`) — completely normal for a component's own layout,
|
|
83
|
+
nothing to promote anywhere.
|
|
84
|
+
3. A genuine one-off value that isn't worth sharing — use Tailwind's arbitrary-value
|
|
85
|
+
syntax (`top-[3px]`, `mt-[7px]`) directly in the component. Still just a utility
|
|
86
|
+
class, still lives entirely in that one component.
|
|
87
|
+
Never primitives (`--purple-500`) or raw inline hex/pixel `style` props — anything
|
|
88
|
+
expressible as a class should be one, from whichever of the three tiers actually
|
|
89
|
+
fits.
|
|
90
|
+
- **What's actually disallowed: a standalone CSS file or CSS-in-JS
|
|
91
|
+
(`Button.module.css`, styled-components, emotion, `<style jsx>`).** Not because
|
|
92
|
+
components can't have their own styling (they can, extensively — see above) but
|
|
93
|
+
because the CDN path has exactly one CSS delivery mechanism: `dist/tokens.css`,
|
|
94
|
+
produced by scanning every component's utility classes (see the content-scan
|
|
95
|
+
requirement in the consumption guide). A separate stylesheet or runtime-injected
|
|
96
|
+
styles has no way to reach a prototype that only ever loads that one file.
|
|
97
|
+
- **Never `import` `@financedistrict/apps-tokens`'s CSS from inside component
|
|
98
|
+
source**, for the same reason — the CSS gets loaded separately by whoever consumes
|
|
99
|
+
the component (an app importing `theme.css` itself, or a prototype linking
|
|
100
|
+
`dist/tokens.css` itself). A component should never assume it's responsible for
|
|
101
|
+
loading its own tokens.
|
|
102
|
+
- **No framework-specific APIs.** Nothing that only runs under Next.js, nothing that
|
|
103
|
+
assumes RSC. Components must render correctly in a plain client-rendered
|
|
104
|
+
environment, since the CDN path is exactly that and the four real apps are Vite,
|
|
105
|
+
not Next. This is the rule `next/font/google` violated (see
|
|
106
|
+
[ADR-0008](../../docs/adr/0008-framework-agnostic-fonts.md)) — fixed by not
|
|
107
|
+
repeating the mistake with a different framework-specific API later.
|
|
108
|
+
- **Don't assume a specific React renderer wiring beyond the `react`/`react-dom` peer
|
|
109
|
+
dependencies.** The UMD build declares both external — it will not bundle its own
|
|
110
|
+
copy of React. Relying on anything Next- or Vite-specific breaks that assumption.
|
|
111
|
+
|
|
112
|
+
## Consuming from a zero-build prototype (CDN)
|
|
113
|
+
|
|
114
|
+
This README covers the normal `npm install` + `import` path, used by the four real
|
|
115
|
+
apps. Standalone HTML/JSX prototypes (Metacarbon's screen deliveries) consume a
|
|
116
|
+
different build of this same package — a UMD bundle loaded via `<script src>`, no
|
|
117
|
+
bundler involved. See
|
|
118
|
+
[`docs/guides/standalone-prototype-consumption.md`](../../docs/guides/standalone-prototype-consumption.md)
|
|
119
|
+
for the exact `index.html` shape and the global variable name (`window.FDAppsUI`).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface RadioProps extends Omit<React.ComponentProps<"input">, "type" | "size"> {
|
|
4
|
+
/**
|
|
5
|
+
* Convenience change callback with the next checked state already
|
|
6
|
+
* extracted. Fires alongside (not instead of) the native `onChange`.
|
|
7
|
+
* Radio semantics: the platform fires `change` only when this radio
|
|
8
|
+
* BECOMES checked (never on deselection by a sibling), so the payload is
|
|
9
|
+
* `true` in practice — the boolean type keeps the ADR-0010 `on<Value>Change`
|
|
10
|
+
* contract shared with Checkbox. Controlled/uncontrolled usage is the
|
|
11
|
+
* standard input contract: `defaultChecked` (uncontrolled, the default) or
|
|
12
|
+
* `checked` + a change handler (controlled).
|
|
13
|
+
*/
|
|
14
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
15
|
+
/** Class names for the outer wrapper span (positions the ● indicator). */
|
|
16
|
+
wrapperClassName?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Radio control — the Figma `radio-control` set (node 5117:5677), rendered as
|
|
20
|
+
* a real `<input type="radio">` so grouping (`name`), keyboard behavior
|
|
21
|
+
* (arrow keys move selection within a group; only the checked radio is in the
|
|
22
|
+
* tab order), forms, and label association all come from the platform. There
|
|
23
|
+
* is no RadioGroup wrapper: give radios the same `name` and wrap the set in a
|
|
24
|
+
* `<fieldset>` with a `<legend>` for a group label.
|
|
25
|
+
*
|
|
26
|
+
* Ships without a label (the Figma set is the bare 20×20 control): associate
|
|
27
|
+
* one by wrapping in a `<label>` or via `htmlFor`/`id`; icon-style usages
|
|
28
|
+
* need an `aria-label`.
|
|
29
|
+
*/
|
|
30
|
+
declare function Radio({ className, wrapperClassName, onChange, onCheckedChange, ...props }: RadioProps): React.JSX.Element;
|
|
31
|
+
|
|
32
|
+
export { Radio as R, type RadioProps as a };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface RadioProps extends Omit<React.ComponentProps<"input">, "type" | "size"> {
|
|
4
|
+
/**
|
|
5
|
+
* Convenience change callback with the next checked state already
|
|
6
|
+
* extracted. Fires alongside (not instead of) the native `onChange`.
|
|
7
|
+
* Radio semantics: the platform fires `change` only when this radio
|
|
8
|
+
* BECOMES checked (never on deselection by a sibling), so the payload is
|
|
9
|
+
* `true` in practice — the boolean type keeps the ADR-0010 `on<Value>Change`
|
|
10
|
+
* contract shared with Checkbox. Controlled/uncontrolled usage is the
|
|
11
|
+
* standard input contract: `defaultChecked` (uncontrolled, the default) or
|
|
12
|
+
* `checked` + a change handler (controlled).
|
|
13
|
+
*/
|
|
14
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
15
|
+
/** Class names for the outer wrapper span (positions the ● indicator). */
|
|
16
|
+
wrapperClassName?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Radio control — the Figma `radio-control` set (node 5117:5677), rendered as
|
|
20
|
+
* a real `<input type="radio">` so grouping (`name`), keyboard behavior
|
|
21
|
+
* (arrow keys move selection within a group; only the checked radio is in the
|
|
22
|
+
* tab order), forms, and label association all come from the platform. There
|
|
23
|
+
* is no RadioGroup wrapper: give radios the same `name` and wrap the set in a
|
|
24
|
+
* `<fieldset>` with a `<legend>` for a group label.
|
|
25
|
+
*
|
|
26
|
+
* Ships without a label (the Figma set is the bare 20×20 control): associate
|
|
27
|
+
* one by wrapping in a `<label>` or via `htmlFor`/`id`; icon-style usages
|
|
28
|
+
* need an `aria-label`.
|
|
29
|
+
*/
|
|
30
|
+
declare function Radio({ className, wrapperClassName, onChange, onCheckedChange, ...props }: RadioProps): React.JSX.Element;
|
|
31
|
+
|
|
32
|
+
export { Radio as R, type RadioProps as a };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/** A selectable option. `disabled` rows render but are skipped by keyboard nav. */
|
|
4
|
+
type SelectOption = {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Optional adornment before the label (usually a 16px Phosphor icon). In
|
|
10
|
+
* multi mode it sits after the checkbox (checkbox → leading → label). Purely
|
|
11
|
+
* decorative — rendered `aria-hidden`, and it inherits the row's text colour
|
|
12
|
+
* (so it recolours to the brand foreground on the single-select selected row).
|
|
13
|
+
*/
|
|
14
|
+
leadingSlot?: React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Optional adornment after the label (usually a 16px Phosphor icon), pinned to
|
|
17
|
+
* the trailing edge of the row. Decorative + colour-inheriting, like
|
|
18
|
+
* `leadingSlot`.
|
|
19
|
+
*/
|
|
20
|
+
trailingSlot?: React.ReactNode;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Pure value-display helper — decides what the trigger shows for a given
|
|
24
|
+
* selection. Kept free of React so it is unit-testable in isolation:
|
|
25
|
+
* - `[]` → the placeholder (`isPlaceholder: true`)
|
|
26
|
+
* - one → that option's label
|
|
27
|
+
* - many → `"${n} selected"` (never overflows the single lg line)
|
|
28
|
+
*
|
|
29
|
+
* A selected value with no matching option is ignored for the single-label case
|
|
30
|
+
* (it can't be labelled); the count path still counts it.
|
|
31
|
+
*/
|
|
32
|
+
declare function selectTriggerLabel(options: SelectOption[], selected: string[], placeholder: string): {
|
|
33
|
+
text: string;
|
|
34
|
+
isPlaceholder: boolean;
|
|
35
|
+
};
|
|
36
|
+
interface SelectTriggerProps extends Omit<React.ComponentProps<"button">, "value"> {
|
|
37
|
+
/** `field` (bordered box) | `line` (bottom border only). */
|
|
38
|
+
variation?: "field" | "line";
|
|
39
|
+
/** Error state — destructive border/label/hint (out-ranks the focus border). */
|
|
40
|
+
error?: boolean;
|
|
41
|
+
/** LINE-only: hide the resting bottom line (still shows on focus/error). */
|
|
42
|
+
showBottomLine?: boolean;
|
|
43
|
+
/** Whether the listbox is currently open (flips the caret + `aria-expanded`). */
|
|
44
|
+
open?: boolean;
|
|
45
|
+
/** Resolved display text (from `selectTriggerLabel`). */
|
|
46
|
+
displayText: string;
|
|
47
|
+
/** Whether `displayText` is the placeholder (muted) vs a real value (accent). */
|
|
48
|
+
isPlaceholder: boolean;
|
|
49
|
+
/** Uppercase label above the field; omitted → no label row. */
|
|
50
|
+
label?: React.ReactNode;
|
|
51
|
+
/** Helper text below the field; destructive when `error`. */
|
|
52
|
+
hint?: React.ReactNode;
|
|
53
|
+
/** Leading adornment (decorative — kept out of the a11y tree via `aria-hidden`). */
|
|
54
|
+
leadingSlot?: React.ReactNode;
|
|
55
|
+
/** id of the field `<button>` (label association + `aria-labelledby` target). */
|
|
56
|
+
id: string;
|
|
57
|
+
/** id of the hint node, linked via `aria-describedby` when a hint is present. */
|
|
58
|
+
hintId?: string;
|
|
59
|
+
/** Class names for the outer wrapper (the label/field/hint stack). */
|
|
60
|
+
wrapperClassName?: string;
|
|
61
|
+
/** Class names for the field row (the trigger button), not the wrapper. */
|
|
62
|
+
fieldClassName?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The Select trigger — a `<button type="button">` styled as an input field
|
|
66
|
+
* (reusing `inputVariants`), with an optional uppercase label above and a hint
|
|
67
|
+
* below (both owned by the component, mirroring `Input`). It renders a leading
|
|
68
|
+
* slot, the current value (or placeholder), and a trailing caret that flips
|
|
69
|
+
* when `open`.
|
|
70
|
+
*
|
|
71
|
+
* This is a presentational leaf: all open/selection/keyboard orchestration and
|
|
72
|
+
* the ARIA popup wiring (`aria-haspopup`/`aria-expanded`/`aria-controls`/
|
|
73
|
+
* `aria-activedescendant`) live in `Select`, which spreads them through
|
|
74
|
+
* `...props`. `ref` is a normal React 19 prop, forwarded to the button.
|
|
75
|
+
*/
|
|
76
|
+
declare function SelectTrigger({ variation, error, showBottomLine, open, displayText, isPlaceholder, label, hint, leadingSlot, id, hintId, disabled, className, wrapperClassName, fieldClassName, ref, ...props }: SelectTriggerProps): React.JSX.Element;
|
|
77
|
+
|
|
78
|
+
export { type SelectOption as S, SelectTrigger as a, type SelectTriggerProps as b, selectTriggerLabel as s };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/** A selectable option. `disabled` rows render but are skipped by keyboard nav. */
|
|
4
|
+
type SelectOption = {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Optional adornment before the label (usually a 16px Phosphor icon). In
|
|
10
|
+
* multi mode it sits after the checkbox (checkbox → leading → label). Purely
|
|
11
|
+
* decorative — rendered `aria-hidden`, and it inherits the row's text colour
|
|
12
|
+
* (so it recolours to the brand foreground on the single-select selected row).
|
|
13
|
+
*/
|
|
14
|
+
leadingSlot?: React.ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Optional adornment after the label (usually a 16px Phosphor icon), pinned to
|
|
17
|
+
* the trailing edge of the row. Decorative + colour-inheriting, like
|
|
18
|
+
* `leadingSlot`.
|
|
19
|
+
*/
|
|
20
|
+
trailingSlot?: React.ReactNode;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Pure value-display helper — decides what the trigger shows for a given
|
|
24
|
+
* selection. Kept free of React so it is unit-testable in isolation:
|
|
25
|
+
* - `[]` → the placeholder (`isPlaceholder: true`)
|
|
26
|
+
* - one → that option's label
|
|
27
|
+
* - many → `"${n} selected"` (never overflows the single lg line)
|
|
28
|
+
*
|
|
29
|
+
* A selected value with no matching option is ignored for the single-label case
|
|
30
|
+
* (it can't be labelled); the count path still counts it.
|
|
31
|
+
*/
|
|
32
|
+
declare function selectTriggerLabel(options: SelectOption[], selected: string[], placeholder: string): {
|
|
33
|
+
text: string;
|
|
34
|
+
isPlaceholder: boolean;
|
|
35
|
+
};
|
|
36
|
+
interface SelectTriggerProps extends Omit<React.ComponentProps<"button">, "value"> {
|
|
37
|
+
/** `field` (bordered box) | `line` (bottom border only). */
|
|
38
|
+
variation?: "field" | "line";
|
|
39
|
+
/** Error state — destructive border/label/hint (out-ranks the focus border). */
|
|
40
|
+
error?: boolean;
|
|
41
|
+
/** LINE-only: hide the resting bottom line (still shows on focus/error). */
|
|
42
|
+
showBottomLine?: boolean;
|
|
43
|
+
/** Whether the listbox is currently open (flips the caret + `aria-expanded`). */
|
|
44
|
+
open?: boolean;
|
|
45
|
+
/** Resolved display text (from `selectTriggerLabel`). */
|
|
46
|
+
displayText: string;
|
|
47
|
+
/** Whether `displayText` is the placeholder (muted) vs a real value (accent). */
|
|
48
|
+
isPlaceholder: boolean;
|
|
49
|
+
/** Uppercase label above the field; omitted → no label row. */
|
|
50
|
+
label?: React.ReactNode;
|
|
51
|
+
/** Helper text below the field; destructive when `error`. */
|
|
52
|
+
hint?: React.ReactNode;
|
|
53
|
+
/** Leading adornment (decorative — kept out of the a11y tree via `aria-hidden`). */
|
|
54
|
+
leadingSlot?: React.ReactNode;
|
|
55
|
+
/** id of the field `<button>` (label association + `aria-labelledby` target). */
|
|
56
|
+
id: string;
|
|
57
|
+
/** id of the hint node, linked via `aria-describedby` when a hint is present. */
|
|
58
|
+
hintId?: string;
|
|
59
|
+
/** Class names for the outer wrapper (the label/field/hint stack). */
|
|
60
|
+
wrapperClassName?: string;
|
|
61
|
+
/** Class names for the field row (the trigger button), not the wrapper. */
|
|
62
|
+
fieldClassName?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The Select trigger — a `<button type="button">` styled as an input field
|
|
66
|
+
* (reusing `inputVariants`), with an optional uppercase label above and a hint
|
|
67
|
+
* below (both owned by the component, mirroring `Input`). It renders a leading
|
|
68
|
+
* slot, the current value (or placeholder), and a trailing caret that flips
|
|
69
|
+
* when `open`.
|
|
70
|
+
*
|
|
71
|
+
* This is a presentational leaf: all open/selection/keyboard orchestration and
|
|
72
|
+
* the ARIA popup wiring (`aria-haspopup`/`aria-expanded`/`aria-controls`/
|
|
73
|
+
* `aria-activedescendant`) live in `Select`, which spreads them through
|
|
74
|
+
* `...props`. `ref` is a normal React 19 prop, forwarded to the button.
|
|
75
|
+
*/
|
|
76
|
+
declare function SelectTrigger({ variation, error, showBottomLine, open, displayText, isPlaceholder, label, hint, leadingSlot, id, hintId, disabled, className, wrapperClassName, fieldClassName, ref, ...props }: SelectTriggerProps): React.JSX.Element;
|
|
77
|
+
|
|
78
|
+
export { type SelectOption as S, SelectTrigger as a, type SelectTriggerProps as b, selectTriggerLabel as s };
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var react = require('@phosphor-icons/react');
|
|
5
|
+
var clsx = require('clsx');
|
|
6
|
+
var tailwindMerge = require('tailwind-merge');
|
|
7
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
8
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
29
|
+
|
|
30
|
+
// src/accordion/Accordion.tsx
|
|
31
|
+
function cn(...inputs) {
|
|
32
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
33
|
+
}
|
|
34
|
+
var accordionRootVariants = classVarianceAuthority.cva(["flex flex-col"]);
|
|
35
|
+
var accordionItemVariants = classVarianceAuthority.cva(["border-b border-card-border"], {
|
|
36
|
+
variants: {
|
|
37
|
+
disabled: {
|
|
38
|
+
true: "opacity-60",
|
|
39
|
+
false: ""
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: {
|
|
43
|
+
disabled: false
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
var accordionTriggerVariants = classVarianceAuthority.cva(
|
|
47
|
+
[
|
|
48
|
+
"group flex w-full cursor-pointer items-start gap-4 pt-3 text-left",
|
|
49
|
+
"outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus",
|
|
50
|
+
"disabled:cursor-not-allowed"
|
|
51
|
+
],
|
|
52
|
+
{
|
|
53
|
+
variants: {
|
|
54
|
+
open: {
|
|
55
|
+
true: "pb-2",
|
|
56
|
+
false: "pb-3"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
open: false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
var accordionTriggerTitleVariants = classVarianceAuthority.cva([
|
|
65
|
+
"body-02-medium min-w-0 flex-1 break-words text-card-foreground"
|
|
66
|
+
]);
|
|
67
|
+
var accordionTriggerIconVariants = classVarianceAuthority.cva([
|
|
68
|
+
"flex shrink-0 items-center text-card-foreground-muted transition-colors",
|
|
69
|
+
"group-hover:text-card-foreground",
|
|
70
|
+
"[&_svg]:size-4 [&_svg]:shrink-0"
|
|
71
|
+
]);
|
|
72
|
+
var accordionContentVariants = classVarianceAuthority.cva([
|
|
73
|
+
"body-03 pb-3 text-card-foreground-muted"
|
|
74
|
+
]);
|
|
75
|
+
var AccordionContext = React__namespace.createContext(
|
|
76
|
+
null
|
|
77
|
+
);
|
|
78
|
+
function useAccordionContext(part) {
|
|
79
|
+
const context = React__namespace.useContext(AccordionContext);
|
|
80
|
+
if (context === null) {
|
|
81
|
+
throw new Error(`${part} must be used within <Accordion.Root>`);
|
|
82
|
+
}
|
|
83
|
+
return context;
|
|
84
|
+
}
|
|
85
|
+
var AccordionItemContext = React__namespace.createContext(null);
|
|
86
|
+
function useAccordionItemContext(part) {
|
|
87
|
+
const context = React__namespace.useContext(AccordionItemContext);
|
|
88
|
+
if (context === null) {
|
|
89
|
+
throw new Error(`${part} must be used within <Accordion.Item>`);
|
|
90
|
+
}
|
|
91
|
+
return context;
|
|
92
|
+
}
|
|
93
|
+
function setRef(ref, node) {
|
|
94
|
+
if (typeof ref === "function") ref(node);
|
|
95
|
+
else if (ref) ref.current = node;
|
|
96
|
+
}
|
|
97
|
+
function AccordionRoot({
|
|
98
|
+
type = "single",
|
|
99
|
+
value: valueProp,
|
|
100
|
+
defaultValue,
|
|
101
|
+
onValueChange,
|
|
102
|
+
collapsible = true,
|
|
103
|
+
className,
|
|
104
|
+
children,
|
|
105
|
+
ref,
|
|
106
|
+
...props
|
|
107
|
+
}) {
|
|
108
|
+
const isMultiple = type === "multiple";
|
|
109
|
+
const isControlled = valueProp !== void 0;
|
|
110
|
+
const [uncontrolledValue, setUncontrolledValue] = React__namespace.useState(
|
|
111
|
+
() => defaultValue !== void 0 ? defaultValue : isMultiple ? [] : null
|
|
112
|
+
);
|
|
113
|
+
const openModel = isControlled ? valueProp : uncontrolledValue;
|
|
114
|
+
const commit = (next) => {
|
|
115
|
+
if (!isControlled) setUncontrolledValue(next);
|
|
116
|
+
onValueChange?.(next);
|
|
117
|
+
};
|
|
118
|
+
const isOpen = (itemValue) => isMultiple ? Array.isArray(openModel) && openModel.includes(itemValue) : openModel === itemValue;
|
|
119
|
+
const toggle = (itemValue) => {
|
|
120
|
+
if (isMultiple) {
|
|
121
|
+
const current2 = Array.isArray(openModel) ? openModel : [];
|
|
122
|
+
commit(
|
|
123
|
+
current2.includes(itemValue) ? current2.filter((v) => v !== itemValue) : [...current2, itemValue]
|
|
124
|
+
);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const current = Array.isArray(openModel) ? null : openModel;
|
|
128
|
+
if (current === itemValue) {
|
|
129
|
+
commit(collapsible ? null : itemValue);
|
|
130
|
+
} else {
|
|
131
|
+
commit(itemValue);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const triggersRef = React__namespace.useRef(/* @__PURE__ */ new Set());
|
|
135
|
+
const registerTrigger = React__namespace.useCallback((node) => {
|
|
136
|
+
triggersRef.current.add(node);
|
|
137
|
+
}, []);
|
|
138
|
+
const unregisterTrigger = React__namespace.useCallback((node) => {
|
|
139
|
+
triggersRef.current.delete(node);
|
|
140
|
+
}, []);
|
|
141
|
+
const onTriggerKeyDown = (event) => {
|
|
142
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
143
|
+
const triggers = Array.from(triggersRef.current).filter((el) => !el.disabled).sort(
|
|
144
|
+
(a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
|
|
145
|
+
);
|
|
146
|
+
if (triggers.length === 0) return;
|
|
147
|
+
const currentIndex = triggers.indexOf(event.currentTarget);
|
|
148
|
+
if (currentIndex === -1) return;
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
let nextIndex = currentIndex;
|
|
151
|
+
switch (event.key) {
|
|
152
|
+
case "ArrowDown":
|
|
153
|
+
nextIndex = (currentIndex + 1) % triggers.length;
|
|
154
|
+
break;
|
|
155
|
+
case "ArrowUp":
|
|
156
|
+
nextIndex = (currentIndex - 1 + triggers.length) % triggers.length;
|
|
157
|
+
break;
|
|
158
|
+
case "Home":
|
|
159
|
+
nextIndex = 0;
|
|
160
|
+
break;
|
|
161
|
+
case "End":
|
|
162
|
+
nextIndex = triggers.length - 1;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
triggers[nextIndex]?.focus();
|
|
166
|
+
};
|
|
167
|
+
const contextValue = {
|
|
168
|
+
type,
|
|
169
|
+
isOpen,
|
|
170
|
+
toggle,
|
|
171
|
+
registerTrigger,
|
|
172
|
+
unregisterTrigger,
|
|
173
|
+
onTriggerKeyDown
|
|
174
|
+
};
|
|
175
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AccordionContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
176
|
+
"div",
|
|
177
|
+
{
|
|
178
|
+
ref,
|
|
179
|
+
"data-slot": "accordion",
|
|
180
|
+
className: cn(accordionRootVariants(), className),
|
|
181
|
+
...props,
|
|
182
|
+
children
|
|
183
|
+
}
|
|
184
|
+
) });
|
|
185
|
+
}
|
|
186
|
+
function AccordionItem({
|
|
187
|
+
value,
|
|
188
|
+
disabled = false,
|
|
189
|
+
className,
|
|
190
|
+
children,
|
|
191
|
+
ref,
|
|
192
|
+
...props
|
|
193
|
+
}) {
|
|
194
|
+
const { isOpen } = useAccordionContext("Accordion.Item");
|
|
195
|
+
const open = isOpen(value);
|
|
196
|
+
const reactId = React__namespace.useId();
|
|
197
|
+
const triggerId = `${reactId}-trigger`;
|
|
198
|
+
const contentId = `${reactId}-content`;
|
|
199
|
+
const itemContext = {
|
|
200
|
+
value,
|
|
201
|
+
open,
|
|
202
|
+
disabled,
|
|
203
|
+
triggerId,
|
|
204
|
+
contentId
|
|
205
|
+
};
|
|
206
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AccordionItemContext.Provider, { value: itemContext, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
ref,
|
|
210
|
+
"data-slot": "accordion-item",
|
|
211
|
+
"data-state": open ? "open" : "closed",
|
|
212
|
+
"data-disabled": disabled || void 0,
|
|
213
|
+
className: cn(accordionItemVariants({ disabled }), className),
|
|
214
|
+
...props,
|
|
215
|
+
children
|
|
216
|
+
}
|
|
217
|
+
) });
|
|
218
|
+
}
|
|
219
|
+
function AccordionTrigger({
|
|
220
|
+
className,
|
|
221
|
+
children,
|
|
222
|
+
onClick,
|
|
223
|
+
onKeyDown,
|
|
224
|
+
ref,
|
|
225
|
+
...props
|
|
226
|
+
}) {
|
|
227
|
+
const { toggle, registerTrigger, unregisterTrigger, onTriggerKeyDown } = useAccordionContext("Accordion.Trigger");
|
|
228
|
+
const { value, open, disabled, triggerId, contentId } = useAccordionItemContext("Accordion.Trigger");
|
|
229
|
+
const buttonRef = React__namespace.useRef(null);
|
|
230
|
+
const setButtonRef = (node) => {
|
|
231
|
+
buttonRef.current = node;
|
|
232
|
+
setRef(ref, node);
|
|
233
|
+
};
|
|
234
|
+
React__namespace.useEffect(() => {
|
|
235
|
+
const node = buttonRef.current;
|
|
236
|
+
if (!node) return;
|
|
237
|
+
registerTrigger(node);
|
|
238
|
+
return () => unregisterTrigger(node);
|
|
239
|
+
}, [registerTrigger, unregisterTrigger]);
|
|
240
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
241
|
+
"button",
|
|
242
|
+
{
|
|
243
|
+
...props,
|
|
244
|
+
ref: setButtonRef,
|
|
245
|
+
type: "button",
|
|
246
|
+
id: triggerId,
|
|
247
|
+
"data-slot": "accordion-trigger",
|
|
248
|
+
"aria-expanded": open,
|
|
249
|
+
"aria-controls": open ? contentId : void 0,
|
|
250
|
+
disabled,
|
|
251
|
+
className: cn(accordionTriggerVariants({ open }), className),
|
|
252
|
+
onClick: (event) => {
|
|
253
|
+
onClick?.(event);
|
|
254
|
+
if (!event.defaultPrevented) toggle(value);
|
|
255
|
+
},
|
|
256
|
+
onKeyDown: (event) => {
|
|
257
|
+
onKeyDown?.(event);
|
|
258
|
+
if (!event.defaultPrevented) onTriggerKeyDown(event);
|
|
259
|
+
},
|
|
260
|
+
children: [
|
|
261
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
262
|
+
"span",
|
|
263
|
+
{
|
|
264
|
+
"data-slot": "accordion-trigger-title",
|
|
265
|
+
className: accordionTriggerTitleVariants(),
|
|
266
|
+
children
|
|
267
|
+
}
|
|
268
|
+
),
|
|
269
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
270
|
+
"span",
|
|
271
|
+
{
|
|
272
|
+
"data-slot": "accordion-trigger-icon",
|
|
273
|
+
"aria-hidden": "true",
|
|
274
|
+
className: accordionTriggerIconVariants(),
|
|
275
|
+
children: open ? /* @__PURE__ */ jsxRuntime.jsx(react.MinusIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(react.PlusIcon, {})
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
]
|
|
279
|
+
}
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function AccordionContent({
|
|
283
|
+
className,
|
|
284
|
+
children,
|
|
285
|
+
ref,
|
|
286
|
+
...props
|
|
287
|
+
}) {
|
|
288
|
+
const { open, triggerId, contentId } = useAccordionItemContext("Accordion.Content");
|
|
289
|
+
if (!open) return null;
|
|
290
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
291
|
+
"div",
|
|
292
|
+
{
|
|
293
|
+
ref,
|
|
294
|
+
role: "region",
|
|
295
|
+
id: contentId,
|
|
296
|
+
"aria-labelledby": triggerId,
|
|
297
|
+
"data-slot": "accordion-content",
|
|
298
|
+
"data-state": "open",
|
|
299
|
+
className: cn(accordionContentVariants(), className),
|
|
300
|
+
...props,
|
|
301
|
+
children
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
var Accordion = {
|
|
306
|
+
Root: AccordionRoot,
|
|
307
|
+
Item: AccordionItem,
|
|
308
|
+
Trigger: AccordionTrigger,
|
|
309
|
+
Content: AccordionContent
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
exports.Accordion = Accordion;
|
|
313
|
+
exports.AccordionContent = AccordionContent;
|
|
314
|
+
exports.AccordionItem = AccordionItem;
|
|
315
|
+
exports.AccordionRoot = AccordionRoot;
|
|
316
|
+
exports.AccordionTrigger = AccordionTrigger;
|
|
317
|
+
exports.accordionContentVariants = accordionContentVariants;
|
|
318
|
+
exports.accordionItemVariants = accordionItemVariants;
|
|
319
|
+
exports.accordionRootVariants = accordionRootVariants;
|
|
320
|
+
exports.accordionTriggerIconVariants = accordionTriggerIconVariants;
|
|
321
|
+
exports.accordionTriggerTitleVariants = accordionTriggerTitleVariants;
|
|
322
|
+
exports.accordionTriggerVariants = accordionTriggerVariants;
|