@ctrl-ui/react 0.8.6 → 0.8.8
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 +54 -57
- package/dist/blocks/design-canvas-data.d.ts +32 -0
- package/dist/blocks/design-canvas-data.js +100 -0
- package/dist/blocks/design-canvas-inspector.d.ts +8 -0
- package/dist/blocks/design-canvas-inspector.js +238 -0
- package/dist/blocks/design-canvas.d.ts +21 -0
- package/dist/blocks/design-canvas.js +452 -0
- 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 +12 -3
- package/dist/chat-composer-attachment.js +61 -19
- package/dist/chat-composer-editor/extensions/mention.d.ts +5 -1
- package/dist/chat-composer-editor/extensions/mention.js +58 -27
- 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 +71 -28
- package/dist/chat-composer.d.ts +13 -32
- package/dist/chat-composer.js +54 -13
- package/dist/chat-layout.d.ts +19 -0
- package/dist/chat-layout.js +96 -32
- 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/context.d.ts +32 -0
- package/dist/filter-bar/context.js +11 -0
- package/dist/filter-bar/editor.d.ts +14 -0
- package/dist/filter-bar/editor.js +216 -0
- package/dist/filter-bar/model.d.ts +10 -0
- package/dist/filter-bar/model.js +57 -0
- package/dist/filter-bar/motion.d.ts +10 -0
- package/dist/filter-bar/motion.js +84 -0
- package/dist/filter-bar/parts.d.ts +19 -0
- package/dist/filter-bar/parts.js +244 -0
- package/dist/filter-bar/types.d.ts +54 -0
- package/dist/filter-bar/types.js +0 -0
- package/dist/filter-bar.d.ts +27 -0
- package/dist/filter-bar.js +310 -0
- package/dist/hooks/use-audio-recorder.js +12 -6
- package/dist/hooks/use-chat-composer.d.ts +21 -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-dropzone.d.ts +7 -4
- package/dist/hooks/use-dropzone.js +34 -3
- 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 +44 -29
- 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-layout-knobs.d.ts +1 -1
- package/dist/knob-contracts/chat-layout-knobs.js +2 -1
- 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/choice-knobs.d.ts +1 -1
- package/dist/knob-contracts/choice-knobs.js +1 -0
- 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/collapsible-knobs.d.ts +1 -1
- package/dist/knob-contracts/collapsible-knobs.js +1 -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 +4 -0
- package/dist/knob-contracts/filter-bar-knobs.js +15 -0
- package/dist/knob-contracts/infinite-canvas-knobs.d.ts +1 -1
- package/dist/knob-contracts/infinite-canvas-knobs.js +3 -0
- 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 +4 -1
- package/dist/knob-contracts/popup-knobs.d.ts +1 -1
- package/dist/knob-contracts/popup-knobs.js +28 -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 +4 -5
- 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 +13 -8
- package/dist/popup-parts.d.ts +8 -0
- package/dist/popup-parts.js +43 -0
- package/dist/scripts/contrast-eval.js +5 -4
- 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 +14 -8
- 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 +6 -8
- package/dist/styles/recipes/button-states.css +66 -0
- package/dist/styles/recipes/button.css +26 -85
- 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 +21 -16
- package/dist/styles/recipes/chat-layout.css +64 -2
- 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 +25 -21
- package/dist/styles/recipes/code-diff.css +51 -26
- package/dist/styles/recipes/code.css +44 -18
- package/dist/styles/recipes/collapsible.css +43 -1
- 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 +23 -4
- package/dist/styles/recipes/context.css +3 -3
- package/dist/styles/recipes/dockable-panel.css +18 -7
- 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 +89 -21
- package/dist/styles/recipes/field.css +83 -26
- package/dist/styles/recipes/filter-bar.css +161 -0
- package/dist/styles/recipes/gradient-editor.css +18 -7
- package/dist/styles/recipes/infinite-canvas.css +51 -4
- package/dist/styles/recipes/inline-attachment.css +9 -4
- 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 +36 -10
- package/dist/styles/recipes/pagination.css +5 -6
- package/dist/styles/recipes/phone-input.css +12 -8
- package/dist/styles/recipes/popup-controls.css +175 -26
- package/dist/styles/recipes/popup-drawer.css +35 -44
- package/dist/styles/recipes/popup-lists.css +139 -29
- package/dist/styles/recipes/popup-motion.css +4 -45
- package/dist/styles/recipes/popup-toast.css +55 -26
- package/dist/styles/recipes/popup.css +149 -153
- package/dist/styles/recipes/range.css +55 -19
- package/dist/styles/recipes/resizable.css +36 -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 +149 -34
- package/dist/styles/recipes/sidebar-parts.css +154 -0
- package/dist/styles/recipes/sidebar.css +187 -128
- package/dist/styles/recipes/source-badge.css +1 -1
- package/dist/styles/recipes/spinner.css +12 -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 +49 -41
- package/dist/styles/recipes/table.css +14 -10
- package/dist/styles/recipes/tabs.css +38 -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 +12 -8
- package/dist/styles/recipes/transcript-divider.css +2 -2
- 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 +287 -107
- 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 +7 -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-group.js +1 -1
- 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 +27 -28
- 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 -8
- package/dist/ui/combobox.d.ts +5 -23
- package/dist/ui/combobox.js +36 -16
- package/dist/ui/command.d.ts +8 -2
- package/dist/ui/command.js +39 -15
- 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 +81 -33
- package/dist/ui/drawer.d.ts +7 -4
- package/dist/ui/drawer.js +35 -22
- package/dist/ui/dropdown-menu.js +4 -3
- package/dist/ui/dropzone.d.ts +5 -3
- package/dist/ui/dropzone.js +78 -17
- 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/field.js +1 -1
- package/dist/ui/gradient-editor.d.ts +1 -1
- package/dist/ui/gradient-editor.js +37 -21
- package/dist/ui/infinite-canvas.d.ts +13 -1
- package/dist/ui/infinite-canvas.js +139 -20
- package/dist/ui/input-group.d.ts +2 -4
- package/dist/ui/input-group.js +13 -14
- package/dist/ui/input-otp.d.ts +1 -1
- package/dist/ui/input-otp.js +32 -15
- package/dist/ui/input.js +11 -2
- 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 +42 -9
- 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/number-field.d.ts +1 -1
- package/dist/ui/number-field.js +13 -2
- 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 +3 -0
- package/dist/ui/radio-group.js +11 -1
- package/dist/ui/resizable.d.ts +20 -2
- package/dist/ui/resizable.js +130 -8
- package/dist/ui/responsive-dialog.d.ts +1 -1
- package/dist/ui/responsive-dialog.js +9 -23
- package/dist/ui/rich-tooltip.d.ts +10 -4
- package/dist/ui/rich-tooltip.js +81 -33
- package/dist/ui/scroll-area.d.ts +4 -1
- package/dist/ui/scroll-area.js +44 -28
- package/dist/ui/select.d.ts +2 -1
- package/dist/ui/select.js +57 -32
- package/dist/ui/sidebar-menu.d.ts +5 -1
- package/dist/ui/sidebar-menu.js +31 -33
- 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 +46 -23
- 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 +5 -4
- package/dist/ui/table-of-contents.js +143 -52
- package/dist/ui/table.js +15 -9
- 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/toggle.d.ts +1 -1
- package/dist/ui/toggle.js +2 -1
- package/dist/ui/toolbar.d.ts +3 -2
- package/dist/ui/toolbar.js +4 -2
- package/dist/ui/tooltip.js +3 -20
- package/dist/ui/tree.js +120 -80
- package/dist/ui/trigger-menu.js +7 -2
- 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
package/dist/ui/dropzone.js
CHANGED
|
@@ -9,6 +9,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
import { CircleAlert, CloudUpload, FileIcon, LoaderCircle, Search, XIcon } from "lucide-react";
|
|
10
10
|
//#region src/ui/dropzone.tsx
|
|
11
11
|
const DropzoneContext = createContext(null);
|
|
12
|
+
const DropzoneFocusContext = createContext(null);
|
|
12
13
|
const fileRenderKeys = /* @__PURE__ */ new WeakMap();
|
|
13
14
|
let nextFileRenderKey = 0;
|
|
14
15
|
function getFileRenderKey(file) {
|
|
@@ -24,8 +25,48 @@ function useDropzoneContext() {
|
|
|
24
25
|
if (!context) throw new Error("Dropzone parts must be used inside Dropzone.");
|
|
25
26
|
return context;
|
|
26
27
|
}
|
|
27
|
-
function
|
|
28
|
+
function createFocusTargets() {
|
|
29
|
+
const triggers = /* @__PURE__ */ new Set();
|
|
30
|
+
const removes = /* @__PURE__ */ new Set();
|
|
31
|
+
const inDocumentOrder = (nodes) => [...nodes].filter((node) => !node.matches(":disabled")).sort((a, b) => a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
32
|
+
return {
|
|
33
|
+
register(kind, node) {
|
|
34
|
+
const nodes = kind === "trigger" ? triggers : removes;
|
|
35
|
+
nodes.add(node);
|
|
36
|
+
return () => {
|
|
37
|
+
nodes.delete(node);
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
focusAfterRemoval(control, all) {
|
|
41
|
+
const siblings = all ? [] : inDocumentOrder(removes);
|
|
42
|
+
const index = siblings.indexOf(control);
|
|
43
|
+
(siblings[index + 1] ?? siblings[index - 1] ?? inDocumentOrder(triggers)[0])?.focus();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function useFocusTargetRef(kind, ref) {
|
|
48
|
+
const focusTargets = useContext(DropzoneFocusContext);
|
|
49
|
+
return (node) => {
|
|
50
|
+
const unregister = focusTargets?.register(kind, node);
|
|
51
|
+
let release;
|
|
52
|
+
if (typeof ref === "function") {
|
|
53
|
+
const cleanup = ref(node);
|
|
54
|
+
release = typeof cleanup === "function" ? cleanup : () => ref(null);
|
|
55
|
+
} else if (ref) {
|
|
56
|
+
ref.current = node;
|
|
57
|
+
release = () => {
|
|
58
|
+
ref.current = null;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return () => {
|
|
62
|
+
unregister?.();
|
|
63
|
+
release?.();
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function Dropzone({ value, defaultValue, onValueChange, policy, disabled, drag, paste, getFilesFromEvent, onDrop, onError, className, children, ...props }) {
|
|
28
68
|
const [globalOverlayCount, setGlobalOverlayCount] = useState(0);
|
|
69
|
+
const [focusTargets] = useState(createFocusTargets);
|
|
29
70
|
const [registerGlobalOverlay] = useState(() => () => {
|
|
30
71
|
let registered = true;
|
|
31
72
|
setGlobalOverlayCount((count) => count + 1);
|
|
@@ -41,6 +82,8 @@ function Dropzone({ value, defaultValue, onValueChange, policy, disabled, getFil
|
|
|
41
82
|
onValueChange,
|
|
42
83
|
policy,
|
|
43
84
|
disabled,
|
|
85
|
+
drag,
|
|
86
|
+
paste,
|
|
44
87
|
getFilesFromEvent,
|
|
45
88
|
onDrop,
|
|
46
89
|
onError,
|
|
@@ -53,15 +96,18 @@ function Dropzone({ value, defaultValue, onValueChange, policy, disabled, getFil
|
|
|
53
96
|
const empty = dropzone.value.length === 0 && dropzone.fileRejections.length === 0;
|
|
54
97
|
return /* @__PURE__ */ jsx(DropzoneContext.Provider, {
|
|
55
98
|
value: context,
|
|
56
|
-
children: /* @__PURE__ */ jsx(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
99
|
+
children: /* @__PURE__ */ jsx(DropzoneFocusContext.Provider, {
|
|
100
|
+
value: focusTargets,
|
|
101
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
102
|
+
...props,
|
|
103
|
+
"data-control-ui": "dropzone",
|
|
104
|
+
"data-control-family": "dropzone",
|
|
105
|
+
"data-slot": "root",
|
|
106
|
+
"data-disabled": dropzone.disabled ? "true" : void 0,
|
|
107
|
+
"data-empty": empty ? "true" : void 0,
|
|
108
|
+
className: cn("min-w-0", className),
|
|
109
|
+
children
|
|
110
|
+
})
|
|
65
111
|
})
|
|
66
112
|
});
|
|
67
113
|
}
|
|
@@ -87,26 +133,32 @@ function DropzoneInput({ className, "aria-label": ariaLabel, "aria-labelledby":
|
|
|
87
133
|
});
|
|
88
134
|
return /* @__PURE__ */ jsx("input", {
|
|
89
135
|
...inputProps,
|
|
136
|
+
tabIndex: -1,
|
|
90
137
|
"data-control-ui": "dropzone",
|
|
91
138
|
"data-control-family": "dropzone",
|
|
92
139
|
"data-slot": "input",
|
|
93
140
|
className: cn("sr-only", className)
|
|
94
141
|
});
|
|
95
142
|
}
|
|
96
|
-
function DropzoneTrigger({ className, children, onClick, disabled, ...props }) {
|
|
143
|
+
function DropzoneTrigger({ className, children, onClick, disabled, ref, ...props }) {
|
|
97
144
|
const context = useDropzoneContext();
|
|
98
|
-
const
|
|
145
|
+
const triggerRef = useFocusTargetRef("trigger", ref);
|
|
146
|
+
const triggerDisabled = disabled || context.disabled;
|
|
147
|
+
const busy = context.isProcessing && !triggerDisabled;
|
|
99
148
|
return /* @__PURE__ */ jsx("button", {
|
|
100
149
|
...props,
|
|
150
|
+
ref: triggerRef,
|
|
101
151
|
type: "button",
|
|
102
152
|
disabled: triggerDisabled,
|
|
153
|
+
"aria-disabled": busy ? "true" : void 0,
|
|
103
154
|
"data-control-ui": "dropzone",
|
|
104
155
|
"data-control-family": "dropzone",
|
|
105
156
|
"data-slot": "trigger",
|
|
106
157
|
"data-state": context.visualState,
|
|
107
|
-
"data-disabled": triggerDisabled ? "true" : void 0,
|
|
108
|
-
className: cn("flex w-full cursor-pointer flex-col items-center justify-center disabled:cursor-not-allowed", className),
|
|
158
|
+
"data-disabled": triggerDisabled || busy ? "true" : void 0,
|
|
159
|
+
className: cn("flex w-full cursor-pointer flex-col items-center justify-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed", className),
|
|
109
160
|
onClick: (event) => {
|
|
161
|
+
if (busy) return;
|
|
110
162
|
onClick?.(event);
|
|
111
163
|
if (!event.defaultPrevented) context.open();
|
|
112
164
|
},
|
|
@@ -191,10 +243,13 @@ function DropzoneStatus({ className, children, role = "status", "aria-live": ari
|
|
|
191
243
|
children: children ? children(context) : getDropzoneStatusMessage(context)
|
|
192
244
|
});
|
|
193
245
|
}
|
|
194
|
-
function DropzoneRemove({ file, children, onClick, disabled, ...props }) {
|
|
246
|
+
function DropzoneRemove({ file, children, onClick, disabled, ref, ...props }) {
|
|
195
247
|
const context = useDropzoneContext();
|
|
248
|
+
const focusTargets = useContext(DropzoneFocusContext);
|
|
249
|
+
const removeRef = useFocusTargetRef("remove", ref);
|
|
196
250
|
return /* @__PURE__ */ jsx(Button, {
|
|
197
251
|
...props,
|
|
252
|
+
ref: removeRef,
|
|
198
253
|
type: "button",
|
|
199
254
|
variant: props.variant ?? "quiet",
|
|
200
255
|
size: props.size ?? "sm",
|
|
@@ -203,13 +258,16 @@ function DropzoneRemove({ file, children, onClick, disabled, ...props }) {
|
|
|
203
258
|
disabled: disabled || context.disabled || context.isProcessing,
|
|
204
259
|
onClick: (event) => {
|
|
205
260
|
onClick?.(event);
|
|
206
|
-
if (
|
|
261
|
+
if (event.defaultPrevented) return;
|
|
262
|
+
focusTargets?.focusAfterRemoval(event.currentTarget, false);
|
|
263
|
+
context.removeFile(file);
|
|
207
264
|
},
|
|
208
265
|
children: children ?? /* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" })
|
|
209
266
|
});
|
|
210
267
|
}
|
|
211
268
|
function DropzoneClear({ children, onClick, disabled, ...props }) {
|
|
212
269
|
const context = useDropzoneContext();
|
|
270
|
+
const focusTargets = useContext(DropzoneFocusContext);
|
|
213
271
|
const empty = context.value.length === 0 && context.fileRejections.length === 0;
|
|
214
272
|
return /* @__PURE__ */ jsx(Button, {
|
|
215
273
|
...props,
|
|
@@ -219,7 +277,9 @@ function DropzoneClear({ children, onClick, disabled, ...props }) {
|
|
|
219
277
|
disabled: disabled || context.disabled || context.isProcessing || empty,
|
|
220
278
|
onClick: (event) => {
|
|
221
279
|
onClick?.(event);
|
|
222
|
-
if (
|
|
280
|
+
if (event.defaultPrevented) return;
|
|
281
|
+
focusTargets?.focusAfterRemoval(event.currentTarget, true);
|
|
282
|
+
context.reset();
|
|
223
283
|
},
|
|
224
284
|
children: children ?? "Clear all"
|
|
225
285
|
});
|
|
@@ -232,6 +292,7 @@ function DropzoneFeedback({ state }) {
|
|
|
232
292
|
"data-control-ui": "dropzone",
|
|
233
293
|
"data-control-family": "dropzone",
|
|
234
294
|
"data-slot": "feedback-spinner",
|
|
295
|
+
"data-motion-essential": "",
|
|
235
296
|
"aria-hidden": "true"
|
|
236
297
|
});
|
|
237
298
|
message = "Checking files…";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EmojiPickerKnobStyle } from "../knob-contracts/emoji-picker-knobs.js";
|
|
2
|
+
import { CSSProperties, ComponentProps } from "react";
|
|
3
|
+
import { EmojiPicker as EmojiPicker$1 } from "frimousse";
|
|
4
|
+
//#region src/ui/emoji-picker.d.ts
|
|
5
|
+
type EmojiPickerStyle = {
|
|
6
|
+
style?: CSSProperties & EmojiPickerKnobStyle;
|
|
7
|
+
};
|
|
8
|
+
export type EmojiPickerProps = Omit<ComponentProps<typeof EmojiPicker$1.Root>, "style"> & EmojiPickerStyle;
|
|
9
|
+
export declare function EmojiPicker({ className, columns, ...props }: EmojiPickerProps): import("react").JSX.Element;
|
|
10
|
+
export type EmojiPickerSearchProps = Omit<ComponentProps<typeof EmojiPicker$1.Search>, "style"> & EmojiPickerStyle;
|
|
11
|
+
export declare function EmojiPickerSearch({ className, placeholder, "aria-label": ariaLabel, ...props }: EmojiPickerSearchProps): import("react").JSX.Element;
|
|
12
|
+
export type EmojiPickerContentProps = Omit<ComponentProps<typeof EmojiPicker$1.Viewport>, "style"> & EmojiPickerStyle;
|
|
13
|
+
export declare function EmojiPickerContent({ className, ...props }: EmojiPickerContentProps): import("react").JSX.Element;
|
|
14
|
+
export type EmojiPickerFooterProps = Omit<ComponentProps<"div">, "style" | "children"> & EmojiPickerStyle & {
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function EmojiPickerFooter({ className, placeholder, ...props }: EmojiPickerFooterProps): import("react").JSX.Element;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { Spinner } from "./spinner.js";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { SearchIcon } from "lucide-react";
|
|
6
|
+
import { EmojiPicker as EmojiPicker$1 } from "frimousse";
|
|
7
|
+
//#region src/ui/emoji-picker.tsx
|
|
8
|
+
function EmojiPicker({ className, columns = 9, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(EmojiPicker$1.Root, {
|
|
10
|
+
"data-control-ui": "emoji-picker",
|
|
11
|
+
"data-control-family": "emoji-picker",
|
|
12
|
+
"data-slot": "root",
|
|
13
|
+
columns,
|
|
14
|
+
className: cn("isolate flex h-72 w-fit flex-col", className),
|
|
15
|
+
...props
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function EmojiPickerSearch({ className, placeholder = "Search emoji…", "aria-label": ariaLabel = "Search emoji", ...props }) {
|
|
19
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
20
|
+
"data-control-ui": "emoji-picker",
|
|
21
|
+
"data-control-family": "emoji-picker",
|
|
22
|
+
"data-slot": "search",
|
|
23
|
+
className: "flex items-center",
|
|
24
|
+
children: [/* @__PURE__ */ jsx(SearchIcon, {
|
|
25
|
+
"aria-hidden": "true",
|
|
26
|
+
"data-control-ui": "emoji-picker",
|
|
27
|
+
"data-control-family": "emoji-picker",
|
|
28
|
+
"data-slot": "search-icon"
|
|
29
|
+
}), /* @__PURE__ */ jsx(EmojiPicker$1.Search, {
|
|
30
|
+
"data-control-ui": "emoji-picker",
|
|
31
|
+
"data-control-family": "emoji-picker",
|
|
32
|
+
"data-slot": "search-input",
|
|
33
|
+
placeholder,
|
|
34
|
+
"aria-label": ariaLabel,
|
|
35
|
+
className: cn("min-w-0 flex-1", className),
|
|
36
|
+
...props
|
|
37
|
+
})]
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function EmojiPickerRow({ children, className, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsx("div", {
|
|
42
|
+
"data-control-ui": "emoji-picker",
|
|
43
|
+
"data-control-family": "emoji-picker",
|
|
44
|
+
"data-slot": "row",
|
|
45
|
+
className: cn("scroll-my-1", className),
|
|
46
|
+
...props,
|
|
47
|
+
children
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function EmojiPickerEmoji({ emoji, className, ...props }) {
|
|
51
|
+
return /* @__PURE__ */ jsx("button", {
|
|
52
|
+
"data-control-ui": "emoji-picker",
|
|
53
|
+
"data-control-family": "emoji-picker",
|
|
54
|
+
"data-slot": "emoji",
|
|
55
|
+
"data-active": emoji.isActive ? "" : void 0,
|
|
56
|
+
className: cn("flex items-center justify-center", className),
|
|
57
|
+
...props,
|
|
58
|
+
children: emoji.emoji
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function EmojiPickerCategoryHeader({ category, className, ...props }) {
|
|
62
|
+
return /* @__PURE__ */ jsx("div", {
|
|
63
|
+
"data-control-ui": "emoji-picker",
|
|
64
|
+
"data-control-family": "emoji-picker",
|
|
65
|
+
"data-slot": "category-header",
|
|
66
|
+
className,
|
|
67
|
+
...props,
|
|
68
|
+
children: category.label
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function EmojiPickerContent({ className, ...props }) {
|
|
72
|
+
return /* @__PURE__ */ jsxs(EmojiPicker$1.Viewport, {
|
|
73
|
+
"data-control-ui": "emoji-picker",
|
|
74
|
+
"data-control-family": "emoji-picker",
|
|
75
|
+
"data-slot": "content",
|
|
76
|
+
className: cn("relative flex-1 outline-none", className),
|
|
77
|
+
...props,
|
|
78
|
+
children: [
|
|
79
|
+
/* @__PURE__ */ jsx(EmojiPicker$1.Loading, {
|
|
80
|
+
"data-control-ui": "emoji-picker",
|
|
81
|
+
"data-control-family": "emoji-picker",
|
|
82
|
+
"data-slot": "loading",
|
|
83
|
+
className: "absolute inset-0 flex items-center justify-center",
|
|
84
|
+
children: /* @__PURE__ */ jsx(Spinner, { label: "Loading emoji" })
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ jsx(EmojiPicker$1.Empty, {
|
|
87
|
+
"data-control-ui": "emoji-picker",
|
|
88
|
+
"data-control-family": "emoji-picker",
|
|
89
|
+
"data-slot": "empty",
|
|
90
|
+
className: "absolute inset-0 flex items-center justify-center",
|
|
91
|
+
children: "No emoji found."
|
|
92
|
+
}),
|
|
93
|
+
/* @__PURE__ */ jsx(EmojiPicker$1.List, {
|
|
94
|
+
"data-control-ui": "emoji-picker",
|
|
95
|
+
"data-control-family": "emoji-picker",
|
|
96
|
+
"data-slot": "list",
|
|
97
|
+
className: "select-none",
|
|
98
|
+
components: {
|
|
99
|
+
Row: EmojiPickerRow,
|
|
100
|
+
Emoji: EmojiPickerEmoji,
|
|
101
|
+
CategoryHeader: EmojiPickerCategoryHeader
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function EmojiPickerFooter({ className, placeholder = "Pick an emoji…", ...props }) {
|
|
108
|
+
return /* @__PURE__ */ jsx("div", {
|
|
109
|
+
"data-control-ui": "emoji-picker",
|
|
110
|
+
"data-control-family": "emoji-picker",
|
|
111
|
+
"data-slot": "footer",
|
|
112
|
+
className: cn("flex min-w-0 items-center", className),
|
|
113
|
+
...props,
|
|
114
|
+
children: /* @__PURE__ */ jsx(EmojiPicker$1.ActiveEmoji, { children: ({ emoji }) => emoji ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
115
|
+
"data-control-ui": "emoji-picker",
|
|
116
|
+
"data-control-family": "emoji-picker",
|
|
117
|
+
"data-slot": "footer-emoji",
|
|
118
|
+
className: "flex-none",
|
|
119
|
+
children: emoji.emoji
|
|
120
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
121
|
+
"data-control-ui": "emoji-picker",
|
|
122
|
+
"data-control-family": "emoji-picker",
|
|
123
|
+
"data-slot": "footer-label",
|
|
124
|
+
className: "truncate",
|
|
125
|
+
children: emoji.label
|
|
126
|
+
})] }) : /* @__PURE__ */ jsx("span", {
|
|
127
|
+
"data-control-ui": "emoji-picker",
|
|
128
|
+
"data-control-family": "emoji-picker",
|
|
129
|
+
"data-slot": "footer-placeholder",
|
|
130
|
+
className: "truncate",
|
|
131
|
+
children: placeholder
|
|
132
|
+
}) })
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { EmojiPicker, EmojiPickerContent, EmojiPickerFooter, EmojiPickerSearch };
|
package/dist/ui/empty.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RenderProp } from "../control-props.js";
|
|
1
2
|
import { EmptyKnobStyle } from "../knob-contracts/empty-knobs.js";
|
|
2
3
|
import { CSSProperties, ComponentProps } from "react";
|
|
3
4
|
//#region src/ui/empty.d.ts
|
|
@@ -17,12 +18,13 @@ export type EmptyDescriptionProps = Omit<ComponentProps<"p">, "style"> & {
|
|
|
17
18
|
style?: CSSProperties & EmptyKnobStyle;
|
|
18
19
|
};
|
|
19
20
|
export type EmptyTitleProps = Omit<ComponentProps<"div">, "style"> & {
|
|
21
|
+
render?: RenderProp<ComponentProps<"div">>;
|
|
20
22
|
style?: CSSProperties & EmptyKnobStyle;
|
|
21
23
|
};
|
|
22
24
|
export declare function Empty({ className, ...props }: EmptyProps): import("react").JSX.Element;
|
|
23
25
|
export declare function EmptyHeader({ className, ...props }: EmptyHeaderProps): import("react").JSX.Element;
|
|
24
26
|
export declare function EmptyMedia({ className, ...props }: EmptyMediaProps): import("react").JSX.Element;
|
|
25
|
-
export declare function EmptyTitle({
|
|
27
|
+
export declare function EmptyTitle({ render, ...props }: EmptyTitleProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|
|
26
28
|
export declare function EmptyDescription({ className, ...props }: EmptyDescriptionProps): import("react").JSX.Element;
|
|
27
29
|
export declare function EmptyContent({ className, ...props }: EmptyContentProps): import("react").JSX.Element;
|
|
28
30
|
//#endregion
|
package/dist/ui/empty.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render";
|
|
2
4
|
import { jsx } from "react/jsx-runtime";
|
|
3
5
|
//#region src/ui/empty.tsx
|
|
4
6
|
function Empty({ className, ...props }) {
|
|
@@ -28,13 +30,16 @@ function EmptyMedia({ className, ...props }) {
|
|
|
28
30
|
...props
|
|
29
31
|
});
|
|
30
32
|
}
|
|
31
|
-
function EmptyTitle({
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
function EmptyTitle({ render, ...props }) {
|
|
34
|
+
return useRender({
|
|
35
|
+
defaultTagName: "div",
|
|
36
|
+
render,
|
|
37
|
+
props: {
|
|
38
|
+
...props,
|
|
39
|
+
"data-control-ui": "empty",
|
|
40
|
+
"data-control-family": "empty",
|
|
41
|
+
"data-slot": "title"
|
|
42
|
+
}
|
|
38
43
|
});
|
|
39
44
|
}
|
|
40
45
|
function EmptyDescription({ className, ...props }) {
|
package/dist/ui/field.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { Separator } from "./separator.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import { cva } from "class-variance-authority";
|
|
6
5
|
import { Field as Field$1 } from "@base-ui/react/field";
|
|
7
6
|
import { Fieldset } from "@base-ui/react/fieldset";
|
|
7
|
+
import { cva } from "class-variance-authority";
|
|
8
8
|
//#region src/ui/field.tsx
|
|
9
9
|
const fieldVariants = cva("group/field flex w-full", {
|
|
10
10
|
variants: { orientation: {
|
|
@@ -39,7 +39,7 @@ export type GradientEditorTypeSelectProps = {
|
|
|
39
39
|
export declare function GradientEditor({ defaultStops, defaultType, defaultAngle, onValueChange, className, children, value: _value, ...props }: GradientEditorProps): import("react").JSX.Element;
|
|
40
40
|
export declare function GradientEditorPreview({ className, style, "aria-label": ariaLabel, ...props }: GradientEditorPreviewProps): import("react").JSX.Element;
|
|
41
41
|
export declare function GradientEditorTrack({ className, children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: GradientEditorTrackProps): import("react").JSX.Element;
|
|
42
|
-
export declare function GradientEditorStop({ stop, className, style, onPointerDown, onKeyDown, onFocus, onDoubleClick, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: GradientEditorStopProps): import("react").JSX.Element;
|
|
42
|
+
export declare function GradientEditorStop({ stop, className, style, onPointerDown, onKeyDown, onFocus, onDoubleClick, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ref, ...props }: GradientEditorStopProps): import("react").JSX.Element;
|
|
43
43
|
export declare function GradientEditorStopAdd({ className, children, ...props }: GradientEditorStopAddProps): import("react").JSX.Element;
|
|
44
44
|
export declare function GradientEditorStopColor(): import("react").JSX.Element | null;
|
|
45
45
|
export declare function GradientEditorTypeSelect({ size, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }: GradientEditorTypeSelectProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { useColorArea } from "../hooks/use-color-area.js";
|
|
3
4
|
import { formatGradient } from "../lib/color.js";
|
|
4
5
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
|
|
5
6
|
import { ColorPicker, ColorPickerAlpha, ColorPickerArea, ColorPickerContent, ColorPickerFormatSelect, ColorPickerHue, ColorPickerInput, ColorPickerTrigger } from "./color-picker.js";
|
|
@@ -30,6 +31,7 @@ function GradientEditor({ defaultStops = DEFAULT_STOPS, defaultType = "linear",
|
|
|
30
31
|
const [selectedId, setSelectedId] = useState(defaultStops[0]?.id ?? "stop-1");
|
|
31
32
|
const idCounter = useRef(defaultStops.length);
|
|
32
33
|
const trackRef = useRef(null);
|
|
34
|
+
const [stopNodes] = useState(() => /* @__PURE__ */ new Map());
|
|
33
35
|
const gradient = formatGradient(stops, type, angle);
|
|
34
36
|
function updateStops(nextStops) {
|
|
35
37
|
setStops(nextStops);
|
|
@@ -58,7 +60,7 @@ function GradientEditor({ defaultStops = DEFAULT_STOPS, defaultType = "linear",
|
|
|
58
60
|
if (stops.length <= 2) return;
|
|
59
61
|
const nextStops = stops.filter((stop) => stop.id !== id);
|
|
60
62
|
updateStops(nextStops);
|
|
61
|
-
|
|
63
|
+
setSelectedId((current) => current === id ? nextStops[0]?.id ?? current : current);
|
|
62
64
|
};
|
|
63
65
|
const setType = (nextType) => {
|
|
64
66
|
setTypeState(nextType);
|
|
@@ -71,6 +73,7 @@ function GradientEditor({ defaultStops = DEFAULT_STOPS, defaultType = "linear",
|
|
|
71
73
|
selectedId,
|
|
72
74
|
gradient,
|
|
73
75
|
trackRef,
|
|
76
|
+
stopNodes,
|
|
74
77
|
select: setSelectedId,
|
|
75
78
|
setStopColor,
|
|
76
79
|
setStopPosition,
|
|
@@ -130,30 +133,35 @@ function GradientEditorTrack({ className, children, style, "aria-label": ariaLab
|
|
|
130
133
|
children: children ?? stops.map((stop) => /* @__PURE__ */ jsx(GradientEditorStop, { stop }, stop.id))
|
|
131
134
|
});
|
|
132
135
|
}
|
|
133
|
-
function GradientEditorStop({ stop, className, style, onPointerDown, onKeyDown, onFocus, onDoubleClick, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }) {
|
|
134
|
-
const { stops, selectedId, select, setStopPosition, removeStop, trackRef } = useGradientEditor();
|
|
136
|
+
function GradientEditorStop({ stop, className, style, onPointerDown, onKeyDown, onFocus, onDoubleClick, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ref, ...props }) {
|
|
137
|
+
const { stops, selectedId, select, setStopPosition, removeStop, trackRef, stopNodes } = useGradientEditor();
|
|
135
138
|
const selected = stop.id === selectedId;
|
|
136
139
|
const canRemove = stops.length > 2;
|
|
140
|
+
const { onPointerDown: startDrag } = useColorArea((offset, rect) => setStopPosition(stop.id, offset.x / rect.width), trackRef);
|
|
137
141
|
function handlePointerDown(event) {
|
|
138
142
|
onPointerDown?.(event);
|
|
139
143
|
if (event.defaultPrevented) return;
|
|
140
144
|
select(stop.id);
|
|
141
145
|
event.currentTarget.focus();
|
|
142
|
-
event
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
startDrag(event);
|
|
147
|
+
}
|
|
148
|
+
function registerStop(node) {
|
|
149
|
+
stopNodes.set(stop.id, node);
|
|
150
|
+
const cleanup = typeof ref === "function" ? ref(node) : void 0;
|
|
151
|
+
if (ref && typeof ref === "object") ref.current = node;
|
|
152
|
+
return () => {
|
|
153
|
+
stopNodes.delete(stop.id);
|
|
154
|
+
if (typeof cleanup === "function") cleanup();
|
|
155
|
+
else if (typeof ref === "function") ref(null);
|
|
156
|
+
else if (ref) ref.current = null;
|
|
153
157
|
};
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
}
|
|
159
|
+
function remove() {
|
|
160
|
+
if (!canRemove) return;
|
|
161
|
+
const index = stops.findIndex((candidate) => candidate.id === stop.id);
|
|
162
|
+
const neighbour = stops[index + 1] ?? stops[index - 1];
|
|
163
|
+
if (neighbour) stopNodes.get(neighbour.id)?.focus();
|
|
164
|
+
removeStop(stop.id);
|
|
157
165
|
}
|
|
158
166
|
function handleFocus(event) {
|
|
159
167
|
onFocus?.(event);
|
|
@@ -194,27 +202,35 @@ function GradientEditorStop({ stop, className, style, onPointerDown, onKeyDown,
|
|
|
194
202
|
case "Delete":
|
|
195
203
|
if (!canRemove) return;
|
|
196
204
|
event.preventDefault();
|
|
197
|
-
|
|
205
|
+
remove();
|
|
198
206
|
}
|
|
199
207
|
}
|
|
200
208
|
function handleDoubleClick(event) {
|
|
201
209
|
onDoubleClick?.(event);
|
|
202
|
-
if (!event.defaultPrevented)
|
|
210
|
+
if (!event.defaultPrevented) remove();
|
|
203
211
|
}
|
|
204
|
-
const
|
|
212
|
+
const percent = Math.round(stop.position * 100);
|
|
213
|
+
const defaultLabel = `Gradient stop ${stops.indexOf(stop) + 1}`;
|
|
205
214
|
return /* @__PURE__ */ jsx("button", {
|
|
215
|
+
ref: registerStop,
|
|
206
216
|
type: "button",
|
|
217
|
+
role: "slider",
|
|
207
218
|
"data-control-ui": "gradient-editor",
|
|
208
219
|
"data-control-family": "gradient-editor",
|
|
209
220
|
"data-slot": "stop",
|
|
210
221
|
"data-selected": selected ? "true" : void 0,
|
|
211
222
|
"aria-label": ariaLabelledBy === void 0 ? ariaLabel ?? defaultLabel : ariaLabel,
|
|
212
223
|
"aria-labelledby": ariaLabelledBy,
|
|
224
|
+
"aria-orientation": "horizontal",
|
|
225
|
+
"aria-valuemin": 0,
|
|
226
|
+
"aria-valuemax": 100,
|
|
227
|
+
"aria-valuenow": percent,
|
|
228
|
+
"aria-valuetext": `${percent}%, ${stop.color}`,
|
|
213
229
|
onPointerDown: handlePointerDown,
|
|
214
230
|
onFocus: handleFocus,
|
|
215
231
|
onKeyDown: handleKeyDown,
|
|
216
232
|
onDoubleClick: handleDoubleClick,
|
|
217
|
-
className: cn("-translate-x-1/2 absolute top-1/2 -translate-y-1/2 cursor-grab touch-pan-y
|
|
233
|
+
className: cn("-translate-x-1/2 absolute top-1/2 -translate-y-1/2 cursor-grab touch-pan-y active:cursor-grabbing", className),
|
|
218
234
|
style: {
|
|
219
235
|
...style,
|
|
220
236
|
left: `${stop.position * 100}%`,
|
|
@@ -22,6 +22,17 @@ export type InfiniteCanvasProps = Omit<ComponentProps<"section">, "onChange" | "
|
|
|
22
22
|
export type InfiniteCanvasContentProps = ComponentProps<"div"> & {
|
|
23
23
|
style?: CSSProperties & InfiniteCanvasKnobStyle;
|
|
24
24
|
};
|
|
25
|
+
export type InfiniteCanvasPoint = {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
};
|
|
29
|
+
export type InfiniteCanvasItemProps = Omit<ComponentProps<"div">, "style"> & {
|
|
30
|
+
x: number;
|
|
31
|
+
y: number;
|
|
32
|
+
onPositionChange?: (position: InfiniteCanvasPoint) => void;
|
|
33
|
+
movableItemLabel?: string;
|
|
34
|
+
style?: CSSProperties & InfiniteCanvasKnobStyle;
|
|
35
|
+
};
|
|
25
36
|
export type InfiniteCanvasControlsProps = Omit<ComponentProps<"div">, "children" | "style"> & {
|
|
26
37
|
style?: CSSProperties & InfiniteCanvasKnobStyle;
|
|
27
38
|
};
|
|
@@ -33,7 +44,8 @@ type InfiniteCanvasContextValue = {
|
|
|
33
44
|
zoomBy: (factor: number, reason: InfiniteCanvasMoveReason) => void;
|
|
34
45
|
};
|
|
35
46
|
export declare function useInfiniteCanvas(): InfiniteCanvasContextValue;
|
|
36
|
-
export declare function InfiniteCanvas({ transform: controlledTransform, defaultTransform, onTransformChange, minScale: minScaleProp, maxScale: maxScaleProp, className, children, style, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onWheel, onKeyDown, "aria-label": ariaLabel, ...props }: InfiniteCanvasProps): import("react").JSX.Element;
|
|
47
|
+
export declare function InfiniteCanvas({ transform: controlledTransform, defaultTransform, onTransformChange, minScale: minScaleProp, maxScale: maxScaleProp, className, children, style, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onWheel, onKeyDown, "aria-label": ariaLabel, "aria-keyshortcuts": ariaKeyShortcuts, ...props }: InfiniteCanvasProps): import("react").JSX.Element;
|
|
37
48
|
export declare function InfiniteCanvasContent({ className, style, ...props }: InfiniteCanvasContentProps): import("react").JSX.Element;
|
|
49
|
+
export declare function InfiniteCanvasItem({ x, y, onPositionChange, movableItemLabel, className, style, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onKeyDown, ...props }: InfiniteCanvasItemProps): import("react").JSX.Element;
|
|
38
50
|
export declare function InfiniteCanvasControls({ className, ...props }: InfiniteCanvasControlsProps): import("react").JSX.Element;
|
|
39
51
|
//#endregion
|