@ctrl-ui/react 0.8.7 → 0.8.9
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/dist/action-bar.d.ts +15 -7
- package/dist/action-bar.js +39 -19
- package/dist/activity.js +7 -15
- package/dist/audio-recorder.d.ts +14 -4
- package/dist/audio-recorder.js +82 -29
- package/dist/audio-visualizer.js +1 -1
- package/dist/blocks/coding-agent.js +39 -39
- package/dist/blocks/design-canvas.d.ts +5 -1
- package/dist/blocks/design-canvas.js +198 -92
- package/dist/blocks/discussion.d.ts +28 -0
- package/dist/blocks/discussion.js +67 -0
- package/dist/blocks/file-explorer-data.d.ts +1 -0
- package/dist/blocks/file-explorer-data.js +4 -1
- package/dist/blocks/file-explorer.d.ts +9 -1
- package/dist/blocks/file-explorer.js +461 -192
- package/dist/blocks/settings.d.ts +2 -1
- package/dist/blocks/settings.js +101 -79
- package/dist/blocks/team-chat.d.ts +12 -0
- package/dist/blocks/team-chat.js +26 -0
- package/dist/blocks/theme-toggle.js +23 -31
- package/dist/chat-composer-attachment.d.ts +4 -1
- package/dist/chat-composer-attachment.js +35 -10
- package/dist/chat-composer-editor/extensions/mention.d.ts +5 -1
- package/dist/chat-composer-editor/extensions/mention.js +59 -28
- package/dist/chat-composer-editor/ghost.js +2 -4
- package/dist/chat-composer-editor/types.d.ts +5 -0
- package/dist/chat-composer-editor.d.ts +1 -1
- package/dist/chat-composer-editor.js +57 -30
- package/dist/chat-composer.d.ts +13 -32
- package/dist/chat-composer.js +52 -12
- package/dist/chat-layout.d.ts +19 -0
- package/dist/chat-layout.js +91 -40
- package/dist/chat-message/social.d.ts +26 -0
- package/dist/chat-message/social.js +122 -0
- package/dist/chat-message.d.ts +28 -29
- package/dist/chat-message.js +106 -25
- package/dist/context.d.ts +2 -2
- package/dist/context.js +38 -23
- package/dist/dynamic-notification-canvas-loop.d.ts +24 -0
- package/dist/dynamic-notification-canvas-loop.js +113 -0
- package/dist/dynamic-notification-glass.js +23 -114
- package/dist/dynamic-notification-liquid.js +14 -118
- package/dist/dynamic-notification.d.ts +16 -8
- package/dist/dynamic-notification.js +85 -22
- package/dist/email/email-brand.d.ts +7 -4
- package/dist/email/email-brand.js +9 -6
- package/dist/email/email-code.d.ts +3 -2
- package/dist/email/email-code.js +11 -9
- package/dist/email/email-footer.d.ts +5 -3
- package/dist/email/email-footer.js +11 -5
- package/dist/email/email.d.ts +31 -9
- package/dist/email/email.js +50 -26
- package/dist/email/templates.d.ts +10 -9
- package/dist/email/templates.js +102 -38
- package/dist/email/theme.js +1 -1
- package/dist/environment-variables.d.ts +4 -2
- package/dist/environment-variables.js +52 -32
- package/dist/filter-bar/editor.js +20 -8
- package/dist/filter-bar/model.d.ts +1 -0
- package/dist/filter-bar/model.js +10 -1
- package/dist/filter-bar/motion.js +4 -4
- package/dist/filter-bar/parts.js +19 -8
- package/dist/filter-bar/types.d.ts +1 -0
- package/dist/filter-bar.js +19 -13
- package/dist/hooks/use-audio-recorder.js +12 -6
- package/dist/hooks/use-chat-composer.d.ts +19 -7
- package/dist/hooks/use-chat-composer.js +32 -5
- package/dist/hooks/use-chat-message.d.ts +28 -2
- package/dist/hooks/use-chat-message.js +41 -10
- package/dist/hooks/use-chat-thread-scroll.js +43 -7
- package/dist/hooks/use-color-area.d.ts +3 -3
- package/dist/hooks/use-color-area.js +13 -12
- package/dist/hooks/use-copy-to-clipboard.d.ts +2 -1
- package/dist/hooks/use-copy-to-clipboard.js +20 -20
- package/dist/hooks/use-dynamic-notification.d.ts +6 -2
- package/dist/hooks/use-dynamic-notification.js +26 -10
- package/dist/hooks/use-mobile.d.ts +3 -2
- package/dist/hooks/use-mobile.js +8 -4
- package/dist/hooks/use-textarea-trigger-menu.js +2 -1
- package/dist/hooks/use-trigger-menu.d.ts +54 -0
- package/dist/hooks/use-trigger-menu.js +102 -47
- package/dist/hooks/use-user-ask.d.ts +2 -0
- package/dist/hooks/use-user-ask.js +35 -41
- package/dist/inline-attachment.d.ts +6 -2
- package/dist/inline-attachment.js +36 -15
- package/dist/inline-citation.d.ts +12 -5
- package/dist/inline-citation.js +25 -16
- package/dist/knob-contracts/audio-recorder-knobs.d.ts +1 -1
- package/dist/knob-contracts/audio-recorder-knobs.js +2 -1
- package/dist/knob-contracts/audio-visualizer-knobs.d.ts +1 -1
- package/dist/knob-contracts/audio-visualizer-knobs.js +2 -1
- package/dist/knob-contracts/avatar-knobs.d.ts +1 -1
- package/dist/knob-contracts/avatar-knobs.js +6 -1
- package/dist/knob-contracts/badge-knobs.d.ts +1 -1
- package/dist/knob-contracts/badge-knobs.js +2 -1
- package/dist/knob-contracts/breadcrumb-knobs.d.ts +4 -0
- package/dist/knob-contracts/breadcrumb-knobs.js +8 -0
- package/dist/knob-contracts/button-knobs.d.ts +1 -1
- package/dist/knob-contracts/button-knobs.js +1 -0
- package/dist/knob-contracts/chat-message-knobs.d.ts +1 -1
- package/dist/knob-contracts/chat-message-knobs.js +8 -1
- package/dist/knob-contracts/code-diff-knobs.d.ts +1 -1
- package/dist/knob-contracts/code-diff-knobs.js +2 -0
- package/dist/knob-contracts/code-knobs.d.ts +1 -1
- package/dist/knob-contracts/code-knobs.js +2 -1
- package/dist/knob-contracts/dynamic-notification-knobs.d.ts +1 -1
- package/dist/knob-contracts/dynamic-notification-knobs.js +2 -0
- package/dist/knob-contracts/emoji-picker-knobs.d.ts +4 -0
- package/dist/knob-contracts/emoji-picker-knobs.js +10 -0
- package/dist/knob-contracts/field-knobs.d.ts +1 -1
- package/dist/knob-contracts/field-knobs.js +5 -1
- package/dist/knob-contracts/filter-bar-knobs.d.ts +1 -1
- package/dist/knob-contracts/filter-bar-knobs.js +1 -2
- package/dist/knob-contracts/markdown-knobs.d.ts +1 -1
- package/dist/knob-contracts/markdown-knobs.js +3 -1
- package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
- package/dist/knob-contracts/page-layout-knobs.js +2 -1
- package/dist/knob-contracts/popup-knobs.d.ts +1 -1
- package/dist/knob-contracts/popup-knobs.js +27 -0
- package/dist/knob-contracts/range-knobs.d.ts +1 -1
- package/dist/knob-contracts/range-knobs.js +1 -0
- package/dist/knob-contracts/rich-tooltip-knobs.d.ts +1 -1
- package/dist/knob-contracts/rich-tooltip-knobs.js +2 -1
- package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
- package/dist/knob-contracts/sidebar-knobs.js +27 -2
- package/dist/knob-contracts/spinner-knobs.d.ts +1 -1
- package/dist/knob-contracts/spinner-knobs.js +1 -1
- package/dist/knob-contracts/stepper-knobs.d.ts +1 -1
- package/dist/knob-contracts/stepper-knobs.js +4 -1
- package/dist/knob-contracts/switch-knobs.d.ts +1 -1
- package/dist/knob-contracts/switch-knobs.js +5 -0
- package/dist/knob-contracts/table-of-contents-knobs.d.ts +1 -1
- package/dist/knob-contracts/table-of-contents-knobs.js +2 -1
- package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
- package/dist/knob-contracts/tabs-knobs.js +1 -0
- package/dist/knob-contracts/tree-knobs.d.ts +1 -1
- package/dist/knob-contracts/tree-knobs.js +2 -1
- package/dist/lib/cn.js +0 -4
- package/dist/lib/contrast.d.ts +1 -0
- package/dist/lib/contrast.js +17 -5
- package/dist/lib/dropzone-validation.js +41 -28
- package/dist/lib/env-file.d.ts +1 -1
- package/dist/lib/env-file.js +5 -5
- package/dist/lib/motion.d.ts +4 -0
- package/dist/lib/motion.js +15 -0
- package/dist/lib/trigger-detect.js +6 -8
- package/dist/markdown-block.js +2 -1
- package/dist/popup-parts.d.ts +8 -0
- package/dist/popup-parts.js +43 -0
- package/dist/source-badge.js +3 -1
- package/dist/styles/code.css +0 -2
- package/dist/styles/effects.css +6 -32
- package/dist/styles/index.css +10 -5
- package/dist/styles/recipes/accordion.css +9 -6
- package/dist/styles/recipes/action-bar.css +0 -15
- package/dist/styles/recipes/activity.css +5 -11
- package/dist/styles/recipes/alert.css +4 -4
- package/dist/styles/recipes/audio-recorder.css +15 -3
- package/dist/styles/recipes/audio-visualizer.css +13 -2
- package/dist/styles/recipes/avatar.css +78 -1
- package/dist/styles/recipes/badge.css +14 -4
- package/dist/styles/recipes/breadcrumb.css +77 -0
- package/dist/styles/recipes/button-group.css +5 -7
- package/dist/styles/recipes/button-states.css +66 -0
- package/dist/styles/recipes/button.css +24 -83
- package/dist/styles/recipes/calendar.css +17 -23
- package/dist/styles/recipes/card.css +2 -2
- package/dist/styles/recipes/chat-composer-attachment.css +9 -3
- package/dist/styles/recipes/chat-composer.css +7 -10
- package/dist/styles/recipes/chat-layout.css +35 -0
- package/dist/styles/recipes/chat-message-social.css +123 -0
- package/dist/styles/recipes/chat-message.css +157 -37
- package/dist/styles/recipes/choice.css +18 -21
- package/dist/styles/recipes/code-diff.css +46 -33
- package/dist/styles/recipes/code.css +36 -16
- package/dist/styles/recipes/collapsible.css +7 -2
- package/dist/styles/recipes/color-picker-details.css +3 -4
- package/dist/styles/recipes/color-picker-values.css +9 -8
- package/dist/styles/recipes/color-picker.css +11 -2
- package/dist/styles/recipes/context.css +3 -3
- package/dist/styles/recipes/dockable-panel.css +7 -4
- package/dist/styles/recipes/dropzone.css +7 -8
- package/dist/styles/recipes/dynamic-notification-input.css +8 -5
- package/dist/styles/recipes/dynamic-notification-motion.css +12 -21
- package/dist/styles/recipes/dynamic-notification.css +40 -26
- package/dist/styles/recipes/emoji-picker.css +132 -0
- package/dist/styles/recipes/empty.css +5 -4
- package/dist/styles/recipes/environment-variables.css +4 -15
- package/dist/styles/recipes/field-parts.css +30 -24
- package/dist/styles/recipes/field.css +61 -26
- package/dist/styles/recipes/filter-bar.css +18 -31
- package/dist/styles/recipes/gradient-editor.css +18 -7
- package/dist/styles/recipes/infinite-canvas.css +0 -1
- package/dist/styles/recipes/inline-attachment.css +3 -3
- package/dist/styles/recipes/inline-citation.css +10 -4
- package/dist/styles/recipes/item.css +23 -9
- package/dist/styles/recipes/markdown-block.css +5 -4
- package/dist/styles/recipes/markdown.css +68 -26
- package/dist/styles/recipes/morphing-panel.css +8 -8
- package/dist/styles/recipes/page-layout.css +20 -12
- package/dist/styles/recipes/pagination.css +4 -5
- package/dist/styles/recipes/phone-input.css +12 -8
- package/dist/styles/recipes/popup-controls.css +166 -33
- package/dist/styles/recipes/popup-drawer.css +3 -14
- package/dist/styles/recipes/popup-lists.css +128 -27
- package/dist/styles/recipes/popup-motion.css +4 -45
- package/dist/styles/recipes/popup-toast.css +55 -26
- package/dist/styles/recipes/popup.css +139 -141
- package/dist/styles/recipes/range.css +54 -18
- package/dist/styles/recipes/resizable.css +2 -7
- package/dist/styles/recipes/rich-tooltip.css +24 -34
- package/dist/styles/recipes/scroll-area.css +8 -1
- package/dist/styles/recipes/sidebar-menu.css +166 -34
- package/dist/styles/recipes/sidebar-parts.css +192 -0
- package/dist/styles/recipes/sidebar.css +188 -128
- package/dist/styles/recipes/source-badge.css +1 -1
- package/dist/styles/recipes/spinner.css +8 -1
- package/dist/styles/recipes/stepper.css +31 -13
- package/dist/styles/recipes/switch.css +68 -23
- package/dist/styles/recipes/table-of-contents.css +9 -1
- package/dist/styles/recipes/table.css +14 -10
- package/dist/styles/recipes/tabs.css +17 -12
- package/dist/styles/recipes/task-list.css +7 -14
- package/dist/styles/recipes/thread-rail.css +42 -19
- package/dist/styles/recipes/timeline.css +2 -0
- package/dist/styles/recipes/toolbar.css +27 -25
- package/dist/styles/recipes/track-highlight.css +10 -7
- package/dist/styles/recipes/tree.css +31 -4
- package/dist/styles/recipes/user-ask-details.css +0 -1
- package/dist/styles/recipes/user-ask.css +4 -4
- package/dist/styles/theme.css +37 -16
- package/dist/task-list.d.ts +4 -1
- package/dist/task-list.js +24 -8
- package/dist/thread-rail.d.ts +1 -1
- package/dist/thread-rail.js +61 -19
- package/dist/transcript-divider.js +2 -1
- package/dist/ui/alert.d.ts +3 -1
- package/dist/ui/alert.js +14 -8
- package/dist/ui/autocomplete.js +3 -1
- package/dist/ui/avatar.d.ts +8 -0
- package/dist/ui/avatar.js +23 -3
- package/dist/ui/badge.js +1 -1
- package/dist/ui/breadcrumb.d.ts +27 -0
- package/dist/ui/breadcrumb.js +88 -0
- package/dist/ui/button.d.ts +2 -1
- package/dist/ui/button.js +1 -1
- package/dist/ui/calendar.js +2 -2
- package/dist/ui/card.d.ts +3 -1
- package/dist/ui/card.js +12 -7
- package/dist/ui/checkbox.d.ts +2 -0
- package/dist/ui/code-diff.d.ts +1 -1
- package/dist/ui/code-diff.js +71 -27
- package/dist/ui/code.d.ts +5 -3
- package/dist/ui/code.js +26 -27
- package/dist/ui/color-picker.d.ts +5 -2
- package/dist/ui/color-picker.js +84 -36
- package/dist/ui/combobox-disabled-selection.d.ts +1 -2
- package/dist/ui/combobox-disabled-selection.js +7 -9
- package/dist/ui/combobox.js +13 -5
- package/dist/ui/command.d.ts +8 -2
- package/dist/ui/command.js +30 -14
- package/dist/ui/context-menu.js +3 -0
- package/dist/ui/dialog.d.ts +2 -1
- package/dist/ui/dialog.js +3 -22
- package/dist/ui/dockable-panel-geometry.d.ts +1 -0
- package/dist/ui/dockable-panel-geometry.js +7 -1
- package/dist/ui/dockable-panel.d.ts +9 -6
- package/dist/ui/dockable-panel.js +63 -23
- package/dist/ui/dropdown-menu.js +4 -3
- package/dist/ui/dropzone.d.ts +2 -2
- package/dist/ui/dropzone.js +75 -16
- package/dist/ui/emoji-picker.d.ts +18 -0
- package/dist/ui/emoji-picker.js +136 -0
- package/dist/ui/empty.d.ts +3 -1
- package/dist/ui/empty.js +12 -7
- package/dist/ui/gradient-editor.d.ts +1 -1
- package/dist/ui/gradient-editor.js +37 -21
- package/dist/ui/infinite-canvas.d.ts +3 -2
- package/dist/ui/infinite-canvas.js +63 -19
- package/dist/ui/input-group.d.ts +0 -3
- package/dist/ui/input-group.js +3 -13
- package/dist/ui/input-otp.d.ts +1 -1
- package/dist/ui/input-otp.js +32 -15
- package/dist/ui/input.js +4 -4
- package/dist/ui/item.d.ts +2 -1
- package/dist/ui/item.js +11 -7
- package/dist/ui/live-status.d.ts +7 -0
- package/dist/ui/live-status.js +17 -0
- package/dist/ui/markdown-elements.d.ts +6 -0
- package/dist/ui/markdown-elements.js +31 -1
- package/dist/ui/menubar.js +2 -2
- package/dist/ui/morphing-panel.js +2 -1
- package/dist/ui/native-select.d.ts +1 -1
- package/dist/ui/native-select.js +24 -11
- package/dist/ui/page-layout.d.ts +2 -2
- package/dist/ui/page-layout.js +2 -4
- package/dist/ui/pagination.d.ts +7 -5
- package/dist/ui/pagination.js +19 -13
- package/dist/ui/phone-input.d.ts +1 -0
- package/dist/ui/phone-input.js +56 -58
- package/dist/ui/radio-group.d.ts +2 -0
- package/dist/ui/resizable.d.ts +3 -2
- package/dist/ui/resizable.js +5 -3
- package/dist/ui/responsive-dialog.d.ts +1 -1
- package/dist/ui/responsive-dialog.js +4 -21
- package/dist/ui/rich-tooltip.d.ts +10 -4
- package/dist/ui/rich-tooltip.js +81 -33
- package/dist/ui/scroll-area.d.ts +1 -1
- package/dist/ui/scroll-area.js +43 -28
- package/dist/ui/sidebar-menu.d.ts +5 -1
- package/dist/ui/sidebar-menu.js +34 -34
- package/dist/ui/sidebar-provider.d.ts +10 -1
- package/dist/ui/sidebar-provider.js +38 -13
- package/dist/ui/sidebar-resize-rail.js +7 -3
- package/dist/ui/sidebar.d.ts +11 -6
- package/dist/ui/sidebar.js +48 -24
- package/dist/ui/slider.js +31 -22
- package/dist/ui/spinner.d.ts +3 -2
- package/dist/ui/spinner.js +3 -2
- package/dist/ui/stepper.d.ts +8 -1
- package/dist/ui/stepper.js +74 -25
- package/dist/ui/switch.d.ts +1 -0
- package/dist/ui/table-of-contents.d.ts +2 -2
- package/dist/ui/table-of-contents.js +20 -8
- package/dist/ui/table.js +4 -2
- package/dist/ui/textarea.d.ts +1 -1
- package/dist/ui/textarea.js +20 -9
- package/dist/ui/timeline.d.ts +3 -1
- package/dist/ui/timeline.js +17 -9
- package/dist/ui/toast.d.ts +11 -5
- package/dist/ui/toast.js +100 -54
- package/dist/ui/toolbar.d.ts +2 -1
- package/dist/ui/toolbar.js +3 -1
- package/dist/ui/tooltip.js +3 -20
- package/dist/ui/tree.js +120 -80
- package/dist/ui/trigger-menu.js +1 -0
- package/dist/user-ask.d.ts +10 -5
- package/dist/user-ask.js +31 -11
- package/package.json +5 -1
- package/dist/hooks/use-keyboard-navigation.d.ts +0 -3
- package/dist/hooks/use-keyboard-navigation.js +0 -22
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { isComposingKey, useTriggerMenu } from "./use-trigger-menu.js";
|
|
2
3
|
import { caretRectInTextarea, detectTrigger } from "../lib/trigger-detect.js";
|
|
3
|
-
import { useTriggerMenu } from "./use-trigger-menu.js";
|
|
4
4
|
import { useEffect, useEffectEvent } from "react";
|
|
5
5
|
//#region src/hooks/use-textarea-trigger-menu.ts
|
|
6
6
|
function replaceRange(element, start, end, text) {
|
|
@@ -36,6 +36,7 @@ function useTextareaTriggerMenu(ref, options) {
|
|
|
36
36
|
controller.report(match, match === null ? null : caretRectInTextarea(element, match.start));
|
|
37
37
|
});
|
|
38
38
|
const handleKeyDown = useEffectEvent((event) => {
|
|
39
|
+
if (isComposingKey(event)) return;
|
|
39
40
|
if (controller.open && controller.handleKeyDown(event.key)) event.preventDefault();
|
|
40
41
|
});
|
|
41
42
|
const closeAfterBlur = useEffectEvent(() => {
|
|
@@ -27,6 +27,16 @@ export type UseTriggerMenuOptions<Item extends TriggerMenuItemData> = {
|
|
|
27
27
|
triggers: readonly TriggerConfig<Item>[];
|
|
28
28
|
onCommit: (item: Item, trigger: TriggerConfig<Item>, match: TriggerMatch) => void;
|
|
29
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Popup attributes for the element that keeps focus (textarea or editor) while the menu is up. It stays a
|
|
32
|
+
* multiline textbox (a <textarea> can't take role="combobox"), so open state is conveyed by `aria-controls`.
|
|
33
|
+
*/
|
|
34
|
+
export type TriggerMenuInputAria = {
|
|
35
|
+
"aria-autocomplete": "list";
|
|
36
|
+
"aria-haspopup": "listbox";
|
|
37
|
+
"aria-controls"?: string;
|
|
38
|
+
"aria-activedescendant"?: string;
|
|
39
|
+
};
|
|
30
40
|
export type TriggerMenuController<Item extends TriggerMenuItemData> = {
|
|
31
41
|
open: boolean;
|
|
32
42
|
items: readonly Item[];
|
|
@@ -34,6 +44,11 @@ export type TriggerMenuController<Item extends TriggerMenuItemData> = {
|
|
|
34
44
|
anchorRect: DOMRect | null;
|
|
35
45
|
activeChar: string | null;
|
|
36
46
|
query: string;
|
|
47
|
+
/** Id for `TriggerMenuList`; the input's `aria-controls` points at it. */
|
|
48
|
+
listId: string;
|
|
49
|
+
/** Id for the option at `index`; the input's `aria-activedescendant` points at the active one. */
|
|
50
|
+
optionId: (index: number) => string;
|
|
51
|
+
inputAria: TriggerMenuInputAria;
|
|
37
52
|
/** Binding → engine: publish current trigger match (or null) and caret rect to anchor to. */
|
|
38
53
|
report: (match: TriggerMatch | null, anchorRect: DOMRect | null) => void;
|
|
39
54
|
/** Binding → engine: route keydown while open. Returns true when engine consumed key. */
|
|
@@ -44,5 +59,44 @@ export type TriggerMenuController<Item extends TriggerMenuItemData> = {
|
|
|
44
59
|
close: () => void;
|
|
45
60
|
setOpen: (open: boolean) => void;
|
|
46
61
|
};
|
|
62
|
+
type DismissedMatch = {
|
|
63
|
+
char: string;
|
|
64
|
+
start: number;
|
|
65
|
+
query: string;
|
|
66
|
+
};
|
|
67
|
+
export type TriggerMenuState = {
|
|
68
|
+
open: boolean;
|
|
69
|
+
char: string | null;
|
|
70
|
+
query: string;
|
|
71
|
+
anchorRect: DOMRect | null;
|
|
72
|
+
activeIndex: number;
|
|
73
|
+
dismissed: DismissedMatch | null;
|
|
74
|
+
};
|
|
75
|
+
export type TriggerMenuAction = {
|
|
76
|
+
type: "report";
|
|
77
|
+
match: TriggerMatch | null;
|
|
78
|
+
anchorRect: DOMRect | null;
|
|
79
|
+
} | {
|
|
80
|
+
type: "close";
|
|
81
|
+
dismissed: DismissedMatch | null;
|
|
82
|
+
} | {
|
|
83
|
+
type: "move";
|
|
84
|
+
delta: number;
|
|
85
|
+
count: number;
|
|
86
|
+
} | {
|
|
87
|
+
type: "activate";
|
|
88
|
+
index: number;
|
|
89
|
+
};
|
|
90
|
+
export declare const CLOSED_TRIGGER_MENU: TriggerMenuState;
|
|
91
|
+
/** A dismissed token stays closed until its query changes, so keyup/click re-detection after Escape can't reopen it. */
|
|
92
|
+
export declare function triggerMenuReducer(state: TriggerMenuState, action: TriggerMenuAction): TriggerMenuState;
|
|
93
|
+
/** Keys an IME is still composing must never reach the menu or the composer's submit. */
|
|
94
|
+
export declare function isComposingKey(event: {
|
|
95
|
+
isComposing: boolean;
|
|
96
|
+
keyCode: number;
|
|
97
|
+
}): boolean;
|
|
98
|
+
export type TriggerMenuKeyIntent = "next" | "previous" | "commit" | "dismiss" | "pass";
|
|
99
|
+
/** What a key means to an open menu; an empty list passes Enter/Tab through so newline, submit and Tab-out still work. */
|
|
100
|
+
export declare function triggerMenuKeyIntent(key: string, open: boolean, itemCount: number): TriggerMenuKeyIntent;
|
|
47
101
|
export declare function useTriggerMenu<Item extends TriggerMenuItemData>({ triggers, onCommit }: UseTriggerMenuOptions<Item>): TriggerMenuController<Item>;
|
|
48
102
|
//#endregion
|
|
@@ -1,12 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useId, useReducer, useRef } from "react";
|
|
2
2
|
//#region src/hooks/use-trigger-menu.ts
|
|
3
|
-
const
|
|
3
|
+
const CLOSED_TRIGGER_MENU = {
|
|
4
4
|
open: false,
|
|
5
5
|
char: null,
|
|
6
6
|
query: "",
|
|
7
7
|
anchorRect: null,
|
|
8
|
-
activeIndex: 0
|
|
8
|
+
activeIndex: 0,
|
|
9
|
+
dismissed: null
|
|
9
10
|
};
|
|
11
|
+
/** A dismissed token stays closed until its query changes, so keyup/click re-detection after Escape can't reopen it. */
|
|
12
|
+
function triggerMenuReducer(state, action) {
|
|
13
|
+
switch (action.type) {
|
|
14
|
+
case "report": {
|
|
15
|
+
const { match, anchorRect } = action;
|
|
16
|
+
if (match === null) return { ...CLOSED_TRIGGER_MENU };
|
|
17
|
+
const { dismissed } = state;
|
|
18
|
+
if (dismissed !== null && dismissed.char === match.char && dismissed.start === match.start && dismissed.query === match.query) return {
|
|
19
|
+
...CLOSED_TRIGGER_MENU,
|
|
20
|
+
dismissed
|
|
21
|
+
};
|
|
22
|
+
const activeIndex = state.open && state.char === match.char && state.query === match.query ? state.activeIndex : 0;
|
|
23
|
+
return {
|
|
24
|
+
open: true,
|
|
25
|
+
char: match.char,
|
|
26
|
+
query: match.query,
|
|
27
|
+
anchorRect,
|
|
28
|
+
activeIndex,
|
|
29
|
+
dismissed: null
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
case "close": return {
|
|
33
|
+
...CLOSED_TRIGGER_MENU,
|
|
34
|
+
dismissed: action.dismissed
|
|
35
|
+
};
|
|
36
|
+
case "move": return {
|
|
37
|
+
...state,
|
|
38
|
+
activeIndex: action.count === 0 ? 0 : (state.activeIndex + action.delta + action.count) % action.count
|
|
39
|
+
};
|
|
40
|
+
case "activate": return {
|
|
41
|
+
...state,
|
|
42
|
+
activeIndex: action.index
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
10
46
|
function matchesQuery(item, query) {
|
|
11
47
|
if (query === "") return true;
|
|
12
48
|
const needle = query.toLowerCase();
|
|
@@ -18,14 +54,45 @@ function resolveItems(trigger, query) {
|
|
|
18
54
|
const filter = trigger.filter ?? matchesQuery;
|
|
19
55
|
return trigger.items.filter((item) => filter(item, query));
|
|
20
56
|
}
|
|
57
|
+
/** Keys an IME is still composing must never reach the menu or the composer's submit. */
|
|
58
|
+
function isComposingKey(event) {
|
|
59
|
+
return event.isComposing || event.keyCode === 229;
|
|
60
|
+
}
|
|
61
|
+
/** What a key means to an open menu; an empty list passes Enter/Tab through so newline, submit and Tab-out still work. */
|
|
62
|
+
function triggerMenuKeyIntent(key, open, itemCount) {
|
|
63
|
+
if (!open) return "pass";
|
|
64
|
+
if (key === "ArrowDown") return "next";
|
|
65
|
+
if (key === "ArrowUp") return "previous";
|
|
66
|
+
if (key === "Escape") return "dismiss";
|
|
67
|
+
if ((key === "Enter" || key === "Tab") && itemCount > 0) return "commit";
|
|
68
|
+
return "pass";
|
|
69
|
+
}
|
|
21
70
|
function useTriggerMenu({ triggers, onCommit }) {
|
|
22
|
-
const [state,
|
|
71
|
+
const [state, dispatch] = useReducer(triggerMenuReducer, CLOSED_TRIGGER_MENU);
|
|
23
72
|
const lastMatch = useRef(null);
|
|
73
|
+
const listId = useId();
|
|
24
74
|
const activeTrigger = state.char === null ? null : triggers.find((trigger) => trigger.char === state.char) ?? null;
|
|
25
75
|
const items = activeTrigger === null ? [] : resolveItems(activeTrigger, state.query);
|
|
76
|
+
const optionId = (index) => `${listId}-option-${index}`;
|
|
77
|
+
const hasActiveItem = state.open && state.activeIndex < items.length;
|
|
78
|
+
function dismiss() {
|
|
79
|
+
const match = lastMatch.current;
|
|
80
|
+
lastMatch.current = null;
|
|
81
|
+
dispatch({
|
|
82
|
+
type: "close",
|
|
83
|
+
dismissed: match === null ? null : {
|
|
84
|
+
char: match.char,
|
|
85
|
+
start: match.start,
|
|
86
|
+
query: match.query
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
26
90
|
function close() {
|
|
27
91
|
lastMatch.current = null;
|
|
28
|
-
|
|
92
|
+
dispatch({
|
|
93
|
+
type: "close",
|
|
94
|
+
dismissed: null
|
|
95
|
+
});
|
|
29
96
|
}
|
|
30
97
|
function select(item) {
|
|
31
98
|
const match = lastMatch.current;
|
|
@@ -33,55 +100,35 @@ function useTriggerMenu({ triggers, onCommit }) {
|
|
|
33
100
|
close();
|
|
34
101
|
}
|
|
35
102
|
function report(match, anchorRect) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
open: true,
|
|
43
|
-
char: match.char,
|
|
44
|
-
query: match.query,
|
|
45
|
-
anchorRect,
|
|
46
|
-
activeIndex
|
|
47
|
-
};
|
|
103
|
+
const known = match !== null && triggers.some((trigger) => trigger.char === match.char);
|
|
104
|
+
lastMatch.current = known ? match : null;
|
|
105
|
+
dispatch({
|
|
106
|
+
type: "report",
|
|
107
|
+
match: known ? match : null,
|
|
108
|
+
anchorRect
|
|
48
109
|
});
|
|
49
110
|
}
|
|
50
111
|
function handleKeyDown(key) {
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
if (key === "ArrowUp") {
|
|
60
|
-
setState((current) => ({
|
|
61
|
-
...current,
|
|
62
|
-
activeIndex: items.length === 0 ? 0 : (current.activeIndex - 1 + items.length) % items.length
|
|
63
|
-
}));
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (key === "Enter" || key === "Tab") {
|
|
112
|
+
const intent = triggerMenuKeyIntent(key, state.open, items.length);
|
|
113
|
+
if (intent === "next" || intent === "previous") dispatch({
|
|
114
|
+
type: "move",
|
|
115
|
+
delta: intent === "next" ? 1 : -1,
|
|
116
|
+
count: items.length
|
|
117
|
+
});
|
|
118
|
+
else if (intent === "commit") {
|
|
67
119
|
const item = items[state.activeIndex];
|
|
68
120
|
if (item && !item.disabled) select(item);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (key === "Escape") {
|
|
72
|
-
close();
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
return false;
|
|
121
|
+
} else if (intent === "dismiss") dismiss();
|
|
122
|
+
return intent !== "pass";
|
|
76
123
|
}
|
|
77
124
|
function setOpen(open) {
|
|
78
|
-
if (!open)
|
|
125
|
+
if (!open) dismiss();
|
|
79
126
|
}
|
|
80
|
-
function setActiveIndex(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
})
|
|
127
|
+
function setActiveIndex(index) {
|
|
128
|
+
dispatch({
|
|
129
|
+
type: "activate",
|
|
130
|
+
index
|
|
131
|
+
});
|
|
85
132
|
}
|
|
86
133
|
return {
|
|
87
134
|
open: state.open,
|
|
@@ -90,6 +137,14 @@ function useTriggerMenu({ triggers, onCommit }) {
|
|
|
90
137
|
anchorRect: state.anchorRect,
|
|
91
138
|
activeChar: state.char,
|
|
92
139
|
query: state.query,
|
|
140
|
+
listId,
|
|
141
|
+
optionId,
|
|
142
|
+
inputAria: {
|
|
143
|
+
"aria-autocomplete": "list",
|
|
144
|
+
"aria-haspopup": "listbox",
|
|
145
|
+
"aria-controls": state.open ? listId : void 0,
|
|
146
|
+
"aria-activedescendant": hasActiveItem ? optionId(state.activeIndex) : void 0
|
|
147
|
+
},
|
|
93
148
|
report,
|
|
94
149
|
handleKeyDown,
|
|
95
150
|
setActiveIndex,
|
|
@@ -99,4 +154,4 @@ function useTriggerMenu({ triggers, onCommit }) {
|
|
|
99
154
|
};
|
|
100
155
|
}
|
|
101
156
|
//#endregion
|
|
102
|
-
export { useTriggerMenu };
|
|
157
|
+
export { CLOSED_TRIGGER_MENU, isComposingKey, triggerMenuKeyIntent, triggerMenuReducer, useTriggerMenu };
|
|
@@ -6,6 +6,7 @@ export type UserAskProps = Omit<ComponentProps<"section">, "style"> & {
|
|
|
6
6
|
children?: ReactNode;
|
|
7
7
|
onComplete?: (answers: UserAskAnswers) => void;
|
|
8
8
|
onDismiss?: () => void;
|
|
9
|
+
questionStatusLabel?: (current: number, total: number, title: string) => string;
|
|
9
10
|
style?: CSSProperties & UserAskKnobStyle;
|
|
10
11
|
};
|
|
11
12
|
export type UserAskQuestionEntry = {
|
|
@@ -36,6 +37,7 @@ export declare function useUserAsk({ onComplete, onDismiss }: Pick<UserAskProps,
|
|
|
36
37
|
allowsMultiple: (questionId: string) => boolean;
|
|
37
38
|
selectionFor: (questionId: string) => string;
|
|
38
39
|
isSelected: (questionId: string, optionKey: string) => boolean;
|
|
40
|
+
isTabStop: (questionId: string, optionKey: string) => boolean;
|
|
39
41
|
select: (questionId: string, optionKey: string) => void;
|
|
40
42
|
freeformTextFor: (questionId: string) => string;
|
|
41
43
|
setFreeformText: (questionId: string, text: string) => void;
|
|
@@ -8,6 +8,12 @@ function upsert(entries, entry) {
|
|
|
8
8
|
next[index] = entry;
|
|
9
9
|
return next;
|
|
10
10
|
}
|
|
11
|
+
const arrowDeltas = {
|
|
12
|
+
ArrowDown: 1,
|
|
13
|
+
ArrowRight: 1,
|
|
14
|
+
ArrowUp: -1,
|
|
15
|
+
ArrowLeft: -1
|
|
16
|
+
};
|
|
11
17
|
function useUserAsk({ onComplete, onDismiss }) {
|
|
12
18
|
const [questions, setQuestions] = useState([]);
|
|
13
19
|
const [optionsByQuestion, setOptionsByQuestion] = useState({});
|
|
@@ -114,21 +120,11 @@ function useUserAsk({ onComplete, onDismiss }) {
|
|
|
114
120
|
function dismiss() {
|
|
115
121
|
onDismiss?.();
|
|
116
122
|
}
|
|
117
|
-
function
|
|
118
|
-
if (
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
const currentIndex = options.findIndex((option) => option.key === currentKey);
|
|
123
|
-
let start = currentIndex;
|
|
124
|
-
if (currentIndex === -1) start = delta > 0 ? -1 : 0;
|
|
125
|
-
for (let step = 1; step <= options.length; step += 1) {
|
|
126
|
-
const candidate = options[(start + delta * step + options.length * step) % options.length];
|
|
127
|
-
if (candidate && !candidate.disabled) {
|
|
128
|
-
select(activeQuestion.id, candidate.key);
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
123
|
+
function isTabStop(questionId, optionKey) {
|
|
124
|
+
if (allowsMultiple(questionId)) return true;
|
|
125
|
+
const selectedKey = selectionFor(questionId);
|
|
126
|
+
if (selectedKey !== void 0) return selectedKey === optionKey;
|
|
127
|
+
return optionsFor(questionId).find((option) => !option.disabled)?.key === optionKey;
|
|
132
128
|
}
|
|
133
129
|
function selectDigit(digit) {
|
|
134
130
|
if (!activeQuestion) return;
|
|
@@ -137,39 +133,28 @@ function useUserAsk({ onComplete, onDismiss }) {
|
|
|
137
133
|
}
|
|
138
134
|
function moveActiveOption(event, delta) {
|
|
139
135
|
if (!activeQuestion) return;
|
|
140
|
-
if (!allowsMultiple(activeQuestion.id)) {
|
|
141
|
-
moveSelection(delta);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
136
|
const rows = [...event.currentTarget.querySelector("[data-slot=\"question\"][data-active]")?.querySelectorAll("[data-slot=\"option\"]:not([disabled])") ?? []];
|
|
145
137
|
if (rows.length === 0) return;
|
|
146
138
|
const focused = rows.findIndex((candidate) => candidate.contains(document.activeElement));
|
|
147
139
|
let start = focused;
|
|
148
140
|
if (focused === -1) start = delta > 0 ? -1 : 0;
|
|
149
141
|
const row = rows[(start + delta + rows.length) % rows.length];
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
142
|
+
const target = row?.matches("button, input") ? row : row?.querySelector("input, button");
|
|
143
|
+
target?.focus();
|
|
144
|
+
if (!allowsMultiple(activeQuestion.id) && target?.matches("button")) target.click();
|
|
145
|
+
}
|
|
146
|
+
function handleEnter(event) {
|
|
147
|
+
if (event.nativeEvent.isComposing || event.keyCode === 229) return;
|
|
148
|
+
if (event.target instanceof Element && event.target.closest("button:not([role=\"radio\"]):not([role=\"checkbox\"]), a[href]")) return;
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
advance();
|
|
151
|
+
}
|
|
152
|
+
function handleOptionKey(event) {
|
|
153
|
+
if (event.target instanceof Element && event.target.closest("input, textarea, [contenteditable]")) return;
|
|
154
|
+
const delta = arrowDeltas[event.key];
|
|
155
|
+
if (delta !== void 0) {
|
|
160
156
|
event.preventDefault();
|
|
161
|
-
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (event.target instanceof HTMLElement && event.target.closest("input, textarea, [contenteditable]")) return;
|
|
165
|
-
if (event.key === "ArrowDown") {
|
|
166
|
-
event.preventDefault();
|
|
167
|
-
moveActiveOption(event, 1);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (event.key === "ArrowUp") {
|
|
171
|
-
event.preventDefault();
|
|
172
|
-
moveActiveOption(event, -1);
|
|
157
|
+
moveActiveOption(event, delta);
|
|
173
158
|
return;
|
|
174
159
|
}
|
|
175
160
|
if (/^[1-9]$/.test(event.key)) {
|
|
@@ -177,6 +162,14 @@ function useUserAsk({ onComplete, onDismiss }) {
|
|
|
177
162
|
selectDigit(Number(event.key));
|
|
178
163
|
}
|
|
179
164
|
}
|
|
165
|
+
function handleKeyDown(event) {
|
|
166
|
+
if (event.defaultPrevented) return;
|
|
167
|
+
if (event.key === "Escape") {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
dismiss();
|
|
170
|
+
} else if (event.key === "Enter") handleEnter(event);
|
|
171
|
+
else handleOptionKey(event);
|
|
172
|
+
}
|
|
180
173
|
return {
|
|
181
174
|
questions,
|
|
182
175
|
activeIndex,
|
|
@@ -191,6 +184,7 @@ function useUserAsk({ onComplete, onDismiss }) {
|
|
|
191
184
|
allowsMultiple,
|
|
192
185
|
selectionFor,
|
|
193
186
|
isSelected,
|
|
187
|
+
isTabStop,
|
|
194
188
|
select,
|
|
195
189
|
freeformTextFor,
|
|
196
190
|
setFreeformText,
|
|
@@ -5,13 +5,17 @@ export type InlineAttachmentState = "ready" | "pending" | "error";
|
|
|
5
5
|
type InlineAttachmentStyleProps<Props, Style> = Omit<Props, "style"> & {
|
|
6
6
|
style?: CSSProperties & Style;
|
|
7
7
|
};
|
|
8
|
+
type AttachmentLabel = (name: string) => string;
|
|
8
9
|
export type InlineAttachmentProps = InlineAttachmentStyleProps<ComponentProps<"button">, InlineAttachmentKnobStyle> & {
|
|
9
10
|
name: string;
|
|
10
11
|
state?: InlineAttachmentState;
|
|
11
12
|
/** Width-to-height ratio of the reserved box — generated media knows its ratio before its pixels, so arrival never reflows the turn. */
|
|
12
13
|
aspect?: number;
|
|
14
|
+
openLabel?: AttachmentLabel;
|
|
15
|
+
pendingLabel?: AttachmentLabel;
|
|
16
|
+
errorLabel?: AttachmentLabel;
|
|
13
17
|
};
|
|
14
|
-
export declare function InlineAttachment({ name, state, aspect, disabled, className, children, style, "aria-label": ariaLabel, ...props }: InlineAttachmentProps): import("react").JSX.Element;
|
|
18
|
+
export declare function InlineAttachment({ name, state, aspect, disabled, openLabel, pendingLabel, errorLabel, onClick, className, children, style, "aria-label": ariaLabel, ...props }: InlineAttachmentProps): import("react").JSX.Element;
|
|
15
19
|
export type InlineAttachmentMediaProps = ComponentProps<"div"> & {
|
|
16
20
|
src?: string;
|
|
17
21
|
alt?: string;
|
|
@@ -26,7 +30,7 @@ export type InlineAttachmentTitleProps = ComponentProps<"div"> & {
|
|
|
26
30
|
};
|
|
27
31
|
export declare function InlineAttachmentTitle({ children, className, ...props }: InlineAttachmentTitleProps): import("react").JSX.Element;
|
|
28
32
|
export type InlineAttachmentDescriptionProps = InlineAttachmentStyleProps<ComponentProps<"div">, InlineAttachmentKnobStyle>;
|
|
29
|
-
export declare function InlineAttachmentDescription({ className, ...props }: InlineAttachmentDescriptionProps): import("react").JSX.Element;
|
|
33
|
+
export declare function InlineAttachmentDescription({ className, children, ...props }: InlineAttachmentDescriptionProps): import("react").JSX.Element;
|
|
30
34
|
export type InlineAttachmentActionsProps = ComponentProps<"div"> & {
|
|
31
35
|
style?: CSSProperties & InlineAttachmentKnobStyle;
|
|
32
36
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "./lib/cn.js";
|
|
3
|
-
import { createContext, useContext } from "react";
|
|
3
|
+
import { createContext, useContext, useId } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/inline-attachment.tsx
|
|
6
6
|
const InlineAttachmentContext = createContext(null);
|
|
@@ -9,32 +9,47 @@ function useInlineAttachmentContext() {
|
|
|
9
9
|
if (!context) throw new Error("InlineAttachment compound components must be rendered inside <InlineAttachment>.");
|
|
10
10
|
return context;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
function InlineAttachment({ name, state = "ready", aspect = 1.26, disabled, className, children, style, "aria-label": ariaLabel, ...props }) {
|
|
12
|
+
const defaultOpenLabel = (name) => `Open attachment: ${name}`;
|
|
13
|
+
const defaultPendingLabel = (name) => `Generating ${name}`;
|
|
14
|
+
const defaultErrorLabel = (name) => `${name} couldn't load. Try again.`;
|
|
15
|
+
function InlineAttachment({ name, state = "ready", aspect = 1.26, disabled, openLabel = defaultOpenLabel, pendingLabel = defaultPendingLabel, errorLabel = defaultErrorLabel, onClick, className, children, style, "aria-label": ariaLabel, ...props }) {
|
|
18
16
|
const attachmentStyle = {
|
|
19
17
|
aspectRatio: aspect,
|
|
20
18
|
...style
|
|
21
19
|
};
|
|
20
|
+
const descriptionId = useId();
|
|
21
|
+
const pending = state === "pending";
|
|
22
|
+
const defaultLabel = {
|
|
23
|
+
ready: openLabel,
|
|
24
|
+
pending: pendingLabel,
|
|
25
|
+
error: errorLabel
|
|
26
|
+
}[state](name);
|
|
22
27
|
return /* @__PURE__ */ jsx(InlineAttachmentContext.Provider, {
|
|
23
28
|
value: {
|
|
24
29
|
name,
|
|
25
|
-
state
|
|
30
|
+
state,
|
|
31
|
+
descriptionId
|
|
26
32
|
},
|
|
27
33
|
children: /* @__PURE__ */ jsx("button", {
|
|
28
34
|
type: "button",
|
|
29
|
-
"aria-label": ariaLabel ?? defaultLabel
|
|
30
|
-
"aria-
|
|
31
|
-
|
|
35
|
+
"aria-label": ariaLabel ?? defaultLabel,
|
|
36
|
+
"aria-describedby": descriptionId,
|
|
37
|
+
"aria-busy": pending || void 0,
|
|
38
|
+
"aria-disabled": pending || void 0,
|
|
39
|
+
disabled,
|
|
40
|
+
onClick: (event) => {
|
|
41
|
+
if (pending) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
onClick?.(event);
|
|
46
|
+
},
|
|
32
47
|
"data-control-ui": "inline-attachment",
|
|
33
48
|
"data-control-family": "inline-attachment",
|
|
34
49
|
"data-slot": "root",
|
|
35
50
|
"data-surface": "panel",
|
|
36
51
|
"data-state": state,
|
|
37
|
-
className: cn("group relative w-full max-w-72 cursor-pointer overflow-hidden disabled:cursor-default", className),
|
|
52
|
+
className: cn("group relative w-full max-w-72 cursor-pointer overflow-hidden disabled:cursor-default aria-disabled:cursor-default", className),
|
|
38
53
|
style: attachmentStyle,
|
|
39
54
|
...props,
|
|
40
55
|
children
|
|
@@ -146,22 +161,28 @@ function InlineAttachmentContent({ className, ...props }) {
|
|
|
146
161
|
}
|
|
147
162
|
function InlineAttachmentTitle({ children, className, ...props }) {
|
|
148
163
|
const { name } = useInlineAttachmentContext();
|
|
164
|
+
const label = children ?? name;
|
|
149
165
|
return /* @__PURE__ */ jsx("div", {
|
|
150
166
|
"data-control-ui": "inline-attachment",
|
|
151
167
|
"data-control-family": "inline-attachment",
|
|
152
168
|
"data-slot": "title",
|
|
169
|
+
title: typeof label === "string" ? label : void 0,
|
|
153
170
|
className: cn("truncate", className),
|
|
154
171
|
...props,
|
|
155
|
-
children:
|
|
172
|
+
children: label
|
|
156
173
|
});
|
|
157
174
|
}
|
|
158
|
-
function InlineAttachmentDescription({ className, ...props }) {
|
|
175
|
+
function InlineAttachmentDescription({ className, children, ...props }) {
|
|
176
|
+
const { descriptionId } = useInlineAttachmentContext();
|
|
159
177
|
return /* @__PURE__ */ jsx("div", {
|
|
178
|
+
id: descriptionId,
|
|
160
179
|
"data-control-ui": "inline-attachment",
|
|
161
180
|
"data-control-family": "inline-attachment",
|
|
162
181
|
"data-slot": "description",
|
|
182
|
+
title: typeof children === "string" ? children : void 0,
|
|
163
183
|
className: cn("truncate", className),
|
|
164
|
-
...props
|
|
184
|
+
...props,
|
|
185
|
+
children
|
|
165
186
|
});
|
|
166
187
|
}
|
|
167
188
|
function InlineAttachmentActions({ className, ...props }) {
|
|
@@ -13,26 +13,33 @@ export type SourceReference = {
|
|
|
13
13
|
type InlineCitationStyleProps<Props, Style> = Omit<Props, "style"> & {
|
|
14
14
|
style?: CSSProperties & Style;
|
|
15
15
|
};
|
|
16
|
+
export type CitationLabelTemplates = {
|
|
17
|
+
emptyLabel?: string;
|
|
18
|
+
viewSourcesLabel?: (count: number) => string;
|
|
19
|
+
positionLabel?: (position: number, count: number) => string;
|
|
20
|
+
};
|
|
21
|
+
export declare function citationLabel(sources: readonly SourceReference[], emptyLabel?: string): string;
|
|
16
22
|
type PopoverRootProps = ComponentProps<typeof Popover>;
|
|
17
23
|
export type InlineCitationProps = ComponentProps<"span"> & {
|
|
18
24
|
sources: readonly SourceReference[];
|
|
19
25
|
open?: PopoverRootProps["open"];
|
|
20
26
|
defaultOpen?: PopoverRootProps["defaultOpen"];
|
|
21
27
|
onOpenChange?: PopoverRootProps["onOpenChange"];
|
|
28
|
+
positionLabel?: CitationLabelTemplates["positionLabel"];
|
|
22
29
|
} & {
|
|
23
30
|
style?: CSSProperties & InlineCitationKnobStyle;
|
|
24
31
|
};
|
|
25
|
-
export declare function InlineCitation({ sources, open, defaultOpen, onOpenChange, className, children, ...props }: InlineCitationProps): import("react").JSX.Element;
|
|
26
|
-
export type InlineCitationTriggerProps = InlineCitationStyleProps<ComponentProps<typeof PopoverTrigger>, InlineCitationKnobStyle>;
|
|
27
|
-
export declare function InlineCitationTrigger({ "aria-label": ariaLabel, className, children, disabled, render, ...props }: InlineCitationTriggerProps): import("react").JSX.Element;
|
|
32
|
+
export declare function InlineCitation({ sources, open, defaultOpen, onOpenChange, positionLabel, className, children, ...props }: InlineCitationProps): import("react").JSX.Element;
|
|
33
|
+
export type InlineCitationTriggerProps = InlineCitationStyleProps<ComponentProps<typeof PopoverTrigger>, InlineCitationKnobStyle> & Pick<CitationLabelTemplates, "emptyLabel" | "viewSourcesLabel">;
|
|
34
|
+
export declare function InlineCitationTrigger({ "aria-label": ariaLabel, emptyLabel, viewSourcesLabel, className, children, disabled, render, ...props }: InlineCitationTriggerProps): import("react").JSX.Element;
|
|
28
35
|
export type InlineCitationFaviconsProps = InlineCitationStyleProps<ComponentProps<"span">, InlineCitationKnobStyle> & {
|
|
29
36
|
limit?: number;
|
|
30
37
|
};
|
|
31
38
|
export declare function InlineCitationFavicons({ limit, className, ...props }: InlineCitationFaviconsProps): import("react").JSX.Element;
|
|
32
|
-
export type InlineCitationLabelProps = ComponentProps<"span"> & {
|
|
39
|
+
export type InlineCitationLabelProps = ComponentProps<"span"> & Pick<CitationLabelTemplates, "emptyLabel"> & {
|
|
33
40
|
style?: CSSProperties & InlineCitationKnobStyle;
|
|
34
41
|
};
|
|
35
|
-
export declare function InlineCitationLabel({ className, children, ...props }: InlineCitationLabelProps): import("react").JSX.Element;
|
|
42
|
+
export declare function InlineCitationLabel({ emptyLabel, className, children, ...props }: InlineCitationLabelProps): import("react").JSX.Element;
|
|
36
43
|
export type InlineCitationContentProps = ComponentProps<typeof PopoverContent>;
|
|
37
44
|
export declare function InlineCitationContent({ className, children, align, padding, ...props }: InlineCitationContentProps): import("react").JSX.Element;
|
|
38
45
|
export type InlineCitationNavigationProps = InlineCitationStyleProps<ComponentProps<"div">, InlineCitationKnobStyle>;
|