@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
package/dist/ui/rich-tooltip.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
import { controlEffectsAttribute } from "../skin.js";
|
|
3
3
|
import { cn } from "../lib/cn.js";
|
|
4
4
|
import { useSkin } from "../skin-provider.js";
|
|
5
|
+
import { prefersReducedMotion } from "../lib/motion.js";
|
|
6
|
+
import { PopupArrowShape } from "../popup-parts.js";
|
|
5
7
|
import { stepAfter, stepBefore, tourPosition } from "./rich-tooltip-tour.js";
|
|
6
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
8
|
+
import { createContext, useContext, useEffect, useId, useRef, useState } from "react";
|
|
7
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { ChevronLeftIcon, ChevronRightIcon, XIcon } from "lucide-react";
|
|
10
|
+
import { CheckIcon, ChevronLeftIcon, ChevronRightIcon, XIcon } from "lucide-react";
|
|
9
11
|
import { Popover } from "@base-ui/react/popover";
|
|
10
12
|
//#region src/ui/rich-tooltip.tsx
|
|
11
13
|
const TourContext = createContext(null);
|
|
@@ -66,11 +68,14 @@ function useRichTooltipContext() {
|
|
|
66
68
|
if (!context) throw new Error("RichTooltip parts must be rendered inside <RichTooltip>.");
|
|
67
69
|
return context;
|
|
68
70
|
}
|
|
69
|
-
function RichTooltip({ step, tone = "accent", storageKey, dismissOnOutsidePress = false, trapFocus = false, open, defaultOpen = true, onOpenChange, children, ...props }) {
|
|
71
|
+
function RichTooltip({ step, tone = "accent", storageKey, dismissOnOutsidePress = false, dismissOnFocusOut = false, trapFocus = false, open, defaultOpen = true, onOpenChange, children, ...props }) {
|
|
70
72
|
const tour = useTour();
|
|
71
73
|
const inTour = tour !== null && step !== void 0;
|
|
72
74
|
const [standaloneOpen, setStandaloneOpen] = useState(defaultOpen);
|
|
73
75
|
const standaloneAllowed = useSeenGate(storageKey, open === void 0 && !inTour);
|
|
76
|
+
const nextRef = useRef(null);
|
|
77
|
+
const [descriptionId, setDescriptionId] = useState();
|
|
78
|
+
const [progressId, setProgressId] = useState();
|
|
74
79
|
const resolvedOpen = open ?? (inTour ? tour.activeStep === step : standaloneOpen && standaloneAllowed);
|
|
75
80
|
function dismiss() {
|
|
76
81
|
if (inTour) {
|
|
@@ -82,12 +87,19 @@ function RichTooltip({ step, tone = "accent", storageKey, dismissOnOutsidePress
|
|
|
82
87
|
}
|
|
83
88
|
const handleOpenChange = (nextOpen, details) => {
|
|
84
89
|
if (!dismissOnOutsidePress && details.reason === "outside-press") return;
|
|
90
|
+
if (!dismissOnFocusOut && details.reason === "focus-out") return;
|
|
85
91
|
onOpenChange?.(nextOpen, details);
|
|
86
92
|
if (!nextOpen) dismiss();
|
|
87
93
|
};
|
|
88
94
|
const context = {
|
|
89
95
|
tone,
|
|
90
|
-
|
|
96
|
+
inTour,
|
|
97
|
+
dismiss,
|
|
98
|
+
nextRef,
|
|
99
|
+
descriptionId,
|
|
100
|
+
setDescriptionId,
|
|
101
|
+
progressId,
|
|
102
|
+
setProgressId
|
|
91
103
|
};
|
|
92
104
|
return /* @__PURE__ */ jsx(RichTooltipContext.Provider, {
|
|
93
105
|
value: context,
|
|
@@ -122,11 +134,10 @@ function useAnchorScroll(anchor, open, enabled) {
|
|
|
122
134
|
if (!(open && enabled)) return;
|
|
123
135
|
const element = resolveAnchorElement(anchor);
|
|
124
136
|
if (!element) return;
|
|
125
|
-
const reduced = globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
126
137
|
element.scrollIntoView({
|
|
127
138
|
block: "center",
|
|
128
139
|
inline: "nearest",
|
|
129
|
-
behavior:
|
|
140
|
+
behavior: prefersReducedMotion(element) ? "auto" : "smooth"
|
|
130
141
|
});
|
|
131
142
|
}, [
|
|
132
143
|
anchor,
|
|
@@ -134,11 +145,20 @@ function useAnchorScroll(anchor, open, enabled) {
|
|
|
134
145
|
open
|
|
135
146
|
]);
|
|
136
147
|
}
|
|
148
|
+
const richTooltipContentSelector = "[data-control-ui=\"rich-tooltip\"][data-slot=\"content\"]";
|
|
137
149
|
function RichTooltipContent({ className, children, side = "bottom", align = "center", sideOffset = 10, anchor, collisionPadding = 12, arrow = true, scrollAnchorIntoView = true, ...props }) {
|
|
138
150
|
const skin = useSkin();
|
|
139
|
-
const { tone } = useRichTooltipContext();
|
|
151
|
+
const { tone, inTour, nextRef, descriptionId, progressId } = useRichTooltipContext();
|
|
140
152
|
const isSurface = tone === "surface";
|
|
141
153
|
useAnchorScroll(anchor, true, scrollAnchorIntoView);
|
|
154
|
+
const describedBy = [descriptionId, progressId].filter(Boolean).join(" ") || void 0;
|
|
155
|
+
const initialFocus = (openType) => {
|
|
156
|
+
const active = document.activeElement;
|
|
157
|
+
const openedWithoutInteraction = !openType;
|
|
158
|
+
const focusIsElsewhere = active !== null && active !== document.body && active.closest(richTooltipContentSelector) === null;
|
|
159
|
+
if (openedWithoutInteraction && focusIsElsewhere) return false;
|
|
160
|
+
return inTour && nextRef.current ? nextRef.current : true;
|
|
161
|
+
};
|
|
142
162
|
return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
|
|
143
163
|
"data-control-ui": "rich-tooltip",
|
|
144
164
|
"data-popup-kind": "rich-tooltip",
|
|
@@ -161,6 +181,8 @@ function RichTooltipContent({ className, children, side = "bottom", align = "cen
|
|
|
161
181
|
"data-surface": isSurface ? "floating" : void 0,
|
|
162
182
|
"data-popup-part": isSurface ? "surface" : void 0,
|
|
163
183
|
className: cn("relative grid w-80 max-w-[calc(100vw-2rem)]", className),
|
|
184
|
+
initialFocus,
|
|
185
|
+
"aria-describedby": describedBy,
|
|
164
186
|
...props,
|
|
165
187
|
children: [children, arrow ? /* @__PURE__ */ jsx(Popover.Arrow, {
|
|
166
188
|
"data-control-ui": "rich-tooltip",
|
|
@@ -168,24 +190,12 @@ function RichTooltipContent({ className, children, side = "bottom", align = "cen
|
|
|
168
190
|
"data-control-family": "popup",
|
|
169
191
|
"data-slot": "arrow",
|
|
170
192
|
"data-tone": tone,
|
|
171
|
-
className:
|
|
172
|
-
children: /* @__PURE__ */ jsx(
|
|
193
|
+
className: "flex",
|
|
194
|
+
children: /* @__PURE__ */ jsx(PopupArrowShape, {})
|
|
173
195
|
}) : null]
|
|
174
196
|
})
|
|
175
197
|
}) });
|
|
176
198
|
}
|
|
177
|
-
function RichTooltipArrowSvg() {
|
|
178
|
-
return /* @__PURE__ */ jsx("svg", {
|
|
179
|
-
"aria-hidden": "true",
|
|
180
|
-
focusable: "false",
|
|
181
|
-
width: "12",
|
|
182
|
-
height: "8",
|
|
183
|
-
viewBox: "0 0 12 8",
|
|
184
|
-
fill: "none",
|
|
185
|
-
overflow: "visible",
|
|
186
|
-
children: /* @__PURE__ */ jsx("path", { d: "M0 7L4 2Q6 0 8 2L12 7L12 8L0 8Z" })
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
199
|
function RichTooltipMedia({ className, ...props }) {
|
|
190
200
|
return /* @__PURE__ */ jsx("div", {
|
|
191
201
|
"data-control-ui": "rich-tooltip",
|
|
@@ -217,8 +227,15 @@ function RichTooltipTitle({ className, ...props }) {
|
|
|
217
227
|
});
|
|
218
228
|
}
|
|
219
229
|
function RichTooltipDescription({ className, ...props }) {
|
|
220
|
-
const { tone } = useRichTooltipContext();
|
|
230
|
+
const { tone, setDescriptionId } = useRichTooltipContext();
|
|
231
|
+
const generatedId = useId();
|
|
232
|
+
const id = props.id ?? generatedId;
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
setDescriptionId(id);
|
|
235
|
+
return () => setDescriptionId(void 0);
|
|
236
|
+
}, [id, setDescriptionId]);
|
|
221
237
|
return /* @__PURE__ */ jsx(Popover.Description, {
|
|
238
|
+
id,
|
|
222
239
|
"data-control-ui": "rich-tooltip",
|
|
223
240
|
"data-control-family": "popup",
|
|
224
241
|
"data-popup-kind": "rich-tooltip",
|
|
@@ -239,9 +256,20 @@ function RichTooltipFooter({ className, ...props }) {
|
|
|
239
256
|
});
|
|
240
257
|
}
|
|
241
258
|
function RichTooltipProgress({ className, variant = "count", children, ...props }) {
|
|
242
|
-
const { tone } = useRichTooltipContext();
|
|
259
|
+
const { tone, setProgressId } = useRichTooltipContext();
|
|
243
260
|
const tour = useTour();
|
|
244
|
-
|
|
261
|
+
const statusId = useId();
|
|
262
|
+
const rendered = tour !== null && tour.total >= 2 && tour.index >= 0;
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
if (!rendered) return;
|
|
265
|
+
setProgressId(statusId);
|
|
266
|
+
return () => setProgressId(void 0);
|
|
267
|
+
}, [
|
|
268
|
+
rendered,
|
|
269
|
+
statusId,
|
|
270
|
+
setProgressId
|
|
271
|
+
]);
|
|
272
|
+
if (!tour || !rendered) return null;
|
|
245
273
|
return /* @__PURE__ */ jsxs("div", {
|
|
246
274
|
"data-control-ui": "rich-tooltip",
|
|
247
275
|
"data-control-family": "popup",
|
|
@@ -252,6 +280,7 @@ function RichTooltipProgress({ className, variant = "count", children, ...props
|
|
|
252
280
|
className: cn("flex items-center", className),
|
|
253
281
|
...props,
|
|
254
282
|
children: [/* @__PURE__ */ jsx("span", {
|
|
283
|
+
id: statusId,
|
|
255
284
|
className: "sr-only",
|
|
256
285
|
children: `Step ${tour.index + 1} of ${tour.total}`
|
|
257
286
|
}), children ?? (variant === "dots" ? Array.from({ length: tour.total }, (_, dot) => /* @__PURE__ */ jsx("span", {
|
|
@@ -267,8 +296,12 @@ function RichTooltipProgress({ className, variant = "count", children, ...props
|
|
|
267
296
|
}))]
|
|
268
297
|
});
|
|
269
298
|
}
|
|
299
|
+
function assignRef(ref, node) {
|
|
300
|
+
if (typeof ref === "function") ref(node);
|
|
301
|
+
else if (ref) ref.current = node;
|
|
302
|
+
}
|
|
270
303
|
const actionClasses = "inline-flex shrink-0 cursor-pointer items-center justify-center disabled:pointer-events-none [&_svg]:size-4";
|
|
271
|
-
function RichTooltipPrevious({ className, children, onClick, ...props }) {
|
|
304
|
+
function RichTooltipPrevious({ className, children, label = "Previous step", onClick, ...props }) {
|
|
272
305
|
const tour = useTour();
|
|
273
306
|
if (!tour || tour.total < 2) return null;
|
|
274
307
|
return /* @__PURE__ */ jsx("button", {
|
|
@@ -277,6 +310,7 @@ function RichTooltipPrevious({ className, children, onClick, ...props }) {
|
|
|
277
310
|
"data-control-family": "popup",
|
|
278
311
|
"data-popup-kind": "rich-tooltip",
|
|
279
312
|
"data-slot": "previous",
|
|
313
|
+
"data-icon-only": children === void 0 ? "true" : void 0,
|
|
280
314
|
disabled: tour.isFirst,
|
|
281
315
|
onClick: (event) => {
|
|
282
316
|
onClick?.(event);
|
|
@@ -284,21 +318,30 @@ function RichTooltipPrevious({ className, children, onClick, ...props }) {
|
|
|
284
318
|
},
|
|
285
319
|
className: cn(actionClasses, className),
|
|
286
320
|
...props,
|
|
287
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ChevronLeftIcon, {
|
|
321
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ChevronLeftIcon, {
|
|
322
|
+
"aria-hidden": "true",
|
|
323
|
+
"data-icon-dir": "inline"
|
|
324
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
288
325
|
className: "sr-only",
|
|
289
|
-
children:
|
|
326
|
+
children: label
|
|
290
327
|
})] })
|
|
291
328
|
});
|
|
292
329
|
}
|
|
293
|
-
function RichTooltipNext({ className, children, onClick, ...props }) {
|
|
294
|
-
const { dismiss } = useRichTooltipContext();
|
|
330
|
+
function RichTooltipNext({ className, children, nextLabel = "Next step", finishLabel = "Finish", gotItLabel = "Got it", onClick, ref, ...props }) {
|
|
331
|
+
const { dismiss, nextRef } = useRichTooltipContext();
|
|
295
332
|
const tour = useTour();
|
|
333
|
+
const setRef = (node) => {
|
|
334
|
+
nextRef.current = node;
|
|
335
|
+
assignRef(ref, node);
|
|
336
|
+
};
|
|
296
337
|
return /* @__PURE__ */ jsx("button", {
|
|
297
338
|
type: "button",
|
|
298
339
|
"data-control-ui": "rich-tooltip",
|
|
299
340
|
"data-control-family": "popup",
|
|
300
341
|
"data-popup-kind": "rich-tooltip",
|
|
301
342
|
"data-slot": "next",
|
|
343
|
+
"data-icon-only": children === void 0 && tour ? "true" : void 0,
|
|
344
|
+
ref: setRef,
|
|
302
345
|
onClick: (event) => {
|
|
303
346
|
onClick?.(event);
|
|
304
347
|
if (event.defaultPrevented) return;
|
|
@@ -309,21 +352,26 @@ function RichTooltipNext({ className, children, onClick, ...props }) {
|
|
|
309
352
|
...props,
|
|
310
353
|
children: children ?? (tour ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
311
354
|
className: "sr-only",
|
|
312
|
-
children: tour.isLast ?
|
|
313
|
-
}), /* @__PURE__ */ jsx(
|
|
355
|
+
children: tour.isLast ? finishLabel : nextLabel
|
|
356
|
+
}), tour.isLast ? /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRightIcon, {
|
|
357
|
+
"aria-hidden": "true",
|
|
358
|
+
"data-icon-dir": "inline"
|
|
359
|
+
})] }) : gotItLabel)
|
|
314
360
|
});
|
|
315
361
|
}
|
|
316
|
-
function RichTooltipClose({ className, children, ...props }) {
|
|
362
|
+
function RichTooltipClose({ className, children, label, ...props }) {
|
|
363
|
+
const { inTour } = useRichTooltipContext();
|
|
317
364
|
return /* @__PURE__ */ jsx(Popover.Close, {
|
|
318
365
|
"data-control-ui": "rich-tooltip",
|
|
319
366
|
"data-control-family": "popup",
|
|
320
367
|
"data-popup-kind": "rich-tooltip",
|
|
321
368
|
"data-slot": "close",
|
|
369
|
+
"data-icon-only": children === void 0 ? "true" : void 0,
|
|
322
370
|
className: cn(actionClasses, className),
|
|
323
371
|
...props,
|
|
324
372
|
children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" }), /* @__PURE__ */ jsx("span", {
|
|
325
373
|
className: "sr-only",
|
|
326
|
-
children: "Dismiss"
|
|
374
|
+
children: label ?? (inTour ? "End tour" : "Dismiss")
|
|
327
375
|
})] })
|
|
328
376
|
});
|
|
329
377
|
}
|
package/dist/ui/scroll-area.d.ts
CHANGED
|
@@ -26,5 +26,5 @@ export type ScrollAreaProps = Omit<ComponentProps<"div">, "style"> & {
|
|
|
26
26
|
lockAxis?: ScrollAreaLockAxis;
|
|
27
27
|
scrollbarVisibility?: ScrollAreaScrollbarVisibility;
|
|
28
28
|
};
|
|
29
|
-
export declare function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask, blur, blurProps, lockAxis, scrollbarVisibility, children, style, ...props }: ScrollAreaProps): import("react").JSX.Element;
|
|
29
|
+
export declare function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask, blur, blurProps, lockAxis, scrollbarVisibility, children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }: ScrollAreaProps): import("react").JSX.Element;
|
|
30
30
|
//#endregion
|
package/dist/ui/scroll-area.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { useSkin } from "../skin-provider.js";
|
|
4
4
|
import { ProgressiveBlur } from "./progressive-blur.js";
|
|
5
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { ScrollArea as ScrollArea$1 } from "@base-ui/react/scroll-area";
|
|
7
7
|
//#region src/ui/scroll-area.tsx
|
|
8
8
|
const scrollAreaScrollbarVisibilities = [
|
|
@@ -27,25 +27,54 @@ function Scrollbar({ orientation, visibility, thumbStyle }) {
|
|
|
27
27
|
})
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
|
-
function viewportStyle(maxHeight, lockX, lockY) {
|
|
31
|
-
if (!maxHeight && !lockX && !lockY) return
|
|
30
|
+
function viewportStyle(baseStyle, maxHeight, lockX, lockY) {
|
|
31
|
+
if (!maxHeight && !lockX && !lockY) return baseStyle;
|
|
32
32
|
return {
|
|
33
|
+
...baseStyle,
|
|
33
34
|
...maxHeight ? { maxHeight } : {},
|
|
34
35
|
...lockX ? { overflowX: "hidden" } : {},
|
|
35
36
|
...lockY ? { overflowY: "hidden" } : {}
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
|
-
function
|
|
39
|
+
function regionProps(ariaLabel, ariaLabelledby) {
|
|
40
|
+
if (!ariaLabel && !ariaLabelledby) return {};
|
|
41
|
+
return {
|
|
42
|
+
role: "region",
|
|
43
|
+
"aria-label": ariaLabel,
|
|
44
|
+
"aria-labelledby": ariaLabelledby
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function EdgeBlurs({ blurProps, lockX, lockY }) {
|
|
48
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49
|
+
!lockY && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
50
|
+
...blurProps,
|
|
51
|
+
side: "top",
|
|
52
|
+
visible: false
|
|
53
|
+
}),
|
|
54
|
+
!lockY && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
55
|
+
...blurProps,
|
|
56
|
+
side: "bottom",
|
|
57
|
+
visible: false
|
|
58
|
+
}),
|
|
59
|
+
!lockX && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
60
|
+
...blurProps,
|
|
61
|
+
side: "inline-start",
|
|
62
|
+
visible: false
|
|
63
|
+
}),
|
|
64
|
+
!lockX && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
65
|
+
...blurProps,
|
|
66
|
+
side: "inline-end",
|
|
67
|
+
visible: false
|
|
68
|
+
})
|
|
69
|
+
] });
|
|
70
|
+
}
|
|
71
|
+
function ScrollArea({ className, viewportClassName, contentClassName, viewportProps, viewportRef, maxHeight, mask = true, blur, blurProps, lockAxis, scrollbarVisibility = "hover", children, style, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, ...props }) {
|
|
39
72
|
const skin = useSkin();
|
|
40
73
|
const resolvedBlur = blur ?? skin.scrollAreaBlur ?? false;
|
|
41
74
|
const lockX = lockAxis === "x" || lockAxis === "both";
|
|
42
75
|
const lockY = lockAxis === "y" || lockAxis === "both";
|
|
43
|
-
const resolvedViewportStyle = viewportStyle(maxHeight, lockX, lockY);
|
|
44
76
|
const { style: viewportPropsStyle, ...resolvedViewportProps } = viewportProps ?? {};
|
|
45
|
-
const mergedViewportStyle = viewportPropsStyle
|
|
46
|
-
...viewportPropsStyle,
|
|
47
|
-
...resolvedViewportStyle
|
|
48
|
-
} : void 0;
|
|
77
|
+
const mergedViewportStyle = viewportStyle(viewportPropsStyle, maxHeight, lockX, lockY);
|
|
49
78
|
const thumbStyle = style;
|
|
50
79
|
const cornerStyle = style;
|
|
51
80
|
return /* @__PURE__ */ jsxs(ScrollArea$1.Root, {
|
|
@@ -64,6 +93,7 @@ function ScrollArea({ className, viewportClassName, contentClassName, viewportPr
|
|
|
64
93
|
"data-control-family": "scroll-area",
|
|
65
94
|
"data-slot": "viewport",
|
|
66
95
|
...resolvedViewportProps,
|
|
96
|
+
...regionProps(ariaLabel, ariaLabelledby),
|
|
67
97
|
"data-scroll-area-viewport": "",
|
|
68
98
|
ref: viewportRef,
|
|
69
99
|
className: cn("h-full w-full", viewportClassName),
|
|
@@ -77,25 +107,10 @@ function ScrollArea({ className, viewportClassName, contentClassName, viewportPr
|
|
|
77
107
|
children
|
|
78
108
|
})
|
|
79
109
|
}),
|
|
80
|
-
resolvedBlur &&
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}),
|
|
85
|
-
resolvedBlur && !lockY && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
86
|
-
...blurProps,
|
|
87
|
-
side: "bottom",
|
|
88
|
-
visible: false
|
|
89
|
-
}),
|
|
90
|
-
resolvedBlur && !lockX && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
91
|
-
...blurProps,
|
|
92
|
-
side: "inline-start",
|
|
93
|
-
visible: false
|
|
94
|
-
}),
|
|
95
|
-
resolvedBlur && !lockX && /* @__PURE__ */ jsx(ProgressiveBlur, {
|
|
96
|
-
...blurProps,
|
|
97
|
-
side: "inline-end",
|
|
98
|
-
visible: false
|
|
110
|
+
resolvedBlur && /* @__PURE__ */ jsx(EdgeBlurs, {
|
|
111
|
+
blurProps,
|
|
112
|
+
lockX,
|
|
113
|
+
lockY
|
|
99
114
|
}),
|
|
100
115
|
!lockY && /* @__PURE__ */ jsx(Scrollbar, {
|
|
101
116
|
orientation: "vertical",
|
|
@@ -43,6 +43,10 @@ export declare function SidebarMenu({ className, indicator, style, children, ...
|
|
|
43
43
|
export declare function SidebarMenuItem({ className, ...props }: ComponentProps<"li"> & {
|
|
44
44
|
style?: CSSProperties & SidebarKnobStyle;
|
|
45
45
|
}): import("react").JSX.Element;
|
|
46
|
-
export
|
|
46
|
+
export type SidebarMenuBadgeProps = Omit<ComponentProps<"div">, "style"> & {
|
|
47
|
+
style?: CSSProperties & SidebarKnobStyle;
|
|
48
|
+
};
|
|
49
|
+
export declare function SidebarMenuBadge({ className, ...props }: SidebarMenuBadgeProps): import("react").JSX.Element;
|
|
50
|
+
export declare function SidebarMenuButton({ render, isActive, variant, size, tooltip, className, children, ref, ...props }: SidebarMenuButtonProps): import("react").JSX.Element;
|
|
47
51
|
export declare function SidebarMenuSub({ className, ...props }: ComponentProps<typeof SidebarMenu>): import("react").JSX.Element;
|
|
48
52
|
//#endregion
|
package/dist/ui/sidebar-menu.js
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
import { cn } from "../lib/cn.js";
|
|
3
3
|
import { useSkin } from "../skin-provider.js";
|
|
4
4
|
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
|
|
5
|
-
import { useSidebar } from "./sidebar-provider.js";
|
|
5
|
+
import { SidebarSurfaceContext, useSidebar } from "./sidebar-provider.js";
|
|
6
6
|
import { TrackHighlight } from "../extensions/track-highlight.js";
|
|
7
|
-
import { createContext, useContext } from "react";
|
|
7
|
+
import { createContext, useContext, useRef, useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useRender } from "@base-ui/react/use-render";
|
|
10
|
-
import { cva } from "class-variance-authority";
|
|
11
10
|
//#region src/ui/sidebar-menu.tsx
|
|
12
11
|
const sidebarMenuButtonVariants = ["default", "outline"];
|
|
13
12
|
const sidebarMenuButtonSizes = [
|
|
@@ -73,7 +72,7 @@ function SidebarMenu({ className, indicator, style, children, ...props }) {
|
|
|
73
72
|
"data-control-family": "sidebar",
|
|
74
73
|
"data-slot": "menu",
|
|
75
74
|
"data-indicator": resolvedIndicator,
|
|
76
|
-
className: cn("flex min-w-0 flex-col", hasHighlight ? void 0 : className),
|
|
75
|
+
className: cn("flex min-w-0 flex-col group-data-[collapsible=icon]:mx-0 group-data-[collapsible=icon]:border-0 group-data-[collapsible=icon]:px-0", hasHighlight ? void 0 : className),
|
|
77
76
|
style: hasHighlight ? void 0 : style,
|
|
78
77
|
...props,
|
|
79
78
|
children: /* @__PURE__ */ jsx(SidebarMenuContext.Provider, {
|
|
@@ -102,31 +101,29 @@ function SidebarMenuItem({ className, ...props }) {
|
|
|
102
101
|
...props
|
|
103
102
|
});
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
defaultVariants: {
|
|
118
|
-
variant: "default",
|
|
119
|
-
size: "default"
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
function SidebarMenuButton({ render, isActive = false, variant = "default", size = "default", tooltip, className, children, ...props }) {
|
|
104
|
+
function SidebarMenuBadge({ className, ...props }) {
|
|
105
|
+
return /* @__PURE__ */ jsx("div", {
|
|
106
|
+
"data-control-ui": "sidebar",
|
|
107
|
+
"data-control-family": "sidebar",
|
|
108
|
+
"data-slot": "menu-badge",
|
|
109
|
+
className: cn("pointer-events-none absolute flex -translate-y-1/2 select-none items-center justify-center tabular-nums group-data-[collapsible=icon]:hidden", className),
|
|
110
|
+
...props
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function SidebarMenuButton({ render, isActive = false, variant = "default", size = "default", tooltip, className, children, ref, ...props }) {
|
|
123
114
|
const { isMobile, state } = useSidebar();
|
|
115
|
+
const surface = useContext(SidebarSurfaceContext);
|
|
116
|
+
const tooltipEnabled = !isMobile && state === "collapsed" && surface?.collapsible === "icon";
|
|
124
117
|
const indicator = useContext(SidebarMenuContext);
|
|
118
|
+
const buttonRef = useRef(null);
|
|
119
|
+
const [textLabel, setTextLabel] = useState("");
|
|
125
120
|
const button = useRender({
|
|
126
121
|
defaultTagName: "button",
|
|
127
122
|
render,
|
|
123
|
+
ref: [ref ?? null, buttonRef],
|
|
128
124
|
props: {
|
|
129
125
|
type: "button",
|
|
126
|
+
"aria-current": isActive ? "page" : void 0,
|
|
130
127
|
...props,
|
|
131
128
|
"data-control-ui": "sidebar",
|
|
132
129
|
"data-control-family": "sidebar",
|
|
@@ -135,20 +132,23 @@ function SidebarMenuButton({ render, isActive = false, variant = "default", size
|
|
|
135
132
|
"data-variant": variant,
|
|
136
133
|
"data-active": isActive || void 0,
|
|
137
134
|
"data-track-item": indicator !== "none" ? "" : void 0,
|
|
138
|
-
className: cn(
|
|
139
|
-
variant,
|
|
140
|
-
size
|
|
141
|
-
}), className),
|
|
135
|
+
className: cn("peer/menu-button flex items-center overflow-hidden text-start disabled:pointer-events-none aria-disabled:pointer-events-none [&>span]:truncate [&>svg]:size-4 [&>svg]:shrink-0", className),
|
|
142
136
|
children
|
|
143
137
|
}
|
|
144
138
|
});
|
|
145
|
-
if (!tooltip) return button;
|
|
146
|
-
return /* @__PURE__ */ jsxs(Tooltip, {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
139
|
+
if (!tooltip && surface?.collapsible !== "icon") return button;
|
|
140
|
+
return /* @__PURE__ */ jsxs(Tooltip, {
|
|
141
|
+
disabled: !tooltipEnabled,
|
|
142
|
+
onOpenChange: (open) => {
|
|
143
|
+
if (open && !tooltip) setTextLabel(buttonRef.current?.textContent?.trim() ?? "");
|
|
144
|
+
},
|
|
145
|
+
children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: button }), /* @__PURE__ */ jsx(TooltipContent, {
|
|
146
|
+
side: surface?.side === "right" ? "inline-start" : "inline-end",
|
|
147
|
+
align: "center",
|
|
148
|
+
hidden: !tooltipEnabled,
|
|
149
|
+
children: tooltip ?? textLabel
|
|
150
|
+
})]
|
|
151
|
+
});
|
|
152
152
|
}
|
|
153
153
|
function SidebarMenuSub({ className, ...props }) {
|
|
154
154
|
return /* @__PURE__ */ jsx(SidebarMenu, {
|
|
@@ -158,4 +158,4 @@ function SidebarMenuSub({ className, ...props }) {
|
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
160
|
//#endregion
|
|
161
|
-
export { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, sidebarMenuButtonSizes, sidebarMenuButtonVariants };
|
|
161
|
+
export { SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, sidebarMenuButtonSizes, sidebarMenuButtonVariants };
|
|
@@ -5,6 +5,7 @@ export type SidebarStyle = CSSProperties & SidebarKnobStyle & {
|
|
|
5
5
|
"--sidebar-width"?: string;
|
|
6
6
|
"--sidebar-width-icon"?: string;
|
|
7
7
|
};
|
|
8
|
+
export type SidebarLayoutMode = "viewport" | "contained";
|
|
8
9
|
type SidebarContextProps = {
|
|
9
10
|
state: "expanded" | "collapsed";
|
|
10
11
|
open: boolean;
|
|
@@ -17,12 +18,17 @@ type SidebarContextProps = {
|
|
|
17
18
|
minWidth: number;
|
|
18
19
|
maxWidth: number;
|
|
19
20
|
setWidth: (width: number) => void;
|
|
21
|
+
layout: SidebarLayoutMode;
|
|
22
|
+
keyboardShortcut: string | null;
|
|
23
|
+
sidebarId: string;
|
|
24
|
+
contentId: string;
|
|
20
25
|
};
|
|
21
26
|
type SidebarElements = {
|
|
22
27
|
wrapperRef: RefObject<HTMLDivElement | null>;
|
|
23
28
|
offcanvasRef: RefObject<HTMLDivElement | null>;
|
|
24
29
|
railRef: RefObject<HTMLElement | null>;
|
|
25
30
|
triggerRef: RefObject<HTMLButtonElement | null>;
|
|
31
|
+
insetRef: RefObject<HTMLElement | null>;
|
|
26
32
|
};
|
|
27
33
|
export declare const SidebarSurfaceContext: import("react").Context<{
|
|
28
34
|
side: "left" | "right";
|
|
@@ -47,7 +53,10 @@ export type SidebarProviderProps = Omit<ComponentProps<"div">, "style"> & {
|
|
|
47
53
|
onWidthChange?: (width: number) => void;
|
|
48
54
|
persistOpen?: boolean;
|
|
49
55
|
keyboardShortcut?: string | null;
|
|
56
|
+
layout?: SidebarLayoutMode;
|
|
57
|
+
skipLinkLabel?: string;
|
|
58
|
+
contentId?: string;
|
|
50
59
|
style?: SidebarStyle;
|
|
51
60
|
};
|
|
52
|
-
export declare function SidebarProvider({ defaultOpen, open: openProp, onOpenChange, defaultWidth, minWidth, maxWidth, width: widthProp, onWidthChange, persistOpen, keyboardShortcut, ref, className, style, children, ...props }: SidebarProviderProps): import("react").JSX.Element;
|
|
61
|
+
export declare function SidebarProvider({ defaultOpen, open: openProp, onOpenChange, defaultWidth, minWidth, maxWidth, width: widthProp, onWidthChange, persistOpen, keyboardShortcut, layout, skipLinkLabel, contentId: contentIdProp, ref, className, style, children, ...props }: SidebarProviderProps): import("react").JSX.Element;
|
|
53
62
|
//#endregion
|
|
@@ -4,15 +4,15 @@ import { useSkin } from "../skin-provider.js";
|
|
|
4
4
|
import { TooltipProvider } from "./tooltip.js";
|
|
5
5
|
import { SIDEBAR_COOKIE_NAME } from "../control-props.js";
|
|
6
6
|
import { useIsMobile } from "../hooks/use-mobile.js";
|
|
7
|
-
import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
8
|
-
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { createContext, useContext, useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
8
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import { useRender } from "@base-ui/react/use-render";
|
|
10
10
|
//#region src/ui/sidebar-provider.tsx
|
|
11
11
|
const SIDEBAR_COOKIE_MAX_AGE = 604800;
|
|
12
12
|
const SIDEBAR_WIDTH = "16rem";
|
|
13
13
|
const SIDEBAR_WIDTH_ICON = "3rem";
|
|
14
14
|
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
15
|
-
const SIDEBAR_MOBILE_BREAKPOINT =
|
|
15
|
+
const SIDEBAR_MOBILE_BREAKPOINT = "--breakpoint-lg";
|
|
16
16
|
const SidebarElementsContext = createContext(null);
|
|
17
17
|
const SidebarSurfaceContext = createContext(null);
|
|
18
18
|
function useSidebarElements() {
|
|
@@ -38,7 +38,7 @@ function useSidebar() {
|
|
|
38
38
|
if (!context) throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
39
39
|
return context;
|
|
40
40
|
}
|
|
41
|
-
function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, defaultWidth, minWidth = 224, maxWidth = 420, width: widthProp, onWidthChange, persistOpen = true, keyboardShortcut = SIDEBAR_KEYBOARD_SHORTCUT, ref, className, style, children, ...props }) {
|
|
41
|
+
function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, defaultWidth, minWidth = 224, maxWidth = 420, width: widthProp, onWidthChange, persistOpen = true, keyboardShortcut = SIDEBAR_KEYBOARD_SHORTCUT, layout = "viewport", skipLinkLabel = "Skip to content", contentId: contentIdProp, ref, className, style, children, ...props }) {
|
|
42
42
|
const skin = useSkin();
|
|
43
43
|
const isMobile = useIsMobile(SIDEBAR_MOBILE_BREAKPOINT);
|
|
44
44
|
const [openMobile, setOpenMobile] = useState(false);
|
|
@@ -46,12 +46,17 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
46
46
|
const offcanvasRef = useRef(null);
|
|
47
47
|
const railRef = useRef(null);
|
|
48
48
|
const triggerRef = useRef(null);
|
|
49
|
+
const insetRef = useRef(null);
|
|
49
50
|
const elements = {
|
|
50
51
|
wrapperRef,
|
|
51
52
|
offcanvasRef,
|
|
52
53
|
railRef,
|
|
53
|
-
triggerRef
|
|
54
|
+
triggerRef,
|
|
55
|
+
insetRef
|
|
54
56
|
};
|
|
57
|
+
const sidebarId = useId();
|
|
58
|
+
const generatedContentId = useId();
|
|
59
|
+
const contentId = contentIdProp ?? generatedContentId;
|
|
55
60
|
const [internalWidth, setInternalWidth] = useState(defaultWidth);
|
|
56
61
|
function clampWidth(nextWidth) {
|
|
57
62
|
return Math.min(maxWidth, Math.max(minWidth, nextWidth));
|
|
@@ -67,7 +72,6 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
67
72
|
const open = openProp ?? internalOpen;
|
|
68
73
|
useLayoutEffect(() => {
|
|
69
74
|
if (!open && !isMobile) focusOutsideCollapsedContent({
|
|
70
|
-
wrapperRef,
|
|
71
75
|
offcanvasRef,
|
|
72
76
|
railRef,
|
|
73
77
|
triggerRef
|
|
@@ -87,11 +91,14 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
87
91
|
});
|
|
88
92
|
useEffect(() => {
|
|
89
93
|
if (keyboardShortcut === null) return;
|
|
94
|
+
const shortcut = keyboardShortcut.toLowerCase();
|
|
90
95
|
const handleKeyDown = (event) => {
|
|
91
|
-
if (event.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
if (event.defaultPrevented || event.repeat || event.altKey || event.shiftKey) return;
|
|
97
|
+
if (!(event.metaKey || event.ctrlKey) || event.key.toLowerCase() !== shortcut) return;
|
|
98
|
+
const target = event.target;
|
|
99
|
+
if (target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select") !== null)) return;
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
toggleRef.current();
|
|
95
102
|
};
|
|
96
103
|
window.addEventListener("keydown", handleKeyDown);
|
|
97
104
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
@@ -107,7 +114,11 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
107
114
|
width,
|
|
108
115
|
setWidth,
|
|
109
116
|
minWidth,
|
|
110
|
-
maxWidth
|
|
117
|
+
maxWidth,
|
|
118
|
+
layout,
|
|
119
|
+
keyboardShortcut,
|
|
120
|
+
sidebarId,
|
|
121
|
+
contentId
|
|
111
122
|
};
|
|
112
123
|
const wrapperStyle = {
|
|
113
124
|
"--sidebar-width": skin.sidebarWidth ?? SIDEBAR_WIDTH,
|
|
@@ -115,6 +126,12 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
115
126
|
...style,
|
|
116
127
|
...width === void 0 ? {} : { "--sidebar-width": `${width}px` }
|
|
117
128
|
};
|
|
129
|
+
function skipToContent(event) {
|
|
130
|
+
const inset = insetRef.current;
|
|
131
|
+
if (!inset) return;
|
|
132
|
+
event.preventDefault();
|
|
133
|
+
inset.focus();
|
|
134
|
+
}
|
|
118
135
|
const wrapper = useRender({
|
|
119
136
|
defaultTagName: "div",
|
|
120
137
|
ref: [ref ?? null, wrapperRef],
|
|
@@ -123,9 +140,17 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange, def
|
|
|
123
140
|
"data-control-ui": "sidebar",
|
|
124
141
|
"data-control-family": "sidebar",
|
|
125
142
|
"data-slot": "wrapper",
|
|
143
|
+
"data-layout": layout,
|
|
126
144
|
style: wrapperStyle,
|
|
127
|
-
className: cn("group/sidebar-wrapper flex min-h-
|
|
128
|
-
children
|
|
145
|
+
className: cn("group/sidebar-wrapper relative flex w-full", layout === "contained" ? "h-full min-h-0 overflow-hidden" : "min-h-svh", className),
|
|
146
|
+
children: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("a", {
|
|
147
|
+
href: `#${contentId}`,
|
|
148
|
+
"data-control-ui": "sidebar",
|
|
149
|
+
"data-control-family": "sidebar",
|
|
150
|
+
"data-slot": "skip-link",
|
|
151
|
+
onClick: skipToContent,
|
|
152
|
+
children: skipLinkLabel
|
|
153
|
+
}), children] })
|
|
129
154
|
}
|
|
130
155
|
});
|
|
131
156
|
return /* @__PURE__ */ jsx(SidebarContext.Provider, {
|