@tomny-dev/uzi 0.8.0 → 0.9.0-pr.89.299.1.9555816
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 +37 -167
- package/dist/components/multi-select/MultiSelect.d.ts +6 -0
- package/dist/components/multi-select/MultiSelect.d.ts.map +1 -1
- package/dist/index26.js +8 -2
- package/dist/index26.js.map +1 -1
- package/dist/index27.cjs +10 -1
- package/dist/index27.cjs.map +1 -1
- package/dist/index27.js +82 -45
- package/dist/index27.js.map +1 -1
- package/dist/index28.cjs +82 -45
- package/dist/index28.cjs.map +1 -1
- package/dist/style.css +40 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,210 +2,80 @@
|
|
|
2
2
|
|
|
3
3
|
Rapid-fire React UI components. Ship faster, build more.
|
|
4
4
|
|
|
5
|
+
Uzi is a reusable React component library for app interfaces, with design tokens, accessible interaction primitives, application layouts, and AI chat components.
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
pnpm add @tomny-dev/uzi
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Uzi supports React 18 and 19 and uses CSS modules internally; Tailwind is not required.
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
import { Button, Card, Modal, ThemeProvider, useToast } from "@tomny-dev/uzi";
|
|
15
|
-
```
|
|
15
|
+
## Quick start
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Import the component stylesheet **once** in your application's global CSS:
|
|
18
18
|
|
|
19
19
|
```css
|
|
20
20
|
@import "@tomny-dev/uzi/styles.css";
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Uzi includes Storybook as the interactive component catalog for exploring components, variants, states, and composition patterns.
|
|
26
|
-
|
|
27
|
-
To run Storybook locally:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
pnpm install
|
|
31
|
-
pnpm storybook
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Then open `http://localhost:6006`.
|
|
35
|
-
|
|
36
|
-
To verify the production Storybook build:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
pnpm build-storybook
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
The static output is written to `storybook-static/`. Story files live beside their components under `src/components/**` using the `*.stories.tsx` naming convention.
|
|
43
|
-
|
|
44
|
-
The **Components / AIChat** stories demonstrate streaming, custom renderers, scoped requests, message limits, error recovery, and an externally controlled runtime with mock approvals; no external AI credentials are needed.
|
|
45
|
-
|
|
46
|
-
CI builds Storybook on every pull request and push to `main`. After changes land on `main`, the Storybook deployment workflow publishes `storybook-static/` to the `uzi-storybook` Cloudflare Pages project. The deployment workflow requires these repository secrets:
|
|
47
|
-
|
|
48
|
-
- `CLOUDFLARE_API_TOKEN` — API token with Pages Write permission.
|
|
49
|
-
- `CLOUDFLARE_ACCOUNT_ID` — Cloudflare account identifier.
|
|
50
|
-
|
|
51
|
-
The Cloudflare Pages project should use `main` as its production branch. A custom domain such as `uzi.tomny.dev` can be attached to that Pages project after the project exists.
|
|
52
|
-
|
|
53
|
-
## Using With Coding Agents
|
|
54
|
-
|
|
55
|
-
Installing `@tomny-dev/uzi` in an app does not by itself cause Claude Code, Codex, or similar agents to prefer `uzi` components. You should add that policy to the consumer repo's agent guidance.
|
|
56
|
-
|
|
57
|
-
Recommended snippet for the consumer repo's `CLAUDE.md`, `AGENTS.md`, or equivalent:
|
|
58
|
-
|
|
59
|
-
```md
|
|
60
|
-
## UI Components
|
|
61
|
-
|
|
62
|
-
- Prefer `@tomny-dev/uzi` for shared UI primitives and layout components.
|
|
63
|
-
- Check `uzi` before creating new local primitives such as buttons, inputs, labels, cards, modals, selects, dropdown menus, alerts, shells, navigation, and theme controls.
|
|
64
|
-
- Only introduce a repo-local primitive when `uzi` lacks the required behavior or when the local file is intentionally app-specific composition.
|
|
65
|
-
- Keep imports consistent with the surrounding area of the codebase. If the repo already uses thin wrappers around `uzi`, follow that local pattern.
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
If you want agents to discover props and examples directly, also configure the `uzi` MCP server. See [`mcp/README.md`](./mcp/README.md).
|
|
69
|
-
|
|
70
|
-
## Themes
|
|
71
|
-
|
|
72
|
-
`uzi` ships with built-in light/dark tokens and a small accent palette layer.
|
|
23
|
+
Then use components in your app:
|
|
73
24
|
|
|
74
25
|
```tsx
|
|
75
26
|
"use client";
|
|
76
27
|
|
|
77
|
-
import { Button,
|
|
78
|
-
|
|
79
|
-
function ThemeToggle() {
|
|
80
|
-
const { resolvedTheme, toggleTheme, accent, setAccent } = useTheme();
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div>
|
|
84
|
-
<Button onClick={toggleTheme}>
|
|
85
|
-
{resolvedTheme === "dark" ? "Switch to light" : "Switch to dark"}
|
|
86
|
-
</Button>
|
|
87
|
-
<Button variant="outline" onClick={() => setAccent(accent === "violet" ? "blue" : "violet")}>
|
|
88
|
-
Toggle accent
|
|
89
|
-
</Button>
|
|
90
|
-
</div>
|
|
91
|
-
);
|
|
92
|
-
}
|
|
28
|
+
import { Button, Card, ThemeProvider } from "@tomny-dev/uzi";
|
|
93
29
|
|
|
94
30
|
export function App() {
|
|
95
31
|
return (
|
|
96
32
|
<ThemeProvider defaultTheme="system" defaultAccent="blue">
|
|
97
|
-
<
|
|
33
|
+
<Card padding="md">
|
|
34
|
+
<h2>Welcome to Uzi</h2>
|
|
35
|
+
<Button onClick={() => alert("Hello!")}>Get started</Button>
|
|
36
|
+
</Card>
|
|
98
37
|
</ThemeProvider>
|
|
99
38
|
);
|
|
100
39
|
}
|
|
101
40
|
```
|
|
102
41
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- `light`
|
|
106
|
-
- `dark`
|
|
107
|
-
- `system`
|
|
108
|
-
|
|
109
|
-
Supported accent palettes:
|
|
110
|
-
|
|
111
|
-
- `blue`
|
|
112
|
-
- `cyan`
|
|
113
|
-
- `violet`
|
|
114
|
-
- `emerald`
|
|
115
|
-
- `amber`
|
|
116
|
-
- `rose`
|
|
42
|
+
For installation variants and a longer walkthrough, see [Getting Started](docs/getting-started.md).
|
|
117
43
|
|
|
118
|
-
##
|
|
44
|
+
## What's included
|
|
119
45
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
- Use native HTML for simple form controls when the platform already gives the right behavior.
|
|
123
|
-
- Use Radix for interaction-heavy primitives such as menus, dialogs, popovers, toasts, and custom selects.
|
|
124
|
-
- Use `uzi` for the public component API, styling, tokens, and higher-level templates like `TopBar`, `SidebarNav`, and `AppShell`.
|
|
125
|
-
|
|
126
|
-
In practice, `uzi` should spend its complexity budget on reusable app scaffolding and cohesive design, not on rebuilding low-level widget behavior that Radix or the browser already solves.
|
|
127
|
-
|
|
128
|
-
## Components
|
|
129
|
-
|
|
130
|
-
| Component | Description |
|
|
46
|
+
| Area | Examples |
|
|
131
47
|
|---|---|
|
|
132
|
-
| `
|
|
133
|
-
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
| `Card` | Discrete object container with tone/padding control |
|
|
138
|
-
| `Surface` | Semantic visual grouping with base/subtle/raised/selected hierarchy |
|
|
139
|
-
| `Checkbox` | Checkbox form primitive |
|
|
140
|
-
| `Input` | Text input primitive |
|
|
141
|
-
| `Label` | Form label primitive |
|
|
142
|
-
| `MultiSelect` | Custom multi-option picker with checkbox-style menu |
|
|
143
|
-
| `Pill` | Inline badge/tag |
|
|
144
|
-
| `Modal` | Radix-backed overlay dialog |
|
|
145
|
-
| `Select` | Styled Radix-based single-select field |
|
|
146
|
-
| `Dropdown` | Deprecated compatibility alias for Select |
|
|
147
|
-
| `DropdownMenu` | Radix-based action menu primitives |
|
|
148
|
-
| `AppShell` | Responsive layout with collapsible sidebar |
|
|
149
|
-
| `SidebarNav` | Sidebar navigation list |
|
|
150
|
-
| `TopBar` | Composable header shell for brand, nav triggers, and actions |
|
|
151
|
-
| `PageContainer` | Centered responsive page wrapper with standard horizontal and vertical gutters |
|
|
152
|
-
| `PageHeader` | Page title, eyebrow, description, and action composition |
|
|
153
|
-
| `SectionHeader` | Reusable section title, description, and actions |
|
|
154
|
-
| `EmptyState` | Empty-result/resource state with visual and action slots |
|
|
155
|
-
| `Stack` / `Inline` | Small gap/alignment layout helpers for common composition |
|
|
156
|
-
| `Stat` / `StatGroup` | Domain-agnostic summary value and responsive stat grouping |
|
|
157
|
-
| `Toolbar` / `ToolbarGroup` | Responsive compact filter/action workspace |
|
|
158
|
-
| `ThemeToggleButton` | Reusable light/dark toggle wired to `ThemeProvider` |
|
|
159
|
-
| `ThemeProvider` / `useTheme` | Light/dark + accent palette theming |
|
|
160
|
-
| `ToastProvider` / `useToast` | Radix-backed toast notification system |
|
|
161
|
-
|
|
162
|
-
`TopBar` supports:
|
|
163
|
-
|
|
164
|
-
- `brandingLocation="left" | "center"`
|
|
165
|
-
- `isSticky={true | false}`
|
|
166
|
-
- `showThemeToggle`
|
|
167
|
-
- `themeToggleProps`
|
|
168
|
-
|
|
169
|
-
## Documentation
|
|
48
|
+
| UI primitives | `Button`, `Card`, `Surface`, `Input`, `Label`, `Checkbox`, `Select`, `MultiSelect`, `Modal`, `DropdownMenu` |
|
|
49
|
+
| App layout | `AppShell`, `SidebarNav`, `TopBar`, `PageContainer`, `PageHeader`, `SectionHeader`, `Stack`, `Inline` |
|
|
50
|
+
| Common patterns | `Toolbar`, `ToolbarGroup`, `EmptyState`, `Avatar`, `Pill`, `Stat`, `StatGroup` |
|
|
51
|
+
| Theming and feedback | `ThemeProvider`, `useTheme`, `ThemeToggleButton`, `ToastProvider`, `useToast` |
|
|
52
|
+
| AI experiences | `AIChat`, `AIChatView`, `AIChatDock`, `FloatingActionStack`, `FloatingActionButton` |
|
|
170
53
|
|
|
171
|
-
|
|
172
|
-
- [Theming](docs/theming.md) — ThemeProvider, useTheme, accent palettes, CSS overrides
|
|
173
|
-
- [Layout Patterns](docs/guides/layout-patterns.md) — Dashboard, full-width header, center-branded
|
|
174
|
-
- [Application Scaffolding](docs/guides/application-scaffolding.md) — Page containers, headers, empty states, stats, and layout composition
|
|
175
|
-
- [Visual Hierarchy](docs/guides/visual-hierarchy.md) — Surface levels, typography, borders, shadows, and toolbar conventions
|
|
176
|
-
- [Form Patterns](docs/guides/form-patterns.md) — Input, Select, MultiSelect, SegmentedToggle patterns
|
|
177
|
-
- [AI Chat](docs/guides/ai-chat.md) — Streaming endpoint contract, authentication, scope authorization, renderers and local Storybook demos
|
|
54
|
+
These are representative exports, not an exhaustive API reference. Use the guides below for configuration and composition examples.
|
|
178
55
|
|
|
179
|
-
##
|
|
180
|
-
|
|
181
|
-
This package bundles CSS inline into the JavaScript output via `vite-plugin-css-injected-by-js`.
|
|
182
|
-
At runtime, a `<style>` tag is injected into the document head so consumers do **not** need
|
|
183
|
-
to import `./styles.css` for client-side rendering.
|
|
56
|
+
## Documentation
|
|
184
57
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
58
|
+
- [Getting Started](docs/getting-started.md) — Installation, styles, and first components
|
|
59
|
+
- [Theming](docs/theming.md) — Light/dark mode, accent palettes, theme APIs, and CSS overrides
|
|
60
|
+
- [Layout Patterns](docs/guides/layout-patterns.md) — Dashboard and header compositions
|
|
61
|
+
- [Application Scaffolding](docs/guides/application-scaffolding.md) — Page structure, empty states, and stats
|
|
62
|
+
- [Visual Hierarchy](docs/guides/visual-hierarchy.md) — Surface, typography, border, and toolbar conventions
|
|
63
|
+
- [Form Patterns](docs/guides/form-patterns.md) — Input, Select, MultiSelect, and SegmentedToggle
|
|
64
|
+
- [AI Chat](docs/guides/ai-chat.md) — Streaming API contracts, scope authorization, and renderers
|
|
65
|
+
- [SSR and Next.js](docs/ssr.md) — Server rendering, stylesheet imports, and server-safe exports
|
|
188
66
|
|
|
189
|
-
|
|
190
|
-
@import "@tomny-dev/uzi/styles.css";
|
|
191
|
-
```
|
|
67
|
+
## Using Uzi with coding agents
|
|
192
68
|
|
|
193
|
-
|
|
69
|
+
Installing the package does not automatically tell Claude Code, Codex, or other agents to prefer Uzi components. Add a rule to your consuming application's `AGENTS.md`, `CLAUDE.md`, or equivalent instructing agents to check Uzi before creating new shared UI primitives.
|
|
194
70
|
|
|
195
|
-
|
|
196
|
-
and React context providers. Next.js Server Components can import and render these exports;
|
|
197
|
-
Next.js will preserve the client boundary without requiring a local wrapper.
|
|
71
|
+
For component discovery, usage examples, and agent configuration, see the [Uzi MCP server guide](mcp/README.md). The MCP server is not bundled in the main npm package.
|
|
198
72
|
|
|
199
|
-
|
|
73
|
+
## SSR and Next.js
|
|
200
74
|
|
|
201
|
-
|
|
202
|
-
Use `@tomny-dev/uzi/utils` for environment-neutral utilities such as `cx`, including
|
|
203
|
-
calls made directly from Server Components.
|
|
75
|
+
For SSR frameworks, keep the stylesheet import shown above to prevent a flash of unstyled components. The main package entry is a client entry; `@tomny-dev/uzi/server` exposes the server-safe `getThemeScript`, while `@tomny-dev/uzi/utils` exposes environment-neutral helpers such as `cx`.
|
|
204
76
|
|
|
205
|
-
|
|
77
|
+
See [SSR and Next.js](docs/ssr.md) for details.
|
|
206
78
|
|
|
207
|
-
|
|
208
|
-
- `"use client"` is handled by the bundle — no need to wrap imports
|
|
209
|
-
- `react` and `react-dom` are peer dependencies, provided by your app
|
|
79
|
+
## Contributing
|
|
210
80
|
|
|
211
|
-
|
|
81
|
+
Working on Uzi itself? See [CONTRIBUTING.md](CONTRIBUTING.md) for local development, Storybook, testing, and design conventions. Infrastructure maintainers can find the Cloudflare Pages setup in [Storybook Deployment](docs/deployment.md).
|
|
@@ -13,10 +13,16 @@ export type MultiSelectProps = {
|
|
|
13
13
|
placeholder?: string;
|
|
14
14
|
fullWidth?: boolean;
|
|
15
15
|
maxVisibleValues?: number;
|
|
16
|
+
/** Minimum popup width, independent of the trigger (e.g. '24rem'). */
|
|
17
|
+
contentMinWidth?: string;
|
|
16
18
|
/** Formats the closed trigger text from the selected options, including an empty selection. */
|
|
17
19
|
formatValue?: (selected: MultiSelectOption[]) => string;
|
|
18
20
|
/** Shows Select all and Clear all actions. Bulk actions modify enabled options only. */
|
|
19
21
|
bulkActions?: boolean;
|
|
22
|
+
/** Stage changes until Apply. Cancel/dismiss discards the draft. */
|
|
23
|
+
draftMode?: boolean;
|
|
24
|
+
/** Minimum number of selected values required to apply; immediate mode blocks changes below this count. */
|
|
25
|
+
minSelected?: number;
|
|
20
26
|
selectAllLabel?: string;
|
|
21
27
|
/** Label for clearing all enabled selections. Disabled selected options remain selected. */
|
|
22
28
|
clearAllLabel?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiSelect.d.ts","sourceRoot":"","sources":["../../../src/components/multi-select/MultiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wFAAwF;IACxF,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+FAA+F;IAC/F,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,MAAM,CAAC;IACxD,wFAAwF;IACxF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"MultiSelect.d.ts","sourceRoot":"","sources":["../../../src/components/multi-select/MultiSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wFAAwF;IACxF,IAAI,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,MAAM,CAAC;IACxD,wFAAwF;IACxF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2GAA2G;IAC3G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4FAA4F;IAC5F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,WAAW,4FAgPvB,CAAC"}
|
package/dist/index26.js
CHANGED
|
@@ -20,6 +20,9 @@ var indicator = "uzi-multi-select-module__indicator__NO-WE";
|
|
|
20
20
|
var indicatorSelected = "uzi-multi-select-module__indicatorSelected__9sEAy";
|
|
21
21
|
var indicatorDisabled = "uzi-multi-select-module__indicatorDisabled__vqdiH";
|
|
22
22
|
var optionIcon = "uzi-multi-select-module__optionIcon__TQddK";
|
|
23
|
+
var draftActions = "uzi-multi-select-module__draftActions__-R2g3";
|
|
24
|
+
var draftButton = "uzi-multi-select-module__draftButton__tO1zu";
|
|
25
|
+
var optionsViewport = "uzi-multi-select-module__optionsViewport__Fus0q";
|
|
23
26
|
var multi_select_module_default = {
|
|
24
27
|
wrapper,
|
|
25
28
|
wrapperFullWidth,
|
|
@@ -41,9 +44,12 @@ var multi_select_module_default = {
|
|
|
41
44
|
indicator,
|
|
42
45
|
indicatorSelected,
|
|
43
46
|
indicatorDisabled,
|
|
44
|
-
optionIcon
|
|
47
|
+
optionIcon,
|
|
48
|
+
draftActions,
|
|
49
|
+
draftButton,
|
|
50
|
+
optionsViewport
|
|
45
51
|
};
|
|
46
52
|
//#endregion
|
|
47
|
-
export { bulkAction, chevron, chip, chipSummary, multi_select_module_default as default, indicator, indicatorDisabled, indicatorSelected, menu, menuFadeIn, option, optionDisabled, optionIcon, optionLabel, optionSelected, placeholder, separator, summary, trigger, value, wrapper, wrapperFullWidth };
|
|
53
|
+
export { bulkAction, chevron, chip, chipSummary, multi_select_module_default as default, draftActions, draftButton, indicator, indicatorDisabled, indicatorSelected, menu, menuFadeIn, option, optionDisabled, optionIcon, optionLabel, optionSelected, optionsViewport, placeholder, separator, summary, trigger, value, wrapper, wrapperFullWidth };
|
|
48
54
|
|
|
49
55
|
//# sourceMappingURL=index26.js.map
|
package/dist/index26.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index26.js","names":[],"sources":["../src/components/multi-select/multi-select.module.css"],"sourcesContent":[".wrapper {\n position: relative;\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n}\n\n.wrapperFullWidth {\n width: 100%;\n}\n\n.trigger {\n width: 100%;\n min-width: 0;\n min-height: var(--uzi-control-min-height);\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.625rem;\n border-radius: var(--uzi-control-radius);\n border: 1px solid var(--ts-dropdown-border, var(--border));\n background: var(--ts-dropdown-bg, var(--uzi-surface-2, var(--secondary)));\n color: var(--ts-dropdown-text, var(--foreground));\n padding:\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x-compact)\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x);\n font-size: var(--uzi-control-font-size);\n line-height: var(--uzi-control-line-height);\n font-family: inherit;\n box-shadow: var(--uzi-control-shadow);\n transition:\n border-color 0.15s ease,\n background 0.15s ease,\n color 0.15s ease,\n box-shadow 0.15s ease;\n cursor: pointer;\n text-align: left;\n}\n\n.trigger:hover:not(:disabled) {\n border-color: var(--ts-dropdown-accent, var(--accent));\n box-shadow: var(--uzi-control-shadow-hover);\n}\n\n.trigger:focus-visible,\n.trigger[data-state=\"open\"] {\n border-color: var(--ts-dropdown-accent, var(--primary));\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 30%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n box-shadow: none;\n}\n\n.value {\n min-width: 0;\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 0.375rem;\n align-items: center;\n}\n\n.placeholder {\n color: var(--muted-foreground);\n}\n\n.summary {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n color: var(--ts-dropdown-text, var(--foreground));\n font-size: 0.75rem;\n font-weight: 600;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.chipSummary {\n color: var(--primary);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--muted-foreground);\n flex-shrink: 0;\n transition: transform 0.15s ease, color 0.15s ease;\n}\n\n.trigger:hover:not(:disabled) .chevron,\n.trigger[data-state=\"open\"] .chevron {\n color: var(--ts-dropdown-text, var(--foreground));\n}\n\n.trigger[data-state=\"open\"] .chevron {\n transform: rotate(180deg);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 6px);\n left: 0;\n z-index: var(--uzi-popover-z-index, 1100);\n min-width:
|
|
1
|
+
{"version":3,"file":"index26.js","names":[],"sources":["../src/components/multi-select/multi-select.module.css"],"sourcesContent":[".wrapper {\n position: relative;\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n}\n\n.wrapperFullWidth {\n width: 100%;\n}\n\n.trigger {\n width: 100%;\n min-width: 0;\n min-height: var(--uzi-control-min-height);\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.625rem;\n border-radius: var(--uzi-control-radius);\n border: 1px solid var(--ts-dropdown-border, var(--border));\n background: var(--ts-dropdown-bg, var(--uzi-surface-2, var(--secondary)));\n color: var(--ts-dropdown-text, var(--foreground));\n padding:\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x-compact)\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x);\n font-size: var(--uzi-control-font-size);\n line-height: var(--uzi-control-line-height);\n font-family: inherit;\n box-shadow: var(--uzi-control-shadow);\n transition:\n border-color 0.15s ease,\n background 0.15s ease,\n color 0.15s ease,\n box-shadow 0.15s ease;\n cursor: pointer;\n text-align: left;\n}\n\n.trigger:hover:not(:disabled) {\n border-color: var(--ts-dropdown-accent, var(--accent));\n box-shadow: var(--uzi-control-shadow-hover);\n}\n\n.trigger:focus-visible,\n.trigger[data-state=\"open\"] {\n border-color: var(--ts-dropdown-accent, var(--primary));\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 30%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n box-shadow: none;\n}\n\n.value {\n min-width: 0;\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 0.375rem;\n align-items: center;\n}\n\n.placeholder {\n color: var(--muted-foreground);\n}\n\n.summary {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n color: var(--ts-dropdown-text, var(--foreground));\n font-size: 0.75rem;\n font-weight: 600;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.chipSummary {\n color: var(--primary);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--muted-foreground);\n flex-shrink: 0;\n transition: transform 0.15s ease, color 0.15s ease;\n}\n\n.trigger:hover:not(:disabled) .chevron,\n.trigger[data-state=\"open\"] .chevron {\n color: var(--ts-dropdown-text, var(--foreground));\n}\n\n.trigger[data-state=\"open\"] .chevron {\n transform: rotate(180deg);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 6px);\n left: 0;\n z-index: var(--uzi-popover-z-index, 1100);\n min-width: var(--radix-dropdown-menu-trigger-width);\n width: max(var(--radix-dropdown-menu-trigger-width), var(--uzi-multiselect-content-min-width, 0px));\n max-width: min(calc(100vw - 1rem), var(--radix-dropdown-menu-content-available-width));\n max-height: min(28rem, var(--radix-dropdown-menu-content-available-height, calc(100dvh - 1rem)));\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--ts-menu-border, var(--border));\n border-radius: var(--uzi-menu-radius);\n background: var(--ts-menu-bg, var(--popover));\n color: var(--ts-menu-fg, var(--popover-foreground));\n padding: var(--uzi-menu-padding);\n box-shadow: var(--uzi-menu-shadow);\n animation: menuFadeIn 140ms ease;\n}\n\n.bulkAction {\n width: 100%;\n display: flex;\n align-items: center;\n border: none;\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: var(--uzi-menu-item-padding-y) var(--uzi-menu-item-padding-x);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n outline: none;\n}\n\n.bulkAction[data-highlighted] {\n background: var(--ts-menu-hover-bg, var(--accent));\n color: var(--ts-menu-hover-fg, var(--accent-foreground));\n}\n\n.bulkAction[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.separator {\n height: 1px;\n margin: var(--uzi-menu-padding) 0;\n background: var(--ts-menu-border, var(--border));\n}\n\n.option {\n width: 100%;\n display: flex;\n align-items: center;\n gap: var(--uzi-menu-item-gap);\n border: none;\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: var(--uzi-menu-item-padding-y) var(--uzi-menu-item-padding-x);\n font: inherit;\n cursor: pointer;\n text-align: left;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.option:hover:not(:disabled),\n.option:focus-visible,\n.option[data-highlighted] {\n background: var(--ts-menu-hover-bg, var(--accent));\n color: var(--ts-menu-hover-fg, var(--accent-foreground));\n outline: none;\n}\n\n.optionDisabled,\n.option[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.optionSelected .optionLabel {\n color: var(--primary);\n}\n\n.indicator {\n width: 1rem;\n height: 1rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 0.3125rem;\n border: 1px solid var(--border);\n color: transparent;\n background: transparent;\n transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;\n}\n\n.indicatorSelected {\n border-color: color-mix(in srgb, var(--primary) 55%, transparent);\n background: color-mix(in srgb, var(--primary) 12%, transparent);\n color: var(--primary);\n}\n\n.indicatorDisabled {\n opacity: 0.65;\n}\n\n.optionLabel {\n min-width: 0;\n flex: 1;\n display: inline-flex;\n align-items: center;\n gap: var(--uzi-menu-item-gap);\n}\n\n.optionIcon {\n width: 1rem;\n height: 1rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.optionIcon > * {\n max-width: 100%;\n max-height: 100%;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-4px) scale(0.98);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.draftActions {\n display: flex;\n flex-shrink: 0;\n gap: 0.5rem;\n padding: 0.5rem 0.25rem 0.125rem;\n border-top: 1px solid var(--ts-menu-border, var(--border));\n}\n.draftButton {\n flex: 1;\n border: 1px solid var(--ts-menu-border, var(--border));\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: 0.4rem 0.75rem;\n font: inherit;\n cursor: pointer;\n}\n.draftButton:last-child {\n background: var(--primary);\n color: var(--primary-foreground);\n border-color: var(--primary);\n}\n.draftButton:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-ring-offset); }\n.draftButton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.optionsViewport {\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1 1 auto;\n scrollbar-gutter: stable;\n}\n"],"mappings":""}
|
package/dist/index27.cjs
CHANGED
|
@@ -20,6 +20,9 @@ var indicator = "uzi-multi-select-module__indicator__NO-WE";
|
|
|
20
20
|
var indicatorSelected = "uzi-multi-select-module__indicatorSelected__9sEAy";
|
|
21
21
|
var indicatorDisabled = "uzi-multi-select-module__indicatorDisabled__vqdiH";
|
|
22
22
|
var optionIcon = "uzi-multi-select-module__optionIcon__TQddK";
|
|
23
|
+
var draftActions = "uzi-multi-select-module__draftActions__-R2g3";
|
|
24
|
+
var draftButton = "uzi-multi-select-module__draftButton__tO1zu";
|
|
25
|
+
var optionsViewport = "uzi-multi-select-module__optionsViewport__Fus0q";
|
|
23
26
|
var multi_select_module_default = {
|
|
24
27
|
wrapper,
|
|
25
28
|
wrapperFullWidth,
|
|
@@ -41,7 +44,10 @@ var multi_select_module_default = {
|
|
|
41
44
|
indicator,
|
|
42
45
|
indicatorSelected,
|
|
43
46
|
indicatorDisabled,
|
|
44
|
-
optionIcon
|
|
47
|
+
optionIcon,
|
|
48
|
+
draftActions,
|
|
49
|
+
draftButton,
|
|
50
|
+
optionsViewport
|
|
45
51
|
};
|
|
46
52
|
//#endregion
|
|
47
53
|
exports.bulkAction = bulkAction;
|
|
@@ -49,6 +55,8 @@ exports.chevron = chevron;
|
|
|
49
55
|
exports.chip = chip;
|
|
50
56
|
exports.chipSummary = chipSummary;
|
|
51
57
|
exports.default = multi_select_module_default;
|
|
58
|
+
exports.draftActions = draftActions;
|
|
59
|
+
exports.draftButton = draftButton;
|
|
52
60
|
exports.indicator = indicator;
|
|
53
61
|
exports.indicatorDisabled = indicatorDisabled;
|
|
54
62
|
exports.indicatorSelected = indicatorSelected;
|
|
@@ -59,6 +67,7 @@ exports.optionDisabled = optionDisabled;
|
|
|
59
67
|
exports.optionIcon = optionIcon;
|
|
60
68
|
exports.optionLabel = optionLabel;
|
|
61
69
|
exports.optionSelected = optionSelected;
|
|
70
|
+
exports.optionsViewport = optionsViewport;
|
|
62
71
|
exports.placeholder = placeholder;
|
|
63
72
|
exports.separator = separator;
|
|
64
73
|
exports.summary = summary;
|
package/dist/index27.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index27.cjs","names":[],"sources":["../src/components/multi-select/multi-select.module.css"],"sourcesContent":[".wrapper {\n position: relative;\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n}\n\n.wrapperFullWidth {\n width: 100%;\n}\n\n.trigger {\n width: 100%;\n min-width: 0;\n min-height: var(--uzi-control-min-height);\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.625rem;\n border-radius: var(--uzi-control-radius);\n border: 1px solid var(--ts-dropdown-border, var(--border));\n background: var(--ts-dropdown-bg, var(--uzi-surface-2, var(--secondary)));\n color: var(--ts-dropdown-text, var(--foreground));\n padding:\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x-compact)\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x);\n font-size: var(--uzi-control-font-size);\n line-height: var(--uzi-control-line-height);\n font-family: inherit;\n box-shadow: var(--uzi-control-shadow);\n transition:\n border-color 0.15s ease,\n background 0.15s ease,\n color 0.15s ease,\n box-shadow 0.15s ease;\n cursor: pointer;\n text-align: left;\n}\n\n.trigger:hover:not(:disabled) {\n border-color: var(--ts-dropdown-accent, var(--accent));\n box-shadow: var(--uzi-control-shadow-hover);\n}\n\n.trigger:focus-visible,\n.trigger[data-state=\"open\"] {\n border-color: var(--ts-dropdown-accent, var(--primary));\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 30%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n box-shadow: none;\n}\n\n.value {\n min-width: 0;\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 0.375rem;\n align-items: center;\n}\n\n.placeholder {\n color: var(--muted-foreground);\n}\n\n.summary {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n color: var(--ts-dropdown-text, var(--foreground));\n font-size: 0.75rem;\n font-weight: 600;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.chipSummary {\n color: var(--primary);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--muted-foreground);\n flex-shrink: 0;\n transition: transform 0.15s ease, color 0.15s ease;\n}\n\n.trigger:hover:not(:disabled) .chevron,\n.trigger[data-state=\"open\"] .chevron {\n color: var(--ts-dropdown-text, var(--foreground));\n}\n\n.trigger[data-state=\"open\"] .chevron {\n transform: rotate(180deg);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 6px);\n left: 0;\n z-index: var(--uzi-popover-z-index, 1100);\n min-width:
|
|
1
|
+
{"version":3,"file":"index27.cjs","names":[],"sources":["../src/components/multi-select/multi-select.module.css"],"sourcesContent":[".wrapper {\n position: relative;\n display: inline-flex;\n min-width: 0;\n max-width: 100%;\n}\n\n.wrapperFullWidth {\n width: 100%;\n}\n\n.trigger {\n width: 100%;\n min-width: 0;\n min-height: var(--uzi-control-min-height);\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.625rem;\n border-radius: var(--uzi-control-radius);\n border: 1px solid var(--ts-dropdown-border, var(--border));\n background: var(--ts-dropdown-bg, var(--uzi-surface-2, var(--secondary)));\n color: var(--ts-dropdown-text, var(--foreground));\n padding:\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x-compact)\n var(--uzi-control-padding-y)\n var(--uzi-control-padding-x);\n font-size: var(--uzi-control-font-size);\n line-height: var(--uzi-control-line-height);\n font-family: inherit;\n box-shadow: var(--uzi-control-shadow);\n transition:\n border-color 0.15s ease,\n background 0.15s ease,\n color 0.15s ease,\n box-shadow 0.15s ease;\n cursor: pointer;\n text-align: left;\n}\n\n.trigger:hover:not(:disabled) {\n border-color: var(--ts-dropdown-accent, var(--accent));\n box-shadow: var(--uzi-control-shadow-hover);\n}\n\n.trigger:focus-visible,\n.trigger[data-state=\"open\"] {\n border-color: var(--ts-dropdown-accent, var(--primary));\n outline: var(--focus-ring);\n outline-offset: var(--focus-ring-offset);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 30%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n box-shadow: none;\n}\n\n.value {\n min-width: 0;\n display: flex;\n flex: 1;\n flex-wrap: wrap;\n gap: 0.375rem;\n align-items: center;\n}\n\n.placeholder {\n color: var(--muted-foreground);\n}\n\n.summary {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.chip {\n display: inline-flex;\n align-items: center;\n max-width: 100%;\n padding: 2px 8px;\n border-radius: 999px;\n border: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);\n background: color-mix(in srgb, var(--primary) 10%, transparent);\n color: var(--ts-dropdown-text, var(--foreground));\n font-size: 0.75rem;\n font-weight: 600;\n line-height: 1.2;\n white-space: nowrap;\n}\n\n.chipSummary {\n color: var(--primary);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--muted-foreground);\n flex-shrink: 0;\n transition: transform 0.15s ease, color 0.15s ease;\n}\n\n.trigger:hover:not(:disabled) .chevron,\n.trigger[data-state=\"open\"] .chevron {\n color: var(--ts-dropdown-text, var(--foreground));\n}\n\n.trigger[data-state=\"open\"] .chevron {\n transform: rotate(180deg);\n}\n\n.menu {\n position: absolute;\n top: calc(100% + 6px);\n left: 0;\n z-index: var(--uzi-popover-z-index, 1100);\n min-width: var(--radix-dropdown-menu-trigger-width);\n width: max(var(--radix-dropdown-menu-trigger-width), var(--uzi-multiselect-content-min-width, 0px));\n max-width: min(calc(100vw - 1rem), var(--radix-dropdown-menu-content-available-width));\n max-height: min(28rem, var(--radix-dropdown-menu-content-available-height, calc(100dvh - 1rem)));\n display: flex;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--ts-menu-border, var(--border));\n border-radius: var(--uzi-menu-radius);\n background: var(--ts-menu-bg, var(--popover));\n color: var(--ts-menu-fg, var(--popover-foreground));\n padding: var(--uzi-menu-padding);\n box-shadow: var(--uzi-menu-shadow);\n animation: menuFadeIn 140ms ease;\n}\n\n.bulkAction {\n width: 100%;\n display: flex;\n align-items: center;\n border: none;\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: var(--uzi-menu-item-padding-y) var(--uzi-menu-item-padding-x);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n outline: none;\n}\n\n.bulkAction[data-highlighted] {\n background: var(--ts-menu-hover-bg, var(--accent));\n color: var(--ts-menu-hover-fg, var(--accent-foreground));\n}\n\n.bulkAction[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.separator {\n height: 1px;\n margin: var(--uzi-menu-padding) 0;\n background: var(--ts-menu-border, var(--border));\n}\n\n.option {\n width: 100%;\n display: flex;\n align-items: center;\n gap: var(--uzi-menu-item-gap);\n border: none;\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: var(--uzi-menu-item-padding-y) var(--uzi-menu-item-padding-x);\n font: inherit;\n cursor: pointer;\n text-align: left;\n transition: background 0.12s ease, color 0.12s ease;\n}\n\n.option:hover:not(:disabled),\n.option:focus-visible,\n.option[data-highlighted] {\n background: var(--ts-menu-hover-bg, var(--accent));\n color: var(--ts-menu-hover-fg, var(--accent-foreground));\n outline: none;\n}\n\n.optionDisabled,\n.option[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.optionSelected .optionLabel {\n color: var(--primary);\n}\n\n.indicator {\n width: 1rem;\n height: 1rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: 0.3125rem;\n border: 1px solid var(--border);\n color: transparent;\n background: transparent;\n transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;\n}\n\n.indicatorSelected {\n border-color: color-mix(in srgb, var(--primary) 55%, transparent);\n background: color-mix(in srgb, var(--primary) 12%, transparent);\n color: var(--primary);\n}\n\n.indicatorDisabled {\n opacity: 0.65;\n}\n\n.optionLabel {\n min-width: 0;\n flex: 1;\n display: inline-flex;\n align-items: center;\n gap: var(--uzi-menu-item-gap);\n}\n\n.optionIcon {\n width: 1rem;\n height: 1rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.optionIcon > * {\n max-width: 100%;\n max-height: 100%;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-4px) scale(0.98);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.draftActions {\n display: flex;\n flex-shrink: 0;\n gap: 0.5rem;\n padding: 0.5rem 0.25rem 0.125rem;\n border-top: 1px solid var(--ts-menu-border, var(--border));\n}\n.draftButton {\n flex: 1;\n border: 1px solid var(--ts-menu-border, var(--border));\n border-radius: var(--uzi-menu-item-radius);\n background: transparent;\n color: inherit;\n padding: 0.4rem 0.75rem;\n font: inherit;\n cursor: pointer;\n}\n.draftButton:last-child {\n background: var(--primary);\n color: var(--primary-foreground);\n border-color: var(--primary);\n}\n.draftButton:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-ring-offset); }\n.draftButton:disabled { opacity: 0.5; cursor: not-allowed; }\n\n.optionsViewport {\n min-height: 0;\n overflow-y: auto;\n overscroll-behavior: contain;\n flex: 1 1 auto;\n scrollbar-gutter: stable;\n}\n"],"mappings":""}
|
package/dist/index27.js
CHANGED
|
@@ -5,9 +5,16 @@ import * as React from "react";
|
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
7
7
|
//#region src/components/multi-select/MultiSelect.tsx
|
|
8
|
-
var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "Select options", fullWidth = true, maxVisibleValues = 2, formatValue, bulkActions = false, selectAllLabel = "Select all", clearAllLabel, className, disabled = false, name, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, ref) => {
|
|
9
|
-
const
|
|
10
|
-
const
|
|
8
|
+
var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "Select options", fullWidth = true, maxVisibleValues = 2, contentMinWidth, formatValue, bulkActions = false, draftMode = false, minSelected = 0, selectAllLabel = "Select all", clearAllLabel, className, disabled = false, name, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, ref) => {
|
|
9
|
+
const [open, setOpen] = React.useState(false);
|
|
10
|
+
const [draft, setDraft] = React.useState(value);
|
|
11
|
+
const editValue = draftMode && open ? draft : value;
|
|
12
|
+
const updateSelection = (next) => {
|
|
13
|
+
if (draftMode) setDraft(next);
|
|
14
|
+
else if (next.length >= minSelected) onChange(next);
|
|
15
|
+
};
|
|
16
|
+
const selectedSet = React.useMemo(() => new Set(editValue), [editValue]);
|
|
17
|
+
const selectedOptions = React.useMemo(() => options.filter((opt) => value.includes(opt.value)), [options, value]);
|
|
11
18
|
const enabledValues = React.useMemo(() => options.filter((option) => !option.disabled).map((option) => option.value), [options]);
|
|
12
19
|
const allEnabledSelected = enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));
|
|
13
20
|
const hasDisabledOptions = options.some((option) => option.disabled);
|
|
@@ -15,20 +22,25 @@ var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
15
22
|
const formattedValue = React.useMemo(() => formatValue?.(selectedOptions), [formatValue, selectedOptions]);
|
|
16
23
|
const toggleValue = React.useCallback((nextValue) => {
|
|
17
24
|
if (selectedSet.has(nextValue)) {
|
|
18
|
-
|
|
25
|
+
updateSelection(editValue.filter((entry) => entry !== nextValue));
|
|
19
26
|
return;
|
|
20
27
|
}
|
|
21
|
-
|
|
28
|
+
updateSelection([...editValue, nextValue]);
|
|
22
29
|
}, [
|
|
23
|
-
|
|
30
|
+
updateSelection,
|
|
24
31
|
selectedSet,
|
|
25
|
-
|
|
32
|
+
editValue
|
|
26
33
|
]);
|
|
27
34
|
const visibleCount = Math.max(1, maxVisibleValues);
|
|
28
35
|
const visibleOptions = selectedOptions.slice(0, visibleCount);
|
|
29
36
|
const overflowCount = Math.max(0, selectedOptions.length - visibleOptions.length);
|
|
30
37
|
return /* @__PURE__ */ jsx(DropdownMenuPrimitive.Root, {
|
|
31
38
|
modal: false,
|
|
39
|
+
open,
|
|
40
|
+
onOpenChange: (next) => {
|
|
41
|
+
setDraft([...value]);
|
|
42
|
+
setOpen(next);
|
|
43
|
+
},
|
|
32
44
|
children: /* @__PURE__ */ jsxs("div", {
|
|
33
45
|
className: cx(multi_select_module_default.wrapper, fullWidth && multi_select_module_default.wrapperFullWidth, className),
|
|
34
46
|
children: [
|
|
@@ -87,6 +99,7 @@ var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
87
99
|
}, entry)) : null,
|
|
88
100
|
/* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsxs(DropdownMenuPrimitive.Content, {
|
|
89
101
|
className: multi_select_module_default.menu,
|
|
102
|
+
style: contentMinWidth ? { "--uzi-multiselect-content-min-width": contentMinWidth } : void 0,
|
|
90
103
|
sideOffset: 4,
|
|
91
104
|
align: "start",
|
|
92
105
|
children: [
|
|
@@ -95,7 +108,7 @@ var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
95
108
|
disabled: allEnabledSelected,
|
|
96
109
|
onSelect: (event) => {
|
|
97
110
|
event.preventDefault();
|
|
98
|
-
|
|
111
|
+
updateSelection([...editValue, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);
|
|
99
112
|
},
|
|
100
113
|
children: selectAllLabel
|
|
101
114
|
}), /* @__PURE__ */ jsx(DropdownMenuPrimitive.Item, {
|
|
@@ -104,49 +117,73 @@ var MultiSelect = React.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
104
117
|
onSelect: (event) => {
|
|
105
118
|
event.preventDefault();
|
|
106
119
|
const enabledSet = new Set(enabledValues);
|
|
107
|
-
|
|
120
|
+
updateSelection(editValue.filter((entry) => !enabledSet.has(entry)));
|
|
108
121
|
},
|
|
109
122
|
children: resolvedClearAllLabel
|
|
110
123
|
})] }) : null,
|
|
111
124
|
bulkActions && enabledValues.length > 0 ? /* @__PURE__ */ jsx(DropdownMenuPrimitive.Separator, { className: multi_select_module_default.separator }) : null,
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
children: /* @__PURE__ */ jsx(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
125
|
+
/* @__PURE__ */ jsx("div", {
|
|
126
|
+
className: multi_select_module_default.optionsViewport,
|
|
127
|
+
children: options.map((option) => {
|
|
128
|
+
const selected = selectedSet.has(option.value);
|
|
129
|
+
return /* @__PURE__ */ jsxs(DropdownMenuPrimitive.CheckboxItem, {
|
|
130
|
+
className: cx(multi_select_module_default.option, selected && multi_select_module_default.optionSelected, option.disabled && multi_select_module_default.optionDisabled),
|
|
131
|
+
checked: selected,
|
|
132
|
+
disabled: option.disabled,
|
|
133
|
+
onCheckedChange: () => toggleValue(option.value),
|
|
134
|
+
onSelect: (event) => event.preventDefault(),
|
|
135
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
136
|
+
className: cx(multi_select_module_default.indicator, selected && multi_select_module_default.indicatorSelected, option.disabled && multi_select_module_default.indicatorDisabled),
|
|
137
|
+
"aria-hidden": "true",
|
|
138
|
+
children: /* @__PURE__ */ jsx(DropdownMenuPrimitive.ItemIndicator, {
|
|
139
|
+
forceMount: true,
|
|
140
|
+
children: /* @__PURE__ */ jsx("svg", {
|
|
141
|
+
viewBox: "0 0 16 16",
|
|
142
|
+
width: "16",
|
|
143
|
+
height: "16",
|
|
144
|
+
fill: "none",
|
|
145
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
146
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
147
|
+
d: "M3.5 8.5 6.5 11.5 12.5 4.5",
|
|
148
|
+
stroke: "currentColor",
|
|
149
|
+
strokeWidth: "1.8",
|
|
150
|
+
strokeLinecap: "round",
|
|
151
|
+
strokeLinejoin: "round"
|
|
152
|
+
})
|
|
137
153
|
})
|
|
138
154
|
})
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
})
|
|
155
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
156
|
+
className: multi_select_module_default.optionLabel,
|
|
157
|
+
children: [option.icon ? /* @__PURE__ */ jsx("span", {
|
|
158
|
+
className: multi_select_module_default.optionIcon,
|
|
159
|
+
"aria-hidden": "true",
|
|
160
|
+
children: option.icon
|
|
161
|
+
}) : null, option.label]
|
|
162
|
+
})]
|
|
163
|
+
}, option.value);
|
|
164
|
+
})
|
|
165
|
+
}),
|
|
166
|
+
draftMode ? /* @__PURE__ */ jsxs("div", {
|
|
167
|
+
className: multi_select_module_default.draftActions,
|
|
168
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
169
|
+
type: "button",
|
|
170
|
+
className: multi_select_module_default.draftButton,
|
|
171
|
+
onClick: () => {
|
|
172
|
+
setDraft([...value]);
|
|
173
|
+
setOpen(false);
|
|
174
|
+
},
|
|
175
|
+
children: "Cancel"
|
|
176
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
177
|
+
type: "button",
|
|
178
|
+
className: multi_select_module_default.draftButton,
|
|
179
|
+
disabled: editValue.length < minSelected,
|
|
180
|
+
onClick: () => {
|
|
181
|
+
onChange(editValue);
|
|
182
|
+
setOpen(false);
|
|
183
|
+
},
|
|
184
|
+
children: "Apply"
|
|
185
|
+
})]
|
|
186
|
+
}) : null
|
|
150
187
|
]
|
|
151
188
|
}) })
|
|
152
189
|
]
|
package/dist/index27.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index27.js","names":[],"sources":["../src/components/multi-select/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./multi-select.module.css\";\n\nexport type MultiSelectOption = {\n label: string;\n value: string;\n disabled?: boolean;\n /** Optional decorative leading visual. The label remains the accessible option name. */\n icon?: React.ReactElement;\n};\n\nexport type MultiSelectProps = {\n options: MultiSelectOption[];\n value: string[];\n onChange: (value: string[]) => void;\n placeholder?: string;\n fullWidth?: boolean;\n maxVisibleValues?: number;\n /** Formats the closed trigger text from the selected options, including an empty selection. */\n formatValue?: (selected: MultiSelectOption[]) => string;\n /** Shows Select all and Clear all actions. Bulk actions modify enabled options only. */\n bulkActions?: boolean;\n selectAllLabel?: string;\n /** Label for clearing all enabled selections. Disabled selected options remain selected. */\n clearAllLabel?: string;\n className?: string;\n disabled?: boolean;\n name?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n};\n\nexport const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(\n (\n {\n options,\n value,\n onChange,\n placeholder = \"Select options\",\n fullWidth = true,\n maxVisibleValues = 2,\n formatValue,\n bulkActions = false,\n selectAllLabel = \"Select all\",\n clearAllLabel,\n className,\n disabled = false,\n name,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n },\n ref,\n ) => {\n const selectedSet = React.useMemo(() => new Set(value), [value]);\n const selectedOptions = React.useMemo(\n () => options.filter((opt) => selectedSet.has(opt.value)),\n [options, selectedSet],\n );\n\n const enabledValues = React.useMemo(\n () => options.filter((option) => !option.disabled).map((option) => option.value),\n [options],\n );\n const allEnabledSelected =\n enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));\n const hasDisabledOptions = options.some((option) => option.disabled);\n const resolvedClearAllLabel =\n clearAllLabel ?? (hasDisabledOptions ? \"Clear enabled\" : \"Clear all\");\n\n const formattedValue = React.useMemo(\n () => formatValue?.(selectedOptions),\n [formatValue, selectedOptions],\n );\n\n const toggleValue = React.useCallback(\n (nextValue: string) => {\n if (selectedSet.has(nextValue)) {\n onChange(value.filter((entry) => entry !== nextValue));\n return;\n }\n\n onChange([...value, nextValue]);\n },\n [onChange, selectedSet, value],\n );\n\n const visibleCount = Math.max(1, maxVisibleValues);\n const visibleOptions = selectedOptions.slice(0, visibleCount);\n const overflowCount = Math.max(\n 0,\n selectedOptions.length - visibleOptions.length,\n );\n\n return (\n <DropdownMenuPrimitive.Root modal={false}>\n <div\n className={cx(\n styles.wrapper,\n fullWidth && styles.wrapperFullWidth,\n className,\n )}\n >\n <DropdownMenuPrimitive.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={styles.trigger}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n disabled={disabled}\n >\n <span className={styles.value}>\n {formatValue ? (\n <span className={styles.summary}>{formattedValue}</span>\n ) : selectedOptions.length === 0 ? (\n <span className={styles.placeholder}>{placeholder}</span>\n ) : (\n <>\n {visibleOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n ))}\n {overflowCount > 0 ? (\n <span className={cx(styles.chip, styles.chipSummary)}>\n +{overflowCount}\n </span>\n ) : null}\n </>\n )}\n </span>\n <span className={styles.chevron} aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n >\n <path\n d=\"M2 3.5L5 6.5L8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n </DropdownMenuPrimitive.Trigger>\n\n {name\n ? value.map((entry) => (\n <input key={entry} type=\"hidden\" name={name} value={entry} />\n ))\n : null}\n\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n className={styles.menu}\n sideOffset={4}\n align=\"start\"\n >\n {bulkActions && enabledValues.length > 0 ? (\n <>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={allEnabledSelected}\n onSelect={(event) => {\n event.preventDefault();\n onChange([...value, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);\n }}\n >\n {selectAllLabel}\n </DropdownMenuPrimitive.Item>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={!enabledValues.some((entry) => selectedSet.has(entry))}\n onSelect={(event) => {\n event.preventDefault();\n const enabledSet = new Set(enabledValues);\n onChange(value.filter((entry) => !enabledSet.has(entry)));\n }}\n >\n {resolvedClearAllLabel}\n </DropdownMenuPrimitive.Item>\n </>\n ) : null}\n {bulkActions && enabledValues.length > 0 ? (\n <DropdownMenuPrimitive.Separator className={styles.separator} />\n ) : null}\n {options.map((option) => {\n const selected = selectedSet.has(option.value);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n key={option.value}\n className={cx(\n styles.option,\n selected && styles.optionSelected,\n option.disabled && styles.optionDisabled,\n )}\n checked={selected}\n disabled={option.disabled}\n onCheckedChange={() => toggleValue(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span\n className={cx(\n styles.indicator,\n selected && styles.indicatorSelected,\n option.disabled && styles.indicatorDisabled,\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator forceMount>\n <svg\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.5 8.5 6.5 11.5 12.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className={styles.optionLabel}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n );\n })}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </div>\n </DropdownMenuPrimitive.Root>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index27.js","names":[],"sources":["../src/components/multi-select/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./multi-select.module.css\";\n\nexport type MultiSelectOption = {\n label: string;\n value: string;\n disabled?: boolean;\n /** Optional decorative leading visual. The label remains the accessible option name. */\n icon?: React.ReactElement;\n};\n\nexport type MultiSelectProps = {\n options: MultiSelectOption[];\n value: string[];\n onChange: (value: string[]) => void;\n placeholder?: string;\n fullWidth?: boolean;\n maxVisibleValues?: number;\n /** Minimum popup width, independent of the trigger (e.g. '24rem'). */\n contentMinWidth?: string;\n /** Formats the closed trigger text from the selected options, including an empty selection. */\n formatValue?: (selected: MultiSelectOption[]) => string;\n /** Shows Select all and Clear all actions. Bulk actions modify enabled options only. */\n bulkActions?: boolean;\n /** Stage changes until Apply. Cancel/dismiss discards the draft. */\n draftMode?: boolean;\n /** Minimum number of selected values required to apply; immediate mode blocks changes below this count. */\n minSelected?: number;\n selectAllLabel?: string;\n /** Label for clearing all enabled selections. Disabled selected options remain selected. */\n clearAllLabel?: string;\n className?: string;\n disabled?: boolean;\n name?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n};\n\nexport const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(\n (\n {\n options,\n value,\n onChange,\n placeholder = \"Select options\",\n fullWidth = true,\n maxVisibleValues = 2,\n contentMinWidth,\n formatValue,\n bulkActions = false,\n draftMode = false,\n minSelected = 0,\n selectAllLabel = \"Select all\",\n clearAllLabel,\n className,\n disabled = false,\n name,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n },\n ref,\n ) => {\n const [open, setOpen] = React.useState(false);\n const [draft, setDraft] = React.useState<string[]>(value);\n const editValue = draftMode && open ? draft : value;\n const updateSelection = (next: string[]) => {\n if (draftMode) setDraft(next);\n else if (next.length >= minSelected) onChange(next);\n };\n const selectedSet = React.useMemo(() => new Set(editValue), [editValue]);\n const selectedOptions = React.useMemo(\n () => options.filter((opt) => value.includes(opt.value)),\n [options, value],\n );\n\n const enabledValues = React.useMemo(\n () => options.filter((option) => !option.disabled).map((option) => option.value),\n [options],\n );\n const allEnabledSelected =\n enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));\n const hasDisabledOptions = options.some((option) => option.disabled);\n const resolvedClearAllLabel =\n clearAllLabel ?? (hasDisabledOptions ? \"Clear enabled\" : \"Clear all\");\n\n const formattedValue = React.useMemo(\n () => formatValue?.(selectedOptions),\n [formatValue, selectedOptions],\n );\n\n const toggleValue = React.useCallback(\n (nextValue: string) => {\n if (selectedSet.has(nextValue)) {\n updateSelection(editValue.filter((entry) => entry !== nextValue));\n return;\n }\n\n updateSelection([...editValue, nextValue]);\n },\n [updateSelection, selectedSet, editValue],\n );\n\n const visibleCount = Math.max(1, maxVisibleValues);\n const visibleOptions = selectedOptions.slice(0, visibleCount);\n const overflowCount = Math.max(\n 0,\n selectedOptions.length - visibleOptions.length,\n );\n\n return (\n <DropdownMenuPrimitive.Root modal={false} open={open} onOpenChange={(next) => {\n setDraft([...value]);\n setOpen(next);\n }}>\n <div\n className={cx(\n styles.wrapper,\n fullWidth && styles.wrapperFullWidth,\n className,\n )}\n >\n <DropdownMenuPrimitive.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={styles.trigger}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n disabled={disabled}\n >\n <span className={styles.value}>\n {formatValue ? (\n <span className={styles.summary}>{formattedValue}</span>\n ) : selectedOptions.length === 0 ? (\n <span className={styles.placeholder}>{placeholder}</span>\n ) : (\n <>\n {visibleOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n ))}\n {overflowCount > 0 ? (\n <span className={cx(styles.chip, styles.chipSummary)}>\n +{overflowCount}\n </span>\n ) : null}\n </>\n )}\n </span>\n <span className={styles.chevron} aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n >\n <path\n d=\"M2 3.5L5 6.5L8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n </DropdownMenuPrimitive.Trigger>\n\n {name\n ? value.map((entry) => (\n <input key={entry} type=\"hidden\" name={name} value={entry} />\n ))\n : null}\n\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n className={styles.menu}\n style={contentMinWidth ? { '--uzi-multiselect-content-min-width': contentMinWidth } as React.CSSProperties : undefined}\n sideOffset={4}\n align=\"start\"\n >\n {bulkActions && enabledValues.length > 0 ? (\n <>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={allEnabledSelected}\n onSelect={(event) => {\n event.preventDefault();\n updateSelection([...editValue, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);\n }}\n >\n {selectAllLabel}\n </DropdownMenuPrimitive.Item>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={!enabledValues.some((entry) => selectedSet.has(entry))}\n onSelect={(event) => {\n event.preventDefault();\n const enabledSet = new Set(enabledValues);\n updateSelection(editValue.filter((entry) => !enabledSet.has(entry)));\n }}\n >\n {resolvedClearAllLabel}\n </DropdownMenuPrimitive.Item>\n </>\n ) : null}\n {bulkActions && enabledValues.length > 0 ? (\n <DropdownMenuPrimitive.Separator className={styles.separator} />\n ) : null}\n <div className={styles.optionsViewport}>\n {options.map((option) => {\n const selected = selectedSet.has(option.value);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n key={option.value}\n className={cx(\n styles.option,\n selected && styles.optionSelected,\n option.disabled && styles.optionDisabled,\n )}\n checked={selected}\n disabled={option.disabled}\n onCheckedChange={() => toggleValue(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span\n className={cx(\n styles.indicator,\n selected && styles.indicatorSelected,\n option.disabled && styles.indicatorDisabled,\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator forceMount>\n <svg\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.5 8.5 6.5 11.5 12.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className={styles.optionLabel}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n );\n })}\n </div>\n {draftMode ? (\n <div className={styles.draftActions}>\n <button type=\"button\" className={styles.draftButton} onClick={() => { setDraft([...value]); setOpen(false); }}>Cancel</button>\n <button type=\"button\" className={styles.draftButton} disabled={editValue.length < minSelected} onClick={() => {\n onChange(editValue);\n setOpen(false);\n }}>Apply</button>\n </div>\n ) : null}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </div>\n </DropdownMenuPrimitive.Root>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n"],"mappings":"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"}
|
package/dist/index28.cjs
CHANGED
|
@@ -8,9 +8,16 @@ let react_jsx_runtime = require("react/jsx-runtime");
|
|
|
8
8
|
let _radix_ui_react_dropdown_menu = require("@radix-ui/react-dropdown-menu");
|
|
9
9
|
_radix_ui_react_dropdown_menu = require_runtime.__toESM(_radix_ui_react_dropdown_menu, 1);
|
|
10
10
|
//#region src/components/multi-select/MultiSelect.tsx
|
|
11
|
-
var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "Select options", fullWidth = true, maxVisibleValues = 2, formatValue, bulkActions = false, selectAllLabel = "Select all", clearAllLabel, className, disabled = false, name, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, ref) => {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
11
|
+
var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "Select options", fullWidth = true, maxVisibleValues = 2, contentMinWidth, formatValue, bulkActions = false, draftMode = false, minSelected = 0, selectAllLabel = "Select all", clearAllLabel, className, disabled = false, name, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }, ref) => {
|
|
12
|
+
const [open, setOpen] = react.useState(false);
|
|
13
|
+
const [draft, setDraft] = react.useState(value);
|
|
14
|
+
const editValue = draftMode && open ? draft : value;
|
|
15
|
+
const updateSelection = (next) => {
|
|
16
|
+
if (draftMode) setDraft(next);
|
|
17
|
+
else if (next.length >= minSelected) onChange(next);
|
|
18
|
+
};
|
|
19
|
+
const selectedSet = react.useMemo(() => new Set(editValue), [editValue]);
|
|
20
|
+
const selectedOptions = react.useMemo(() => options.filter((opt) => value.includes(opt.value)), [options, value]);
|
|
14
21
|
const enabledValues = react.useMemo(() => options.filter((option) => !option.disabled).map((option) => option.value), [options]);
|
|
15
22
|
const allEnabledSelected = enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));
|
|
16
23
|
const hasDisabledOptions = options.some((option) => option.disabled);
|
|
@@ -18,20 +25,25 @@ var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
18
25
|
const formattedValue = react.useMemo(() => formatValue?.(selectedOptions), [formatValue, selectedOptions]);
|
|
19
26
|
const toggleValue = react.useCallback((nextValue) => {
|
|
20
27
|
if (selectedSet.has(nextValue)) {
|
|
21
|
-
|
|
28
|
+
updateSelection(editValue.filter((entry) => entry !== nextValue));
|
|
22
29
|
return;
|
|
23
30
|
}
|
|
24
|
-
|
|
31
|
+
updateSelection([...editValue, nextValue]);
|
|
25
32
|
}, [
|
|
26
|
-
|
|
33
|
+
updateSelection,
|
|
27
34
|
selectedSet,
|
|
28
|
-
|
|
35
|
+
editValue
|
|
29
36
|
]);
|
|
30
37
|
const visibleCount = Math.max(1, maxVisibleValues);
|
|
31
38
|
const visibleOptions = selectedOptions.slice(0, visibleCount);
|
|
32
39
|
const overflowCount = Math.max(0, selectedOptions.length - visibleOptions.length);
|
|
33
40
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_dropdown_menu.Root, {
|
|
34
41
|
modal: false,
|
|
42
|
+
open,
|
|
43
|
+
onOpenChange: (next) => {
|
|
44
|
+
setDraft([...value]);
|
|
45
|
+
setOpen(next);
|
|
46
|
+
},
|
|
35
47
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
36
48
|
className: require_cx.cx(require_multi_select_module.default.wrapper, fullWidth && require_multi_select_module.default.wrapperFullWidth, className),
|
|
37
49
|
children: [
|
|
@@ -90,6 +102,7 @@ var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
90
102
|
}, entry)) : null,
|
|
91
103
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_dropdown_menu.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_radix_ui_react_dropdown_menu.Content, {
|
|
92
104
|
className: require_multi_select_module.default.menu,
|
|
105
|
+
style: contentMinWidth ? { "--uzi-multiselect-content-min-width": contentMinWidth } : void 0,
|
|
93
106
|
sideOffset: 4,
|
|
94
107
|
align: "start",
|
|
95
108
|
children: [
|
|
@@ -98,7 +111,7 @@ var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
98
111
|
disabled: allEnabledSelected,
|
|
99
112
|
onSelect: (event) => {
|
|
100
113
|
event.preventDefault();
|
|
101
|
-
|
|
114
|
+
updateSelection([...editValue, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);
|
|
102
115
|
},
|
|
103
116
|
children: selectAllLabel
|
|
104
117
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_dropdown_menu.Item, {
|
|
@@ -107,49 +120,73 @@ var MultiSelect = react.forwardRef(({ options, value, onChange, placeholder = "S
|
|
|
107
120
|
onSelect: (event) => {
|
|
108
121
|
event.preventDefault();
|
|
109
122
|
const enabledSet = new Set(enabledValues);
|
|
110
|
-
|
|
123
|
+
updateSelection(editValue.filter((entry) => !enabledSet.has(entry)));
|
|
111
124
|
},
|
|
112
125
|
children: resolvedClearAllLabel
|
|
113
126
|
})] }) : null,
|
|
114
127
|
bulkActions && enabledValues.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_dropdown_menu.Separator, { className: require_multi_select_module.default.separator }) : null,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
128
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
129
|
+
className: require_multi_select_module.default.optionsViewport,
|
|
130
|
+
children: options.map((option) => {
|
|
131
|
+
const selected = selectedSet.has(option.value);
|
|
132
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_radix_ui_react_dropdown_menu.CheckboxItem, {
|
|
133
|
+
className: require_cx.cx(require_multi_select_module.default.option, selected && require_multi_select_module.default.optionSelected, option.disabled && require_multi_select_module.default.optionDisabled),
|
|
134
|
+
checked: selected,
|
|
135
|
+
disabled: option.disabled,
|
|
136
|
+
onCheckedChange: () => toggleValue(option.value),
|
|
137
|
+
onSelect: (event) => event.preventDefault(),
|
|
138
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
139
|
+
className: require_cx.cx(require_multi_select_module.default.indicator, selected && require_multi_select_module.default.indicatorSelected, option.disabled && require_multi_select_module.default.indicatorDisabled),
|
|
140
|
+
"aria-hidden": "true",
|
|
141
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_radix_ui_react_dropdown_menu.ItemIndicator, {
|
|
142
|
+
forceMount: true,
|
|
143
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
144
|
+
viewBox: "0 0 16 16",
|
|
145
|
+
width: "16",
|
|
146
|
+
height: "16",
|
|
147
|
+
fill: "none",
|
|
148
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
149
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
150
|
+
d: "M3.5 8.5 6.5 11.5 12.5 4.5",
|
|
151
|
+
stroke: "currentColor",
|
|
152
|
+
strokeWidth: "1.8",
|
|
153
|
+
strokeLinecap: "round",
|
|
154
|
+
strokeLinejoin: "round"
|
|
155
|
+
})
|
|
140
156
|
})
|
|
141
157
|
})
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
})
|
|
158
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
159
|
+
className: require_multi_select_module.default.optionLabel,
|
|
160
|
+
children: [option.icon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
161
|
+
className: require_multi_select_module.default.optionIcon,
|
|
162
|
+
"aria-hidden": "true",
|
|
163
|
+
children: option.icon
|
|
164
|
+
}) : null, option.label]
|
|
165
|
+
})]
|
|
166
|
+
}, option.value);
|
|
167
|
+
})
|
|
168
|
+
}),
|
|
169
|
+
draftMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
170
|
+
className: require_multi_select_module.default.draftActions,
|
|
171
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
172
|
+
type: "button",
|
|
173
|
+
className: require_multi_select_module.default.draftButton,
|
|
174
|
+
onClick: () => {
|
|
175
|
+
setDraft([...value]);
|
|
176
|
+
setOpen(false);
|
|
177
|
+
},
|
|
178
|
+
children: "Cancel"
|
|
179
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
180
|
+
type: "button",
|
|
181
|
+
className: require_multi_select_module.default.draftButton,
|
|
182
|
+
disabled: editValue.length < minSelected,
|
|
183
|
+
onClick: () => {
|
|
184
|
+
onChange(editValue);
|
|
185
|
+
setOpen(false);
|
|
186
|
+
},
|
|
187
|
+
children: "Apply"
|
|
188
|
+
})]
|
|
189
|
+
}) : null
|
|
153
190
|
]
|
|
154
191
|
}) })
|
|
155
192
|
]
|
package/dist/index28.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index28.cjs","names":[],"sources":["../src/components/multi-select/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./multi-select.module.css\";\n\nexport type MultiSelectOption = {\n label: string;\n value: string;\n disabled?: boolean;\n /** Optional decorative leading visual. The label remains the accessible option name. */\n icon?: React.ReactElement;\n};\n\nexport type MultiSelectProps = {\n options: MultiSelectOption[];\n value: string[];\n onChange: (value: string[]) => void;\n placeholder?: string;\n fullWidth?: boolean;\n maxVisibleValues?: number;\n /** Formats the closed trigger text from the selected options, including an empty selection. */\n formatValue?: (selected: MultiSelectOption[]) => string;\n /** Shows Select all and Clear all actions. Bulk actions modify enabled options only. */\n bulkActions?: boolean;\n selectAllLabel?: string;\n /** Label for clearing all enabled selections. Disabled selected options remain selected. */\n clearAllLabel?: string;\n className?: string;\n disabled?: boolean;\n name?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n};\n\nexport const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(\n (\n {\n options,\n value,\n onChange,\n placeholder = \"Select options\",\n fullWidth = true,\n maxVisibleValues = 2,\n formatValue,\n bulkActions = false,\n selectAllLabel = \"Select all\",\n clearAllLabel,\n className,\n disabled = false,\n name,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n },\n ref,\n ) => {\n const selectedSet = React.useMemo(() => new Set(value), [value]);\n const selectedOptions = React.useMemo(\n () => options.filter((opt) => selectedSet.has(opt.value)),\n [options, selectedSet],\n );\n\n const enabledValues = React.useMemo(\n () => options.filter((option) => !option.disabled).map((option) => option.value),\n [options],\n );\n const allEnabledSelected =\n enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));\n const hasDisabledOptions = options.some((option) => option.disabled);\n const resolvedClearAllLabel =\n clearAllLabel ?? (hasDisabledOptions ? \"Clear enabled\" : \"Clear all\");\n\n const formattedValue = React.useMemo(\n () => formatValue?.(selectedOptions),\n [formatValue, selectedOptions],\n );\n\n const toggleValue = React.useCallback(\n (nextValue: string) => {\n if (selectedSet.has(nextValue)) {\n onChange(value.filter((entry) => entry !== nextValue));\n return;\n }\n\n onChange([...value, nextValue]);\n },\n [onChange, selectedSet, value],\n );\n\n const visibleCount = Math.max(1, maxVisibleValues);\n const visibleOptions = selectedOptions.slice(0, visibleCount);\n const overflowCount = Math.max(\n 0,\n selectedOptions.length - visibleOptions.length,\n );\n\n return (\n <DropdownMenuPrimitive.Root modal={false}>\n <div\n className={cx(\n styles.wrapper,\n fullWidth && styles.wrapperFullWidth,\n className,\n )}\n >\n <DropdownMenuPrimitive.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={styles.trigger}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n disabled={disabled}\n >\n <span className={styles.value}>\n {formatValue ? (\n <span className={styles.summary}>{formattedValue}</span>\n ) : selectedOptions.length === 0 ? (\n <span className={styles.placeholder}>{placeholder}</span>\n ) : (\n <>\n {visibleOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n ))}\n {overflowCount > 0 ? (\n <span className={cx(styles.chip, styles.chipSummary)}>\n +{overflowCount}\n </span>\n ) : null}\n </>\n )}\n </span>\n <span className={styles.chevron} aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n >\n <path\n d=\"M2 3.5L5 6.5L8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n </DropdownMenuPrimitive.Trigger>\n\n {name\n ? value.map((entry) => (\n <input key={entry} type=\"hidden\" name={name} value={entry} />\n ))\n : null}\n\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n className={styles.menu}\n sideOffset={4}\n align=\"start\"\n >\n {bulkActions && enabledValues.length > 0 ? (\n <>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={allEnabledSelected}\n onSelect={(event) => {\n event.preventDefault();\n onChange([...value, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);\n }}\n >\n {selectAllLabel}\n </DropdownMenuPrimitive.Item>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={!enabledValues.some((entry) => selectedSet.has(entry))}\n onSelect={(event) => {\n event.preventDefault();\n const enabledSet = new Set(enabledValues);\n onChange(value.filter((entry) => !enabledSet.has(entry)));\n }}\n >\n {resolvedClearAllLabel}\n </DropdownMenuPrimitive.Item>\n </>\n ) : null}\n {bulkActions && enabledValues.length > 0 ? (\n <DropdownMenuPrimitive.Separator className={styles.separator} />\n ) : null}\n {options.map((option) => {\n const selected = selectedSet.has(option.value);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n key={option.value}\n className={cx(\n styles.option,\n selected && styles.optionSelected,\n option.disabled && styles.optionDisabled,\n )}\n checked={selected}\n disabled={option.disabled}\n onCheckedChange={() => toggleValue(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span\n className={cx(\n styles.indicator,\n selected && styles.indicatorSelected,\n option.disabled && styles.indicatorDisabled,\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator forceMount>\n <svg\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.5 8.5 6.5 11.5 12.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className={styles.optionLabel}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n );\n })}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </div>\n </DropdownMenuPrimitive.Root>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index28.cjs","names":[],"sources":["../src/components/multi-select/MultiSelect.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { cx } from \"../../utils/cx\";\nimport styles from \"./multi-select.module.css\";\n\nexport type MultiSelectOption = {\n label: string;\n value: string;\n disabled?: boolean;\n /** Optional decorative leading visual. The label remains the accessible option name. */\n icon?: React.ReactElement;\n};\n\nexport type MultiSelectProps = {\n options: MultiSelectOption[];\n value: string[];\n onChange: (value: string[]) => void;\n placeholder?: string;\n fullWidth?: boolean;\n maxVisibleValues?: number;\n /** Minimum popup width, independent of the trigger (e.g. '24rem'). */\n contentMinWidth?: string;\n /** Formats the closed trigger text from the selected options, including an empty selection. */\n formatValue?: (selected: MultiSelectOption[]) => string;\n /** Shows Select all and Clear all actions. Bulk actions modify enabled options only. */\n bulkActions?: boolean;\n /** Stage changes until Apply. Cancel/dismiss discards the draft. */\n draftMode?: boolean;\n /** Minimum number of selected values required to apply; immediate mode blocks changes below this count. */\n minSelected?: number;\n selectAllLabel?: string;\n /** Label for clearing all enabled selections. Disabled selected options remain selected. */\n clearAllLabel?: string;\n className?: string;\n disabled?: boolean;\n name?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n};\n\nexport const MultiSelect = React.forwardRef<HTMLButtonElement, MultiSelectProps>(\n (\n {\n options,\n value,\n onChange,\n placeholder = \"Select options\",\n fullWidth = true,\n maxVisibleValues = 2,\n contentMinWidth,\n formatValue,\n bulkActions = false,\n draftMode = false,\n minSelected = 0,\n selectAllLabel = \"Select all\",\n clearAllLabel,\n className,\n disabled = false,\n name,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n },\n ref,\n ) => {\n const [open, setOpen] = React.useState(false);\n const [draft, setDraft] = React.useState<string[]>(value);\n const editValue = draftMode && open ? draft : value;\n const updateSelection = (next: string[]) => {\n if (draftMode) setDraft(next);\n else if (next.length >= minSelected) onChange(next);\n };\n const selectedSet = React.useMemo(() => new Set(editValue), [editValue]);\n const selectedOptions = React.useMemo(\n () => options.filter((opt) => value.includes(opt.value)),\n [options, value],\n );\n\n const enabledValues = React.useMemo(\n () => options.filter((option) => !option.disabled).map((option) => option.value),\n [options],\n );\n const allEnabledSelected =\n enabledValues.length > 0 && enabledValues.every((entry) => selectedSet.has(entry));\n const hasDisabledOptions = options.some((option) => option.disabled);\n const resolvedClearAllLabel =\n clearAllLabel ?? (hasDisabledOptions ? \"Clear enabled\" : \"Clear all\");\n\n const formattedValue = React.useMemo(\n () => formatValue?.(selectedOptions),\n [formatValue, selectedOptions],\n );\n\n const toggleValue = React.useCallback(\n (nextValue: string) => {\n if (selectedSet.has(nextValue)) {\n updateSelection(editValue.filter((entry) => entry !== nextValue));\n return;\n }\n\n updateSelection([...editValue, nextValue]);\n },\n [updateSelection, selectedSet, editValue],\n );\n\n const visibleCount = Math.max(1, maxVisibleValues);\n const visibleOptions = selectedOptions.slice(0, visibleCount);\n const overflowCount = Math.max(\n 0,\n selectedOptions.length - visibleOptions.length,\n );\n\n return (\n <DropdownMenuPrimitive.Root modal={false} open={open} onOpenChange={(next) => {\n setDraft([...value]);\n setOpen(next);\n }}>\n <div\n className={cx(\n styles.wrapper,\n fullWidth && styles.wrapperFullWidth,\n className,\n )}\n >\n <DropdownMenuPrimitive.Trigger asChild>\n <button\n ref={ref}\n type=\"button\"\n className={styles.trigger}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n disabled={disabled}\n >\n <span className={styles.value}>\n {formatValue ? (\n <span className={styles.summary}>{formattedValue}</span>\n ) : selectedOptions.length === 0 ? (\n <span className={styles.placeholder}>{placeholder}</span>\n ) : (\n <>\n {visibleOptions.map((option) => (\n <span key={option.value} className={styles.chip}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n ))}\n {overflowCount > 0 ? (\n <span className={cx(styles.chip, styles.chipSummary)}>\n +{overflowCount}\n </span>\n ) : null}\n </>\n )}\n </span>\n <span className={styles.chevron} aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 10 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"10\"\n height=\"10\"\n >\n <path\n d=\"M2 3.5L5 6.5L8 3.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n </DropdownMenuPrimitive.Trigger>\n\n {name\n ? value.map((entry) => (\n <input key={entry} type=\"hidden\" name={name} value={entry} />\n ))\n : null}\n\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n className={styles.menu}\n style={contentMinWidth ? { '--uzi-multiselect-content-min-width': contentMinWidth } as React.CSSProperties : undefined}\n sideOffset={4}\n align=\"start\"\n >\n {bulkActions && enabledValues.length > 0 ? (\n <>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={allEnabledSelected}\n onSelect={(event) => {\n event.preventDefault();\n updateSelection([...editValue, ...enabledValues.filter((entry) => !selectedSet.has(entry))]);\n }}\n >\n {selectAllLabel}\n </DropdownMenuPrimitive.Item>\n <DropdownMenuPrimitive.Item\n className={styles.bulkAction}\n disabled={!enabledValues.some((entry) => selectedSet.has(entry))}\n onSelect={(event) => {\n event.preventDefault();\n const enabledSet = new Set(enabledValues);\n updateSelection(editValue.filter((entry) => !enabledSet.has(entry)));\n }}\n >\n {resolvedClearAllLabel}\n </DropdownMenuPrimitive.Item>\n </>\n ) : null}\n {bulkActions && enabledValues.length > 0 ? (\n <DropdownMenuPrimitive.Separator className={styles.separator} />\n ) : null}\n <div className={styles.optionsViewport}>\n {options.map((option) => {\n const selected = selectedSet.has(option.value);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n key={option.value}\n className={cx(\n styles.option,\n selected && styles.optionSelected,\n option.disabled && styles.optionDisabled,\n )}\n checked={selected}\n disabled={option.disabled}\n onCheckedChange={() => toggleValue(option.value)}\n onSelect={(event) => event.preventDefault()}\n >\n <span\n className={cx(\n styles.indicator,\n selected && styles.indicatorSelected,\n option.disabled && styles.indicatorDisabled,\n )}\n aria-hidden=\"true\"\n >\n <DropdownMenuPrimitive.ItemIndicator forceMount>\n <svg\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3.5 8.5 6.5 11.5 12.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.8\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n <span className={styles.optionLabel}>\n {option.icon ? <span className={styles.optionIcon} aria-hidden=\"true\">{option.icon}</span> : null}\n {option.label}\n </span>\n </DropdownMenuPrimitive.CheckboxItem>\n );\n })}\n </div>\n {draftMode ? (\n <div className={styles.draftActions}>\n <button type=\"button\" className={styles.draftButton} onClick={() => { setDraft([...value]); setOpen(false); }}>Cancel</button>\n <button type=\"button\" className={styles.draftButton} disabled={editValue.length < minSelected} onClick={() => {\n onChange(editValue);\n setOpen(false);\n }}>Apply</button>\n </div>\n ) : null}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </div>\n </DropdownMenuPrimitive.Root>\n );\n },\n);\n\nMultiSelect.displayName = \"MultiSelect\";\n"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -1141,9 +1141,13 @@ body {
|
|
|
1141
1141
|
top: calc(100% + 6px);
|
|
1142
1142
|
left: 0;
|
|
1143
1143
|
z-index: var(--uzi-popover-z-index, 1100);
|
|
1144
|
-
min-width:
|
|
1145
|
-
max-
|
|
1146
|
-
|
|
1144
|
+
min-width: var(--radix-dropdown-menu-trigger-width);
|
|
1145
|
+
width: max(var(--radix-dropdown-menu-trigger-width), var(--uzi-multiselect-content-min-width, 0px));
|
|
1146
|
+
max-width: min(calc(100vw - 1rem), var(--radix-dropdown-menu-content-available-width));
|
|
1147
|
+
max-height: min(28rem, var(--radix-dropdown-menu-content-available-height, calc(100dvh - 1rem)));
|
|
1148
|
+
display: flex;
|
|
1149
|
+
flex-direction: column;
|
|
1150
|
+
overflow: hidden;
|
|
1147
1151
|
border: 1px solid var(--ts-menu-border, var(--border));
|
|
1148
1152
|
border-radius: var(--uzi-menu-radius);
|
|
1149
1153
|
background: var(--ts-menu-bg, var(--popover));
|
|
@@ -1275,6 +1279,39 @@ body {
|
|
|
1275
1279
|
transform: translateY(0) scale(1);
|
|
1276
1280
|
}
|
|
1277
1281
|
}
|
|
1282
|
+
|
|
1283
|
+
.uzi-multi-select-module__draftActions__-R2g3 {
|
|
1284
|
+
display: flex;
|
|
1285
|
+
flex-shrink: 0;
|
|
1286
|
+
gap: 0.5rem;
|
|
1287
|
+
padding: 0.5rem 0.25rem 0.125rem;
|
|
1288
|
+
border-top: 1px solid var(--ts-menu-border, var(--border));
|
|
1289
|
+
}
|
|
1290
|
+
.uzi-multi-select-module__draftButton__tO1zu {
|
|
1291
|
+
flex: 1;
|
|
1292
|
+
border: 1px solid var(--ts-menu-border, var(--border));
|
|
1293
|
+
border-radius: var(--uzi-menu-item-radius);
|
|
1294
|
+
background: transparent;
|
|
1295
|
+
color: inherit;
|
|
1296
|
+
padding: 0.4rem 0.75rem;
|
|
1297
|
+
font: inherit;
|
|
1298
|
+
cursor: pointer;
|
|
1299
|
+
}
|
|
1300
|
+
.uzi-multi-select-module__draftButton__tO1zu:last-child {
|
|
1301
|
+
background: var(--primary);
|
|
1302
|
+
color: var(--primary-foreground);
|
|
1303
|
+
border-color: var(--primary);
|
|
1304
|
+
}
|
|
1305
|
+
.uzi-multi-select-module__draftButton__tO1zu:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-ring-offset); }
|
|
1306
|
+
.uzi-multi-select-module__draftButton__tO1zu:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
1307
|
+
|
|
1308
|
+
.uzi-multi-select-module__optionsViewport__Fus0q {
|
|
1309
|
+
min-height: 0;
|
|
1310
|
+
overflow-y: auto;
|
|
1311
|
+
overscroll-behavior: contain;
|
|
1312
|
+
flex: 1 1 auto;
|
|
1313
|
+
scrollbar-gutter: stable;
|
|
1314
|
+
}
|
|
1278
1315
|
.uzi-select-module__wrapper__7szq0 {
|
|
1279
1316
|
position: relative;
|
|
1280
1317
|
display: inline-flex;
|