@api7/ui-components 0.6.0 → 0.8.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.
Files changed (75) hide show
  1. package/README.md +170 -9
  2. package/dist/components/anchor/anchor.d.ts +28 -0
  3. package/dist/components/anchor/anchor.js +249 -0
  4. package/dist/components/breadcrumb/breadcrumb.d.ts +15 -0
  5. package/dist/components/breadcrumb/breadcrumb.js +60 -0
  6. package/dist/components/button/button.d.ts +1 -1
  7. package/dist/components/button/button.js +1 -1
  8. package/dist/components/calendar/calendar.js +24 -3
  9. package/dist/components/cascader/cascader-data.d.ts +26 -0
  10. package/dist/components/cascader/cascader-data.js +110 -0
  11. package/dist/components/cascader/cascader.d.ts +41 -0
  12. package/dist/components/cascader/cascader.js +513 -0
  13. package/dist/components/code/code.d.ts +9 -0
  14. package/dist/components/code/code.js +20 -0
  15. package/dist/components/code/copy-button.js +42 -0
  16. package/dist/components/code-block/code-block.d.ts +16 -0
  17. package/dist/components/code-block/code-block.js +45 -0
  18. package/dist/components/code-block/highlight.js +67 -0
  19. package/dist/components/collapsible/collapsible.d.ts +14 -0
  20. package/dist/components/collapsible/collapsible.js +36 -0
  21. package/dist/components/combobox/combobox-loading.d.ts +18 -0
  22. package/dist/components/combobox/combobox-loading.js +148 -0
  23. package/dist/components/combobox/combobox.d.ts +13 -6
  24. package/dist/components/combobox/combobox.js +58 -10
  25. package/dist/components/data-table/data-table.d.ts +27 -3
  26. package/dist/components/data-table/data-table.js +155 -40
  27. package/dist/components/data-table/expandable-row.js +40 -0
  28. package/dist/components/data-table/filter-header.d.ts +28 -5
  29. package/dist/components/data-table/filter-header.js +103 -40
  30. package/dist/components/data-table/index.d.ts +3 -3
  31. package/dist/components/data-table/use-table-layout.js +84 -0
  32. package/dist/components/date-picker/date-picker.js +11 -2
  33. package/dist/components/description-list/description-list.d.ts +1 -1
  34. package/dist/components/dialog/dialog.js +1 -1
  35. package/dist/components/drawer/drawer.js +1 -1
  36. package/dist/components/empty/empty.d.ts +1 -1
  37. package/dist/components/field/labeled-field.js +1 -1
  38. package/dist/components/file-upload/file-upload.d.ts +44 -0
  39. package/dist/components/file-upload/file-upload.js +195 -0
  40. package/dist/components/form/choice-fields.js +2 -2
  41. package/dist/components/form/date-fields.d.ts +1 -1
  42. package/dist/components/form/date-fields.js +1 -1
  43. package/dist/components/form/form-item.js +1 -1
  44. package/dist/components/form/form.js +1 -1
  45. package/dist/components/form/index.d.ts +2 -2
  46. package/dist/components/form/index.js +4 -4
  47. package/dist/components/form/text-field.js +2 -2
  48. package/dist/components/form/toggle-fields.d.ts +1 -1
  49. package/dist/components/form/toggle-fields.js +3 -3
  50. package/dist/components/pagination/pagination.d.ts +20 -4
  51. package/dist/components/pagination/pagination.js +83 -32
  52. package/dist/components/relative-date-range-picker/relative-date-range-picker.d.ts +14 -0
  53. package/dist/components/relative-date-range-picker/relative-date-range-picker.js +245 -0
  54. package/dist/components/relative-date-range-picker/relative-date-range.d.ts +26 -0
  55. package/dist/components/relative-date-range-picker/relative-date-range.js +109 -0
  56. package/dist/components/select/select.js +1 -1
  57. package/dist/components/sidebar/sidebar.js +2 -2
  58. package/dist/components/steps/steps.d.ts +23 -0
  59. package/dist/components/steps/steps.js +86 -0
  60. package/dist/components/table/table.d.ts +2 -1
  61. package/dist/components/table/table.js +2 -1
  62. package/dist/components/toast/toast.d.ts +1 -1
  63. package/dist/components/toast/toast.js +1 -1
  64. package/dist/config/config-provider.d.ts +2 -2
  65. package/dist/config/messages.d.ts +115 -1
  66. package/dist/config/messages.js +140 -2
  67. package/dist/hooks/use-clipboard.d.ts +11 -0
  68. package/dist/hooks/use-clipboard.js +75 -0
  69. package/dist/hooks/use-field-label-with-text.js +32 -0
  70. package/dist/index.d.ts +26 -13
  71. package/dist/index.js +15 -4
  72. package/dist/theme.css +1 -0
  73. package/dist/tokens/index.d.ts +1 -1
  74. package/dist/tokens/index.js +1 -1
  75. package/package.json +7 -6
