@tulipfarm/sprout 0.0.0-stage → 0.2.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 +21 -0
- package/README.md +183 -2
- package/dist/components/accordion.d.ts +28 -0
- package/dist/components/accordion.js +26 -0
- package/dist/components/alert-dialog.d.ts +60 -0
- package/dist/components/alert-dialog.js +69 -0
- package/dist/components/alert.d.ts +30 -0
- package/dist/components/alert.js +35 -0
- package/dist/components/aspect-ratio.d.ts +7 -0
- package/dist/components/aspect-ratio.js +6 -0
- package/dist/components/attachment.d.ts +118 -0
- package/dist/components/attachment.js +285 -0
- package/dist/components/avatar.d.ts +32 -0
- package/dist/components/avatar.js +73 -0
- package/dist/components/badge.d.ts +21 -0
- package/dist/components/badge.js +27 -0
- package/dist/components/brand-icon.d.ts +28 -0
- package/dist/components/brand-icon.js +82 -0
- package/dist/components/breadcrumb.d.ts +29 -0
- package/dist/components/breadcrumb.js +44 -0
- package/dist/components/button-group.d.ts +28 -0
- package/dist/components/button-group.js +36 -0
- package/dist/components/button.d.ts +79 -0
- package/dist/components/button.js +93 -0
- package/dist/components/calendar.d.ts +27 -0
- package/dist/components/calendar.js +107 -0
- package/dist/components/canvas.d.ts +78 -0
- package/dist/components/canvas.js +180 -0
- package/dist/components/card.d.ts +43 -0
- package/dist/components/card.js +42 -0
- package/dist/components/carousel.d.ts +57 -0
- package/dist/components/carousel.js +422 -0
- package/dist/components/chart.d.ts +112 -0
- package/dist/components/chart.js +172 -0
- package/dist/components/chat-confirmation.d.ts +42 -0
- package/dist/components/chat-confirmation.js +62 -0
- package/dist/components/chat-input.d.ts +94 -0
- package/dist/components/chat-input.js +279 -0
- package/dist/components/chat-plan.d.ts +21 -0
- package/dist/components/chat-plan.js +35 -0
- package/dist/components/chat-sources.d.ts +64 -0
- package/dist/components/chat-sources.js +66 -0
- package/dist/components/checkbox.d.ts +16 -0
- package/dist/components/checkbox.js +17 -0
- package/dist/components/choice-list.d.ts +53 -0
- package/dist/components/choice-list.js +36 -0
- package/dist/components/code-block.d.ts +35 -0
- package/dist/components/code-block.js +64 -0
- package/dist/components/collapsible.d.ts +24 -0
- package/dist/components/collapsible.js +27 -0
- package/dist/components/combobox.d.ts +95 -0
- package/dist/components/combobox.js +106 -0
- package/dist/components/command.d.ts +94 -0
- package/dist/components/command.js +414 -0
- package/dist/components/context-menu.d.ts +57 -0
- package/dist/components/context-menu.js +60 -0
- package/dist/components/dialog.d.ts +60 -0
- package/dist/components/dialog.js +79 -0
- package/dist/components/direction.d.ts +6 -0
- package/dist/components/direction.js +6 -0
- package/dist/components/dropdown-menu.d.ts +62 -0
- package/dist/components/dropdown-menu.js +59 -0
- package/dist/components/field.d.ts +117 -0
- package/dist/components/field.js +150 -0
- package/dist/components/file-explorer.d.ts +27 -0
- package/dist/components/file-explorer.js +300 -0
- package/dist/components/file-viewer.d.ts +137 -0
- package/dist/components/file-viewer.js +400 -0
- package/dist/components/form.d.ts +87 -0
- package/dist/components/form.js +55 -0
- package/dist/components/glass-banner.d.ts +27 -0
- package/dist/components/glass-banner.js +116 -0
- package/dist/components/gradient-banner.d.ts +37 -0
- package/dist/components/gradient-banner.js +43 -0
- package/dist/components/hover-card.d.ts +27 -0
- package/dist/components/hover-card.js +26 -0
- package/dist/components/input-group.d.ts +68 -0
- package/dist/components/input-group.js +88 -0
- package/dist/components/input-otp.d.ts +38 -0
- package/dist/components/input-otp.js +43 -0
- package/dist/components/input.d.ts +16 -0
- package/dist/components/input.js +18 -0
- package/dist/components/kbd.d.ts +12 -0
- package/dist/components/kbd.js +11 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.js +10 -0
- package/dist/components/mention-list.d.ts +54 -0
- package/dist/components/mention-list.js +31 -0
- package/dist/components/menubar.d.ts +64 -0
- package/dist/components/menubar.js +68 -0
- package/dist/components/message-actions.d.ts +34 -0
- package/dist/components/message-actions.js +68 -0
- package/dist/components/message-response.d.ts +20 -0
- package/dist/components/message-response.js +46 -0
- package/dist/components/message-scroller.d.ts +71 -0
- package/dist/components/message-scroller.js +217 -0
- package/dist/components/message.d.ts +49 -0
- package/dist/components/message.js +59 -0
- package/dist/components/navigation-menu.d.ts +45 -0
- package/dist/components/navigation-menu.js +54 -0
- package/dist/components/notice-banner.d.ts +14 -0
- package/dist/components/notice-banner.js +11 -0
- package/dist/components/page-content.d.ts +7 -0
- package/dist/components/page-content.js +9 -0
- package/dist/components/page-header.d.ts +37 -0
- package/dist/components/page-header.js +53 -0
- package/dist/components/pagination.d.ts +29 -0
- package/dist/components/pagination.js +29 -0
- package/dist/components/plan-outline.d.ts +60 -0
- package/dist/components/plan-outline.js +108 -0
- package/dist/components/popover.d.ts +34 -0
- package/dist/components/popover.js +35 -0
- package/dist/components/progress.d.ts +27 -0
- package/dist/components/progress.js +35 -0
- package/dist/components/prompt-list.d.ts +23 -0
- package/dist/components/prompt-list.js +11 -0
- package/dist/components/questionnaire.d.ts +148 -0
- package/dist/components/questionnaire.js +1002 -0
- package/dist/components/radio-group.d.ts +16 -0
- package/dist/components/radio-group.js +21 -0
- package/dist/components/reasoning-effort.d.ts +24 -0
- package/dist/components/reasoning-effort.js +269 -0
- package/dist/components/resizable.d.ts +67 -0
- package/dist/components/resizable.js +536 -0
- package/dist/components/result-card.d.ts +58 -0
- package/dist/components/result-card.js +88 -0
- package/dist/components/review-card.d.ts +62 -0
- package/dist/components/review-card.js +49 -0
- package/dist/components/rich-text-editor.d.ts +51 -0
- package/dist/components/rich-text-editor.js +248 -0
- package/dist/components/schema-diagram.d.ts +52 -0
- package/dist/components/schema-diagram.js +226 -0
- package/dist/components/scroll-area.d.ts +22 -0
- package/dist/components/scroll-area.js +19 -0
- package/dist/components/search-dialog.d.ts +103 -0
- package/dist/components/search-dialog.js +65 -0
- package/dist/components/search-field.d.ts +17 -0
- package/dist/components/search-field.js +27 -0
- package/dist/components/select.d.ts +57 -0
- package/dist/components/select.js +57 -0
- package/dist/components/selection-slot.d.ts +18 -0
- package/dist/components/selection-slot.js +53 -0
- package/dist/components/separator.d.ts +48 -0
- package/dist/components/separator.js +54 -0
- package/dist/components/settings-list.d.ts +26 -0
- package/dist/components/settings-list.js +17 -0
- package/dist/components/sheet.d.ts +70 -0
- package/dist/components/sheet.js +77 -0
- package/dist/components/sidebar.d.ts +70 -0
- package/dist/components/sidebar.js +187 -0
- package/dist/components/skeleton.d.ts +31 -0
- package/dist/components/skeleton.js +32 -0
- package/dist/components/slider.d.ts +17 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/spinner.d.ts +37 -0
- package/dist/components/spinner.js +43 -0
- package/dist/components/state-panel-samples.d.ts +25 -0
- package/dist/components/state-panel-samples.js +423 -0
- package/dist/components/state-panel.d.ts +35 -0
- package/dist/components/state-panel.js +29 -0
- package/dist/components/state-sample.d.ts +63 -0
- package/dist/components/state-sample.js +42 -0
- package/dist/components/switch.d.ts +12 -0
- package/dist/components/switch.js +14 -0
- package/dist/components/table-nuqs.d.ts +16 -0
- package/dist/components/table-nuqs.js +59 -0
- package/dist/components/table.d.ts +120 -0
- package/dist/components/table.js +663 -0
- package/dist/components/tabs.d.ts +37 -0
- package/dist/components/tabs.js +36 -0
- package/dist/components/textarea.d.ts +18 -0
- package/dist/components/textarea.js +19 -0
- package/dist/components/toast.d.ts +45 -0
- package/dist/components/toast.js +83 -0
- package/dist/components/toggle-group.d.ts +30 -0
- package/dist/components/toggle-group.js +39 -0
- package/dist/components/toggle.d.ts +27 -0
- package/dist/components/toggle.js +21 -0
- package/dist/components/tool-activity.d.ts +79 -0
- package/dist/components/tool-activity.js +226 -0
- package/dist/components/toolbar-status.d.ts +21 -0
- package/dist/components/toolbar-status.js +14 -0
- package/dist/components/tooltip.d.ts +31 -0
- package/dist/components/tooltip.js +99 -0
- package/dist/components/typed-text.d.ts +17 -0
- package/dist/components/typed-text.js +56 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +90 -0
- package/dist/internal/brand-glyphs.d.ts +370 -0
- package/dist/internal/brand-glyphs.js +262 -0
- package/dist/internal/classes.d.ts +3 -0
- package/dist/internal/classes.js +20 -0
- package/dist/internal/code-tokens.d.ts +4 -0
- package/dist/internal/code-tokens.js +34 -0
- package/dist/internal/fieldset.d.ts +6 -0
- package/dist/internal/fieldset.js +38 -0
- package/dist/internal/file-kind.d.ts +4 -0
- package/dist/internal/file-kind.js +62 -0
- package/dist/internal/languages.d.ts +7 -0
- package/dist/internal/languages.js +1010 -0
- package/dist/internal/message-scroller.d.ts +102 -0
- package/dist/internal/message-scroller.js +637 -0
- package/dist/internal/pressable.d.ts +2 -0
- package/dist/internal/pressable.js +29 -0
- package/dist/internal/syntax.d.ts +14 -0
- package/dist/internal/syntax.js +137 -0
- package/dist/styles/accordion.css +102 -0
- package/dist/styles/alert-dialog.css +198 -0
- package/dist/styles/alert.css +149 -0
- package/dist/styles/aspect-ratio.css +8 -0
- package/dist/styles/attachment.css +700 -0
- package/dist/styles/avatar.css +186 -0
- package/dist/styles/badge.css +178 -0
- package/dist/styles/brand-icon.css +104 -0
- package/dist/styles/breadcrumb.css +121 -0
- package/dist/styles/button-group.css +113 -0
- package/dist/styles/button.css +380 -0
- package/dist/styles/calendar.css +295 -0
- package/dist/styles/canvas.css +313 -0
- package/dist/styles/card.css +146 -0
- package/dist/styles/carousel.css +107 -0
- package/dist/styles/chart.css +227 -0
- package/dist/styles/chat-confirmation.css +29 -0
- package/dist/styles/chat-input.css +240 -0
- package/dist/styles/chat-plan.css +109 -0
- package/dist/styles/chat-sources.css +191 -0
- package/dist/styles/checkbox.css +122 -0
- package/dist/styles/choice-list.css +343 -0
- package/dist/styles/code-block.css +211 -0
- package/dist/styles/collapsible.css +72 -0
- package/dist/styles/combobox.css +347 -0
- package/dist/styles/command.css +233 -0
- package/dist/styles/context-menu.css +151 -0
- package/dist/styles/dialog.css +237 -0
- package/dist/styles/dropdown-menu.css +150 -0
- package/dist/styles/field.css +340 -0
- package/dist/styles/file-explorer.css +517 -0
- package/dist/styles/file-viewer.css +375 -0
- package/dist/styles/form.css +155 -0
- package/dist/styles/glass-banner.css +308 -0
- package/dist/styles/gradient-banner.css +256 -0
- package/dist/styles/hover-card.css +95 -0
- package/dist/styles/index.css +268 -0
- package/dist/styles/input-group.css +285 -0
- package/dist/styles/input-otp.css +138 -0
- package/dist/styles/input.css +98 -0
- package/dist/styles/kbd.css +59 -0
- package/dist/styles/label.css +89 -0
- package/dist/styles/mention-list.css +166 -0
- package/dist/styles/menubar.css +226 -0
- package/dist/styles/message-actions.css +83 -0
- package/dist/styles/message-response.css +176 -0
- package/dist/styles/message-scroller.css +136 -0
- package/dist/styles/message.css +310 -0
- package/dist/styles/navigation-menu.css +291 -0
- package/dist/styles/notice-banner.css +68 -0
- package/dist/styles/page-content.css +21 -0
- package/dist/styles/page-header.css +156 -0
- package/dist/styles/pagination.css +72 -0
- package/dist/styles/plan-outline.css +393 -0
- package/dist/styles/popover.css +140 -0
- package/dist/styles/progress.css +93 -0
- package/dist/styles/prompt-list.css +165 -0
- package/dist/styles/questionnaire.css +308 -0
- package/dist/styles/radio-group.css +119 -0
- package/dist/styles/reasoning-effort.css +157 -0
- package/dist/styles/resizable.css +108 -0
- package/dist/styles/result-card.css +215 -0
- package/dist/styles/review-card.css +235 -0
- package/dist/styles/rich-text-editor.css +169 -0
- package/dist/styles/schema-diagram.css +419 -0
- package/dist/styles/scroll-area.css +77 -0
- package/dist/styles/search-dialog.css +280 -0
- package/dist/styles/search-field.css +17 -0
- package/dist/styles/select.css +285 -0
- package/dist/styles/selection-slot.css +31 -0
- package/dist/styles/separator.css +206 -0
- package/dist/styles/settings-list.css +81 -0
- package/dist/styles/sheet.css +361 -0
- package/dist/styles/sidebar.css +363 -0
- package/dist/styles/skeleton.css +80 -0
- package/dist/styles/slider.css +142 -0
- package/dist/styles/spinner.css +39 -0
- package/dist/styles/state-panel-samples.css +41 -0
- package/dist/styles/state-panel.css +173 -0
- package/dist/styles/state-sample.css +285 -0
- package/dist/styles/switch.css +128 -0
- package/dist/styles/table.css +604 -0
- package/dist/styles/tabs.css +223 -0
- package/dist/styles/textarea.css +77 -0
- package/dist/styles/themes/chatgpt.css +125 -0
- package/dist/styles/themes/claude.css +125 -0
- package/dist/styles/themes/cloudflare.css +125 -0
- package/dist/styles/themes/discord.css +125 -0
- package/dist/styles/themes/github.css +125 -0
- package/dist/styles/themes/grok.css +125 -0
- package/dist/styles/themes/linear.css +126 -0
- package/dist/styles/themes/neutral.css +125 -0
- package/dist/styles/themes/notion.css +125 -0
- package/dist/styles/themes/perplexity.css +125 -0
- package/dist/styles/themes/raycast.css +125 -0
- package/dist/styles/themes/spotify.css +125 -0
- package/dist/styles/themes/stripe.css +125 -0
- package/dist/styles/themes/supabase.css +125 -0
- package/dist/styles/themes/tulipfarm.css +115 -0
- package/dist/styles/themes/vercel.css +126 -0
- package/dist/styles/toast.css +197 -0
- package/dist/styles/toggle-group.css +161 -0
- package/dist/styles/toggle.css +119 -0
- package/dist/styles/tool-activity.css +396 -0
- package/dist/styles/toolbar-status.css +52 -0
- package/dist/styles/tooltip.css +122 -0
- package/dist/styles/typed-text.css +17 -0
- package/package.json +452 -4
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, isValidElement, useContext, useId, useLayoutEffect, useRef, useState, useSyncExternalStore, } from "react";
|
|
4
|
+
import { Check } from "reicon-react/icons/Check";
|
|
5
|
+
import { Search } from "reicon-react/icons/Search";
|
|
6
|
+
import { cn } from "../internal/classes.js";
|
|
7
|
+
import { Dialog, DialogContent, DialogDescription, DialogTitle, } from "./dialog.js";
|
|
8
|
+
const normalize = (text) => text
|
|
9
|
+
.normalize("NFD")
|
|
10
|
+
.replace(/\p{Diacritic}/gu, "")
|
|
11
|
+
.toLowerCase();
|
|
12
|
+
function tokenScore(haystack, token) {
|
|
13
|
+
const index = haystack.indexOf(token);
|
|
14
|
+
if (index === 0)
|
|
15
|
+
return 1;
|
|
16
|
+
if (index > 0)
|
|
17
|
+
return /[\s\-_/.(]/.test(haystack[index - 1]) ? 0.9 : 0.7;
|
|
18
|
+
let from = 0;
|
|
19
|
+
let last = -1;
|
|
20
|
+
let gaps = 0;
|
|
21
|
+
for (const char of token) {
|
|
22
|
+
const found = haystack.indexOf(char, from);
|
|
23
|
+
if (found === -1)
|
|
24
|
+
return 0;
|
|
25
|
+
if (last >= 0)
|
|
26
|
+
gaps += found - last - 1;
|
|
27
|
+
last = found;
|
|
28
|
+
from = found + 1;
|
|
29
|
+
}
|
|
30
|
+
return Math.max(0.05, 0.5 - gaps * 0.02);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The default filter. Every word of the search must appear in the value or a
|
|
34
|
+
* keyword, as a substring or in order with gaps. Prefix and word-start matches
|
|
35
|
+
* rank above loose ones. Case and accents are ignored.
|
|
36
|
+
*/
|
|
37
|
+
export const defaultCommandFilter = (value, search, keywords = []) => {
|
|
38
|
+
const haystack = normalize([value, ...keywords].join(" "));
|
|
39
|
+
const tokens = normalize(search).trim().split(/\s+/).filter(Boolean);
|
|
40
|
+
let score = 1;
|
|
41
|
+
for (const token of tokens)
|
|
42
|
+
score = Math.min(score, tokenScore(haystack, token));
|
|
43
|
+
return score;
|
|
44
|
+
};
|
|
45
|
+
class CommandStore {
|
|
46
|
+
search = "";
|
|
47
|
+
active = null;
|
|
48
|
+
ready = false;
|
|
49
|
+
count = 0;
|
|
50
|
+
version = 0;
|
|
51
|
+
needsFirst = true;
|
|
52
|
+
options = { filter: defaultCommandFilter, shouldFilter: true };
|
|
53
|
+
items = new Map();
|
|
54
|
+
scores = new Map();
|
|
55
|
+
groupScores = new Map();
|
|
56
|
+
listeners = new Set();
|
|
57
|
+
scheduled = false;
|
|
58
|
+
subscribe = (listener) => {
|
|
59
|
+
this.listeners.add(listener);
|
|
60
|
+
return () => this.listeners.delete(listener);
|
|
61
|
+
};
|
|
62
|
+
get filtering() {
|
|
63
|
+
return this.options.shouldFilter && this.search.trim() !== "";
|
|
64
|
+
}
|
|
65
|
+
emit() {
|
|
66
|
+
this.version++;
|
|
67
|
+
for (const listener of this.listeners)
|
|
68
|
+
listener();
|
|
69
|
+
}
|
|
70
|
+
refilter() {
|
|
71
|
+
this.scores.clear();
|
|
72
|
+
this.groupScores.clear();
|
|
73
|
+
let count = 0;
|
|
74
|
+
for (const [id, entry] of this.items) {
|
|
75
|
+
const score = this.filtering
|
|
76
|
+
? this.options.filter(entry.value, this.search, entry.keywords)
|
|
77
|
+
: 1;
|
|
78
|
+
if (score <= 0)
|
|
79
|
+
continue;
|
|
80
|
+
count++;
|
|
81
|
+
this.scores.set(id, score);
|
|
82
|
+
if (entry.group)
|
|
83
|
+
this.groupScores.set(entry.group, Math.max(score, this.groupScores.get(entry.group) ?? 0));
|
|
84
|
+
}
|
|
85
|
+
this.count = count;
|
|
86
|
+
}
|
|
87
|
+
/** Coalesces item registrations into one refilter and render. */
|
|
88
|
+
schedule() {
|
|
89
|
+
if (this.scheduled)
|
|
90
|
+
return;
|
|
91
|
+
this.scheduled = true;
|
|
92
|
+
queueMicrotask(() => {
|
|
93
|
+
this.scheduled = false;
|
|
94
|
+
this.refilter();
|
|
95
|
+
if (this.active && !this.scores.has(this.active))
|
|
96
|
+
this.needsFirst = true;
|
|
97
|
+
this.emit();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
setSearch(search) {
|
|
101
|
+
if (search === this.search)
|
|
102
|
+
return;
|
|
103
|
+
this.search = search;
|
|
104
|
+
this.refilter();
|
|
105
|
+
this.needsFirst = true;
|
|
106
|
+
this.emit();
|
|
107
|
+
}
|
|
108
|
+
setActive(id) {
|
|
109
|
+
if (id === this.active)
|
|
110
|
+
return;
|
|
111
|
+
this.active = id;
|
|
112
|
+
this.emit();
|
|
113
|
+
}
|
|
114
|
+
isVisible(id) {
|
|
115
|
+
return !this.filtering || this.scores.has(id);
|
|
116
|
+
}
|
|
117
|
+
order(score) {
|
|
118
|
+
return this.filtering && score ? -Math.round(score * 1000) : undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const CommandContext = createContext(null);
|
|
122
|
+
const GroupContext = createContext(null);
|
|
123
|
+
function useCommandContext(part) {
|
|
124
|
+
const context = useContext(CommandContext);
|
|
125
|
+
if (!context)
|
|
126
|
+
throw new Error(`${part} must be inside Command.`);
|
|
127
|
+
return context;
|
|
128
|
+
}
|
|
129
|
+
function useStore(store, read) {
|
|
130
|
+
return useSyncExternalStore(store.subscribe, read, read);
|
|
131
|
+
}
|
|
132
|
+
const ITEM = '[data-slot="command-item"]';
|
|
133
|
+
function orderOf(element) {
|
|
134
|
+
return element instanceof HTMLElement ? Number(element.style.order || 0) : 0;
|
|
135
|
+
}
|
|
136
|
+
/** Enabled items in visual order: groups and items reorder by score while searching. */
|
|
137
|
+
function enabledItems(root) {
|
|
138
|
+
const items = [
|
|
139
|
+
...root.querySelectorAll(`${ITEM}:not([aria-disabled="true"])`),
|
|
140
|
+
].filter((item) => item.closest('[data-slot="command"]') === root);
|
|
141
|
+
const keyed = items.map((item) => {
|
|
142
|
+
const group = item.closest('[data-slot="command-group"]');
|
|
143
|
+
return group && root.contains(group)
|
|
144
|
+
? { item, group, outer: orderOf(group), inner: orderOf(item) }
|
|
145
|
+
: { item, group: null, outer: orderOf(item), inner: 0 };
|
|
146
|
+
});
|
|
147
|
+
return keyed.sort((a, b) => a.outer - b.outer || a.inner - b.inner);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* A searchable list of actions. Type to filter, move with the arrow keys,
|
|
151
|
+
* and press Enter to choose. Focus stays in the search input while the
|
|
152
|
+
* active item is announced through `aria-activedescendant`.
|
|
153
|
+
*/
|
|
154
|
+
export function Command({ label, shouldFilter = true, filter = defaultCommandFilter, loop = false, className, children, onKeyDown, ref, ...props }) {
|
|
155
|
+
const [store] = useState(() => new CommandStore());
|
|
156
|
+
const root = useRef(null);
|
|
157
|
+
const id = useId();
|
|
158
|
+
const context = useRef({
|
|
159
|
+
store,
|
|
160
|
+
listId: `${id}-list`,
|
|
161
|
+
inputId: `${id}-input`,
|
|
162
|
+
labelId: `${id}-label`,
|
|
163
|
+
label,
|
|
164
|
+
}).current;
|
|
165
|
+
context.label = label;
|
|
166
|
+
const version = useStore(store, () => store.version);
|
|
167
|
+
useLayoutEffect(() => {
|
|
168
|
+
const changed = store.options.filter !== filter ||
|
|
169
|
+
store.options.shouldFilter !== shouldFilter;
|
|
170
|
+
store.options = { filter, shouldFilter };
|
|
171
|
+
if (changed && store.ready) {
|
|
172
|
+
store.refilter();
|
|
173
|
+
store.needsFirst = true;
|
|
174
|
+
store.emit();
|
|
175
|
+
}
|
|
176
|
+
}, [store, filter, shouldFilter]);
|
|
177
|
+
useLayoutEffect(() => {
|
|
178
|
+
if (!store.ready) {
|
|
179
|
+
store.ready = true;
|
|
180
|
+
store.refilter();
|
|
181
|
+
store.emit();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!store.needsFirst || !root.current)
|
|
185
|
+
return;
|
|
186
|
+
store.needsFirst = false;
|
|
187
|
+
const first = enabledItems(root.current)[0]?.item;
|
|
188
|
+
store.setActive(first?.id ?? null);
|
|
189
|
+
root.current
|
|
190
|
+
.querySelector('[data-slot="command-list"]')
|
|
191
|
+
?.scrollTo({ top: 0 });
|
|
192
|
+
}, [store, version]);
|
|
193
|
+
const move = (to) => {
|
|
194
|
+
if (!root.current)
|
|
195
|
+
return;
|
|
196
|
+
const items = enabledItems(root.current);
|
|
197
|
+
if (!items.length)
|
|
198
|
+
return;
|
|
199
|
+
const index = items.findIndex(({ item }) => item.id === store.active);
|
|
200
|
+
const next = items[to(items, index)];
|
|
201
|
+
if (!next)
|
|
202
|
+
return;
|
|
203
|
+
store.setActive(next.item.id);
|
|
204
|
+
const firstInGroup = next.group && items.find(({ group }) => group === next.group) === next;
|
|
205
|
+
const heading = firstInGroup
|
|
206
|
+
? next.group.querySelector('[data-slot="command-group-heading"]')
|
|
207
|
+
: null;
|
|
208
|
+
(heading ?? next.item).scrollIntoView({ block: "nearest" });
|
|
209
|
+
if (heading)
|
|
210
|
+
next.item.scrollIntoView({ block: "nearest" });
|
|
211
|
+
};
|
|
212
|
+
const step = (delta) => move((items, index) => {
|
|
213
|
+
if (index === -1)
|
|
214
|
+
return delta === 1 ? 0 : items.length - 1;
|
|
215
|
+
const next = index + delta;
|
|
216
|
+
if (loop)
|
|
217
|
+
return (next + items.length) % items.length;
|
|
218
|
+
return Math.min(Math.max(next, 0), items.length - 1);
|
|
219
|
+
});
|
|
220
|
+
const jumpGroup = (delta) => move((items, index) => {
|
|
221
|
+
const current = items[index];
|
|
222
|
+
if (!current)
|
|
223
|
+
return 0;
|
|
224
|
+
const groups = [...new Set(items.map(({ group }) => group))];
|
|
225
|
+
const next = groups[groups.indexOf(current.group) + delta];
|
|
226
|
+
if (next === undefined)
|
|
227
|
+
return index;
|
|
228
|
+
return items.findIndex(({ group }) => group === next);
|
|
229
|
+
});
|
|
230
|
+
const handleKeyDown = (event) => {
|
|
231
|
+
onKeyDown?.(event);
|
|
232
|
+
if (event.defaultPrevented || event.nativeEvent.isComposing)
|
|
233
|
+
return;
|
|
234
|
+
const target = event.target;
|
|
235
|
+
const fromInput = target.dataset.slot === "command-input";
|
|
236
|
+
if (!fromInput &&
|
|
237
|
+
target.closest("button, a[href], input, textarea, select, [contenteditable]"))
|
|
238
|
+
return;
|
|
239
|
+
const vim = event.ctrlKey && !event.metaKey && !event.altKey;
|
|
240
|
+
switch (event.key) {
|
|
241
|
+
case "ArrowDown":
|
|
242
|
+
case "ArrowUp": {
|
|
243
|
+
const delta = event.key === "ArrowDown" ? 1 : -1;
|
|
244
|
+
if (event.metaKey)
|
|
245
|
+
move((items) => (delta === 1 ? items.length - 1 : 0));
|
|
246
|
+
else if (event.altKey)
|
|
247
|
+
jumpGroup(delta);
|
|
248
|
+
else
|
|
249
|
+
step(delta);
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case "n":
|
|
253
|
+
case "j":
|
|
254
|
+
if (!vim)
|
|
255
|
+
return;
|
|
256
|
+
step(1);
|
|
257
|
+
break;
|
|
258
|
+
case "p":
|
|
259
|
+
case "k":
|
|
260
|
+
if (!vim)
|
|
261
|
+
return;
|
|
262
|
+
step(-1);
|
|
263
|
+
break;
|
|
264
|
+
case "Home":
|
|
265
|
+
move(() => 0);
|
|
266
|
+
break;
|
|
267
|
+
case "End":
|
|
268
|
+
move((items) => items.length - 1);
|
|
269
|
+
break;
|
|
270
|
+
case "Enter": {
|
|
271
|
+
if (!store.active)
|
|
272
|
+
return;
|
|
273
|
+
const entry = store.items.get(store.active);
|
|
274
|
+
if (!entry)
|
|
275
|
+
return;
|
|
276
|
+
event.preventDefault();
|
|
277
|
+
entry.select();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
default:
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
event.preventDefault();
|
|
284
|
+
};
|
|
285
|
+
return (_jsx(CommandContext.Provider, { value: context, children: _jsxs("div", { "data-slot": "command", ...props, ref: (node) => {
|
|
286
|
+
root.current = node;
|
|
287
|
+
if (typeof ref === "function")
|
|
288
|
+
return ref(node);
|
|
289
|
+
if (ref)
|
|
290
|
+
ref.current = node;
|
|
291
|
+
}, className: cn("sprout-command", className), onKeyDown: handleKeyDown, children: [label && (_jsx("label", { id: context.labelId, htmlFor: context.inputId, className: "sprout-command-sr-only", children: label })), children] }) }));
|
|
292
|
+
}
|
|
293
|
+
/** The search field with a leading magnifier. It drives filtering and keyboard navigation. */
|
|
294
|
+
export function CommandInput({ value, onValueChange, onChange, className, id, ...props }) {
|
|
295
|
+
const { store, listId, inputId, labelId, label } = useCommandContext("CommandInput");
|
|
296
|
+
const search = useStore(store, () => store.search);
|
|
297
|
+
const active = useStore(store, () => store.active);
|
|
298
|
+
const empty = useStore(store, () => store.ready && store.count === 0);
|
|
299
|
+
useLayoutEffect(() => {
|
|
300
|
+
if (value !== undefined)
|
|
301
|
+
store.setSearch(value);
|
|
302
|
+
}, [store, value]);
|
|
303
|
+
return (_jsx("div", { "data-slot": "command-input-wrapper", className: "sprout-command-input-wrapper", children: _jsxs("div", { "data-slot": "command-input-group", className: "sprout-command-input-group", children: [_jsx(Search, { size: 16, "aria-hidden": "true", className: "sprout-command-input-icon" }), _jsx("input", { id: id ?? inputId, type: "text", role: "combobox", autoComplete: "off", autoCorrect: "off", spellCheck: false, "aria-autocomplete": "list", "aria-expanded": !empty, "aria-controls": listId, "aria-labelledby": label && !props["aria-label"] ? labelId : undefined, "aria-activedescendant": active ?? undefined, "data-slot": "command-input", ...props, value: value ?? search, onChange: (event) => {
|
|
304
|
+
onChange?.(event);
|
|
305
|
+
onValueChange?.(event.target.value);
|
|
306
|
+
if (value === undefined)
|
|
307
|
+
store.setSearch(event.target.value);
|
|
308
|
+
}, className: cn("sprout-command-input", className) })] }) }));
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* The scrolling listbox. It caps at 18rem and keeps the active item in view.
|
|
312
|
+
* While nothing matches it drops the listbox role so `CommandEmpty` can hold
|
|
313
|
+
* ordinary content such as a Clear search button.
|
|
314
|
+
*/
|
|
315
|
+
export function CommandList({ className, children, ...props }) {
|
|
316
|
+
const { store, listId, label } = useCommandContext("CommandList");
|
|
317
|
+
const empty = useStore(store, () => store.ready && store.count === 0);
|
|
318
|
+
const { "aria-label": ariaLabel = props["aria-labelledby"]
|
|
319
|
+
? undefined
|
|
320
|
+
: (label ?? "Suggestions"), "aria-labelledby": ariaLabelledBy, ...rest } = props;
|
|
321
|
+
return (_jsx("div", { id: listId, role: empty ? undefined : "listbox", tabIndex: empty ? undefined : -1, "aria-label": empty ? undefined : ariaLabel, "aria-labelledby": empty ? undefined : ariaLabelledBy, "data-slot": "command-list", "data-empty": empty || undefined, ...rest, className: cn("sprout-command-list", className), children: _jsx("div", { "data-slot": "command-list-sizer", className: "sprout-command-list-sizer", children: children }) }));
|
|
322
|
+
}
|
|
323
|
+
/** Shown only when no item matches the search. It can hold a recovery action. */
|
|
324
|
+
export function CommandEmpty({ className, ...props }) {
|
|
325
|
+
const { store } = useCommandContext("CommandEmpty");
|
|
326
|
+
const empty = useStore(store, () => store.ready && store.count === 0);
|
|
327
|
+
if (!empty)
|
|
328
|
+
return null;
|
|
329
|
+
return (_jsx("div", { role: "presentation", "data-slot": "command-empty", ...props, className: cn("sprout-command-empty", className) }));
|
|
330
|
+
}
|
|
331
|
+
/** Groups related items under an optional heading. It hides when none of its items match. */
|
|
332
|
+
export function CommandGroup({ heading, forceMount = false, className, children, style, ...props }) {
|
|
333
|
+
const { store } = useCommandContext("CommandGroup");
|
|
334
|
+
const id = useId();
|
|
335
|
+
const headingId = `${id}-heading`;
|
|
336
|
+
const score = useStore(store, () => store.groupScores.get(id));
|
|
337
|
+
const filtering = useStore(store, () => store.filtering);
|
|
338
|
+
const hidden = filtering && score === undefined && !forceMount;
|
|
339
|
+
return (_jsxs("div", { role: "presentation", "data-slot": "command-group", hidden: hidden || undefined, ...props, style: { order: store.order(score), ...style }, className: cn("sprout-command-group", className), children: [heading != null && heading !== false && (_jsx("div", { id: headingId, "aria-hidden": "true", "data-slot": "command-group-heading", className: "sprout-command-group-heading", children: heading })), _jsx("div", { role: "group", "aria-labelledby": heading != null && heading !== false ? headingId : undefined, "data-slot": "command-group-items", className: "sprout-command-group-items", children: _jsx(GroupContext.Provider, { value: id, children: children }) })] }));
|
|
340
|
+
}
|
|
341
|
+
export function CommandSeparator({ alwaysRender = false, className, ...props }) {
|
|
342
|
+
const { store } = useCommandContext("CommandSeparator");
|
|
343
|
+
const searching = useStore(store, () => store.search !== "");
|
|
344
|
+
if (searching && !alwaysRender)
|
|
345
|
+
return null;
|
|
346
|
+
return (_jsx("div", { "aria-hidden": "true", "data-slot": "command-separator", ...props, className: cn("sprout-command-separator", className) }));
|
|
347
|
+
}
|
|
348
|
+
function textOf(node) {
|
|
349
|
+
if (typeof node === "string" || typeof node === "number")
|
|
350
|
+
return String(node);
|
|
351
|
+
if (Array.isArray(node))
|
|
352
|
+
return node.map(textOf).join("");
|
|
353
|
+
if (isValidElement(node))
|
|
354
|
+
return textOf(node.props.children);
|
|
355
|
+
return "";
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* One choice. Put an icon first, then the label. A trailing check marks the
|
|
359
|
+
* current choice with `data-checked`; a `CommandShortcut` replaces it.
|
|
360
|
+
*/
|
|
361
|
+
export function CommandItem({ value, keywords, disabled = false, onSelect, forceMount = false, className, children, style, onClick, onPointerMove, onPointerDown, ...props }) {
|
|
362
|
+
const { store } = useCommandContext("CommandItem");
|
|
363
|
+
const group = useContext(GroupContext);
|
|
364
|
+
const id = useId();
|
|
365
|
+
const resolved = (value ?? textOf(children)).trim();
|
|
366
|
+
const select = useRef(() => { });
|
|
367
|
+
select.current = () => {
|
|
368
|
+
if (!disabled)
|
|
369
|
+
onSelect?.(resolved);
|
|
370
|
+
};
|
|
371
|
+
const keywordKey = (keywords ?? []).join("\u0000");
|
|
372
|
+
useLayoutEffect(() => {
|
|
373
|
+
store.items.set(id, {
|
|
374
|
+
value: resolved,
|
|
375
|
+
keywords: keywordKey ? keywordKey.split("\u0000") : [],
|
|
376
|
+
group,
|
|
377
|
+
select: () => select.current(),
|
|
378
|
+
});
|
|
379
|
+
store.schedule();
|
|
380
|
+
return () => {
|
|
381
|
+
store.items.delete(id);
|
|
382
|
+
if (store.active === id)
|
|
383
|
+
store.needsFirst = true;
|
|
384
|
+
store.schedule();
|
|
385
|
+
};
|
|
386
|
+
}, [store, id, resolved, keywordKey, group]);
|
|
387
|
+
const visible = useStore(store, () => forceMount || store.isVisible(id));
|
|
388
|
+
const active = useStore(store, () => store.active === id);
|
|
389
|
+
const score = useStore(store, () => store.scores.get(id));
|
|
390
|
+
if (!visible)
|
|
391
|
+
return null;
|
|
392
|
+
return (_jsxs("div", { id: id, role: "option", "aria-selected": active, "aria-disabled": disabled || undefined, "data-selected": active || undefined, "data-disabled": disabled || undefined, "data-value": resolved, "data-slot": "command-item", ...props, style: { order: store.order(score), ...style }, className: cn("sprout-command-item", className), onPointerDown: (event) => {
|
|
393
|
+
onPointerDown?.(event);
|
|
394
|
+
// Keep focus in the search input so typing and arrows keep working.
|
|
395
|
+
if (!event.defaultPrevented)
|
|
396
|
+
event.preventDefault();
|
|
397
|
+
}, onPointerMove: (event) => {
|
|
398
|
+
onPointerMove?.(event);
|
|
399
|
+
if (!disabled && !event.defaultPrevented)
|
|
400
|
+
store.setActive(id);
|
|
401
|
+
}, onClick: (event) => {
|
|
402
|
+
onClick?.(event);
|
|
403
|
+
if (!event.defaultPrevented)
|
|
404
|
+
select.current();
|
|
405
|
+
}, children: [children, _jsx(Check, { size: 16, "aria-hidden": "true", className: "sprout-command-item-check" })] }));
|
|
406
|
+
}
|
|
407
|
+
/** A keyboard hint at the end of an item. */
|
|
408
|
+
export function CommandShortcut({ className, ...props }) {
|
|
409
|
+
return (_jsx("span", { "data-slot": "command-shortcut", ...props, className: cn("sprout-command-shortcut", className) }));
|
|
410
|
+
}
|
|
411
|
+
/** A command palette pinned near the top of the viewport. */
|
|
412
|
+
export function CommandDialog({ title = "Command Palette", description = "Search for a command to run...", className, showCloseButton = false, closeLabel, container, children, ...props }) {
|
|
413
|
+
return (_jsx(Dialog, { ...props, children: _jsxs(DialogContent, { placement: "top", showCloseButton: showCloseButton, closeLabel: closeLabel, container: container, className: cn("sprout-command-dialog", className), children: [_jsx(DialogTitle, { className: "sprout-command-sr-only", children: title }), _jsx(DialogDescription, { className: "sprout-command-sr-only", children: description }), children] }) }));
|
|
414
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ComponentProps } from "react";
|
|
2
|
+
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
|
|
3
|
+
export declare const contextMenuItemVariantNames: readonly ["default", "destructive"];
|
|
4
|
+
export type ContextMenuItemVariant = (typeof contextMenuItemVariantNames)[number];
|
|
5
|
+
export type ContextMenuProps = ContextMenuPrimitive.Root.Props;
|
|
6
|
+
/** Opens a menu at the pointer on right-click, or after a long press on touch screens. */
|
|
7
|
+
export declare function ContextMenu(props: ContextMenuProps): import("react").JSX.Element;
|
|
8
|
+
export type ContextMenuPortalProps = ContextMenuPrimitive.Portal.Props;
|
|
9
|
+
export declare function ContextMenuPortal(props: ContextMenuPortalProps): import("react").JSX.Element;
|
|
10
|
+
export type ContextMenuTriggerProps = ContextMenuPrimitive.Trigger.Props;
|
|
11
|
+
/** The area that opens the menu. It renders a `div`; pass `render` to use another element. */
|
|
12
|
+
export declare function ContextMenuTrigger({ className, ...props }: ContextMenuTriggerProps): import("react").JSX.Element;
|
|
13
|
+
type PositionerProps = Pick<ContextMenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding" | "collisionAvoidance" | "sticky" | "positionMethod">;
|
|
14
|
+
export interface ContextMenuContentProps extends ContextMenuPrimitive.Popup.Props, PositionerProps {
|
|
15
|
+
/** Where the portal renders. Defaults to `document.body`. */
|
|
16
|
+
container?: ContextMenuPrimitive.Portal.Props["container"];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The menu surface. It renders its own portal and positioner and opens beside
|
|
20
|
+
* the pointer, so place it directly inside `ContextMenu` or `ContextMenuSub`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ContextMenuContent({ align, alignOffset, side, sideOffset, collisionPadding, collisionAvoidance, sticky, positionMethod, container, className, ...props }: ContextMenuContentProps): import("react").JSX.Element;
|
|
23
|
+
export type ContextMenuGroupProps = ContextMenuPrimitive.Group.Props;
|
|
24
|
+
export declare function ContextMenuGroup(props: ContextMenuGroupProps): import("react").JSX.Element;
|
|
25
|
+
interface Inset {
|
|
26
|
+
/** Indents the text to line up with items that have a leading icon. */
|
|
27
|
+
inset?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ContextMenuLabelProps extends ContextMenuPrimitive.GroupLabel.Props, Inset {
|
|
30
|
+
}
|
|
31
|
+
export declare function ContextMenuLabel({ className, inset, ...props }: ContextMenuLabelProps): import("react").JSX.Element;
|
|
32
|
+
export interface ContextMenuItemProps extends ContextMenuPrimitive.Item.Props, Inset {
|
|
33
|
+
variant?: ContextMenuItemVariant;
|
|
34
|
+
}
|
|
35
|
+
export declare function ContextMenuItem({ className, inset, variant, ...props }: ContextMenuItemProps): import("react").JSX.Element;
|
|
36
|
+
export type ContextMenuSubProps = ContextMenuPrimitive.SubmenuRoot.Props;
|
|
37
|
+
export declare function ContextMenuSub(props: ContextMenuSubProps): import("react").JSX.Element;
|
|
38
|
+
export interface ContextMenuSubTriggerProps extends ContextMenuPrimitive.SubmenuTrigger.Props, Inset {
|
|
39
|
+
}
|
|
40
|
+
export declare function ContextMenuSubTrigger({ className, inset, children, ...props }: ContextMenuSubTriggerProps): import("react").JSX.Element;
|
|
41
|
+
export type ContextMenuSubContentProps = ContextMenuContentProps;
|
|
42
|
+
/** A nested menu surface. It opens to the side of its sub trigger. */
|
|
43
|
+
export declare function ContextMenuSubContent({ alignOffset, side, className, ...props }: ContextMenuSubContentProps): import("react").JSX.Element;
|
|
44
|
+
export interface ContextMenuCheckboxItemProps extends ContextMenuPrimitive.CheckboxItem.Props, Inset {
|
|
45
|
+
}
|
|
46
|
+
export declare function ContextMenuCheckboxItem({ className, inset, children, ...props }: ContextMenuCheckboxItemProps): import("react").JSX.Element;
|
|
47
|
+
export type ContextMenuRadioGroupProps = ContextMenuPrimitive.RadioGroup.Props;
|
|
48
|
+
export declare function ContextMenuRadioGroup(props: ContextMenuRadioGroupProps): import("react").JSX.Element;
|
|
49
|
+
export interface ContextMenuRadioItemProps extends ContextMenuPrimitive.RadioItem.Props, Inset {
|
|
50
|
+
}
|
|
51
|
+
export declare function ContextMenuRadioItem({ className, inset, children, ...props }: ContextMenuRadioItemProps): import("react").JSX.Element;
|
|
52
|
+
export type ContextMenuSeparatorProps = ContextMenuPrimitive.Separator.Props;
|
|
53
|
+
export declare function ContextMenuSeparator({ className, ...props }: ContextMenuSeparatorProps): import("react").JSX.Element;
|
|
54
|
+
export type ContextMenuShortcutProps = ComponentProps<"span">;
|
|
55
|
+
/** Right-aligned hint text, such as a keyboard shortcut. It does not bind keys. */
|
|
56
|
+
export declare function ContextMenuShortcut({ className, ...props }: ContextMenuShortcutProps): import("react").JSX.Element;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
|
|
4
|
+
import { Check } from "reicon-react/icons/Check";
|
|
5
|
+
import { ChevronRight } from "reicon-react/icons/ChevronRight";
|
|
6
|
+
import { cn, stateClassName } from "../internal/classes.js";
|
|
7
|
+
export const contextMenuItemVariantNames = ["default", "destructive"];
|
|
8
|
+
/** Opens a menu at the pointer on right-click, or after a long press on touch screens. */
|
|
9
|
+
export function ContextMenu(props) {
|
|
10
|
+
return _jsx(ContextMenuPrimitive.Root, { ...props });
|
|
11
|
+
}
|
|
12
|
+
export function ContextMenuPortal(props) {
|
|
13
|
+
return (_jsx(ContextMenuPrimitive.Portal, { "data-slot": "context-menu-portal", ...props }));
|
|
14
|
+
}
|
|
15
|
+
/** The area that opens the menu. It renders a `div`; pass `render` to use another element. */
|
|
16
|
+
export function ContextMenuTrigger({ className, ...props }) {
|
|
17
|
+
return (_jsx(ContextMenuPrimitive.Trigger, { "data-slot": "context-menu-trigger", ...props, className: stateClassName("sprout-context-menu-trigger", className) }));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The menu surface. It renders its own portal and positioner and opens beside
|
|
21
|
+
* the pointer, so place it directly inside `ContextMenu` or `ContextMenuSub`.
|
|
22
|
+
*/
|
|
23
|
+
export function ContextMenuContent({ align = "start", alignOffset = 4, side = "right", sideOffset = 0, collisionPadding = 8, collisionAvoidance, sticky, positionMethod, container, className, ...props }) {
|
|
24
|
+
return (_jsx(ContextMenuPrimitive.Portal, { container: container, children: _jsx(ContextMenuPrimitive.Positioner, { className: "sprout-context-menu-positioner", align: align, alignOffset: alignOffset, side: side, sideOffset: sideOffset, collisionPadding: collisionPadding, collisionAvoidance: collisionAvoidance, sticky: sticky, positionMethod: positionMethod, children: _jsx(ContextMenuPrimitive.Popup, { "data-slot": "context-menu-content", ...props, className: stateClassName("sprout-context-menu-content", className) }) }) }));
|
|
25
|
+
}
|
|
26
|
+
export function ContextMenuGroup(props) {
|
|
27
|
+
return (_jsx(ContextMenuPrimitive.Group, { "data-slot": "context-menu-group", ...props }));
|
|
28
|
+
}
|
|
29
|
+
export function ContextMenuLabel({ className, inset, ...props }) {
|
|
30
|
+
return (_jsx(ContextMenuPrimitive.GroupLabel, { "data-slot": "context-menu-label", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-context-menu-label", className) }));
|
|
31
|
+
}
|
|
32
|
+
export function ContextMenuItem({ className, inset, variant = "default", ...props }) {
|
|
33
|
+
return (_jsx(ContextMenuPrimitive.Item, { "data-slot": "context-menu-item", "data-inset": inset || undefined, "data-variant": variant, ...props, className: stateClassName("sprout-context-menu-item", className) }));
|
|
34
|
+
}
|
|
35
|
+
export function ContextMenuSub(props) {
|
|
36
|
+
return _jsx(ContextMenuPrimitive.SubmenuRoot, { ...props });
|
|
37
|
+
}
|
|
38
|
+
export function ContextMenuSubTrigger({ className, inset, children, ...props }) {
|
|
39
|
+
return (_jsxs(ContextMenuPrimitive.SubmenuTrigger, { "data-slot": "context-menu-sub-trigger", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-context-menu-item sprout-context-menu-sub-trigger", className), children: [children, _jsx(ChevronRight, { size: 16, "aria-hidden": "true", className: "sprout-context-menu-sub-chevron" })] }));
|
|
40
|
+
}
|
|
41
|
+
/** A nested menu surface. It opens to the side of its sub trigger. */
|
|
42
|
+
export function ContextMenuSubContent({ alignOffset = -5, side = "right", className, ...props }) {
|
|
43
|
+
return (_jsx(ContextMenuContent, { "data-slot": "context-menu-sub-content", alignOffset: alignOffset, side: side, ...props, className: stateClassName("sprout-context-menu-sub-content", className) }));
|
|
44
|
+
}
|
|
45
|
+
export function ContextMenuCheckboxItem({ className, inset, children, ...props }) {
|
|
46
|
+
return (_jsxs(ContextMenuPrimitive.CheckboxItem, { "data-slot": "context-menu-checkbox-item", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-context-menu-item sprout-context-menu-choice", className), children: [_jsx("span", { className: "sprout-context-menu-indicator", "data-slot": "context-menu-checkbox-item-indicator", children: _jsx(ContextMenuPrimitive.CheckboxItemIndicator, { children: _jsx(Check, { size: 16, "aria-hidden": "true" }) }) }), children] }));
|
|
47
|
+
}
|
|
48
|
+
export function ContextMenuRadioGroup(props) {
|
|
49
|
+
return (_jsx(ContextMenuPrimitive.RadioGroup, { "data-slot": "context-menu-radio-group", ...props }));
|
|
50
|
+
}
|
|
51
|
+
export function ContextMenuRadioItem({ className, inset, children, ...props }) {
|
|
52
|
+
return (_jsxs(ContextMenuPrimitive.RadioItem, { "data-slot": "context-menu-radio-item", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-context-menu-item sprout-context-menu-choice", className), children: [_jsx("span", { className: "sprout-context-menu-indicator", "data-slot": "context-menu-radio-item-indicator", children: _jsx(ContextMenuPrimitive.RadioItemIndicator, { children: _jsx(Check, { size: 16, "aria-hidden": "true" }) }) }), children] }));
|
|
53
|
+
}
|
|
54
|
+
export function ContextMenuSeparator({ className, ...props }) {
|
|
55
|
+
return (_jsx(ContextMenuPrimitive.Separator, { "data-slot": "context-menu-separator", ...props, className: stateClassName("sprout-context-menu-separator", className) }));
|
|
56
|
+
}
|
|
57
|
+
/** Right-aligned hint text, such as a keyboard shortcut. It does not bind keys. */
|
|
58
|
+
export function ContextMenuShortcut({ className, ...props }) {
|
|
59
|
+
return (_jsx("span", { "data-slot": "context-menu-shortcut", ...props, className: cn("sprout-context-menu-shortcut", className) }));
|
|
60
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
+
export declare const dialogSizeNames: readonly ["default", "form", "split", "fullscreen"];
|
|
4
|
+
export declare const dialogPlacementNames: readonly ["center", "top"];
|
|
5
|
+
export type DialogSize = (typeof dialogSizeNames)[number];
|
|
6
|
+
export type DialogPlacement = (typeof dialogPlacementNames)[number];
|
|
7
|
+
export type DialogProps = DialogPrimitive.Root.Props;
|
|
8
|
+
export declare function Dialog(props: DialogProps): import("react").JSX.Element;
|
|
9
|
+
export type DialogTriggerProps = DialogPrimitive.Trigger.Props;
|
|
10
|
+
export declare function DialogTrigger(props: DialogTriggerProps): import("react").JSX.Element;
|
|
11
|
+
export type DialogPortalProps = DialogPrimitive.Portal.Props;
|
|
12
|
+
export declare function DialogPortal(props: DialogPortalProps): import("react").JSX.Element;
|
|
13
|
+
export type DialogCloseProps = DialogPrimitive.Close.Props;
|
|
14
|
+
export declare function DialogClose(props: DialogCloseProps): import("react").JSX.Element;
|
|
15
|
+
export type DialogOverlayProps = DialogPrimitive.Backdrop.Props;
|
|
16
|
+
export declare function DialogOverlay({ className, ...props }: DialogOverlayProps): import("react").JSX.Element;
|
|
17
|
+
export interface DialogContentProps extends DialogPrimitive.Popup.Props {
|
|
18
|
+
/** Adds a ghost icon button in the top-right corner. Defaults to `true`. */
|
|
19
|
+
showCloseButton?: boolean;
|
|
20
|
+
/** Accessible name of the corner close button. */
|
|
21
|
+
closeLabel?: string;
|
|
22
|
+
size?: DialogSize;
|
|
23
|
+
/** `top` pins the dialog near the top of the viewport for search and command palettes. */
|
|
24
|
+
placement?: DialogPlacement;
|
|
25
|
+
/** Where the portal renders. Defaults to `document.body`. */
|
|
26
|
+
container?: DialogPrimitive.Portal.Props["container"];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The dialog surface. It renders its own portal and overlay, so place it
|
|
30
|
+
* directly inside `Dialog`.
|
|
31
|
+
*/
|
|
32
|
+
export declare function DialogContent({ className, children, showCloseButton, closeLabel, size, placement, container, ...props }: DialogContentProps): import("react").JSX.Element;
|
|
33
|
+
type PartSlot = "dialog-header" | "dialog-body";
|
|
34
|
+
export interface DialogPartState extends Record<string, unknown> {
|
|
35
|
+
slot: PartSlot | "dialog-footer";
|
|
36
|
+
}
|
|
37
|
+
export type DialogPartProps = useRender.ComponentProps<"div", DialogPartState>;
|
|
38
|
+
/** Stacks the title and description. */
|
|
39
|
+
export declare const DialogHeader: ({ className, render, ref, ...props }: DialogPartProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
40
|
+
/**
|
|
41
|
+
* The scrolling middle of a `form` dialog. It bleeds to the dialog edges so
|
|
42
|
+
* scrollbars and focus rings are not clipped.
|
|
43
|
+
*/
|
|
44
|
+
export declare const DialogBody: ({ className, render, ref, ...props }: DialogPartProps) => import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
45
|
+
export interface DialogFooterProps extends DialogPartProps {
|
|
46
|
+
/** Appends an outline Close button after the other actions. */
|
|
47
|
+
showCloseButton?: boolean;
|
|
48
|
+
closeLabel?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* A tinted action bar pinned to the bottom edge. Actions stack in reverse
|
|
52
|
+
* order on narrow screens and align right from 640px. A leading `<p>` becomes
|
|
53
|
+
* a hint that sits at the start.
|
|
54
|
+
*/
|
|
55
|
+
export declare function DialogFooter({ className, render, ref, showCloseButton, closeLabel, children, ...props }: DialogFooterProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
56
|
+
export type DialogTitleProps = DialogPrimitive.Title.Props;
|
|
57
|
+
export declare function DialogTitle({ className, ...props }: DialogTitleProps): import("react").JSX.Element;
|
|
58
|
+
export type DialogDescriptionProps = DialogPrimitive.Description.Props;
|
|
59
|
+
export declare function DialogDescription({ className, ...props }: DialogDescriptionProps): import("react").JSX.Element;
|
|
60
|
+
export {};
|