@particle-academy/react-fancy 6.1.1 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +1 -0
- package/dist/breadcrumbs.cjs +2 -2
- package/dist/breadcrumbs.d.cts +13 -2
- package/dist/breadcrumbs.d.ts +13 -2
- package/dist/breadcrumbs.js +1 -1
- package/dist/chunk-5EW47IH7.js +194 -0
- package/dist/chunk-5EW47IH7.js.map +1 -0
- package/dist/{chunk-WJHPZS3U.js → chunk-GTS3QA7M.js} +11 -4
- package/dist/chunk-GTS3QA7M.js.map +1 -0
- package/dist/{chunk-MTDOFZIB.js → chunk-JY2RC6I4.js} +37 -7
- package/dist/chunk-JY2RC6I4.js.map +1 -0
- package/dist/{chunk-GK7IGL7N.cjs → chunk-KOTUFZJ6.cjs} +37 -7
- package/dist/chunk-KOTUFZJ6.cjs.map +1 -0
- package/dist/{chunk-EWE776WI.cjs → chunk-SKMORSBO.cjs} +11 -4
- package/dist/chunk-SKMORSBO.cjs.map +1 -0
- package/dist/chunk-Y3QAEF2P.cjs +196 -0
- package/dist/chunk-Y3QAEF2P.cjs.map +1 -0
- package/dist/index.cjs +16 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/inputs.cjs +5 -5
- package/dist/inputs.js +1 -1
- package/dist/sidebar.cjs +7 -3
- package/dist/sidebar.d.cts +20 -1
- package/dist/sidebar.d.ts +20 -1
- package/dist/sidebar.js +5 -1
- package/dist/stepper.cjs +14 -0
- package/dist/stepper.cjs.map +1 -0
- package/dist/stepper.d.cts +72 -0
- package/dist/stepper.d.ts +72 -0
- package/dist/stepper.js +5 -0
- package/dist/stepper.js.map +1 -0
- package/docs/Breadcrumbs.md +10 -1
- package/docs/Sidebar.md +54 -0
- package/docs/Stepper.md +124 -0
- package/package.json +11 -1
- package/dist/chunk-EWE776WI.cjs.map +0 -1
- package/dist/chunk-GK7IGL7N.cjs.map +0 -1
- package/dist/chunk-MTDOFZIB.js.map +0 -1
- package/dist/chunk-WJHPZS3U.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [6.3.0] - 2026-11-01
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`Stepper`: ordered steps with states (requested by Prism).** An `<ol>` of
|
|
19
|
+
steps, each with a title, optional description and rich content, in one of
|
|
20
|
+
`upcoming` / `current` / `complete` / `error`. Data-driven through a JSON-
|
|
21
|
+
friendly `steps` array, or compound with `Stepper.Step` (read as data, so both
|
|
22
|
+
forms render identically). Controlled (`current` + `onChange`) or
|
|
23
|
+
uncontrolled (`defaultCurrent`); a step's own `state` overrides the derived
|
|
24
|
+
one, which is how `error` is shown. **Pure content by default: no button,
|
|
25
|
+
input or form element at all.** `clickable` opts in to step buttons, with
|
|
26
|
+
arrow-key / Home / End focus movement. `aria-current="step"` on the current
|
|
27
|
+
step; each state is in visually hidden text and in the indicator's glyph,
|
|
28
|
+
never colour alone; `stateLabels` translates the words. Vertical by default,
|
|
29
|
+
`orientation="horizontal"` for short content; `showContent="current"` shows
|
|
30
|
+
only the current step's body. Server-renders without DOM globals. Handles:
|
|
31
|
+
`data-react-fancy-stepper`, `data-react-fancy-stepper-step` with `data-state`,
|
|
32
|
+
`data-index` and `data-step-id`. Subpath: `@particle-academy/react-fancy/stepper`.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **`BreadcrumbsItemProps` now accepts the element's HTML attributes.**
|
|
37
|
+
`Breadcrumbs.Item` always forwarded `title`, `id`, `aria-*`, `style` and
|
|
38
|
+
handlers to the element it renders, but the type listed its keys by hand and
|
|
39
|
+
rejected them, so a consumer titling a truncated crumb had to cast. It now
|
|
40
|
+
extends `HTMLAttributes<HTMLElement>` (the attributes valid on every element a
|
|
41
|
+
crumb can be: `<a>`, the `as` component, `<button>`, `<span>`), with
|
|
42
|
+
`onClick` kept at its existing `() => void` signature. The collapsed (below
|
|
43
|
+
`md`) dropdown now carries a crumb's `title` onto its menu entry; other
|
|
44
|
+
attributes stay on the trail, because both trails are in the DOM at once and
|
|
45
|
+
an `id` or `data-*` handle would be duplicated. **No action needed:** this
|
|
46
|
+
only adds accepted props, and every existing usage type-checks unchanged.
|
|
47
|
+
|
|
48
|
+
## [6.2.0] - 2026-11-01
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- **`Sidebar.Item` `dotTooltip`: the dot's words for sighted users.**
|
|
53
|
+
`dotLabel` reached screen readers only, and the item sets its own collapsed
|
|
54
|
+
`title`, so a consumer could not show those words. `dotTooltip` shows
|
|
55
|
+
`dotLabel` in a Fancy `Tooltip` to the right of the item on hover and
|
|
56
|
+
keyboard focus. It reuses `dotLabel` rather than taking separate text, so the
|
|
57
|
+
two audiences cannot be told different things. On a collapsed item it
|
|
58
|
+
replaces the native `title` (one bubble, not two) and shows the label above
|
|
59
|
+
the words. The bubble is `aria-hidden` and not wired as a description, since
|
|
60
|
+
the words are already in the accessible name. Inert without `dot` and
|
|
61
|
+
`dotLabel`. Handle: `data-react-fancy-sidebar-tooltip`.
|
|
62
|
+
- **`Sidebar.Item` `badgeLabel`: words for the badge.** A bare count ("2")
|
|
63
|
+
means nothing on its own to a screen reader. With `badgeLabel="2 agents"` the
|
|
64
|
+
visible badge gets `aria-hidden` and the label is added to the item's
|
|
65
|
+
accessible name as visually hidden text after a comma: "tynn, 2 agents". It
|
|
66
|
+
works expanded and on a collapsed rail with `collapsedBadge`, and composes
|
|
67
|
+
with `dotLabel` ("tynn needs you, 2 agents"). It is ignored while the badge is
|
|
68
|
+
not rendered. Handle: `data-react-fancy-sidebar-badge-label`.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- **`Sidebar.Item`: an expanded item's label and badge ran together in the
|
|
73
|
+
accessible name ("tynn2").** A visually hidden space now separates them
|
|
74
|
+
("tynn 2"). This adds one `<span class="sr-only"> </span>` before the badge
|
|
75
|
+
of an expanded item that has a `badge`; nothing changes visually, and items
|
|
76
|
+
without a badge render byte-identical markup. No consumer action needed,
|
|
77
|
+
unless you snapshot Sidebar markup, in which case expect that one element.
|
|
78
|
+
|
|
14
79
|
## [6.1.1] - 2026-11-01
|
|
15
80
|
|
|
16
81
|
### Fixed
|
package/README.md
CHANGED
|
@@ -130,6 +130,7 @@ npx vite build # Build demo app (verifies imports work)
|
|
|
130
130
|
| Card | Container with Header, Body, Footer compound slots | [docs](docs/Card.md) |
|
|
131
131
|
| Callout | Alert/info box with icon, color, and dismissible support | [docs](docs/Callout.md) |
|
|
132
132
|
| Timeline | Stacked, alternating, and horizontal timeline with data-driven or compound API | [docs](docs/Timeline.md) |
|
|
133
|
+
| Stepper | Ordered steps with upcoming / current / complete / error states; pure content by default, opt-in clickable steps | [docs](docs/Stepper.md) |
|
|
133
134
|
| Marquee | Auto-scrolling ticker strip with seamless wrap, px/s speed, fade edges, reduced-motion gate | [docs](docs/Marquee.md) |
|
|
134
135
|
|
|
135
136
|
### Overlay & Floating
|
package/dist/breadcrumbs.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSKMORSBO_cjs = require('./chunk-SKMORSBO.cjs');
|
|
4
4
|
require('./chunk-57FQGQJK.cjs');
|
|
5
5
|
require('./chunk-OUYC6EIL.cjs');
|
|
6
6
|
require('./chunk-ZU5Q77OT.cjs');
|
|
@@ -9,7 +9,7 @@ require('./chunk-ZU5Q77OT.cjs');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "Breadcrumbs", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkSKMORSBO_cjs.Breadcrumbs; }
|
|
13
13
|
});
|
|
14
14
|
//# sourceMappingURL=breadcrumbs.cjs.map
|
|
15
15
|
//# sourceMappingURL=breadcrumbs.cjs.map
|
package/dist/breadcrumbs.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ReactNode, HTMLAttributes } from 'react';
|
|
3
3
|
import { N as NavigableProps } from './types-DJI492iY.cjs';
|
|
4
4
|
|
|
5
5
|
interface BreadcrumbsProps {
|
|
@@ -8,7 +8,18 @@ interface BreadcrumbsProps {
|
|
|
8
8
|
shrink?: boolean;
|
|
9
9
|
className?: string;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A crumb accepts the HTML attributes common to every element it can render as
|
|
13
|
+
* (`<a>`, the `as` component, `<button>` or `<span>`), so `title`, `id`,
|
|
14
|
+
* `aria-*`, `style` and handlers are typed as well as forwarded. Typed against
|
|
15
|
+
* `HTMLElement` rather than one element because the crumb's element depends on
|
|
16
|
+
* its props; anchor-only attributes such as `target` are not offered, since the
|
|
17
|
+
* same crumb renders as a `<span>` once it is `active`.
|
|
18
|
+
*
|
|
19
|
+
* `onClick` is omitted from the element's attributes and redeclared below with
|
|
20
|
+
* its existing `() => void` signature.
|
|
21
|
+
*/
|
|
22
|
+
interface BreadcrumbsItemProps extends NavigableProps, Omit<HTMLAttributes<HTMLElement>, "onClick" | "children"> {
|
|
12
23
|
children: ReactNode;
|
|
13
24
|
active?: boolean;
|
|
14
25
|
/**
|
package/dist/breadcrumbs.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
2
|
+
import { ReactNode, HTMLAttributes } from 'react';
|
|
3
3
|
import { N as NavigableProps } from './types-DJI492iY.js';
|
|
4
4
|
|
|
5
5
|
interface BreadcrumbsProps {
|
|
@@ -8,7 +8,18 @@ interface BreadcrumbsProps {
|
|
|
8
8
|
shrink?: boolean;
|
|
9
9
|
className?: string;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* A crumb accepts the HTML attributes common to every element it can render as
|
|
13
|
+
* (`<a>`, the `as` component, `<button>` or `<span>`), so `title`, `id`,
|
|
14
|
+
* `aria-*`, `style` and handlers are typed as well as forwarded. Typed against
|
|
15
|
+
* `HTMLElement` rather than one element because the crumb's element depends on
|
|
16
|
+
* its props; anchor-only attributes such as `target` are not offered, since the
|
|
17
|
+
* same crumb renders as a `<span>` once it is `active`.
|
|
18
|
+
*
|
|
19
|
+
* `onClick` is omitted from the element's attributes and redeclared below with
|
|
20
|
+
* its existing `() => void` signature.
|
|
21
|
+
*/
|
|
22
|
+
interface BreadcrumbsItemProps extends NavigableProps, Omit<HTMLAttributes<HTMLElement>, "onClick" | "children"> {
|
|
12
23
|
children: ReactNode;
|
|
13
24
|
active?: boolean;
|
|
14
25
|
/**
|
package/dist/breadcrumbs.js
CHANGED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
2
|
+
import { cn } from './chunk-MMW2JGKZ.js';
|
|
3
|
+
import { forwardRef, Children, isValidElement } from 'react';
|
|
4
|
+
import { Check } from 'lucide-react';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var DEFAULT_STATE_LABELS = {
|
|
8
|
+
upcoming: "Not started",
|
|
9
|
+
current: "Current",
|
|
10
|
+
complete: "Completed",
|
|
11
|
+
error: "Error"
|
|
12
|
+
};
|
|
13
|
+
function StepperStep(_props) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
StepperStep.displayName = "StepperStep";
|
|
17
|
+
function stepsFromChildren(children) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const child of Children.toArray(children)) {
|
|
20
|
+
if (!isValidElement(child) || child.type !== StepperStep) continue;
|
|
21
|
+
const { children: content, ...rest } = child.props;
|
|
22
|
+
out.push({ ...rest, content });
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
var indicatorClass = {
|
|
27
|
+
complete: "border-transparent bg-zinc-900 text-white dark:bg-white dark:text-zinc-900",
|
|
28
|
+
current: "border-2 border-zinc-900 bg-[color:var(--fancy-surface,var(--color-white))] text-zinc-900 ring-4 ring-zinc-900/10 dark:border-white dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:text-white dark:ring-white/15",
|
|
29
|
+
upcoming: "border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]",
|
|
30
|
+
error: "border-transparent bg-red-600 text-white dark:bg-red-500"
|
|
31
|
+
};
|
|
32
|
+
var titleClass = {
|
|
33
|
+
complete: "font-medium text-zinc-900 dark:text-white",
|
|
34
|
+
current: "font-semibold text-zinc-900 dark:text-white",
|
|
35
|
+
upcoming: "font-medium text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]",
|
|
36
|
+
error: "font-semibold text-red-700 dark:text-red-400"
|
|
37
|
+
};
|
|
38
|
+
function Indicator({ state, index }) {
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
"span",
|
|
41
|
+
{
|
|
42
|
+
"aria-hidden": "true",
|
|
43
|
+
"data-react-fancy-stepper-indicator": "",
|
|
44
|
+
className: cn(
|
|
45
|
+
"relative z-10 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-sm font-semibold",
|
|
46
|
+
indicatorClass[state]
|
|
47
|
+
),
|
|
48
|
+
children: state === "complete" ? /* @__PURE__ */ jsx(Check, { size: 16, strokeWidth: 3 }) : state === "error" ? "!" : index + 1
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
var StepperRoot = forwardRef(
|
|
53
|
+
({
|
|
54
|
+
steps: stepsProp,
|
|
55
|
+
children,
|
|
56
|
+
current: currentProp,
|
|
57
|
+
defaultCurrent = 0,
|
|
58
|
+
onChange,
|
|
59
|
+
orientation = "vertical",
|
|
60
|
+
clickable = false,
|
|
61
|
+
showContent = "all",
|
|
62
|
+
stateLabels,
|
|
63
|
+
className,
|
|
64
|
+
onKeyDown,
|
|
65
|
+
...rest
|
|
66
|
+
}, ref) => {
|
|
67
|
+
const [current, setCurrent] = useControllableState(currentProp, defaultCurrent, onChange);
|
|
68
|
+
const steps = stepsProp ?? stepsFromChildren(children);
|
|
69
|
+
const labels = { ...DEFAULT_STATE_LABELS, ...stateLabels };
|
|
70
|
+
const horizontal = orientation === "horizontal";
|
|
71
|
+
const handleKeyDown = (e) => {
|
|
72
|
+
onKeyDown?.(e);
|
|
73
|
+
if (!clickable || e.defaultPrevented) return;
|
|
74
|
+
const prevKey = horizontal ? "ArrowLeft" : "ArrowUp";
|
|
75
|
+
const nextKey = horizontal ? "ArrowRight" : "ArrowDown";
|
|
76
|
+
if (![prevKey, nextKey, "Home", "End"].includes(e.key)) return;
|
|
77
|
+
const list = e.currentTarget;
|
|
78
|
+
const target = e.target.closest("[data-react-fancy-stepper-trigger]");
|
|
79
|
+
if (!target || target.closest("[data-react-fancy-stepper]") !== list) return;
|
|
80
|
+
const buttons = Array.from(
|
|
81
|
+
list.querySelectorAll("[data-react-fancy-stepper-trigger]")
|
|
82
|
+
).filter((b) => b.closest("[data-react-fancy-stepper]") === list && !b.disabled);
|
|
83
|
+
const at = buttons.indexOf(target);
|
|
84
|
+
let next;
|
|
85
|
+
if (e.key === "Home") next = buttons[0];
|
|
86
|
+
else if (e.key === "End") next = buttons[buttons.length - 1];
|
|
87
|
+
else if (e.key === nextKey) next = buttons[at + 1] ?? target;
|
|
88
|
+
else next = at > 0 ? buttons[at - 1] : target;
|
|
89
|
+
e.preventDefault();
|
|
90
|
+
next?.focus();
|
|
91
|
+
};
|
|
92
|
+
return /* @__PURE__ */ jsx(
|
|
93
|
+
"ol",
|
|
94
|
+
{
|
|
95
|
+
ref,
|
|
96
|
+
"data-react-fancy-stepper": "",
|
|
97
|
+
"data-orientation": orientation,
|
|
98
|
+
"data-current": current,
|
|
99
|
+
className: cn(horizontal ? "flex items-start" : "flex flex-col", className),
|
|
100
|
+
onKeyDown: handleKeyDown,
|
|
101
|
+
...rest,
|
|
102
|
+
children: steps.map((step, index) => {
|
|
103
|
+
const derived = index < current ? "complete" : index === current ? "current" : "upcoming";
|
|
104
|
+
const state = step.state ?? derived;
|
|
105
|
+
const isCurrent = index === current;
|
|
106
|
+
const isLast = index === steps.length - 1;
|
|
107
|
+
const showBody = step.content != null && (showContent === "all" || isCurrent);
|
|
108
|
+
const headerInner = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
109
|
+
/* @__PURE__ */ jsx(Indicator, { state, index }),
|
|
110
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", "data-react-fancy-stepper-state": "", children: [
|
|
111
|
+
labels[state],
|
|
112
|
+
":",
|
|
113
|
+
" "
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { "data-react-fancy-stepper-title": "", className: cn("text-sm", titleClass[state]), children: step.title })
|
|
116
|
+
] });
|
|
117
|
+
const headerClass = horizontal ? "flex flex-col items-center gap-2 text-center" : "flex items-center gap-x-4 text-left";
|
|
118
|
+
const header = clickable ? /* @__PURE__ */ jsx(
|
|
119
|
+
"button",
|
|
120
|
+
{
|
|
121
|
+
type: "button",
|
|
122
|
+
"data-react-fancy-stepper-trigger": "",
|
|
123
|
+
disabled: step.disabled,
|
|
124
|
+
onClick: () => {
|
|
125
|
+
if (index !== current) setCurrent(index);
|
|
126
|
+
},
|
|
127
|
+
className: cn(
|
|
128
|
+
headerClass,
|
|
129
|
+
"cursor-pointer rounded-md border-0 bg-transparent p-0",
|
|
130
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
131
|
+
"focus-visible:ring-[color:var(--fancy-focus,var(--color-blue-500))] focus-visible:ring-offset-[color:var(--fancy-surface,var(--color-white))]",
|
|
132
|
+
"dark:focus-visible:ring-[color:var(--fancy-focus-dark,var(--color-blue-400))] dark:focus-visible:ring-offset-[color:var(--fancy-surface-dark,var(--color-zinc-900))]",
|
|
133
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
134
|
+
),
|
|
135
|
+
children: headerInner
|
|
136
|
+
}
|
|
137
|
+
) : /* @__PURE__ */ jsx("div", { className: headerClass, children: headerInner });
|
|
138
|
+
return /* @__PURE__ */ jsxs(
|
|
139
|
+
"li",
|
|
140
|
+
{
|
|
141
|
+
"data-react-fancy-stepper-step": "",
|
|
142
|
+
"data-state": state,
|
|
143
|
+
"data-index": index,
|
|
144
|
+
"data-step-id": step.id,
|
|
145
|
+
"data-disabled": step.disabled ? "true" : void 0,
|
|
146
|
+
"aria-current": isCurrent ? "step" : void 0,
|
|
147
|
+
className: cn("relative", horizontal ? "min-w-0 flex-1" : !isLast && "pb-8"),
|
|
148
|
+
children: [
|
|
149
|
+
!isLast && /* @__PURE__ */ jsx(
|
|
150
|
+
"span",
|
|
151
|
+
{
|
|
152
|
+
"aria-hidden": "true",
|
|
153
|
+
"data-react-fancy-stepper-connector": "",
|
|
154
|
+
className: cn(
|
|
155
|
+
"absolute",
|
|
156
|
+
horizontal ? "top-4 left-[calc(50%+1.5rem)] h-px w-[calc(100%-3rem)]" : "top-10 bottom-2 left-4 w-px -translate-x-1/2",
|
|
157
|
+
index < current ? "bg-zinc-900 dark:bg-white" : "bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]"
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
),
|
|
161
|
+
header,
|
|
162
|
+
(step.description != null || showBody) && /* @__PURE__ */ jsxs("div", { className: horizontal ? "mt-1 px-2 text-center" : "pl-12", children: [
|
|
163
|
+
step.description != null && /* @__PURE__ */ jsx(
|
|
164
|
+
"div",
|
|
165
|
+
{
|
|
166
|
+
"data-react-fancy-stepper-description": "",
|
|
167
|
+
className: "text-sm text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]",
|
|
168
|
+
children: step.description
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
showBody && /* @__PURE__ */ jsx(
|
|
172
|
+
"div",
|
|
173
|
+
{
|
|
174
|
+
"data-react-fancy-stepper-content": "",
|
|
175
|
+
className: "mt-2 text-sm text-[color:var(--fancy-text-subtle,var(--color-zinc-600))] dark:text-[color:var(--fancy-text-subtle-dark,var(--color-zinc-400))]",
|
|
176
|
+
children: step.content
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
] })
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
step.id ?? index
|
|
183
|
+
);
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
StepperRoot.displayName = "Stepper";
|
|
190
|
+
var Stepper = Object.assign(StepperRoot, { Step: StepperStep });
|
|
191
|
+
|
|
192
|
+
export { Stepper };
|
|
193
|
+
//# sourceMappingURL=chunk-5EW47IH7.js.map
|
|
194
|
+
//# sourceMappingURL=chunk-5EW47IH7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Stepper/Stepper.tsx"],"names":[],"mappings":"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","file":"chunk-5EW47IH7.js","sourcesContent":["import {\n Children,\n forwardRef,\n isValidElement,\n type KeyboardEvent,\n type ReactNode,\n} from \"react\";\nimport { Check } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useControllableState } from \"../../hooks/use-controllable-state\";\nimport type {\n StepperProps,\n StepperStep as StepperStepData,\n StepperStepProps,\n StepperStepState,\n} from \"./Stepper.types\";\n\nconst DEFAULT_STATE_LABELS: Record<StepperStepState, string> = {\n upcoming: \"Not started\",\n current: \"Current\",\n complete: \"Completed\",\n error: \"Error\",\n};\n\n/**\n * Declarative step. Renders nothing itself: `Stepper` reads its props as data\n * and renders it through the same path as an entry in `steps`, so the two forms\n * cannot drift apart in markup, states or handles. Its children are the step's\n * content. It must be a DIRECT child of `Stepper` (not wrapped in another\n * component) for the same reason `Breadcrumbs.Item` must.\n */\nfunction StepperStep(_props: StepperStepProps): null {\n return null;\n}\nStepperStep.displayName = \"StepperStep\";\n\nfunction stepsFromChildren(children: ReactNode): StepperStepData[] {\n const out: StepperStepData[] = [];\n for (const child of Children.toArray(children)) {\n if (!isValidElement<StepperStepProps>(child) || child.type !== StepperStep) continue;\n const { children: content, ...rest } = child.props;\n out.push({ ...rest, content });\n }\n return out;\n}\n\nconst indicatorClass: Record<StepperStepState, string> = {\n complete:\n \"border-transparent bg-zinc-900 text-white dark:bg-white dark:text-zinc-900\",\n current:\n \"border-2 border-zinc-900 bg-[color:var(--fancy-surface,var(--color-white))] text-zinc-900 ring-4 ring-zinc-900/10 dark:border-white dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:text-white dark:ring-white/15\",\n upcoming:\n \"border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\",\n error: \"border-transparent bg-red-600 text-white dark:bg-red-500\",\n};\n\nconst titleClass: Record<StepperStepState, string> = {\n complete: \"font-medium text-zinc-900 dark:text-white\",\n current: \"font-semibold text-zinc-900 dark:text-white\",\n upcoming:\n \"font-medium text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\",\n error: \"font-semibold text-red-700 dark:text-red-400\",\n};\n\n/** The glyph differs per state, so state reads without colour: number, tick, \"!\". */\nfunction Indicator({ state, index }: { state: StepperStepState; index: number }) {\n return (\n <span\n aria-hidden=\"true\"\n data-react-fancy-stepper-indicator=\"\"\n className={cn(\n \"relative z-10 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border text-sm font-semibold\",\n indicatorClass[state],\n )}\n >\n {state === \"complete\" ? <Check size={16} strokeWidth={3} /> : state === \"error\" ? \"!\" : index + 1}\n </span>\n );\n}\n\nconst StepperRoot = forwardRef<HTMLOListElement, StepperProps>(\n (\n {\n steps: stepsProp,\n children,\n current: currentProp,\n defaultCurrent = 0,\n onChange,\n orientation = \"vertical\",\n clickable = false,\n showContent = \"all\",\n stateLabels,\n className,\n onKeyDown,\n ...rest\n },\n ref,\n ) => {\n const [current, setCurrent] = useControllableState(currentProp, defaultCurrent, onChange);\n const steps = stepsProp ?? stepsFromChildren(children);\n const labels = { ...DEFAULT_STATE_LABELS, ...stateLabels };\n const horizontal = orientation === \"horizontal\";\n\n // Arrow keys move focus between step buttons; Enter / Space activate them\n // natively. Focus only -- the current step changes on activation, never on\n // arrowing past it. DOM is read in the handler, never during render.\n const handleKeyDown = (e: KeyboardEvent<HTMLOListElement>) => {\n onKeyDown?.(e);\n if (!clickable || e.defaultPrevented) return;\n\n const prevKey = horizontal ? \"ArrowLeft\" : \"ArrowUp\";\n const nextKey = horizontal ? \"ArrowRight\" : \"ArrowDown\";\n if (![prevKey, nextKey, \"Home\", \"End\"].includes(e.key)) return;\n\n const list = e.currentTarget;\n const target = (e.target as HTMLElement).closest<HTMLButtonElement>(\"[data-react-fancy-stepper-trigger]\");\n if (!target || target.closest(\"[data-react-fancy-stepper]\") !== list) return;\n\n // Only this stepper's own buttons: a stepper nested in step content is\n // its own list.\n const buttons = Array.from(\n list.querySelectorAll<HTMLButtonElement>(\"[data-react-fancy-stepper-trigger]\"),\n ).filter((b) => b.closest(\"[data-react-fancy-stepper]\") === list && !b.disabled);\n const at = buttons.indexOf(target);\n\n let next: HTMLButtonElement | undefined;\n if (e.key === \"Home\") next = buttons[0];\n else if (e.key === \"End\") next = buttons[buttons.length - 1];\n else if (e.key === nextKey) next = buttons[at + 1] ?? target;\n else next = at > 0 ? buttons[at - 1] : target;\n\n e.preventDefault();\n next?.focus();\n };\n\n return (\n <ol\n ref={ref}\n data-react-fancy-stepper=\"\"\n data-orientation={orientation}\n data-current={current}\n className={cn(horizontal ? \"flex items-start\" : \"flex flex-col\", className)}\n onKeyDown={handleKeyDown}\n {...rest}\n >\n {steps.map((step, index) => {\n const derived: StepperStepState =\n index < current ? \"complete\" : index === current ? \"current\" : \"upcoming\";\n const state = step.state ?? derived;\n const isCurrent = index === current;\n const isLast = index === steps.length - 1;\n const showBody = step.content != null && (showContent === \"all\" || isCurrent);\n\n const headerInner = (\n <>\n <Indicator state={state} index={index} />\n {/* State in words, before the title so it is read first. A\n sibling of the title, so the title handle reads the title. */}\n <span className=\"sr-only\" data-react-fancy-stepper-state=\"\">\n {labels[state]}:{\" \"}\n </span>\n <span data-react-fancy-stepper-title=\"\" className={cn(\"text-sm\", titleClass[state])}>\n {step.title}\n </span>\n </>\n );\n\n const headerClass = horizontal\n ? \"flex flex-col items-center gap-2 text-center\"\n : \"flex items-center gap-x-4 text-left\";\n\n const header = clickable ? (\n <button\n type=\"button\"\n data-react-fancy-stepper-trigger=\"\"\n disabled={step.disabled}\n onClick={() => {\n if (index !== current) setCurrent(index);\n }}\n className={cn(\n headerClass,\n \"cursor-pointer rounded-md border-0 bg-transparent p-0\",\n \"focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2\",\n \"focus-visible:ring-[color:var(--fancy-focus,var(--color-blue-500))] focus-visible:ring-offset-[color:var(--fancy-surface,var(--color-white))]\",\n \"dark:focus-visible:ring-[color:var(--fancy-focus-dark,var(--color-blue-400))] dark:focus-visible:ring-offset-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n )}\n >\n {headerInner}\n </button>\n ) : (\n <div className={headerClass}>{headerInner}</div>\n );\n\n return (\n <li\n key={step.id ?? index}\n data-react-fancy-stepper-step=\"\"\n data-state={state}\n data-index={index}\n data-step-id={step.id}\n data-disabled={step.disabled ? \"true\" : undefined}\n aria-current={isCurrent ? \"step\" : undefined}\n className={cn(\"relative\", horizontal ? \"min-w-0 flex-1\" : !isLast && \"pb-8\")}\n >\n {!isLast && (\n <span\n aria-hidden=\"true\"\n data-react-fancy-stepper-connector=\"\"\n className={cn(\n \"absolute\",\n horizontal\n ? \"top-4 left-[calc(50%+1.5rem)] h-px w-[calc(100%-3rem)]\"\n : \"top-10 bottom-2 left-4 w-px -translate-x-1/2\",\n index < current\n ? \"bg-zinc-900 dark:bg-white\"\n : \"bg-[color:var(--fancy-border,var(--color-zinc-200))] dark:bg-[color:var(--fancy-border-dark,var(--color-zinc-700))]\",\n )}\n />\n )}\n {header}\n {(step.description != null || showBody) && (\n <div className={horizontal ? \"mt-1 px-2 text-center\" : \"pl-12\"}>\n {step.description != null && (\n <div\n data-react-fancy-stepper-description=\"\"\n className=\"text-sm text-[color:var(--fancy-text-muted,var(--color-zinc-500))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))]\"\n >\n {step.description}\n </div>\n )}\n {showBody && (\n <div\n data-react-fancy-stepper-content=\"\"\n className=\"mt-2 text-sm text-[color:var(--fancy-text-subtle,var(--color-zinc-600))] dark:text-[color:var(--fancy-text-subtle-dark,var(--color-zinc-400))]\"\n >\n {step.content}\n </div>\n )}\n </div>\n )}\n </li>\n );\n })}\n </ol>\n );\n },\n);\n\nStepperRoot.displayName = \"Stepper\";\n\nexport const Stepper = Object.assign(StepperRoot, { Step: StepperStep });\n"]}
|
|
@@ -78,6 +78,7 @@ function BreadcrumbsDropdown({ items, activeLabel }) {
|
|
|
78
78
|
Link,
|
|
79
79
|
{
|
|
80
80
|
...item.href ? { href: item.href } : {},
|
|
81
|
+
title: item.title,
|
|
81
82
|
className: cls,
|
|
82
83
|
onClick: () => {
|
|
83
84
|
item.onClick?.();
|
|
@@ -94,6 +95,7 @@ function BreadcrumbsDropdown({ items, activeLabel }) {
|
|
|
94
95
|
"button",
|
|
95
96
|
{
|
|
96
97
|
type: "button",
|
|
98
|
+
title: item.title,
|
|
97
99
|
className: cn(cls, "cursor-pointer border-0 bg-transparent"),
|
|
98
100
|
onClick: () => {
|
|
99
101
|
onClick();
|
|
@@ -104,7 +106,7 @@ function BreadcrumbsDropdown({ items, activeLabel }) {
|
|
|
104
106
|
i
|
|
105
107
|
);
|
|
106
108
|
}
|
|
107
|
-
return /* @__PURE__ */ jsx("span", { className: cls, children: item.label }, i);
|
|
109
|
+
return /* @__PURE__ */ jsx("span", { title: item.title, className: cls, children: item.label }, i);
|
|
108
110
|
}) })
|
|
109
111
|
] });
|
|
110
112
|
}
|
|
@@ -126,7 +128,12 @@ function BreadcrumbsRoot({
|
|
|
126
128
|
href: el.props?.href,
|
|
127
129
|
as: el.props?.as,
|
|
128
130
|
onClick: el.props?.onClick,
|
|
129
|
-
active: el.props?.active
|
|
131
|
+
active: el.props?.active,
|
|
132
|
+
// Only `title` crosses into the menu. It is the full text of a crumb the
|
|
133
|
+
// consumer truncated, and the narrow menu is where labels get cut. Other
|
|
134
|
+
// attributes stay on the trail: both trails are in the DOM at once (CSS
|
|
135
|
+
// hides one), so an `id` or a `data-*` handle would be duplicated.
|
|
136
|
+
title: el.props?.title
|
|
130
137
|
};
|
|
131
138
|
});
|
|
132
139
|
const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? "Menu";
|
|
@@ -166,5 +173,5 @@ var Breadcrumbs = Object.assign(BreadcrumbsRoot, {
|
|
|
166
173
|
});
|
|
167
174
|
|
|
168
175
|
export { Breadcrumbs };
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
170
|
-
//# sourceMappingURL=chunk-
|
|
176
|
+
//# sourceMappingURL=chunk-GTS3QA7M.js.map
|
|
177
|
+
//# sourceMappingURL=chunk-GTS3QA7M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Breadcrumbs/BreadcrumbsItem.tsx","../src/components/Breadcrumbs/BreadcrumbsDropdown.tsx","../src/components/Breadcrumbs/Breadcrumbs.tsx"],"names":["jsx","useState","jsxs","Fragment"],"mappings":"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","file":"chunk-GTS3QA7M.js","sourcesContent":["import type { ElementType } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nexport function BreadcrumbsItem({\n children,\n href,\n as: As,\n active = false,\n onClick,\n className,\n ...rest\n}: BreadcrumbsItemProps) {\n const baseClass = cn(\n \"text-sm\",\n active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n className,\n );\n\n // The CURRENT crumb stays a <span> even with `as`: it is the page you are on,\n // so a link to it is a link to nowhere, and `aria-current=\"page\"` is the point.\n if ((href || As) && !active) {\n const Link = (As ?? \"a\") as ElementType;\n\n return (\n <Link\n data-react-fancy-breadcrumbs-item=\"\"\n {...(href ? { href } : {})}\n onClick={onClick}\n className={baseClass}\n {...rest}\n >\n {children}\n </Link>\n );\n }\n\n // A crumb that navigates through a callback rather than a URL. Controlled\n // components own their navigation and have no href to give — a repository\n // browser walking directories, a wizard stepping back — and until this\n // existed the only way to make such a crumb clickable was to nest a button\n // inside the span below, which is interactive content inside a non-\n // interactive element.\n if (onClick && !active) {\n return (\n <button\n type=\"button\"\n data-react-fancy-breadcrumbs-item=\"\"\n onClick={onClick}\n className={cn(baseClass, \"cursor-pointer border-0 bg-transparent p-0\")}\n {...rest}\n >\n {children}\n </button>\n );\n }\n\n return (\n <span data-react-fancy-breadcrumbs-item=\"\" className={baseClass} aria-current={active ? \"page\" : undefined} {...rest}>\n {children}\n </span>\n );\n}\n\nBreadcrumbsItem.displayName = \"BreadcrumbsItem\";\n","import { useState, useRef, type ElementType, type ReactNode } from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { useOutsideClick } from \"../../hooks/use-outside-click\";\nimport { useEscapeKey } from \"../../hooks/use-escape-key\";\n\ninterface BreadcrumbsDropdownItem {\n label: ReactNode;\n href?: string;\n as?: ElementType;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n}\n\ninterface BreadcrumbsDropdownProps {\n items: BreadcrumbsDropdownItem[];\n activeLabel: ReactNode;\n}\n\nexport function BreadcrumbsDropdown({ items, activeLabel }: BreadcrumbsDropdownProps) {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useOutsideClick(ref, () => setOpen(false), open);\n useEscapeKey(() => setOpen(false), open);\n\n return (\n <div ref={ref} data-react-fancy-breadcrumbs-dropdown=\"\" className=\"relative flex md:hidden\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1 rounded-lg px-2 py-1 text-sm font-medium text-zinc-900 hover:bg-[color:var(--fancy-surface-muted,var(--color-zinc-100))] dark:text-white dark:hover:bg-[color:var(--fancy-surface-muted-dark,var(--color-zinc-800))]\"\n >\n {activeLabel}\n <ChevronDown size={14} className={cn(\"transition-transform\", open && \"rotate-180\")} />\n </button>\n {open && (\n <div className=\"absolute top-full left-0 z-50 mt-1 min-w-[180px] rounded-lg border border-[color:var(--fancy-border,var(--color-zinc-200))] bg-[color:var(--fancy-surface,var(--color-white))] py-1 shadow-lg dark:border-[color:var(--fancy-border-dark,var(--color-zinc-700))] dark:bg-[color:var(--fancy-surface-dark,var(--color-zinc-900))]\">\n {items.map((item, i) => {\n const cls = cn(\n \"block w-full px-3 py-1.5 text-left text-sm\",\n item.active\n ? \"font-medium text-zinc-900 dark:text-white\"\n : \"text-[color:var(--fancy-text-muted,var(--color-zinc-500))] hover:bg-zinc-50 hover:text-[color:var(--fancy-text-soft,var(--color-zinc-700))] dark:text-[color:var(--fancy-text-muted-dark,var(--color-zinc-400))] dark:hover:bg-zinc-800 dark:hover:text-[color:var(--fancy-text-soft-dark,var(--color-zinc-300))]\",\n );\n\n // Mirrors BreadcrumbsItem: href / `as` wins, then onClick, and the\n // active crumb stays inert whatever it carries.\n if ((item.href || item.as) && !item.active) {\n const Link = (item.as ?? \"a\") as ElementType;\n return (\n <Link\n key={i}\n {...(item.href ? { href: item.href } : {})}\n title={item.title}\n className={cls}\n onClick={() => {\n item.onClick?.();\n setOpen(false);\n }}\n >\n {item.label}\n </Link>\n );\n }\n\n if (item.onClick && !item.active) {\n const onClick = item.onClick;\n return (\n <button\n key={i}\n type=\"button\"\n title={item.title}\n className={cn(cls, \"cursor-pointer border-0 bg-transparent\")}\n onClick={() => {\n onClick();\n setOpen(false);\n }}\n >\n {item.label}\n </button>\n );\n }\n\n return (\n <span key={i} title={item.title} className={cls}>\n {item.label}\n </span>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n\nBreadcrumbsDropdown.displayName = \"BreadcrumbsDropdown\";\n","import { Children, Fragment, useState, type ReactElement } from \"react\";\nimport { ChevronRight } from \"lucide-react\";\nimport { cn } from \"../../utils/cn\";\nimport { BreadcrumbsItem } from \"./BreadcrumbsItem\";\nimport { BreadcrumbsDropdown } from \"./BreadcrumbsDropdown\";\nimport type { BreadcrumbsProps, BreadcrumbsItemProps } from \"./Breadcrumbs.types\";\n\nfunction BreadcrumbsRoot({\n children,\n separator,\n shrink,\n className,\n}: BreadcrumbsProps) {\n const items = Children.toArray(children);\n const [expanded, setExpanded] = useState(false);\n\n const sep = separator ?? (\n <ChevronRight size={12} className=\"text-zinc-400\" />\n );\n\n const lastItem = items[items.length - 1];\n\n // Extract info from children for mobile dropdown\n const dropdownItems = items.map((child) => {\n const el = child as ReactElement<BreadcrumbsItemProps>;\n return {\n label: el.props?.children,\n href: el.props?.href,\n as: el.props?.as,\n onClick: el.props?.onClick,\n active: el.props?.active,\n // Only `title` crosses into the menu. It is the full text of a crumb the\n // consumer truncated, and the narrow menu is where labels get cut. Other\n // attributes stay on the trail: both trails are in the DOM at once (CSS\n // hides one), so an `id` or a `data-*` handle would be duplicated.\n title: el.props?.title,\n };\n });\n\n const activeLabel = dropdownItems[dropdownItems.length - 1]?.label ?? \"Menu\";\n\n const showShrunk = shrink && !expanded && items.length > 1;\n\n return (\n <>\n {/* Desktop trail */}\n <nav\n data-react-fancy-breadcrumbs=\"\"\n aria-label=\"Breadcrumb\"\n className={cn(\"hidden items-center gap-2 md:flex\", className)}\n onMouseLeave={() => shrink && setExpanded(false)}\n >\n {showShrunk ? (\n <>\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n onMouseEnter={() => setExpanded(true)}\n className=\"text-sm text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300\"\n >\n ...\n </button>\n <span aria-hidden=\"true\">{sep}</span>\n {lastItem}\n </>\n ) : (\n items.map((child, i) => (\n <Fragment key={i}>\n {i > 0 && <span aria-hidden=\"true\">{sep}</span>}\n {child}\n </Fragment>\n ))\n )}\n </nav>\n\n {/* Mobile dropdown */}\n <BreadcrumbsDropdown items={dropdownItems} activeLabel={activeLabel} />\n </>\n );\n}\n\nexport const Breadcrumbs = Object.assign(BreadcrumbsRoot, {\n Item: BreadcrumbsItem,\n});\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Tooltip } from './chunk-GR2WKBER.js';
|
|
1
2
|
import { badgeDot } from './chunk-S53A6JIE.js';
|
|
2
3
|
import { useControllableState } from './chunk-EDYAXGUM.js';
|
|
3
4
|
import { cn } from './chunk-MMW2JGKZ.js';
|
|
@@ -118,9 +119,11 @@ function SidebarItem({
|
|
|
118
119
|
active = false,
|
|
119
120
|
disabled = false,
|
|
120
121
|
badge,
|
|
122
|
+
badgeLabel,
|
|
121
123
|
collapsedBadge = false,
|
|
122
124
|
dot,
|
|
123
125
|
dotLabel,
|
|
126
|
+
dotTooltip = false,
|
|
124
127
|
onClick,
|
|
125
128
|
className,
|
|
126
129
|
...rest
|
|
@@ -135,13 +138,19 @@ function SidebarItem({
|
|
|
135
138
|
const dotColor = dot === true ? "red" : dot || null;
|
|
136
139
|
const showCollapsedBadge = collapsed && collapsedBadge && Boolean(badge);
|
|
137
140
|
const hasMarks = dotColor !== null || showCollapsedBadge;
|
|
141
|
+
const badgeShown = Boolean(badge) && (!collapsed || showCollapsedBadge);
|
|
142
|
+
const badgeLabelEl = badgeShown && badgeLabel ? (
|
|
143
|
+
// The comma is the separator, so whatever renders before this must not
|
|
144
|
+
// end in a space ("tynn , 2 agents"); see the two trailing spaces below.
|
|
145
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", "data-react-fancy-sidebar-badge-label": "", children: `, ${badgeLabel}` })
|
|
146
|
+
) : null;
|
|
138
147
|
const dotLabelEl = dotColor && dotLabel ? (
|
|
139
148
|
// The spaces are load-bearing: adjacent inline elements concatenate in
|
|
140
149
|
// the accessible name, so without them it reads "Inbox3 unread".
|
|
141
150
|
/* @__PURE__ */ jsxs("span", { className: "sr-only", "data-react-fancy-sidebar-dot-label": "", children: [
|
|
142
151
|
" ",
|
|
143
152
|
dotLabel,
|
|
144
|
-
" "
|
|
153
|
+
badgeLabelEl ? null : " "
|
|
145
154
|
] })
|
|
146
155
|
) : null;
|
|
147
156
|
const needsHiddenLabel = collapsed && (dotLabelEl !== null || showCollapsedBadge);
|
|
@@ -150,6 +159,7 @@ function SidebarItem({
|
|
|
150
159
|
"span",
|
|
151
160
|
{
|
|
152
161
|
"data-react-fancy-sidebar-badge": "",
|
|
162
|
+
"aria-hidden": badgeLabelEl ? "true" : void 0,
|
|
153
163
|
className: "pointer-events-none absolute -right-3 -top-2.5 whitespace-nowrap",
|
|
154
164
|
children: badge
|
|
155
165
|
}
|
|
@@ -173,7 +183,8 @@ function SidebarItem({
|
|
|
173
183
|
"flex h-5 w-5 shrink-0 items-center justify-center",
|
|
174
184
|
hasMarks && "relative"
|
|
175
185
|
);
|
|
176
|
-
|
|
186
|
+
const showDotTooltip = dotTooltip && dotLabelEl !== null;
|
|
187
|
+
const node = /* @__PURE__ */ jsxs(
|
|
177
188
|
Tag,
|
|
178
189
|
{
|
|
179
190
|
...tagProps,
|
|
@@ -182,7 +193,7 @@ function SidebarItem({
|
|
|
182
193
|
"data-active": active || void 0,
|
|
183
194
|
"aria-current": active ? "page" : void 0,
|
|
184
195
|
"aria-disabled": disabled || void 0,
|
|
185
|
-
title: collapsed ? title : void 0,
|
|
196
|
+
title: collapsed && !showDotTooltip ? title : void 0,
|
|
186
197
|
className: cn(
|
|
187
198
|
// `w-full` matters when the Tag is a <button>: form controls size to
|
|
188
199
|
// FIT-CONTENT, not to their parent, so a long label made the item wider
|
|
@@ -203,9 +214,10 @@ function SidebarItem({
|
|
|
203
214
|
children: [
|
|
204
215
|
needsHiddenLabel && /* @__PURE__ */ jsxs("span", { className: "sr-only", "data-react-fancy-sidebar-label": "", children: [
|
|
205
216
|
children,
|
|
206
|
-
" "
|
|
217
|
+
badgeLabelEl && !dotLabelEl ? null : " "
|
|
207
218
|
] }),
|
|
208
219
|
collapsed && dotLabelEl,
|
|
220
|
+
collapsed && badgeLabelEl,
|
|
209
221
|
showIconOnly && /* @__PURE__ */ jsxs("span", { className: iconClass, children: [
|
|
210
222
|
icon,
|
|
211
223
|
renderMarks(false)
|
|
@@ -229,11 +241,29 @@ function SidebarItem({
|
|
|
229
241
|
!icon && renderMarks(true),
|
|
230
242
|
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-left", children }),
|
|
231
243
|
dotLabelEl,
|
|
232
|
-
badge && /* @__PURE__ */ jsx("span", { className: "
|
|
244
|
+
badge && (badgeLabelEl ?? /* @__PURE__ */ jsx("span", { className: "sr-only", children: " " })),
|
|
245
|
+
badge && /* @__PURE__ */ jsx("span", { className: "shrink-0", "aria-hidden": badgeLabelEl ? "true" : void 0, children: badge })
|
|
233
246
|
] })
|
|
234
247
|
]
|
|
235
248
|
}
|
|
236
249
|
);
|
|
250
|
+
if (!showDotTooltip) return node;
|
|
251
|
+
return /* @__PURE__ */ jsx(
|
|
252
|
+
Tooltip,
|
|
253
|
+
{
|
|
254
|
+
placement: "right",
|
|
255
|
+
content: (
|
|
256
|
+
// aria-hidden, and deliberately NOT linked with aria-describedby:
|
|
257
|
+
// the same words are already in the item's accessible name via
|
|
258
|
+
// `dotLabel`, so exposing the bubble would read them twice.
|
|
259
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": "true", "data-react-fancy-sidebar-tooltip": "", children: [
|
|
260
|
+
collapsed && /* @__PURE__ */ jsx("span", { className: "block font-medium", "data-react-fancy-sidebar-tooltip-label": "", children }),
|
|
261
|
+
dotLabel
|
|
262
|
+
] })
|
|
263
|
+
),
|
|
264
|
+
children: node
|
|
265
|
+
}
|
|
266
|
+
);
|
|
237
267
|
}
|
|
238
268
|
SidebarItem.displayName = "SidebarItem";
|
|
239
269
|
function SidebarGroup({ children, label, className }) {
|
|
@@ -403,5 +433,5 @@ var Sidebar = Object.assign(SidebarRoot, {
|
|
|
403
433
|
});
|
|
404
434
|
|
|
405
435
|
export { Sidebar, useSidebar };
|
|
406
|
-
//# sourceMappingURL=chunk-
|
|
407
|
-
//# sourceMappingURL=chunk-
|
|
436
|
+
//# sourceMappingURL=chunk-JY2RC6I4.js.map
|
|
437
|
+
//# sourceMappingURL=chunk-JY2RC6I4.js.map
|