@neasg/design-system 0.4.10 → 0.4.12
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/README.md +2 -2
- package/dist/avatar-profile-popover.d.ts +34 -0
- package/dist/avatar-profile-popover.js +27 -0
- package/dist/badge.d.ts +1 -1
- package/dist/button.d.ts +1 -1
- package/dist/card.d.ts +2 -0
- package/dist/card.js +72 -3
- package/dist/command-search.d.ts +47 -2
- package/dist/command-search.js +173 -24
- package/dist/command.d.ts +2 -0
- package/dist/command.js +2 -2
- package/dist/date-input.d.ts +2 -0
- package/dist/date-input.js +44 -4
- package/dist/dialog-primitive.js +1 -1
- package/dist/draggable-tabs.d.ts +3 -0
- package/dist/draggable-tabs.js +4 -0
- package/dist/editable-table.js +2 -2
- package/dist/filter-popover.d.ts +2 -1
- package/dist/filter-popover.js +2 -2
- package/dist/guidance-tip.d.ts +26 -0
- package/dist/guidance-tip.js +162 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.js +5 -1
- package/dist/jump-target-highlight.d.ts +13 -0
- package/dist/jump-target-highlight.js +95 -0
- package/dist/layout.d.ts +27 -5
- package/dist/layout.js +128 -34
- package/dist/message-item.js +9 -10
- package/dist/notification.js +1 -1
- package/dist/page-layout.d.ts +22 -0
- package/dist/page-layout.js +38 -0
- package/dist/page-section.js +1 -1
- package/dist/popover-menu.js +2 -2
- package/dist/routing-timeline.js +1 -1
- package/dist/table-column-visibility.d.ts +3 -1
- package/dist/table-column-visibility.js +74 -27
- package/dist/table-toolbar.d.ts +2 -1
- package/dist/table-toolbar.js +7 -2
- package/dist/table.d.ts +32 -3
- package/dist/table.js +318 -29
- package/dist/tabs.d.ts +2 -1
- package/dist/tabs.js +8 -5
- package/dist/theme-switcher.d.ts +1 -1
- package/dist/theme-switcher.js +4 -6
- package/package.json +2 -2
package/dist/date-input.d.ts
CHANGED
package/dist/date-input.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { format, parse } from "date-fns";
|
|
5
5
|
import { CalendarIcon } from "lucide-react";
|
|
6
|
+
import { XIcon } from "./animated-icons/x";
|
|
6
7
|
import { Calendar } from "./calendar";
|
|
7
8
|
import { inputControlClassName } from "./input-control";
|
|
8
9
|
import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
|
|
@@ -92,8 +93,9 @@ function formatDisplayRange(range) {
|
|
|
92
93
|
}
|
|
93
94
|
const DateInput = React.forwardRef((props, ref) => {
|
|
94
95
|
var _a, _b, _c;
|
|
95
|
-
const { label, appearance = "field", description, error, invalid = false, hideLabel = false, disabled = false, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, } = props;
|
|
96
|
+
const { label, appearance = "field", description, error, invalid = false, hideLabel = false, disabled = false, clearable = false, clearLabel, minDate, maxDate, className, triggerClassName, labelClassName, descriptionClassName, errorClassName, id, } = props;
|
|
96
97
|
const [open, setOpen] = React.useState(false);
|
|
98
|
+
const [isSelectingRangeEnd, setIsSelectingRangeEnd] = React.useState(false);
|
|
97
99
|
const generatedId = React.useId();
|
|
98
100
|
const inputId = id !== null && id !== void 0 ? id : `date-input-${generatedId}`;
|
|
99
101
|
const errorId = error ? `${inputId}-error` : undefined;
|
|
@@ -109,6 +111,24 @@ const DateInput = React.forwardRef((props, ref) => {
|
|
|
109
111
|
? formatDisplayDate(selectedDate)
|
|
110
112
|
: undefined;
|
|
111
113
|
const placeholder = (_a = props.placeholder) !== null && _a !== void 0 ? _a : (isRange ? "Pick range" : "Pick a date");
|
|
114
|
+
const showClearButton = clearable && Boolean(displayValue) && !disabled;
|
|
115
|
+
const resolvedClearLabel = clearLabel !== null && clearLabel !== void 0 ? clearLabel : (isRange ? "Clear date range" : "Clear date");
|
|
116
|
+
const handleOpenChange = (nextOpen) => {
|
|
117
|
+
setOpen(nextOpen);
|
|
118
|
+
if (!nextOpen) {
|
|
119
|
+
setIsSelectingRangeEnd(false);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const handleClear = () => {
|
|
123
|
+
if (props.mode === "range") {
|
|
124
|
+
props.onValueChange({});
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
props.onValueChange("");
|
|
128
|
+
}
|
|
129
|
+
setIsSelectingRangeEnd(false);
|
|
130
|
+
setOpen(false);
|
|
131
|
+
};
|
|
112
132
|
const handleSelect = (date) => {
|
|
113
133
|
if (props.mode === "range")
|
|
114
134
|
return;
|
|
@@ -118,17 +138,37 @@ const DateInput = React.forwardRef((props, ref) => {
|
|
|
118
138
|
const handleRangeSelect = (range) => {
|
|
119
139
|
if (props.mode !== "range")
|
|
120
140
|
return;
|
|
141
|
+
if (!(range === null || range === void 0 ? void 0 : range.from)) {
|
|
142
|
+
props.onValueChange({});
|
|
143
|
+
setIsSelectingRangeEnd(false);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const rangeFrom = range.from;
|
|
147
|
+
const rangeTo = range.to;
|
|
148
|
+
const isCompletingRange = isSelectingRangeEnd || Boolean((selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) && !selectedRange.to);
|
|
149
|
+
const isSingleDayRange = rangeTo
|
|
150
|
+
? getDateTime(rangeFrom) === getDateTime(rangeTo)
|
|
151
|
+
: false;
|
|
152
|
+
if (!isCompletingRange && isSingleDayRange) {
|
|
153
|
+
props.onValueChange({ from: formatISODate(rangeFrom) });
|
|
154
|
+
setIsSelectingRangeEnd(true);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
121
157
|
props.onValueChange(formatDateRangeValue(range));
|
|
122
|
-
if (
|
|
158
|
+
if (rangeTo) {
|
|
159
|
+
setIsSelectingRangeEnd(false);
|
|
123
160
|
setOpen(false);
|
|
124
161
|
}
|
|
162
|
+
else {
|
|
163
|
+
setIsSelectingRangeEnd(true);
|
|
164
|
+
}
|
|
125
165
|
};
|
|
126
166
|
const disabledDays = (date) => isDateOutsideBounds(date, minDate, maxDate);
|
|
127
167
|
const calendarContent = (_jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: props.mode === "range" ? (_jsx(Calendar, { mode: "range", selected: selectedRange, onSelect: handleRangeSelect, disabled: disabledDays, defaultMonth: (_b = selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.from) !== null && _b !== void 0 ? _b : selectedRange === null || selectedRange === void 0 ? void 0 : selectedRange.to, numberOfMonths: (_c = props.numberOfMonths) !== null && _c !== void 0 ? _c : 2, autoFocus: true })) : (_jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: disabledDays, defaultMonth: selectedDate, autoFocus: true })) }));
|
|
128
168
|
if (appearance === "inline") {
|
|
129
|
-
return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsxs(PopoverRoot, { open: open, onOpenChange:
|
|
169
|
+
return (_jsxs("span", { className: cn("inline-flex", className), "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsxs(PopoverRoot, { open: open, onOpenChange: handleOpenChange, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn("inline-flex cursor-pointer items-baseline rounded-sm border-0 bg-transparent p-0 font-medium text-primary underline decoration-primary/40 underline-offset-4 transition-colors hover:decoration-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", !displayValue && "text-muted-foreground decoration-border", isInvalid && "text-destructive decoration-destructive", triggerClassName), children: [_jsxs("span", { className: "sr-only", children: [label, ": "] }), _jsx("span", { children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder })] }) }), calendarContent] }), showDescription ? (_jsx("span", { id: descriptionId, className: "sr-only", children: description })) : null, error ? (_jsx("span", { id: errorId, role: "alert", className: "sr-only", children: error })) : null] }));
|
|
130
170
|
}
|
|
131
|
-
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange:
|
|
171
|
+
return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange: handleOpenChange, children: [_jsxs("div", { className: "relative", children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "relative cursor-pointer pr-9 text-left", showClearButton && "pr-16", !displayValue && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: _jsx("span", { className: "block truncate", children: displayValue !== null && displayValue !== void 0 ? displayValue : placeholder }) }) }), _jsxs("span", { "aria-hidden": showClearButton ? undefined : true, className: "pointer-events-none absolute inset-y-0 right-3 flex items-center gap-2 text-muted-foreground", children: [showClearButton ? (_jsx("button", { type: "button", "aria-label": resolvedClearLabel, onClick: handleClear, className: "pointer-events-auto inline-flex h-4 w-4 cursor-pointer items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:cursor-not-allowed", children: _jsx(XIcon, { size: 14, className: "flex items-center justify-center" }) })) : null, _jsx(CalendarIcon, { "aria-hidden": "true", className: "h-4 w-4 shrink-0", strokeWidth: 2 })] })] }), calendarContent] }), showDescription ? (_jsx(FieldDescription, { id: descriptionId, className: descriptionClassName, children: description })) : null, _jsx(FieldError, { id: errorId, className: errorClassName, children: error })] }));
|
|
132
172
|
});
|
|
133
173
|
DateInput.displayName = "DateInput";
|
|
134
174
|
export { DateInput };
|
package/dist/dialog-primitive.js
CHANGED
|
@@ -9,7 +9,7 @@ const DialogRoot = DialogPrimitive.Root;
|
|
|
9
9
|
const DialogTrigger = DialogPrimitive.Trigger;
|
|
10
10
|
const DialogPortal = DialogPrimitive.Portal;
|
|
11
11
|
const DialogClose = DialogPrimitive.Close;
|
|
12
|
-
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
|
|
12
|
+
const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, "data-slot": "dialog-overlay", className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
|
|
13
13
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
14
14
|
const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-3 border bg-background p-4 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-overlay", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-control text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
|
|
15
15
|
DialogSurface.displayName = DialogPrimitive.Content.displayName;
|
package/dist/draggable-tabs.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type BadgeProps } from "./badge";
|
|
3
|
+
import { type GuidanceTipProps } from "./guidance-tip";
|
|
3
4
|
import { type TooltipProps } from "./tooltip";
|
|
4
5
|
export interface DraggableTabBadge {
|
|
5
6
|
label: React.ReactNode;
|
|
6
7
|
variant?: BadgeProps["variant"];
|
|
7
8
|
bordered?: BadgeProps["bordered"];
|
|
8
9
|
}
|
|
10
|
+
export type DraggableTabGuidance = Omit<GuidanceTipProps, "trigger">;
|
|
9
11
|
export interface DraggableTabItem {
|
|
10
12
|
id: string;
|
|
11
13
|
label: React.ReactNode;
|
|
@@ -17,6 +19,7 @@ export interface DraggableTabItem {
|
|
|
17
19
|
tooltip?: React.ReactNode;
|
|
18
20
|
tooltipContentClassName?: string;
|
|
19
21
|
tooltipSide?: TooltipProps["side"];
|
|
22
|
+
guidance?: DraggableTabGuidance;
|
|
20
23
|
onSelect?: () => void;
|
|
21
24
|
onClose?: () => void;
|
|
22
25
|
className?: string;
|
package/dist/draggable-tabs.js
CHANGED
|
@@ -5,6 +5,7 @@ import { SortableContext, horizontalListSortingStrategy, sortableKeyboardCoordin
|
|
|
5
5
|
import { CSS } from "@dnd-kit/utilities";
|
|
6
6
|
import { XIcon } from "./animated-icons/x";
|
|
7
7
|
import { Badge } from "./badge";
|
|
8
|
+
import { GuidanceTip } from "./guidance-tip";
|
|
8
9
|
import { cn } from "./lib/utils";
|
|
9
10
|
import { Tooltip } from "./tooltip";
|
|
10
11
|
function TabButton({ item, dragHandleProps, }) {
|
|
@@ -26,6 +27,9 @@ function TabButton({ item, dragHandleProps, }) {
|
|
|
26
27
|
event.stopPropagation();
|
|
27
28
|
(_a = item.onClose) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
28
29
|
}, className: cn("cursor-pointer rounded p-1 text-muted-foreground hover:text-foreground", item.closeButtonClassName), "aria-label": "Close tab", children: _jsx(XIcon, { size: 12 }) })) : null] }));
|
|
30
|
+
if (item.guidance) {
|
|
31
|
+
return _jsx(GuidanceTip, { ...item.guidance, trigger: content });
|
|
32
|
+
}
|
|
29
33
|
if (!item.tooltip) {
|
|
30
34
|
return content;
|
|
31
35
|
}
|
package/dist/editable-table.js
CHANGED
|
@@ -33,7 +33,7 @@ function setNestedValue(obj, path, value) {
|
|
|
33
33
|
current[parts[parts.length - 1]] = value;
|
|
34
34
|
return result;
|
|
35
35
|
}
|
|
36
|
-
function EditableTable({ value, onChange, columns, isEditing = false, className, emptyPlaceholder = "Enter text
|
|
36
|
+
function EditableTable({ value, onChange, columns, isEditing = false, className, emptyPlaceholder = "Enter text", checkable = false, checkableHeader, activeField = "active", addRowLabel = "Add Row", renderRowActions, }) {
|
|
37
37
|
const [editingCell, setEditingCell] = React.useState(null);
|
|
38
38
|
const [editValue, setEditValue] = React.useState("");
|
|
39
39
|
const inputRef = React.useRef(null);
|
|
@@ -130,7 +130,7 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
|
|
|
130
130
|
const isEmptyCell = isEmptyCellValue(cellValue);
|
|
131
131
|
const isEditingCell = (editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
|
|
132
132
|
(editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === column.path;
|
|
133
|
-
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), width: column.width, minWidth: getColumnMinWidth(column), maxWidth: getColumnMaxWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (
|
|
133
|
+
return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), width: column.width, minWidth: getColumnMinWidth(column), maxWidth: getColumnMaxWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsxs("div", { className: "relative min-h-8 min-w-0", children: [_jsx("span", { "aria-hidden": "true", className: "block min-h-8 whitespace-normal break-words opacity-0", style: { maxWidth: getColumnMaxWidth(column) }, children: editValue || emptyPlaceholder }), _jsx(InputControl, { ref: inputRef, value: editValue, placeholder: emptyPlaceholder, onChange: (event) => setEditValue(event.target.value), onClick: (event) => event.stopPropagation(), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "absolute inset-x-0 top-0 h-8 w-full px-2 py-1 text-sm" })] })) : (_jsx("span", { className: cn("flex min-h-8 items-center whitespace-normal break-words", isEmptyCell
|
|
134
134
|
? "text-muted-foreground"
|
|
135
135
|
: undefined), style: { maxWidth: getColumnMaxWidth(column) }, children: isEmptyCell && isEditing
|
|
136
136
|
? emptyPlaceholder
|
package/dist/filter-popover.d.ts
CHANGED
|
@@ -30,8 +30,9 @@ export interface FilterPopoverProps extends Pick<PopoverProps, "align" | "defaul
|
|
|
30
30
|
emptyLabel?: React.ReactNode;
|
|
31
31
|
onReset?: () => void;
|
|
32
32
|
contentClassName?: string;
|
|
33
|
+
viewClassName?: string;
|
|
33
34
|
maxHeight?: string;
|
|
34
35
|
}
|
|
35
36
|
declare function getFilterSelectionLabel(count: number): string;
|
|
36
|
-
declare function FilterPopover({ align, contentClassName, defaultOpen, emptyLabel, groupListLabel, groups, maxHeight, modal, onOpenChange, onReset, open, resetLabel, selectedCount, side, trigger, triggerLabel, }: FilterPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
declare function FilterPopover({ align, contentClassName, defaultOpen, emptyLabel, groupListLabel, groups, maxHeight, modal, onOpenChange, onReset, open, resetLabel, selectedCount, side, trigger, triggerLabel, viewClassName, }: FilterPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
37
38
|
export { FilterPopover, getFilterSelectionLabel };
|
package/dist/filter-popover.js
CHANGED
|
@@ -32,7 +32,7 @@ function getFilterSelectionLabel(count) {
|
|
|
32
32
|
}
|
|
33
33
|
return count === 1 ? "1 selected" : `${count} selected`;
|
|
34
34
|
}
|
|
35
|
-
function FilterPopover({ align = "start", contentClassName, defaultOpen, emptyLabel = "No options found.", groupListLabel = "Filter by", groups, maxHeight = "max-h-80", modal, onOpenChange, onReset, open, resetLabel = "Reset filters", selectedCount, side, trigger, triggerLabel = "Filters", }) {
|
|
35
|
+
function FilterPopover({ align = "start", contentClassName, defaultOpen, emptyLabel = "No options found.", groupListLabel = "Filter by", groups, maxHeight = "max-h-80", modal, onOpenChange, onReset, open, resetLabel = "Reset filters", selectedCount, side, trigger, triggerLabel = "Filters", viewClassName, }) {
|
|
36
36
|
var _a, _b, _c, _d, _e;
|
|
37
37
|
const [activeGroupId, setActiveGroupId] = React.useState(null);
|
|
38
38
|
const [transitionDirection, setTransitionDirection] = React.useState("forward");
|
|
@@ -63,7 +63,7 @@ function FilterPopover({ align = "start", contentClassName, defaultOpen, emptyLa
|
|
|
63
63
|
setActiveGroupId(null);
|
|
64
64
|
};
|
|
65
65
|
const defaultTrigger = (_jsxs(Button, { type: "button", variant: "outline", children: [_jsx(SlidersHorizontal, { className: "h-4 w-4" }), triggerLabel, resolvedSelectedCount > 0 ? (_jsx(CountBadge, { count: resolvedSelectedCount, size: "sm" })) : null] }));
|
|
66
|
-
return (_jsxs(Popover, { align: align, contentClassName: cn("w-[360px]", contentClassName), defaultOpen: defaultOpen, modal: modal, onOpenChange: onOpenChange, open: open, side: side, surface: "menu", trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, children: [_jsx(PopoverMenuView, { className: "-mx-1 -mt-1 px-1 pt-1", direction: transitionDirection, viewKey: activeGroup ? `group-${activeGroup.id}` : "filter-groups", children: activeGroup ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "-mx-1 -mt-1 border-b p-1", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: showFilterGroups, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), activeGroup.label] }) }), activeGroup.searchable ? (_jsx(PopoverMenuSearch, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: (_c = activeGroup.searchPlaceholder) !== null && _c !== void 0 ? _c : `Search ${getGroupLabel(activeGroup).toLowerCase()}...`, "aria-label": (_d = activeGroup.searchPlaceholder) !== null && _d !== void 0 ? _d : `Search ${getGroupLabel(activeGroup).toLowerCase()}` })) : null, _jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsx(PopoverMenuSection, { children: filteredOptions.length ? (filteredOptions.map((option) => (_jsx(PopoverMenuItem, { active: option.selected, "aria-label": option.ariaLabel, "aria-pressed": option.selected, disabled: option.disabled, onClick: option.onSelect, children: option.label }, option.id)))) : (_jsx(Typography, { as: "p", variant: "caption", className: "px-2 py-2", children: (_e = activeGroup.emptyLabel) !== null && _e !== void 0 ? _e : emptyLabel })) }) })] })) : (_jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: groupListLabel }), _jsx(PopoverMenuSection, { children: groups.map((group) => {
|
|
66
|
+
return (_jsxs(Popover, { align: align, contentClassName: cn("w-[360px]", contentClassName), defaultOpen: defaultOpen, modal: modal, onOpenChange: onOpenChange, open: open, side: side, surface: "menu", trigger: trigger !== null && trigger !== void 0 ? trigger : defaultTrigger, children: [_jsx(PopoverMenuView, { className: cn("-mx-1 -mt-1 px-1 pt-1", viewClassName), direction: transitionDirection, viewKey: activeGroup ? `group-${activeGroup.id}` : "filter-groups", children: activeGroup ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "-mx-1 -mt-1 border-b p-1", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: showFilterGroups, children: [_jsx(ChevronLeft, { className: "h-4 w-4" }), activeGroup.label] }) }), activeGroup.searchable ? (_jsx(PopoverMenuSearch, { value: query, onChange: (event) => setQuery(event.target.value), placeholder: (_c = activeGroup.searchPlaceholder) !== null && _c !== void 0 ? _c : `Search ${getGroupLabel(activeGroup).toLowerCase()}...`, "aria-label": (_d = activeGroup.searchPlaceholder) !== null && _d !== void 0 ? _d : `Search ${getGroupLabel(activeGroup).toLowerCase()}` })) : null, _jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsx(PopoverMenuSection, { children: filteredOptions.length ? (filteredOptions.map((option) => (_jsx(PopoverMenuItem, { active: option.selected, "aria-label": option.ariaLabel, "aria-pressed": option.selected, disabled: option.disabled, onClick: option.onSelect, children: option.label }, option.id)))) : (_jsx(Typography, { as: "p", variant: "caption", className: "px-2 py-2", children: (_e = activeGroup.emptyLabel) !== null && _e !== void 0 ? _e : emptyLabel })) }) })] })) : (_jsx(PopoverMenuScrollArea, { maxHeight: maxHeight, children: _jsxs(PopoverMenuGroup, { children: [_jsx(PopoverMenuGroupLabel, { children: groupListLabel }), _jsx(PopoverMenuSection, { children: groups.map((group) => {
|
|
67
67
|
var _a;
|
|
68
68
|
const groupSelectedCount = getGroupSelectedCount(group);
|
|
69
69
|
const selectionLabel = (_a = group.selectionLabel) !== null && _a !== void 0 ? _a : getFilterSelectionLabel(groupSelectedCount);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type ButtonProps } from "./button";
|
|
3
|
+
import { type PopoverProps } from "./popover";
|
|
4
|
+
export interface GuidanceTipAction {
|
|
5
|
+
label?: React.ReactNode;
|
|
6
|
+
onClick?: ButtonProps["onClick"];
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
loading?: boolean;
|
|
9
|
+
loadingText?: React.ReactNode;
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface GuidanceTipProps extends Omit<PopoverProps, "children" | "contentClassName" | "surface" | "title"> {
|
|
13
|
+
title: React.ReactNode;
|
|
14
|
+
description: React.ReactNode;
|
|
15
|
+
step?: number;
|
|
16
|
+
totalSteps?: number;
|
|
17
|
+
stepLabel?: React.ReactNode;
|
|
18
|
+
previousAction?: GuidanceTipAction;
|
|
19
|
+
nextAction?: GuidanceTipAction;
|
|
20
|
+
dismissAction?: GuidanceTipAction;
|
|
21
|
+
highlightTrigger?: boolean;
|
|
22
|
+
focusOverlay?: boolean;
|
|
23
|
+
contentClassName?: string;
|
|
24
|
+
}
|
|
25
|
+
declare function GuidanceTip({ title, description, step, totalSteps, stepLabel, previousAction, nextAction, dismissAction, highlightTrigger, focusOverlay, contentClassName, trigger, open, defaultOpen, onOpenChange, align, side, sideOffset, onKeyDown, ...popoverProps }: GuidanceTipProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
export { GuidanceTip };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
import { cn } from "./lib/utils";
|
|
8
|
+
import { Popover } from "./popover";
|
|
9
|
+
const triggerHighlightClassName = "rounded-control ring-[calc(var(--space-1)/2)] ring-[hsl(var(--ring))] ring-offset-background [--tw-ring-offset-width:var(--space-1)] shadow-[0_0_var(--space-10)_hsl(var(--ring)/0.55)]";
|
|
10
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;
|
|
11
|
+
function setRef(ref, value) {
|
|
12
|
+
if (!ref) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (typeof ref === "function") {
|
|
16
|
+
ref(value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
ref.current = value;
|
|
20
|
+
}
|
|
21
|
+
function composeRefs(...refs) {
|
|
22
|
+
return (value) => {
|
|
23
|
+
refs.forEach((ref) => setRef(ref, value));
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function getStepLabel({ stepLabel, step, totalSteps, }) {
|
|
27
|
+
if (stepLabel !== undefined) {
|
|
28
|
+
return stepLabel;
|
|
29
|
+
}
|
|
30
|
+
if (typeof step === "number" && typeof totalSteps === "number") {
|
|
31
|
+
return `Step ${step} of ${totalSteps}`;
|
|
32
|
+
}
|
|
33
|
+
if (typeof step === "number") {
|
|
34
|
+
return `Step ${step}`;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function isDoneActionLabel(label) {
|
|
39
|
+
return typeof label === "string" && label.trim().toLowerCase() === "done";
|
|
40
|
+
}
|
|
41
|
+
function isEditableKeyboardTarget(target) {
|
|
42
|
+
if (!(target instanceof HTMLElement)) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return (target.isContentEditable ||
|
|
46
|
+
target.matches("input, select, textarea, [role='textbox']"));
|
|
47
|
+
}
|
|
48
|
+
function canClickActionButton(button) {
|
|
49
|
+
return !(!button ||
|
|
50
|
+
button.disabled ||
|
|
51
|
+
button.getAttribute("aria-disabled") === "true");
|
|
52
|
+
}
|
|
53
|
+
function getGuidanceTrigger({ trigger, highlightTrigger, triggerRef, }) {
|
|
54
|
+
if (!highlightTrigger || !React.isValidElement(trigger)) {
|
|
55
|
+
return trigger;
|
|
56
|
+
}
|
|
57
|
+
const triggerElement = trigger;
|
|
58
|
+
return React.cloneElement(triggerElement, {
|
|
59
|
+
"data-guidance-highlight": "true",
|
|
60
|
+
ref: composeRefs(triggerElement.ref, triggerRef),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function GuidanceTriggerHighlight({ enabled, focusOverlay, targetRef, }) {
|
|
64
|
+
var _a, _b;
|
|
65
|
+
const [rect, setRect] = React.useState(null);
|
|
66
|
+
const updateRect = React.useCallback(() => {
|
|
67
|
+
const element = targetRef.current;
|
|
68
|
+
setRect(element && enabled ? element.getBoundingClientRect() : null);
|
|
69
|
+
}, [enabled, targetRef]);
|
|
70
|
+
useIsomorphicLayoutEffect(() => {
|
|
71
|
+
var _a;
|
|
72
|
+
if (!enabled) {
|
|
73
|
+
setRect(null);
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const element = targetRef.current;
|
|
77
|
+
if (!element) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
const ownerWindow = (_a = element.ownerDocument.defaultView) !== null && _a !== void 0 ? _a : window;
|
|
81
|
+
let frame = 0;
|
|
82
|
+
const requestUpdate = () => {
|
|
83
|
+
ownerWindow.cancelAnimationFrame(frame);
|
|
84
|
+
frame = ownerWindow.requestAnimationFrame(updateRect);
|
|
85
|
+
};
|
|
86
|
+
const resizeObserver = typeof ResizeObserver === "undefined"
|
|
87
|
+
? null
|
|
88
|
+
: new ResizeObserver(requestUpdate);
|
|
89
|
+
updateRect();
|
|
90
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.observe(element);
|
|
91
|
+
ownerWindow.addEventListener("resize", requestUpdate);
|
|
92
|
+
ownerWindow.addEventListener("scroll", requestUpdate, true);
|
|
93
|
+
return () => {
|
|
94
|
+
ownerWindow.cancelAnimationFrame(frame);
|
|
95
|
+
resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
|
|
96
|
+
ownerWindow.removeEventListener("resize", requestUpdate);
|
|
97
|
+
ownerWindow.removeEventListener("scroll", requestUpdate, true);
|
|
98
|
+
};
|
|
99
|
+
}, [enabled, targetRef, updateRect]);
|
|
100
|
+
if (!enabled || !rect || typeof document === "undefined") {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const ownerDocument = (_b = (_a = targetRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) !== null && _b !== void 0 ? _b : document;
|
|
104
|
+
return createPortal(_jsx("div", { "aria-hidden": "true", "data-guidance-highlight-overlay": "true", className: cn("pointer-events-none fixed z-40", triggerHighlightClassName), style: {
|
|
105
|
+
left: rect.left,
|
|
106
|
+
top: rect.top,
|
|
107
|
+
width: rect.width,
|
|
108
|
+
height: rect.height,
|
|
109
|
+
boxShadow: focusOverlay
|
|
110
|
+
? "0 0 0 9999px rgb(0 0 0 / 0.8), 0 0 var(--space-10) hsl(var(--ring) / 0.55)"
|
|
111
|
+
: "0 0 var(--space-10) hsl(var(--ring) / 0.55)",
|
|
112
|
+
} }), ownerDocument.body);
|
|
113
|
+
}
|
|
114
|
+
function GuidanceTip({ title, description, step, totalSteps, stepLabel, previousAction, nextAction, dismissAction, highlightTrigger = true, focusOverlay = false, contentClassName, trigger, open, defaultOpen, onOpenChange, align = "start", side = "bottom", sideOffset = 0, onKeyDown, ...popoverProps }) {
|
|
115
|
+
var _a, _b, _c;
|
|
116
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen !== null && defaultOpen !== void 0 ? defaultOpen : false);
|
|
117
|
+
const previousButtonRef = React.useRef(null);
|
|
118
|
+
const nextButtonRef = React.useRef(null);
|
|
119
|
+
const triggerHighlightRef = React.useRef(null);
|
|
120
|
+
const isControlled = open !== undefined;
|
|
121
|
+
const isOpen = isControlled ? open : internalOpen;
|
|
122
|
+
const resolvedStepLabel = getStepLabel({ stepLabel, step, totalSteps });
|
|
123
|
+
const showActions = Boolean(previousAction || nextAction || dismissAction);
|
|
124
|
+
const isFinalStep = typeof step === "number" &&
|
|
125
|
+
typeof totalSteps === "number" &&
|
|
126
|
+
step >= totalSteps;
|
|
127
|
+
const showNextActionIcon = !isFinalStep && !isDoneActionLabel(nextAction === null || nextAction === void 0 ? void 0 : nextAction.label);
|
|
128
|
+
const resolvedTrigger = getGuidanceTrigger({
|
|
129
|
+
trigger,
|
|
130
|
+
highlightTrigger: highlightTrigger && isOpen,
|
|
131
|
+
triggerRef: triggerHighlightRef,
|
|
132
|
+
});
|
|
133
|
+
const handleOpenChange = React.useCallback((nextOpen) => {
|
|
134
|
+
if (!isControlled) {
|
|
135
|
+
setInternalOpen(nextOpen);
|
|
136
|
+
}
|
|
137
|
+
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen);
|
|
138
|
+
}, [isControlled, onOpenChange]);
|
|
139
|
+
const handleKeyDown = React.useCallback((event) => {
|
|
140
|
+
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
|
|
141
|
+
if (event.defaultPrevented ||
|
|
142
|
+
event.altKey ||
|
|
143
|
+
event.ctrlKey ||
|
|
144
|
+
event.metaKey ||
|
|
145
|
+
isEditableKeyboardTarget(event.target)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const actionButton = event.key === "ArrowRight"
|
|
152
|
+
? nextButtonRef.current
|
|
153
|
+
: previousButtonRef.current;
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
event.stopPropagation();
|
|
156
|
+
if (canClickActionButton(actionButton)) {
|
|
157
|
+
actionButton.click();
|
|
158
|
+
}
|
|
159
|
+
}, [onKeyDown]);
|
|
160
|
+
return (_jsxs(_Fragment, { children: [_jsx(Popover, { open: isOpen, onOpenChange: handleOpenChange, trigger: resolvedTrigger, align: align, side: side, sideOffset: sideOffset, onKeyDown: handleKeyDown, contentClassName: cn("w-[calc(var(--space-12)*6)] max-w-[calc(100vw-var(--space-8))] p-[var(--space-3)]", "data-[side=bottom]:mt-[var(--space-3)] data-[side=left]:mr-[var(--space-3)] data-[side=right]:ml-[var(--space-3)] data-[side=top]:mb-[var(--space-3)]", contentClassName), ...popoverProps, children: _jsxs("div", { className: "space-y-[var(--space-2)]", children: [_jsxs("div", { className: "space-y-[var(--space-1)]", children: [resolvedStepLabel ? (_jsx("p", { className: "text-xs font-medium text-muted-foreground", children: resolvedStepLabel })) : null, _jsx("p", { className: "text-sm font-medium text-foreground", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: description })] }), showActions ? (_jsxs("div", { className: cn("flex items-center gap-[var(--space-2)] pt-[var(--space-1)]", previousAction || dismissAction ? "justify-between" : "justify-end"), children: [previousAction || dismissAction ? (_jsxs("div", { className: "flex items-center gap-[var(--space-2)]", children: [dismissAction ? (_jsx(Button, { type: "button", variant: "ghost", size: "compact", onClick: dismissAction.onClick, disabled: dismissAction.disabled, loading: dismissAction.loading, loadingText: dismissAction.loadingText, "aria-label": dismissAction.ariaLabel, children: (_a = dismissAction.label) !== null && _a !== void 0 ? _a : "Skip" })) : null, previousAction ? (_jsxs(Button, { ref: previousButtonRef, type: "button", variant: "secondary", size: "compact", onClick: previousAction.onClick, disabled: previousAction.disabled, loading: previousAction.loading, loadingText: previousAction.loadingText, "aria-label": previousAction.ariaLabel, children: [_jsx(ChevronLeft, { className: "h-[var(--space-4)] w-[var(--space-4)]" }), (_b = previousAction.label) !== null && _b !== void 0 ? _b : "Previous"] })) : null] })) : null, nextAction ? (_jsxs(Button, { ref: nextButtonRef, type: "button", size: "compact", onClick: nextAction.onClick, disabled: nextAction.disabled, loading: nextAction.loading, loadingText: nextAction.loadingText, "aria-label": nextAction.ariaLabel, children: [(_c = nextAction.label) !== null && _c !== void 0 ? _c : "Next", showNextActionIcon ? (_jsx(ChevronRight, { className: "h-[var(--space-4)] w-[var(--space-4)]" })) : null] })) : null] })) : null] }) }), _jsx(GuidanceTriggerHighlight, { enabled: highlightTrigger && isOpen, focusOverlay: focusOverlay, targetRef: triggerHighlightRef })] }));
|
|
161
|
+
}
|
|
162
|
+
export { GuidanceTip };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, } from "./avatar";
|
|
2
2
|
export type { AvatarProps, AvatarSize, AvatarProfileProps, AvatarRootProps, } from "./avatar";
|
|
3
|
+
export { AvatarProfilePopover, AvatarProfilePopoverContent, AvatarProfilePopoverHeader, AvatarProfilePopoverSection, AvatarProfilePopoverFooter, AvatarProfilePopoverFooterAction, } from "./avatar-profile-popover";
|
|
4
|
+
export type { AvatarProfilePopoverProps, AvatarProfilePopoverContentProps, AvatarProfilePopoverHeaderProps, AvatarProfilePopoverSectionProps, AvatarProfilePopoverFooterProps, AvatarProfilePopoverFooterActionProps, } from "./avatar-profile-popover";
|
|
3
5
|
export * from "./animated-icons";
|
|
4
6
|
export { Alert, AlertAction, AlertConsent, alertVariants } from "./alert";
|
|
5
7
|
export type { AlertActionProps, AlertConsentProps, AlertProps } from "./alert";
|
|
@@ -63,7 +65,7 @@ export type { LinkProps } from "./link";
|
|
|
63
65
|
export { Dialog } from "./dialog";
|
|
64
66
|
export type { DialogAction, DialogProps } from "./dialog";
|
|
65
67
|
export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut, } from "./command";
|
|
66
|
-
export { CommandSearch, type CommandSearchFilter, type CommandSearchItem, type CommandSearchProps, type CommandSearchSection, type CommandSearchShowAllResultsLabel, } from "./command-search";
|
|
68
|
+
export { CommandSearch, type CommandSearchFilter, type CommandSearchFilterSelectDetails, type CommandSearchItem, type CommandSearchItemDetail, type CommandSearchProps, type CommandSearchSection, type CommandSearchSectionAction, type CommandSearchShowAllResultsLabel, type CommandSearchShortcutPlatform, } from "./command-search";
|
|
67
69
|
export { FileUpload } from "./file-upload";
|
|
68
70
|
export type { FileUploadProps } from "./file-upload";
|
|
69
71
|
export { FileUploadStatusToast, showFileUploadStatusToast, } from "./file-upload-status-toast";
|
|
@@ -90,8 +92,12 @@ export { SectionNav } from "./section-nav";
|
|
|
90
92
|
export type { SectionNavItem, SectionNavProps } from "./section-nav";
|
|
91
93
|
export { GovtMasthead } from "./govt-masthead";
|
|
92
94
|
export type { GovtMastheadProps } from "./govt-masthead";
|
|
95
|
+
export { GuidanceTip } from "./guidance-tip";
|
|
96
|
+
export type { GuidanceTipAction, GuidanceTipProps } from "./guidance-tip";
|
|
93
97
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
94
98
|
export type { SearchHighlightProps, SearchHighlightSegment, } from "./use-search-highlight";
|
|
99
|
+
export { clearJumpTargetHighlights, highlightJumpTarget, jumpTargetHighlightAttribute, jumpTargetHighlightClassName, jumpTargetHighlightDurationMs, jumpTargetHighlightIterations, jumpTargetHighlightSelector, } from "./jump-target-highlight";
|
|
100
|
+
export type { HighlightJumpTargetOptions, JumpTargetHighlightRoot, } from "./jump-target-highlight";
|
|
95
101
|
export { useErrorShake } from "./use-error-shake";
|
|
96
102
|
export type { UseErrorShakeOptions } from "./use-error-shake";
|
|
97
103
|
export { useStickySentinel } from "./use-sticky-sentinel";
|
|
@@ -100,12 +106,14 @@ export { useViewportThreshold } from "./use-viewport-threshold";
|
|
|
100
106
|
export type { UseViewportThresholdOptions, UseViewportThresholdReturn, } from "./use-viewport-threshold";
|
|
101
107
|
export { Textarea } from "./textarea";
|
|
102
108
|
export type { TextareaProps } from "./textarea";
|
|
103
|
-
export { DraggableTabs, type DraggableTabBadge, type DraggableTabItem, type DraggableTabsProps, } from "./draggable-tabs";
|
|
109
|
+
export { DraggableTabs, type DraggableTabBadge, type DraggableTabGuidance, type DraggableTabItem, type DraggableTabsProps, } from "./draggable-tabs";
|
|
104
110
|
export { Drawer, } from "./drawer";
|
|
105
111
|
export type { DrawerAction, DrawerProps, DrawerSide } from "./drawer";
|
|
106
|
-
export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, SidebarProvider, useSidebar, } from "./layout";
|
|
107
|
-
export type { DashboardContentProps, DashboardLayoutProps, DashboardRightPanelBodyProps, DashboardRightPanelHeaderProps, DashboardRightPanelMode, DashboardRightPanelProps, DashboardRightPanelSectionProps, DashboardRightPanelTabsProps, DashboardSidebarNavDropdownItem, DashboardSidebarNavGroup, DashboardSidebarNavItem, DashboardSidebarNavLinkItem, DashboardSidebarProfileProps, } from "./layout";
|
|
112
|
+
export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
|
|
113
|
+
export type { DashboardContentProps, DashboardLayoutProps, DashboardRightPanelBodyProps, DashboardRightPanelHeaderProps, DashboardRightPanelMode, DashboardRightPanelProps, DashboardRightPanelSectionProps, DashboardRightPanelTabsProps, DashboardSidebarNavDropdownItem, DashboardSidebarNavGroup, DashboardSidebarNavItem, DashboardSidebarNavLinkItem, DashboardSidebarProfileProps, DashboardSidebarProfilePopoverProps, } from "./layout";
|
|
108
114
|
export { PageHeader } from "./page-header";
|
|
115
|
+
export { PageLayout, PageLayoutContext, PageLayoutControls, PageLayoutHeader, PageLayoutSection, PageLayoutStack, PageLayoutTitle, pageLayoutGapClassNames, pageLayoutStackGapClassNames, } from "./page-layout";
|
|
116
|
+
export type { PageLayoutGap, PageLayoutProps, PageLayoutStackGap, PageLayoutStackProps, PageLayoutTitleProps, } from "./page-layout";
|
|
109
117
|
export { WorkspaceHeader } from "./workspace-header";
|
|
110
118
|
export type { WorkspaceHeaderProps } from "./workspace-header";
|
|
111
119
|
export { PageSection, PageSectionGroup } from "./page-section";
|
|
@@ -123,7 +131,7 @@ export type { TableColumnVisibilityMenuProps } from "./table-column-visibility";
|
|
|
123
131
|
export { useTableSort } from "./use-table-sort";
|
|
124
132
|
export type { UseTableSortOptions, UseTableSortReturn, } from "./use-table-sort";
|
|
125
133
|
export { Table, TableRoot, TableContainer, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, TableRowSkeleton, TABLE_SKELETON_PRESETS, } from "./table";
|
|
126
|
-
export type { TableColumn, TableProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
134
|
+
export type { TableColumn, TableColumnWidths, TableProps, TableRowTone, TableSortDirection, TableSortingProps, TableSkeletonConfig, TableRowSkeletonProps, } from "./table";
|
|
127
135
|
export { Tabs, TabsRoot, TabWithDropdown, type TabsItem, type TabsItemLabel, type TabsItemLabelProps, type TabsProps, TabsList, TabsTrigger, TabsContent, type TabWithDropdownProps, useTabsContext, type TabDropdownSection, } from "./tabs";
|
|
128
136
|
export { Tooltip, TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider, type TooltipProps, } from "./tooltip";
|
|
129
137
|
export { Toaster, toast } from "./toaster";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, } from "./avatar";
|
|
2
|
+
export { AvatarProfilePopover, AvatarProfilePopoverContent, AvatarProfilePopoverHeader, AvatarProfilePopoverSection, AvatarProfilePopoverFooter, AvatarProfilePopoverFooterAction, } from "./avatar-profile-popover";
|
|
2
3
|
export * from "./animated-icons";
|
|
3
4
|
export { Alert, AlertAction, AlertConsent, alertVariants } from "./alert";
|
|
4
5
|
export { Badge, badgeVariants } from "./badge";
|
|
@@ -46,15 +47,18 @@ export { PopoverMenuContent, PopoverMenuCheckboxItem, PopoverMenuHeader, Popover
|
|
|
46
47
|
export { SearchInput } from "./search-input";
|
|
47
48
|
export { SectionNav } from "./section-nav";
|
|
48
49
|
export { GovtMasthead } from "./govt-masthead";
|
|
50
|
+
export { GuidanceTip } from "./guidance-tip";
|
|
49
51
|
export { SearchHighlight, useSearchHighlight, } from "./use-search-highlight";
|
|
52
|
+
export { clearJumpTargetHighlights, highlightJumpTarget, jumpTargetHighlightAttribute, jumpTargetHighlightClassName, jumpTargetHighlightDurationMs, jumpTargetHighlightIterations, jumpTargetHighlightSelector, } from "./jump-target-highlight";
|
|
50
53
|
export { useErrorShake } from "./use-error-shake";
|
|
51
54
|
export { useStickySentinel } from "./use-sticky-sentinel";
|
|
52
55
|
export { useViewportThreshold } from "./use-viewport-threshold";
|
|
53
56
|
export { Textarea } from "./textarea";
|
|
54
57
|
export { DraggableTabs, } from "./draggable-tabs";
|
|
55
58
|
export { Drawer, } from "./drawer";
|
|
56
|
-
export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, SidebarProvider, useSidebar, } from "./layout";
|
|
59
|
+
export { DashboardContent, DashboardLayout, DashboardRightPanel, DashboardRightPanelBody, DashboardRightPanelHeader, DashboardRightPanelSection, DashboardRightPanelTabs, DashboardSidebar, DashboardSidebarProfile, DashboardSidebarProfilePopover, SidebarProvider, useSidebar, } from "./layout";
|
|
57
60
|
export { PageHeader } from "./page-header";
|
|
61
|
+
export { PageLayout, PageLayoutContext, PageLayoutControls, PageLayoutHeader, PageLayoutSection, PageLayoutStack, PageLayoutTitle, pageLayoutGapClassNames, pageLayoutStackGapClassNames, } from "./page-layout";
|
|
58
62
|
export { WorkspaceHeader } from "./workspace-header";
|
|
59
63
|
export { PageSection, PageSectionGroup } from "./page-section";
|
|
60
64
|
export { Typography, typographyVariants } from "./typography";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const jumpTargetHighlightAttribute = "data-jump-target-highlight";
|
|
2
|
+
export declare const jumpTargetHighlightSelector = "[data-jump-target-highlight=\"true\"]";
|
|
3
|
+
export declare const jumpTargetHighlightDurationMs = 420;
|
|
4
|
+
export declare const jumpTargetHighlightIterations = 2;
|
|
5
|
+
export declare const jumpTargetHighlightClassName = "transition-[background-color,box-shadow,border-color] duration-150 data-[jump-target-highlight=true]:border-ring/40 data-[jump-target-highlight=true]:bg-primary/5 data-[jump-target-highlight=true]:shadow-[0_0_0_2px_hsl(var(--ring)_/_0.16)] motion-reduce:transition-none";
|
|
6
|
+
export type JumpTargetHighlightRoot = Document | DocumentFragment | Element;
|
|
7
|
+
export interface HighlightJumpTargetOptions {
|
|
8
|
+
root?: JumpTargetHighlightRoot;
|
|
9
|
+
durationMs?: number;
|
|
10
|
+
iterations?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function clearJumpTargetHighlights(root?: JumpTargetHighlightRoot): void;
|
|
13
|
+
export declare function highlightJumpTarget(target: HTMLElement | null | undefined, { root, durationMs, iterations, }?: HighlightJumpTargetOptions): () => void;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export const jumpTargetHighlightAttribute = "data-jump-target-highlight";
|
|
2
|
+
export const jumpTargetHighlightSelector = `[${jumpTargetHighlightAttribute}="true"]`;
|
|
3
|
+
export const jumpTargetHighlightDurationMs = 420;
|
|
4
|
+
export const jumpTargetHighlightIterations = 2;
|
|
5
|
+
export const jumpTargetHighlightClassName = "transition-[background-color,box-shadow,border-color] duration-150 data-[jump-target-highlight=true]:border-ring/40 data-[jump-target-highlight=true]:bg-primary/5 data-[jump-target-highlight=true]:shadow-[0_0_0_2px_hsl(var(--ring)_/_0.16)] motion-reduce:transition-none";
|
|
6
|
+
const jumpTargetHighlightIdDataKey = "jumpTargetHighlightId";
|
|
7
|
+
const activeJumpTargetHighlights = new WeakMap();
|
|
8
|
+
function getJumpTargetHighlightTotalMs(durationMs, iterations) {
|
|
9
|
+
return durationMs * iterations;
|
|
10
|
+
}
|
|
11
|
+
function prefersReducedMotion(ownerWindow) {
|
|
12
|
+
return (typeof ownerWindow.matchMedia === "function" &&
|
|
13
|
+
ownerWindow.matchMedia("(prefers-reduced-motion: reduce)").matches);
|
|
14
|
+
}
|
|
15
|
+
function clearJumpTargetElement(element) {
|
|
16
|
+
const activeHighlight = activeJumpTargetHighlights.get(element);
|
|
17
|
+
if (activeHighlight) {
|
|
18
|
+
activeJumpTargetHighlights.delete(element);
|
|
19
|
+
if (activeHighlight.timeoutId !== undefined) {
|
|
20
|
+
activeHighlight.ownerWindow.clearTimeout(activeHighlight.timeoutId);
|
|
21
|
+
}
|
|
22
|
+
if (activeHighlight.animation) {
|
|
23
|
+
activeHighlight.animation.onfinish = null;
|
|
24
|
+
activeHighlight.animation.oncancel = null;
|
|
25
|
+
activeHighlight.animation.cancel();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
element.removeAttribute(jumpTargetHighlightAttribute);
|
|
29
|
+
delete element.dataset[jumpTargetHighlightIdDataKey];
|
|
30
|
+
}
|
|
31
|
+
export function clearJumpTargetHighlights(root) {
|
|
32
|
+
const highlightRoot = root !== null && root !== void 0 ? root : (typeof document === "undefined" ? undefined : document);
|
|
33
|
+
if (!highlightRoot) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
highlightRoot
|
|
37
|
+
.querySelectorAll(jumpTargetHighlightSelector)
|
|
38
|
+
.forEach(clearJumpTargetElement);
|
|
39
|
+
}
|
|
40
|
+
export function highlightJumpTarget(target, { root, durationMs = jumpTargetHighlightDurationMs, iterations = jumpTargetHighlightIterations, } = {}) {
|
|
41
|
+
if (!target) {
|
|
42
|
+
return () => undefined;
|
|
43
|
+
}
|
|
44
|
+
const ownerWindow = target.ownerDocument.defaultView;
|
|
45
|
+
if (!ownerWindow) {
|
|
46
|
+
return () => undefined;
|
|
47
|
+
}
|
|
48
|
+
clearJumpTargetHighlights(root !== null && root !== void 0 ? root : target.ownerDocument);
|
|
49
|
+
const highlightId = `${Date.now()}`;
|
|
50
|
+
const clearHighlight = () => {
|
|
51
|
+
if (target.dataset[jumpTargetHighlightIdDataKey] !== highlightId) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
clearJumpTargetElement(target);
|
|
55
|
+
};
|
|
56
|
+
target.dataset[jumpTargetHighlightIdDataKey] = highlightId;
|
|
57
|
+
target.setAttribute(jumpTargetHighlightAttribute, "true");
|
|
58
|
+
if (!prefersReducedMotion(ownerWindow) &&
|
|
59
|
+
typeof target.animate === "function") {
|
|
60
|
+
const animation = target.animate([
|
|
61
|
+
{
|
|
62
|
+
backgroundColor: "hsl(var(--primary) / 0.04)",
|
|
63
|
+
borderColor: "hsl(var(--ring) / 0.35)",
|
|
64
|
+
boxShadow: "0 0 0 2px hsl(var(--ring) / 0.12)",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
backgroundColor: "hsl(var(--primary) / 0.12)",
|
|
68
|
+
borderColor: "hsl(var(--ring) / 0.6)",
|
|
69
|
+
boxShadow: "0 0 0 3px hsl(var(--ring) / 0.24)",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
backgroundColor: "hsl(var(--primary) / 0.04)",
|
|
73
|
+
borderColor: "hsl(var(--ring) / 0.35)",
|
|
74
|
+
boxShadow: "0 0 0 2px hsl(var(--ring) / 0.12)",
|
|
75
|
+
},
|
|
76
|
+
], {
|
|
77
|
+
duration: durationMs,
|
|
78
|
+
easing: "ease-in-out",
|
|
79
|
+
iterations,
|
|
80
|
+
});
|
|
81
|
+
activeJumpTargetHighlights.set(target, {
|
|
82
|
+
animation,
|
|
83
|
+
ownerWindow,
|
|
84
|
+
});
|
|
85
|
+
animation.onfinish = clearHighlight;
|
|
86
|
+
animation.oncancel = clearHighlight;
|
|
87
|
+
return clearHighlight;
|
|
88
|
+
}
|
|
89
|
+
const timeoutId = ownerWindow.setTimeout(clearHighlight, getJumpTargetHighlightTotalMs(durationMs, iterations));
|
|
90
|
+
activeJumpTargetHighlights.set(target, {
|
|
91
|
+
ownerWindow,
|
|
92
|
+
timeoutId,
|
|
93
|
+
});
|
|
94
|
+
return clearHighlight;
|
|
95
|
+
}
|