atlas-react-kit 1.1.0 → 1.2.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/COMPONENTS.md +3 -3
- package/README.md +1 -1
- package/dist/accordion.js +2 -2
- package/dist/badge.js +5 -2
- package/dist/breadcrumb.js +2 -2
- package/dist/button.js +7 -4
- package/dist/combobox.js +4 -5
- package/dist/dropdown-menu.js +3 -3
- package/dist/info-tip.js +7 -11
- package/dist/internal/listbox-navigation.d.ts +0 -5
- package/dist/internal/listbox-navigation.js +0 -7
- package/dist/internal/overlay-styles.d.ts +0 -2
- package/dist/internal/overlay-styles.js +0 -2
- package/dist/internal/search.d.ts +5 -1
- package/dist/internal/search.js +8 -5
- package/dist/internal/styles.d.ts +27 -0
- package/dist/internal/styles.js +27 -0
- package/dist/internal/tabs-styles.d.ts +8 -7
- package/dist/internal/tabs-styles.js +15 -13
- package/dist/internal/use-media-query.d.ts +5 -0
- package/dist/internal/use-media-query.js +5 -0
- package/dist/kanban.d.ts +1 -1
- package/dist/kanban.js +4 -3
- package/dist/search-picker.d.ts +1 -1
- package/dist/search-picker.js +5 -6
- package/dist/select.js +5 -5
- package/dist/tabs.d.ts +3 -3
- package/dist/tabs.js +4 -4
- package/dist/toggle.d.ts +2 -0
- package/dist/toggle.js +8 -3
- package/package.json +1 -1
package/COMPONENTS.md
CHANGED
|
@@ -75,7 +75,7 @@ theme from `next-themes`, so toast consumers install that too.
|
|
|
75
75
|
| `table-body-skeleton` | `TableBodySkeleton`; `columns`, optional `rows` (default 5) |
|
|
76
76
|
| `tabs` | `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `TabsNav`, `TabsNavLink`, `tabsListVariants`, `tabsTriggerVariants`; list `variant` is `default` or `line`; `TabsNavLink` is the link inside `TabsNav` (required `active`, `asChild` for a router link); `TabsNav` / `TabsList` scroll horizontally only (`overflow-y` hidden, `p-1` counted in the scroller height, edge fade, active item into view, mouse drag scrolls the row) — do not wrap them in `overflow-x-auto` |
|
|
77
77
|
| `toast` | `Toaster`, `toast`; mount one `Toaster` (`position`, `closeButton` (default on), `expand`, `visibleToasts`, `duration`), then `toast(message, options)`. The stack expands on hover and while keyboard focus is inside it; collapsed toasts behind the front one are hidden, `.success`, `.info`, `.warning`, `.error`, `.loading`, `.dismiss(id?)`. Options: `id` (replaces that toast), `description`, `duration`, `action` / `cancel` as `{ label, onClick }`. Kit-owned API: no toast library is exposed |
|
|
78
|
-
| `toggle` | `Toggle`, `toggleVariants
|
|
78
|
+
| `toggle` | `Toggle`, `toggleVariants`; `variant`, `size`. `selectedToggleChrome` is deprecated: `toggleVariants()` already includes it. Pressed state is the selected wash, text, and border via `data-state=on`, `aria-pressed`, and `aria-checked` |
|
|
79
79
|
| `toggle-group` | `ToggleGroup`, `ToggleGroupItem`; `variant`, `size`. Items share `toggleVariants`, so single (radio) and multiple selections match a pressed `Toggle` |
|
|
80
80
|
| `theme-provider` | `ThemeProvider`, `useTheme`; optional `storageKey` (default `atlas-theme`), `enableShortcut` for the `d` toggle |
|
|
81
81
|
| `tooltip` | `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider`; opens on hover and focus; short labels only; content keeps a `max-w-xs` reading width (override with `className`) |
|
|
@@ -124,7 +124,7 @@ each part carries a `data-slot` for parent selectors such as
|
|
|
124
124
|
| `Combobox` | `contentClassName` (panel, default trigger width), `listClassName` (default `max-h-60`); button props go to trigger | `combobox-search`, `combobox-list`, `combobox-option` |
|
|
125
125
|
| `SearchPicker` | `listClassName` (default `max-h-60`); div props go to the root | `search-picker-option`, `search-picker-empty` |
|
|
126
126
|
| `InfoTip` | `contentClassName` (default `w-72`); button props go to the trigger | |
|
|
127
|
-
| `KanbanBoard` | `scrollerClassName`, `columnClassName` (default `
|
|
127
|
+
| `KanbanBoard` | `scrollerClassName`, `columnClassName` (default `flex-1 basis-72 min-w-72` and a drop-area min height; columns grow to fill the board and keep an 18rem minimum so a long row still scrolls), `cardClassName` (cards and the drag overlay); div props go to the root | `kanban-board`, `kanban-scroller`, `kanban-column`, `kanban-column-header`, `kanban-column-empty`, `kanban-card`, `kanban-card-handle`, `kanban-card-body`, `kanban-drag-overlay`, `kanban-action-rail`, `kanban-action-zone`, `kanban-scroll-button`, `kanban-overflow-fade`, `kanban-skeleton` |
|
|
128
128
|
| `chart` pieces | `ChartTooltip` and `ChartLegend` take div props; `ChartLegendKey` `className` | `chart-y-axis`, `chart-tooltip`, `chart-tooltip-row`, `chart-legend`, `chart-legend-key` |
|
|
129
129
|
| `PageHeader`, `PeriodStepper`, `SkipLink` | `PageHeader` `titleClassName`; `PeriodStepper` `labelClassName` | `page-header`, `page-header-heading`, `page-header-title`, `page-header-description`, `page-header-actions`, `period-stepper`, `period-stepper-label`, `skip-link` |
|
|
130
130
|
| `FormCheckboxGroupField` | `className` (the options box), `fieldClassName` (the fieldset) | `form-checkbox-group-options` |
|
|
@@ -132,7 +132,7 @@ each part carries a `data-slot` for parent selectors such as
|
|
|
132
132
|
| `DatePickerButton`, `DateTimePickerButton` | `contentClassName`, `calendarProps` (`disabled` / `hidden` days, `startMonth`, `endMonth`, `weekStartsOn`, date-fns `locale`, `showOutsideDays`, `fixedWeeks`, `showWeekNumber`, `captionLayout`, `today`, `className`); `minDate` / `maxDate` add to its disabled days | `date-picker-value`, `date-picker-footer`, `date-time-picker-time` |
|
|
133
133
|
| `form/*` fields | `fieldClassName` (wrapper); `className` styles the control (on `FormControlField`, the wrapper); `FormSelectField` `contentClassName`; `FormMarkdownField` `previewClassName` | `form-field`, `form-field-header`, `form-field-description`, `form-field-error`, `form-feedback`, `form-markdown-preview` |
|
|
134
134
|
| `Table` | `containerClassName` (the scroll box, e.g. `max-h-96 overflow-y-auto`); `className` styles the `<table>` | |
|
|
135
|
-
| `TabsList`, `TabsNav` | `scrollerClassName`; `TabsNav` `listClassName`; a list `className` height replaces `h-
|
|
135
|
+
| `TabsList`, `TabsNav` | `scrollerClassName`; `TabsNav` `listClassName`; a list `className` height replaces `h-7`; default scroller is `h-9` (`p-1` + list `h-7`) to match `Button` `size="sm"`; `TabsNav` sizes to its links in a flex row, so add `w-full` to stretch it | `tabs-scroller` |
|
|
136
136
|
| `SortableTableHead` | `buttonClassName` | `sortable-table-head-button` |
|
|
137
137
|
| `AccordionTrigger`, `AccordionContent` | `headerClassName`; `AccordionContent` `className` styles the inner box | `accordion-header`, `accordion-content-inner` |
|
|
138
138
|
| `Progress` | `indicatorClassName` | `progress-indicator` |
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ React 19, Tailwind 4, and Node >=20.19 are required. Next 16 is needed only
|
|
|
8
8
|
when using `next/nav-link`, `next/period-stepper`, or `next/tabs-nav-link`.
|
|
9
9
|
|
|
10
10
|
```sh
|
|
11
|
-
npm install --save-exact atlas-react-kit@1.
|
|
11
|
+
npm install --save-exact atlas-react-kit@1.2.0
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
Import components by subpath:
|
package/dist/accordion.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Accordion as AccordionPrimitive } from "radix-ui";
|
|
5
5
|
import { ChevronDownIcon } from "lucide-react";
|
|
6
|
-
import { disabledState, focusRing } from "./internal/styles.js";
|
|
6
|
+
import { disabledState, focusRing, quietTextHover } from "./internal/styles.js";
|
|
7
7
|
import { cn } from "./utils.js";
|
|
8
8
|
/** Stacked sections that expand in place (FAQs, settings groups). */
|
|
9
9
|
function Accordion({ ...props }) {
|
|
@@ -14,7 +14,7 @@ function AccordionItem({ className, ...props }) {
|
|
|
14
14
|
}
|
|
15
15
|
/** `headerClassName` styles the heading wrapper (`data-slot="accordion-header"`). */
|
|
16
16
|
function AccordionTrigger({ className, headerClassName, children, ...props }) {
|
|
17
|
-
return (_jsx(AccordionPrimitive.Header, { "data-slot": "accordion-header", className: cn("flex", headerClassName), children: _jsxs(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn(focusRing, disabledState, "flex flex-1 items-start justify-between gap-4 rounded-none py-4 text-left text-sm font-medium transition-colors
|
|
17
|
+
return (_jsx(AccordionPrimitive.Header, { "data-slot": "accordion-header", className: cn("flex", headerClassName), children: _jsxs(AccordionPrimitive.Trigger, { "data-slot": "accordion-trigger", className: cn(focusRing, disabledState, "flex flex-1 items-start justify-between gap-4 rounded-none py-4 text-left text-sm font-medium transition-colors", quietTextHover, "[&[data-state=open]>svg]:rotate-180", className), ...props, children: [children, _jsx(ChevronDownIcon, { className: "pointer-events-none size-4 shrink-0 translate-y-0.5 text-muted-foreground transition-transform duration-200" })] }) }));
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* `className` styles the padded inner box (`data-slot="accordion-content-inner"`);
|
package/dist/badge.js
CHANGED
|
@@ -2,12 +2,15 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { Slot } from "radix-ui";
|
|
5
|
-
import { focusRing, invalidState } from "./internal/styles.js";
|
|
5
|
+
import { controlText, focusRing, invalidState } from "./internal/styles.js";
|
|
6
6
|
import { cn } from "./utils.js";
|
|
7
7
|
const badgeVariants = cva([
|
|
8
8
|
focusRing,
|
|
9
9
|
invalidState,
|
|
10
|
-
"group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1.5 overflow-hidden rounded-none border-0 bg-transparent px-0 py-0
|
|
10
|
+
"group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1.5 overflow-hidden rounded-none border-0 bg-transparent px-0 py-0",
|
|
11
|
+
controlText,
|
|
12
|
+
// Smaller than `controlText`'s `text-xs`; tailwind-merge keeps this one.
|
|
13
|
+
"text-[0.625rem] transition-colors has-data-[icon=inline-end]:pr-0 has-data-[icon=inline-start]:pl-0 [&>svg]:pointer-events-none [&>svg:not([class*='size-'])]:size-3",
|
|
11
14
|
], {
|
|
12
15
|
variants: {
|
|
13
16
|
variant: {
|
package/dist/breadcrumb.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Slot } from "radix-ui";
|
|
4
4
|
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
5
|
-
import { focusRing } from "./internal/styles.js";
|
|
5
|
+
import { focusRing, quietTextHover } from "./internal/styles.js";
|
|
6
6
|
import { cn } from "./utils.js";
|
|
7
7
|
/**
|
|
8
8
|
* Where the current page sits in a hierarchy. The last item is
|
|
@@ -20,7 +20,7 @@ function BreadcrumbItem({ className, ...props }) {
|
|
|
20
20
|
/** Pass `asChild` to render a router link (e.g. Next `Link`) with these styles. */
|
|
21
21
|
function BreadcrumbLink({ asChild, className, ...props }) {
|
|
22
22
|
const Comp = asChild ? Slot.Root : "a";
|
|
23
|
-
return (_jsx(Comp, { "data-slot": "breadcrumb-link", className: cn(focusRing, "transition-colors
|
|
23
|
+
return (_jsx(Comp, { "data-slot": "breadcrumb-link", className: cn(focusRing, "transition-colors", quietTextHover, className), ...props }));
|
|
24
24
|
}
|
|
25
25
|
function BreadcrumbPage({ className, ...props }) {
|
|
26
26
|
return (_jsx("span", { "data-slot": "breadcrumb-page", "aria-current": "page", className: cn("font-medium text-foreground", className), ...props }));
|
package/dist/button.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { Slot } from "radix-ui";
|
|
5
|
-
import { controlSize, disabledState, focusRing, invalidState, selectedState, } from "./internal/styles.js";
|
|
5
|
+
import { controlSize, controlText, disabledState, focusRing, inlineIcon, invalidState, selectedState, } from "./internal/styles.js";
|
|
6
6
|
import { cn } from "./utils.js";
|
|
7
7
|
/**
|
|
8
8
|
* Outline and ghost hover/focus: selected-foreground border, selected wash, and
|
|
@@ -19,7 +19,10 @@ const buttonVariants = cva([
|
|
|
19
19
|
focusRing,
|
|
20
20
|
invalidState,
|
|
21
21
|
disabledState,
|
|
22
|
-
"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding
|
|
22
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding",
|
|
23
|
+
controlText,
|
|
24
|
+
"transition-all select-none active:not-aria-[haspopup]:translate-y-px",
|
|
25
|
+
inlineIcon.default,
|
|
23
26
|
], {
|
|
24
27
|
variants: {
|
|
25
28
|
variant: {
|
|
@@ -32,11 +35,11 @@ const buttonVariants = cva([
|
|
|
32
35
|
},
|
|
33
36
|
size: {
|
|
34
37
|
default: `${controlSize.default} gap-1.5`,
|
|
35
|
-
xs:
|
|
38
|
+
xs: `h-7 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 ${inlineIcon.sm}`,
|
|
36
39
|
sm: `${controlSize.sm} gap-1`,
|
|
37
40
|
lg: `${controlSize.lg} gap-1.5`,
|
|
38
41
|
icon: "size-10",
|
|
39
|
-
"icon-xs":
|
|
42
|
+
"icon-xs": `size-7 ${inlineIcon.sm}`,
|
|
40
43
|
"icon-sm": "size-9",
|
|
41
44
|
"icon-lg": "size-11",
|
|
42
45
|
},
|
package/dist/combobox.js
CHANGED
|
@@ -5,9 +5,10 @@ import { ChevronDownIcon } from "lucide-react";
|
|
|
5
5
|
import { Button } from "./button.js";
|
|
6
6
|
import { Input } from "./input.js";
|
|
7
7
|
import { formControlTriggerClassName } from "./internal/form-control.js";
|
|
8
|
-
import {
|
|
8
|
+
import { handleListboxKey, listboxOptionId, } from "./internal/listbox-navigation.js";
|
|
9
9
|
import { ListboxEmptyStatus, PickerOption } from "./internal/listbox-option.js";
|
|
10
|
-
import { createSearchIndex, filterSearchIndex, normalizeSearchQuery, } from "./internal/search.js";
|
|
10
|
+
import { createSearchIndex, filterSearchIndex, foldSearchText, normalizeSearchQuery, } from "./internal/search.js";
|
|
11
|
+
import { listboxScroll } from "./internal/styles.js";
|
|
11
12
|
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
12
13
|
import { cn, onInputChange } from "./utils.js";
|
|
13
14
|
const CREATE_OPTION_KEY = "__atlas-combobox-create";
|
|
@@ -134,9 +135,7 @@ export function Combobox({ options, value, onValueChange, placeholder = "Select"
|
|
|
134
135
|
},
|
|
135
136
|
});
|
|
136
137
|
};
|
|
137
|
-
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ...props, id: triggerId, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled: disabled, onKeyDown: onTriggerKeyDown, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: cn("w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", contentClassName), children: [_jsx("div", { "data-slot": "combobox-search", className: "border-b p-2", children: _jsx(Input, { value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption ? listboxOptionId(listId, highlight) : undefined }) }), _jsx("ul", { id: listId, role: "listbox", "data-slot": "combobox-list", "aria-label": ariaLabelledBy ? undefined : ariaLabel, "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? undefined : triggerId), className: empty
|
|
138
|
-
? "sr-only"
|
|
139
|
-
: cn("max-h-60 overflow-y-auto p-1", listClassName), children: list.map((option, index) => {
|
|
138
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { ...props, id: triggerId, type: "button", variant: "outline", role: "combobox", "aria-expanded": open, "aria-controls": listId, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, disabled: disabled, onKeyDown: onTriggerKeyDown, className: cn(formControlTriggerClassName, "justify-between", !selected && "text-muted-foreground", className), children: [_jsx("span", { className: "truncate", children: selected?.label ?? placeholder }), _jsx(ChevronDownIcon, { "data-icon": "inline-end", className: "opacity-50" })] }) }), _jsxs(PopoverContent, { align: "start", className: cn("w-[var(--radix-popover-trigger-width)] gap-0 rounded-none p-0", contentClassName), children: [_jsx("div", { "data-slot": "combobox-search", className: "border-b p-2", children: _jsx(Input, { value: query, onChange: onQueryChange, onKeyDown: onSearchKeyDown, placeholder: searchPlaceholder, "aria-label": searchPlaceholder, "aria-autocomplete": "list", "aria-controls": listId, "aria-activedescendant": activeOption ? listboxOptionId(listId, highlight) : undefined }) }), _jsx("ul", { id: listId, role: "listbox", "data-slot": "combobox-list", "aria-label": ariaLabelledBy ? undefined : ariaLabel, "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? undefined : triggerId), className: empty ? "sr-only" : cn(listboxScroll, "p-1", listClassName), children: list.map((option, index) => {
|
|
140
139
|
const isCreate = createOption != null && option === createOption;
|
|
141
140
|
const isSelected = option.value === value && !isCreate;
|
|
142
141
|
return (_jsx(PickerOption, { "data-slot": "combobox-option", listId: listId, index: index, active: index === highlight, selected: isSelected, showCheck: true, item: option, getLabel: getOptionLabel, onHighlight: setHighlight, onSelect: selectOption }, isCreate ? CREATE_OPTION_KEY : option.value));
|
package/dist/dropdown-menu.js
CHANGED
|
@@ -3,11 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
5
5
|
import { CheckIcon, ChevronRightIcon } from "lucide-react";
|
|
6
|
-
import { menuLabel,
|
|
7
|
-
import { dataDisabledState, optionState } from "./internal/styles.js";
|
|
6
|
+
import { menuLabel, optionRow, overlayFadeZoom, overlaySideSlide, overlaySurface, } from "./internal/overlay-styles.js";
|
|
7
|
+
import { dataDisabledState, inlineIcon, optionState, } from "./internal/styles.js";
|
|
8
8
|
import { cn } from "./utils.js";
|
|
9
9
|
/** Menu row: the shared option row with menu padding and the inset slot. */
|
|
10
|
-
const menuItemClassName = cn(optionRow, optionState.focus, dataDisabledState,
|
|
10
|
+
const menuItemClassName = cn(optionRow, optionState.focus, dataDisabledState, inlineIcon.default, "pr-3 data-inset:pl-9");
|
|
11
11
|
const menuContentClassName = cn(overlaySurface, overlaySideSlide, overlayFadeZoom, "z-50 overflow-x-hidden overflow-y-auto p-1");
|
|
12
12
|
/** Action menu for commands (row actions, overflow menus). Use `Select` to pick a value. */
|
|
13
13
|
function DropdownMenu({ ...props }) {
|
package/dist/info-tip.js
CHANGED
|
@@ -3,15 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { CircleHelpIcon } from "lucide-react";
|
|
5
5
|
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, } from "./popover.js";
|
|
6
|
-
import { focusRing, hitArea44 } from "./internal/styles.js";
|
|
6
|
+
import { focusRing, hitArea44, quietTextHover } from "./internal/styles.js";
|
|
7
|
+
import { HOVER_MEDIA_QUERY, useMediaQuery } from "./internal/use-media-query.js";
|
|
7
8
|
import { cn } from "./utils.js";
|
|
8
|
-
/**
|
|
9
|
-
* True when a mouse can hover. Touch and coarse pointers must use click;
|
|
10
|
-
* a hover-open popover would trap them after the first tap.
|
|
11
|
-
*/
|
|
12
|
-
function canHoverOpen() {
|
|
13
|
-
return window.matchMedia("(hover: hover) and (pointer: fine)").matches;
|
|
14
|
-
}
|
|
15
9
|
/**
|
|
16
10
|
* Longer help than a Tooltip: a Popover with a 20px glyph and a 44px hit
|
|
17
11
|
* area. Hover opens only on a fine pointer; click, tap, and keyboard always
|
|
@@ -25,6 +19,8 @@ function InfoTip({ label, title, description, children, layout = "box", side = "
|
|
|
25
19
|
const openedBy = React.useRef(null);
|
|
26
20
|
const titleId = React.useId();
|
|
27
21
|
const inline = layout === "inline";
|
|
22
|
+
// Hover opens only for a pointer that can hover; touch must click.
|
|
23
|
+
const canHoverOpen = useMediaQuery(HOVER_MEDIA_QUERY);
|
|
28
24
|
const cancelClose = () => {
|
|
29
25
|
if (closeTimer.current !== null) {
|
|
30
26
|
window.clearTimeout(closeTimer.current);
|
|
@@ -32,7 +28,7 @@ function InfoTip({ label, title, description, children, layout = "box", side = "
|
|
|
32
28
|
}
|
|
33
29
|
};
|
|
34
30
|
const openFromHover = () => {
|
|
35
|
-
if (!canHoverOpen
|
|
31
|
+
if (!canHoverOpen)
|
|
36
32
|
return;
|
|
37
33
|
cancelClose();
|
|
38
34
|
if (open)
|
|
@@ -41,7 +37,7 @@ function InfoTip({ label, title, description, children, layout = "box", side = "
|
|
|
41
37
|
setOpen(true);
|
|
42
38
|
};
|
|
43
39
|
const closeFromHover = () => {
|
|
44
|
-
if (!canHoverOpen
|
|
40
|
+
if (!canHoverOpen || openedBy.current !== "hover")
|
|
45
41
|
return;
|
|
46
42
|
cancelClose();
|
|
47
43
|
// Leave a beat so the pointer can travel from the glyph into the panel.
|
|
@@ -55,7 +51,7 @@ function InfoTip({ label, title, description, children, layout = "box", side = "
|
|
|
55
51
|
if (next)
|
|
56
52
|
openedBy.current = "click";
|
|
57
53
|
setOpen(next);
|
|
58
|
-
}, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { ...props, type: "button", "aria-label": label, "data-slot": "info-tip-trigger", "data-layout": layout, className: cn(focusRing, "relative inline-flex shrink-0 items-center justify-center rounded-none text-muted-foreground
|
|
54
|
+
}, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { ...props, type: "button", "aria-label": label, "data-slot": "info-tip-trigger", "data-layout": layout, className: cn(focusRing, "relative inline-flex shrink-0 items-center justify-center rounded-none text-muted-foreground", quietTextHover, inline ? cn("size-5 align-middle", hitArea44) : "size-11", className), onMouseEnter: openFromHover, onMouseLeave: closeFromHover, onClick: (event) => {
|
|
59
55
|
// Hover already opened the panel; this click pins it instead of
|
|
60
56
|
// toggling it closed (Playwright and real mice both hover before
|
|
61
57
|
// they click). Preventing default skips Radix's toggle.
|
|
@@ -28,8 +28,3 @@ export declare function handleListboxKey(event: {
|
|
|
28
28
|
setHighlight: (index: number) => void;
|
|
29
29
|
onEnter: (index: number) => void;
|
|
30
30
|
}): boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Case-fold and strip combining marks so "nino" matches "Niño". Shared by
|
|
33
|
-
* Combobox and SearchPicker (which re-exports it).
|
|
34
|
-
*/
|
|
35
|
-
export declare function foldSearchText(value: string): string;
|
|
@@ -66,10 +66,3 @@ export function handleListboxKey(event, { highlight, length, setHighlight, onEnt
|
|
|
66
66
|
}
|
|
67
67
|
return false;
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Case-fold and strip combining marks so "nino" matches "Niño". Shared by
|
|
71
|
-
* Combobox and SearchPicker (which re-exports it).
|
|
72
|
-
*/
|
|
73
|
-
export function foldSearchText(value) {
|
|
74
|
-
return value.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();
|
|
75
|
-
}
|
|
@@ -22,7 +22,5 @@ export declare const overlayFadeZoom = "duration-100 data-open:animate-in data-o
|
|
|
22
22
|
* indicator, plus the highlight from `optionState`.
|
|
23
23
|
*/
|
|
24
24
|
export declare const optionRow = "relative flex w-full cursor-default items-center gap-2.5 rounded-none py-2 pl-3 text-left text-sm outline-hidden select-none";
|
|
25
|
-
/** Icons in a row: no pointer events, no shrinking, 14px unless sized. */
|
|
26
|
-
export declare const optionIcon = "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5";
|
|
27
25
|
/** Group label in a menu or listbox (DropdownMenuLabel, SelectLabel). */
|
|
28
26
|
export declare const menuLabel = "px-3 py-2 text-xs font-semibold tracking-wider text-muted-foreground uppercase";
|
|
@@ -22,7 +22,5 @@ export const overlayFadeZoom = `${overlayFade} data-open:zoom-in-95 data-closed:
|
|
|
22
22
|
* indicator, plus the highlight from `optionState`.
|
|
23
23
|
*/
|
|
24
24
|
export const optionRow = "relative flex w-full cursor-default items-center gap-2.5 rounded-none py-2 pl-3 text-left text-sm outline-hidden select-none";
|
|
25
|
-
/** Icons in a row: no pointer events, no shrinking, 14px unless sized. */
|
|
26
|
-
export const optionIcon = "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5";
|
|
27
25
|
/** Group label in a menu or listbox (DropdownMenuLabel, SelectLabel). */
|
|
28
26
|
export const menuLabel = "px-3 py-2 text-xs font-semibold tracking-wider text-muted-foreground uppercase";
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Case-fold and strip combining marks so "nino" matches "Niño". Shared by
|
|
3
|
+
* Combobox and SearchPicker (which re-exports it).
|
|
4
|
+
*/
|
|
5
|
+
export declare function foldSearchText(value: string): string;
|
|
1
6
|
/** Fold the query once; item labels are folded when their catalog changes. */
|
|
2
7
|
export declare function normalizeSearchQuery(query: string): string;
|
|
3
|
-
export declare function matchesSearchLabel(label: string, needle: string): boolean;
|
|
4
8
|
export declare function createSearchIndex<T>(items: T[], getLabel: (item: T) => string): {
|
|
5
9
|
item: T;
|
|
6
10
|
label: string;
|
package/dist/internal/search.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Case-fold and strip combining marks so "nino" matches "Niño". Shared by
|
|
3
|
+
* Combobox and SearchPicker (which re-exports it).
|
|
4
|
+
*/
|
|
5
|
+
export function foldSearchText(value) {
|
|
6
|
+
return value.normalize("NFD").replace(/\p{M}/gu, "").toLowerCase();
|
|
7
|
+
}
|
|
2
8
|
/** Fold the query once; item labels are folded when their catalog changes. */
|
|
3
9
|
export function normalizeSearchQuery(query) {
|
|
4
10
|
return foldSearchText(query.trim());
|
|
5
11
|
}
|
|
6
|
-
export function matchesSearchLabel(label, needle) {
|
|
7
|
-
return label.includes(needle);
|
|
8
|
-
}
|
|
9
12
|
export function createSearchIndex(items, getLabel) {
|
|
10
13
|
return items.map((item) => ({ item, label: foldSearchText(getLabel(item)) }));
|
|
11
14
|
}
|
|
12
15
|
export function filterSearchIndex(index, needle) {
|
|
13
16
|
return index
|
|
14
|
-
.filter(({ label }) =>
|
|
17
|
+
.filter(({ label }) => label.includes(needle))
|
|
15
18
|
.map(({ item }) => item);
|
|
16
19
|
}
|
|
@@ -39,6 +39,11 @@ export declare const selectedState: {
|
|
|
39
39
|
};
|
|
40
40
|
/** The "No results" row of a listbox. */
|
|
41
41
|
export declare const listboxEmpty = "px-3 py-4 text-center text-sm text-muted-foreground";
|
|
42
|
+
/**
|
|
43
|
+
* The scrolling frame of a listbox (Combobox, SearchPicker): about ten rows
|
|
44
|
+
* tall, then scrolls. A consumer `listClassName` replaces the height.
|
|
45
|
+
*/
|
|
46
|
+
export declare const listboxScroll = "max-h-60 overflow-y-auto";
|
|
42
47
|
/** Options in menus and listboxes. */
|
|
43
48
|
export declare const optionState: {
|
|
44
49
|
/** Highlight as focus moves: grey fill plus a 2px ring bar (the fill alone is 1.1:1). */
|
|
@@ -72,6 +77,28 @@ export declare const controlSize: {
|
|
|
72
77
|
sm: string;
|
|
73
78
|
lg: string;
|
|
74
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* Label text of a control (Button, Toggle, Badge): small, bold, wide-tracked
|
|
82
|
+
* uppercase on one line. Badge adds its own `text-[0.625rem]` after it;
|
|
83
|
+
* tailwind-merge then drops the `text-xs`.
|
|
84
|
+
*/
|
|
85
|
+
export declare const controlText = "text-xs font-semibold tracking-widest whitespace-nowrap uppercase";
|
|
86
|
+
/**
|
|
87
|
+
* Icons inside a control or row: no pointer events, no shrinking, 14px
|
|
88
|
+
* unless the icon sets its own `size-*`. `sm` lowers that default to 12px
|
|
89
|
+
* for the xs controls; it goes after `default`, and tailwind-merge keeps
|
|
90
|
+
* the later size.
|
|
91
|
+
*/
|
|
92
|
+
export declare const inlineIcon: {
|
|
93
|
+
default: string;
|
|
94
|
+
sm: string;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Brand-colored text on hover and keyboard focus for quiet links and
|
|
98
|
+
* triggers (BreadcrumbLink, AccordionTrigger, InfoTip). DESIGN_RULES.md,
|
|
99
|
+
* "Tokens": brand text is `text-selected-foreground`, never `text-primary`.
|
|
100
|
+
*/
|
|
101
|
+
export declare const quietTextHover = "hover:text-selected-foreground focus-visible:text-selected-foreground";
|
|
75
102
|
/**
|
|
76
103
|
* Uppercase muted label used on tiles, legends, and thin section chrome.
|
|
77
104
|
* Re-exported publicly from `atlas-react-kit/stat-tile`.
|
package/dist/internal/styles.js
CHANGED
|
@@ -39,6 +39,11 @@ export const selectedState = {
|
|
|
39
39
|
};
|
|
40
40
|
/** The "No results" row of a listbox. */
|
|
41
41
|
export const listboxEmpty = "px-3 py-4 text-center text-sm text-muted-foreground";
|
|
42
|
+
/**
|
|
43
|
+
* The scrolling frame of a listbox (Combobox, SearchPicker): about ten rows
|
|
44
|
+
* tall, then scrolls. A consumer `listClassName` replaces the height.
|
|
45
|
+
*/
|
|
46
|
+
export const listboxScroll = "max-h-60 overflow-y-auto";
|
|
42
47
|
/** Options in menus and listboxes. */
|
|
43
48
|
export const optionState = {
|
|
44
49
|
/** Highlight as focus moves: grey fill plus a 2px ring bar (the fill alone is 1.1:1). */
|
|
@@ -72,6 +77,28 @@ export const controlSize = {
|
|
|
72
77
|
sm: "h-9 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
|
73
78
|
lg: "h-11 px-8 has-data-[icon=inline-end]:pr-5 has-data-[icon=inline-start]:pl-5",
|
|
74
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* Label text of a control (Button, Toggle, Badge): small, bold, wide-tracked
|
|
82
|
+
* uppercase on one line. Badge adds its own `text-[0.625rem]` after it;
|
|
83
|
+
* tailwind-merge then drops the `text-xs`.
|
|
84
|
+
*/
|
|
85
|
+
export const controlText = "text-xs font-semibold tracking-widest whitespace-nowrap uppercase";
|
|
86
|
+
/**
|
|
87
|
+
* Icons inside a control or row: no pointer events, no shrinking, 14px
|
|
88
|
+
* unless the icon sets its own `size-*`. `sm` lowers that default to 12px
|
|
89
|
+
* for the xs controls; it goes after `default`, and tailwind-merge keeps
|
|
90
|
+
* the later size.
|
|
91
|
+
*/
|
|
92
|
+
export const inlineIcon = {
|
|
93
|
+
default: "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
94
|
+
sm: "[&_svg:not([class*='size-'])]:size-3",
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Brand-colored text on hover and keyboard focus for quiet links and
|
|
98
|
+
* triggers (BreadcrumbLink, AccordionTrigger, InfoTip). DESIGN_RULES.md,
|
|
99
|
+
* "Tokens": brand text is `text-selected-foreground`, never `text-primary`.
|
|
100
|
+
*/
|
|
101
|
+
export const quietTextHover = "hover:text-selected-foreground focus-visible:text-selected-foreground";
|
|
75
102
|
/**
|
|
76
103
|
* Uppercase muted label used on tiles, legends, and thin section chrome.
|
|
77
104
|
* Re-exported publicly from `atlas-react-kit/stat-tile`.
|
|
@@ -10,13 +10,14 @@ declare const tabsListVariants: (props?: ({
|
|
|
10
10
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
11
11
|
/**
|
|
12
12
|
* Horizontal scroller around a tab row. `p-1` leaves room for the active
|
|
13
|
-
* border and focus ring; the height is the `h-
|
|
14
|
-
* (`h-
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* `overflow-y` is not hidden. Line
|
|
18
|
-
* (`h-
|
|
19
|
-
* `w-full`. `theme.css` hides the
|
|
13
|
+
* border and focus ring; the height is the `h-7` list plus that padding
|
|
14
|
+
* (`h-9` = 28px + 8px) so the list fits the content box and the outer
|
|
15
|
+
* row matches `Button` `size="sm"`. Putting padding on an overflow box
|
|
16
|
+
* without this height makes `scrollHeight` taller than `clientHeight`
|
|
17
|
+
* and a vertical scrollbar appears if `overflow-y` is not hidden. Line
|
|
18
|
+
* variant adds `pb-2` for the underline (`h-10` = 28px + 4px + 8px). A
|
|
19
|
+
* block, so it fills its parent without `w-full`. `theme.css` hides the
|
|
20
|
+
* scrollbar and draws the edge fades.
|
|
20
21
|
*/
|
|
21
22
|
declare const tabsScrollerVariants: (props?: ({
|
|
22
23
|
variant?: "default" | "line" | null | undefined;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cva } from "class-variance-authority";
|
|
2
|
-
import { disabledState, focusRing, selectedState } from "./styles.js";
|
|
2
|
+
import { disabledState, focusRing, inlineIcon, selectedState, } from "./styles.js";
|
|
3
3
|
/**
|
|
4
4
|
* Tab row. `TabsList` and `TabsNav` pass `orientation`, which picks plain
|
|
5
5
|
* size classes so a consumer `className` (`h-9`) replaces them. Called
|
|
@@ -13,8 +13,8 @@ const tabsListVariants = cva("group/tabs-list inline-flex w-max min-w-full items
|
|
|
13
13
|
line: "gap-1 bg-transparent",
|
|
14
14
|
},
|
|
15
15
|
orientation: {
|
|
16
|
-
auto: 'group-data-[orientation="horizontal"]/tabs:h-
|
|
17
|
-
horizontal: "h-
|
|
16
|
+
auto: 'group-data-[orientation="horizontal"]/tabs:h-7 group-data-[orientation="vertical"]/tabs:h-fit group-data-[orientation="vertical"]/tabs:flex-col',
|
|
17
|
+
horizontal: "h-7",
|
|
18
18
|
vertical: "h-fit flex-col",
|
|
19
19
|
},
|
|
20
20
|
},
|
|
@@ -25,13 +25,14 @@ const tabsListVariants = cva("group/tabs-list inline-flex w-max min-w-full items
|
|
|
25
25
|
});
|
|
26
26
|
/**
|
|
27
27
|
* Horizontal scroller around a tab row. `p-1` leaves room for the active
|
|
28
|
-
* border and focus ring; the height is the `h-
|
|
29
|
-
* (`h-
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `overflow-y` is not hidden. Line
|
|
33
|
-
* (`h-
|
|
34
|
-
* `w-full`. `theme.css` hides the
|
|
28
|
+
* border and focus ring; the height is the `h-7` list plus that padding
|
|
29
|
+
* (`h-9` = 28px + 8px) so the list fits the content box and the outer
|
|
30
|
+
* row matches `Button` `size="sm"`. Putting padding on an overflow box
|
|
31
|
+
* without this height makes `scrollHeight` taller than `clientHeight`
|
|
32
|
+
* and a vertical scrollbar appears if `overflow-y` is not hidden. Line
|
|
33
|
+
* variant adds `pb-2` for the underline (`h-10` = 28px + 4px + 8px). A
|
|
34
|
+
* block, so it fills its parent without `w-full`. `theme.css` hides the
|
|
35
|
+
* scrollbar and draws the edge fades.
|
|
35
36
|
*/
|
|
36
37
|
const tabsScrollerVariants = cva("relative box-border min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain p-1", {
|
|
37
38
|
variants: {
|
|
@@ -45,8 +46,8 @@ const tabsScrollerVariants = cva("relative box-border min-w-0 max-w-full overflo
|
|
|
45
46
|
},
|
|
46
47
|
},
|
|
47
48
|
compoundVariants: [
|
|
48
|
-
{ variant: "default", orientation: "horizontal", className: "h-
|
|
49
|
-
{ variant: "line", orientation: "horizontal", className: "h-
|
|
49
|
+
{ variant: "default", orientation: "horizontal", className: "h-9" },
|
|
50
|
+
{ variant: "line", orientation: "horizontal", className: "h-10" },
|
|
50
51
|
],
|
|
51
52
|
defaultVariants: {
|
|
52
53
|
variant: "default",
|
|
@@ -59,7 +60,8 @@ const tabsTriggerVariants = cva([
|
|
|
59
60
|
// flex-none + px-4: every trigger and TabsNav link keeps the same
|
|
60
61
|
// horizontal padding. flex-1 used to grow short labels and make the
|
|
61
62
|
// longest (e.g. Apple Reminders) look tighter. No last-child padding.
|
|
62
|
-
'relative inline-flex h-full min-w-max flex-none items-center justify-center gap-2 border border-transparent px-4 py-1.5 text-xs font-semibold tracking-wider whitespace-nowrap text-foreground/60 uppercase transition-all group-data-[orientation="vertical"]/tabs:w-full group-data-[orientation="vertical"]/tabs:justify-start group-data-[orientation="vertical"]/tabs:px-4 group-data-[orientation="vertical"]/tabs:py-2 hover:text-foreground has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5 dark:text-muted-foreground dark:hover:text-foreground
|
|
63
|
+
'relative inline-flex h-full min-w-max flex-none items-center justify-center gap-2 border border-transparent px-4 py-1.5 text-xs font-semibold tracking-wider whitespace-nowrap text-foreground/60 uppercase transition-all group-data-[orientation="vertical"]/tabs:w-full group-data-[orientation="vertical"]/tabs:justify-start group-data-[orientation="vertical"]/tabs:px-4 group-data-[orientation="vertical"]/tabs:py-2 hover:text-foreground has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5 dark:text-muted-foreground dark:hover:text-foreground',
|
|
64
|
+
inlineIcon.default,
|
|
63
65
|
'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state="active"]:border-transparent group-data-[variant=line]/tabs-list:data-[state="active"]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state="active"]:bg-transparent',
|
|
64
66
|
selectedState.active,
|
|
65
67
|
'after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation="horizontal"]/tabs:after:inset-x-0 group-data-[orientation="horizontal"]/tabs:after:bottom-[-5px] group-data-[orientation="horizontal"]/tabs:after:h-0.5 group-data-[orientation="vertical"]/tabs:after:inset-y-0 group-data-[orientation="vertical"]/tabs:after:-right-1 group-data-[orientation="vertical"]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state="active"]:after:opacity-100',
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/** Tailwind `md` breakpoint. Used for range calendars that stack on small screens. */
|
|
2
2
|
export declare const MD_MEDIA_QUERY = "(min-width: 768px)";
|
|
3
|
+
/**
|
|
4
|
+
* A pointer that can hover (a mouse or trackpad). Touch and coarse pointers
|
|
5
|
+
* must use click; a hover-open popover would trap them after the first tap.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HOVER_MEDIA_QUERY = "(hover: hover) and (pointer: fine)";
|
|
3
8
|
/**
|
|
4
9
|
* Subscribe to a CSS media query with `useSyncExternalStore`. The server
|
|
5
10
|
* render and hydration use `defaultMatches`, so the markup always agrees;
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
/** Tailwind `md` breakpoint. Used for range calendars that stack on small screens. */
|
|
4
4
|
export const MD_MEDIA_QUERY = "(min-width: 768px)";
|
|
5
|
+
/**
|
|
6
|
+
* A pointer that can hover (a mouse or trackpad). Touch and coarse pointers
|
|
7
|
+
* must use click; a hover-open popover would trap them after the first tap.
|
|
8
|
+
*/
|
|
9
|
+
export const HOVER_MEDIA_QUERY = "(hover: hover) and (pointer: fine)";
|
|
5
10
|
function hasMatchMedia() {
|
|
6
11
|
return (typeof window !== "undefined" && typeof window.matchMedia === "function");
|
|
7
12
|
}
|
package/dist/kanban.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type KanbanBoardProps<T extends {
|
|
|
59
59
|
deleteLabel?: string;
|
|
60
60
|
/** Classes for the horizontal scroller that holds the columns. */
|
|
61
61
|
scrollerClassName?: string;
|
|
62
|
-
/** Classes for every column, e.g.
|
|
62
|
+
/** Classes for every column, e.g. to pin a width instead of growing. */
|
|
63
63
|
columnClassName?: string;
|
|
64
64
|
/** Classes for every card, including the one under the pointer while dragging. */
|
|
65
65
|
cardClassName?: string;
|
package/dist/kanban.js
CHANGED
|
@@ -13,7 +13,8 @@ import { cn } from "./utils.js";
|
|
|
13
13
|
const COLUMN_DROP_PRIORITY = 1;
|
|
14
14
|
/** Rail zones beat columns when both are under the pointer. */
|
|
15
15
|
const ACTION_ZONE_PRIORITY = 10;
|
|
16
|
-
|
|
16
|
+
/** Grow to fill the board; 18rem floor so a long row still scrolls. */
|
|
17
|
+
const columnSize = "flex-1 basis-72 min-w-72 min-h-[min(70vh,32rem)]";
|
|
17
18
|
/**
|
|
18
19
|
* Drag-and-drop board built on dnd-kit. The consumer owns `items` and maps
|
|
19
20
|
* each to a column; the board derives its layout from them, so an optimistic
|
|
@@ -123,7 +124,7 @@ function KanbanColumnView({ column, count, emptyLabel, loading, className, child
|
|
|
123
124
|
collisionPriority: COLUMN_DROP_PRIORITY,
|
|
124
125
|
});
|
|
125
126
|
const empty = count === 0;
|
|
126
|
-
return (_jsxs("div", { ref: ref, "data-slot": "kanban-column", "data-drop-target": isDropTarget || undefined, className: cn("flex
|
|
127
|
+
return (_jsxs("div", { ref: ref, "data-slot": "kanban-column", "data-drop-target": isDropTarget || undefined, className: cn("flex snap-start flex-col gap-3 p-3", "bg-muted/40 ring-1 ring-foreground/5", "data-drop-target:bg-muted/60 data-drop-target:ring-2 data-drop-target:ring-ring/60", columnSize, className), children: [_jsxs("header", { "data-slot": "kanban-column-header", className: "flex items-start justify-between gap-2", children: [_jsxs("span", { className: "flex items-center gap-2 text-xs font-semibold tracking-widest uppercase", children: [column.color ? (_jsx("span", { "aria-hidden": true, className: "size-2 shrink-0 rounded-full", style: { backgroundColor: column.color } })) : null, _jsx("span", { className: "leading-tight", children: column.label })] }), _jsxs("span", { className: "flex shrink-0 flex-col items-end gap-0.5 text-muted-foreground tabular-nums", children: [_jsx("span", { className: "text-xs", children: count }), column.badge ? (_jsx("span", { className: "text-[10px] font-medium", children: column.badge })) : null] })] }), _jsx("div", { className: "flex min-h-32 flex-1 flex-col gap-2 overflow-y-auto pr-1", children: loading ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-20" }), _jsx(Skeleton, { className: "h-16" })] })) : (_jsxs(_Fragment, { children: [children, _jsx("p", { "data-slot": "kanban-column-empty", "aria-hidden": !empty, className: cn("border border-dashed px-3 py-6 text-center text-xs text-muted-foreground", !empty && "hidden"), children: emptyLabel })] })) })] }));
|
|
127
128
|
}
|
|
128
129
|
const cardChrome = cn("flex border border-border bg-card text-card-foreground");
|
|
129
130
|
const handleChrome = cn("flex shrink-0 items-center self-stretch border-r border-border", "bg-muted/30 px-1.5 text-muted-foreground");
|
|
@@ -192,6 +193,6 @@ function OverflowFade({ side, visible, }) {
|
|
|
192
193
|
}
|
|
193
194
|
/** Board-shaped placeholder for a route `loading` file. */
|
|
194
195
|
function KanbanSkeleton({ columnCount = 4, className, columnClassName, ...props }) {
|
|
195
|
-
return (_jsx("div", { "data-slot": "kanban-skeleton", className: cn("flex gap-4 overflow-hidden", className), ...props, children: Array.from({ length: columnCount }, (_, index) => (_jsx(Skeleton, { className: cn(
|
|
196
|
+
return (_jsx("div", { "data-slot": "kanban-skeleton", className: cn("flex gap-4 overflow-hidden", className), ...props, children: Array.from({ length: columnCount }, (_, index) => (_jsx(Skeleton, { className: cn(columnSize, columnClassName) }, index))) }));
|
|
196
197
|
}
|
|
197
198
|
export { KanbanBoard, KanbanSkeleton };
|
package/dist/search-picker.d.ts
CHANGED
package/dist/search-picker.js
CHANGED
|
@@ -3,9 +3,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Input } from "./input.js";
|
|
5
5
|
import { Label } from "./label.js";
|
|
6
|
-
import {
|
|
6
|
+
import { handleListboxKey, listboxOptionId, } from "./internal/listbox-navigation.js";
|
|
7
7
|
import { ListboxEmptyStatus, PickerOption } from "./internal/listbox-option.js";
|
|
8
|
-
import { createSearchIndex, filterSearchIndex,
|
|
8
|
+
import { createSearchIndex, filterSearchIndex, foldSearchText, normalizeSearchQuery, } from "./internal/search.js";
|
|
9
|
+
import { listboxScroll } from "./internal/styles.js";
|
|
9
10
|
import { cn } from "./utils.js";
|
|
10
11
|
export { foldSearchText };
|
|
11
12
|
/**
|
|
@@ -15,7 +16,7 @@ export function defaultSearchFilter(item, query, getLabel) {
|
|
|
15
16
|
const needle = normalizeSearchQuery(query);
|
|
16
17
|
if (!needle)
|
|
17
18
|
return true;
|
|
18
|
-
return
|
|
19
|
+
return foldSearchText(getLabel(item)).includes(needle);
|
|
19
20
|
}
|
|
20
21
|
/** Frame shared by the listbox and the empty state that replaces it. */
|
|
21
22
|
const listFrame = "border border-input bg-background";
|
|
@@ -84,8 +85,6 @@ function SearchPicker({ items, getValue, getLabel, filter = defaultSearchFilter,
|
|
|
84
85
|
}
|
|
85
86
|
event.currentTarget.blur();
|
|
86
87
|
};
|
|
87
|
-
return (_jsxs("div", { "data-slot": "search-picker", className: cn("flex flex-col gap-1.5", className), ...props, children: [_jsx(Label, { htmlFor: inputId, children: label }), _jsx(Input, { id: inputId, role: "combobox", "aria-expanded": true, "aria-controls": listId, "aria-autocomplete": "list", "aria-activedescendant": active ? listboxOptionId(listId, highlight) : undefined, value: query, disabled: disabled, placeholder: placeholder, onChange: (event) => setQuery(event.target.value), onKeyDown: onKeyDown }), _jsx("ul", { id: listId, role: "listbox", "aria-label": listLabel ?? label, className: empty
|
|
88
|
-
? "sr-only"
|
|
89
|
-
: cn("max-h-60 overflow-y-auto", listFrame, listClassName), children: rows.map(({ item, value: itemValue }, index) => (_jsx(PickerOption, { "data-slot": "search-picker-option", listId: listId, index: index, active: index === highlight, selected: itemValue === value, disabled: disabled, item: item, getLabel: getLabel, onHighlight: setHighlight, onSelect: selectItem }, itemValue))) }), _jsx(ListboxEmptyStatus, { "data-slot": "search-picker-empty", empty: empty, className: listFrame, children: emptyText })] }));
|
|
88
|
+
return (_jsxs("div", { "data-slot": "search-picker", className: cn("flex flex-col gap-1.5", className), ...props, children: [_jsx(Label, { htmlFor: inputId, children: label }), _jsx(Input, { id: inputId, role: "combobox", "aria-expanded": true, "aria-controls": listId, "aria-autocomplete": "list", "aria-activedescendant": active ? listboxOptionId(listId, highlight) : undefined, value: query, disabled: disabled, placeholder: placeholder, onChange: (event) => setQuery(event.target.value), onKeyDown: onKeyDown }), _jsx("ul", { id: listId, role: "listbox", "aria-label": listLabel ?? label, className: empty ? "sr-only" : cn(listboxScroll, listFrame, listClassName), children: rows.map(({ item, value: itemValue }, index) => (_jsx(PickerOption, { "data-slot": "search-picker-option", listId: listId, index: index, active: index === highlight, selected: itemValue === value, disabled: disabled, item: item, getLabel: getLabel, onHighlight: setHighlight, onSelect: selectItem }, itemValue))) }), _jsx(ListboxEmptyStatus, { "data-slot": "search-picker-empty", empty: empty, className: listFrame, children: emptyText })] }));
|
|
90
89
|
}
|
|
91
90
|
export { SearchPicker };
|
package/dist/select.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Select as SelectPrimitive } from "radix-ui";
|
|
5
|
-
import { dataDisabledState, disabledState, fieldSurface, focusRing, invalidState, optionState, } from "./internal/styles.js";
|
|
6
|
-
import { menuLabel,
|
|
5
|
+
import { dataDisabledState, disabledState, fieldSurface, focusRing, inlineIcon, invalidState, optionState, } from "./internal/styles.js";
|
|
6
|
+
import { menuLabel, optionRow, overlayFadeZoom, overlaySideSlide, overlaySurface, } from "./internal/overlay-styles.js";
|
|
7
7
|
import { cn } from "./utils.js";
|
|
8
8
|
import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
|
|
9
9
|
/**
|
|
@@ -11,7 +11,7 @@ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react";
|
|
|
11
11
|
* replaces them (a `data-[size=*]:` variant would outrank it).
|
|
12
12
|
*/
|
|
13
13
|
const triggerHeight = { default: "h-10", sm: "h-9" };
|
|
14
|
-
const scrollButtonClassName = "z-10 flex cursor-default items-center justify-center bg-popover py-1
|
|
14
|
+
const scrollButtonClassName = cn("z-10 flex cursor-default items-center justify-center bg-popover py-1", inlineIcon.default);
|
|
15
15
|
function Select({ ...props }) {
|
|
16
16
|
return _jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
17
17
|
}
|
|
@@ -22,7 +22,7 @@ function SelectValue({ ...props }) {
|
|
|
22
22
|
return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
23
23
|
}
|
|
24
24
|
function SelectTrigger({ className, size = "default", children, ...props }) {
|
|
25
|
-
return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: cn(fieldSurface, focusRing, invalidState, disabledState,
|
|
25
|
+
return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: cn(fieldSurface, focusRing, invalidState, disabledState, inlineIcon.default, triggerHeight[size], "flex items-center justify-between gap-1.5 whitespace-nowrap data-placeholder:text-muted-foreground *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { "data-slot": "select-icon", asChild: true, children: _jsx(ChevronDownIcon, { className: "pointer-events-none size-3.5 text-muted-foreground" }) })] }));
|
|
26
26
|
}
|
|
27
27
|
function SelectContent({ className, children, position = "popper", align = "center", sideOffset = 4, collisionPadding = 8, ...props }) {
|
|
28
28
|
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { "data-slot": "select-content", "data-align-trigger": position === "item-aligned", className: cn(overlaySurface, overlaySideSlide, overlayFadeZoom, "relative z-50 max-h-(--radix-select-content-available-height) min-w-(--radix-select-trigger-width) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none", position === "popper" &&
|
|
@@ -32,7 +32,7 @@ function SelectLabel({ className, ...props }) {
|
|
|
32
32
|
return (_jsx(SelectPrimitive.Label, { "data-slot": "select-label", className: cn(menuLabel, className), ...props }));
|
|
33
33
|
}
|
|
34
34
|
function SelectItem({ className, children, ...props }) {
|
|
35
|
-
return (_jsxs(SelectPrimitive.Item, { "data-slot": "select-item", className: cn(optionRow, optionState.focus, optionState.checked, dataDisabledState,
|
|
35
|
+
return (_jsxs(SelectPrimitive.Item, { "data-slot": "select-item", className: cn(optionRow, optionState.focus, optionState.checked, dataDisabledState, inlineIcon.default, "pr-8 not-data-[variant=destructive]:focus:**:text-accent-foreground *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className), ...props, children: [_jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { "data-slot": "select-item-indicator", children: _jsx(CheckIcon, { className: "pointer-events-none" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] }));
|
|
36
36
|
}
|
|
37
37
|
function SelectSeparator({ className, ...props }) {
|
|
38
38
|
return (_jsx(SelectPrimitive.Separator, { "data-slot": "select-separator", className: cn("pointer-events-none -mx-1.5 my-1.5 h-px bg-border", className), ...props }));
|
package/dist/tabs.d.ts
CHANGED
|
@@ -5,14 +5,14 @@ import type { AsChildProps } from "./internal/as-child.js";
|
|
|
5
5
|
import { tabsListVariants, tabsTriggerVariants } from "./internal/tabs-styles.js";
|
|
6
6
|
/** Props `TabsList` and `TabsNav` share for the scroller around their row. */
|
|
7
7
|
type TabsScrollerClassNameProps = {
|
|
8
|
-
/** Classes for the scroller around the tab row (`h-
|
|
8
|
+
/** Classes for the scroller around the tab row (`h-9` with `p-1` by default). */
|
|
9
9
|
scrollerClassName?: string;
|
|
10
10
|
};
|
|
11
11
|
declare function Tabs({ className, orientation, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>): React.JSX.Element;
|
|
12
12
|
/**
|
|
13
|
-
* The tab row inside its scroller. `className` styles the list (its `h-
|
|
13
|
+
* The tab row inside its scroller. `className` styles the list (its `h-7`
|
|
14
14
|
* height, fill, gap); `scrollerClassName` styles the scroller around it
|
|
15
|
-
* (`h-
|
|
15
|
+
* (`h-9` with `p-1` for the active border and focus ring).
|
|
16
16
|
*/
|
|
17
17
|
declare function TabsList({ className, scrollerClassName, variant, ...props }: React.ComponentProps<typeof TabsPrimitive.List> & Omit<VariantProps<typeof tabsListVariants>, "orientation"> & TabsScrollerClassNameProps): React.JSX.Element;
|
|
18
18
|
declare function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>): React.JSX.Element;
|
package/dist/tabs.js
CHANGED
|
@@ -9,7 +9,7 @@ import { useDragScroll } from "./internal/use-drag-scroll.js";
|
|
|
9
9
|
import { useHorizontalOverflow } from "./internal/use-horizontal-overflow.js";
|
|
10
10
|
import { cn } from "./utils.js";
|
|
11
11
|
/**
|
|
12
|
-
* The root's orientation, so the list can pick plain size classes (`h-
|
|
12
|
+
* The root's orientation, so the list can pick plain size classes (`h-7`)
|
|
13
13
|
* that a consumer `className` replaces, instead of `group-data-*` variants
|
|
14
14
|
* that would beat it.
|
|
15
15
|
*/
|
|
@@ -21,7 +21,7 @@ function Tabs({ className, orientation = "horizontal", ...props }) {
|
|
|
21
21
|
* Horizontal scroller around a tab row. `overflow-x: auto` alone would
|
|
22
22
|
* compute `overflow-y` to `auto` as well (CSS overflow pairing), so the
|
|
23
23
|
* active tab's border and focus ring grow a vertical scrollbar. Pad for
|
|
24
|
-
* those strokes *inside* the box (`h-
|
|
24
|
+
* those strokes *inside* the box (`h-9` = `h-7` list + `p-1`), clip the
|
|
25
25
|
* y axis as a backstop, and fade the edges while the row overflows —
|
|
26
26
|
* same cue as `Table`. While it overflows, a mouse can also drag the row
|
|
27
27
|
* sideways (`useDragScroll`); touch, wheel and keyboard scroll as before.
|
|
@@ -50,9 +50,9 @@ function TabsScroller({ variant = "default", orientation = "horizontal", classNa
|
|
|
50
50
|
return (_jsx("div", { ref: ref, "data-slot": "tabs-scroller", "data-variant": variant, tabIndex: overflowing ? 0 : undefined, className: cn(focusRing, tabsScrollerVariants({ variant, orientation }), className), children: children }));
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* The tab row inside its scroller. `className` styles the list (its `h-
|
|
53
|
+
* The tab row inside its scroller. `className` styles the list (its `h-7`
|
|
54
54
|
* height, fill, gap); `scrollerClassName` styles the scroller around it
|
|
55
|
-
* (`h-
|
|
55
|
+
* (`h-9` with `p-1` for the active border and focus ring).
|
|
56
56
|
*/
|
|
57
57
|
function TabsList({ className, scrollerClassName, variant = "default", ...props }) {
|
|
58
58
|
const orientation = React.useContext(TabsOrientationContext);
|
package/dist/toggle.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { Toggle as TogglePrimitive } from "radix-ui";
|
|
|
5
5
|
* Selected chrome shared by Toggle and ToggleGroupItem (see
|
|
6
6
|
* `selectedState.toggle`): the wash, selected text, and a selected border
|
|
7
7
|
* for `data-state=on`, `aria-pressed`, and `aria-checked`.
|
|
8
|
+
*
|
|
9
|
+
* @deprecated `toggleVariants()` already includes this chrome. Removed in 2.0.
|
|
8
10
|
*/
|
|
9
11
|
declare const selectedToggleChrome: string;
|
|
10
12
|
declare const toggleVariants: (props?: ({
|
package/dist/toggle.js
CHANGED
|
@@ -3,21 +3,26 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import { Toggle as TogglePrimitive } from "radix-ui";
|
|
6
|
-
import { controlSize, disabledState, focusRing, invalidState, selectedState, } from "./internal/styles.js";
|
|
6
|
+
import { controlSize, controlText, disabledState, focusRing, inlineIcon, invalidState, selectedState, } from "./internal/styles.js";
|
|
7
7
|
import { cn } from "./utils.js";
|
|
8
8
|
/**
|
|
9
9
|
* Selected chrome shared by Toggle and ToggleGroupItem (see
|
|
10
10
|
* `selectedState.toggle`): the wash, selected text, and a selected border
|
|
11
11
|
* for `data-state=on`, `aria-pressed`, and `aria-checked`.
|
|
12
|
+
*
|
|
13
|
+
* @deprecated `toggleVariants()` already includes this chrome. Removed in 2.0.
|
|
12
14
|
*/
|
|
13
15
|
const selectedToggleChrome = selectedState.toggle;
|
|
14
16
|
const toggleVariants = cva([
|
|
15
17
|
focusRing,
|
|
16
18
|
selectedState.hover,
|
|
17
|
-
|
|
19
|
+
selectedState.toggle,
|
|
18
20
|
invalidState,
|
|
19
21
|
disabledState,
|
|
20
|
-
"group/toggle inline-flex items-center justify-center gap-1.5 rounded-none
|
|
22
|
+
"group/toggle inline-flex items-center justify-center gap-1.5 rounded-none",
|
|
23
|
+
controlText,
|
|
24
|
+
"transition-colors focus-visible:text-selected-foreground",
|
|
25
|
+
inlineIcon.default,
|
|
21
26
|
], {
|
|
22
27
|
variants: {
|
|
23
28
|
variant: {
|