@@ -0,0 +1,245 @@
1
+ "use client";
2
+ import { describeRelativeDateRange, normalizeRelativeTime, parseRelativeTime, resolveRelativeDateRange } from "./relative-date-range.js";
3
+ import { Button } from "../button/button.js";
4
+ import { Calendar } from "../calendar/calendar.js";
5
+ import { InputGroup, InputGroupAddon } from "../input-group/input-group.js";
6
+ import { Input } from "../input/input.js";
7
+ import { Popover, PopoverContent, PopoverTrigger } from "../popover/popover.js";
8
+ import { useMessages } from "../../config/config-provider.js";
9
+ import { useState } from "react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { CalendarIcon, SearchIcon, XIcon } from "lucide-react";
12
+ // src/components/relative-date-range-picker/relative-date-range-picker.tsx
13
+ const CALENDAR_YEARS = 5;
14
+ const pad = (n) => String(n).padStart(2, "0");
15
+ const localText = (seconds) => {
16
+ const d = /* @__PURE__ */ new Date(seconds * 1e3);
17
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
18
+ };
19
+ const zoneName = () => new Intl.DateTimeFormat().resolvedOptions().timeZone;
20
+ const zoneOffset = () => {
21
+ const minutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
22
+ return `UTC${minutes < 0 ? "-" : "+"}${pad(Math.floor(Math.abs(minutes) / 60))}:${pad(Math.abs(minutes) % 60)}`;
23
+ };
24
+ const typed = (end) => {
25
+ const read = parseRelativeTime(end);
26
+ return "error" in read || read.kind === "now" ? end : localText(read.seconds);
27
+ };
28
+ function RelativeDateRangePicker({ value, onChange, presets, maxSpanSeconds, now, className }) {
29
+ const t = useMessages().relativeDateRangePicker;
30
+ const [open, setOpen] = useState(false);
31
+ const [from, setFrom] = useState(value.from);
32
+ const [to, setTo] = useState(value.to);
33
+ const [problem, setProblem] = useState(null);
34
+ const [calendarOpen, setCalendarOpen] = useState(false);
35
+ const [anchor, setAnchor] = useState(null);
36
+ const [query, setQuery] = useState("");
37
+ const apply = (range) => {
38
+ const resolved = resolveRelativeDateRange(range, now(), maxSpanSeconds, t);
39
+ if ("error" in resolved) {
40
+ setProblem(resolved.error);
41
+ return;
42
+ }
43
+ onChange({
44
+ from: normalizeRelativeTime(range.from),
45
+ to: normalizeRelativeTime(range.to)
46
+ });
47
+ setOpen(false);
48
+ };
49
+ const show = (next) => {
50
+ if (next) {
51
+ setFrom(typed(value.from));
52
+ setTo(typed(value.to));
53
+ setProblem(null);
54
+ setCalendarOpen(false);
55
+ setAnchor(null);
56
+ setQuery("");
57
+ }
58
+ setOpen(next);
59
+ };
60
+ const edit = (end, text) => {
61
+ (end === "start" ? setFrom : setTo)(text);
62
+ setProblem(null);
63
+ };
64
+ const day = (text) => {
65
+ const read = parseRelativeTime(text);
66
+ if ("error" in read) return void 0;
67
+ return /* @__PURE__ */ new Date((read.kind === "now" ? now() - read.offsetSeconds : read.seconds) * 1e3);
68
+ };
69
+ const onDay = (end, date) => {
70
+ const read = parseRelativeTime(end === "start" ? from : to);
71
+ const clock = "error" in read || read.kind !== "absolute" ? null : /* @__PURE__ */ new Date(read.seconds * 1e3);
72
+ const edge = new Date(date);
73
+ const [h, m, sec] = clock ? [
74
+ clock.getHours(),
75
+ clock.getMinutes(),
76
+ clock.getSeconds()
77
+ ] : end === "start" ? [
78
+ 0,
79
+ 0,
80
+ 0
81
+ ] : [
82
+ 23,
83
+ 59,
84
+ 59
85
+ ];
86
+ edge.setHours(h, m, sec, 0);
87
+ return end === "end" && edge.getTime() / 1e3 > now() ? "now" : localText(edge.getTime() / 1e3);
88
+ };
89
+ const pickDay = (date) => {
90
+ const [first, last] = anchor && anchor.getTime() < date.getTime() ? [anchor, date] : anchor ? [date, anchor] : [date, date];
91
+ setFrom(onDay("start", first));
92
+ setTo(onDay("end", last));
93
+ setProblem(null);
94
+ setAnchor(anchor ? null : date);
95
+ };
96
+ const shown = presets.filter((preset) => preset.label.toLowerCase().includes(query.trim().toLowerCase()));
97
+ const current = {
98
+ from: normalizeRelativeTime(value.from),
99
+ to: normalizeRelativeTime(value.to)
100
+ };
101
+ const field = (end, label) => /* @__PURE__ */ jsxs("div", {
102
+ className: "flex flex-col gap-1.5",
103
+ children: [/* @__PURE__ */ jsx("label", {
104
+ htmlFor: `relative-date-range-${end}`,
105
+ className: "text-sm text-muted-foreground",
106
+ children: label
107
+ }), /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(Input, {
108
+ id: `relative-date-range-${end}`,
109
+ "aria-label": label,
110
+ value: end === "start" ? from : to,
111
+ placeholder: end === "start" ? "now-5m" : "now",
112
+ onValueChange: (text) => edit(end, text)
113
+ }), /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Button, {
114
+ variant: "ghost",
115
+ size: "icon",
116
+ "aria-label": calendarOpen ? t.closeCalendarFor({ label }) : t.openCalendarFor({ label }),
117
+ "aria-expanded": calendarOpen,
118
+ onClick: () => setCalendarOpen(!calendarOpen),
119
+ children: /* @__PURE__ */ jsx(CalendarIcon, {
120
+ "aria-hidden": true,
121
+ className: "size-4"
122
+ })
123
+ }) })] })]
124
+ });
125
+ return /* @__PURE__ */ jsxs(Popover, {
126
+ open,
127
+ onOpenChange: show,
128
+ children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
129
+ render: /* @__PURE__ */ jsx(Button, {
130
+ variant: "outline",
131
+ className
132
+ }),
133
+ children: [/* @__PURE__ */ jsx(CalendarIcon, {
134
+ "aria-hidden": true,
135
+ className: "size-4 shrink-0 text-muted-foreground"
136
+ }), describeRelativeDateRange(value, localText, t)]
137
+ }), /* @__PURE__ */ jsxs(PopoverContent, {
138
+ align: "end",
139
+ className: "w-auto",
140
+ children: [/* @__PURE__ */ jsxs("div", {
141
+ className: "flex flex-wrap gap-3",
142
+ children: [
143
+ calendarOpen && /* @__PURE__ */ jsxs("div", {
144
+ className: "flex shrink-0 flex-col gap-2 border-r border-border pr-3",
145
+ children: [/* @__PURE__ */ jsxs("div", {
146
+ className: "flex items-center justify-between",
147
+ children: [/* @__PURE__ */ jsx("p", {
148
+ className: "text-sm font-medium",
149
+ children: t.calendar
150
+ }), /* @__PURE__ */ jsx(Button, {
151
+ variant: "ghost",
152
+ size: "icon",
153
+ "aria-label": t.closeCalendar,
154
+ onClick: () => setCalendarOpen(false),
155
+ children: /* @__PURE__ */ jsx(XIcon, {
156
+ "aria-hidden": true,
157
+ className: "size-4"
158
+ })
159
+ })]
160
+ }), /* @__PURE__ */ jsx(Calendar, {
161
+ mode: "range",
162
+ selected: {
163
+ from: day(from),
164
+ to: day(to)
165
+ },
166
+ onDayClick: pickDay,
167
+ disabled: { after: /* @__PURE__ */ new Date(now() * 1e3) },
168
+ defaultMonth: day(to),
169
+ captionLayout: "dropdown",
170
+ startMonth: new Date((/* @__PURE__ */ new Date(now() * 1e3)).getFullYear() - CALENDAR_YEARS, 0),
171
+ endMonth: /* @__PURE__ */ new Date(now() * 1e3),
172
+ classNames: { caption_label: "[&_svg]:hidden" }
173
+ })]
174
+ }),
175
+ /* @__PURE__ */ jsxs("div", {
176
+ className: "flex w-72 shrink-0 flex-col gap-3",
177
+ children: [
178
+ /* @__PURE__ */ jsx("p", {
179
+ className: "text-sm font-medium",
180
+ children: t.absolute
181
+ }),
182
+ field("start", t.from),
183
+ field("end", t.to),
184
+ problem && /* @__PURE__ */ jsx("p", {
185
+ role: "alert",
186
+ className: "text-sm text-destructive",
187
+ children: problem
188
+ }),
189
+ /* @__PURE__ */ jsx(Button, {
190
+ className: "self-start",
191
+ onClick: () => apply({
192
+ from,
193
+ to
194
+ }),
195
+ children: t.apply
196
+ })
197
+ ]
198
+ }),
199
+ /* @__PURE__ */ jsxs("div", {
200
+ className: "flex w-56 shrink-0 flex-col gap-2 border-l border-border pl-3",
201
+ children: [/* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, {
202
+ "aria-hidden": true,
203
+ className: "size-4"
204
+ }) }), /* @__PURE__ */ jsx(Input, {
205
+ "aria-label": t.search,
206
+ placeholder: t.search,
207
+ value: query,
208
+ onValueChange: setQuery
209
+ })] }), /* @__PURE__ */ jsxs("ul", {
210
+ "aria-label": t.presets,
211
+ className: "flex max-h-64 flex-col gap-1 overflow-y-auto",
212
+ children: [shown.map((preset) => {
213
+ const selected = current.from === normalizeRelativeTime(preset.from) && current.to === normalizeRelativeTime(preset.to);
214
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
215
+ type: "button",
216
+ "aria-pressed": selected,
217
+ onClick: () => apply(preset),
218
+ className: `h-8 w-full rounded-sm px-3 text-left text-sm whitespace-nowrap outline-none hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring/40 ${selected ? "bg-accent font-medium text-primary-text" : "text-foreground"}`,
219
+ children: preset.label
220
+ }) }, preset.label);
221
+ }), shown.length === 0 && /* @__PURE__ */ jsx("li", {
222
+ className: "px-3 py-2 text-sm text-muted-foreground",
223
+ children: t.none
224
+ })]
225
+ })]
226
+ })
227
+ ]
228
+ }), /* @__PURE__ */ jsxs("div", {
229
+ className: "mt-3 flex items-center justify-between gap-3 border-t border-border pt-3 text-xs text-muted-foreground",
230
+ children: [/* @__PURE__ */ jsxs("span", { children: [
231
+ t.browserTime,
232
+ " ",
233
+ /* @__PURE__ */ jsx("span", {
234
+ className: "ml-1",
235
+ children: zoneName()
236
+ })
237
+ ] }), /* @__PURE__ */ jsx("span", {
238
+ className: "rounded-sm bg-muted px-2 py-1",
239
+ children: zoneOffset()
240
+ })]
241
+ })]
242
+ })]
243
+ });
244
+ }
245
+ export { RelativeDateRangePicker };
@@ -0,0 +1,26 @@
1
+ import { Messages } from "../../config/messages.js";
2
+ export type RelativeDateRangeMessages = Messages['relativeDateRangePicker'];
3
+ export type RelativeDateRangeValue = {
4
+ from: string;
5
+ to: string;
6
+ };
7
+ export type ParsedRelativeTime = {
8
+ kind: 'now';
9
+ offsetSeconds: number;
10
+ } | {
11
+ kind: 'absolute';
12
+ seconds: number;
13
+ };
14
+ export declare function parseRelativeTime(text: string, messages?: RelativeDateRangeMessages): ParsedRelativeTime | {
15
+ error: string;
16
+ };
17
+ export declare function normalizeRelativeTime(text: string, messages?: RelativeDateRangeMessages): string | {
18
+ error: string;
19
+ };
20
+ export declare function resolveRelativeDateRange(value: RelativeDateRangeValue, nowSeconds: number, maxSpanSeconds: number, messages?: RelativeDateRangeMessages): {
21
+ start: number;
22
+ end: number;
23
+ } | {
24
+ error: string;
25
+ };
26
+ export declare function describeRelativeDateRange(value: RelativeDateRangeValue, formatMoment: (seconds: number) => string, messages?: RelativeDateRangeMessages): string;
@@ -0,0 +1,109 @@
1
+ import { enUS } from "../../config/messages.js";
2
+ // src/components/relative-date-range-picker/relative-date-range.ts
3
+ const MIN_YEAR = 1970;
4
+ const UNIT_SECONDS = {
5
+ m: 60,
6
+ h: 3600,
7
+ d: 86400,
8
+ w: 604800
9
+ };
10
+ const FUTURE_SLACK_SECONDS = 60;
11
+ const NOW = /^now(?:\s*-\s*(\d+)\s*([mhdw]))?$/i;
12
+ const WITH_ZONE = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d))?(Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/i;
13
+ const LOCAL = /^(\d{4})-(\d\d)-(\d\d)(?:[ T](\d\d):(\d\d)(?::(\d\d))?)?$/;
14
+ function parseRelativeTime(text, messages = enUS.relativeDateRangePicker) {
15
+ const fail = () => ({ error: messages.understood });
16
+ const value = text.trim();
17
+ const now = NOW.exec(value);
18
+ if (now) {
19
+ if (now[1] === void 0) return {
20
+ kind: "now",
21
+ offsetSeconds: 0
22
+ };
23
+ const count = Number(now[1]);
24
+ return count > 0 ? {
25
+ kind: "now",
26
+ offsetSeconds: count * UNIT_SECONDS[now[2].toLowerCase()]
27
+ } : fail();
28
+ }
29
+ const zoned = WITH_ZONE.exec(value);
30
+ if (zoned) {
31
+ const [, y, mo, d, h, mi, s, zone] = zoned;
32
+ if (Number(y) < MIN_YEAR) return fail();
33
+ const calendar = Date.UTC(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s ?? 0));
34
+ const check = new Date(calendar);
35
+ if (check.getUTCMonth() !== Number(mo) - 1 || check.getUTCDate() !== Number(d) || Number(h) > 23 || Number(mi) > 59 || Number(s ?? 0) > 59) return fail();
36
+ return {
37
+ kind: "absolute",
38
+ seconds: (calendar - (zone.toUpperCase() === "Z" ? 0 : (zone[0] === "-" ? -1 : 1) * (Number(zone.slice(1, 3)) * 60 + Number(zone.slice(4, 6))) * 6e4)) / 1e3
39
+ };
40
+ }
41
+ const local = LOCAL.exec(value);
42
+ if (local) {
43
+ const [, y, mo, d, h = "0", mi = "0", s = "0"] = local;
44
+ if (Number(y) < MIN_YEAR) return fail();
45
+ const date = new Date(Number(y), Number(mo) - 1, Number(d), Number(h), Number(mi), Number(s));
46
+ if (date.getMonth() !== Number(mo) - 1 || date.getDate() !== Number(d) || Number(h) > 23 || Number(mi) > 59 || Number(s) > 59) return fail();
47
+ return {
48
+ kind: "absolute",
49
+ seconds: date.getTime() / 1e3
50
+ };
51
+ }
52
+ return fail();
53
+ }
54
+ function offsetText(seconds) {
55
+ const unit = [
56
+ "w",
57
+ "d",
58
+ "h",
59
+ "m"
60
+ ].find((one) => seconds % UNIT_SECONDS[one] === 0);
61
+ return `${seconds / UNIT_SECONDS[unit]}${unit}`;
62
+ }
63
+ const isoUtc = (seconds) => (/* @__PURE__ */ new Date(seconds * 1e3)).toISOString().replace(".000Z", "Z");
64
+ function normalizeRelativeTime(text, messages = enUS.relativeDateRangePicker) {
65
+ const read = parseRelativeTime(text, messages);
66
+ if ("error" in read) return read;
67
+ if (read.kind === "now") return read.offsetSeconds === 0 ? "now" : `now-${offsetText(read.offsetSeconds)}`;
68
+ return isoUtc(read.seconds);
69
+ }
70
+ function resolveRelativeDateRange(value, nowSeconds, maxSpanSeconds, messages = enUS.relativeDateRangePicker) {
71
+ const from = parseRelativeTime(value.from, messages);
72
+ if ("error" in from) return { error: messages.endError({
73
+ label: messages.from,
74
+ reason: from.error
75
+ }) };
76
+ const to = parseRelativeTime(value.to, messages);
77
+ if ("error" in to) return { error: messages.endError({
78
+ label: messages.to,
79
+ reason: to.error
80
+ }) };
81
+ const at = (time) => time.kind === "now" ? nowSeconds - time.offsetSeconds : time.seconds;
82
+ const start = at(from);
83
+ const end = at(to);
84
+ if (end > nowSeconds + FUTURE_SLACK_SECONDS) return { error: messages.future };
85
+ if (end <= start) return { error: messages.endBeforeStart };
86
+ if (end - start > maxSpanSeconds) return { error: messages.tooLong({ days: String(maxSpanSeconds / 86400) }) };
87
+ return {
88
+ start,
89
+ end
90
+ };
91
+ }
92
+ function describeRelativeDateRange(value, formatMoment, messages = enUS.relativeDateRangePicker) {
93
+ const from = normalizeRelativeTime(value.from, messages);
94
+ const to = normalizeRelativeTime(value.to, messages);
95
+ if (typeof from === "string" && typeof to === "string" && to === "now" && from.startsWith("now-")) {
96
+ const text = offsetText(parseRelativeTime(from, messages).offsetSeconds);
97
+ return messages.last({
98
+ count: text.slice(0, -1),
99
+ unit: text.slice(-1)
100
+ });
101
+ }
102
+ const show = (end, original) => {
103
+ if (typeof end !== "string") return original;
104
+ const read = parseRelativeTime(end, messages);
105
+ return "error" in read || read.kind === "now" ? end : formatMoment(read.seconds);
106
+ };
107
+ return `${show(from, value.from)} ~ ${show(to, value.to)}`;
108
+ }
109
+ export { describeRelativeDateRange, normalizeRelativeTime, parseRelativeTime, resolveRelativeDateRange };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { useMessages } from "../../config/config-provider.js";
3
3
  import { cn } from "../../lib/cn.js";
