rift-ds 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/behaviors/LinkProvider.d.ts +3 -0
- package/behaviors/LocaleProvider.d.ts +27 -0
- package/behaviors/LocaleProvider.js +16 -0
- package/behaviors/direction.css +19 -0
- package/behaviors/direction.d.ts +40 -0
- package/behaviors/direction.js +56 -0
- package/behaviors/focusable.d.ts +2 -1
- package/behaviors/locale.d.ts +47 -0
- package/behaviors/locale.js +87 -0
- package/behaviors/shortcut-keys.d.ts +49 -0
- package/behaviors/shortcut-keys.js +129 -0
- package/behaviors/shortcuts.d.ts +75 -0
- package/behaviors/shortcuts.js +160 -0
- package/behaviors/useAnchoredPosition.d.ts +17 -4
- package/behaviors/useAnchoredPosition.js +8 -3
- package/behaviors/useFocusScope.d.ts +6 -0
- package/behaviors/useFocusScope.js +2 -0
- package/behaviors/useLayer.d.ts +9 -0
- package/behaviors/useLayer.js +4 -0
- package/behaviors/useScrollLock.d.ts +4 -0
- package/bin/rift-ds.mjs +3 -0
- package/chat/ChatWidget.css +24 -24
- package/chat/ChatWidget.js +4 -2
- package/chat/suggestions.d.ts +12 -0
- package/components/Accordion/Accordion.css +1 -1
- package/components/AgentPlan/AgentPlan.css +2 -2
- package/components/AgentRail/AgentRail.css +4 -4
- package/components/AgentRail/AgentRail.js +1 -1
- package/components/AgentStatus/AgentStatus.css +1 -1
- package/components/AiButton/AiButton.css +4 -4
- package/components/AiButton/AiButton.js +2 -1
- package/components/AlertDialog/AlertDialog.css +1 -1
- package/components/AnchorNav/AnchorNav.css +6 -6
- package/components/AnchorNav/AnchorNav.js +4 -2
- package/components/AnimatedNumber/AnimatedNumber.d.ts +6 -0
- package/components/AnimatedNumber/AnimatedNumber.js +12 -5
- package/components/AppLayout/AppLayout.css +3 -3
- package/components/AppSidebar/AppSidebar.css +20 -20
- package/components/AppSidebar/AppSidebar.js +6 -4
- package/components/ArtifactCard/ArtifactCard.css +1 -1
- package/components/ArtifactCard/ArtifactCard.js +2 -1
- package/components/ArtifactPanel/ArtifactPanel.js +2 -1
- package/components/Attachment/Attachment.css +4 -4
- package/components/Attachment/AttachmentDropZone.js +2 -1
- package/components/Attachment/AttachmentGroup.d.ts +2 -0
- package/components/Attachment/AttachmentGroup.js +4 -1
- package/components/Attachment/AttachmentViewer.d.ts +2 -0
- package/components/Attachment/AttachmentViewer.js +8 -13
- package/components/Attachment/fileTypes.d.ts +5 -3
- package/components/Attachment/fileTypes.js +8 -3
- package/components/Avatar/Avatar.css +1 -1
- package/components/AvatarGroup/AvatarGroup.css +1 -1
- package/components/BentoTile/BentoTile.css +15 -3
- package/components/BottomNav/BottomNav.css +6 -6
- package/components/BottomNav/BottomNav.js +3 -1
- package/components/Breadcrumb/Breadcrumb.js +2 -2
- package/components/Button/Button.css +1 -1
- package/components/Button/Button.js +4 -2
- package/components/Card/Card.css +3 -3
- package/components/CardStack/CardStack.js +4 -2
- package/components/Carousel/Carousel.css +5 -2
- package/components/Carousel/Carousel.js +11 -7
- package/components/Chart/AreaChart.d.ts +2 -0
- package/components/Chart/AreaChart.js +15 -6
- package/components/Chart/BarChart.d.ts +2 -0
- package/components/Chart/BarChart.js +15 -5
- package/components/Chart/Chart.css +6 -6
- package/components/Chart/ComboChart.d.ts +2 -0
- package/components/Chart/ComboChart.js +16 -6
- package/components/Chart/LineChart.d.ts +2 -0
- package/components/Chart/LineChart.js +15 -6
- package/components/Chart/PieChart.d.ts +2 -0
- package/components/Chart/PieChart.js +9 -5
- package/components/Chart/RadarChart.d.ts +2 -0
- package/components/Chart/RadarChart.js +15 -6
- package/components/Chart/RadialChart.d.ts +2 -0
- package/components/Chart/RadialChart.js +9 -5
- package/components/Chart/ScatterChart.d.ts +2 -0
- package/components/Chart/ScatterChart.js +17 -7
- package/components/Chart/StackedBarChart.d.ts +2 -0
- package/components/Chart/StackedBarChart.js +15 -7
- package/components/Chart/Treemap.d.ts +2 -0
- package/components/Chart/Treemap.js +9 -5
- package/components/ChatMarker/ChatMarker.js +2 -1
- package/components/ChatMessage/ChatMessage.css +2 -2
- package/components/ChatThread/ChatThread.css +1 -1
- package/components/Checkbox/Checkbox.css +4 -2
- package/components/CircularButton/CircularButton.d.ts +2 -2
- package/components/CircularButton/CircularButton.js +2 -1
- package/components/CodeDiff/CodeDiff.css +2 -2
- package/components/ColorPicker/ColorPicker.css +5 -4
- package/components/ColourSwatch/ColourSwatch.css +1 -1
- package/components/CommandPalette/CommandPalette.d.ts +13 -1
- package/components/CommandPalette/CommandPalette.js +12 -13
- package/components/CommandPaletteTrigger/CommandPaletteTrigger.css +1 -1
- package/components/CommandPaletteTrigger/CommandPaletteTrigger.d.ts +11 -1
- package/components/CommandPaletteTrigger/CommandPaletteTrigger.js +14 -5
- package/components/Composer/Composer.css +4 -4
- package/components/Composer/Composer.d.ts +2 -0
- package/components/Composer/Composer.js +6 -2
- package/components/ContactCard/ContactCard.css +1 -1
- package/components/ContactCard/ContactCard.js +4 -3
- package/components/ContextMenu/ContextMenu.css +10 -7
- package/components/ContextMenu/ContextMenu.d.ts +3 -0
- package/components/ContextMenu/ContextMenu.js +15 -9
- package/components/ContributionGraph/ContributionGraph.css +2 -2
- package/components/ContributionGraph/ContributionGraph.d.ts +7 -1
- package/components/ContributionGraph/ContributionGraph.js +6 -4
- package/components/DataTable/DataTable.css +1 -1
- package/components/DataTable/DataTable.d.ts +9 -3
- package/components/DataTable/DataTable.js +39 -29
- package/components/DataTable/columnTypes.d.ts +2 -2
- package/components/DataTable/columnTypes.js +9 -9
- package/components/DateInput/DateInput.css +4 -4
- package/components/DatePicker/DatePicker.d.ts +23 -7
- package/components/DatePicker/DatePicker.js +41 -34
- package/components/Dialog/Dialog.css +1 -1
- package/components/DocumentChip/DocumentChip.css +1 -1
- package/components/DocumentChip/DocumentChip.js +2 -1
- package/components/Drawer/Drawer.css +46 -12
- package/components/Drawer/Drawer.d.ts +12 -2
- package/components/Drawer/Drawer.js +12 -1
- package/components/Dropdown/ChosenMark.css +1 -1
- package/components/Dropdown/Dropdown.css +1 -1
- package/components/Dropdown/Dropdown.js +4 -3
- package/components/DropdownMenu/DropdownMenu.css +8 -5
- package/components/DropdownMenu/DropdownMenu.d.ts +6 -1
- package/components/DropdownMenu/DropdownMenu.js +15 -9
- package/components/DropdownMenu/ShortcutHint.d.ts +12 -0
- package/components/DropdownMenu/ShortcutHint.js +17 -0
- package/components/EmptyState/EmptyState.js +2 -1
- package/components/EntityCard/EntityCard.js +2 -1
- package/components/EventCalendar/EventCalendar.css +1 -1
- package/components/EventCalendar/EventCalendar.d.ts +21 -6
- package/components/EventCalendar/EventCalendar.js +33 -31
- package/components/FileInput/FileInput.d.ts +2 -0
- package/components/FileInput/FileInput.js +4 -1
- package/components/FilterBar/FilterBar.js +2 -1
- package/components/FunnelChart/FunnelChart.d.ts +2 -0
- package/components/FunnelChart/FunnelChart.js +11 -7
- package/components/GanttChart/GanttChart.css +1 -0
- package/components/GanttChart/GanttChart.js +2 -1
- package/components/Gauge/Gauge.css +1 -1
- package/components/Gauge/Gauge.d.ts +2 -0
- package/components/Gauge/Gauge.js +3 -1
- package/components/Globe/Globe.css +1 -0
- package/components/HoverCard/HoverCard.css +1 -0
- package/components/HoverCard/HoverCard.d.ts +2 -2
- package/components/ImageCompare/ImageCompare.css +1 -0
- package/components/Input/Input.css +8 -8
- package/components/Input/Input.js +3 -2
- package/components/Inspector/Inspector.css +12 -11
- package/components/Inspector/InspectorSlider.d.ts +2 -0
- package/components/Inspector/InspectorSlider.js +8 -1
- package/components/Instructions/Instructions.css +1 -1
- package/components/Instructions/Instructions.js +2 -1
- package/components/InterruptCard/InterruptCard.css +1 -1
- package/components/InterruptCard/InterruptCard.js +2 -1
- package/components/Kbd/Kbd.css +21 -0
- package/components/Kbd/Kbd.d.ts +14 -4
- package/components/Kbd/Kbd.js +10 -1
- package/components/LegendTile/LegendTile.d.ts +6 -1
- package/components/LegendTile/LegendTile.js +3 -2
- package/components/Lightbox/Lightbox.css +3 -3
- package/components/Lightbox/Lightbox.js +6 -14
- package/components/LinkList/LinkList.js +3 -2
- package/components/MapCallout/MapCallout.css +1 -0
- package/components/MegaMenu/MegaMenu.css +271 -0
- package/components/MegaMenu/MegaMenu.d.ts +72 -0
- package/components/MegaMenu/MegaMenu.js +71 -0
- package/components/Mention/Mention.js +2 -1
- package/components/MessageActions/MessageActions.js +2 -1
- package/components/MessageCard/MessageCard.css +1 -1
- package/components/MessageCard/MessageCard.js +2 -1
- package/components/Meter/Meter.css +1 -1
- package/components/Meter/Meter.d.ts +2 -0
- package/components/Meter/Meter.js +3 -1
- package/components/MotionSwatch/MotionSwatch.css +3 -3
- package/components/Nav/Nav.d.ts +7 -2
- package/components/NavList/NavList.css +3 -3
- package/components/NotificationCenter/NotificationCenter.d.ts +2 -0
- package/components/NotificationCenter/NotificationCenter.js +7 -2
- package/components/Pagination/Pagination.d.ts +2 -0
- package/components/Pagination/Pagination.js +6 -2
- package/components/PinInput/PinInput.js +3 -2
- package/components/Popover/Popover.d.ts +2 -2
- package/components/ProgressBar/ProgressBar.css +1 -1
- package/components/ProgressBar/ProgressBar.d.ts +2 -0
- package/components/ProgressBar/ProgressBar.js +3 -5
- package/components/ProgressiveBlur/ProgressiveBlur.css +102 -0
- package/components/ProgressiveBlur/ProgressiveBlur.d.ts +30 -0
- package/components/ProgressiveBlur/ProgressiveBlur.js +27 -0
- package/components/PromptSuggestions/PromptSuggestions.css +11 -4
- package/components/PromptSuggestions/PromptSuggestions.js +3 -1
- package/components/Prose/Prose.css +3 -0
- package/components/QuestionCard/QuestionCard.css +4 -3
- package/components/QuestionCard/QuestionCard.js +2 -8
- package/components/Quote/Quote.css +4 -4
- package/components/RadioButton/RadioButton.css +5 -3
- package/components/Rating/Rating.js +4 -3
- package/components/Reasoning/Reasoning.css +8 -8
- package/components/Reasoning/Reasoning.js +1 -0
- package/components/RichDropdown/RichDropdown.css +4 -3
- package/components/SegmentedControl/SegmentedControl.css +1 -1
- package/components/SegmentedControl/SegmentedControl.js +5 -3
- package/components/SidebarPanel/SidebarPanel.css +7 -7
- package/components/SidebarPanel/SidebarPanel.js +2 -2
- package/components/SiteHeader/SiteHeader.css +305 -0
- package/components/SiteHeader/SiteHeader.d.ts +117 -0
- package/components/SiteHeader/SiteHeader.js +329 -0
- package/components/Skeleton/Skeleton.css +2 -2
- package/components/Skeleton/Skeleton.js +1 -0
- package/components/Slider/Slider.css +16 -1
- package/components/Slider/Slider.js +1 -1
- package/components/SourceChip/SourceChip.d.ts +2 -0
- package/components/SourceChip/SourceChip.js +6 -2
- package/components/SourceTrail/SourceTrail.css +1 -1
- package/components/SpacingSwatch/SpacingSwatch.css +3 -3
- package/components/SplitButton/SplitButton.css +2 -2
- package/components/SplitButton/SplitButton.js +1 -0
- package/components/SplitPane/SplitPane.js +3 -2
- package/components/Stat/Stat.css +1 -1
- package/components/Stat/Stat.d.ts +2 -0
- package/components/Stat/Stat.js +3 -1
- package/components/Stepper/Stepper.css +5 -5
- package/components/Stepper/Stepper.d.ts +2 -0
- package/components/Stepper/Stepper.js +5 -1
- package/components/StreamingText/StreamingText.css +1 -1
- package/components/Table/Table.css +2 -2
- package/components/Table/Table.d.ts +2 -2
- package/components/Table/Table.js +4 -2
- package/components/TableToolbar/TableToolbar.js +2 -1
- package/components/Tabs/Tabs.js +3 -2
- package/components/ThreadPanel/ThreadPanel.css +19 -5
- package/components/ThreadPanel/ThreadPanel.d.ts +6 -1
- package/components/ThreadPanel/ThreadPanel.js +11 -7
- package/components/ThreadTabs/ThreadTabs.css +8 -1
- package/components/ThreadTabs/ThreadTabs.js +4 -2
- package/components/TimePicker/TimePicker.css +1 -1
- package/components/TimePicker/TimePicker.d.ts +17 -4
- package/components/TimePicker/TimePicker.js +21 -3
- package/components/Timeline/Timeline.css +8 -8
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/Timeline/Timeline.js +5 -2
- package/components/Toast/Toast.css +5 -5
- package/components/Toast/Toast.js +3 -2
- package/components/ToggleGroup/ToggleGroup.css +1 -1
- package/components/ToggleSwitch/ToggleSwitch.css +5 -5
- package/components/ToggleSwitch/ToggleSwitch.js +1 -0
- package/components/ToolCall/ToolCall.css +3 -3
- package/components/Toolbar/Toolbar.js +4 -2
- package/components/Tooltip/Tooltip.css +1 -0
- package/components/Tooltip/Tooltip.d.ts +2 -2
- package/components/TopAppBar/TopAppBar.css +2 -2
- package/components/TopAppBar/TopAppBar.js +3 -1
- package/components/TreeView/TreeView.css +1 -1
- package/components/TreeView/TreeView.js +4 -3
- package/components/UsageCard/UsageCard.d.ts +2 -0
- package/components/UsageCard/UsageCard.js +3 -0
- package/components/Widget/Widget.css +1 -1
- package/components/Widget/Widget.d.ts +2 -0
- package/components/Widget/Widget.js +3 -2
- package/components/WorldMap/WorldMap.css +1 -0
- package/components/registry.json +26 -2
- package/components/registry.json.d.ts +26 -2
- package/components/registry.json.js +1 -1
- package/fonts/material-symbols.css +13 -1
- package/fonts/presets/anton-400-latin-ext.woff2 +0 -0
- package/fonts/presets/anton-400-latin.woff2 +0 -0
- package/fonts/presets/work-sans-300-700-latin-ext.woff2 +0 -0
- package/fonts/presets/work-sans-300-700-latin.woff2 +0 -0
- package/index.d.ts +4 -0
- package/index.js +9 -0
- package/package.json +9 -1
- package/tokens/motion.d.ts +2 -0
- package/tokens/motion.js +2 -0
- package/tokens/presets/marquee.css +299 -0
- package/tokens/presets/presets.css +1 -0
- package/tokens/registry.json +6 -0
- package/tokens/registry.json.d.ts +6 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +18 -0
- package/tokens/tokens-light.css +18 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore, useRef, useEffect } from "react";
|
|
3
|
+
import { MOTION_SHORTCUT_SEQUENCE_MS } from "../tokens/motion.js";
|
|
4
|
+
import { warnOnce } from "./devWarning.js";
|
|
5
|
+
import { activeModalPanel } from "./useFocusScope.js";
|
|
6
|
+
import { hasOpenLayer, openLayerContains } from "./useLayer.js";
|
|
7
|
+
import { detectPlatform, parseShortcut, KEY_ALIASES } from "./shortcut-keys.js";
|
|
8
|
+
import { formatShortcut, shortcutAria, shortcutKeys } from "./shortcut-keys.js";
|
|
9
|
+
const noSubscription = () => () => {
|
|
10
|
+
};
|
|
11
|
+
function usePlatform() {
|
|
12
|
+
return useSyncExternalStore(noSubscription, detectPlatform, () => "other");
|
|
13
|
+
}
|
|
14
|
+
const eventKey = (event) => {
|
|
15
|
+
const key = event.key.toLowerCase();
|
|
16
|
+
return KEY_ALIASES[key] ?? key;
|
|
17
|
+
};
|
|
18
|
+
const codeKey = (event) => {
|
|
19
|
+
const match = /^(?:Key([A-Z])|Digit(\d))$/.exec(event.code ?? "");
|
|
20
|
+
return match ? (match[1] ?? match[2]).toLowerCase() : null;
|
|
21
|
+
};
|
|
22
|
+
const matchesStep = (step, event, platform) => {
|
|
23
|
+
const ctrl = step.ctrl || step.mod && platform === "other";
|
|
24
|
+
const meta = step.meta || step.mod && platform === "apple";
|
|
25
|
+
if (event.ctrlKey !== ctrl || event.metaKey !== meta || event.altKey !== step.alt) return false;
|
|
26
|
+
const symbol = step.key.length === 1 && !/[a-z0-9]/.test(step.key);
|
|
27
|
+
if (!symbol && event.shiftKey !== step.shift) return false;
|
|
28
|
+
return eventKey(event) === step.key || codeKey(event) === step.key;
|
|
29
|
+
};
|
|
30
|
+
const isTextField = (target) => {
|
|
31
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
32
|
+
if (target.isContentEditable) return true;
|
|
33
|
+
if (target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) return true;
|
|
34
|
+
if (target instanceof HTMLInputElement) {
|
|
35
|
+
return !["checkbox", "radio", "button", "submit", "reset", "range", "color", "file", "image"].includes(target.type);
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
};
|
|
39
|
+
const registrations = [];
|
|
40
|
+
let version = 0;
|
|
41
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
42
|
+
const notify = () => {
|
|
43
|
+
version += 1;
|
|
44
|
+
for (const listener of listeners) listener();
|
|
45
|
+
};
|
|
46
|
+
let recent = [];
|
|
47
|
+
const eligible = (registration, target) => {
|
|
48
|
+
const options = registration.optionsRef.current;
|
|
49
|
+
if (options.enabled === false) return false;
|
|
50
|
+
if (isTextField(target) && !options.allowInInput) return false;
|
|
51
|
+
if (options.global) return true;
|
|
52
|
+
const modal = activeModalPanel();
|
|
53
|
+
const node = target instanceof Node ? target : null;
|
|
54
|
+
const unfocused = !node || node === document.body || node === document.documentElement;
|
|
55
|
+
const scope = options.scope?.current;
|
|
56
|
+
if (scope) {
|
|
57
|
+
if (!unfocused) return scope.contains(node);
|
|
58
|
+
return modal ? modal.contains(scope) : !openLayerContains(scope);
|
|
59
|
+
}
|
|
60
|
+
if (modal) return false;
|
|
61
|
+
return unfocused || !openLayerContains(node);
|
|
62
|
+
};
|
|
63
|
+
const handleKeyDown = (event) => {
|
|
64
|
+
if (event.isComposing || event.defaultPrevented) return;
|
|
65
|
+
if (event.key === "Escape" && hasOpenLayer()) return;
|
|
66
|
+
if (["Shift", "Control", "Alt", "Meta"].includes(event.key)) return;
|
|
67
|
+
const now = event.timeStamp || performance.now();
|
|
68
|
+
const last = recent[recent.length - 1];
|
|
69
|
+
if (last && now - last.at > MOTION_SHORTCUT_SEQUENCE_MS) recent = [];
|
|
70
|
+
recent = [...recent.slice(-3), { event, at: now }];
|
|
71
|
+
const platform = detectPlatform();
|
|
72
|
+
let best = null;
|
|
73
|
+
registrations.forEach((registration2, index) => {
|
|
74
|
+
if (!eligible(registration2, event.target)) return;
|
|
75
|
+
for (const steps of registration2.steps) {
|
|
76
|
+
if (steps.length > recent.length) continue;
|
|
77
|
+
const tail = recent.slice(recent.length - steps.length);
|
|
78
|
+
if (!steps.every((step, i) => matchesStep(step, tail[i].event, platform))) continue;
|
|
79
|
+
if (!best || steps.length > best.length || steps.length === best.length && index > best.index) {
|
|
80
|
+
best = { registration: registration2, length: steps.length, index };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
if (!best) return;
|
|
85
|
+
const { registration } = best;
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
recent = [];
|
|
88
|
+
registration.handlerRef.current(event);
|
|
89
|
+
};
|
|
90
|
+
const register = (registration) => {
|
|
91
|
+
for (const shortcut of registration.shortcuts) {
|
|
92
|
+
const scope = registration.optionsRef.current.scope;
|
|
93
|
+
const clash = registrations.find(
|
|
94
|
+
(other) => other.optionsRef.current.enabled !== false && other.optionsRef.current.scope === scope && other.shortcuts.includes(shortcut)
|
|
95
|
+
);
|
|
96
|
+
if (clash && registration.optionsRef.current.enabled !== false) {
|
|
97
|
+
warnOnce(`The shortcut "${shortcut}" is registered twice in one scope; the one registered last wins.`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
registrations.push(registration);
|
|
101
|
+
if (registrations.length === 1) document.addEventListener("keydown", handleKeyDown);
|
|
102
|
+
notify();
|
|
103
|
+
return () => {
|
|
104
|
+
const index = registrations.indexOf(registration);
|
|
105
|
+
if (index !== -1) registrations.splice(index, 1);
|
|
106
|
+
if (registrations.length === 0) {
|
|
107
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
108
|
+
recent = [];
|
|
109
|
+
}
|
|
110
|
+
notify();
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
function useShortcut(shortcut, handler, options = {}) {
|
|
114
|
+
const handlerRef = useRef(handler);
|
|
115
|
+
const optionsRef = useRef(options);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
handlerRef.current = handler;
|
|
118
|
+
optionsRef.current = options;
|
|
119
|
+
});
|
|
120
|
+
const shortcuts = Array.isArray(shortcut) ? shortcut : [shortcut];
|
|
121
|
+
const key = shortcuts.join("\0");
|
|
122
|
+
const enabled = options.enabled !== false;
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!enabled) return;
|
|
125
|
+
const list = key.split("\0");
|
|
126
|
+
return register({ shortcuts: list, steps: list.map(parseShortcut), handlerRef, optionsRef });
|
|
127
|
+
}, [key, enabled]);
|
|
128
|
+
}
|
|
129
|
+
const subscribe = (listener) => {
|
|
130
|
+
listeners.add(listener);
|
|
131
|
+
return () => listeners.delete(listener);
|
|
132
|
+
};
|
|
133
|
+
let snapshot = { version: -1, list: [] };
|
|
134
|
+
const readRegistered = () => {
|
|
135
|
+
if (snapshot.version !== version) {
|
|
136
|
+
snapshot = {
|
|
137
|
+
version,
|
|
138
|
+
list: registrations.filter((r) => r.optionsRef.current.enabled !== false && r.optionsRef.current.description).map((r) => ({
|
|
139
|
+
shortcuts: r.shortcuts,
|
|
140
|
+
description: r.optionsRef.current.description ?? "",
|
|
141
|
+
group: r.optionsRef.current.group
|
|
142
|
+
}))
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return snapshot.list;
|
|
146
|
+
};
|
|
147
|
+
const EMPTY = [];
|
|
148
|
+
function useRegisteredShortcuts() {
|
|
149
|
+
return useSyncExternalStore(subscribe, readRegistered, () => EMPTY);
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
detectPlatform,
|
|
153
|
+
formatShortcut,
|
|
154
|
+
parseShortcut,
|
|
155
|
+
shortcutAria,
|
|
156
|
+
shortcutKeys,
|
|
157
|
+
usePlatform,
|
|
158
|
+
useRegisteredShortcuts,
|
|
159
|
+
useShortcut
|
|
160
|
+
};
|
|
@@ -46,6 +46,8 @@
|
|
|
46
46
|
* overflow does the room narrow to its box.
|
|
47
47
|
*/
|
|
48
48
|
export type AnchoredSide = 'top' | 'bottom' | 'left' | 'right';
|
|
49
|
+
/** A side a caller can ask for: a screen side, or `start` / `end` of the reading direction. */
|
|
50
|
+
export type AnchoredSideRequest = AnchoredSide | 'start' | 'end';
|
|
49
51
|
export type AnchoredAlign = 'start' | 'center' | 'end';
|
|
50
52
|
export type AnchoredPlacement = {
|
|
51
53
|
/** The side the panel took after flipping. */
|
|
@@ -71,9 +73,20 @@ export type AnchoredPositionOptions = {
|
|
|
71
73
|
anchorRef: React.RefObject<HTMLElement | null>;
|
|
72
74
|
/** The panel being placed. */
|
|
73
75
|
panelRef: React.RefObject<HTMLElement | null>;
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
/**
|
|
77
|
+
* The preferred side. Default `bottom`. `start` and `end` resolve against
|
|
78
|
+
* the anchor's reading direction at placement time (`start` is the left
|
|
79
|
+
* in English, the right in Arabic); the placement reports the screen side
|
|
80
|
+
* it took.
|
|
81
|
+
*/
|
|
82
|
+
side?: AnchoredSideRequest;
|
|
83
|
+
/**
|
|
84
|
+
* Where along that side the panel lines up with the anchor. Default
|
|
85
|
+
* `start`. On the top and bottom sides `start` and `end` follow the
|
|
86
|
+
* anchor's reading direction, so a menu lines up with its trigger's
|
|
87
|
+
* leading edge in either. The panel's `data-align` reports the screen
|
|
88
|
+
* alignment it took (`start` is the left edge), like `data-side`.
|
|
89
|
+
*/
|
|
77
90
|
align?: AnchoredAlign;
|
|
78
91
|
/**
|
|
79
92
|
* The custom property that holds the gap between anchor and panel, read
|
|
@@ -108,4 +121,4 @@ export type AnchoredPositionOptions = {
|
|
|
108
121
|
*/
|
|
109
122
|
export declare function fixedContainingBlock(element: HTMLElement): HTMLElement | null;
|
|
110
123
|
/** Places `panelRef` against `anchorRef` while `open`. See the module comment. */
|
|
111
|
-
export declare function useAnchoredPosition({ open, anchorRef, panelRef, side, align, gapProperty, edgeProperty, flip, fitHeight, matchWidth, onPlace, target, }: AnchoredPositionOptions): void;
|
|
124
|
+
export declare function useAnchoredPosition({ open, anchorRef, panelRef, side: sideRequest, align: alignRequest, gapProperty, edgeProperty, flip, fitHeight, matchWidth, onPlace, target, }: AnchoredPositionOptions): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useRef, useLayoutEffect } from "react";
|
|
3
|
+
import { isRtl } from "./direction.js";
|
|
3
4
|
function fixedContainingBlock(element) {
|
|
4
5
|
for (let node = element.parentElement; node; node = node.parentElement) {
|
|
5
6
|
const style = getComputedStyle(node);
|
|
@@ -21,8 +22,8 @@ function useAnchoredPosition({
|
|
|
21
22
|
open,
|
|
22
23
|
anchorRef,
|
|
23
24
|
panelRef,
|
|
24
|
-
side = "bottom",
|
|
25
|
-
align = "start",
|
|
25
|
+
side: sideRequest = "bottom",
|
|
26
|
+
align: alignRequest = "start",
|
|
26
27
|
gapProperty = "--gap-200",
|
|
27
28
|
edgeProperty = "--gap-200",
|
|
28
29
|
flip = true,
|
|
@@ -64,6 +65,10 @@ function useAnchoredPosition({
|
|
|
64
65
|
bounds.bottom = Math.min(bounds.bottom, origin.top + block.clientHeight);
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
const rtl = isRtl(anchor);
|
|
69
|
+
const side = sideRequest === "start" ? rtl ? "right" : "left" : sideRequest === "end" ? rtl ? "left" : "right" : sideRequest;
|
|
70
|
+
const flipsAlign = rtl && (side === "top" || side === "bottom") && alignRequest !== "center";
|
|
71
|
+
const align = flipsAlign ? alignRequest === "start" ? "end" : "start" : alignRequest;
|
|
67
72
|
const a = anchor.getBoundingClientRect();
|
|
68
73
|
const panelStyle = getComputedStyle(panel);
|
|
69
74
|
const gap = parseFloat(panelStyle.getPropertyValue(gapProperty)) || 0;
|
|
@@ -145,7 +150,7 @@ function useAnchoredPosition({
|
|
|
145
150
|
panel.style.removeProperty("visibility");
|
|
146
151
|
}
|
|
147
152
|
};
|
|
148
|
-
}, [open, target, anchorRef, panelRef,
|
|
153
|
+
}, [open, target, anchorRef, panelRef, sideRequest, alignRequest, gapProperty, edgeProperty, flip, fitHeight, matchWidth]);
|
|
149
154
|
}
|
|
150
155
|
export {
|
|
151
156
|
fixedContainingBlock,
|
|
@@ -47,5 +47,11 @@ type FocusScopeOptions = {
|
|
|
47
47
|
/** Make everything outside the scope inert while active. Default true. */
|
|
48
48
|
inertOutside?: boolean;
|
|
49
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* The panel of the topmost modal scope that isolates the page, or null when
|
|
52
|
+
* none is open. Keyboard shortcuts read it: while a modal is open, only the
|
|
53
|
+
* shortcuts that live inside it (or are global) may fire.
|
|
54
|
+
*/
|
|
55
|
+
export declare const activeModalPanel: () => HTMLElement | null;
|
|
50
56
|
export declare function useFocusScope(ref: React.RefObject<HTMLElement | null>, options: FocusScopeOptions): void;
|
|
51
57
|
export {};
|
|
@@ -23,6 +23,7 @@ const applyInert = () => {
|
|
|
23
23
|
inerted.clear();
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
+
const activeModalPanel = () => inertScopes[inertScopes.length - 1]?.panel ?? null;
|
|
26
27
|
const isVisible = (el) => el.getClientRects().length > 0;
|
|
27
28
|
const restoreTarget = (previous) => {
|
|
28
29
|
if (!document.contains(previous)) return null;
|
|
@@ -92,5 +93,6 @@ function useFocusScope(ref, options) {
|
|
|
92
93
|
}, [active, ref]);
|
|
93
94
|
}
|
|
94
95
|
export {
|
|
96
|
+
activeModalPanel,
|
|
95
97
|
useFocusScope
|
|
96
98
|
};
|
package/behaviors/useLayer.d.ts
CHANGED
|
@@ -58,6 +58,15 @@ export type LayerHandle = {
|
|
|
58
58
|
*/
|
|
59
59
|
ownsPress: () => boolean;
|
|
60
60
|
};
|
|
61
|
+
/**
|
|
62
|
+
* Whether `node` sits inside an open layer that names its elements: a
|
|
63
|
+
* popover, menu or listbox holding focus, or a modal panel. Keyboard
|
|
64
|
+
* shortcuts read it, so a page shortcut never fires while focus is in an
|
|
65
|
+
* overlay that has its own keys.
|
|
66
|
+
*/
|
|
67
|
+
export declare const openLayerContains: (node: Node) => boolean;
|
|
68
|
+
/** Whether any layer is open. Escape belongs to the stack while one is, so keyboard shortcuts leave it alone. */
|
|
69
|
+
export declare const hasOpenLayer: () => boolean;
|
|
61
70
|
/**
|
|
62
71
|
* Register an overlay on the dismissal stack while `open` is true. Options
|
|
63
72
|
* are read at event time, so a `dismissOnEscape` toggle takes effect without
|
package/behaviors/useLayer.js
CHANGED
|
@@ -4,6 +4,8 @@ const layers = [];
|
|
|
4
4
|
let listenersInstalled = false;
|
|
5
5
|
let pressOwner = null;
|
|
6
6
|
const contains = (layer, target) => (layer.optionsRef.current.getElements?.() ?? []).some((el) => el?.contains(target));
|
|
7
|
+
const openLayerContains = (node) => layers.some((layer) => contains(layer, node));
|
|
8
|
+
const hasOpenLayer = () => layers.length > 0;
|
|
7
9
|
const handleKeyDown = (event) => {
|
|
8
10
|
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
9
11
|
const top = layers[layers.length - 1];
|
|
@@ -63,5 +65,7 @@ function useLayer(options) {
|
|
|
63
65
|
return { ownsPress };
|
|
64
66
|
}
|
|
65
67
|
export {
|
|
68
|
+
hasOpenLayer,
|
|
69
|
+
openLayerContains,
|
|
66
70
|
useLayer
|
|
67
71
|
};
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
* swapping the modals onto it would change their scrollbar rendering.
|
|
32
32
|
* Instances are independent — overlapping cancel-events locks stack
|
|
33
33
|
* harmlessly.
|
|
34
|
+
*
|
|
35
|
+
* Published as the `./behaviors/useScrollLock` subpath so host chrome can
|
|
36
|
+
* join the counter; with LinkProvider it is one of only two behaviors that
|
|
37
|
+
* are. The rest of src/behaviors stays internal.
|
|
34
38
|
*/
|
|
35
39
|
type ScrollLockOptions = {
|
|
36
40
|
/** Which locking strategy to use. Default `'pin'`. */
|
package/bin/rift-ds.mjs
CHANGED
|
@@ -42,6 +42,9 @@
|
|
|
42
42
|
* the disk: a skill name is one kebab-case folder, a file is a plain
|
|
43
43
|
* relative path, and nothing may climb out of the target folder.
|
|
44
44
|
*
|
|
45
|
+
* A bin and never an exports subpath: nothing imports it, and build-package.mjs
|
|
46
|
+
* ships it as dist/bin/<BIN_NAME>.mjs.
|
|
47
|
+
*
|
|
45
48
|
* Zero dependencies by design: global fetch plus node:fs, so npx never
|
|
46
49
|
* installs anything beyond the package itself. SITE_ORIGIN, SKILL_NAME,
|
|
47
50
|
* MCP_SERVER_NAME and PACKAGE_NAME are stamped by build-package.mjs from
|
package/chat/ChatWidget.css
CHANGED
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
font-weight: var(--font-sub-display-weight);
|
|
190
190
|
line-height: var(--font-sub-display-line-height);
|
|
191
191
|
letter-spacing: var(--font-sub-display-letter-spacing);
|
|
192
|
-
color: var(--color-text-
|
|
192
|
+
color: var(--color-text-display);
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/* The panel is a viewport of its own. tokens-typography.css collapses
|
|
@@ -562,7 +562,7 @@
|
|
|
562
562
|
flex: none;
|
|
563
563
|
display: flex;
|
|
564
564
|
min-height: 0;
|
|
565
|
-
border-
|
|
565
|
+
border-inline-end: var(--border-025) solid var(--color-bg-container-border);
|
|
566
566
|
}
|
|
567
567
|
|
|
568
568
|
/* The sheet layer: hidden entirely (visibility) while closed, so nothing in
|
|
@@ -604,13 +604,13 @@
|
|
|
604
604
|
position: absolute;
|
|
605
605
|
top: 0;
|
|
606
606
|
bottom: 0;
|
|
607
|
-
|
|
607
|
+
inset-inline-start: 0;
|
|
608
608
|
display: flex;
|
|
609
609
|
background-color: var(--color-bg-glass);
|
|
610
610
|
backdrop-filter: blur(24px);
|
|
611
|
-
border-
|
|
611
|
+
border-inline-end: var(--border-025) solid var(--color-bg-container-border);
|
|
612
612
|
box-shadow: var(--shadow-floating);
|
|
613
|
-
transform: translateX(-100%);
|
|
613
|
+
transform: translateX(calc(-100% * var(--ds-inline-sign, 1)));
|
|
614
614
|
transition: transform var(--motion-duration-slow) var(--motion-ease-emphasized);
|
|
615
615
|
}
|
|
616
616
|
|
|
@@ -655,7 +655,7 @@
|
|
|
655
655
|
/* Before the first measurement there is no number to glide to, so the
|
|
656
656
|
rail simply takes its content's width. */
|
|
657
657
|
width: var(--ds-chat-aside-width, max-content);
|
|
658
|
-
margin-
|
|
658
|
+
margin-inline-end: var(--padding-500);
|
|
659
659
|
opacity: 1;
|
|
660
660
|
visibility: visible;
|
|
661
661
|
transition:
|
|
@@ -728,7 +728,7 @@
|
|
|
728
728
|
|
|
729
729
|
.ds-chat-widget__artifact-rail--open {
|
|
730
730
|
flex-grow: 1.2;
|
|
731
|
-
margin-
|
|
731
|
+
margin-inline-end: var(--padding-500);
|
|
732
732
|
opacity: 1;
|
|
733
733
|
visibility: visible;
|
|
734
734
|
transition:
|
|
@@ -798,7 +798,7 @@
|
|
|
798
798
|
position: absolute;
|
|
799
799
|
top: 0;
|
|
800
800
|
bottom: 0;
|
|
801
|
-
|
|
801
|
+
inset-inline-start: -10px;
|
|
802
802
|
width: 20px;
|
|
803
803
|
}
|
|
804
804
|
|
|
@@ -806,7 +806,7 @@
|
|
|
806
806
|
content: "";
|
|
807
807
|
position: absolute;
|
|
808
808
|
top: calc(50% - 24px);
|
|
809
|
-
|
|
809
|
+
inset-inline-start: -2px;
|
|
810
810
|
width: 4px;
|
|
811
811
|
height: 48px;
|
|
812
812
|
border-radius: var(--radius-pill);
|
|
@@ -833,7 +833,7 @@
|
|
|
833
833
|
|
|
834
834
|
.ds-chat-widget__rails[data-artifact-expanded] > .ds-chat-widget__artifact-rail--open {
|
|
835
835
|
flex: 1 1 0;
|
|
836
|
-
margin-
|
|
836
|
+
margin-inline-start: var(--padding-500);
|
|
837
837
|
}
|
|
838
838
|
|
|
839
839
|
/* The sheet runs nearly the widget's height: a preview has no natural
|
|
@@ -859,7 +859,7 @@
|
|
|
859
859
|
.ds-chat-widget__rail-actions {
|
|
860
860
|
position: absolute;
|
|
861
861
|
top: calc(var(--padding-200) + var(--padding-150));
|
|
862
|
-
|
|
862
|
+
inset-inline-end: var(--padding-500);
|
|
863
863
|
z-index: 6;
|
|
864
864
|
display: flex;
|
|
865
865
|
align-items: center;
|
|
@@ -925,7 +925,7 @@
|
|
|
925
925
|
top: var(--ds-chat-inset);
|
|
926
926
|
/* Placed from the left on both docks, so one property carries every move
|
|
927
927
|
the card makes and they all glide. */
|
|
928
|
-
left: calc(100% - var(--ds-chat-width) - var(--ds-chat-inset));
|
|
928
|
+
left: calc(100% - var(--ds-chat-width) - var(--ds-chat-inset)); /* ds-allow(physical): the panel is placed on a dock the visitor picks by screen edge (src/chat/placement.ts), not by reading direction */
|
|
929
929
|
height: calc(100dvh - var(--ds-chat-inset) * 2);
|
|
930
930
|
width: var(--ds-chat-width);
|
|
931
931
|
max-width: calc(100vw - var(--ds-chat-inset) * 2);
|
|
@@ -992,7 +992,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
992
992
|
|
|
993
993
|
/* The left dock: the same card on the other edge. */
|
|
994
994
|
.ds-chat-launcher__panel--left {
|
|
995
|
-
left: var(--ds-chat-inset);
|
|
995
|
+
left: var(--ds-chat-inset); /* ds-allow(physical): the left dock is the screen's left edge */
|
|
996
996
|
}
|
|
997
997
|
|
|
998
998
|
/* Fullscreen view: a true viewport takeover. The stronger blur keeps the
|
|
@@ -1000,7 +1000,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1000
1000
|
border fades rather than vanishing, so the geometry never snaps mid-glide. */
|
|
1001
1001
|
.ds-chat-launcher__panel--full {
|
|
1002
1002
|
top: 0;
|
|
1003
|
-
left: 0;
|
|
1003
|
+
left: 0; /* ds-allow(physical): fullscreen covers the viewport from its corner */
|
|
1004
1004
|
height: 100dvh;
|
|
1005
1005
|
width: 100vw;
|
|
1006
1006
|
max-width: 100vw;
|
|
@@ -1032,7 +1032,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1032
1032
|
position: fixed;
|
|
1033
1033
|
top: var(--ds-chat-inset);
|
|
1034
1034
|
height: calc(100dvh - var(--ds-chat-inset) * 2);
|
|
1035
|
-
right: calc(var(--ds-chat-inset) + var(--ds-chat-width) - 10px);
|
|
1035
|
+
right: calc(var(--ds-chat-inset) + var(--ds-chat-width) - 10px); /* ds-allow(physical): the dock grip tracks the docked card's screen edge */
|
|
1036
1036
|
width: 20px;
|
|
1037
1037
|
display: flex;
|
|
1038
1038
|
align-items: center;
|
|
@@ -1044,7 +1044,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1044
1044
|
|
|
1045
1045
|
.ds-chat-launcher__dock-handle--left {
|
|
1046
1046
|
right: auto;
|
|
1047
|
-
left: calc(var(--ds-chat-inset) + var(--ds-chat-width) - 10px);
|
|
1047
|
+
left: calc(var(--ds-chat-inset) + var(--ds-chat-width) - 10px); /* ds-allow(physical): the dock grip tracks the docked card's screen edge */
|
|
1048
1048
|
}
|
|
1049
1049
|
|
|
1050
1050
|
.ds-chat-launcher__dock-handle::after {
|
|
@@ -1089,7 +1089,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1089
1089
|
calc(100dvh - var(--ds-chat-inset) * 2)
|
|
1090
1090
|
);
|
|
1091
1091
|
top: var(--ds-chat-float-y, calc(100dvh - var(--ds-chat-float-h) - var(--ds-chat-inset)));
|
|
1092
|
-
left: var(--ds-chat-float-x, calc(100% - var(--ds-chat-width) - var(--ds-chat-inset)));
|
|
1092
|
+
left: var(--ds-chat-float-x, calc(100% - var(--ds-chat-width) - var(--ds-chat-inset))); /* ds-allow(physical): the floating card sits where the visitor dragged it, in screen pixels */
|
|
1093
1093
|
width: var(--ds-chat-float-w, var(--ds-chat-width));
|
|
1094
1094
|
height: var(--ds-chat-float-h);
|
|
1095
1095
|
max-height: 100dvh;
|
|
@@ -1125,8 +1125,8 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1125
1125
|
|
|
1126
1126
|
.ds-chat-launcher__float-grip[data-dir="n"] { top: 0; }
|
|
1127
1127
|
.ds-chat-launcher__float-grip[data-dir="s"] { bottom: 0; }
|
|
1128
|
-
.ds-chat-launcher__float-grip[data-dir="e"] { right: 0; }
|
|
1129
|
-
.ds-chat-launcher__float-grip[data-dir="w"] { left: 0; }
|
|
1128
|
+
.ds-chat-launcher__float-grip[data-dir="e"] { right: 0; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen edge */
|
|
1129
|
+
.ds-chat-launcher__float-grip[data-dir="w"] { left: 0; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen edge */
|
|
1130
1130
|
|
|
1131
1131
|
.ds-chat-launcher__float-grip[data-dir="ne"],
|
|
1132
1132
|
.ds-chat-launcher__float-grip[data-dir="nw"],
|
|
@@ -1136,10 +1136,10 @@ html[data-chat-resizing] .ds-chat-launcher__panel {
|
|
|
1136
1136
|
height: 16px;
|
|
1137
1137
|
}
|
|
1138
1138
|
|
|
1139
|
-
.ds-chat-launcher__float-grip[data-dir="ne"] { top: 0; right: 0; cursor: nesw-resize; }
|
|
1140
|
-
.ds-chat-launcher__float-grip[data-dir="sw"] { bottom: 0; left: 0; cursor: nesw-resize; }
|
|
1141
|
-
.ds-chat-launcher__float-grip[data-dir="nw"] { top: 0; left: 0; cursor: nwse-resize; }
|
|
1142
|
-
.ds-chat-launcher__float-grip[data-dir="se"] { bottom: 0; right: 0; cursor: nwse-resize; }
|
|
1139
|
+
.ds-chat-launcher__float-grip[data-dir="ne"] { top: 0; right: 0; cursor: nesw-resize; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen corner */
|
|
1140
|
+
.ds-chat-launcher__float-grip[data-dir="sw"] { bottom: 0; left: 0; cursor: nesw-resize; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen corner */
|
|
1141
|
+
.ds-chat-launcher__float-grip[data-dir="nw"] { top: 0; left: 0; cursor: nwse-resize; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen corner */
|
|
1142
|
+
.ds-chat-launcher__float-grip[data-dir="se"] { bottom: 0; right: 0; cursor: nwse-resize; } /* ds-allow(physical): a compass grip resizes the floating card toward that screen corner */
|
|
1143
1143
|
|
|
1144
1144
|
.ds-chat-launcher__float-grip[data-dir="n"]::after,
|
|
1145
1145
|
.ds-chat-launcher__float-grip[data-dir="s"]::after,
|
|
@@ -1209,7 +1209,7 @@ html[data-chat-resizing] .ds-chat-launcher__panel--floating .ds-chat-header {
|
|
|
1209
1209
|
|
|
1210
1210
|
.ds-chat-launcher__fab {
|
|
1211
1211
|
position: fixed;
|
|
1212
|
-
right: var(--ds-chat-inset);
|
|
1212
|
+
right: var(--ds-chat-inset); /* ds-allow(physical): the launcher sits in the corner the default dock opens from, a screen corner like the docks */
|
|
1213
1213
|
bottom: var(--ds-chat-inset);
|
|
1214
1214
|
z-index: var(--layer-chat-launcher);
|
|
1215
1215
|
}
|
package/chat/ChatWidget.js
CHANGED
|
@@ -32,6 +32,8 @@ import { ReplyBody } from "./TurnQuestion.js";
|
|
|
32
32
|
import { ResponseActionsLabelsContext } from "./ResponseActions.js";
|
|
33
33
|
import { FollowupSuggestionsLabelContext } from "./FollowupSuggestions.js";
|
|
34
34
|
import "./ChatWidget.css";
|
|
35
|
+
import "../behaviors/direction.css";
|
|
36
|
+
import { inlineSign } from "../behaviors/direction.js";
|
|
35
37
|
const DEFAULT_MAX_ATTACHMENTS = 10;
|
|
36
38
|
const DEFAULT_MAX_ATTACHMENT_BYTES = 50 * 1024 * 1024;
|
|
37
39
|
const LONG_PASTE_CHARS = 1200;
|
|
@@ -287,14 +289,14 @@ function ChatWidget({
|
|
|
287
289
|
if (!rail || !column) return;
|
|
288
290
|
const width = rail.getBoundingClientRect().width;
|
|
289
291
|
const spare = column.getBoundingClientRect().width - ARTIFACT_MIN_COLUMN_WIDTH;
|
|
290
|
-
artifactDragRef.current = { startX: e.clientX, width, max: width + Math.max(0, spare), next: width };
|
|
292
|
+
artifactDragRef.current = { startX: e.clientX, width, max: width + Math.max(0, spare), next: width, sign: inlineSign(rail) };
|
|
291
293
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
292
294
|
setArtifactResizing(true);
|
|
293
295
|
};
|
|
294
296
|
const moveArtifactResize = (e) => {
|
|
295
297
|
const drag = artifactDragRef.current;
|
|
296
298
|
if (!drag) return;
|
|
297
|
-
const grown = drag.width - (e.clientX - drag.startX);
|
|
299
|
+
const grown = drag.width - (e.clientX - drag.startX) * drag.sign;
|
|
298
300
|
drag.next = Math.round(Math.min(drag.max, Math.max(ARTIFACT_MIN_COLUMN_WIDTH, grown)));
|
|
299
301
|
railsHostRef.current?.style.setProperty("--ds-chat-artifact-width", `${drag.next}px`);
|
|
300
302
|
};
|
package/chat/suggestions.d.ts
CHANGED
|
@@ -16,6 +16,18 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Every producer of a suggestion checks against it. A suggestion that will
|
|
18
18
|
* not fit is dropped, never truncated: half a question is not a question.
|
|
19
|
+
*
|
|
20
|
+
* The FAB summary panel's chips render through the same row, so they share
|
|
21
|
+
* the budget too. It lives in the package rather than the site so every
|
|
22
|
+
* consumer's chat holds the same line. The enforcement points: the
|
|
23
|
+
* follow-ups model is told the number in its prompt (server.ts), the
|
|
24
|
+
* follow-ups route drops a long one rather than clipping it, and the
|
|
25
|
+
* options of a question the agent asks are held to it as well (the
|
|
26
|
+
* `ask_user` input schema tells the model the number, and
|
|
27
|
+
* `sanitizeQuestionSet` in questions.ts drops a question whose option
|
|
28
|
+
* outruns it). Written copy is a build check: validate-chat-starters.mjs
|
|
29
|
+
* holds the starters, follow-ups and the demo script's question options,
|
|
30
|
+
* and validate-page-summaries.mjs the summary panel's chips.
|
|
19
31
|
*/
|
|
20
32
|
export declare const SUGGESTION_MAX_CHARS = 40;
|
|
21
33
|
/** Whether a suggestion label is one the chip row can actually show. */
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
padding: var(--padding-200) var(--padding-500);
|
|
35
35
|
background: none;
|
|
36
36
|
border: none;
|
|
37
|
-
text-align:
|
|
37
|
+
text-align: start;
|
|
38
38
|
cursor: pointer;
|
|
39
39
|
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
40
40
|
}
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
position: absolute;
|
|
142
142
|
top: calc(var(--padding-100) + var(--icon-size-500));
|
|
143
143
|
bottom: calc(-1 * var(--padding-100));
|
|
144
|
-
|
|
144
|
+
inset-inline-start: calc(var(--icon-size-500) / 2);
|
|
145
145
|
width: var(--border-025);
|
|
146
146
|
background-color: var(--color-divider);
|
|
147
147
|
}
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
`--ds-agent-rail-collapse-top` is the seat, which a host overrides to
|
|
54
54
|
line the chevron up with its own header row. */
|
|
55
55
|
top: var(--ds-agent-rail-collapse-top, var(--padding-300));
|
|
56
|
-
|
|
56
|
+
inset-inline-start: var(--padding-300);
|
|
57
57
|
z-index: 1;
|
|
58
58
|
display: inline-flex;
|
|
59
59
|
align-items: center;
|
|
@@ -77,8 +77,8 @@
|
|
|
77
77
|
way out usually sits. The host that asks for it has decided its controls
|
|
78
78
|
and this one do not collide. */
|
|
79
79
|
.ds-agent-rail__collapse--close {
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
inset-inline-start: auto;
|
|
81
|
+
inset-inline-end: var(--padding-300);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
.ds-agent-rail__collapse .material-symbols-rounded {
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
annotate. The offset puts the circle's centre roughly on the portrait's
|
|
147
147
|
45-degree point, so it straddles the edge the way a badge should and the
|
|
148
148
|
glyph underneath stays whole. */
|
|
149
|
-
|
|
149
|
+
inset-inline-end: -6px;
|
|
150
150
|
bottom: -6px;
|
|
151
151
|
display: inline-flex;
|
|
152
152
|
align-items: center;
|
|
@@ -37,7 +37,7 @@ const AgentRail = React.forwardRef(
|
|
|
37
37
|
className: `${baseClass}__collapse${collapseVariant === "close" ? ` ${baseClass}__collapse--close` : ""}`,
|
|
38
38
|
"aria-label": collapseLabel,
|
|
39
39
|
onClick: onCollapse,
|
|
40
|
-
children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", "aria-hidden": "true", children: collapseVariant === "close" ? "close" : "chevron_right" })
|
|
40
|
+
children: /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded ds-mirror-rtl", "aria-hidden": "true", children: collapseVariant === "close" ? "close" : "chevron_right" })
|
|
41
41
|
}
|
|
42
42
|
),
|
|
43
43
|
profile && /* @__PURE__ */ jsxs("header", { className: `${baseClass}__header`, children: [
|
|
@@ -398,7 +398,7 @@
|
|
|
398
398
|
.ds-ai-button__request {
|
|
399
399
|
position: fixed;
|
|
400
400
|
top: 0;
|
|
401
|
-
left: 0;
|
|
401
|
+
left: 0; /* ds-allow(physical): closed, the panel rests at the viewport corner the anchored behaviour then places it from, in screen pixels */
|
|
402
402
|
z-index: 1;
|
|
403
403
|
/* Component-local lengths, chosen by eye like the button's glow: a
|
|
404
404
|
readable measure, capped so a phone viewport keeps its margins. */
|
|
@@ -620,7 +620,7 @@
|
|
|
620
620
|
.ds-ai-button__summary-dismiss {
|
|
621
621
|
position: absolute;
|
|
622
622
|
top: var(--gap-200);
|
|
623
|
-
|
|
623
|
+
inset-inline-end: var(--gap-200);
|
|
624
624
|
display: inline-flex;
|
|
625
625
|
align-items: center;
|
|
626
626
|
justify-content: center;
|
|
@@ -649,7 +649,7 @@
|
|
|
649
649
|
align-items: baseline;
|
|
650
650
|
gap: var(--gap-200);
|
|
651
651
|
/* Keeps the row clear of the dismiss button in the corner. */
|
|
652
|
-
padding-
|
|
652
|
+
padding-inline-end: var(--gap-1000);
|
|
653
653
|
}
|
|
654
654
|
|
|
655
655
|
.ds-ai-button__summary-overline {
|
|
@@ -672,7 +672,7 @@
|
|
|
672
672
|
|
|
673
673
|
.ds-ai-button__summary-title {
|
|
674
674
|
/* Long titles wrap short of the dismiss corner. */
|
|
675
|
-
padding-
|
|
675
|
+
padding-inline-end: var(--gap-500);
|
|
676
676
|
font-family: var(--font-family-primary);
|
|
677
677
|
font-size: var(--font-title-body-size);
|
|
678
678
|
font-weight: var(--font-title-body-weight);
|