@botiverse/raft-ui 0.84.0 → 0.85.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 +20 -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/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.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/package.json +1 -1
- package/skills/raft-ui-guide/SKILL.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [0.85.0](https://github.com/botiverse/raft-design/compare/v0.84.0...v0.85.0) (2026-11-10)
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- **Named layers, `z-below` to `z-drag`, and the lint rule `raft-ui/no-raw-z-index`**: every z-index has a name and a place in one order ([Layer order](https://raft-design.botiverse.build/foundations/elevation/#layer-order)). The names are ordinary Tailwind `z-*` utilities from `--z-index-*` theme variables in `styles.css` (`@theme static`, so CSS can always read `var(--z-index-sticky)`): in the page `z-below` -1, `z-base` 0, `z-raised` 1, `z-control` 10, `z-sticky` 20, `z-float` 30, `z-chrome` 35, `z-cover` 40, `z-app` 45, `z-scrollbar` 49; overlays `z-popup` and `z-dialog` 50, `z-dialog-layer` 60, `z-lightbox` 70, `z-toast` 80, `z-drag` 999. They take every variant (`max-md:z-chrome`, `before:z-below`), and `cn` and the recipes merge them with a number an app passes (`z-popup` and `z-40` keep `z-40`). raft-ui's own components use them. The new rule reports a z class with a number or an arbitrary value (`z-10`, `-z-1`, `z-[60]`), a numeric `zIndex` in a style object, a `zIndex={n}` prop and `el.style.zIndex = n`; a number kept on purpose takes a `// raft-ui: z-index <reason>` comment on the line above. `z-index-named.test.ts` holds raft-ui's own code to the same rule, CSS included, with its kept exceptions listed.
|
|
6
|
+
- Why: slock alone writes 186 z-index values, and the same role has up to five numbers (sticky headers at 2, 10, 15, 20 and 30) while one number has up to seven roles; a share lightbox at 100 hides its own toast, and a badge menu at 1000 sits above the drag lift (#proj-raft-ui:#218, step 1, approved by Artea).
|
|
7
|
+
- Affects: nothing on the upgrade for an app that extends `recommended.json`: the rule is `"off"` in it for now, so an app that lints with `--max-warnings=0` (slock) stays green. It turns on there as `"error"` once slock has moved to the names (#218 step 2). An app can opt in early with `"raft-ui/no-raw-z-index": "warn"` or `"error"` in its own `rules`. Map each value with the table in Elevation: a local lift is `z-raised` inside an `isolate` root (there is no third local level: order a third part by DOM order); a popup, menu, dialog, lightbox, toast or drag copy takes raft-ui's component and no z-index of its own. Nothing may sit above the toasts (80) or the drag lift (999). slock's InlineBadgeEditor (1000) and SelectShareLightbox (100) are not exceptions: they move onto `Popover` and `z-lightbox` in step 2.
|
|
8
|
+
- Docs: https://raft-design.botiverse.build/foundations/elevation/#layer-order, https://raft-design.botiverse.build/about/use-raft-ui/#lint-rules
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **raft-ui's in-page layers take the scale's values**: where a component's z-index moved to a name with another number, it renders the same inside the component, but its number against an app's own layers changes. Overlays keep theirs (50, 60, 70, 80, 999).
|
|
13
|
+
- Raised parts 10 → 1 (`z-raised`): Button's and Toast's label and loading indicator, Avatar's badge, InboxItem's lead, badge, selection, text, trail and corner (its trigger is `z-base`, 0), ChoiceList's control column, Comment's cover and active comment, CodeBlock's actions, ComposerAttachment's veils, FilePreview's corner badge, MessageImageGallery's "+N" veil, MessageItem's trailing meta, MobileNav's icons, Select's scroll arrows, Tabs' tab content and drop placeholder, Tooltip's kbd, Lightbox's arrows, info dock and counter, ConversationPanelEmptyState's illustration. 20 → 1: CodeBlock's corners, ComposerAttachment's progress bar (over the veil by DOM order), ComposerDropOverlay's second icon (and its first, 10 → 1), Lightbox's close, a dragged TaskDraggable. MessageList's end fade 5 → 1.
|
|
14
|
+
- Up: MessageList's jump controls and SelectionToolbar 10 → 30 (`z-float`), the pull-to-refresh indicator 10 → 20 (`z-sticky`), PanelHeader's sticky phone header 30 → 35 (`z-chrome`), ThreadPanel's header 20 → 35 (inside the panel's `isolate`), AppShellOverlaySlot 20 → 40 (`z-cover`).
|
|
15
|
+
- Down: MessageItem's hover toolbar 20 → 10 and ComposerAttachment's remove button 20 → 10 (`z-control`), the composer attachment row's arrows 30 → 10 (outside the row's ScrollArea, so still over it). The sidebar header mask -10 → -1 (`z-below`).
|
|
16
|
+
- Isolation: a tab is now `isolate` instead of `z-10`, and a dragged tab is lifted by `var(--z-index-raised)` instead of 20, all inside the tab list's `isolate`. TaskDraggable is `isolate`, so a card's own parts rank only inside the card, and a dragged card at `z-raised` is above every other card.
|
|
17
|
+
- Why: the scale has one number per role; the old numbers made the same role differ between components and forced slock to workarounds (a day heading at `z-15`, an `isolate` around the artifacts dashboard, `max-md:z-40` beside the phone header) (#proj-raft-ui:#218).
|
|
18
|
+
- Affects: an app layer that sat between the old and the new number of a raft-ui layer it overlaps. In slock, move these in the same upgrade: a cover at `z-30` beside a PanelHeader (MainLayout, ProfilePanel, ChannelSideArea, LegacyTaskPanel, TaskConversationDialog, `index.css`) to `z-cover`, or the header, now 35, is drawn over it; the typing line (`z-6`) to `z-float`, so it stays over the end fade and beside the jump pills; a hit target at `z-10` in a message (MessageItem) to `z-raised`, so the hover toolbar, now 10, stays above it; ThreadsInbox's day heading (`z-15`) and "new" pill (`z-20`) to `z-sticky` and `z-float`, which InboxItem's parts at 1 now allow.
|
|
19
|
+
- Docs: https://raft-design.botiverse.build/foundations/elevation/#in-page-layers
|
|
20
|
+
|
|
1
21
|
## [0.84.0](https://github.com/botiverse/raft-design/compare/v0.83.0...v0.84.0) (2026-11-10)
|
|
2
22
|
|
|
3
23
|
### Added
|
package/dist/cn.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ClassValue } from "cnfast";
|
|
2
2
|
//#region src/lib/cn.d.ts
|
|
3
|
+
/** The `--z-index-*` names of styles.css, in order (design/foundations/elevation.md#layer-order). */
|
|
4
|
+
export declare const Z_INDEX_NAMES: string[];
|
|
3
5
|
export declare function cn(...inputs: ClassValue[]): string;
|
|
4
6
|
//#endregion
|
|
5
7
|
export type { ClassValue };
|
package/dist/cn.mjs
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { clsx } from "cnfast";
|
|
2
2
|
import { extendTailwindMerge } from "tailwind-merge";
|
|
3
3
|
//#region src/lib/cn.ts
|
|
4
|
+
/** The `--z-index-*` names of styles.css, in order (design/foundations/elevation.md#layer-order). */
|
|
5
|
+
const Z_INDEX_NAMES = [
|
|
6
|
+
"below",
|
|
7
|
+
"base",
|
|
8
|
+
"raised",
|
|
9
|
+
"control",
|
|
10
|
+
"sticky",
|
|
11
|
+
"float",
|
|
12
|
+
"chrome",
|
|
13
|
+
"cover",
|
|
14
|
+
"app",
|
|
15
|
+
"scrollbar",
|
|
16
|
+
"popup",
|
|
17
|
+
"dialog",
|
|
18
|
+
"dialog-layer",
|
|
19
|
+
"lightbox",
|
|
20
|
+
"toast",
|
|
21
|
+
"drag"
|
|
22
|
+
];
|
|
4
23
|
const twMerge = extendTailwindMerge({ extend: {
|
|
5
24
|
theme: { spacing: [
|
|
6
25
|
"control",
|
|
@@ -59,6 +78,7 @@ const twMerge = extendTailwindMerge({ extend: {
|
|
|
59
78
|
"x"
|
|
60
79
|
] }],
|
|
61
80
|
opacity: [{ opacity: ["dimmed"] }],
|
|
81
|
+
z: [{ z: Z_INDEX_NAMES }],
|
|
62
82
|
"bg-image": [{ overlay: [
|
|
63
83
|
"subtle",
|
|
64
84
|
"medium",
|
|
@@ -71,4 +91,4 @@ function cn(...inputs) {
|
|
|
71
91
|
return twMerge(clsx(inputs));
|
|
72
92
|
}
|
|
73
93
|
//#endregion
|
|
74
|
-
export { cn };
|
|
94
|
+
export { Z_INDEX_NAMES, cn };
|
|
@@ -13,9 +13,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
//#region src/components/alert-dialog/alert-dialog.tsx
|
|
14
14
|
const alertDialog = tv({
|
|
15
15
|
slots: {
|
|
16
|
-
overlay: ["fixed inset-0 z-
|
|
16
|
+
overlay: ["fixed inset-0 z-dialog bg-layer-backdrop"],
|
|
17
17
|
content: [
|
|
18
|
-
"fixed top-1/2 left-1/2 z-
|
|
18
|
+
"fixed top-1/2 left-1/2 z-dialog grid w-[calc(100%-2rem)] -translate-1/2 outline-none",
|
|
19
19
|
decisionWidth,
|
|
20
20
|
"overflow-clip rounded-dialog bg-layer-popover text-foreground",
|
|
21
21
|
"shadow-float ring-1 ring-line-seam"
|
|
@@ -19,7 +19,7 @@ const appShell = tv({
|
|
|
19
19
|
sidebarSlot: ["hidden min-h-0 shrink-0 flex-col md:flex"],
|
|
20
20
|
mainSlot: ["flex min-h-0 min-w-0 flex-1 flex-col"],
|
|
21
21
|
panelSlot: ["hidden min-h-0 min-w-0 flex-col md:flex"],
|
|
22
|
-
overlaySlot: ["absolute inset-0 z-
|
|
22
|
+
overlaySlot: ["absolute inset-0 z-cover flex min-h-0 min-w-0"]
|
|
23
23
|
},
|
|
24
24
|
variants: { overlay: {
|
|
25
25
|
false: {},
|
|
@@ -135,7 +135,7 @@ function AppShellSidebarSlot({ className, id: idProp, render, ...props }) {
|
|
|
135
135
|
id,
|
|
136
136
|
inert: collapsed ? true : void 0,
|
|
137
137
|
className: sidebarSlot({ className: cn(className, sidebar?.collapsible && [
|
|
138
|
-
"group-data-[state=expanded]/app-shell:relative group-data-[state=expanded]/app-shell:z-
|
|
138
|
+
"group-data-[state=expanded]/app-shell:relative group-data-[state=expanded]/app-shell:z-raised",
|
|
139
139
|
"group-data-[state=collapsed]/app-shell:pointer-events-none",
|
|
140
140
|
"group-data-[state=collapsed]/app-shell:opacity-0"
|
|
141
141
|
]) })
|
|
@@ -37,7 +37,7 @@ const avatar = tv({
|
|
|
37
37
|
"[[data-size='3xs']>&]:[&>svg]:size-2"
|
|
38
38
|
],
|
|
39
39
|
badge: [
|
|
40
|
-
"absolute z-
|
|
40
|
+
"absolute z-raised select-none",
|
|
41
41
|
"size-[11px] -right-1 -bottom-1 rounded-[2px]",
|
|
42
42
|
"outline-2 outline-solid outline-layer-canvas",
|
|
43
43
|
"group-data-[size=xl]/avatar:size-5 group-data-[size=xl]/avatar:-right-2 group-data-[size=xl]/avatar:-bottom-2",
|
|
@@ -10,11 +10,11 @@ const buttonSplit = tv({ base: [
|
|
|
10
10
|
"data-sticker-edge:ring-[1.5px]",
|
|
11
11
|
"data-[size=lg]:rounded-(--control-radius)"
|
|
12
12
|
] });
|
|
13
|
-
const buttonSplitMain = tv({ base: ["rounded-e-none border-e-0", "ring-0 focus-visible:z-
|
|
13
|
+
const buttonSplitMain = tv({ base: ["rounded-e-none border-e-0", "ring-0 focus-visible:z-raised"] });
|
|
14
14
|
const buttonSplitMenu = tv({
|
|
15
15
|
base: [
|
|
16
16
|
"min-w-0 rounded-s-none px-0",
|
|
17
|
-
"ring-0 focus-visible:z-
|
|
17
|
+
"ring-0 focus-visible:z-raised",
|
|
18
18
|
"after:inset-s-0"
|
|
19
19
|
],
|
|
20
20
|
variants: {
|
|
@@ -38,8 +38,8 @@ const buttonVariants = tv({
|
|
|
38
38
|
"disabled:border-line-hairline disabled:bg-fill-muted disabled:bg-none disabled:text-foreground-disabled disabled:ring-0",
|
|
39
39
|
"aria-disabled:border-line-hairline aria-disabled:bg-fill-muted aria-disabled:bg-none aria-disabled:text-foreground-disabled aria-disabled:ring-0"
|
|
40
40
|
],
|
|
41
|
-
content: "relative z-
|
|
42
|
-
loadingIndicator: "pointer-events-none absolute inset-0 z-
|
|
41
|
+
content: "relative z-raised inline-flex min-w-0 max-w-full items-center justify-center gap-[inherit] data-[loading=true]:invisible",
|
|
42
|
+
loadingIndicator: "pointer-events-none absolute inset-0 z-raised flex items-center justify-center"
|
|
43
43
|
},
|
|
44
44
|
variants: {
|
|
45
45
|
variant: {
|
|
@@ -24,7 +24,7 @@ const choiceList = tv({
|
|
|
24
24
|
description: ["block truncate font-sans text-footnote font-normal text-foreground-muted", "in-data-disabled:text-foreground-disabled"],
|
|
25
25
|
meta: ["block truncate font-sans text-footnote font-normal text-foreground-muted", "in-data-disabled:text-foreground-disabled"],
|
|
26
26
|
action: [
|
|
27
|
-
"relative z-
|
|
27
|
+
"relative z-raised col-start-2 flex h-lh items-center self-start pr-1",
|
|
28
28
|
"mt-option-inset pointer-coarse:mt-[calc((--spacing(11)-1lh)/2)]",
|
|
29
29
|
"font-sans text-subhead"
|
|
30
30
|
],
|
|
@@ -16,11 +16,11 @@ const codeBlock = tv({ slots: {
|
|
|
16
16
|
actions: [
|
|
17
17
|
"ml-auto flex items-center gap-1",
|
|
18
18
|
"[[data-slot=code-block-body]>&]:col-start-2 [[data-slot=code-block-body]>&]:row-start-1",
|
|
19
|
-
"[[data-slot=code-block-body]>&]:z-
|
|
19
|
+
"[[data-slot=code-block-body]>&]:z-raised [[data-slot=code-block-body]>&]:ml-3",
|
|
20
20
|
"[[data-slot=code-block-body]>&]:my-[calc(var(--control-embedded-inset)-0.5rem-1px)] [[data-slot=code-block-body]>&]:mr-[calc(var(--control-embedded-inset)-0.75rem-1px)]"
|
|
21
21
|
],
|
|
22
22
|
corner: [
|
|
23
|
-
"pointer-events-none absolute z-
|
|
23
|
+
"pointer-events-none absolute z-raised size-1",
|
|
24
24
|
"data-[y=top]:top-0 data-[y=bottom]:bottom-0",
|
|
25
25
|
"data-[x=left]:left-0 data-[x=right]:right-0",
|
|
26
26
|
"hidden"
|
|
@@ -60,7 +60,7 @@ const combobox = tv({
|
|
|
60
60
|
"first:rounded-t-container has-focus-visible:keyboard:inset-ring-2 has-focus-visible:keyboard:inset-ring-foreground"
|
|
61
61
|
],
|
|
62
62
|
input: ["w-full outline-none"],
|
|
63
|
-
positioner: ["isolate z-
|
|
63
|
+
positioner: ["isolate z-popup outline-none"],
|
|
64
64
|
content: [
|
|
65
65
|
"h-auto max-h-(--available-height) min-w-[220px] overflow-hidden",
|
|
66
66
|
"max-w-[min(var(--available-width),max(var(--anchor-width),24rem))]",
|
|
@@ -7,7 +7,7 @@ const comment = tv({
|
|
|
7
7
|
"absolute inset-x-0 top-0",
|
|
8
8
|
"data-animate:transition-transform data-animate:duration-150 data-animate:ease-out",
|
|
9
9
|
"motion-reduce:transition-none",
|
|
10
|
-
"data-active:z-
|
|
10
|
+
"data-active:z-raised"
|
|
11
11
|
],
|
|
12
12
|
card: [
|
|
13
13
|
"relative flex min-w-0 flex-col gap-2",
|
|
@@ -16,7 +16,7 @@ const comment = tv({
|
|
|
16
16
|
"data-active:border-[1.5px] data-active:border-line-strong data-active:p-[11.5px] data-active:shadow-float"
|
|
17
17
|
],
|
|
18
18
|
cardTrigger: [
|
|
19
|
-
"absolute -inset-px z-
|
|
19
|
+
"absolute -inset-px z-raised cursor-pointer",
|
|
20
20
|
"rounded-container border-0 bg-transparent p-0",
|
|
21
21
|
"hover:bg-fill-subtle active:bg-fill-medium",
|
|
22
22
|
"outline-none focus-visible:shadow-focus"
|
|
@@ -20,7 +20,7 @@ const composerAttachment = tv({
|
|
|
20
20
|
"pe-1.5"
|
|
21
21
|
],
|
|
22
22
|
attachmentsNav: [
|
|
23
|
-
"absolute top-1/2 z-
|
|
23
|
+
"absolute top-1/2 z-control -translate-y-1/2",
|
|
24
24
|
"size-8 rounded-chip shadow-none",
|
|
25
25
|
"[&_svg:not([class*='size-'])]:size-4.5"
|
|
26
26
|
],
|
|
@@ -42,26 +42,26 @@ const composerAttachment = tv({
|
|
|
42
42
|
attachmentTitle: ["block truncate", "font-sans text-footnote font-semibold text-foreground"],
|
|
43
43
|
attachmentMeta: ["block w-full truncate", "text-left font-mono text-mono-meta text-foreground-hint"],
|
|
44
44
|
attachmentUploadingOverlay: [
|
|
45
|
-
"absolute inset-0 z-
|
|
45
|
+
"absolute inset-0 z-raised flex flex-col items-center justify-center px-1",
|
|
46
46
|
"text-center",
|
|
47
47
|
"rounded-control bg-layer-veil",
|
|
48
48
|
"font-mono text-mono-meta font-bold text-foreground"
|
|
49
49
|
],
|
|
50
50
|
attachmentUploadProgressBar: [
|
|
51
|
-
"absolute z-
|
|
51
|
+
"absolute z-raised h-1 overflow-hidden",
|
|
52
52
|
"right-1.5 bottom-1.5 left-1.5 w-auto rounded-[2px]",
|
|
53
53
|
"bg-layer-card"
|
|
54
54
|
],
|
|
55
55
|
attachmentUploadProgressBarIndicator: ["block h-full", "rounded-[inherit] bg-info"],
|
|
56
56
|
attachmentFailedOverlay: [
|
|
57
|
-
"absolute inset-0 z-
|
|
57
|
+
"absolute inset-0 z-raised flex flex-col items-center justify-center px-1",
|
|
58
58
|
"[border-width:var(--ca-overlay-border,2px)]",
|
|
59
59
|
"text-center",
|
|
60
60
|
"rounded-control border-danger-strong bg-layer-veil",
|
|
61
61
|
"font-sans text-caption font-semibold text-danger-strong"
|
|
62
62
|
],
|
|
63
63
|
attachmentRemove: [
|
|
64
|
-
"absolute z-
|
|
64
|
+
"absolute z-control flex items-center justify-center",
|
|
65
65
|
"transition-opacity group-hover/composer-attachment:opacity-100",
|
|
66
66
|
"[@media(hover:none)]:opacity-100",
|
|
67
67
|
"[&_svg]:shrink-0",
|
|
@@ -42,11 +42,11 @@ function ComposerDropOverlayPrompt({ children, ...props }) {
|
|
|
42
42
|
children: /* @__PURE__ */ jsx(FileText, { className: "text-foreground-muted" })
|
|
43
43
|
}),
|
|
44
44
|
/* @__PURE__ */ jsx("span", {
|
|
45
|
-
className: dropOverlayIcon({ className: "absolute z-
|
|
45
|
+
className: dropOverlayIcon({ className: "absolute z-raised" }),
|
|
46
46
|
children: /* @__PURE__ */ jsx(Upload, { className: "text-foreground-muted" })
|
|
47
47
|
}),
|
|
48
48
|
/* @__PURE__ */ jsx("span", {
|
|
49
|
-
className: dropOverlayIcon({ className: "absolute z-
|
|
49
|
+
className: dropOverlayIcon({ className: "absolute z-raised translate-x-7 translate-y-1 rotate-12" }),
|
|
50
50
|
children: /* @__PURE__ */ jsx(Image, { className: "text-foreground-muted" })
|
|
51
51
|
})
|
|
52
52
|
]
|
|
@@ -2,7 +2,7 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
2
2
|
//#region src/components/composer/composer-drop-overlay.recipe.ts
|
|
3
3
|
const composerDropOverlay = tv({ slots: {
|
|
4
4
|
dropOverlay: [
|
|
5
|
-
"absolute inset-0 z-
|
|
5
|
+
"absolute inset-0 z-float flex items-center justify-center",
|
|
6
6
|
"rounded-container border-[1.5px] border-dashed border-line-seam",
|
|
7
7
|
"bg-layer-card bg-[linear-gradient(var(--info-soft),var(--info-soft))]"
|
|
8
8
|
],
|
|
@@ -225,7 +225,7 @@ function SortableComposerAttachment({ id, label, children }) {
|
|
|
225
225
|
const style = {
|
|
226
226
|
transform: isDragging ? void 0 : CSS.Translate.toString(transform),
|
|
227
227
|
transition: isDragging ? void 0 : transition,
|
|
228
|
-
zIndex: isDragging ?
|
|
228
|
+
zIndex: isDragging ? "var(--z-index-base)" : void 0
|
|
229
229
|
};
|
|
230
230
|
const place = isDragging && !home;
|
|
231
231
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -7,7 +7,7 @@ import { ContextMenu } from "@base-ui/react";
|
|
|
7
7
|
//#region src/components/context-menu/context-menu.tsx
|
|
8
8
|
const contextMenu = tv({ slots: {
|
|
9
9
|
trigger: ["select-none"],
|
|
10
|
-
positioner: ["isolate z-
|
|
10
|
+
positioner: ["isolate z-popup outline-none"],
|
|
11
11
|
content: [
|
|
12
12
|
"flex flex-col max-h-(--available-height) overflow-hidden",
|
|
13
13
|
"outline-none",
|
|
@@ -12,7 +12,7 @@ const conversationPanelEmptyState = tv({ slots: {
|
|
|
12
12
|
brand: ["shrink-0", "mb-1 inline-flex rounded-none p-0 text-foreground-hint"],
|
|
13
13
|
brandMark: [
|
|
14
14
|
"relative flex items-center justify-center",
|
|
15
|
-
"[&>svg]:relative [&>svg]:z-
|
|
15
|
+
"[&>svg]:relative [&>svg]:z-raised",
|
|
16
16
|
"size-9 overflow-visible rounded-none",
|
|
17
17
|
"[&>svg]:size-9 [&>svg]:stroke-2"
|
|
18
18
|
]
|
|
@@ -22,9 +22,9 @@ import { createPortal } from "react-dom";
|
|
|
22
22
|
//#region src/components/dialog/dialog.tsx
|
|
23
23
|
const dialog = tv({
|
|
24
24
|
slots: {
|
|
25
|
-
overlay: ["fixed inset-0 z-
|
|
25
|
+
overlay: ["fixed inset-0 z-dialog bg-layer-backdrop"],
|
|
26
26
|
content: [
|
|
27
|
-
"fixed top-1/2 left-1/2 z-
|
|
27
|
+
"fixed top-1/2 left-1/2 z-dialog flex w-[calc(100%-2rem)] -translate-1/2 flex-col",
|
|
28
28
|
"max-h-[calc(100dvh-2rem)] outline-none",
|
|
29
29
|
"overflow-clip rounded-dialog bg-layer-popover text-foreground",
|
|
30
30
|
"shadow-float ring-1 ring-line-seam"
|
|
@@ -83,8 +83,8 @@ const dialog = tv({
|
|
|
83
83
|
content: []
|
|
84
84
|
},
|
|
85
85
|
1: {
|
|
86
|
-
overlay: ["z-
|
|
87
|
-
content: ["z-
|
|
86
|
+
overlay: ["z-dialog-layer"],
|
|
87
|
+
content: ["z-dialog-layer"]
|
|
88
88
|
}
|
|
89
89
|
},
|
|
90
90
|
nested: {
|
|
@@ -49,8 +49,9 @@ export declare function keepGrabInside(proxyWidth: number, inset?: number): Modi
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function cancelDrag(win?: Window): void;
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
52
|
+
* `--z-index-drag` (`z-drag`) as a number: above every raft-ui layer (popups
|
|
53
|
+
* and dialogs 50, a `layer={1}` dialog 60, the lightbox 70, toasts 80) and an
|
|
54
|
+
* app's own top layers, among the layers rendered in
|
|
54
55
|
* `document.body`, where the copy goes by default. dnd-kit's own default.
|
|
55
56
|
*/
|
|
56
57
|
export declare const DRAG_LIFT_Z_INDEX = 999;
|
|
@@ -109,8 +109,9 @@ function cancelDrag(win = window) {
|
|
|
109
109
|
win.dispatchEvent(new Event("resize"));
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
|
-
*
|
|
113
|
-
*
|
|
112
|
+
* `--z-index-drag` (`z-drag`) as a number: above every raft-ui layer (popups
|
|
113
|
+
* and dialogs 50, a `layer={1}` dialog 60, the lightbox 70, toasts 80) and an
|
|
114
|
+
* app's own top layers, among the layers rendered in
|
|
114
115
|
* `document.body`, where the copy goes by default. dnd-kit's own default.
|
|
115
116
|
*/
|
|
116
117
|
const DRAG_LIFT_Z_INDEX = 999;
|
|
@@ -18,7 +18,7 @@ const drag = tv({
|
|
|
18
18
|
"border-[1.5px] border-dashed border-line-strong bg-fill-subtle"
|
|
19
19
|
],
|
|
20
20
|
hint: [
|
|
21
|
-
"pointer-events-none fixed top-0 left-0 z-
|
|
21
|
+
"pointer-events-none fixed top-0 left-0 z-drag max-w-80",
|
|
22
22
|
"rounded-chip px-2 py-1",
|
|
23
23
|
"font-sans text-caption",
|
|
24
24
|
"bg-layer-hud text-foreground-on-hud shadow-float ring-1 ring-line-seam"
|
|
@@ -66,13 +66,13 @@ const drawer = tv({
|
|
|
66
66
|
extend: drawerMotion,
|
|
67
67
|
slots: {
|
|
68
68
|
overlay: [
|
|
69
|
-
"fixed inset-0 z-
|
|
69
|
+
"fixed inset-0 z-dialog min-h-dvh select-none",
|
|
70
70
|
"supports-[-webkit-touch-callout:none]:absolute",
|
|
71
71
|
"bg-layer-backdrop"
|
|
72
72
|
],
|
|
73
|
-
viewport: ["pointer-events-none fixed inset-0 z-
|
|
73
|
+
viewport: ["pointer-events-none fixed inset-0 z-dialog select-none"],
|
|
74
74
|
popup: [
|
|
75
|
-
"group/drawer-popup pointer-events-auto fixed z-
|
|
75
|
+
"group/drawer-popup pointer-events-auto fixed z-dialog flex h-(--drawer-content-height) flex-col outline-none",
|
|
76
76
|
"[--drawer-inset:12px] [--drawer-content-height:var(--drawer-height,auto)]",
|
|
77
77
|
"data-nested-drawer-open:overflow-hidden",
|
|
78
78
|
"bg-layer-popover text-foreground",
|
|
@@ -80,7 +80,7 @@ const drawer = tv({
|
|
|
80
80
|
],
|
|
81
81
|
content: ["flex min-h-0 flex-1 flex-col rounded-[inherit] select-text", "group-data-swiping/drawer-popup:select-none"],
|
|
82
82
|
swipeHandle: [
|
|
83
|
-
"relative z-
|
|
83
|
+
"relative z-control shrink-0 cursor-grab select-none active:cursor-grabbing",
|
|
84
84
|
"before:absolute before:content-['']",
|
|
85
85
|
"before:rounded-full before:bg-line-seam"
|
|
86
86
|
],
|
|
@@ -9,7 +9,7 @@ import { Menu } from "@base-ui/react/menu";
|
|
|
9
9
|
//#region src/components/dropdown-menu/dropdown-menu.tsx
|
|
10
10
|
const dropdownMenu = tv({ slots: {
|
|
11
11
|
trigger: ["select-none"],
|
|
12
|
-
positioner: ["isolate z-
|
|
12
|
+
positioner: ["isolate z-popup outline-none"],
|
|
13
13
|
content: [
|
|
14
14
|
"max-h-(--available-height) overflow-hidden",
|
|
15
15
|
"outline-none",
|
|
@@ -30,7 +30,7 @@ const filePreview = tv({
|
|
|
30
30
|
media: ["relative h-10 w-8 overflow-hidden rounded-md ring-1", "bg-fill-muted shadow-none ring-line-hairline"]
|
|
31
31
|
},
|
|
32
32
|
variants: { placement: {
|
|
33
|
-
corner: { badge: "absolute -right-1.5 bottom-0.5 z-
|
|
33
|
+
corner: { badge: "absolute -right-1.5 bottom-0.5 z-raised" },
|
|
34
34
|
inline: { badge: "inline-flex h-3.5 w-7 shrink-0 items-center justify-center px-0 py-0" }
|
|
35
35
|
} },
|
|
36
36
|
defaultVariants: { placement: "corner" }
|
|
@@ -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",
|
|
@@ -162,7 +162,7 @@ function NotificationCenterPopup({ viewport = "desktop", size = "md", className,
|
|
|
162
162
|
side,
|
|
163
163
|
sideOffset,
|
|
164
164
|
sticky,
|
|
165
|
-
className: "isolate z-
|
|
165
|
+
className: "isolate z-popup outline-none",
|
|
166
166
|
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
167
167
|
"aria-label": props["aria-label"] ?? "Notification center",
|
|
168
168
|
"data-slot": "notification-center-popup",
|
|
@@ -61,7 +61,7 @@ const panelHeader = tv({
|
|
|
61
61
|
"flex h-(--shell-header-height,var(--header-height)) shrink-0 items-center gap-3 max-md:gap-2",
|
|
62
62
|
panelHeadEdges,
|
|
63
63
|
"border-b border-line-seam bg-layer-canvas text-foreground",
|
|
64
|
-
"max-md:sticky max-md:top-0 max-md:z-
|
|
64
|
+
"max-md:sticky max-md:top-0 max-md:z-chrome"
|
|
65
65
|
]
|
|
66
66
|
}, {
|
|
67
67
|
slots: ["sectionHeader"],
|
|
@@ -21,7 +21,7 @@ const panelSplitAction = tv({ base: [
|
|
|
21
21
|
const splitActionMainParts = [
|
|
22
22
|
"pointer-events-auto rounded-e-none",
|
|
23
23
|
"after:end-0",
|
|
24
|
-
"focus-visible:z-
|
|
24
|
+
"focus-visible:z-raised aria-pressed:z-raised data-pressed:z-raised",
|
|
25
25
|
"bg-(--split-action-main-tint,transparent)",
|
|
26
26
|
"group-hover/split-action:bg-fill-subtle",
|
|
27
27
|
"hover:bg-fill-medium active:bg-fill-medium"
|
|
@@ -40,7 +40,7 @@ const panelSplitActionMenu = tv({
|
|
|
40
40
|
"pointer-events-auto min-w-0 rounded-s-none px-0",
|
|
41
41
|
"w-6 me-5 md:pointer-fine:w-5 md:pointer-fine:me-0",
|
|
42
42
|
"after:start-0 after:inset-e-[-21.5px] md:pointer-fine:after:-end-[calc(var(--spacing-control-hit)+1.5px)]",
|
|
43
|
-
"focus-visible:z-
|
|
43
|
+
"focus-visible:z-raised",
|
|
44
44
|
"[[data-split-action-main][data-pressed]~&]:[--split-action-menu-tint:var(--fill-subtle)]",
|
|
45
45
|
"[[data-split-action-main][aria-pressed=true]~&]:[--split-action-menu-tint:var(--fill-subtle)]",
|
|
46
46
|
"bg-(--split-action-menu-tint,transparent)",
|
|
@@ -9,7 +9,7 @@ import { Popover } from "@base-ui/react/popover";
|
|
|
9
9
|
const popover = tv({
|
|
10
10
|
slots: {
|
|
11
11
|
trigger: ["select-none"],
|
|
12
|
-
positioner: ["isolate z-
|
|
12
|
+
positioner: ["isolate z-popup outline-none"],
|
|
13
13
|
content: [
|
|
14
14
|
"max-h-(--available-height) min-w-[220px] overflow-hidden",
|
|
15
15
|
"outline-none",
|
|
@@ -10,7 +10,7 @@ import { PreviewCard } from "@base-ui/react/preview-card";
|
|
|
10
10
|
const previewCard = tv({
|
|
11
11
|
slots: {
|
|
12
12
|
trigger: [],
|
|
13
|
-
positioner: ["isolate z-
|
|
13
|
+
positioner: ["isolate z-popup outline-none"],
|
|
14
14
|
popup: [
|
|
15
15
|
"max-h-(--available-height) min-w-[220px] overflow-hidden",
|
|
16
16
|
"outline-none",
|
|
@@ -45,7 +45,7 @@ const pullToRefreshIndicator = tv({
|
|
|
45
45
|
surface: ["size-full"]
|
|
46
46
|
},
|
|
47
47
|
android: {
|
|
48
|
-
root: ["sticky top-0 z-
|
|
48
|
+
root: ["sticky top-0 z-sticky h-0 overflow-visible"],
|
|
49
49
|
surface: [
|
|
50
50
|
"absolute inset-x-0 top-0 mx-auto size-10 rounded-full bg-layer-popover shadow-float",
|
|
51
51
|
"translate-y-[calc(var(--pull-distance)-100%)]",
|
|
@@ -4,7 +4,7 @@ const resizable = tv({ slots: {
|
|
|
4
4
|
group: ["flex size-full min-h-0 min-w-0", "data-[orientation=vertical]:flex-col"],
|
|
5
5
|
panel: ["min-h-0 min-w-0"],
|
|
6
6
|
handle: [
|
|
7
|
-
"right-0 z-
|
|
7
|
+
"right-0 z-control cursor-ew-resize touch-none select-none",
|
|
8
8
|
"relative -mr-3 flex w-3 shrink-0 items-center justify-center pointer-coarse:-mr-6 pointer-coarse:w-6",
|
|
9
9
|
"before:pointer-events-none before:absolute before:transition-colors before:content-['']",
|
|
10
10
|
"focus-visible:outline-none focus-visible:before:outline-2 focus-visible:before:outline-offset-2 focus-visible:before:outline-foreground",
|
|
@@ -469,6 +469,7 @@
|
|
|
469
469
|
.r-scroll-area > .r-scroll-area__gutters {
|
|
470
470
|
pointer-events: none;
|
|
471
471
|
user-select: none;
|
|
472
|
+
/* raft-ui: z-index the gutters paint over every layer inside the area (its root is isolate) until slock's layers inside its ScrollAreas are named (#218 step 2); then var(--z-index-scrollbar). */
|
|
472
473
|
z-index: 2147483647;
|
|
473
474
|
}
|
|
474
475
|
/*
|
|
@@ -39,7 +39,7 @@ const select = tv({
|
|
|
39
39
|
"[&>svg]:size-4 [&>svg]:stroke-2 [&>svg_*]:stroke-2"
|
|
40
40
|
],
|
|
41
41
|
value: ["flex min-w-0 flex-1 truncate text-left"],
|
|
42
|
-
positioner: ["isolate z-
|
|
42
|
+
positioner: ["isolate z-popup outline-none"],
|
|
43
43
|
content: [
|
|
44
44
|
"relative max-h-(--available-height) min-w-[max(var(--anchor-width),220px)] overflow-hidden",
|
|
45
45
|
"max-w-[min(var(--available-width),max(var(--anchor-width),24rem))]",
|
|
@@ -92,7 +92,7 @@ const select = tv({
|
|
|
92
92
|
groupLabel: ["py-2", "px-2.5 pt-2 pb-1 text-caption font-bold text-foreground-hint"],
|
|
93
93
|
separator: ["h-px shrink-0 border-0", "-mx-1 my-1 bg-line-hairline"],
|
|
94
94
|
scrollArrow: [
|
|
95
|
-
"absolute inset-x-0 z-
|
|
95
|
+
"absolute inset-x-0 z-raised flex h-6 w-full cursor-default items-center justify-center",
|
|
96
96
|
"outline-none transition-colors",
|
|
97
97
|
"data-[direction=up]:top-0 data-[direction=down]:bottom-0",
|
|
98
98
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
@@ -3,7 +3,7 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
3
3
|
const selectionToolbar = tv({
|
|
4
4
|
slots: {
|
|
5
5
|
dock: [
|
|
6
|
-
"pointer-events-none absolute inset-x-0 bottom-0 z-
|
|
6
|
+
"pointer-events-none absolute inset-x-0 bottom-0 z-float flex justify-center",
|
|
7
7
|
"px-5 pb-[calc(--spacing(3)+env(safe-area-inset-bottom))]",
|
|
8
8
|
"*:pointer-events-auto"
|
|
9
9
|
],
|
|
@@ -16,7 +16,7 @@ const sidebarRecipe = tv({ slots: {
|
|
|
16
16
|
headEdgePull,
|
|
17
17
|
"[@media(max-height:600px)]:h-(--header-height-short)"
|
|
18
18
|
],
|
|
19
|
-
sidebarHeaderMask: ["pointer-events-none absolute inset-x-0 top-0
|
|
19
|
+
sidebarHeaderMask: ["pointer-events-none absolute inset-x-0 top-0 z-below hidden"],
|
|
20
20
|
sidebarHeaderMaskLayer: ["absolute inset-x-0 top-0"],
|
|
21
21
|
sidebarHeaderTitle: ["truncate font-bold", "font-sans text-headline text-foreground max-md:text-foreground-on-frame"],
|
|
22
22
|
sidebarGroupLabel: ["px-5 pt-4 pb-0 md:pointer-fine:px-(--sidebar-glyph-axis) md:pointer-fine:pt-2", "font-sans text-footnote font-bold normal-case tracking-normal text-foreground-hint"],
|
|
@@ -22,7 +22,7 @@ const tabs = tv({
|
|
|
22
22
|
],
|
|
23
23
|
background: ["", "hidden"],
|
|
24
24
|
tab: [
|
|
25
|
-
"relative
|
|
25
|
+
"relative isolate flex shrink-0 cursor-pointer touch-manipulation select-none [-webkit-touch-callout:none] items-center gap-1.5 whitespace-nowrap outline-none",
|
|
26
26
|
"data-[reorderable=true]:cursor-pointer data-[dragging-source=true]:cursor-grabbing",
|
|
27
27
|
"font-sans text-callout font-semibold text-foreground-muted",
|
|
28
28
|
"transition-[background-color,box-shadow,color] duration-100 ease-out",
|
|
@@ -31,7 +31,7 @@ const tabs = tv({
|
|
|
31
31
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:stroke-2 [&_svg:not([class*='size-'])]:size-4",
|
|
32
32
|
"data-disabled:pointer-events-none data-disabled:text-foreground-disabled"
|
|
33
33
|
],
|
|
34
|
-
content: ["relative z-
|
|
34
|
+
content: ["relative z-raised inline-flex items-center gap-[inherit]"],
|
|
35
35
|
label: [""],
|
|
36
36
|
panel: ["outline-none"],
|
|
37
37
|
indicator: ["", "hidden"]
|
|
@@ -416,7 +416,7 @@ function SortableTabsTab({ value, ...props }) {
|
|
|
416
416
|
...baseStyle,
|
|
417
417
|
transform: translate === void 0 ? void 0 : vertical ? `translate3d(0, ${translate}px, 0)` : `translate3d(${translate}px, 0, 0)`,
|
|
418
418
|
transition,
|
|
419
|
-
zIndex: isDragging ?
|
|
419
|
+
zIndex: isDragging ? "var(--z-index-raised)" : baseStyle?.zIndex,
|
|
420
420
|
cursor: isDragging ? "grabbing" : "pointer",
|
|
421
421
|
...isDragging && !home ? PLACE_STYLE : null
|
|
422
422
|
}), [
|
|
@@ -483,7 +483,7 @@ function TabsTabButton({ value, sortableRef, dropPlace = false, className, child
|
|
|
483
483
|
"data-slot": "tabs-tab-content",
|
|
484
484
|
className: content({ className: dropPlace ? "invisible" : void 0 }),
|
|
485
485
|
children
|
|
486
|
-
}), dropPlace ? /* @__PURE__ */ jsx(DropPlaceholder, { className: "absolute inset-0 z-
|
|
486
|
+
}), dropPlace ? /* @__PURE__ */ jsx(DropPlaceholder, { className: "absolute inset-0 z-raised rounded-control" }) : null]
|
|
487
487
|
});
|
|
488
488
|
}
|
|
489
489
|
function TabsLabel({ className, ...props }) {
|
|
@@ -2,9 +2,9 @@ import { tv } from "../../lib/tv.mjs";
|
|
|
2
2
|
//#region src/components/task-dnd/task-dnd.recipe.ts
|
|
3
3
|
const taskDnd = tv({ slots: {
|
|
4
4
|
draggable: [
|
|
5
|
-
"group/task-draggable relative cursor-grab touch-manipulation select-none [-webkit-touch-callout:none] active:cursor-grabbing",
|
|
5
|
+
"group/task-draggable relative isolate cursor-grab touch-manipulation select-none [-webkit-touch-callout:none] active:cursor-grabbing",
|
|
6
6
|
"outline-none",
|
|
7
|
-
"data-[dragging=true]:z-
|
|
7
|
+
"data-[dragging=true]:z-raised data-[dragging=true]:will-change-transform",
|
|
8
8
|
"data-[disabled=true]:cursor-default data-[disabled=true]:touch-auto",
|
|
9
9
|
"rounded-container",
|
|
10
10
|
"focus-visible:shadow-focus"
|
|
@@ -17,7 +17,7 @@ const threadPanel = tv({ slots: {
|
|
|
17
17
|
titleMeta: ["font-normal text-foreground-hint"],
|
|
18
18
|
actions: panelHeadActions,
|
|
19
19
|
search: [
|
|
20
|
-
"relative z-
|
|
20
|
+
"relative z-chrome flex shrink-0 items-center gap-1.5 py-2",
|
|
21
21
|
"[&>[data-slot=input-group]]:min-w-0 *:data-[slot=input-group]:flex-1",
|
|
22
22
|
"border-b border-line-hairline bg-layer-canvas px-(--surface-inset)"
|
|
23
23
|
],
|
|
@@ -10,8 +10,8 @@ import { Toast } from "@base-ui/react/toast";
|
|
|
10
10
|
//#region src/components/toast/toast.tsx
|
|
11
11
|
const toastStyles = tv({
|
|
12
12
|
slots: {
|
|
13
|
-
viewport: ["pointer-events-none isolate z-
|
|
14
|
-
positioner: ["isolate z-[calc(
|
|
13
|
+
viewport: ["pointer-events-none isolate z-toast w-[min(24rem,calc(100vw-2rem))]", "outline-none"],
|
|
14
|
+
positioner: ["isolate z-[calc(var(--z-index-toast)-var(--toast-index))] outline-none"],
|
|
15
15
|
root: [
|
|
16
16
|
"group/toast pointer-events-auto",
|
|
17
17
|
"select-text",
|
|
@@ -101,7 +101,7 @@ const toastStyles = tv({
|
|
|
101
101
|
layout: {
|
|
102
102
|
stacked: { root: [
|
|
103
103
|
"absolute inset-x-0 bottom-0 mx-auto h-(--toast-stack-height) origin-bottom",
|
|
104
|
-
"z-[calc(
|
|
104
|
+
"z-[calc(var(--z-index-toast)-var(--toast-index))]",
|
|
105
105
|
"before:pointer-events-auto before:absolute before:inset-x-0 before:top-full before:h-[calc(var(--toast-gap)+3px)] before:content-['']",
|
|
106
106
|
"[--toast-peek-dir:-1]",
|
|
107
107
|
"transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+(var(--toast-index)*var(--toast-peek)*var(--toast-peek-dir))))_scale(var(--toast-scale))]",
|
|
@@ -185,8 +185,8 @@ const toastAction = tv({ slots: {
|
|
|
185
185
|
"data-[loading=true]:cursor-wait data-[loading=true]:opacity-100",
|
|
186
186
|
"[&_svg]:pointer-events-none [&_svg]:shrink-0 **:data-icon:size-[1em] [&_svg:not([class*='size-'])]:size-3"
|
|
187
187
|
],
|
|
188
|
-
content: "relative z-
|
|
189
|
-
loadingIndicator: "pointer-events-none absolute inset-0 z-
|
|
188
|
+
content: "relative z-raised inline-flex items-center justify-center gap-[inherit] data-[loading=true]:invisible",
|
|
189
|
+
loadingIndicator: "pointer-events-none absolute inset-0 z-raised flex items-center justify-center"
|
|
190
190
|
} });
|
|
191
191
|
const createToastManager = Toast.createToastManager;
|
|
192
192
|
const useToastManager = Toast.useToastManager;
|
|
@@ -9,7 +9,7 @@ import { Tooltip } from "@base-ui/react/tooltip";
|
|
|
9
9
|
const tooltip = tv({
|
|
10
10
|
slots: {
|
|
11
11
|
trigger: ["select-none"],
|
|
12
|
-
positioner: ["isolate z-
|
|
12
|
+
positioner: ["isolate z-popup pointer-events-none outline-none"],
|
|
13
13
|
content: [
|
|
14
14
|
"pointer-events-none relative inline-block max-w-[min(20rem,var(--available-width,20rem))] min-w-0 px-2.5 py-1",
|
|
15
15
|
"origin-(--transform-origin) outline-none",
|
|
@@ -25,7 +25,7 @@ const tooltip = tv({
|
|
|
25
25
|
],
|
|
26
26
|
body: [
|
|
27
27
|
"block min-w-0 text-footnote whitespace-normal wrap-break-word",
|
|
28
|
-
"**:data-[slot=kbd]:relative **:data-[slot=kbd]:z-
|
|
28
|
+
"**:data-[slot=kbd]:relative **:data-[slot=kbd]:z-raised **:data-[slot=kbd]:ml-1.5",
|
|
29
29
|
"**:data-[slot=kbd-group]:ml-1.5 [&_[data-slot=kbd-group]_[data-slot=kbd]]:ml-0",
|
|
30
30
|
"**:data-[slot=kbd]:h-4 **:data-[slot=kbd]:min-w-4 **:data-[slot=kbd]:px-1 **:data-[slot=kbd]:py-0",
|
|
31
31
|
"[&_[data-slot=kbd][data-glyph=icon]]:px-0",
|
package/dist/lib/list-cell.mjs
CHANGED
|
@@ -5,7 +5,7 @@ const listCell = [
|
|
|
5
5
|
"md:pointer-fine:[--cell-pad-x:calc(var(--page-inset)-var(--cell-inset-x))]",
|
|
6
6
|
"[--cell-inset-end:max(0px,calc(var(--cell-inset-x)-var(--scrollbar-size,0px)))]",
|
|
7
7
|
"pr-[calc(var(--cell-inset-end)+var(--cell-pad-x))] pl-[calc(var(--cell-inset-x)+var(--cell-pad-x))]",
|
|
8
|
-
"before:pointer-events-none before:absolute before
|
|
8
|
+
"before:pointer-events-none before:absolute before:z-below before:block before:content-['']",
|
|
9
9
|
"before:inset-y-0 before:right-(--cell-inset-end) before:left-(--cell-inset-x)",
|
|
10
10
|
"before:rounded-(--cell-radius) before:border-0",
|
|
11
11
|
"before:transition-colors before:duration-150 before:ease-out"
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { classContext, constDeclarator, propertyKey, stringValue } from "./prefer-scroll-area.mjs";
|
|
2
|
+
//#region src/lint/no-raw-z-index.ts
|
|
3
|
+
/**
|
|
4
|
+
* raft-ui/no-raw-z-index: every z-index is a named layer of the scale
|
|
5
|
+
* (design/foundations/elevation.md#layer-order), so a number of the app's own,
|
|
6
|
+
* which ranks its layer above or below layers it doesn't know about, is
|
|
7
|
+
* reported where an app writes it.
|
|
8
|
+
*
|
|
9
|
+
* Reported:
|
|
10
|
+
* - a Tailwind z-index class with a number or an arbitrary value (`z-10`,
|
|
11
|
+
* `-z-1`, `z-[60]`, `z-(--my-z)`, `[z-index:5]`, with any variant prefix or
|
|
12
|
+
* `!`) in a string or template literal that is a class, found as
|
|
13
|
+
* `raft-ui/prefer-scroll-area` finds one (a `className`, `class` or
|
|
14
|
+
* `*ClassName` attribute or property, an argument of `cn`, `tv` and the
|
|
15
|
+
* like, or a `const` of the same file used as a class). `z-auto` and the
|
|
16
|
+
* named layers (`z-raised`, `max-md:z-chrome`) are not reported;
|
|
17
|
+
* - a `zIndex` property whose value is a number or a numeric string
|
|
18
|
+
* (`style={{ zIndex: 10 }}`, `const s = { zIndex: open ? 20 : "5" }`), a
|
|
19
|
+
* `zIndex={n}` JSX attribute, and an assignment `el.style.zIndex = "n"`.
|
|
20
|
+
* A `var(--z-index-…)` string is a name, and is not reported.
|
|
21
|
+
*
|
|
22
|
+
* Allowed with a `raft-ui: z-index <reason>` comment, line or block, on the
|
|
23
|
+
* line above the reported string or property (or at the end of its line), as
|
|
24
|
+
* for `raft-ui/prefer-scroll-area`. A comment without a reason doesn't count.
|
|
25
|
+
*/
|
|
26
|
+
const RAW_Z_CLASS = /(?<![\w-])!?-?z-(?:\d+|\[[^\]\s]*\]|\([^)\s]*\))!?(?![\w-])/;
|
|
27
|
+
const RAW_Z_ARBITRARY = /\[z-index:[^\]]*\]/;
|
|
28
|
+
const NUMERIC = /^\s*[-+]?\d+(?:\.\d+)?\s*$/;
|
|
29
|
+
const ESCAPE = /\braft-ui:\s*z-index\s+\S/;
|
|
30
|
+
/** Whether a class string has a z-index class with a number or an arbitrary value. */
|
|
31
|
+
function hasRawZIndexClass(value) {
|
|
32
|
+
if (!value.includes("z-")) return false;
|
|
33
|
+
return RAW_Z_CLASS.test(value) || RAW_Z_ARBITRARY.test(value);
|
|
34
|
+
}
|
|
35
|
+
/** The numeric literals a `zIndex` value can be: `10`, `-1`, `"10"`, `a ? 20 : undefined`. */
|
|
36
|
+
function numericLiterals(node, out) {
|
|
37
|
+
if (node.type === "ConditionalExpression") {
|
|
38
|
+
numericLiterals(node.consequent, out);
|
|
39
|
+
numericLiterals(node.alternate, out);
|
|
40
|
+
} else if (node.type === "LogicalExpression") {
|
|
41
|
+
numericLiterals(node.left, out);
|
|
42
|
+
numericLiterals(node.right, out);
|
|
43
|
+
} else if (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression" || node.type === "ParenthesizedExpression" || node.type === "JSXExpressionContainer") numericLiterals(node.expression, out);
|
|
44
|
+
else if (node.type === "UnaryExpression" && (node.operator === "-" || node.operator === "+")) {
|
|
45
|
+
if (numericLiterals(node.argument, []).length > 0) out.push(node);
|
|
46
|
+
} else if (node.type === "Literal" && typeof node.value === "number") out.push(node);
|
|
47
|
+
else {
|
|
48
|
+
const text = stringValue(node);
|
|
49
|
+
if (text !== void 0 && NUMERIC.test(text)) out.push(node);
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
const noRawZIndex = {
|
|
54
|
+
meta: {
|
|
55
|
+
type: "suggestion",
|
|
56
|
+
docs: {
|
|
57
|
+
description: "A z-index is a named layer of the Raft Design System's scale (z-raised, z-sticky, ...), not a number.",
|
|
58
|
+
url: "https://raft-design.botiverse.build/foundations/elevation/#layer-order"
|
|
59
|
+
},
|
|
60
|
+
messages: { noRawZIndex: "Use a named layer instead of a z-index number: z-below, z-base, z-raised (inside an `isolate` root), z-control, z-sticky, z-float, z-chrome, z-cover, z-app; a popup, dialog, lightbox, toast or drag lift takes raft-ui's own component and no z-index. If this number must stay, say why in a `// raft-ui: z-index <reason>` comment on the line above. https://raft-design.botiverse.build/foundations/elevation/#layer-order" },
|
|
61
|
+
schema: []
|
|
62
|
+
},
|
|
63
|
+
create(context) {
|
|
64
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode?.();
|
|
65
|
+
let escapeLines;
|
|
66
|
+
function line(index) {
|
|
67
|
+
return sourceCode.getLocFromIndex(index).line;
|
|
68
|
+
}
|
|
69
|
+
/** The lines an escape comment covers: the one it ends on and the next. */
|
|
70
|
+
function escaped() {
|
|
71
|
+
if (escapeLines) return escapeLines;
|
|
72
|
+
escapeLines = /* @__PURE__ */ new Set();
|
|
73
|
+
for (const comment of sourceCode?.getAllComments() ?? []) {
|
|
74
|
+
if (!ESCAPE.test(comment.value)) continue;
|
|
75
|
+
const end = comment.loc?.end.line ?? line(comment.range[1]);
|
|
76
|
+
escapeLines.add(end);
|
|
77
|
+
escapeLines.add(end + 1);
|
|
78
|
+
}
|
|
79
|
+
return escapeLines;
|
|
80
|
+
}
|
|
81
|
+
function startLine(node) {
|
|
82
|
+
return node.loc?.start.line ?? line(node.range[0]);
|
|
83
|
+
}
|
|
84
|
+
/** Reports `node` unless an escape comment covers the line `anchor` starts on. */
|
|
85
|
+
function report(node, anchor) {
|
|
86
|
+
const lines = escaped();
|
|
87
|
+
if (lines.size > 0 && lines.has(startLine(anchor))) return;
|
|
88
|
+
context.report({
|
|
89
|
+
node,
|
|
90
|
+
messageId: "noRawZIndex"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const constStrings = /* @__PURE__ */ new Map();
|
|
94
|
+
const classNames = /* @__PURE__ */ new Set();
|
|
95
|
+
function checkClassString(node, value) {
|
|
96
|
+
if (!hasRawZIndexClass(value)) return;
|
|
97
|
+
if (classContext(node)) return report(node, node);
|
|
98
|
+
const declarator = constDeclarator(node);
|
|
99
|
+
if (!declarator) return;
|
|
100
|
+
const name = declarator.id.name;
|
|
101
|
+
constStrings.set(name, [...constStrings.get(name) ?? [], node]);
|
|
102
|
+
}
|
|
103
|
+
function checkZIndexValue(value, anchor) {
|
|
104
|
+
for (const literal of numericLiterals(value, [])) report(literal, anchor);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
Literal(node) {
|
|
108
|
+
if (typeof node.value === "string") checkClassString(node, node.value);
|
|
109
|
+
},
|
|
110
|
+
TemplateLiteral(node) {
|
|
111
|
+
checkClassString(node, node.quasis.map((quasi) => quasi.value.raw).join(" "));
|
|
112
|
+
},
|
|
113
|
+
Identifier(node) {
|
|
114
|
+
const parent = node.parent;
|
|
115
|
+
if (parent?.type === "Property" && parent.key === node && !parent.computed && !parent.shorthand) return;
|
|
116
|
+
if (classContext(node)) classNames.add(node.name);
|
|
117
|
+
},
|
|
118
|
+
Property(node) {
|
|
119
|
+
if (propertyKey(node) !== "zIndex") return;
|
|
120
|
+
checkZIndexValue(node.value, node);
|
|
121
|
+
},
|
|
122
|
+
JSXAttribute(node) {
|
|
123
|
+
const name = node.name;
|
|
124
|
+
if (name?.type !== "JSXIdentifier" || name.name !== "zIndex") return;
|
|
125
|
+
const value = node.value;
|
|
126
|
+
if (value) checkZIndexValue(value, node);
|
|
127
|
+
},
|
|
128
|
+
AssignmentExpression(node) {
|
|
129
|
+
const target = node.left;
|
|
130
|
+
if (target.type !== "MemberExpression") return;
|
|
131
|
+
const property = target.property;
|
|
132
|
+
if ((target.computed ? stringValue(property) : property.type === "Identifier" ? property.name : void 0) !== "zIndex") return;
|
|
133
|
+
checkZIndexValue(node.right, node);
|
|
134
|
+
},
|
|
135
|
+
"Program:exit"() {
|
|
136
|
+
for (const name of classNames) for (const node of constStrings.get(name) ?? []) report(node, node);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { hasRawZIndexClass, noRawZIndex };
|
package/dist/lint.d.mts
CHANGED
|
@@ -13,8 +13,14 @@ export interface RaftUiLintPlugin {
|
|
|
13
13
|
configs: Record<string, RaftUiLintConfig>;
|
|
14
14
|
}
|
|
15
15
|
export declare const rules: Record<string, RuleModule>;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Every rule of the plugin with its severity, as `recommended.json` lists them.
|
|
18
|
+
* A rule an app can't pass yet ships `off`, so an app that lints with
|
|
19
|
+
* `--max-warnings=0` (slock) stays green on the upgrade; an app turns it on in
|
|
20
|
+
* its own `rules` to clear what it reports, and it turns `error` here once the
|
|
21
|
+
* app has.
|
|
22
|
+
*/
|
|
23
|
+
export declare const recommendedRules: Record<string, "error" | "warn" | "off">;
|
|
18
24
|
declare const plugin: RaftUiLintPlugin;
|
|
19
25
|
/** ESLint flat config: `export default [raftUi.configs.recommended]`. */
|
|
20
26
|
export declare const recommended: RaftUiLintConfig;
|
package/dist/lint.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { preferScrollArea } from "./lint/prefer-scroll-area.mjs";
|
|
2
|
+
import { noRawZIndex } from "./lint/no-raw-z-index.mjs";
|
|
2
3
|
//#region src/lint/index.ts
|
|
3
4
|
/**
|
|
4
5
|
* raft-ui's lint plugin: the Raft Design System's rules for the code of an app
|
|
@@ -10,9 +11,21 @@ import { preferScrollArea } from "./lint/prefer-scroll-area.mjs";
|
|
|
10
11
|
* rule added in a later release reaches the app with the upgrade. See
|
|
11
12
|
* design/about/use-raft-ui.md#lint-rules.
|
|
12
13
|
*/
|
|
13
|
-
const rules = {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const rules = {
|
|
15
|
+
"prefer-scroll-area": preferScrollArea,
|
|
16
|
+
"no-raw-z-index": noRawZIndex
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Every rule of the plugin with its severity, as `recommended.json` lists them.
|
|
20
|
+
* A rule an app can't pass yet ships `off`, so an app that lints with
|
|
21
|
+
* `--max-warnings=0` (slock) stays green on the upgrade; an app turns it on in
|
|
22
|
+
* its own `rules` to clear what it reports, and it turns `error` here once the
|
|
23
|
+
* app has.
|
|
24
|
+
*/
|
|
25
|
+
const recommendedRules = {
|
|
26
|
+
"raft-ui/prefer-scroll-area": "error",
|
|
27
|
+
"raft-ui/no-raw-z-index": "off"
|
|
28
|
+
};
|
|
16
29
|
const plugin = {
|
|
17
30
|
meta: { name: "raft-ui" },
|
|
18
31
|
rules,
|
package/dist/styles.css
CHANGED
|
@@ -200,6 +200,34 @@
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
/* Raft Design System layer order (design/foundations/elevation.md#layer-order).
|
|
204
|
+
Each name is an ordinary Tailwind `z-*` utility (`z-raised`, `max-md:z-chrome`,
|
|
205
|
+
`before:z-below`) and a variable for CSS (`var(--z-index-sticky)`). In-page
|
|
206
|
+
layers stay below 50, where the overlays begin; nothing sits above toasts or
|
|
207
|
+
the drag lift. `z-below`, `z-base` and `z-raised` are local: the component's
|
|
208
|
+
root is `isolate`, so they rank parts inside it only. A component that needs
|
|
209
|
+
a third local layer orders it by DOM order inside its own `isolate`.
|
|
210
|
+
Static, so every variable exists for an app's own CSS whether or not a
|
|
211
|
+
utility uses it. `z-index-named.test.ts` keeps the order. */
|
|
212
|
+
@theme static {
|
|
213
|
+
--z-index-below: -1;
|
|
214
|
+
--z-index-base: 0;
|
|
215
|
+
--z-index-raised: 1;
|
|
216
|
+
--z-index-control: 10;
|
|
217
|
+
--z-index-sticky: 20;
|
|
218
|
+
--z-index-float: 30;
|
|
219
|
+
--z-index-chrome: 35;
|
|
220
|
+
--z-index-cover: 40;
|
|
221
|
+
--z-index-app: 45;
|
|
222
|
+
--z-index-scrollbar: 49;
|
|
223
|
+
--z-index-popup: 50;
|
|
224
|
+
--z-index-dialog: 50;
|
|
225
|
+
--z-index-dialog-layer: 60;
|
|
226
|
+
--z-index-lightbox: 70;
|
|
227
|
+
--z-index-toast: 80;
|
|
228
|
+
--z-index-drag: 999;
|
|
229
|
+
}
|
|
230
|
+
|
|
203
231
|
@theme inline {
|
|
204
232
|
/* A drag settling: the drop and cancel glide, siblings sliding apart, a
|
|
205
233
|
layout reflowing on a drop (design/foundations/motion.md). */
|
package/package.json
CHANGED
|
@@ -91,6 +91,7 @@ When reviewing or editing code that uses raft-ui, check:
|
|
|
91
91
|
- [ ] Product state (upload, permissions, read/unread) lives in the app; the component renders parts, not a `state` prop
|
|
92
92
|
- [ ] No shadow written as `shadow-[var(--…)]`: named utility or fully literal
|
|
93
93
|
- [ ] Every region that scrolls is a `ScrollArea` (or `PanelScrollViewport` in a Panel), not `overflow-auto` / `overflow-scroll`; a native scroller kept on purpose has a `// raft-ui: native-scroll <reason>` comment. The `raft-ui/prefer-scroll-area` lint rule checks it: https://raft-design.botiverse.build/about/use-raft-ui.md#lint-rules
|
|
94
|
+
- [ ] Every z-index is a layer name (`z-raised`, `z-control`, `z-sticky`, `z-float`, `z-chrome`, `z-cover`, `z-app`; `var(--z-index-…)` in CSS), never a number; popups, dialogs, lightboxes, toasts and drag lifts take raft-ui's components and no z-index. A number kept on purpose has a `// raft-ui: z-index <reason>` comment. The `raft-ui/no-raw-z-index` lint rule checks it: https://raft-design.botiverse.build/foundations/elevation.md#layer-order
|
|
94
95
|
|
|
95
96
|
## Stability
|
|
96
97
|
|