4
- import { listItemClassName, listboxClassName, popupLayerClassName } from "../../lib/popup.js";
5
4
  import { controlFocus, controlSurface } from "../../lib/control.js";
5
+ import { listItemClassName, listboxClassName, popupLayerClassName } from "../../lib/popup.js";
6
6
  import { createContext, useCallback, useContext, useMemo, useRef, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { cn } from "../../lib/cn.js";
3
- import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.js";
4
2
  import { Separator } from "../separator/separator.js";
3
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip/tooltip.js";
4
+ import { cn } from "../../lib/cn.js";
5
5
  import { cloneElement, useId } from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  // src/components/sidebar/sidebar.tsx
@@ -0,0 +1,23 @@
1
+ import { ComponentProps, Key, ReactNode } from "react";
2
+ export type StepsStatus = 'wait' | 'process' | 'finish' | 'error';
3
+ export interface StepsItem {
4
+ key?: Key;
5
+ title: ReactNode;
6
+ description?: ReactNode;
7
+ icon?: ReactNode;
8
+ status?: StepsStatus;
9
+ disabled?: boolean;
10
+ }
11
+ export interface StepsProps extends Omit<ComponentProps<'ol'>, 'children'> {
12
+ items: readonly StepsItem[];
13
+ /** Zero-based active step. Set to items.length to mark every step complete. */
14
+ current?: number;
15
+ /** Status of the current step. An item's status takes precedence. */
16
+ status?: StepsStatus;
17
+ orientation?: 'horizontal' | 'vertical';
18
+ /** Enables step buttons. The caller decides when to update current. */
19
+ onStepChange?: (index: number) => void;
20
+ disabled?: boolean;
21
+ }
22
+ declare function Steps({ items, current, status, orientation, onStepChange, disabled, className, ...props }: StepsProps): import("react").JSX.Element;
23
+ export { Steps };
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { useMessages } from "../../config/config-provider.js";
3
+ import { cn } from "../../lib/cn.js";
4
+ import { useId } from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { Check, X } from "lucide-react";
7
+ // src/components/steps/steps.tsx
8
+ function Steps({ items, current = 0, status = "process", orientation = "horizontal", onStepChange, disabled = false, className, ...props }) {
9
+ const messages = useMessages();
10
+ const id = useId();
11
+ const active = Number.isFinite(current) ? Math.min(items.length, Math.max(0, Math.floor(current))) : 0;
12
+ const vertical = orientation === "vertical";
13
+ return /* @__PURE__ */ jsx("ol", {
14
+ "aria-label": messages.steps.label,
15
+ role: "list",
16
+ className: cn("m-0 flex list-none p-1 text-sm", vertical && "flex-col", className),
17
+ ...props,
18
+ "data-slot": "steps",
19
+ "data-orientation": orientation,
20
+ children: items.map((item, index) => {
21
+ const itemStatus = item.status ?? (index < active ? "finish" : index === active ? status : "wait");
22
+ const isCurrent = index === active;
23
+ const isDisabled = disabled || item.disabled;
24
+ const titleId = `${id}-${index}-title`;
25
+ const statusId = `${id}-${index}-status`;
26
+ const descriptionId = `${id}-${index}-description`;
27
+ const hasDescription = item.description != null;
28
+ const contentClassName = cn("relative flex min-w-0 gap-2", vertical ? "items-start text-start" : "flex-col items-center text-center", itemStatus === "process" ? "text-primary-text" : itemStatus === "error" ? "text-destructive-text" : itemStatus === "finish" ? "text-foreground" : "text-muted-foreground");
29
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
30
+ "aria-hidden": "true",
31
+ className: cn("relative flex size-6 shrink-0 items-center justify-center rounded-full border-2 border-border bg-background text-muted-foreground [&>svg]:size-3.5", (itemStatus === "process" || itemStatus === "finish") && "border-primary-text bg-info-subtle text-primary-text", itemStatus === "process" && "ring-4 ring-info-subtle", itemStatus === "error" && "border-destructive-text bg-destructive-subtle text-destructive-text"),
32
+ "data-slot": "steps-indicator",
33
+ children: item.icon ?? (itemStatus === "finish" ? /* @__PURE__ */ jsx(Check, {}) : itemStatus === "error" ? /* @__PURE__ */ jsx(X, {}) : /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-current" }))
34
+ }), /* @__PURE__ */ jsxs("span", {
35
+ className: cn("min-w-0 break-words", vertical ? "pt-0.5" : "w-full px-2"),
36
+ children: [
37
+ /* @__PURE__ */ jsx("span", {
38
+ id: titleId,
39
+ className: cn("block", isCurrent && "font-medium"),
40
+ "data-slot": "steps-title",
41
+ children: item.title
42
+ }),
43
+ /* @__PURE__ */ jsx("span", {
44
+ id: statusId,
45
+ className: "sr-only",
46
+ children: messages.steps[itemStatus]
47
+ }),
48
+ hasDescription && /* @__PURE__ */ jsx("span", {
49
+ id: descriptionId,
50
+ className: "mt-1 block text-xs text-muted-foreground",
51
+ "data-slot": "steps-description",
52
+ children: item.description
53
+ })
54
+ ]
55
+ })] });
56
+ return /* @__PURE__ */ jsxs("li", {
57
+ className: cn("relative min-w-0", vertical ? "pb-6 last:pb-0" : "flex-1"),
58
+ "aria-current": !onStepChange && isCurrent ? "step" : void 0,
59
+ "data-slot": "steps-item",
60
+ "data-status": itemStatus,
61
+ "data-disabled": isDisabled || void 0,
62
+ children: [index < items.length - 1 && /* @__PURE__ */ jsx("span", {
63
+ "aria-hidden": "true",
64
+ className: cn("absolute bg-border", vertical ? "start-3 top-3 h-full w-0.5 -translate-x-1/2 rtl:translate-x-1/2" : "start-1/2 top-3 h-0.5 w-full -translate-y-1/2", itemStatus === "finish" && "bg-primary"),
65
+ "data-slot": "steps-separator"
66
+ }), onStepChange ? /* @__PURE__ */ jsx("button", {
67
+ type: "button",
68
+ className: cn(contentClassName, "w-full rounded-md border-0 bg-transparent p-0 outline-none enabled:cursor-pointer enabled:hover:underline focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"),
69
+ disabled: isDisabled,
70
+ "aria-current": isCurrent ? "step" : void 0,
71
+ "aria-labelledby": titleId,
72
+ "aria-describedby": [statusId, hasDescription && descriptionId].filter(Boolean).join(" "),
73
+ onClick: () => {
74
+ if (!isCurrent) onStepChange(index);
75
+ },
76
+ "data-slot": "steps-trigger",
77
+ children: content
78
+ }) : /* @__PURE__ */ jsx("div", {
79
+ className: contentClassName,
80
+ children: content
81
+ })]
82
+ }, item.key ?? index);
83
+ })
84
+ });
85
+ }
86
+ export { Steps };
@@ -2,8 +2,9 @@ import { ComponentProps } from "react";
2
2
  export type TableProps = Omit<ComponentProps<'table'>, 'className'> & {
3
3
  className?: string;
4
4
  containerClassName?: string;
5
+ containerRef?: ComponentProps<'div'>['ref'];
5
6
  };
