atlas-react-kit 0.7.0 → 0.8.1
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 +54 -54
- package/DESIGN_RULES.md +7 -3
- package/README.md +2 -2
- package/dist/internal/tabs-styles.js +5 -2
- package/dist/internal/use-horizontal-overflow.d.ts +7 -0
- package/dist/internal/use-horizontal-overflow.js +23 -0
- package/dist/table.js +1 -20
- package/dist/tabs.d.ts +5 -0
- package/dist/tabs.js +35 -3
- package/dist/toast.d.ts +57 -0
- package/dist/{sonner.js → toast.js} +34 -19
- package/package.json +5 -5
- package/skills/atlas-react-kit/SKILL.md +5 -3
- package/theme.css +49 -0
- package/dist/sonner.d.ts +0 -8
package/COMPONENTS.md
CHANGED
|
@@ -5,60 +5,60 @@ underlying element or Radix props, including `className`, alongside their option
|
|
|
5
5
|
Form helpers and `TableBodySkeleton` accept only their documented props. There is
|
|
6
6
|
no root component barrel.
|
|
7
7
|
|
|
8
|
-
| Subpath | Main exports and options
|
|
9
|
-
| ----------------------------- |
|
|
10
|
-
| `accordion` | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`; Radix `type` `single` (with `collapsible`) or `multiple`
|
|
11
|
-
| `alert` | `Alert`, `AlertTitle`, `AlertDescription`, `alertVariants`; `variant` `default`, `success`, `warning`, `destructive`; tone on title and icon, body stays muted; destructive is `role="alert"`
|
|
12
|
-
| `avatar` | `Avatar`, `AvatarImage`, `AvatarFallback`; `size` `sm`, `default`, `lg`; round by design
|
|
13
|
-
| `breadcrumb` | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink` (`asChild` for router links), `BreadcrumbPage` (`aria-current`), `BreadcrumbSeparator`, `BreadcrumbEllipsis`
|
|
14
|
-
| `button` | `Button`, `buttonVariants`, `quietButtonInteraction`; `variant`, `size`, `asChild`; outline/ghost hover is brand purple + selected wash, not muted grey
|
|
15
|
-
| `badge` | `Badge`, `badgeVariants`; `variant`, `tone`, `asChild`
|
|
16
|
-
| `calendar` | `Calendar`, `CalendarDayButton`; React Day Picker props and `buttonVariant`
|
|
17
|
-
| `card` | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter`; `Card` supports `flush`; root uses `min-h-min shrink-0` so flex columns do not collapse it, and `min-w-0` so nested tables scroll; `CardContent className="px-0"` overrides padding without `!`
|
|
18
|
-
| `checkbox` | `Checkbox`
|
|
19
|
-
| `color-legend` | `ColorLegend`; `title`, `items` as `{ color, range?, label }[]`, optional `caption`, `children`, `aria-label`, `className` (overlay chrome). No attribution.
|
|
20
|
-
| `combobox` | `Combobox`; `options` as `{ value, label }[]`, `value`, `onValueChange`; optional placeholder, search, empty text; trigger matches Input/SelectTrigger chrome; keyboard highlight scrolls into view
|
|
21
|
-
| `date-picker` | `DatePickerButton`, `toDate`, `formatLocalDate`, `DateRange`; `mode` `"single"` (default) or `"range"`; single `value` is `Date` or `yyyy-MM-dd`; range `value` is `{ from, to }`; trigger matches Input chrome; optional `numberOfMonths` (range default 1 below `md`, 2 at `md+`) and `side`
|
|
22
|
-
| `date-time-picker` | `DateTimePickerButton`, `resolveTimeStep`, `DEFAULT_TIME_STEP`; controlled `value` is `Date` or `null`; `onChange` emits `Date \
|
|
23
|
-
| `dialog` | `Dialog`, trigger, portal, overlay, content, close, header, footer, title, description; `DialogContent` supports `showCloseButton`
|
|
24
|
-
| `dropdown-menu` | `DropdownMenu` family (trigger, content, item, checkbox/radio items, label, separator, shortcut, sub menus); item `variant="destructive"` and `inset`; for commands, not values
|
|
25
|
-
| `empty-panel` | `EmptyPanel`; required `children`; optional `size`, `muted`, `className`
|
|
26
|
-
| `error-boundary` | `ErrorBoundary`, `ErrorFallback`; optional `message`; retry resets, reload refreshes the page
|
|
27
|
-
| `field` | Field, label, legend, description, group, set, title, content, separator, error; `Field` supports `orientation`
|
|
28
|
-
| `info-tip` | `InfoTip`, `InlineTip`; required `label` (aria-label); `title`, `description`, `children`, `layout` `box` \| `inline`, `side`, `align`, `badge`, `icon`, `className`. Popover, 20px glyph, 44px hit. Hover opens only on a fine pointer. Not a Tooltip.
|
|
29
|
-
| `input`, `textarea`, `label` | `Input`, `Textarea`, `Label`
|
|
30
|
-
| `markdown` | `Markdown`, `MarkdownContent`; `content`, optional `className`. GFM via `react-markdown` + `remark-gfm` in this subpath only. Sanitized (no raw HTML; http/https/mailto/#/`/` URLs). Token styles, no typography plugin.
|
|
31
|
-
| `meter` | `Meter`; `value`, `max`, optional `min` (default 0), `fillClassName`, `markers` as `{ position, className? }[]`, required `aria-label`, `className`. `role="meter"`. Not `Progress`.
|
|
32
|
-
| `pagination` | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink` (`isActive` sets `aria-current`, the selected wash, and a selected border), `PaginationPrevious`, `PaginationNext`, `PaginationEllipsis`
|
|
33
|
-
| `popover` | `Popover`, trigger, anchor, content, header, title, description
|
|
34
|
-
| `progress` | `Progress`; Radix props, `value` 0–100; label it with `aria-label` or `aria-labelledby`. For a value against a scale with ticks, use `Meter`.
|
|
35
|
-
| `radio-group` | `RadioGroup`, `RadioGroupItem`; short visible lists; arrow keys move the selection; round dots
|
|
36
|
-
| `search-picker` | `SearchPicker<T>`; always-visible combobox + listbox; `items`, `getValue`, `getLabel`, optional `filter` (default casefold + accent-fold includes), `value`, `onSelect`, `label`, `placeholder`, `emptyText`, `listLabel`, `disabled`, `className`. Arrows, Home/End, PageUp/PageDown, Enter, Escape.
|
|
37
|
-
| `select` | Select, trigger, value, content, group, label, item, separator, scroll buttons; trigger `size`; trigger text is `text-base md:text-sm` like Input
|
|
38
|
-
| `separator`, `skeleton` | `Separator`, `Skeleton`
|
|
39
|
-
| `slider` | `Slider`; `value` number, `onValueChange`, optional `onValueCommit`, `min`, `max`, `step`, `disabled`, `id`, `aria-labelledby`, `className`. Radix Slider; 44px thumb hit; square track; primary fill. Name it with `aria-labelledby`.
|
|
40
|
-
| `sortable-table-head` | `SortableTableHead`; `sorted`, `direction` (`asc` \
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
45
|
-
| `table`
|
|
46
|
-
| `
|
|
47
|
-
| `
|
|
48
|
-
| `toggle` | `Toggle`, `toggleVariants`, `selectedToggleChrome`; `variant`, `size`. Pressed state is the selected wash, text, and border via `data-state=on`, `aria-pressed`, and `aria-checked`
|
|
49
|
-
| `toggle-group` | `ToggleGroup`, `ToggleGroupItem`; `variant`, `size`. Items share `toggleVariants`, so single (radio) and multiple selections match a pressed `Toggle`
|
|
50
|
-
| `theme-provider` | `ThemeProvider`, `useTheme`; optional `storageKey` (default `atlas-theme`), `enableShortcut` for the `d` toggle
|
|
51
|
-
| `tooltip` | `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider`; opens on hover and focus; short labels only
|
|
52
|
-
| `form/markdown-field` | `FormMarkdownField`; `field` is `TextFieldApi`; `label`, optional `id`, `placeholder`, `rows`, `showError`. Write / preview; preview uses `Markdown`.
|
|
53
|
-
| `form/text-field` | `FormTextField`, type `TextFieldApi`; controlled field, label, multiline, description, input constraints
|
|
54
|
-
| `form/select-field` | `FormSelectField`; `value`, `onValueChange`, `label`, optional `meta` and placeholder; select item children
|
|
55
|
-
| `form/date-picker-field` | `FormDatePickerField`; `value`, `onValueChange`, `label`, optional `meta`, placeholder, and `className` (forwarded to the trigger)
|
|
56
|
-
| `form/date-time-picker-field` | `FormDateTimePickerField`; `value` is `Date` or `null`; `onValueChange` emits `Date \
|
|
57
|
-
| `form/field-error` | `FieldError`, `getFieldErrorMessage`; types `FieldErrorMessage`, `FieldMetaState`
|
|
58
|
-
| `form/feedback-field` | `FormFeedbackField`; nullable `message`
|
|
59
|
-
| `next/tabs-nav-link` | `TabsNavLink`; Next Link props and required `active` boolean; requires Next.js 16
|
|
60
|
-
| `utils` | `cn`, `onInputChange`
|
|
61
|
-
| `theme.css` | Tailwind 4 theme; installation in [README](./README.md)
|
|
8
|
+
| Subpath | Main exports and options |
|
|
9
|
+
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
10
|
+
| `accordion` | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent`; Radix `type` `single` (with `collapsible`) or `multiple` |
|
|
11
|
+
| `alert` | `Alert`, `AlertTitle`, `AlertDescription`, `alertVariants`; `variant` `default`, `success`, `warning`, `destructive`; tone on title and icon, body stays muted; destructive is `role="alert"` |
|
|
12
|
+
| `avatar` | `Avatar`, `AvatarImage`, `AvatarFallback`; `size` `sm`, `default`, `lg`; round by design |
|
|
13
|
+
| `breadcrumb` | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink` (`asChild` for router links), `BreadcrumbPage` (`aria-current`), `BreadcrumbSeparator`, `BreadcrumbEllipsis` |
|
|
14
|
+
| `button` | `Button`, `buttonVariants`, `quietButtonInteraction`; `variant`, `size`, `asChild`; outline/ghost hover is brand purple + selected wash, not muted grey |
|
|
15
|
+
| `badge` | `Badge`, `badgeVariants`; `variant`, `tone`, `asChild` |
|
|
16
|
+
| `calendar` | `Calendar`, `CalendarDayButton`; React Day Picker props and `buttonVariant` |
|
|
17
|
+
| `card` | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter`; `Card` supports `flush`; root uses `min-h-min shrink-0` so flex columns do not collapse it, and `min-w-0` so nested tables scroll; `CardContent className="px-0"` overrides padding without `!` |
|
|
18
|
+
| `checkbox` | `Checkbox` |
|
|
19
|
+
| `color-legend` | `ColorLegend`; `title`, `items` as `{ color, range?, label }[]`, optional `caption`, `children`, `aria-label`, `className` (overlay chrome). No attribution. |
|
|
20
|
+
| `combobox` | `Combobox`; `options` as `{ value, label }[]`, `value`, `onValueChange`; optional placeholder, search, empty text; trigger matches Input/SelectTrigger chrome; keyboard highlight scrolls into view |
|
|
21
|
+
| `date-picker` | `DatePickerButton`, `toDate`, `formatLocalDate`, `DateRange`; `mode` `"single"` (default) or `"range"`; single `value` is `Date` or `yyyy-MM-dd`; range `value` is `{ from, to }`; trigger matches Input chrome; optional `numberOfMonths` (range default 1 below `md`, 2 at `md+`) and `side` |
|
|
22
|
+
| `date-time-picker` | `DateTimePickerButton`, `resolveTimeStep`, `DEFAULT_TIME_STEP`; controlled `value` is `Date` or `null`; `onChange` emits `Date \ |
|
|
23
|
+
| `dialog` | `Dialog`, trigger, portal, overlay, content, close, header, footer, title, description; `DialogContent` supports `showCloseButton` |
|
|
24
|
+
| `dropdown-menu` | `DropdownMenu` family (trigger, content, item, checkbox/radio items, label, separator, shortcut, sub menus); item `variant="destructive"` and `inset`; for commands, not values |
|
|
25
|
+
| `empty-panel` | `EmptyPanel`; required `children`; optional `size`, `muted`, `className` |
|
|
26
|
+
| `error-boundary` | `ErrorBoundary`, `ErrorFallback`; optional `message`; retry resets, reload refreshes the page |
|
|
27
|
+
| `field` | Field, label, legend, description, group, set, title, content, separator, error; `Field` supports `orientation` |
|
|
28
|
+
| `info-tip` | `InfoTip`, `InlineTip`; required `label` (aria-label); `title`, `description`, `children`, `layout` `box` \| `inline`, `side`, `align`, `badge`, `icon`, `className`. Popover, 20px glyph, 44px hit. Hover opens only on a fine pointer. Not a Tooltip. |
|
|
29
|
+
| `input`, `textarea`, `label` | `Input`, `Textarea`, `Label` |
|
|
30
|
+
| `markdown` | `Markdown`, `MarkdownContent`; `content`, optional `className`. GFM via `react-markdown` + `remark-gfm` in this subpath only. Sanitized (no raw HTML; http/https/mailto/#/`/` URLs). Token styles, no typography plugin. |
|
|
31
|
+
| `meter` | `Meter`; `value`, `max`, optional `min` (default 0), `fillClassName`, `markers` as `{ position, className? }[]`, required `aria-label`, `className`. `role="meter"`. Not `Progress`. |
|
|
32
|
+
| `pagination` | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink` (`isActive` sets `aria-current`, the selected wash, and a selected border), `PaginationPrevious`, `PaginationNext`, `PaginationEllipsis` |
|
|
33
|
+
| `popover` | `Popover`, trigger, anchor, content, header, title, description |
|
|
34
|
+
| `progress` | `Progress`; Radix props, `value` 0–100; label it with `aria-label` or `aria-labelledby`. For a value against a scale with ticks, use `Meter`. |
|
|
35
|
+
| `radio-group` | `RadioGroup`, `RadioGroupItem`; short visible lists; arrow keys move the selection; round dots |
|
|
36
|
+
| `search-picker` | `SearchPicker<T>`; always-visible combobox + listbox; `items`, `getValue`, `getLabel`, optional `filter` (default casefold + accent-fold includes), `value`, `onSelect`, `label`, `placeholder`, `emptyText`, `listLabel`, `disabled`, `className`. Arrows, Home/End, PageUp/PageDown, Enter, Escape. |
|
|
37
|
+
| `select` | Select, trigger, value, content, group, label, item, separator, scroll buttons; trigger `size`; trigger text is `text-base md:text-sm` like Input |
|
|
38
|
+
| `separator`, `skeleton` | `Separator`, `Skeleton` |
|
|
39
|
+
| `slider` | `Slider`; `value` number, `onValueChange`, optional `onValueCommit`, `min`, `max`, `step`, `disabled`, `id`, `aria-labelledby`, `className`. Radix Slider; 44px thumb hit; square track; primary fill. Name it with `aria-labelledby`. |
|
|
40
|
+
| `sortable-table-head` | `SortableTableHead`; `sorted`, `direction` (`asc` \ |
|
|
41
|
+
| `spinner` | `Spinner`; `role="status"` with `aria-label` (default `Loading`) |
|
|
42
|
+
| `stat-tile` | `StatTile`, `statTileGrid`, `sectionLabel`; `label`, `value`, optional `sub`, `children`, `className`. |
|
|
43
|
+
| `switch` | `Switch`; settings that apply immediately; square track and thumb |
|
|
44
|
+
| `table` | Table, header, body, footer, row, head, cell, caption; root scroller is `min-w-0 overflow-x-auto` with a fade cue; cells are `px-2` below `sm` |
|
|
45
|
+
| `table-body-skeleton` | `TableBodySkeleton`; `columns`, optional `rows` (default 5) |
|
|
46
|
+
| `tabs` | `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `TabsNav`, `tabsListVariants`, `tabsTriggerVariants`; list `variant` is `default` or `line`; style `TabsNav` links with `tabsTriggerVariants()`; `TabsNav` / `TabsList` scroll horizontally only (`overflow-y` hidden, edge fade, active item into view) — do not wrap them in `overflow-x-auto` |
|
|
47
|
+
| `toast` | `Toaster`, `toast`; mount one `Toaster` (`position`, `closeButton` (default on), `expand`, `visibleToasts`, `duration`), then `toast(message, options)`, `.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 |
|
|
48
|
+
| `toggle` | `Toggle`, `toggleVariants`, `selectedToggleChrome`; `variant`, `size`. Pressed state is the selected wash, text, and border via `data-state=on`, `aria-pressed`, and `aria-checked` |
|
|
49
|
+
| `toggle-group` | `ToggleGroup`, `ToggleGroupItem`; `variant`, `size`. Items share `toggleVariants`, so single (radio) and multiple selections match a pressed `Toggle` |
|
|
50
|
+
| `theme-provider` | `ThemeProvider`, `useTheme`; optional `storageKey` (default `atlas-theme`), `enableShortcut` for the `d` toggle |
|
|
51
|
+
| `tooltip` | `Tooltip`, `TooltipTrigger`, `TooltipContent`, `TooltipProvider`; opens on hover and focus; short labels only |
|
|
52
|
+
| `form/markdown-field` | `FormMarkdownField`; `field` is `TextFieldApi`; `label`, optional `id`, `placeholder`, `rows`, `showError`. Write / preview; preview uses `Markdown`. |
|
|
53
|
+
| `form/text-field` | `FormTextField`, type `TextFieldApi`; controlled field, label, multiline, description, input constraints |
|
|
54
|
+
| `form/select-field` | `FormSelectField`; `value`, `onValueChange`, `label`, optional `meta` and placeholder; select item children |
|
|
55
|
+
| `form/date-picker-field` | `FormDatePickerField`; `value`, `onValueChange`, `label`, optional `meta`, placeholder, and `className` (forwarded to the trigger) |
|
|
56
|
+
| `form/date-time-picker-field` | `FormDateTimePickerField`; `value` is `Date` or `null`; `onValueChange` emits `Date \ |
|
|
57
|
+
| `form/field-error` | `FieldError`, `getFieldErrorMessage`; types `FieldErrorMessage`, `FieldMetaState` |
|
|
58
|
+
| `form/feedback-field` | `FormFeedbackField`; nullable `message` |
|
|
59
|
+
| `next/tabs-nav-link` | `TabsNavLink`; Next Link props and required `active` boolean; requires Next.js 16 |
|
|
60
|
+
| `utils` | `cn`, `onInputChange` |
|
|
61
|
+
| `theme.css` | Tailwind 4 theme; installation in [README](./README.md) |
|
|
62
62
|
|
|
63
63
|
## Status
|
|
64
64
|
|
package/DESIGN_RULES.md
CHANGED
|
@@ -54,8 +54,8 @@ keyboard and screen-reader testing.
|
|
|
54
54
|
- Focus is a solid `ring-ring` (brand purple), never a translucent ring such
|
|
55
55
|
as `ring-ring/30`, which fades below 3:1. Keyboard-highlighted menu and list
|
|
56
56
|
items show a 2px `ring` bar on their leading edge. Content that scrolls must
|
|
57
|
-
be reachable by keyboard; `Table`
|
|
58
|
-
|
|
57
|
+
be reachable by keyboard; `Table`, `TabsList`, and `TabsNav` add their
|
|
58
|
+
scroller to the tab order while they overflow.
|
|
59
59
|
|
|
60
60
|
## Writing
|
|
61
61
|
|
|
@@ -103,7 +103,11 @@ triggers as outline buttons in application code.
|
|
|
103
103
|
|
|
104
104
|
Use `Tabs` with actual `TabsContent` panels. For URL view switches, use a labelled
|
|
105
105
|
`TabsNav` with links and `aria-current="page"` on the active link. The optional
|
|
106
|
-
Next adapter provides `TabsNavLink` with this behavior.
|
|
106
|
+
Next adapter provides `TabsNavLink` with this behavior. `TabsNav` and `TabsList`
|
|
107
|
+
scroll overflowing labels inside themselves (`overflow-x-auto overflow-y-hidden`,
|
|
108
|
+
with padding for the active border and focus ring, and an edge fade like
|
|
109
|
+
`Table`). Do not wrap them in another `overflow-x-auto` — that pairing forces
|
|
110
|
+
`overflow-y: auto` and a stray vertical scrollbar.
|
|
107
111
|
|
|
108
112
|
Use `FormTextField`, `FormSelectField`, `FormDatePickerField`,
|
|
109
113
|
`FormDateTimePickerField`, `FormMarkdownField`, and `FormFeedbackField` for
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ keeping locally (`InfoTip`, `ColorLegend`, `SearchPicker`, `Markdown`,
|
|
|
7
7
|
React 19 and Tailwind 4 are required.
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
npm install --save-exact atlas-react-kit@0.
|
|
10
|
+
npm install --save-exact atlas-react-kit@0.8.1
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Import components by subpath:
|
|
@@ -116,7 +116,7 @@ artifact with the package owner's npm login:
|
|
|
116
116
|
```sh
|
|
117
117
|
mkdir -p release-artifacts
|
|
118
118
|
npm pack --pack-destination release-artifacts
|
|
119
|
-
npm publish ./release-artifacts/atlas-react-kit-0.
|
|
119
|
+
npm publish ./release-artifacts/atlas-react-kit-0.8.1.tgz --access public
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
See [CONTRIBUTING.md](./CONTRIBUTING.md) for adding components, the browser
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cva } from "class-variance-authority";
|
|
2
2
|
import { disabledState, focusRing, selectedState } from "./styles.js";
|
|
3
|
-
const tabsListVariants = cva('group/tabs-list inline-flex w-
|
|
3
|
+
const tabsListVariants = cva('group/tabs-list inline-flex w-max min-w-full items-stretch justify-start p-0 text-muted-foreground group-data-[orientation="horizontal"]/tabs:h-11 group-data-[orientation="vertical"]/tabs:h-fit group-data-[orientation="vertical"]/tabs:flex-col', {
|
|
4
4
|
variants: {
|
|
5
5
|
variant: {
|
|
6
6
|
default: "bg-muted",
|
|
@@ -14,7 +14,10 @@ const tabsListVariants = cva('group/tabs-list inline-flex w-fit items-stretch ju
|
|
|
14
14
|
const tabsTriggerVariants = cva([
|
|
15
15
|
focusRing,
|
|
16
16
|
disabledState,
|
|
17
|
-
|
|
17
|
+
// flex-none + px-4: every trigger and TabsNav link keeps the same
|
|
18
|
+
// horizontal padding. flex-1 used to grow short labels and make the
|
|
19
|
+
// longest (e.g. Apple Reminders) look tighter. No last-child padding.
|
|
20
|
+
'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 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-3.5',
|
|
18
21
|
'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',
|
|
19
22
|
selectedState.active,
|
|
20
23
|
'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',
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* True while the element's content is wider than its box. Re-checked when
|
|
4
|
+
* the container or its content resizes. Used so a horizontal scroller can
|
|
5
|
+
* join the tab order only while it overflows (WCAG 2.1.1).
|
|
6
|
+
*/
|
|
7
|
+
export declare function useHorizontalOverflow(ref: React.RefObject<HTMLElement | null>): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* True while the element's content is wider than its box. Re-checked when
|
|
5
|
+
* the container or its content resizes. Used so a horizontal scroller can
|
|
6
|
+
* join the tab order only while it overflows (WCAG 2.1.1).
|
|
7
|
+
*/
|
|
8
|
+
export function useHorizontalOverflow(ref) {
|
|
9
|
+
const [overflowing, setOverflowing] = React.useState(false);
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
const element = ref.current;
|
|
12
|
+
if (!element || typeof ResizeObserver === "undefined")
|
|
13
|
+
return;
|
|
14
|
+
const check = () => setOverflowing(element.scrollWidth > element.clientWidth + 1);
|
|
15
|
+
check();
|
|
16
|
+
const observer = new ResizeObserver(check);
|
|
17
|
+
observer.observe(element);
|
|
18
|
+
if (element.firstElementChild)
|
|
19
|
+
observer.observe(element.firstElementChild);
|
|
20
|
+
return () => observer.disconnect();
|
|
21
|
+
}, [ref]);
|
|
22
|
+
return overflowing;
|
|
23
|
+
}
|
package/dist/table.js
CHANGED
|
@@ -2,27 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { focusRing } from "./internal/styles.js";
|
|
5
|
+
import { useHorizontalOverflow } from "./internal/use-horizontal-overflow.js";
|
|
5
6
|
import { cn } from "./utils.js";
|
|
6
|
-
/**
|
|
7
|
-
* True while the element's content is wider than its box. Re-checked when
|
|
8
|
-
* the container or its content resizes.
|
|
9
|
-
*/
|
|
10
|
-
function useHorizontalOverflow(ref) {
|
|
11
|
-
const [overflowing, setOverflowing] = React.useState(false);
|
|
12
|
-
React.useEffect(() => {
|
|
13
|
-
const element = ref.current;
|
|
14
|
-
if (!element || typeof ResizeObserver === "undefined")
|
|
15
|
-
return;
|
|
16
|
-
const check = () => setOverflowing(element.scrollWidth > element.clientWidth + 1);
|
|
17
|
-
check();
|
|
18
|
-
const observer = new ResizeObserver(check);
|
|
19
|
-
observer.observe(element);
|
|
20
|
-
if (element.firstElementChild)
|
|
21
|
-
observer.observe(element.firstElementChild);
|
|
22
|
-
return () => observer.disconnect();
|
|
23
|
-
}, [ref]);
|
|
24
|
-
return overflowing;
|
|
25
|
-
}
|
|
26
7
|
/**
|
|
27
8
|
* Data table. The root is a `min-w-0 overflow-x-auto` scroller so nowrap
|
|
28
9
|
* columns scroll inside the table instead of widening a card or panel.
|
package/dist/tabs.d.ts
CHANGED
|
@@ -13,6 +13,11 @@ declare function TabsContent({ className, ...props }: React.ComponentProps<typeo
|
|
|
13
13
|
* with `tabsTriggerVariants()` and mark the active one with
|
|
14
14
|
* `data-state="active"` and `aria-current="page"` (the Next adapter
|
|
15
15
|
* `TabsNavLink` does this for you).
|
|
16
|
+
*
|
|
17
|
+
* Overflow is handled here: the row scrolls horizontally only, with padding
|
|
18
|
+
* for active borders and focus rings, an edge fade while it overflows, and
|
|
19
|
+
* the active link scrolled into view on mount. Do not wrap it in
|
|
20
|
+
* `overflow-x-auto`.
|
|
16
21
|
*/
|
|
17
22
|
declare function TabsNav({ className, children, ...props }: React.ComponentProps<"nav"> & {
|
|
18
23
|
"aria-label": string;
|
package/dist/tabs.js
CHANGED
|
@@ -3,13 +3,40 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import {} from "class-variance-authority";
|
|
5
5
|
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
6
|
-
import {
|
|
6
|
+
import { focusRing } from "./internal/styles.js";
|
|
7
7
|
import { tabsListVariants, tabsTriggerVariants, } from "./internal/tabs-styles.js";
|
|
8
|
+
import { useHorizontalOverflow } from "./internal/use-horizontal-overflow.js";
|
|
9
|
+
import { cn } from "./utils.js";
|
|
8
10
|
function Tabs({ className, orientation = "horizontal", ...props }) {
|
|
9
11
|
return (_jsx(TabsPrimitive.Root, { "data-slot": "tabs", "data-orientation": orientation, orientation: orientation, className: cn('group/tabs flex gap-2 data-[orientation="horizontal"]:flex-col', className), ...props }));
|
|
10
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Horizontal scroller around a tab row. `overflow-x: auto` alone would
|
|
15
|
+
* compute `overflow-y` to `auto` as well (CSS overflow pairing), so the
|
|
16
|
+
* active tab's border and focus ring grow a vertical scrollbar. Clip the
|
|
17
|
+
* y axis, pad for those strokes, and fade the edges while the row
|
|
18
|
+
* overflows — same cue as `Table`.
|
|
19
|
+
*/
|
|
20
|
+
function TabsScroller({ variant = "default", children, }) {
|
|
21
|
+
const ref = React.useRef(null);
|
|
22
|
+
const overflowing = useHorizontalOverflow(ref);
|
|
23
|
+
React.useLayoutEffect(() => {
|
|
24
|
+
const scroller = ref.current;
|
|
25
|
+
if (!scroller)
|
|
26
|
+
return;
|
|
27
|
+
const active = scroller.querySelector('[aria-current="page"], [data-state="active"]');
|
|
28
|
+
active?.scrollIntoView({
|
|
29
|
+
block: "nearest",
|
|
30
|
+
inline: "nearest",
|
|
31
|
+
behavior: "auto",
|
|
32
|
+
});
|
|
33
|
+
}, []);
|
|
34
|
+
return (_jsx("div", { ref: ref, "data-slot": "tabs-scroller", "data-variant": variant, tabIndex: overflowing ? 0 : undefined, className: cn(focusRing, "relative w-full min-w-0 max-w-full overflow-x-auto overflow-y-hidden overscroll-x-contain p-1 [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden", variant === "line" && "pb-2"), children: children }));
|
|
35
|
+
}
|
|
11
36
|
function TabsList({ className, variant = "default", ...props }) {
|
|
12
|
-
return (_jsx(TabsPrimitive.List, { "data-slot": "tabs-list", "data-variant": variant, className: cn(tabsListVariants({ variant }),
|
|
37
|
+
return (_jsx(TabsScroller, { variant: variant ?? "default", children: _jsx(TabsPrimitive.List, { "data-slot": "tabs-list", "data-variant": variant, className: cn(tabsListVariants({ variant }),
|
|
38
|
+
// The scroller owns the muted fill so edge fades show through.
|
|
39
|
+
variant === "default" && "bg-transparent", className), ...props }) }));
|
|
13
40
|
}
|
|
14
41
|
function TabsTrigger({ className, ...props }) {
|
|
15
42
|
return (_jsx(TabsPrimitive.Trigger, { "data-slot": "tabs-trigger", className: cn(tabsTriggerVariants(), className), ...props }));
|
|
@@ -24,8 +51,13 @@ function TabsContent({ className, ...props }) {
|
|
|
24
51
|
* with `tabsTriggerVariants()` and mark the active one with
|
|
25
52
|
* `data-state="active"` and `aria-current="page"` (the Next adapter
|
|
26
53
|
* `TabsNavLink` does this for you).
|
|
54
|
+
*
|
|
55
|
+
* Overflow is handled here: the row scrolls horizontally only, with padding
|
|
56
|
+
* for active borders and focus rings, an edge fade while it overflows, and
|
|
57
|
+
* the active link scrolled into view on mount. Do not wrap it in
|
|
58
|
+
* `overflow-x-auto`.
|
|
27
59
|
*/
|
|
28
60
|
function TabsNav({ className, children, ...props }) {
|
|
29
|
-
return (_jsx("nav", { "data-slot": "tabs-nav", "data-orientation": "horizontal", className: cn("group/tabs", className), ...props, children: _jsx("div", { "data-slot": "tabs-list", "data-variant": "default", className: tabsListVariants(), children: children }) }));
|
|
61
|
+
return (_jsx("nav", { "data-slot": "tabs-nav", "data-orientation": "horizontal", className: cn("group/tabs min-w-0 w-full max-w-full", className), ...props, children: _jsx(TabsScroller, { children: _jsx("div", { "data-slot": "tabs-list", "data-variant": "default", className: cn(tabsListVariants(), "bg-transparent"), children: children }) }) }));
|
|
30
62
|
}
|
|
31
63
|
export { Tabs, TabsList, TabsTrigger, TabsContent, TabsNav, tabsListVariants, tabsTriggerVariants, };
|
package/dist/toast.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/** Identifies a toast, to replace it in place or dismiss it. */
|
|
3
|
+
type ToastId = string | number;
|
|
4
|
+
/** A button in a toast. Clicking it runs `onClick`, then closes the toast. */
|
|
5
|
+
interface ToastAction {
|
|
6
|
+
label: string;
|
|
7
|
+
onClick: () => void;
|
|
8
|
+
}
|
|
9
|
+
interface ToastOptions {
|
|
10
|
+
/** An existing toast's id replaces that toast, e.g. loading → success. */
|
|
11
|
+
id?: ToastId;
|
|
12
|
+
/** A second, muted line under the message. */
|
|
13
|
+
description?: ReactNode;
|
|
14
|
+
/** Milliseconds before it closes; `Number.POSITIVE_INFINITY` keeps it open. */
|
|
15
|
+
duration?: number;
|
|
16
|
+
/** The primary button, such as "Undo" or "Retry". */
|
|
17
|
+
action?: ToastAction;
|
|
18
|
+
/** A secondary outline button, such as "Dismiss". */
|
|
19
|
+
cancel?: ToastAction;
|
|
20
|
+
}
|
|
21
|
+
/** Shows a toast and returns its id. */
|
|
22
|
+
type ShowToast = (message: ReactNode, options?: ToastOptions) => ToastId;
|
|
23
|
+
type Toast = ShowToast & {
|
|
24
|
+
success: ShowToast;
|
|
25
|
+
info: ShowToast;
|
|
26
|
+
warning: ShowToast;
|
|
27
|
+
error: ShowToast;
|
|
28
|
+
/** A spinner toast that stays until it is replaced (same `id`) or dismissed. */
|
|
29
|
+
loading: ShowToast;
|
|
30
|
+
/** Closes one toast by id, or every toast when called without one. */
|
|
31
|
+
dismiss: (id?: ToastId) => void;
|
|
32
|
+
};
|
|
33
|
+
type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
|
|
34
|
+
interface ToasterProps {
|
|
35
|
+
/** Where toasts stack. Default `bottom-right`. */
|
|
36
|
+
position?: ToastPosition;
|
|
37
|
+
/** A labelled close button on every toast. Default `true`. */
|
|
38
|
+
closeButton?: boolean;
|
|
39
|
+
/** Keep the stack expanded instead of collapsed behind the newest toast. */
|
|
40
|
+
expand?: boolean;
|
|
41
|
+
/** How many toasts show at once. Default 3. */
|
|
42
|
+
visibleToasts?: number;
|
|
43
|
+
/** Milliseconds before a toast closes when it sets no `duration`. Default 4000. */
|
|
44
|
+
duration?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Shows a toast through the app's one `Toaster`: `toast("Saved")`,
|
|
48
|
+
* `toast.success(...)`, `toast.error(...)`. Returns its id.
|
|
49
|
+
*/
|
|
50
|
+
declare const toast: Toast;
|
|
51
|
+
/**
|
|
52
|
+
* Mount one near the app root, and show toasts with `toast()` from this
|
|
53
|
+
* module. Only the props declared here reach the library.
|
|
54
|
+
*/
|
|
55
|
+
declare const Toaster: ({ position, closeButton, expand, visibleToasts, duration, }: ToasterProps) => import("react").JSX.Element;
|
|
56
|
+
export { Toaster, toast };
|
|
57
|
+
export type { ToastAction, ToastId, ToastOptions, ToastPosition, ToasterProps };
|
|
@@ -2,9 +2,38 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { CircleAlertIcon, CircleCheckIcon, InfoIcon, LoaderCircleIcon, XIcon, } from "lucide-react";
|
|
4
4
|
import { useTheme } from "next-themes";
|
|
5
|
-
import { Toaster as Sonner, toast } from "sonner";
|
|
5
|
+
import { Toaster as Sonner, toast as sonnerToast, } from "sonner";
|
|
6
6
|
import { buttonVariants } from "./button.js";
|
|
7
7
|
import { cn } from "./utils.js";
|
|
8
|
+
/**
|
|
9
|
+
* Copies only the kit's options, so plain JavaScript callers cannot hand the
|
|
10
|
+
* library its own styling options (class names, `unstyled`, rich colors).
|
|
11
|
+
*/
|
|
12
|
+
function libraryOptions(options = {}) {
|
|
13
|
+
const { id, description, duration, action, cancel } = options;
|
|
14
|
+
return {
|
|
15
|
+
id,
|
|
16
|
+
description,
|
|
17
|
+
duration,
|
|
18
|
+
action: action && { label: action.label, onClick: () => action.onClick() },
|
|
19
|
+
cancel: cancel && { label: cancel.label, onClick: () => cancel.onClick() },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const show = (method) => (message, options) => method(message, libraryOptions(options));
|
|
23
|
+
/**
|
|
24
|
+
* Shows a toast through the app's one `Toaster`: `toast("Saved")`,
|
|
25
|
+
* `toast.success(...)`, `toast.error(...)`. Returns its id.
|
|
26
|
+
*/
|
|
27
|
+
const toast = Object.assign(show(sonnerToast), {
|
|
28
|
+
success: show(sonnerToast.success),
|
|
29
|
+
info: show(sonnerToast.info),
|
|
30
|
+
warning: show(sonnerToast.warning),
|
|
31
|
+
error: show(sonnerToast.error),
|
|
32
|
+
loading: show(sonnerToast.loading),
|
|
33
|
+
dismiss: (id) => {
|
|
34
|
+
sonnerToast.dismiss(id);
|
|
35
|
+
},
|
|
36
|
+
});
|
|
8
37
|
/**
|
|
9
38
|
* Toasts drawn entirely with kit classes. Sonner's own styles are unlayered
|
|
10
39
|
* CSS that Tailwind utilities cannot override, so the toaster runs Sonner
|
|
@@ -36,26 +65,12 @@ const icons = {
|
|
|
36
65
|
loading: (_jsx(LoaderCircleIcon, { "aria-hidden": true, className: "animate-spin text-muted-foreground" })),
|
|
37
66
|
close: _jsx(XIcon, { "aria-hidden": true }),
|
|
38
67
|
};
|
|
39
|
-
/** Merge app class names onto the kit's, part by part. */
|
|
40
|
-
function mergeClassNames(extra) {
|
|
41
|
-
if (!extra)
|
|
42
|
-
return classNames;
|
|
43
|
-
const merged = { ...classNames };
|
|
44
|
-
for (const [part, value] of Object.entries(extra)) {
|
|
45
|
-
merged[part] = cn(classNames[part], value);
|
|
46
|
-
}
|
|
47
|
-
return merged;
|
|
48
|
-
}
|
|
49
68
|
/**
|
|
50
|
-
* Mount one near the app root and
|
|
51
|
-
*
|
|
69
|
+
* Mount one near the app root, and show toasts with `toast()` from this
|
|
70
|
+
* module. Only the props declared here reach the library.
|
|
52
71
|
*/
|
|
53
|
-
const Toaster = ({
|
|
72
|
+
const Toaster = ({ position, closeButton = true, expand, visibleToasts, duration, }) => {
|
|
54
73
|
const { theme = "system" } = useTheme();
|
|
55
|
-
return (_jsx(Sonner, { theme: theme, className: "toaster group", closeButton:
|
|
56
|
-
...toastOptions,
|
|
57
|
-
unstyled: true,
|
|
58
|
-
classNames: mergeClassNames(toastOptions?.classNames),
|
|
59
|
-
} }));
|
|
74
|
+
return (_jsx(Sonner, { theme: theme, className: "toaster group", position: position, closeButton: closeButton, expand: expand, visibleToasts: visibleToasts, duration: duration, icons: icons, toastOptions: { unstyled: true, classNames } }));
|
|
60
75
|
};
|
|
61
76
|
export { Toaster, toast };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "atlas-react-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Shared React components and Tailwind theme for Atlas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -148,10 +148,6 @@
|
|
|
148
148
|
"types": "./dist/slider.d.ts",
|
|
149
149
|
"default": "./dist/slider.js"
|
|
150
150
|
},
|
|
151
|
-
"./sonner": {
|
|
152
|
-
"types": "./dist/sonner.d.ts",
|
|
153
|
-
"default": "./dist/sonner.js"
|
|
154
|
-
},
|
|
155
151
|
"./sortable-table-head": {
|
|
156
152
|
"types": "./dist/sortable-table-head.d.ts",
|
|
157
153
|
"default": "./dist/sortable-table-head.js"
|
|
@@ -188,6 +184,10 @@
|
|
|
188
184
|
"types": "./dist/theme-provider.d.ts",
|
|
189
185
|
"default": "./dist/theme-provider.js"
|
|
190
186
|
},
|
|
187
|
+
"./toast": {
|
|
188
|
+
"types": "./dist/toast.d.ts",
|
|
189
|
+
"default": "./dist/toast.js"
|
|
190
|
+
},
|
|
191
191
|
"./toggle": {
|
|
192
192
|
"types": "./dist/toggle.d.ts",
|
|
193
193
|
"default": "./dist/toggle.js"
|
|
@@ -39,8 +39,10 @@ and tells Tailwind to scan the kit's compiled files:
|
|
|
39
39
|
|
|
40
40
|
Dark mode needs `ThemeProvider` from `atlas-react-kit/theme-provider` near the
|
|
41
41
|
root (or a `dark` class on an ancestor). Toasts need one `<Toaster />` from
|
|
42
|
-
`atlas-react-kit/
|
|
43
|
-
|
|
42
|
+
`atlas-react-kit/toast`; show them with `toast()` from the same module, using
|
|
43
|
+
only the options it declares. Never import a toast library such as `sonner`
|
|
44
|
+
directly: the kit owns the toast API, and a second copy never reaches its
|
|
45
|
+
toaster. Fix missing setup rather than working
|
|
44
46
|
around unstyled components.
|
|
45
47
|
|
|
46
48
|
## 3. Pick the kit component for the job
|
|
@@ -125,7 +127,7 @@ list; the ones that come up most:
|
|
|
125
127
|
Overriding their height, padding, or border makes one field look different
|
|
126
128
|
from its neighbors.
|
|
127
129
|
- **Layout overrides**: `CardContent className="px-0"` makes one section flush
|
|
128
|
-
without `!important`. Tables already scroll horizontally
|
|
130
|
+
without `!important`. Tables and tab rows already scroll horizontally, so do
|
|
129
131
|
not wrap them in another overflow container.
|
|
130
132
|
- **Headings**: `CardTitle` and `DialogTitle` already apply the uppercase,
|
|
131
133
|
tracked heading style; use `font-heading` for other headings.
|
package/theme.css
CHANGED
|
@@ -255,4 +255,53 @@
|
|
|
255
255
|
[data-slot="card"] [data-slot="table-container"] {
|
|
256
256
|
--table-scroll-fade: var(--card);
|
|
257
257
|
}
|
|
258
|
+
|
|
259
|
+
/*
|
|
260
|
+
* Tab row overflow: same pinned-shadow / local-cover trick as tables.
|
|
261
|
+
* Covers match the muted list so a clipped label reads as overflow.
|
|
262
|
+
* The fifth layer is the list fill — the list itself stays transparent
|
|
263
|
+
* so the fades show through. Scrollbars stay hidden; the fade is the cue.
|
|
264
|
+
*/
|
|
265
|
+
[data-slot="tabs-scroller"] {
|
|
266
|
+
--tabs-scroll-fade: var(--muted);
|
|
267
|
+
scrollbar-width: none;
|
|
268
|
+
-ms-overflow-style: none;
|
|
269
|
+
scroll-padding-inline: 1rem;
|
|
270
|
+
background:
|
|
271
|
+
linear-gradient(to right, var(--tabs-scroll-fade) 40%, transparent),
|
|
272
|
+
linear-gradient(to left, var(--tabs-scroll-fade) 40%, transparent),
|
|
273
|
+
linear-gradient(
|
|
274
|
+
to right,
|
|
275
|
+
color-mix(in oklch, var(--foreground) 16%, transparent),
|
|
276
|
+
transparent 80%
|
|
277
|
+
),
|
|
278
|
+
linear-gradient(
|
|
279
|
+
to left,
|
|
280
|
+
color-mix(in oklch, var(--foreground) 16%, transparent),
|
|
281
|
+
transparent 80%
|
|
282
|
+
),
|
|
283
|
+
var(--tabs-scroll-fade);
|
|
284
|
+
background-repeat: no-repeat;
|
|
285
|
+
background-size:
|
|
286
|
+
1.5rem 100%,
|
|
287
|
+
1.5rem 100%,
|
|
288
|
+
0.75rem 100%,
|
|
289
|
+
0.75rem 100%,
|
|
290
|
+
100% 100%;
|
|
291
|
+
background-position:
|
|
292
|
+
left center,
|
|
293
|
+
right center,
|
|
294
|
+
left center,
|
|
295
|
+
right center,
|
|
296
|
+
center;
|
|
297
|
+
background-attachment: local, local, scroll, scroll, scroll;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
[data-slot="tabs-scroller"]::-webkit-scrollbar {
|
|
301
|
+
display: none;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
[data-slot="tabs-scroller"][data-variant="line"] {
|
|
305
|
+
--tabs-scroll-fade: var(--background);
|
|
306
|
+
}
|
|
258
307
|
}
|
package/dist/sonner.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { toast, type ToasterProps } from "sonner";
|
|
2
|
-
/**
|
|
3
|
-
* Mount one near the app root and call `toast()` from this module (not from
|
|
4
|
-
* `sonner` directly), so the app and the toaster always share one Sonner.
|
|
5
|
-
*/
|
|
6
|
-
declare const Toaster: ({ toastOptions, ...props }: ToasterProps) => import("react").JSX.Element;
|
|
7
|
-
export { Toaster, toast };
|
|
8
|
-
export type { ToasterProps };
|