@efolusi/meridian 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/ai/AgentRun.d.ts +20 -0
- package/ai/AgentRun.js +100 -0
- package/ai/ChatMessage.d.ts +19 -0
- package/ai/ChatMessage.js +81 -0
- package/ai/Citation.d.ts +23 -0
- package/ai/Citation.js +146 -0
- package/ai/Confirmation.d.ts +26 -0
- package/ai/Confirmation.js +84 -0
- package/ai/Conversation.d.ts +15 -0
- package/ai/Conversation.js +81 -0
- package/ai/DocumentCard.d.ts +17 -0
- package/ai/DocumentCard.js +101 -0
- package/ai/FeedbackBar.d.ts +14 -0
- package/ai/FeedbackBar.js +84 -0
- package/ai/GeneratedImage.d.ts +22 -0
- package/ai/GeneratedImage.js +100 -0
- package/ai/ModelSelector.d.ts +21 -0
- package/ai/ModelSelector.js +112 -0
- package/ai/Player.d.ts +18 -0
- package/ai/Player.js +201 -0
- package/ai/PromptComposer.d.ts +28 -0
- package/ai/PromptComposer.js +111 -0
- package/ai/PromptSteps.d.ts +18 -0
- package/ai/PromptSteps.js +167 -0
- package/ai/Reasoning.d.ts +17 -0
- package/ai/Reasoning.js +57 -0
- package/ai/RichComposer.d.ts +25 -0
- package/ai/RichComposer.js +247 -0
- package/ai/Sandbox.d.ts +20 -0
- package/ai/Sandbox.js +96 -0
- package/ai/SelectionQuote.d.ts +15 -0
- package/ai/SelectionQuote.js +123 -0
- package/ai/SourceCard.d.ts +17 -0
- package/ai/SourceCard.js +57 -0
- package/ai/Suggestions.d.ts +10 -0
- package/ai/Suggestions.js +38 -0
- package/ai/Task.d.ts +15 -0
- package/ai/Task.js +49 -0
- package/ai/Todo.d.ts +13 -0
- package/ai/Todo.js +87 -0
- package/ai/ToolCall.d.ts +30 -0
- package/ai/ToolCall.js +147 -0
- package/ai/Transcript.d.ts +27 -0
- package/ai/Transcript.js +96 -0
- package/ai/UsageMeter.d.ts +21 -0
- package/ai/UsageMeter.js +81 -0
- package/ai/WebPreview.d.ts +19 -0
- package/ai/WebPreview.js +179 -0
- package/assets/fonts/BricolageGrotesque-Variable.ttf +0 -0
- package/assets/fonts/Figtree-Italic-Variable.ttf +0 -0
- package/assets/fonts/Figtree-Variable.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Italic-Variable.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Variable.ttf +0 -0
- package/assets/fonts/OFL-BricolageGrotesque.txt +93 -0
- package/assets/fonts/OFL-Figtree.txt +93 -0
- package/assets/fonts/OFL-JetBrainsMono.txt +93 -0
- package/code/CodeBlock.d.ts +17 -0
- package/code/CodeBlock.js +99 -0
- package/code/Console.d.ts +19 -0
- package/code/Console.js +124 -0
- package/code/CopyField.d.ts +10 -0
- package/code/CopyField.js +54 -0
- package/code/Diff.d.ts +26 -0
- package/code/Diff.js +358 -0
- package/code/EnvList.d.ts +14 -0
- package/code/EnvList.js +89 -0
- package/code/Exception.d.ts +25 -0
- package/code/Exception.js +90 -0
- package/code/Terminal.d.ts +20 -0
- package/code/Terminal.js +58 -0
- package/data/BarChart.d.ts +14 -0
- package/data/BarChart.js +44 -0
- package/data/DonutChart.d.ts +17 -0
- package/data/DonutChart.js +114 -0
- package/data/EmptyState.d.ts +13 -0
- package/data/EmptyState.js +39 -0
- package/data/KeyValueList.d.ts +14 -0
- package/data/KeyValueList.js +34 -0
- package/data/LineChart.d.ts +15 -0
- package/data/LineChart.js +85 -0
- package/data/Skeleton.d.ts +11 -0
- package/data/Skeleton.js +49 -0
- package/data/Sparkline.d.ts +14 -0
- package/data/Sparkline.js +42 -0
- package/data/Stat.d.ts +14 -0
- package/data/Stat.js +40 -0
- package/data/StatusDot.d.ts +10 -0
- package/data/StatusDot.js +34 -0
- package/data/Table.d.ts +53 -0
- package/data/Table.js +174 -0
- package/dates/Calendar.d.ts +8 -0
- package/dates/Calendar.js +143 -0
- package/dates/DatePicker.d.ts +12 -0
- package/dates/DatePicker.js +118 -0
- package/display/Accordion.d.ts +15 -0
- package/display/Accordion.js +52 -0
- package/display/AspectRatio.d.ts +8 -0
- package/display/AspectRatio.js +24 -0
- package/display/Avatar.d.ts +17 -0
- package/display/Avatar.js +52 -0
- package/display/Badge.d.ts +10 -0
- package/display/Badge.js +34 -0
- package/display/Card.d.ts +17 -0
- package/display/Card.js +51 -0
- package/display/Carousel.d.ts +16 -0
- package/display/Carousel.js +97 -0
- package/display/Collapsible.d.ts +12 -0
- package/display/Collapsible.js +46 -0
- package/display/Divider.d.ts +9 -0
- package/display/Divider.js +33 -0
- package/display/Kbd.d.ts +7 -0
- package/display/Kbd.js +18 -0
- package/display/Link.d.ts +12 -0
- package/display/Link.js +41 -0
- package/display/ListItem.d.ts +19 -0
- package/display/ListItem.js +61 -0
- package/display/Resizable.d.ts +16 -0
- package/display/Resizable.js +90 -0
- package/display/ScrollArea.d.ts +8 -0
- package/display/ScrollArea.js +28 -0
- package/display/Tag.d.ts +9 -0
- package/display/Tag.js +41 -0
- package/display/Toolbar.d.ts +22 -0
- package/display/Toolbar.js +55 -0
- package/display/TreeList.d.ts +20 -0
- package/display/TreeList.js +101 -0
- package/feedback/Alert.d.ts +14 -0
- package/feedback/Alert.js +56 -0
- package/feedback/Banner.d.ts +15 -0
- package/feedback/Banner.js +49 -0
- package/feedback/ConfirmDialog.d.ts +18 -0
- package/feedback/ConfirmDialog.js +49 -0
- package/feedback/Dialog.d.ts +13 -0
- package/feedback/Dialog.js +107 -0
- package/feedback/Loader.d.ts +12 -0
- package/feedback/Loader.js +41 -0
- package/feedback/Progress.d.ts +15 -0
- package/feedback/Progress.js +48 -0
- package/feedback/Spinner.d.ts +9 -0
- package/feedback/Spinner.js +38 -0
- package/feedback/Toast.d.ts +70 -0
- package/feedback/Toast.js +216 -0
- package/feedback/Tooltip.d.ts +12 -0
- package/feedback/Tooltip.js +86 -0
- package/files/FileDrop.d.ts +15 -0
- package/files/FileDrop.js +75 -0
- package/files/FileTile.d.ts +19 -0
- package/files/FileTile.js +96 -0
- package/files/FileTypeIcon.d.ts +11 -0
- package/files/FileTypeIcon.js +121 -0
- package/finance/PaymentCard.d.ts +17 -0
- package/finance/PaymentCard.js +109 -0
- package/forms/Button.d.ts +15 -0
- package/forms/Button.js +82 -0
- package/forms/ButtonGroup.d.ts +5 -0
- package/forms/ButtonGroup.js +22 -0
- package/forms/ButtonTile.d.ts +21 -0
- package/forms/ButtonTile.js +69 -0
- package/forms/Checkbox.d.ts +6 -0
- package/forms/Checkbox.js +52 -0
- package/forms/Combobox.d.ts +17 -0
- package/forms/Combobox.js +162 -0
- package/forms/DigitEntry.d.ts +15 -0
- package/forms/DigitEntry.js +88 -0
- package/forms/FormField.d.ts +39 -0
- package/forms/FormField.js +127 -0
- package/forms/IconButton.d.ts +11 -0
- package/forms/IconButton.js +41 -0
- package/forms/Input.d.ts +14 -0
- package/forms/Input.js +75 -0
- package/forms/InputGroup.d.ts +15 -0
- package/forms/InputGroup.js +59 -0
- package/forms/Label.d.ts +11 -0
- package/forms/Label.js +29 -0
- package/forms/Radio.d.ts +6 -0
- package/forms/Radio.js +46 -0
- package/forms/Select.d.ts +10 -0
- package/forms/Select.js +68 -0
- package/forms/Slider.d.ts +18 -0
- package/forms/Slider.js +75 -0
- package/forms/Switch.d.ts +6 -0
- package/forms/Switch.js +46 -0
- package/forms/Textarea.d.ts +8 -0
- package/forms/Textarea.js +58 -0
- package/forms/Toggle.d.ts +26 -0
- package/forms/Toggle.js +85 -0
- package/icons/Icon.d.ts +13 -0
- package/icons/Icon.js +54 -0
- package/index.d.ts +106 -0
- package/index.js +106 -0
- package/navigation/Breadcrumbs.d.ts +12 -0
- package/navigation/Breadcrumbs.js +41 -0
- package/navigation/Menubar.d.ts +10 -0
- package/navigation/Menubar.js +173 -0
- package/navigation/PageControl.d.ts +11 -0
- package/navigation/PageControl.js +36 -0
- package/navigation/Pagination.d.ts +9 -0
- package/navigation/Pagination.js +68 -0
- package/navigation/SegmentedControl.d.ts +17 -0
- package/navigation/SegmentedControl.js +42 -0
- package/navigation/SideNav.d.ts +18 -0
- package/navigation/SideNav.js +87 -0
- package/navigation/Steps.d.ts +15 -0
- package/navigation/Steps.js +61 -0
- package/navigation/Tabs.d.ts +17 -0
- package/navigation/Tabs.js +76 -0
- package/navigation/TopNav.d.ts +10 -0
- package/navigation/TopNav.js +26 -0
- package/overlay/CommandPalette.d.ts +21 -0
- package/overlay/CommandPalette.js +164 -0
- package/overlay/ContextMenu.d.ts +11 -0
- package/overlay/ContextMenu.js +140 -0
- package/overlay/Drawer.d.ts +14 -0
- package/overlay/Drawer.js +99 -0
- package/overlay/HoverCard.d.ts +17 -0
- package/overlay/HoverCard.js +74 -0
- package/overlay/Menu.d.ts +24 -0
- package/overlay/Menu.js +153 -0
- package/overlay/Popover.d.ts +16 -0
- package/overlay/Popover.js +96 -0
- package/overlay/Portal.d.ts +10 -0
- package/overlay/Portal.js +127 -0
- package/package.json +41 -0
- package/styles.css +6 -0
- package/tokens/base.css +10 -0
- package/tokens/colors.css +38 -0
- package/tokens/effects.css +22 -0
- package/tokens/fonts.css +5 -0
- package/tokens/spacing.css +12 -0
- package/tokens/typography.css +9 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { injectEfCss } from "../forms/Button.js";
|
|
4
|
+
import { Icon } from "../icons/Icon.js";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.ef-richcomposer{position:relative;border:1px solid var(--border-strong);border-radius:var(--radius-lg,14px);background:var(--surface-card);transition:border-color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
|
|
7
|
+
.ef-richcomposer:focus-within{border-color:var(--text-muted);box-shadow:var(--focus-ring)}
|
|
8
|
+
.ef-richcomposer__input{min-height:44px;max-height:200px;overflow-y:auto;padding:12px 14px 4px;font-family:var(--font-sans);font-size:14px;line-height:1.6;color:var(--text-primary);outline:none;white-space:pre-wrap;word-break:break-word}
|
|
9
|
+
.ef-richcomposer__input:empty::before{content:attr(data-placeholder);color:var(--text-muted);pointer-events:none}
|
|
10
|
+
.ef-richcomposer__chip{display:inline-flex;align-items:center;gap:4px;margin:0 1px;padding:1px 7px;border-radius:var(--radius-sm);background:var(--accent-subtle);border:1px solid var(--accent-subtle-border);color:var(--text-primary);font-size:13px;white-space:nowrap;user-select:none}
|
|
11
|
+
.ef-richcomposer__bar{display:flex;align-items:center;gap:8px;padding:8px 10px 10px}
|
|
12
|
+
.ef-richcomposer__hint{font-size:12px;color:var(--text-muted)}
|
|
13
|
+
.ef-richcomposer__send{margin-left:auto;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;border-radius:var(--radius-full);background:var(--accent);color:var(--accent-contrast);cursor:pointer;transition:background var(--dur-fast) var(--ease-out),opacity var(--dur-fast) var(--ease-out)}
|
|
14
|
+
.ef-richcomposer__send:hover{background:var(--accent-hover)}
|
|
15
|
+
.ef-richcomposer__send:disabled{opacity:.35;cursor:default}
|
|
16
|
+
.ef-richcomposer__send:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
17
|
+
.ef-richcomposer__pop{position:absolute;bottom:calc(100% + 6px);left:0;right:0;z-index:40;max-height:260px;overflow-y:auto;padding:4px;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-card);box-shadow:var(--shadow-lg,0 8px 24px rgba(0,0,0,.12))}
|
|
18
|
+
.ef-richcomposer__group{padding:7px 10px 3px;font-size:11px;font-weight:var(--weight-semibold);letter-spacing:.04em;text-transform:uppercase;color:var(--text-muted)}
|
|
19
|
+
.ef-richcomposer__item{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:none;background:none;cursor:pointer;text-align:left;border-radius:var(--radius-sm);font-family:var(--font-sans);font-size:13.5px;color:var(--text-primary)}
|
|
20
|
+
.ef-richcomposer__item--hi{background:var(--surface-sunken)}
|
|
21
|
+
.ef-richcomposer__itemicon{display:inline-flex;flex:none;color:var(--text-muted)}
|
|
22
|
+
.ef-richcomposer__itemdesc{margin-left:auto;font-size:12px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
23
|
+
.ef-richcomposer__empty{padding:8px 10px;font-size:13px;color:var(--text-muted)}
|
|
24
|
+
`;
|
|
25
|
+
function findTrigger(root) {
|
|
26
|
+
const s = window.getSelection();
|
|
27
|
+
if (!s || !s.rangeCount || !s.isCollapsed) return null;
|
|
28
|
+
const node = s.anchorNode;
|
|
29
|
+
if (!node || node.nodeType !== 3 || !root.contains(node)) return null;
|
|
30
|
+
const before = node.textContent.slice(0, s.anchorOffset);
|
|
31
|
+
const m = before.match(/(^|\s)([@\/])([\w./-]*)$/);
|
|
32
|
+
if (!m) return null;
|
|
33
|
+
return {
|
|
34
|
+
node,
|
|
35
|
+
offset: s.anchorOffset,
|
|
36
|
+
char: m[2],
|
|
37
|
+
query: m[3]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function RichComposer({
|
|
41
|
+
placeholder = 'Message… use @ to mention, / for commands',
|
|
42
|
+
mentions = [],
|
|
43
|
+
commands = [],
|
|
44
|
+
hint,
|
|
45
|
+
actions,
|
|
46
|
+
disabled,
|
|
47
|
+
autoFocus,
|
|
48
|
+
onSubmit,
|
|
49
|
+
onCommand,
|
|
50
|
+
style,
|
|
51
|
+
className,
|
|
52
|
+
...rest
|
|
53
|
+
}) {
|
|
54
|
+
injectEfCss('ef-css-richcomposer', CSS);
|
|
55
|
+
const edRef = React.useRef(null);
|
|
56
|
+
const [pop, setPop] = React.useState(null);
|
|
57
|
+
const [empty, setEmpty] = React.useState(true);
|
|
58
|
+
const items = React.useMemo(() => {
|
|
59
|
+
if (!pop) return [];
|
|
60
|
+
const src = pop.char === '@' ? mentions : commands;
|
|
61
|
+
const q = pop.query.toLowerCase();
|
|
62
|
+
return src.filter(it => !q || it.label.toLowerCase().includes(q) || (it.keywords || []).some(k => k.toLowerCase().includes(q)));
|
|
63
|
+
}, [pop, mentions, commands]);
|
|
64
|
+
const refresh = () => {
|
|
65
|
+
const ed = edRef.current;
|
|
66
|
+
if (!ed) return;
|
|
67
|
+
setEmpty(ed.textContent.trim().length === 0 && !ed.querySelector('[data-chip-id]'));
|
|
68
|
+
const t = findTrigger(ed);
|
|
69
|
+
setPop(t ? {
|
|
70
|
+
char: t.char,
|
|
71
|
+
query: t.query,
|
|
72
|
+
hi: 0
|
|
73
|
+
} : null);
|
|
74
|
+
};
|
|
75
|
+
const removeTrigger = () => {
|
|
76
|
+
const ed = edRef.current;
|
|
77
|
+
const t = findTrigger(ed);
|
|
78
|
+
if (!t) return null;
|
|
79
|
+
const range = document.createRange();
|
|
80
|
+
range.setStart(t.node, t.offset - t.query.length - 1);
|
|
81
|
+
range.setEnd(t.node, t.offset);
|
|
82
|
+
range.deleteContents();
|
|
83
|
+
return range;
|
|
84
|
+
};
|
|
85
|
+
const pick = it => {
|
|
86
|
+
const ed = edRef.current;
|
|
87
|
+
if (!ed || !pop) return;
|
|
88
|
+
const range = removeTrigger();
|
|
89
|
+
if (pop.char === '/') {
|
|
90
|
+
setPop(null);
|
|
91
|
+
refresh();
|
|
92
|
+
if (onCommand) onCommand(it);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!range) return;
|
|
96
|
+
const chip = document.createElement('span');
|
|
97
|
+
chip.className = 'ef-richcomposer__chip';
|
|
98
|
+
chip.contentEditable = 'false';
|
|
99
|
+
chip.setAttribute('data-chip-id', it.id);
|
|
100
|
+
chip.textContent = '@' + it.label;
|
|
101
|
+
range.insertNode(chip);
|
|
102
|
+
const space = document.createTextNode('\u00A0');
|
|
103
|
+
chip.after(space);
|
|
104
|
+
const sel = window.getSelection();
|
|
105
|
+
const r = document.createRange();
|
|
106
|
+
r.setStartAfter(space);
|
|
107
|
+
r.collapse(true);
|
|
108
|
+
sel.removeAllRanges();
|
|
109
|
+
sel.addRange(r);
|
|
110
|
+
setPop(null);
|
|
111
|
+
refresh();
|
|
112
|
+
};
|
|
113
|
+
const serialize = () => {
|
|
114
|
+
const ed = edRef.current;
|
|
115
|
+
const found = [];
|
|
116
|
+
let text = '';
|
|
117
|
+
const walk = n => {
|
|
118
|
+
n.childNodes.forEach(c => {
|
|
119
|
+
if (c.nodeType === 3) text += c.textContent;else if (c.getAttribute && c.getAttribute('data-chip-id')) {
|
|
120
|
+
found.push({
|
|
121
|
+
id: c.getAttribute('data-chip-id'),
|
|
122
|
+
label: c.textContent.replace(/^@/, '')
|
|
123
|
+
});
|
|
124
|
+
text += c.textContent;
|
|
125
|
+
} else if (c.nodeName === 'BR') text += '\n';else {
|
|
126
|
+
if (text && (c.nodeName === 'DIV' || c.nodeName === 'P')) text += '\n';
|
|
127
|
+
walk(c);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
walk(ed);
|
|
132
|
+
return {
|
|
133
|
+
text: text.replace(/\u00A0/g, ' ').trim(),
|
|
134
|
+
mentions: found
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
const submit = () => {
|
|
138
|
+
const v = serialize();
|
|
139
|
+
if (!v.text) return;
|
|
140
|
+
if (onSubmit) onSubmit(v);
|
|
141
|
+
edRef.current.innerHTML = '';
|
|
142
|
+
setEmpty(true);
|
|
143
|
+
setPop(null);
|
|
144
|
+
edRef.current.focus();
|
|
145
|
+
};
|
|
146
|
+
const onKey = e => {
|
|
147
|
+
if (pop && items.length) {
|
|
148
|
+
if (e.key === 'ArrowDown') {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
setPop(p => ({
|
|
151
|
+
...p,
|
|
152
|
+
hi: Math.min(items.length - 1, p.hi + 1)
|
|
153
|
+
}));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (e.key === 'ArrowUp') {
|
|
157
|
+
e.preventDefault();
|
|
158
|
+
setPop(p => ({
|
|
159
|
+
...p,
|
|
160
|
+
hi: Math.max(0, p.hi - 1)
|
|
161
|
+
}));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (e.key === 'Enter' || e.key === 'Tab') {
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
pick(items[pop.hi]);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (e.key === 'Escape') {
|
|
170
|
+
e.preventDefault();
|
|
171
|
+
setPop(null);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
submit();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
React.useEffect(() => {
|
|
181
|
+
if (autoFocus && edRef.current) edRef.current.focus();
|
|
182
|
+
}, [autoFocus]);
|
|
183
|
+
let lastGroup = null;
|
|
184
|
+
return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
|
|
185
|
+
className: `ef-richcomposer${className ? ' ' + className : ''}`,
|
|
186
|
+
style: style
|
|
187
|
+
}), pop ? /*#__PURE__*/React.createElement("div", {
|
|
188
|
+
className: "ef-richcomposer__pop",
|
|
189
|
+
role: "listbox"
|
|
190
|
+
}, !items.length ? /*#__PURE__*/React.createElement("div", {
|
|
191
|
+
className: "ef-richcomposer__empty"
|
|
192
|
+
}, "No matches for ", pop.char, pop.query) : null, items.map((it, i) => {
|
|
193
|
+
const head = it.group && it.group !== lastGroup ? /*#__PURE__*/React.createElement("div", {
|
|
194
|
+
key: 'g' + it.group,
|
|
195
|
+
className: "ef-richcomposer__group"
|
|
196
|
+
}, it.group) : null;
|
|
197
|
+
lastGroup = it.group;
|
|
198
|
+
return /*#__PURE__*/React.createElement(React.Fragment, {
|
|
199
|
+
key: it.id
|
|
200
|
+
}, head, /*#__PURE__*/React.createElement("button", {
|
|
201
|
+
type: "button",
|
|
202
|
+
role: "option",
|
|
203
|
+
"aria-selected": i === pop.hi,
|
|
204
|
+
className: `ef-richcomposer__item${i === pop.hi ? ' ef-richcomposer__item--hi' : ''}`,
|
|
205
|
+
onMouseEnter: () => setPop(p => ({
|
|
206
|
+
...p,
|
|
207
|
+
hi: i
|
|
208
|
+
})),
|
|
209
|
+
onMouseDown: e => e.preventDefault(),
|
|
210
|
+
onClick: () => pick(it)
|
|
211
|
+
}, it.icon ? /*#__PURE__*/React.createElement("span", {
|
|
212
|
+
className: "ef-richcomposer__itemicon"
|
|
213
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
214
|
+
name: it.icon,
|
|
215
|
+
size: 14
|
|
216
|
+
})) : null, /*#__PURE__*/React.createElement("span", null, pop.char === '/' ? '/' + it.label : it.label), it.description ? /*#__PURE__*/React.createElement("span", {
|
|
217
|
+
className: "ef-richcomposer__itemdesc"
|
|
218
|
+
}, it.description) : null));
|
|
219
|
+
})) : null, /*#__PURE__*/React.createElement("div", {
|
|
220
|
+
ref: edRef,
|
|
221
|
+
className: "ef-richcomposer__input",
|
|
222
|
+
contentEditable: !disabled,
|
|
223
|
+
suppressContentEditableWarning: true,
|
|
224
|
+
"data-placeholder": placeholder,
|
|
225
|
+
role: "textbox",
|
|
226
|
+
"aria-multiline": "true",
|
|
227
|
+
spellCheck: false,
|
|
228
|
+
onInput: refresh,
|
|
229
|
+
onKeyUp: refresh,
|
|
230
|
+
onClick: refresh,
|
|
231
|
+
onKeyDown: onKey,
|
|
232
|
+
onBlur: () => setTimeout(() => setPop(null), 120)
|
|
233
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
234
|
+
className: "ef-richcomposer__bar"
|
|
235
|
+
}, actions, hint ? /*#__PURE__*/React.createElement("span", {
|
|
236
|
+
className: "ef-richcomposer__hint"
|
|
237
|
+
}, hint) : null, /*#__PURE__*/React.createElement("button", {
|
|
238
|
+
type: "button",
|
|
239
|
+
className: "ef-richcomposer__send",
|
|
240
|
+
"aria-label": "Send",
|
|
241
|
+
disabled: empty || disabled,
|
|
242
|
+
onClick: submit
|
|
243
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
244
|
+
name: "send",
|
|
245
|
+
size: 14
|
|
246
|
+
}))));
|
|
247
|
+
}
|
package/ai/Sandbox.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface SandboxTab {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
content: React.ReactNode;
|
|
6
|
+
}
|
|
7
|
+
export interface SandboxProps {
|
|
8
|
+
/** Command or filename, mono */
|
|
9
|
+
title: React.ReactNode;
|
|
10
|
+
/** 'running' | 'success' | 'error' */
|
|
11
|
+
state?: 'running' | 'success' | 'error';
|
|
12
|
+
/** Right-side meta, e.g. duration */
|
|
13
|
+
meta?: React.ReactNode;
|
|
14
|
+
tabs: SandboxTab[];
|
|
15
|
+
defaultOpen?: boolean;
|
|
16
|
+
defaultTab?: string;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function Sandbox(props: SandboxProps): React.JSX.Element;
|
package/ai/Sandbox.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { injectEfCss } from "../forms/Button.js";
|
|
4
|
+
import { Icon } from "../icons/Icon.js";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.ef-sandbox{border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-card);overflow:hidden;font-family:var(--font-sans);transition:border-color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
|
|
7
|
+
.ef-sandbox--running{border-color:var(--accent-subtle-border);box-shadow:0 0 0 3px var(--accent-subtle)}
|
|
8
|
+
.ef-sandbox--error{border-color:var(--danger-300);box-shadow:0 0 0 3px var(--danger-100)}
|
|
9
|
+
.ef-sandbox__head{display:flex;align-items:center;gap:9px;width:100%;padding:10px 14px;border:none;background:none;cursor:pointer;text-align:left;font-family:inherit}
|
|
10
|
+
.ef-sandbox__head:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
11
|
+
.ef-sandbox__chev{display:inline-flex;color:var(--text-muted);transition:transform var(--dur-med) var(--ease-out)}
|
|
12
|
+
.ef-sandbox--open .ef-sandbox__chev{transform:rotate(90deg)}
|
|
13
|
+
.ef-sandbox__title{flex:1;min-width:0;font-family:var(--font-mono);font-size:12.5px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
14
|
+
.ef-sandbox--error .ef-sandbox__title{color:var(--danger-600)}
|
|
15
|
+
.ef-sandbox__meta{font-size:12px;color:var(--text-muted);display:inline-flex;align-items:center;gap:6px}
|
|
16
|
+
.ef-sandbox__spin{display:inline-flex;color:var(--text-secondary);animation:ef-sandbox-spin 1s linear infinite}
|
|
17
|
+
@keyframes ef-sandbox-spin{to{transform:rotate(360deg)}}
|
|
18
|
+
.ef-sandbox__body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur-med) var(--ease-out)}
|
|
19
|
+
.ef-sandbox--open .ef-sandbox__body{grid-template-rows:1fr}
|
|
20
|
+
.ef-sandbox__clip{overflow:hidden;min-height:0}
|
|
21
|
+
.ef-sandbox__inner{border-top:1px solid var(--border-default)}
|
|
22
|
+
.ef-sandbox__tabs{display:flex;gap:18px;padding:0 14px;border-bottom:1px solid var(--border-default)}
|
|
23
|
+
.ef-sandbox__tab{display:inline-flex;align-items:center;gap:6px;height:36px;border:none;background:none;cursor:pointer;font-family:var(--font-sans);font-size:12.5px;font-weight:var(--weight-semibold);color:var(--text-muted);border-bottom:2px solid transparent;margin-bottom:-1px;transition:color var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out)}
|
|
24
|
+
.ef-sandbox__tab:hover{color:var(--text-primary)}
|
|
25
|
+
.ef-sandbox__tab--on{color:var(--text-primary);border-bottom-color:var(--accent)}
|
|
26
|
+
.ef-sandbox__tab:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
27
|
+
.ef-sandbox__panel{padding:12px 14px;font-family:var(--font-mono);font-size:12.5px;line-height:1.7;color:var(--text-secondary);overflow-x:auto}
|
|
28
|
+
.ef-sandbox__panel pre{margin:0;white-space:pre-wrap;word-break:break-word}
|
|
29
|
+
`;
|
|
30
|
+
const STATES = {
|
|
31
|
+
running: 'Running',
|
|
32
|
+
success: 'Done',
|
|
33
|
+
error: 'Failed'
|
|
34
|
+
};
|
|
35
|
+
export function Sandbox({
|
|
36
|
+
title,
|
|
37
|
+
state = 'success',
|
|
38
|
+
meta,
|
|
39
|
+
tabs = [],
|
|
40
|
+
defaultOpen,
|
|
41
|
+
defaultTab,
|
|
42
|
+
style,
|
|
43
|
+
className,
|
|
44
|
+
...rest
|
|
45
|
+
}) {
|
|
46
|
+
injectEfCss('ef-css-sandbox', CSS);
|
|
47
|
+
const [open, setOpen] = React.useState(defaultOpen !== undefined ? !!defaultOpen : state === 'error');
|
|
48
|
+
const [tab, setTab] = React.useState(defaultTab || tabs[0] && tabs[0].id);
|
|
49
|
+
const active = tabs.find(t => t.id === tab) || tabs[0];
|
|
50
|
+
return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
|
|
51
|
+
className: `ef-sandbox ef-sandbox--${state}${open ? ' ef-sandbox--open' : ''}${className ? ' ' + className : ''}`,
|
|
52
|
+
style: style,
|
|
53
|
+
"data-state": state
|
|
54
|
+
}), /*#__PURE__*/React.createElement("button", {
|
|
55
|
+
type: "button",
|
|
56
|
+
className: "ef-sandbox__head",
|
|
57
|
+
"aria-expanded": open,
|
|
58
|
+
onClick: () => setOpen(!open)
|
|
59
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
60
|
+
className: "ef-sandbox__chev"
|
|
61
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
62
|
+
name: "chevron-right",
|
|
63
|
+
size: 14
|
|
64
|
+
})), /*#__PURE__*/React.createElement("span", {
|
|
65
|
+
className: "ef-sandbox__title"
|
|
66
|
+
}, title), /*#__PURE__*/React.createElement("span", {
|
|
67
|
+
className: "ef-sandbox__meta"
|
|
68
|
+
}, state === 'running' ? /*#__PURE__*/React.createElement("span", {
|
|
69
|
+
className: "ef-sandbox__spin"
|
|
70
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
71
|
+
name: "loader-circle",
|
|
72
|
+
size: 13
|
|
73
|
+
})) : null, meta || STATES[state])), /*#__PURE__*/React.createElement("div", {
|
|
74
|
+
className: "ef-sandbox__body"
|
|
75
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
76
|
+
className: "ef-sandbox__clip"
|
|
77
|
+
}, /*#__PURE__*/React.createElement("div", {
|
|
78
|
+
className: "ef-sandbox__inner"
|
|
79
|
+
}, tabs.length > 1 ? /*#__PURE__*/React.createElement("div", {
|
|
80
|
+
className: "ef-sandbox__tabs",
|
|
81
|
+
role: "tablist"
|
|
82
|
+
}, tabs.map(t => /*#__PURE__*/React.createElement("button", {
|
|
83
|
+
key: t.id,
|
|
84
|
+
type: "button",
|
|
85
|
+
role: "tab",
|
|
86
|
+
"aria-selected": t.id === (active && active.id),
|
|
87
|
+
className: `ef-sandbox__tab${t.id === (active && active.id) ? ' ef-sandbox__tab--on' : ''}`,
|
|
88
|
+
onClick: () => setTab(t.id)
|
|
89
|
+
}, t.icon ? /*#__PURE__*/React.createElement(Icon, {
|
|
90
|
+
name: t.icon,
|
|
91
|
+
size: 13
|
|
92
|
+
}) : null, t.label))) : null, /*#__PURE__*/React.createElement("div", {
|
|
93
|
+
className: "ef-sandbox__panel",
|
|
94
|
+
role: "tabpanel"
|
|
95
|
+
}, active ? active.content : null)))));
|
|
96
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SelectionAction {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SelectionQuoteProps {
|
|
7
|
+
/** The selectable content */
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
/** Toolbar buttons. Default: one "Quote" action */
|
|
10
|
+
actions?: SelectionAction[];
|
|
11
|
+
onAction?: (id: string, text: string) => void;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function SelectionQuote(props: SelectionQuoteProps): React.JSX.Element;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { injectEfCss } from "../forms/Button.js";
|
|
4
|
+
import { Icon } from "../icons/Icon.js";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.ef-selq{position:relative}
|
|
7
|
+
.ef-selq__bar{position:absolute;z-index:30;display:inline-flex;align-items:center;gap:2px;padding:4px;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-card);box-shadow:var(--shadow-lg,0 8px 24px rgba(0,0,0,.12));user-select:none}
|
|
8
|
+
.ef-selq__btn{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border:none;background:none;cursor:pointer;border-radius:var(--radius-sm);font-family:var(--font-sans);font-size:12.5px;font-weight:var(--weight-semibold);color:var(--text-secondary);transition:color var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out)}
|
|
9
|
+
.ef-selq__btn:hover{color:var(--text-primary);background:var(--surface-subtle)}
|
|
10
|
+
.ef-selq__btn:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
11
|
+
.ef-selq__sep{width:1px;height:16px;background:var(--border-default);margin:0 3px}
|
|
12
|
+
`;
|
|
13
|
+
export function SelectionQuote({
|
|
14
|
+
children,
|
|
15
|
+
actions = [{
|
|
16
|
+
id: 'quote',
|
|
17
|
+
label: 'Quote',
|
|
18
|
+
icon: 'corner-up-left'
|
|
19
|
+
}],
|
|
20
|
+
onAction,
|
|
21
|
+
style,
|
|
22
|
+
className,
|
|
23
|
+
...rest
|
|
24
|
+
}) {
|
|
25
|
+
injectEfCss('ef-css-selq', CSS);
|
|
26
|
+
const contRef = React.useRef(null);
|
|
27
|
+
const barRef = React.useRef(null);
|
|
28
|
+
const [sel, setSel] = React.useState(null);
|
|
29
|
+
const [pos, setPos] = React.useState(null);
|
|
30
|
+
const read = () => {
|
|
31
|
+
const s = window.getSelection();
|
|
32
|
+
const cont = contRef.current;
|
|
33
|
+
if (!s || s.isCollapsed || !s.rangeCount || !cont) return null;
|
|
34
|
+
const r = s.getRangeAt(0);
|
|
35
|
+
if (!cont.contains(r.startContainer) || !cont.contains(r.endContainer)) return null;
|
|
36
|
+
const rects = r.getClientRects();
|
|
37
|
+
if (!rects.length) return null;
|
|
38
|
+
const text = s.toString();
|
|
39
|
+
if (!text.trim()) return null;
|
|
40
|
+
return {
|
|
41
|
+
text,
|
|
42
|
+
rect: rects[0]
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
React.useEffect(() => {
|
|
46
|
+
const up = e => {
|
|
47
|
+
if (barRef.current && barRef.current.contains(e.target)) return;
|
|
48
|
+
requestAnimationFrame(() => {
|
|
49
|
+
const r = read();
|
|
50
|
+
if (r) setSel(r);
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
const change = () => {
|
|
54
|
+
const s = window.getSelection();
|
|
55
|
+
if (!s || s.isCollapsed) {
|
|
56
|
+
setSel(null);
|
|
57
|
+
setPos(null);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const key = e => {
|
|
61
|
+
if (e.key === 'Escape') {
|
|
62
|
+
setSel(null);
|
|
63
|
+
setPos(null);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
document.addEventListener('pointerup', up);
|
|
67
|
+
document.addEventListener('selectionchange', change);
|
|
68
|
+
document.addEventListener('keydown', key);
|
|
69
|
+
return () => {
|
|
70
|
+
document.removeEventListener('pointerup', up);
|
|
71
|
+
document.removeEventListener('selectionchange', change);
|
|
72
|
+
document.removeEventListener('keydown', key);
|
|
73
|
+
};
|
|
74
|
+
}, []);
|
|
75
|
+
React.useLayoutEffect(() => {
|
|
76
|
+
if (!sel || !barRef.current || !contRef.current) return;
|
|
77
|
+
const bar = barRef.current.getBoundingClientRect();
|
|
78
|
+
const cont = contRef.current.getBoundingClientRect();
|
|
79
|
+
let top = sel.rect.top - cont.top - bar.height - 8;
|
|
80
|
+
if (top < 4) top = sel.rect.bottom - cont.top + 8;
|
|
81
|
+
let left = sel.rect.left - cont.left;
|
|
82
|
+
left = Math.max(4, Math.min(left, cont.width - bar.width - 4));
|
|
83
|
+
setPos({
|
|
84
|
+
top,
|
|
85
|
+
left
|
|
86
|
+
});
|
|
87
|
+
}, [sel]);
|
|
88
|
+
return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
|
|
89
|
+
ref: contRef,
|
|
90
|
+
className: `ef-selq${className ? ' ' + className : ''}`,
|
|
91
|
+
style: style
|
|
92
|
+
}), children, sel ? /*#__PURE__*/React.createElement("div", {
|
|
93
|
+
ref: barRef,
|
|
94
|
+
className: "ef-selq__bar",
|
|
95
|
+
role: "toolbar",
|
|
96
|
+
style: pos ? {
|
|
97
|
+
top: pos.top,
|
|
98
|
+
left: pos.left
|
|
99
|
+
} : {
|
|
100
|
+
top: 0,
|
|
101
|
+
left: 0,
|
|
102
|
+
visibility: 'hidden'
|
|
103
|
+
},
|
|
104
|
+
onMouseDown: e => e.preventDefault()
|
|
105
|
+
}, actions.map((a, i) => /*#__PURE__*/React.createElement(React.Fragment, {
|
|
106
|
+
key: a.id || i
|
|
107
|
+
}, i > 0 ? /*#__PURE__*/React.createElement("span", {
|
|
108
|
+
className: "ef-selq__sep",
|
|
109
|
+
"aria-hidden": "true"
|
|
110
|
+
}) : null, /*#__PURE__*/React.createElement("button", {
|
|
111
|
+
type: "button",
|
|
112
|
+
className: "ef-selq__btn",
|
|
113
|
+
onClick: () => {
|
|
114
|
+
if (onAction) onAction(a.id, sel.text);
|
|
115
|
+
window.getSelection().removeAllRanges();
|
|
116
|
+
setSel(null);
|
|
117
|
+
setPos(null);
|
|
118
|
+
}
|
|
119
|
+
}, a.icon ? /*#__PURE__*/React.createElement(Icon, {
|
|
120
|
+
name: a.icon,
|
|
121
|
+
size: 13
|
|
122
|
+
}) : null, a.label)))) : null);
|
|
123
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SourceCardProps {
|
|
2
|
+
href?: string;
|
|
3
|
+
title: React.ReactNode;
|
|
4
|
+
description?: React.ReactNode;
|
|
5
|
+
/** e.g. 'stripe.com' */
|
|
6
|
+
domain?: string;
|
|
7
|
+
/** Favicon URL; falls back to icon */
|
|
8
|
+
favicon?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
thumbnail?: string;
|
|
11
|
+
/** 'card' | 'plain' */
|
|
12
|
+
variant?: 'card' | 'plain';
|
|
13
|
+
onClick?: (e: React.MouseEvent) => void;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function SourceCard(props: SourceCardProps): React.JSX.Element;
|
package/ai/SourceCard.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { injectEfCss } from "../forms/Button.js";
|
|
4
|
+
import { Icon } from "../icons/Icon.js";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.ef-sourcecard{display:flex;flex-direction:column;gap:6px;padding:12px;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-card);text-decoration:none;color:inherit;transition:border-color var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out)}
|
|
7
|
+
a.ef-sourcecard{cursor:pointer}
|
|
8
|
+
a.ef-sourcecard:hover{border-color:var(--border-strong);background:var(--surface-subtle)}
|
|
9
|
+
a.ef-sourcecard:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
10
|
+
.ef-sourcecard--plain{border-color:transparent;background:transparent;padding:8px 10px}
|
|
11
|
+
.ef-sourcecard__thumb{width:100%;aspect-ratio:16/9;border-radius:var(--radius-sm);object-fit:cover;background:var(--surface-sunken);margin-bottom:4px}
|
|
12
|
+
.ef-sourcecard__domain{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--text-muted)}
|
|
13
|
+
.ef-sourcecard__domain img{width:14px;height:14px;border-radius:var(--radius-full)}
|
|
14
|
+
.ef-sourcecard__title{font-size:13.5px;font-weight:var(--weight-semibold);color:var(--text-primary);line-height:1.4}
|
|
15
|
+
.ef-sourcecard__desc{font-size:12.5px;color:var(--text-muted);line-height:1.55;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
|
|
16
|
+
`;
|
|
17
|
+
export function SourceCard({
|
|
18
|
+
href,
|
|
19
|
+
title,
|
|
20
|
+
description,
|
|
21
|
+
domain,
|
|
22
|
+
favicon,
|
|
23
|
+
icon = 'globe',
|
|
24
|
+
thumbnail,
|
|
25
|
+
variant = 'card',
|
|
26
|
+
onClick,
|
|
27
|
+
style,
|
|
28
|
+
className,
|
|
29
|
+
...rest
|
|
30
|
+
}) {
|
|
31
|
+
injectEfCss('ef-css-sourcecard', CSS);
|
|
32
|
+
const Tag = href || onClick ? 'a' : 'div';
|
|
33
|
+
return /*#__PURE__*/React.createElement(Tag, _extends({}, rest, {
|
|
34
|
+
className: `ef-sourcecard${variant === 'plain' ? ' ef-sourcecard--plain' : ''}${className ? ' ' + className : ''}`,
|
|
35
|
+
style: style,
|
|
36
|
+
href: href,
|
|
37
|
+
target: href ? '_blank' : undefined,
|
|
38
|
+
rel: href ? 'noreferrer noopener' : undefined,
|
|
39
|
+
onClick: onClick
|
|
40
|
+
}), thumbnail ? /*#__PURE__*/React.createElement("img", {
|
|
41
|
+
className: "ef-sourcecard__thumb",
|
|
42
|
+
src: thumbnail,
|
|
43
|
+
alt: ""
|
|
44
|
+
}) : null, domain ? /*#__PURE__*/React.createElement("span", {
|
|
45
|
+
className: "ef-sourcecard__domain"
|
|
46
|
+
}, favicon ? /*#__PURE__*/React.createElement("img", {
|
|
47
|
+
src: favicon,
|
|
48
|
+
alt: ""
|
|
49
|
+
}) : /*#__PURE__*/React.createElement(Icon, {
|
|
50
|
+
name: icon,
|
|
51
|
+
size: 13
|
|
52
|
+
}), domain) : null, /*#__PURE__*/React.createElement("span", {
|
|
53
|
+
className: "ef-sourcecard__title"
|
|
54
|
+
}, title), description ? /*#__PURE__*/React.createElement("span", {
|
|
55
|
+
className: "ef-sourcecard__desc"
|
|
56
|
+
}, description) : null);
|
|
57
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface SuggestionItem { label: string; /** Lucide icon */ icon?: string; }
|
|
2
|
+
export interface SuggestionsProps {
|
|
3
|
+
/** Strings or { label, icon } */
|
|
4
|
+
items: Array<string | SuggestionItem>;
|
|
5
|
+
/** Fires with the picked label */
|
|
6
|
+
onPick?: (label: string, index: number) => void;
|
|
7
|
+
style?: React.CSSProperties;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function Suggestions(props: SuggestionsProps): React.JSX.Element;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { injectEfCss } from "../forms/Button.js";
|
|
4
|
+
import { Icon } from "../icons/Icon.js";
|
|
5
|
+
const CSS = `
|
|
6
|
+
.ef-suggestions{display:flex;flex-wrap:wrap;gap:8px}
|
|
7
|
+
.ef-suggestion{display:inline-flex;align-items:center;gap:7px;padding:7px 13px;border:1px solid var(--border-strong);border-radius:var(--radius-full);background:var(--surface-card);cursor:pointer;font-family:var(--font-sans);font-size:13.5px;color:var(--text-secondary);transition:color var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out)}
|
|
8
|
+
.ef-suggestion:hover{color:var(--text-primary);border-color:var(--text-muted);background:var(--surface-subtle)}
|
|
9
|
+
.ef-suggestion:focus-visible{outline:none;box-shadow:var(--focus-ring)}
|
|
10
|
+
.ef-suggestion__icon{display:inline-flex;color:var(--text-muted)}
|
|
11
|
+
`;
|
|
12
|
+
export function Suggestions({
|
|
13
|
+
items = [],
|
|
14
|
+
onPick,
|
|
15
|
+
style,
|
|
16
|
+
className,
|
|
17
|
+
...rest
|
|
18
|
+
}) {
|
|
19
|
+
injectEfCss('ef-css-suggestions', CSS);
|
|
20
|
+
return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
|
|
21
|
+
className: `ef-suggestions${className ? ' ' + className : ''}`,
|
|
22
|
+
style: style
|
|
23
|
+
}), items.map((it, i) => {
|
|
24
|
+
const label = typeof it === 'string' ? it : it.label;
|
|
25
|
+
const icon = typeof it === 'string' ? null : it.icon;
|
|
26
|
+
return /*#__PURE__*/React.createElement("button", {
|
|
27
|
+
key: i,
|
|
28
|
+
type: "button",
|
|
29
|
+
className: "ef-suggestion",
|
|
30
|
+
onClick: () => onPick && onPick(label, i)
|
|
31
|
+
}, icon ? /*#__PURE__*/React.createElement("span", {
|
|
32
|
+
className: "ef-suggestion__icon"
|
|
33
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
|
34
|
+
name: icon,
|
|
35
|
+
size: 14
|
|
36
|
+
})) : null, label);
|
|
37
|
+
}));
|
|
38
|
+
}
|
package/ai/Task.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface TaskItem {
|
|
2
|
+
/** Lucide icon name; omit for a dot */
|
|
3
|
+
icon?: string;
|
|
4
|
+
label: React.ReactNode;
|
|
5
|
+
/** Muted inline detail after the label */
|
|
6
|
+
detail?: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface TaskProps {
|
|
9
|
+
items: TaskItem[];
|
|
10
|
+
/** Pulses the last row while the agent works */
|
|
11
|
+
streaming?: boolean;
|
|
12
|
+
style?: React.CSSProperties;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function Task(props: TaskProps): React.JSX.Element;
|