6
- declare function Table({ className, containerClassName, ...props }: TableProps): import("react").JSX.Element;
7
+ declare function Table({ className, containerClassName, containerRef, ...props }: TableProps): import("react").JSX.Element;
7
8
  export type TableHeaderProps = Omit<ComponentProps<'thead'>, 'className'> & {
8
9
  className?: string;
9
10
  };
@@ -1,8 +1,9 @@
1
1
  import { cn } from "../../lib/cn.js";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  // src/components/table/table.tsx
4
- function Table({ className, containerClassName, ...props }) {
4
+ function Table({ className, containerClassName, containerRef, ...props }) {
5
5
  return /* @__PURE__ */ jsx("div", {
6
+ ref: containerRef,
6
7
  "data-slot": "table-container",
7
8
  className: cn("relative w-full overflow-x-auto", containerClassName),
8
9
  children: /* @__PURE__ */ jsx("table", {
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from "react";
2
- import { CircleCheck } from "lucide-react";
2
+ import "lucide-react";
3
3
  export type ToastActionOptions = React.ComponentPropsWithoutRef<'button'>;
4
4
  export interface ToastOptions {
5
5
  description?: ReactNode;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
+ import { buttonVariants } from "../button/button.js";
2
3
  import { useMessages } from "../../config/config-provider.js";
3
4
  import { cn } from "../../lib/cn.js";
4
- import { buttonVariants } from "../button/button.js";
5
5
  import { useEffect, useState, useSyncExternalStore } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { CircleAlert, CircleCheck, Info, LoaderCircle, TriangleAlert, X } from "lucide-react";
@@ -1,4 +1,4 @@
1
- import { Locale, Messages, MessagesOverride } from "./messages.js";
1
+ import { Locale, MessagesOverride, ResolvedMessages } from "./messages.js";
2
2
  import { ReactNode } from "react";
3
3
  export interface ConfigProviderProps {
4
4
  locale?: Locale;
@@ -8,5 +8,5 @@ export interface ConfigProviderProps {
8
8
  }
9
9
  /** Global configuration entry for the library; currently carries the locale and built-in message overrides used by components. */
10
10
  export declare function ConfigProvider({ locale, messages, children }: ConfigProviderProps): import("react").JSX.Element;
11
- export declare function useMessages(): Messages;
11
+ export declare function useMessages(): ResolvedMessages;
12
12
  export declare function useLocale(): Locale;