@botiverse/raft-ui 0.84.0 → 0.86.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/CHANGELOG.md +33 -0
- package/dist/cn.d.mts +2 -0
- package/dist/cn.mjs +21 -1
- package/dist/components/alert-dialog/alert-dialog.mjs +2 -2
- package/dist/components/app-shell/app-shell.mjs +2 -2
- package/dist/components/avatar/avatar.mjs +1 -1
- package/dist/components/button/button-split.mjs +2 -2
- package/dist/components/button/button.mjs +2 -2
- package/dist/components/choice-list/choice-list.recipe.mjs +1 -1
- package/dist/components/code-block/code-block.recipe.mjs +2 -2
- package/dist/components/combobox/combobox.mjs +1 -1
- package/dist/components/combobox-select/combobox-select.css +1 -1
- package/dist/components/comment/comment.recipe.mjs +2 -2
- package/dist/components/composer/composer-attachment.recipe.mjs +5 -5
- package/dist/components/composer/composer-drop-overlay.mjs +2 -2
- package/dist/components/composer/composer-drop-overlay.recipe.mjs +1 -1
- package/dist/components/composer/sortable-composer-attachments.mjs +1 -1
- package/dist/components/context-menu/context-menu.mjs +1 -1
- package/dist/components/conversation-panel/conversation-panel-empty-state.mjs +1 -1
- package/dist/components/dialog/dialog.mjs +4 -4
- package/dist/components/drag/drag-lift.d.mts +3 -2
- package/dist/components/drag/drag-lift.mjs +3 -2
- package/dist/components/drag/drag.recipe.mjs +1 -1
- package/dist/components/drawer/drawer.recipe.mjs +4 -4
- package/dist/components/dropdown-menu/dropdown-menu.mjs +1 -1
- package/dist/components/file-preview/file-preview.recipe.mjs +1 -1
- package/dist/components/fit-toolbar/fit-toolbar.d.mts +78 -2
- package/dist/components/fit-toolbar/fit-toolbar.mjs +331 -14
- package/dist/components/fit-toolbar/fit-toolbar.recipe.mjs +30 -4
- package/dist/components/fit-toolbar/index.d.mts +2 -2
- package/dist/components/inbox-item/inbox-item.recipe.mjs +7 -7
- package/dist/components/lightbox/lightbox.d.mts +2 -2
- package/dist/components/lightbox/lightbox.mjs +7 -7
- package/dist/components/message-attachment/message-image-gallery.recipe.mjs +1 -1
- package/dist/components/message-item/message-item.recipe.mjs +2 -2
- package/dist/components/message-list/message-list.recipe.mjs +2 -2
- package/dist/components/mobile-nav/mobile-nav.mjs +2 -2
- package/dist/components/notification-center/notification-center.mjs +1 -1
- package/dist/components/panel/panel-header.recipe.mjs +1 -1
- package/dist/components/panel/panel-split-action.recipe.mjs +2 -2
- package/dist/components/popover/popover.mjs +1 -1
- package/dist/components/preview-card/preview-card.mjs +1 -1
- package/dist/components/pull-to-refresh/pull-to-refresh-indicator.mjs +1 -1
- package/dist/components/resizable/resizable.recipe.mjs +1 -1
- package/dist/components/scroll-area/scroll-area.css +1 -0
- package/dist/components/select/select.mjs +2 -2
- package/dist/components/selection-toolbar/selection-toolbar.d.mts +1 -1
- package/dist/components/selection-toolbar/selection-toolbar.recipe.mjs +1 -1
- package/dist/components/sidebar/sidebar.recipe.mjs +1 -1
- package/dist/components/tabs/tabs.mjs +4 -4
- package/dist/components/task-dnd/task-dnd.recipe.mjs +2 -2
- package/dist/components/thread-panel/thread-panel.recipe.mjs +1 -1
- package/dist/components/toast/toast.mjs +5 -5
- package/dist/components/tooltip/tooltip.mjs +2 -2
- package/dist/lib/list-cell.mjs +1 -1
- package/dist/lint/no-raw-z-index.mjs +142 -0
- package/dist/lint/prefer-scroll-area.mjs +1 -1
- package/dist/lint/recommended.json +2 -1
- package/dist/lint.d.mts +8 -2
- package/dist/lint.mjs +16 -3
- package/dist/styles.css +28 -0
- package/dist/wip.d.mts +2 -2
- package/dist/wip.mjs +2 -2
- package/package.json +1 -1
- package/skills/raft-ui-guide/SKILL.md +1 -0
|
@@ -3,9 +3,10 @@ import { Button } from "../button/button.mjs";
|
|
|
3
3
|
import { useMergedRef } from "../../lib/use-merged-ref.mjs";
|
|
4
4
|
import { ScrollArea } from "../scroll-area/scroll-area.mjs";
|
|
5
5
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.mjs";
|
|
6
|
+
import { InputGroup, InputGroupAddon, InputGroupInput } from "../input-group/input-group.mjs";
|
|
6
7
|
import { PickerTriggerButton } from "../picker-trigger-button/picker-trigger-button.mjs";
|
|
7
8
|
import { fitToolbar } from "./fit-toolbar.recipe.mjs";
|
|
8
|
-
import { ChevronDown, Plus } from "lucide-react";
|
|
9
|
+
import { ChevronDown, MoreHorizontal, Plus, Search, X } from "lucide-react";
|
|
9
10
|
import { Fragment, cloneElement, createContext, useCallback, useContext, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
10
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
12
|
import { Toolbar } from "@base-ui/react/toolbar";
|
|
@@ -32,6 +33,7 @@ const NO_WRAP = "data-fit-first-line";
|
|
|
32
33
|
const WRAP_LINE = "data-fit-wrap-line";
|
|
33
34
|
const BREAK = "data-fit-break";
|
|
34
35
|
const NEEDS_ICON = "data-fit-needs-icon";
|
|
36
|
+
const PINNED_END = "[data-slot=fit-toolbar-group-end]";
|
|
35
37
|
const stepAttribute = (step) => `data-fit-${step}`;
|
|
36
38
|
const hasIcon = (item) => item.querySelector("svg, img") !== null;
|
|
37
39
|
/** The group has a `wrap` step it may take: the toolbar wraps and the page lets it. */
|
|
@@ -55,10 +57,10 @@ function fits(root, allowWrap) {
|
|
|
55
57
|
for (const group of root.querySelectorAll("[data-fit-scroll]")) {
|
|
56
58
|
if (group.getClientRects().length === 0) continue;
|
|
57
59
|
const content = group.querySelector("[data-slot=scroll-area-content]") ?? group;
|
|
60
|
+
const scroller = group.querySelector("[data-fit-scroller]") ?? group;
|
|
58
61
|
const [first] = laidOutChildren(content);
|
|
59
|
-
if (first &&
|
|
62
|
+
if (first && scroller.clientWidth + .5 < first.getBoundingClientRect().width) return false;
|
|
60
63
|
if (canWrap(group, allowWrap) && !group.hasAttribute(stepAttribute("wrap"))) {
|
|
61
|
-
const scroller = group.querySelector("[data-fit-scroller]") ?? group;
|
|
62
64
|
if (scroller.scrollWidth > scroller.clientWidth + .5) return false;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
@@ -145,7 +147,7 @@ function measure(root, allowWrap) {
|
|
|
145
147
|
};
|
|
146
148
|
for (const { members, step } of batches) {
|
|
147
149
|
if (fits(root, allowWrap)) break;
|
|
148
|
-
const giving = members.filter((element) => !taken.get(element)?.has("more"));
|
|
150
|
+
const giving = members.filter((element) => !taken.get(element)?.has("more") && element.parentElement?.closest(`[${stepAttribute("more")}]`) == null);
|
|
149
151
|
if (giving.length === 0) continue;
|
|
150
152
|
for (const element of giving) take(element, step);
|
|
151
153
|
history.push({
|
|
@@ -159,8 +161,10 @@ function measure(root, allowWrap) {
|
|
|
159
161
|
const group = members[0].closest(`[${stepAttribute("wrap")}]`);
|
|
160
162
|
if (!group || !root.contains(group)) continue;
|
|
161
163
|
if (history.findIndex((entry) => entry.members.includes(group) && entry.step === "wrap") < index) continue;
|
|
162
|
-
|
|
163
|
-
if (
|
|
164
|
+
const back = members.filter((element) => element.closest(PINNED_END) === null);
|
|
165
|
+
if (back.length === 0) continue;
|
|
166
|
+
for (const element of back) undo(element, step);
|
|
167
|
+
if (!fits(root, allowWrap)) for (const element of back) take(element, step);
|
|
164
168
|
}
|
|
165
169
|
const items = /* @__PURE__ */ new Map();
|
|
166
170
|
const more = [];
|
|
@@ -229,10 +233,11 @@ function lineOf(element, root) {
|
|
|
229
233
|
* order of the DOM on each line. Wrapped groups move with CSS `order`, which
|
|
230
234
|
* neither the browser's focus order nor Base UI's list follows (WCAG 2.4.3).
|
|
231
235
|
* Leaves out what isn't shown (in More, a collapsed group's items), what is
|
|
232
|
-
* disabled natively, hidden from assistive technology
|
|
236
|
+
* disabled natively, hidden from assistive technology or `inert` (the first
|
|
237
|
+
* line under an open search), or a popup's focus guard.
|
|
233
238
|
*/
|
|
234
239
|
function readingOrder(root) {
|
|
235
|
-
const controls = Array.from(root.querySelectorAll(STOP)).filter((control) => !control.matches(":disabled") && control.closest("[aria-hidden=true]") === null && !control.hasAttribute("data-base-ui-focus-guard") && control.getClientRects().length > 0);
|
|
240
|
+
const controls = Array.from(root.querySelectorAll(STOP)).filter((control) => !control.matches(":disabled") && control.closest("[aria-hidden=true], [inert]") === null && !control.hasAttribute("data-base-ui-focus-guard") && control.getClientRects().length > 0);
|
|
236
241
|
const lines = new Map(controls.map((control) => [control, lineOf(control, root)]));
|
|
237
242
|
return controls.sort((a, b) => lines.get(a) - lines.get(b));
|
|
238
243
|
}
|
|
@@ -495,6 +500,28 @@ function FitToolbarMoreItems() {
|
|
|
495
500
|
if (!context) return null;
|
|
496
501
|
return context.applied.more.map((id) => /* @__PURE__ */ jsx(Fragment, { children: context.store.get(id) }, id));
|
|
497
502
|
}
|
|
503
|
+
/**
|
|
504
|
+
* The toolbar's More as one toolbar item: a ghost ⋯ icon button, shown only
|
|
505
|
+
* while an item is in More, its name as a tooltip. Put it where the items it
|
|
506
|
+
* holds were: on a list's toolbar, before the primary action.
|
|
507
|
+
*/
|
|
508
|
+
function FitToolbarMore({ trigger, "aria-label": label = "More", children, className, ...props }) {
|
|
509
|
+
const { more } = fitToolbar();
|
|
510
|
+
const fit = useFitMore();
|
|
511
|
+
const ownTrigger = cloneElement(trigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
512
|
+
variant: "ghost",
|
|
513
|
+
size: "icon-md",
|
|
514
|
+
"aria-label": label,
|
|
515
|
+
className: more({ className }),
|
|
516
|
+
...fit.props,
|
|
517
|
+
...props
|
|
518
|
+
}) });
|
|
519
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
520
|
+
"data-slot": "button",
|
|
521
|
+
render: /* @__PURE__ */ jsx(Toolbar.Button, { render: ownTrigger }),
|
|
522
|
+
children: children ?? /* @__PURE__ */ jsx(MoreHorizontal, {})
|
|
523
|
+
}), /* @__PURE__ */ jsx(TooltipContent, { children: label })] });
|
|
524
|
+
}
|
|
498
525
|
const noSubscription = () => () => {};
|
|
499
526
|
const noVersion = () => 0;
|
|
500
527
|
/**
|
|
@@ -579,18 +606,31 @@ function useScrollGroup(group) {
|
|
|
579
606
|
};
|
|
580
607
|
}, [group]);
|
|
581
608
|
}
|
|
609
|
+
let warnedEndWithoutScroll = false;
|
|
610
|
+
function warnEndWithoutScroll() {
|
|
611
|
+
if (warnedEndWithoutScroll) return;
|
|
612
|
+
warnedEndWithoutScroll = true;
|
|
613
|
+
console.warn("raft-ui: a FitToolbarGroup has `end` without `overflow=\"scroll\"`; it is not rendered. Pin an item at the end of a scrolling group only, or put it among the group's children.");
|
|
614
|
+
}
|
|
582
615
|
/**
|
|
583
616
|
* A group of items in one row, a fixed gap apart. A toolbar wraps only
|
|
584
617
|
* between groups, the last first; groups with the same `wrapLine` share a
|
|
585
618
|
* line, any other takes one of its own.
|
|
586
619
|
*/
|
|
587
|
-
function FitToolbarGroup({ className, wrapOrder = 0, firstLine = false, wrapLine, collapseOrder, collapsed, overflow, children, ref, ...props }) {
|
|
588
|
-
const
|
|
620
|
+
function FitToolbarGroup({ className, wrapOrder = 0, firstLine = false, wrapLine, collapseOrder, collapsed, moreOrder, moreItem, overflow, end, children, ref, ...props }) {
|
|
621
|
+
const pinned = overflow === "scroll" && end !== void 0 && end !== null;
|
|
622
|
+
if (process.env.NODE_ENV !== "production" && !pinned && end !== void 0 && end !== null) warnEndWithoutScroll();
|
|
623
|
+
const { group, full, short, scroller, scrollContent, end: endSlot } = fitToolbar({
|
|
624
|
+
scroll: overflow === "scroll",
|
|
625
|
+
pinned
|
|
626
|
+
});
|
|
589
627
|
const [scrollerElement, setScroller] = useState(null);
|
|
590
628
|
useScrollGroup(overflow === "scroll" ? scrollerElement : null);
|
|
591
629
|
const item = useFitItem({
|
|
592
630
|
wrap: wrapOrder,
|
|
593
|
-
collapse: collapsed === void 0 ? void 0 : collapseOrder ?? 0
|
|
631
|
+
collapse: collapsed === void 0 ? void 0 : collapseOrder ?? 0,
|
|
632
|
+
more: moreOrder,
|
|
633
|
+
moreItem
|
|
594
634
|
});
|
|
595
635
|
return /* @__PURE__ */ jsx(Toolbar.Group, {
|
|
596
636
|
ref,
|
|
@@ -602,7 +642,7 @@ function FitToolbarGroup({ className, wrapOrder = 0, firstLine = false, wrapLine
|
|
|
602
642
|
className: group({ className }),
|
|
603
643
|
...item.props,
|
|
604
644
|
...props,
|
|
605
|
-
children: overflow === "scroll" ? /* @__PURE__ */ jsx(ScrollArea, {
|
|
645
|
+
children: overflow === "scroll" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ScrollArea, {
|
|
606
646
|
ref: setScroller,
|
|
607
647
|
orientation: "horizontal",
|
|
608
648
|
overscroll: "contain",
|
|
@@ -613,7 +653,11 @@ function FitToolbarGroup({ className, wrapOrder = 0, firstLine = false, wrapLine
|
|
|
613
653
|
className: scroller(),
|
|
614
654
|
contentClassName: scrollContent(),
|
|
615
655
|
children
|
|
616
|
-
})
|
|
656
|
+
}), pinned ? /* @__PURE__ */ jsx("span", {
|
|
657
|
+
"data-slot": "fit-toolbar-group-end",
|
|
658
|
+
className: endSlot(),
|
|
659
|
+
children: end
|
|
660
|
+
}) : null] }) : collapsed === void 0 ? children : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
617
661
|
"data-slot": "fit-toolbar-group-items",
|
|
618
662
|
className: full(),
|
|
619
663
|
children
|
|
@@ -732,5 +776,278 @@ function FitToolbarPicker({ trigger, icon, children, value, labelOrder, moreOrde
|
|
|
732
776
|
}), /* @__PURE__ */ jsx(TooltipContent, { children })]
|
|
733
777
|
});
|
|
734
778
|
}
|
|
779
|
+
const COVERED = "data-fit-search-covered";
|
|
780
|
+
/** How many FitToolbarSearch fields each toolbar root holds (`data-fit-search`). */
|
|
781
|
+
const searchesByRoot = /* @__PURE__ */ new WeakMap();
|
|
782
|
+
/**
|
|
783
|
+
* While a collapsed search is open in the scope's place, the first line's
|
|
784
|
+
* items before it (the scope) are under it: hidden (their room kept, so the
|
|
785
|
+
* toolbar measures the same) and `inert`, so neither the pointer, the arrow
|
|
786
|
+
* keys nor assistive technology reach what can't be seen. The items after it
|
|
787
|
+
* (More, the primary action) and the wrapped lines stay as they are.
|
|
788
|
+
*/
|
|
789
|
+
function coverScope(root, search) {
|
|
790
|
+
const covered = [];
|
|
791
|
+
for (const child of Array.from(root.children)) {
|
|
792
|
+
if (!(child instanceof HTMLElement)) continue;
|
|
793
|
+
if (child === search || child.contains(search)) break;
|
|
794
|
+
if (child.hasAttribute(BREAK)) continue;
|
|
795
|
+
if ((Number(getComputedStyle(child).order) || 0) > 0) continue;
|
|
796
|
+
if (child.hasAttribute("inert")) continue;
|
|
797
|
+
child.setAttribute(COVERED, "");
|
|
798
|
+
child.setAttribute("inert", "");
|
|
799
|
+
child.style.visibility = "hidden";
|
|
800
|
+
covered.push(child);
|
|
801
|
+
}
|
|
802
|
+
return () => {
|
|
803
|
+
for (const child of covered) {
|
|
804
|
+
if (!child.hasAttribute(COVERED)) continue;
|
|
805
|
+
child.removeAttribute(COVERED);
|
|
806
|
+
child.removeAttribute("inert");
|
|
807
|
+
child.style.removeProperty("visibility");
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* The search field of a list's toolbar: it fills the rest of its line and
|
|
813
|
+
* keeps at least the room its icon and its whole placeholder take (measured,
|
|
814
|
+
* or `minWidth`), so the toolbar's other steps come before
|
|
815
|
+
* it is squeezed. From `collapseOrder` on it is a search icon button at the
|
|
816
|
+
* start of the line, which opens the field in the scope's place, More and the
|
|
817
|
+
* primary action kept at the line's end; the
|
|
818
|
+
* field closes once it is empty and loses focus, or on Esc. A search with
|
|
819
|
+
* text stays open. Put it straight in the FitToolbar, between its groups.
|
|
820
|
+
*/
|
|
821
|
+
function FitToolbarSearch({ "aria-label": label, value, defaultValue = "", onValueChange, minWidth, collapseOrder, icon = /* @__PURE__ */ jsx(Search, {}), clearLabel, className, style, onKeyDown, disabled, ref, ...props }) {
|
|
822
|
+
const { search, searchButton, searchSpacer, searchField, searchInput, searchSizer } = fitToolbar();
|
|
823
|
+
const item = useFitItem({ collapse: collapseOrder });
|
|
824
|
+
const collapsed = item.taken("collapse");
|
|
825
|
+
const [own, setOwn] = useState(defaultValue);
|
|
826
|
+
const text = value ?? own;
|
|
827
|
+
const [opened, setOpened] = useState(false);
|
|
828
|
+
const open = collapsed && (opened || text !== "");
|
|
829
|
+
const wrapper = useRef(null);
|
|
830
|
+
const field = useRef(null);
|
|
831
|
+
const spacer = useRef(null);
|
|
832
|
+
const input = useRef(null);
|
|
833
|
+
const button = useRef(null);
|
|
834
|
+
const [setInput] = useMergedRef(input, ref);
|
|
835
|
+
const sizer = useRef(null);
|
|
836
|
+
const sizerText = useRef(null);
|
|
837
|
+
const focusOnOpen = useRef(false);
|
|
838
|
+
const focusButtonOnClose = useRef(false);
|
|
839
|
+
useLayoutEffect(() => {
|
|
840
|
+
const root = wrapper.current?.closest("[data-slot=fit-toolbar]");
|
|
841
|
+
if (!root) return;
|
|
842
|
+
const count = (searchesByRoot.get(root) ?? 0) + 1;
|
|
843
|
+
searchesByRoot.set(root, count);
|
|
844
|
+
root.setAttribute("data-fit-search", "");
|
|
845
|
+
return () => {
|
|
846
|
+
const left = (searchesByRoot.get(root) ?? 1) - 1;
|
|
847
|
+
if (left > 0) searchesByRoot.set(root, left);
|
|
848
|
+
else {
|
|
849
|
+
searchesByRoot.delete(root);
|
|
850
|
+
root.removeAttribute("data-fit-search");
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
}, []);
|
|
854
|
+
const [measured, setMeasured] = useState(null);
|
|
855
|
+
const placeholder = typeof props.placeholder === "string" ? props.placeholder : label;
|
|
856
|
+
useLayoutEffect(() => {
|
|
857
|
+
const copy = sizer.current;
|
|
858
|
+
const words = sizerText.current;
|
|
859
|
+
const real = input.current;
|
|
860
|
+
if (!copy || !words || !real || minWidth !== void 0) return;
|
|
861
|
+
const read = () => {
|
|
862
|
+
const style = getComputedStyle(real);
|
|
863
|
+
words.style.font = style.font;
|
|
864
|
+
words.style.letterSpacing = style.letterSpacing;
|
|
865
|
+
words.style.paddingInlineEnd = style.paddingInlineEnd;
|
|
866
|
+
const width = Math.ceil(copy.getBoundingClientRect().width);
|
|
867
|
+
if (width <= 0) return;
|
|
868
|
+
wrapper.current?.style.setProperty("--fit-search-min", `${width}px`);
|
|
869
|
+
setMeasured(width);
|
|
870
|
+
};
|
|
871
|
+
read();
|
|
872
|
+
const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(read);
|
|
873
|
+
resize?.observe(copy);
|
|
874
|
+
const fonts = typeof document === "undefined" ? void 0 : document.fonts;
|
|
875
|
+
fonts?.addEventListener?.("loadingdone", read);
|
|
876
|
+
return () => {
|
|
877
|
+
resize?.disconnect();
|
|
878
|
+
fonts?.removeEventListener?.("loadingdone", read);
|
|
879
|
+
};
|
|
880
|
+
}, [
|
|
881
|
+
minWidth,
|
|
882
|
+
placeholder,
|
|
883
|
+
icon
|
|
884
|
+
]);
|
|
885
|
+
const least = minWidth ?? measured;
|
|
886
|
+
const change = useCallback((next) => {
|
|
887
|
+
setOwn(next);
|
|
888
|
+
onValueChange?.(next);
|
|
889
|
+
}, [onValueChange]);
|
|
890
|
+
useLayoutEffect(() => {
|
|
891
|
+
const box = field.current;
|
|
892
|
+
const line = spacer.current;
|
|
893
|
+
const root = wrapper.current?.closest("[data-slot=fit-toolbar]");
|
|
894
|
+
if (!box || !line || !root || !open) return;
|
|
895
|
+
const place = () => {
|
|
896
|
+
const style = getComputedStyle(root);
|
|
897
|
+
const edge = root.getBoundingClientRect();
|
|
898
|
+
const slot = line.getBoundingClientRect();
|
|
899
|
+
const end = style.direction === "rtl" ? slot.left - edge.left - parseFloat(style.borderLeftWidth) : edge.right - parseFloat(style.borderRightWidth) - slot.right;
|
|
900
|
+
box.style.insetInlineStart = style.paddingInlineStart;
|
|
901
|
+
box.style.insetInlineEnd = `${end}px`;
|
|
902
|
+
box.style.top = `${line.offsetTop + (line.offsetHeight - box.offsetHeight) / 2}px`;
|
|
903
|
+
};
|
|
904
|
+
place();
|
|
905
|
+
const uncover = coverScope(root, wrapper.current);
|
|
906
|
+
const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(place);
|
|
907
|
+
resize?.observe(root);
|
|
908
|
+
resize?.observe(line);
|
|
909
|
+
if (focusOnOpen.current) {
|
|
910
|
+
focusOnOpen.current = false;
|
|
911
|
+
input.current?.focus();
|
|
912
|
+
}
|
|
913
|
+
return () => {
|
|
914
|
+
resize?.disconnect();
|
|
915
|
+
uncover();
|
|
916
|
+
for (const side of [
|
|
917
|
+
"inset-inline-start",
|
|
918
|
+
"inset-inline-end",
|
|
919
|
+
"top"
|
|
920
|
+
]) box.style.removeProperty(side);
|
|
921
|
+
};
|
|
922
|
+
}, [open]);
|
|
923
|
+
useLayoutEffect(() => {
|
|
924
|
+
if (open || !focusButtonOnClose.current) return;
|
|
925
|
+
focusButtonOnClose.current = false;
|
|
926
|
+
if (collapsed) button.current?.focus();
|
|
927
|
+
});
|
|
928
|
+
const close = useCallback(() => {
|
|
929
|
+
setOpened(false);
|
|
930
|
+
focusOnOpen.current = false;
|
|
931
|
+
}, []);
|
|
932
|
+
const handleFocus = useCallback(() => setOpened(true), []);
|
|
933
|
+
const handleBlur = useCallback((event) => {
|
|
934
|
+
const to = event.relatedTarget;
|
|
935
|
+
if (to instanceof Node && field.current?.contains(to)) return;
|
|
936
|
+
close();
|
|
937
|
+
}, [close]);
|
|
938
|
+
const handleKeyDown = useCallback((event) => {
|
|
939
|
+
onKeyDown?.(event);
|
|
940
|
+
if (event.defaultPrevented || event.key !== "Escape") return;
|
|
941
|
+
if (event.nativeEvent.isComposing) return;
|
|
942
|
+
if (text === "" && !collapsed) return;
|
|
943
|
+
event.preventDefault();
|
|
944
|
+
event.stopPropagation();
|
|
945
|
+
if (text !== "") {
|
|
946
|
+
change("");
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
focusButtonOnClose.current = true;
|
|
950
|
+
close();
|
|
951
|
+
}, [
|
|
952
|
+
change,
|
|
953
|
+
close,
|
|
954
|
+
collapsed,
|
|
955
|
+
onKeyDown,
|
|
956
|
+
text
|
|
957
|
+
]);
|
|
958
|
+
const clear = useCallback(() => {
|
|
959
|
+
change("");
|
|
960
|
+
input.current?.focus();
|
|
961
|
+
}, [change]);
|
|
962
|
+
const openField = useCallback(() => {
|
|
963
|
+
focusOnOpen.current = true;
|
|
964
|
+
setOpened(true);
|
|
965
|
+
}, []);
|
|
966
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
967
|
+
ref: wrapper,
|
|
968
|
+
"data-slot": "fit-toolbar-search",
|
|
969
|
+
className: search(),
|
|
970
|
+
style: least === null ? void 0 : { "--fit-search-min": `${least}px` },
|
|
971
|
+
...item.props,
|
|
972
|
+
children: [
|
|
973
|
+
/* @__PURE__ */ jsx("div", {
|
|
974
|
+
"aria-hidden": true,
|
|
975
|
+
inert: true,
|
|
976
|
+
"data-slot": "fit-toolbar-search-sizer",
|
|
977
|
+
className: searchSizer(),
|
|
978
|
+
children: /* @__PURE__ */ jsxs(InputGroup, {
|
|
979
|
+
ref: sizer,
|
|
980
|
+
size: "md",
|
|
981
|
+
className: "w-max",
|
|
982
|
+
children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: icon }), /* @__PURE__ */ jsx("span", {
|
|
983
|
+
ref: sizerText,
|
|
984
|
+
className: "whitespace-pre",
|
|
985
|
+
children: placeholder
|
|
986
|
+
})]
|
|
987
|
+
})
|
|
988
|
+
}),
|
|
989
|
+
/* @__PURE__ */ jsxs(Tooltip, {
|
|
990
|
+
disabled: !collapsed || open,
|
|
991
|
+
children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
992
|
+
"data-slot": "button",
|
|
993
|
+
render: /* @__PURE__ */ jsx(Toolbar.Button, {
|
|
994
|
+
ref: button,
|
|
995
|
+
disabled,
|
|
996
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
997
|
+
variant: "ghost",
|
|
998
|
+
size: "icon-md",
|
|
999
|
+
"aria-label": label,
|
|
1000
|
+
"data-fit-search-button": "",
|
|
1001
|
+
inert: open || void 0,
|
|
1002
|
+
className: searchButton(),
|
|
1003
|
+
onClick: openField
|
|
1004
|
+
})
|
|
1005
|
+
}),
|
|
1006
|
+
children: icon
|
|
1007
|
+
}), /* @__PURE__ */ jsx(TooltipContent, { children: label })]
|
|
1008
|
+
}),
|
|
1009
|
+
/* @__PURE__ */ jsx("span", {
|
|
1010
|
+
ref: spacer,
|
|
1011
|
+
"aria-hidden": true,
|
|
1012
|
+
"data-slot": "fit-toolbar-search-spacer",
|
|
1013
|
+
className: searchSpacer()
|
|
1014
|
+
}),
|
|
1015
|
+
/* @__PURE__ */ jsxs(InputGroup, {
|
|
1016
|
+
ref: field,
|
|
1017
|
+
size: "md",
|
|
1018
|
+
"data-fit-search-field": "",
|
|
1019
|
+
"data-open": open ? "" : void 0,
|
|
1020
|
+
className: searchField({ className }),
|
|
1021
|
+
style,
|
|
1022
|
+
onFocus: handleFocus,
|
|
1023
|
+
onBlur: handleBlur,
|
|
1024
|
+
children: [
|
|
1025
|
+
/* @__PURE__ */ jsx(InputGroupAddon, { children: icon }),
|
|
1026
|
+
/* @__PURE__ */ jsx(Toolbar.Input, { render: /* @__PURE__ */ jsx(InputGroupInput, {
|
|
1027
|
+
ref: setInput,
|
|
1028
|
+
type: "search",
|
|
1029
|
+
"aria-label": label,
|
|
1030
|
+
className: searchInput(),
|
|
1031
|
+
disabled,
|
|
1032
|
+
...props,
|
|
1033
|
+
value: text,
|
|
1034
|
+
onValueChange: change,
|
|
1035
|
+
onKeyDown: handleKeyDown
|
|
1036
|
+
}) }),
|
|
1037
|
+
clearLabel !== void 0 && text !== "" ? /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
1038
|
+
align: "inline-end",
|
|
1039
|
+
children: /* @__PURE__ */ jsx(Toolbar.Button, { render: /* @__PURE__ */ jsx(Button, {
|
|
1040
|
+
variant: "ghost",
|
|
1041
|
+
size: "icon-md",
|
|
1042
|
+
"aria-label": clearLabel,
|
|
1043
|
+
onClick: clear,
|
|
1044
|
+
children: /* @__PURE__ */ jsx(X, {})
|
|
1045
|
+
}) })
|
|
1046
|
+
}) : null
|
|
1047
|
+
]
|
|
1048
|
+
})
|
|
1049
|
+
]
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
735
1052
|
//#endregion
|
|
736
|
-
export { FitToolbar, FitToolbarButton, FitToolbarGroup, FitToolbarMoreItems, FitToolbarPicker, useFitItem, useFitMore, useInFitToolbar };
|
|
1053
|
+
export { FitToolbar, FitToolbarButton, FitToolbarGroup, FitToolbarMore, FitToolbarMoreItems, FitToolbarPicker, FitToolbarSearch, useFitItem, useFitMore, useInFitToolbar };
|
|
@@ -2,8 +2,17 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
2
2
|
//#region src/components/fit-toolbar/fit-toolbar.recipe.ts
|
|
3
3
|
const fitToolbar = tv({
|
|
4
4
|
slots: {
|
|
5
|
-
root: [
|
|
6
|
-
|
|
5
|
+
root: [
|
|
6
|
+
"flex min-w-0 max-w-full flex-nowrap items-center",
|
|
7
|
+
"data-fit-wrapping:flex-wrap data-fit-wrapping:gap-y-0",
|
|
8
|
+
"data-fit-search:relative",
|
|
9
|
+
"data-fit-search:[--fit-scroll-grow:0] data-fit-search:[--fit-scroll-basis:auto]"
|
|
10
|
+
],
|
|
11
|
+
group: [
|
|
12
|
+
"group/fit-group flex shrink-0 flex-nowrap items-center",
|
|
13
|
+
"data-fit-wrap:mt-(--fit-gap)",
|
|
14
|
+
"data-fit-more:hidden"
|
|
15
|
+
],
|
|
7
16
|
full: ["contents group-data-fit-collapse/fit-group:hidden"],
|
|
8
17
|
short: ["hidden group-data-fit-collapse/fit-group:contents"],
|
|
9
18
|
button: [
|
|
@@ -19,15 +28,32 @@ const fitToolbar = tv({
|
|
|
19
28
|
pickerValue: [],
|
|
20
29
|
chevron: ["inline-flex"],
|
|
21
30
|
plus: ["hidden in-data-fit-plus:block"],
|
|
31
|
+
more: ["hidden data-fit-shown:inline-flex"],
|
|
22
32
|
scroller: [],
|
|
23
|
-
scrollContent: []
|
|
33
|
+
scrollContent: [],
|
|
34
|
+
end: ["flex shrink-0 items-center gap-[inherit]"],
|
|
35
|
+
search: ["contents"],
|
|
36
|
+
searchButton: ["hidden order-first in-data-fit-collapse:inline-flex", "inert:invisible"],
|
|
37
|
+
searchSizer: ["pointer-events-none invisible absolute inset-s-0 top-0 size-0 overflow-hidden"],
|
|
38
|
+
searchSpacer: ["hidden min-w-0 flex-1 basis-0 self-stretch in-data-fit-collapse:block"],
|
|
39
|
+
searchField: [
|
|
40
|
+
"w-auto min-w-(--fit-search-min) flex-1 basis-0",
|
|
41
|
+
"in-data-fit-collapse:not-data-open:not-focus-within:hidden",
|
|
42
|
+
"in-data-fit-collapse:data-open:absolute in-data-fit-collapse:data-open:min-w-0",
|
|
43
|
+
"in-data-fit-collapse:focus-within:absolute in-data-fit-collapse:focus-within:min-w-0"
|
|
44
|
+
],
|
|
45
|
+
searchInput: ["[&::-webkit-search-cancel-button]:appearance-none"]
|
|
24
46
|
},
|
|
25
47
|
variants: {
|
|
26
48
|
count: { true: { pickerValue: ["font-mono text-mono-meta"] } },
|
|
27
49
|
scroll: { true: {
|
|
28
|
-
group: ["block min-w-0
|
|
50
|
+
group: ["block min-w-0 shrink grow-(--fit-scroll-grow,1) basis-(--fit-scroll-basis,0px)", "data-fit-wrap:grow"],
|
|
29
51
|
scroller: ["-my-1.5 w-full gap-[inherit] scroll-px-6 mask-fade-x"],
|
|
30
52
|
scrollContent: ["flex w-max items-center gap-[inherit] py-1.5"]
|
|
53
|
+
} },
|
|
54
|
+
pinned: { true: {
|
|
55
|
+
group: ["flex"],
|
|
56
|
+
scroller: ["w-auto min-w-0 flex-auto"]
|
|
31
57
|
} }
|
|
32
58
|
}
|
|
33
59
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { FitItemOptions, FitStep, FitSteps, FitToolbar, FitToolbarButton, FitToolbarButtonProps, FitToolbarGroup, FitToolbarGroupProps, FitToolbarMoreItems, FitToolbarPicker, FitToolbarPickerProps, FitToolbarProps, useFitItem, useFitMore, useInFitToolbar } from "./fit-toolbar.mjs";
|
|
2
|
-
export { type FitItemOptions, type FitStep, type FitSteps, FitToolbar, FitToolbarButton, type FitToolbarButtonProps, FitToolbarGroup, type FitToolbarGroupProps, FitToolbarMoreItems, FitToolbarPicker, type FitToolbarPickerProps, type FitToolbarProps, useFitItem, useFitMore, useInFitToolbar };
|
|
1
|
+
import { FitItemOptions, FitStep, FitSteps, FitToolbar, FitToolbarButton, FitToolbarButtonProps, FitToolbarGroup, FitToolbarGroupProps, FitToolbarMore, FitToolbarMoreItems, FitToolbarMoreProps, FitToolbarPicker, FitToolbarPickerProps, FitToolbarProps, FitToolbarSearch, FitToolbarSearchProps, useFitItem, useFitMore, useInFitToolbar } from "./fit-toolbar.mjs";
|
|
2
|
+
export { type FitItemOptions, type FitStep, type FitSteps, FitToolbar, FitToolbarButton, type FitToolbarButtonProps, FitToolbarGroup, type FitToolbarGroupProps, FitToolbarMore, FitToolbarMoreItems, type FitToolbarMoreProps, FitToolbarPicker, type FitToolbarPickerProps, type FitToolbarProps, FitToolbarSearch, type FitToolbarSearchProps, useFitItem, useFitMore, useInFitToolbar };
|
|
@@ -18,17 +18,17 @@ const inboxItem = tv({
|
|
|
18
18
|
"has-[[data-slot=inbox-item-open]:focus-visible]:keyboard:before:inset-ring-2 has-[[data-slot=inbox-item-open]:focus-visible]:keyboard:before:inset-ring-foreground",
|
|
19
19
|
"not-data-[density=compact]:has-data-[slot=inbox-item-trailing]:[--inbox-item-content-display:grid] not-data-[density=compact]:has-data-[slot=inbox-item-trailing]:[--inbox-item-content-end:-1]"
|
|
20
20
|
],
|
|
21
|
-
itemTrigger: ["absolute inset-0 z-
|
|
22
|
-
itemLeading: ["pointer-events-none relative z-
|
|
21
|
+
itemTrigger: ["absolute inset-0 z-base outline-none"],
|
|
22
|
+
itemLeading: ["pointer-events-none relative z-raised flex size-9 shrink-0 items-center justify-center"],
|
|
23
23
|
itemLeadingBadge: [
|
|
24
|
-
"absolute -right-0.5 -bottom-0.5 z-
|
|
24
|
+
"absolute -right-0.5 -bottom-0.5 z-raised inline-flex size-3.5 items-center justify-center",
|
|
25
25
|
"rounded-[3px] border border-sticker-ink outline-2 outline-layer-canvas outline-solid",
|
|
26
26
|
"bg-layer-canvas bg-[linear-gradient(var(--info-soft),var(--info-soft))] text-foreground",
|
|
27
27
|
"[&_svg]:size-2.5 [&_svg]:shrink-0"
|
|
28
28
|
],
|
|
29
|
-
itemSelection: ["relative z-
|
|
29
|
+
itemSelection: ["relative z-raised flex size-5 shrink-0 items-center justify-center"],
|
|
30
30
|
itemContent: [
|
|
31
|
-
"pointer-events-none relative z-
|
|
31
|
+
"pointer-events-none relative z-raised min-w-0 flex-1 text-left",
|
|
32
32
|
"-col-start-3 col-end-(--inbox-item-content-end) row-start-1",
|
|
33
33
|
"[display:var(--inbox-item-content-display,block)] grid-cols-subgrid"
|
|
34
34
|
],
|
|
@@ -57,7 +57,7 @@ const inboxItem = tv({
|
|
|
57
57
|
"[&>svg]:text-foreground-hint"
|
|
58
58
|
],
|
|
59
59
|
itemTrailing: [
|
|
60
|
-
"pointer-events-none relative z-
|
|
60
|
+
"pointer-events-none relative z-raised col-[-2/-1] row-start-1",
|
|
61
61
|
"flex shrink-0",
|
|
62
62
|
"mt-0 flex-col items-end gap-2 pt-px",
|
|
63
63
|
"max-md:flex-col max-md:items-end max-md:gap-2",
|
|
@@ -138,7 +138,7 @@ const inboxItem = tv({
|
|
|
138
138
|
} },
|
|
139
139
|
reveal: { hover: {
|
|
140
140
|
itemActions: [
|
|
141
|
-
"absolute top-0 right-0 z-
|
|
141
|
+
"absolute top-0 right-0 z-raised",
|
|
142
142
|
"pointer-events-none opacity-0 transition-opacity",
|
|
143
143
|
"group-hover/inbox-item:pointer-events-auto group-hover/inbox-item:opacity-100",
|
|
144
144
|
"group-focus-within/inbox-item:pointer-events-auto group-focus-within/inbox-item:opacity-100",
|
|
@@ -39,10 +39,10 @@ export type LightboxTriggerProps = Dialog.Trigger.Props;
|
|
|
39
39
|
export declare function LightboxTrigger(props: LightboxTriggerProps): import("react").JSX.Element;
|
|
40
40
|
export type LightboxPortalProps = StyledProps<Dialog.Portal.Props>;
|
|
41
41
|
/**
|
|
42
|
-
* The lightbox's own stacking context, at `z-
|
|
42
|
+
* The lightbox's own stacking context, at `z-lightbox` (70) above the page's dialogs
|
|
43
43
|
* and popups: the scrim, the content, and every Base UI popup opened from
|
|
44
44
|
* inside, which Base UI portals into this element by default, in DOM order.
|
|
45
|
-
* A popup's own `z-
|
|
45
|
+
* A popup's own `z-popup` then counts inside the lightbox, so it is drawn above
|
|
46
46
|
* the content instead of under the scrim, and a press on it is a press inside
|
|
47
47
|
* the lightbox.
|
|
48
48
|
*/
|
|
@@ -15,11 +15,11 @@ import { useHotkey } from "@tanstack/react-hotkeys";
|
|
|
15
15
|
//#region src/components/lightbox/lightbox.tsx
|
|
16
16
|
const lightbox = tv({
|
|
17
17
|
slots: {
|
|
18
|
-
portal: ["relative isolate z-
|
|
18
|
+
portal: ["relative isolate z-lightbox"],
|
|
19
19
|
backdrop: ["fixed inset-0 bg-layer-backdrop data-closed:hidden"],
|
|
20
20
|
content: [
|
|
21
21
|
"pointer-events-none fixed inset-0 flex flex-col data-closed:hidden",
|
|
22
|
-
"*:data-lightbox-close:pointer-events-auto *:data-lightbox-close:absolute *:data-lightbox-close:z-
|
|
22
|
+
"*:data-lightbox-close:pointer-events-auto *:data-lightbox-close:absolute *:data-lightbox-close:z-raised",
|
|
23
23
|
"*:data-lightbox-close:top-[calc(16px+env(safe-area-inset-top,0px))] *:data-lightbox-close:right-[calc(16px+env(safe-area-inset-right,0px))]"
|
|
24
24
|
],
|
|
25
25
|
header: [
|
|
@@ -61,7 +61,7 @@ const lightbox = tv({
|
|
|
61
61
|
stage: ["pointer-events-none relative flex min-h-0 flex-1 items-center justify-center overflow-hidden"],
|
|
62
62
|
media: ["pointer-events-auto max-h-[80vh] max-w-[86vw] border-0 bg-transparent shadow-none"],
|
|
63
63
|
navigationButton: [
|
|
64
|
-
"pointer-events-auto absolute z-
|
|
64
|
+
"pointer-events-auto absolute z-raised inline-flex items-center justify-center",
|
|
65
65
|
"transition-[background-color,color,opacity,box-shadow,transform] duration-150",
|
|
66
66
|
"outline-[1px] outline-offset-2 outline-transparent",
|
|
67
67
|
"data-[disabled=true]:cursor-default",
|
|
@@ -71,7 +71,7 @@ const lightbox = tv({
|
|
|
71
71
|
"focus-visible:outline-transparent focus-visible:shadow-focus",
|
|
72
72
|
"[&_svg]:size-5.5"
|
|
73
73
|
],
|
|
74
|
-
infoDock: ["pointer-events-none absolute right-6 bottom-20 left-6 z-
|
|
74
|
+
infoDock: ["pointer-events-none absolute right-6 bottom-20 left-6 z-raised flex justify-center"],
|
|
75
75
|
infoBar: [
|
|
76
76
|
"pointer-events-auto flex items-center",
|
|
77
77
|
"w-[clamp(144px,20vw,224px)] max-w-[calc(100vw-48px)] min-w-36",
|
|
@@ -87,7 +87,7 @@ const lightbox = tv({
|
|
|
87
87
|
"*:data-[slot=button]:after:inset-x-[-3px] *:data-[slot=button]:first:after:left-[-9.5px] *:data-[slot=button]:last:after:right-[-9.5px]",
|
|
88
88
|
"pointer-coarse:*:data-[slot=button]:after:inset-y-[-9.5px]"
|
|
89
89
|
],
|
|
90
|
-
thumbnailStrip: ["pointer-events-none absolute right-0 bottom-4 left-0 z-
|
|
90
|
+
thumbnailStrip: ["pointer-events-none absolute right-0 bottom-4 left-0 z-raised", "flex items-center justify-center gap-1.5"],
|
|
91
91
|
thumbnail: [
|
|
92
92
|
"group/lightbox-thumb pointer-events-auto relative size-12 overflow-hidden",
|
|
93
93
|
"transition-[border-color,opacity,box-shadow] duration-150",
|
|
@@ -155,10 +155,10 @@ function LightboxTrigger(props) {
|
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
|
-
* The lightbox's own stacking context, at `z-
|
|
158
|
+
* The lightbox's own stacking context, at `z-lightbox` (70) above the page's dialogs
|
|
159
159
|
* and popups: the scrim, the content, and every Base UI popup opened from
|
|
160
160
|
* inside, which Base UI portals into this element by default, in DOM order.
|
|
161
|
-
* A popup's own `z-
|
|
161
|
+
* A popup's own `z-popup` then counts inside the lightbox, so it is drawn above
|
|
162
162
|
* the content instead of under the scrim, and a press on it is a press inside
|
|
163
163
|
* the lightbox.
|
|
164
164
|
*/
|
|
@@ -13,7 +13,7 @@ const messageImageGallery = tv({
|
|
|
13
13
|
"outline-none focus-visible:keyboard:inset-ring-2 focus-visible:keyboard:inset-ring-foreground"
|
|
14
14
|
],
|
|
15
15
|
action: [
|
|
16
|
-
"absolute z-
|
|
16
|
+
"absolute z-raised hidden items-center justify-center",
|
|
17
17
|
"focus:flex",
|
|
18
18
|
"group-hover/img:flex",
|
|
19
19
|
"right-[calc(var(--control-embedded-inset)-1px)] bottom-[calc(var(--control-embedded-inset)-1px)] size-8 rounded-chip border-[1.5px] border-line-strong",
|
|
@@ -81,7 +81,7 @@ const messageItem = tv({
|
|
|
81
81
|
"dark:shadow-[0_0_0_3px_var(--mi-row-fill,transparent),0_0_0_3px_var(--layer-canvas)]"
|
|
82
82
|
],
|
|
83
83
|
edited: ["ms-1 whitespace-nowrap", "text-caption text-foreground-hint"],
|
|
84
|
-
trailing: ["absolute end-0 bottom-0 z-
|
|
84
|
+
trailing: ["absolute end-0 bottom-0 z-raised flex h-lh items-center", "select-none! **:select-none!"],
|
|
85
85
|
body: [
|
|
86
86
|
"wrap-break-word select-text",
|
|
87
87
|
"**:select-text",
|
|
@@ -93,7 +93,7 @@ const messageItem = tv({
|
|
|
93
93
|
attachments: ["stack-y-2", "mt-2"],
|
|
94
94
|
footer: ["mt-1.5 flex flex-wrap items-center gap-1.5"],
|
|
95
95
|
toolbar: [
|
|
96
|
-
"absolute z-
|
|
96
|
+
"absolute z-control flex items-center",
|
|
97
97
|
"opacity-(--mi-toolbar-opacity,0)",
|
|
98
98
|
"[pointer-events:var(--mi-toolbar-pe,none)]",
|
|
99
99
|
"top-[-18px] md:pointer-fine:top-[calc(-1*(var(--control-height)+8px)/2)] right-3 gap-1 overflow-visible rounded-container p-1",
|
|
@@ -14,7 +14,7 @@ const messageList = tv({
|
|
|
14
14
|
dateDividerRule: ["flex-1", "min-w-3 border-t border-line-hairline"],
|
|
15
15
|
dateDividerChip: ["inline-flex items-center", "font-mono text-mono-meta whitespace-nowrap text-foreground-hint"],
|
|
16
16
|
endFade: [
|
|
17
|
-
"pointer-events-none absolute inset-x-0 bottom-0 z-
|
|
17
|
+
"pointer-events-none absolute inset-x-0 bottom-0 z-raised",
|
|
18
18
|
"h-timeline-section",
|
|
19
19
|
"bg-linear-to-t from-layer-canvas to-transparent"
|
|
20
20
|
],
|
|
@@ -35,7 +35,7 @@ const messageList = tv({
|
|
|
35
35
|
});
|
|
36
36
|
const messageListJump = tv({
|
|
37
37
|
slots: {
|
|
38
|
-
controls: ["absolute inset-x-0 z-
|
|
38
|
+
controls: ["absolute inset-x-0 z-float mx-auto", "flex w-fit max-w-[calc(100%-1.5rem)] flex-wrap items-center justify-center gap-x-2 gap-y-3"],
|
|
39
39
|
group: ["inline-flex shrink-0 items-stretch", "*:data-[slot=message-list-jump-pill]:rounded-e-none"],
|
|
40
40
|
dismiss: [
|
|
41
41
|
"rounded-s-none border-s-0",
|
|
@@ -17,8 +17,8 @@ const mobileNav = tv({ slots: {
|
|
|
17
17
|
"[&_svg]:shrink-0",
|
|
18
18
|
"isolate min-w-0 flex-col justify-start gap-[7px] border-0 px-0 pt-1 pb-0",
|
|
19
19
|
"font-sans text-[10px]/3 font-semibold text-foreground-hint",
|
|
20
|
-
"*:relative *:z-
|
|
21
|
-
"before:pointer-events-none before:absolute before:top-0 before:left-1/2 before:z-
|
|
20
|
+
"*:relative *:z-raised [&_svg]:size-[22px] [&_svg]:stroke-2",
|
|
21
|
+
"before:pointer-events-none before:absolute before:top-0 before:left-1/2 before:z-base before:-translate-x-1/2",
|
|
22
22
|
"before:h-[30px] before:w-14 before:rounded-control before:border-[1.5px] before:border-transparent before:content-['']",
|
|
23
23
|
"active:before:bg-fill-medium",
|
|
24
24
|
"data-[selected=true]:font-bold data-[selected=true]:text-foreground",
|