@zvk/ui 0.1.2 → 0.1.5

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 (53) hide show
  1. package/dist/components/alert-dialog/alert-dialog.d.ts +8 -5
  2. package/dist/components/alert-dialog/alert-dialog.js +21 -8
  3. package/dist/components/button/button.d.ts +3 -2
  4. package/dist/components/button/button.js +5 -1
  5. package/dist/components/calendar/calendar.d.ts +51 -0
  6. package/dist/components/calendar/calendar.js +190 -0
  7. package/dist/components/calendar/index.d.ts +2 -0
  8. package/dist/components/calendar/index.js +2 -0
  9. package/dist/components/carousel/carousel.d.ts +51 -0
  10. package/dist/components/carousel/carousel.js +210 -0
  11. package/dist/components/carousel/index.d.ts +2 -0
  12. package/dist/components/carousel/index.js +2 -0
  13. package/dist/components/collapsible/collapsible.d.ts +3 -2
  14. package/dist/components/collapsible/collapsible.js +5 -1
  15. package/dist/components/command/command.d.ts +11 -4
  16. package/dist/components/command/command.js +27 -16
  17. package/dist/components/command/index.d.ts +1 -1
  18. package/dist/components/context-menu/context-menu.d.ts +17 -6
  19. package/dist/components/context-menu/context-menu.js +139 -36
  20. package/dist/components/date-picker/date-picker.d.ts +16 -0
  21. package/dist/components/date-picker/date-picker.js +50 -0
  22. package/dist/components/date-picker/index.d.ts +2 -0
  23. package/dist/components/date-picker/index.js +2 -0
  24. package/dist/components/dialog/dialog.d.ts +6 -4
  25. package/dist/components/dialog/dialog.js +14 -4
  26. package/dist/components/dropdown-menu/dropdown-menu.d.ts +13 -7
  27. package/dist/components/dropdown-menu/dropdown-menu.js +127 -72
  28. package/dist/components/hover-card/hover-card.d.ts +37 -0
  29. package/dist/components/hover-card/hover-card.js +271 -0
  30. package/dist/components/hover-card/index.d.ts +2 -0
  31. package/dist/components/hover-card/index.js +2 -0
  32. package/dist/components/index.d.ts +14 -6
  33. package/dist/components/index.js +5 -1
  34. package/dist/components/menubar/menubar.d.ts +24 -5
  35. package/dist/components/menubar/menubar.js +182 -33
  36. package/dist/components/popover/popover.d.ts +9 -3
  37. package/dist/components/popover/popover.js +15 -5
  38. package/dist/components/sheet/sheet.d.ts +6 -4
  39. package/dist/components/sheet/sheet.js +21 -8
  40. package/dist/components/toast/index.d.ts +2 -2
  41. package/dist/components/toast/index.js +2 -1
  42. package/dist/components/toast/toast.d.ts +40 -0
  43. package/dist/components/toast/toast.js +144 -2
  44. package/dist/components/tooltip/tooltip.d.ts +8 -2
  45. package/dist/components/tooltip/tooltip.js +8 -5
  46. package/dist/internal/floating/placement-aliases.d.ts +7 -0
  47. package/dist/internal/floating/placement-aliases.js +13 -0
  48. package/dist/internal/slot/index.d.ts +2 -0
  49. package/dist/internal/slot/index.js +1 -0
  50. package/dist/internal/slot/slot.d.ts +6 -0
  51. package/dist/internal/slot/slot.js +53 -0
  52. package/dist/styles.css +356 -4
  53. package/package.json +18 -2
@@ -6,7 +6,8 @@ export interface AlertDialogProps extends React.HTMLAttributes<HTMLDivElement> {
6
6
  ref?: React.Ref<HTMLDivElement>;
7
7
  }
8
8
  export interface AlertDialogTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
9
- ref?: React.Ref<HTMLButtonElement>;
9
+ asChild?: boolean;
10
+ ref?: React.Ref<HTMLButtonElement | HTMLElement>;
10
11
  }
11
12
  export interface AlertDialogContentProps extends React.HTMLAttributes<HTMLDivElement> {
12
13
  ref?: React.Ref<HTMLDivElement>;
@@ -21,18 +22,20 @@ export interface AlertDialogFooterProps extends React.HTMLAttributes<HTMLDivElem
21
22
  ref?: React.Ref<HTMLDivElement>;
22
23
  }
23
24
  export interface AlertDialogActionProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
24
- ref?: React.Ref<HTMLButtonElement>;
25
+ asChild?: boolean;
26
+ ref?: React.Ref<HTMLButtonElement | HTMLElement>;
25
27
  }
26
28
  export interface AlertDialogCancelProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
27
- ref?: React.Ref<HTMLButtonElement>;
29
+ asChild?: boolean;
30
+ ref?: React.Ref<HTMLButtonElement | HTMLElement>;
28
31
  }
29
32
  declare function AlertDialogRoot({ children, className, defaultOpen, onOpenChange, open: openProp, ref, ...props }: AlertDialogProps): React.JSX.Element;
30
- declare function AlertDialogTrigger({ className, disabled, onClick, ref, type, ...props }: AlertDialogTriggerProps): React.JSX.Element;
33
+ declare function AlertDialogTrigger({ asChild, className, disabled, onClick, ref, type, ...props }: AlertDialogTriggerProps): React.JSX.Element;
31
34
  declare function AlertDialogContent({ children, className, ref, ...props }: AlertDialogContentProps): React.JSX.Element | null;
32
35
  declare function AlertDialogTitle({ className, ref, ...props }: AlertDialogTitleProps): React.JSX.Element;
33
36
  declare function AlertDialogDescription({ className, ref, ...props }: AlertDialogDescriptionProps): React.JSX.Element;
34
37
  declare function AlertDialogFooter({ className, ref, ...props }: AlertDialogFooterProps): React.JSX.Element;
35
- declare function AlertDialogCloseButton({ className, onClick, ref, type, ...props }: AlertDialogActionProps | AlertDialogCancelProps): React.JSX.Element;
38
+ declare function AlertDialogCloseButton({ asChild, className, disabled, onClick, ref, type, ...props }: AlertDialogActionProps | AlertDialogCancelProps): React.JSX.Element;
36
39
  type AlertDialogComponent = typeof AlertDialogRoot & {
37
40
  Action: typeof AlertDialogCloseButton;
38
41
  Cancel: typeof AlertDialogCloseButton;
@@ -8,6 +8,7 @@ import { DismissableLayer } from "../../internal/dismissable-layer/index.js";
8
8
  import { FocusScope } from "../../internal/focus/index.js";
9
9
  import { Portal } from "../../internal/portal/index.js";
10
10
  import { lockScroll, unlockScroll } from "../../internal/scroll-lock/index.js";
11
+ import { Slot } from "../../internal/slot/index.js";
11
12
  const AlertDialogContext = React.createContext(null);
12
13
  function useAlertDialogContext(calledBy) {
13
14
  const context = React.useContext(AlertDialogContext);
@@ -67,13 +68,17 @@ function AlertDialogRoot({ children, className, defaultOpen = false, onOpenChang
67
68
  triggerRef
68
69
  }, children: _jsx("div", { ...props, ref: ref, className: cn("liano-alert-dialog", className), "data-state": open ? "open" : "closed", children: children }) }));
69
70
  }
70
- function AlertDialogTrigger({ className, disabled, onClick, ref, type = "button", ...props }) {
71
+ function AlertDialogTrigger({ asChild = false, className, disabled, onClick, ref, type = "button", ...props }) {
71
72
  const { contentId, open, setOpen, triggerRef } = useAlertDialogContext("AlertDialog.Trigger");
72
- return (_jsx("button", { ...props, ref: composeRefs(ref, triggerRef), type: type, disabled: disabled, "aria-controls": contentId, "aria-expanded": open ? "true" : "false", className: cn("liano-alert-dialog__trigger", className), "data-state": open ? "open" : "closed", onClick: composeEventHandlers(onClick, () => {
73
- if (!disabled) {
74
- setOpen(true);
75
- }
76
- }) }));
73
+ const handleClick = () => {
74
+ if (!disabled) {
75
+ setOpen(true);
76
+ }
77
+ };
78
+ if (asChild) {
79
+ return (_jsx(Slot, { ...props, ref: composeRefs(ref, triggerRef), "aria-controls": contentId, "aria-disabled": disabled ? true : undefined, "aria-expanded": open ? "true" : "false", className: cn("liano-alert-dialog__trigger", className), "data-disabled": disabled ? "true" : undefined, "data-state": open ? "open" : "closed", onClick: composeEventHandlers(onClick, handleClick), children: props.children }));
80
+ }
81
+ return (_jsx("button", { ...props, ref: composeRefs(ref, triggerRef), type: type, disabled: disabled, "aria-controls": contentId, "aria-expanded": open ? "true" : "false", className: cn("liano-alert-dialog__trigger", className), "data-state": open ? "open" : "closed", onClick: composeEventHandlers(onClick, handleClick) }));
77
82
  }
78
83
  function AlertDialogContent({ children, className, ref, ...props }) {
79
84
  const { close, contentId, describedBy, labelledBy, open } = useAlertDialogContext("AlertDialog.Content");
@@ -97,9 +102,17 @@ function AlertDialogDescription({ className, ref, ...props }) {
97
102
  function AlertDialogFooter({ className, ref, ...props }) {
98
103
  return _jsx("div", { ...props, ref: ref, className: cn("liano-alert-dialog__footer", className) });
99
104
  }
100
- function AlertDialogCloseButton({ className, onClick, ref, type = "button", ...props }) {
105
+ function AlertDialogCloseButton({ asChild = false, className, disabled, onClick, ref, type = "button", ...props }) {
101
106
  const { close } = useAlertDialogContext("AlertDialog.Action");
102
- return (_jsx("button", { ...props, ref: ref, type: type, className: cn("liano-alert-dialog__button", className), onClick: composeEventHandlers(onClick, close) }));
107
+ const handleClick = () => {
108
+ if (!disabled) {
109
+ close();
110
+ }
111
+ };
112
+ if (asChild) {
113
+ return (_jsx(Slot, { ...props, ref: ref, "aria-disabled": disabled ? true : undefined, className: cn("liano-alert-dialog__button", className), "data-disabled": disabled ? "true" : undefined, onClick: composeEventHandlers(onClick, handleClick), children: props.children }));
114
+ }
115
+ return (_jsx("button", { ...props, ref: ref, type: type, disabled: disabled, className: cn("liano-alert-dialog__button", className), onClick: composeEventHandlers(onClick, handleClick) }));
103
116
  }
104
117
  export const AlertDialog = Object.assign(AlertDialogRoot, {
105
118
  Action: AlertDialogCloseButton,
@@ -2,12 +2,13 @@ import * as React from "react";
2
2
  export type ButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "destructive";
3
3
  export type ButtonSize = "sm" | "md" | "lg" | "icon";
4
4
  export interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "disabled"> {
5
+ asChild?: boolean;
5
6
  variant?: ButtonVariant;
6
7
  size?: ButtonSize;
7
8
  loading?: boolean;
8
9
  disabled?: boolean;
9
10
  leadingIcon?: React.ReactNode;
10
11
  trailingIcon?: React.ReactNode;
11
- ref?: React.Ref<HTMLButtonElement>;
12
+ ref?: React.Ref<HTMLButtonElement | HTMLElement>;
12
13
  }
13
- export declare function Button({ children, className, disabled, leadingIcon, loading, ref, size, trailingIcon, type, variant, ...props }: ButtonProps): React.JSX.Element;
14
+ export declare function Button({ asChild, children, className, disabled, leadingIcon, loading, ref, size, trailingIcon, type, variant, ...props }: ButtonProps): React.JSX.Element;
@@ -1,8 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { Spinner } from "../spinner/spinner.js";
4
+ import { Slot } from "../../internal/slot/index.js";
4
5
  import { cn } from "../../utils/cn.js";
5
- export function Button({ children, className, disabled, leadingIcon, loading = false, ref, size = "md", trailingIcon, type = "button", variant = "primary", ...props }) {
6
+ export function Button({ asChild = false, children, className, disabled, leadingIcon, loading = false, ref, size = "md", trailingIcon, type = "button", variant = "primary", ...props }) {
6
7
  const isDisabled = disabled || loading;
8
+ if (asChild) {
9
+ return (_jsx(Slot, { ...props, ref: ref, "aria-busy": loading ? true : undefined, "aria-disabled": isDisabled ? true : undefined, className: cn("liano-button", className), "data-disabled": isDisabled ? "true" : undefined, "data-loading": loading ? "true" : undefined, "data-size": size, "data-variant": variant, children: children }));
10
+ }
7
11
  return (_jsxs("button", { ...props, ref: ref, "aria-busy": loading ? true : undefined, className: cn("liano-button", className), "data-disabled": isDisabled ? "true" : undefined, "data-loading": loading ? "true" : undefined, "data-size": size, "data-variant": variant, disabled: isDisabled, type: type, children: [loading ? (_jsx("span", { "aria-hidden": "true", className: "liano-button__spinner", children: _jsx(Spinner, { size: "sm" }) })) : null, leadingIcon ? (_jsx("span", { "aria-hidden": "true", className: "liano-button__icon", children: leadingIcon })) : null, _jsx("span", { className: "liano-button__content", children: children }), trailingIcon ? (_jsx("span", { "aria-hidden": "true", className: "liano-button__icon", children: trailingIcon })) : null] }));
8
12
  }
@@ -0,0 +1,51 @@
1
+ import * as React from "react";
2
+ export type CalendarMode = "single";
3
+ export type CalendarClassNames = Partial<{
4
+ months: string;
5
+ month: string;
6
+ caption: string;
7
+ caption_label: string;
8
+ nav: string;
9
+ nav_button: string;
10
+ nav_button_previous: string;
11
+ nav_button_next: string;
12
+ table: string;
13
+ head_row: string;
14
+ head_cell: string;
15
+ row: string;
16
+ cell: string;
17
+ day: string;
18
+ day_selected: string;
19
+ day_today: string;
20
+ day_outside: string;
21
+ day_disabled: string;
22
+ }>;
23
+ interface CalendarBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect"> {
24
+ month?: Date;
25
+ defaultMonth?: Date;
26
+ onMonthChange?: (month: Date) => void;
27
+ minDate?: Date;
28
+ maxDate?: Date;
29
+ disabled?: (date: Date) => boolean;
30
+ disabledDate?: (date: Date) => boolean;
31
+ showOutsideDays?: boolean;
32
+ classNames?: CalendarClassNames;
33
+ weekStartsOn?: 0 | 1;
34
+ locale?: string;
35
+ ref?: React.Ref<HTMLDivElement>;
36
+ }
37
+ export interface CalendarNativeProps extends CalendarBaseProps {
38
+ mode?: undefined;
39
+ selected?: Date | null;
40
+ defaultSelected?: Date | null;
41
+ onSelect?: (date: Date | null) => void;
42
+ }
43
+ export interface CalendarSingleProps extends CalendarBaseProps {
44
+ mode: CalendarMode;
45
+ selected?: Date | null | undefined;
46
+ defaultSelected?: Date | null;
47
+ onSelect?: (date: Date | undefined) => void;
48
+ }
49
+ export type CalendarProps = CalendarNativeProps | CalendarSingleProps;
50
+ export declare function Calendar({ classNames, className, defaultMonth, defaultSelected, disabled, disabledDate, locale, maxDate, minDate, mode, month, onKeyDown, onMonthChange, onSelect, ref, selected, showOutsideDays, weekStartsOn, ...props }: CalendarProps): React.JSX.Element;
51
+ export {};
@@ -0,0 +1,190 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../../utils/cn.js";
5
+ const dayMs = 24 * 60 * 60 * 1000;
6
+ function startOfDay(date) {
7
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
8
+ }
9
+ function startOfMonth(date) {
10
+ return new Date(date.getFullYear(), date.getMonth(), 1);
11
+ }
12
+ function addDays(date, amount) {
13
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
14
+ }
15
+ function addMonths(date, amount) {
16
+ return new Date(date.getFullYear(), date.getMonth() + amount, 1);
17
+ }
18
+ function isSameDay(left, right) {
19
+ if (!left || !right) {
20
+ return false;
21
+ }
22
+ return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();
23
+ }
24
+ function isBeforeDay(left, right) {
25
+ return startOfDay(left).getTime() < startOfDay(right).getTime();
26
+ }
27
+ function isAfterDay(left, right) {
28
+ return startOfDay(left).getTime() > startOfDay(right).getTime();
29
+ }
30
+ function getInitialMonth(month, selected) {
31
+ if (month) {
32
+ return startOfMonth(month);
33
+ }
34
+ if (selected) {
35
+ return startOfMonth(selected);
36
+ }
37
+ return startOfMonth(new Date());
38
+ }
39
+ function getCalendarStart(month, weekStartsOn) {
40
+ const firstDay = startOfMonth(month);
41
+ const offset = (firstDay.getDay() - weekStartsOn + 7) % 7;
42
+ return addDays(firstDay, -offset);
43
+ }
44
+ function getCalendarDays(month, weekStartsOn) {
45
+ const start = getCalendarStart(month, weekStartsOn);
46
+ return Array.from({ length: 42 }, (_, index) => addDays(start, index));
47
+ }
48
+ function isDisabled(date, props) {
49
+ if (props.minDate && isBeforeDay(date, props.minDate)) {
50
+ return true;
51
+ }
52
+ if (props.maxDate && isAfterDay(date, props.maxDate)) {
53
+ return true;
54
+ }
55
+ const normalizedDate = startOfDay(date);
56
+ if (props.disabled?.(normalizedDate)) {
57
+ return true;
58
+ }
59
+ return props.disabledDate ? props.disabledDate(normalizedDate) : false;
60
+ }
61
+ function getMonthLabel(date, locale) {
62
+ return new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(date);
63
+ }
64
+ function getDayLabel(date, locale) {
65
+ return new Intl.DateTimeFormat(locale, { day: "numeric", month: "long", year: "numeric" }).format(date);
66
+ }
67
+ function getWeekdayLabels(weekStartsOn, locale) {
68
+ const sunday = new Date(2026, 5, 7);
69
+ return Array.from({ length: 7 }, (_, index) => {
70
+ const dayIndex = (index + weekStartsOn) % 7;
71
+ return new Intl.DateTimeFormat(locale, { weekday: "short" }).format(addDays(sunday, dayIndex));
72
+ });
73
+ }
74
+ function getNearestEnabledDate(date, visibleMonth, props) {
75
+ if (!isDisabled(date, props)) {
76
+ return date;
77
+ }
78
+ const days = getCalendarDays(visibleMonth, 0);
79
+ return days.find((day) => !isDisabled(day, props)) ?? date;
80
+ }
81
+ export function Calendar({ classNames, className, defaultMonth, defaultSelected = null, disabled, disabledDate, locale, maxDate, minDate, mode, month, onKeyDown, onMonthChange, onSelect, ref, selected, showOutsideDays = true, weekStartsOn = 0, ...props }) {
82
+ const isSelectedControlled = selected !== undefined;
83
+ const selectedDate = isSelectedControlled ? selected : defaultSelected;
84
+ const [uncontrolledSelected, setUncontrolledSelected] = React.useState(defaultSelected);
85
+ const currentSelected = isSelectedControlled ? selected : uncontrolledSelected;
86
+ const [uncontrolledMonth, setUncontrolledMonth] = React.useState(() => getInitialMonth(defaultMonth, selectedDate));
87
+ const visibleMonth = startOfMonth(month ?? uncontrolledMonth);
88
+ const [focusedDate, setFocusedDate] = React.useState(() => startOfDay(currentSelected ?? visibleMonth));
89
+ const headingId = React.useId();
90
+ const dayButtonRefs = React.useRef(new Map());
91
+ const disabledProps = React.useMemo(() => ({ disabled, disabledDate, maxDate, minDate }), [disabled, disabledDate, maxDate, minDate]);
92
+ const days = React.useMemo(() => getCalendarDays(visibleMonth, weekStartsOn), [visibleMonth, weekStartsOn]);
93
+ const weekdays = React.useMemo(() => getWeekdayLabels(weekStartsOn, locale), [locale, weekStartsOn]);
94
+ const monthLabel = getMonthLabel(visibleMonth, locale);
95
+ const today = startOfDay(new Date());
96
+ React.useEffect(() => {
97
+ if (currentSelected) {
98
+ setFocusedDate(startOfDay(currentSelected));
99
+ }
100
+ }, [currentSelected]);
101
+ const setVisibleMonth = (nextMonth) => {
102
+ const normalizedMonth = startOfMonth(nextMonth);
103
+ if (month === undefined) {
104
+ setUncontrolledMonth(normalizedMonth);
105
+ }
106
+ onMonthChange?.(normalizedMonth);
107
+ };
108
+ const focusDay = React.useCallback((date) => {
109
+ const key = startOfDay(date).getTime();
110
+ dayButtonRefs.current.get(key)?.focus();
111
+ }, []);
112
+ const moveFocus = (nextDate) => {
113
+ const normalizedDate = getNearestEnabledDate(startOfDay(nextDate), startOfMonth(nextDate), disabledProps);
114
+ setFocusedDate(normalizedDate);
115
+ if (normalizedDate.getMonth() !== visibleMonth.getMonth() || normalizedDate.getFullYear() !== visibleMonth.getFullYear()) {
116
+ setVisibleMonth(startOfMonth(normalizedDate));
117
+ }
118
+ window.requestAnimationFrame(() => focusDay(normalizedDate));
119
+ };
120
+ const selectDate = (date) => {
121
+ const normalizedDate = startOfDay(date);
122
+ const nextSelected = isSameDay(currentSelected, normalizedDate) ? null : normalizedDate;
123
+ if (!isSelectedControlled) {
124
+ setUncontrolledSelected(nextSelected);
125
+ }
126
+ if (mode === "single") {
127
+ onSelect?.(nextSelected ?? undefined);
128
+ return;
129
+ }
130
+ onSelect?.(nextSelected);
131
+ };
132
+ const handleKeyDown = (event) => {
133
+ onKeyDown?.(event);
134
+ if (event.defaultPrevented) {
135
+ return;
136
+ }
137
+ const keyOffsets = {
138
+ ArrowDown: 7,
139
+ ArrowLeft: -1,
140
+ ArrowRight: 1,
141
+ ArrowUp: -7,
142
+ PageDown: dayMs * 31,
143
+ PageUp: -dayMs * 31
144
+ };
145
+ if (event.key === "Enter" || event.key === " ") {
146
+ const targetDate = getNearestEnabledDate(focusedDate, visibleMonth, disabledProps);
147
+ if (!isDisabled(targetDate, disabledProps)) {
148
+ event.preventDefault();
149
+ selectDate(targetDate);
150
+ }
151
+ return;
152
+ }
153
+ if (event.key === "Home" || event.key === "End") {
154
+ event.preventDefault();
155
+ const weekDay = (focusedDate.getDay() - weekStartsOn + 7) % 7;
156
+ moveFocus(addDays(focusedDate, event.key === "Home" ? -weekDay : 6 - weekDay));
157
+ return;
158
+ }
159
+ const offset = keyOffsets[event.key];
160
+ if (offset === undefined) {
161
+ return;
162
+ }
163
+ event.preventDefault();
164
+ if (event.key === "PageDown" || event.key === "PageUp") {
165
+ moveFocus(addMonths(focusedDate, offset > 0 ? 1 : -1));
166
+ return;
167
+ }
168
+ moveFocus(addDays(focusedDate, offset));
169
+ };
170
+ return (_jsxs("div", { ...props, ref: ref, className: cn("liano-calendar", classNames?.months, classNames?.month, className), onKeyDown: handleKeyDown, children: [_jsxs("div", { className: cn("liano-calendar__header", classNames?.caption, classNames?.nav), children: [_jsx("button", { "aria-label": "Previous month", className: cn("liano-calendar__nav", classNames?.nav_button, classNames?.nav_button_previous), type: "button", onClick: () => setVisibleMonth(addMonths(visibleMonth, -1)), children: _jsx("span", { "aria-hidden": "true", children: "\u2039" }) }), _jsx("h2", { className: cn("liano-calendar__heading", classNames?.caption_label), id: headingId, children: monthLabel }), _jsx("button", { "aria-label": "Next month", className: cn("liano-calendar__nav", classNames?.nav_button, classNames?.nav_button_next), type: "button", onClick: () => setVisibleMonth(addMonths(visibleMonth, 1)), children: _jsx("span", { "aria-hidden": "true", children: "\u203A" }) })] }), _jsxs("div", { "aria-labelledby": headingId, className: cn("liano-calendar__grid", classNames?.table), role: "grid", children: [_jsx("div", { className: cn("liano-calendar__weekdays", classNames?.head_row), role: "row", children: weekdays.map((weekday) => (_jsx("span", { className: cn("liano-calendar__weekday", classNames?.head_cell), role: "columnheader", children: weekday }, weekday))) }), Array.from({ length: 6 }, (_, rowIndex) => (_jsx("div", { className: cn("liano-calendar__week", classNames?.row), role: "row", children: days.slice(rowIndex * 7, rowIndex * 7 + 7).map((date) => {
171
+ const normalizedDate = startOfDay(date);
172
+ const dateKey = normalizedDate.getTime();
173
+ const outsideMonth = date.getMonth() !== visibleMonth.getMonth();
174
+ const hideOutsideDay = outsideMonth && !showOutsideDays;
175
+ const disabled = isDisabled(date, disabledProps);
176
+ const selectedDay = isSameDay(currentSelected, date);
177
+ const focusedDay = isSameDay(focusedDate, date);
178
+ if (hideOutsideDay) {
179
+ return (_jsx("span", { className: cn("liano-calendar__cell", classNames?.cell), role: "gridcell", children: _jsx("span", { "aria-hidden": "true", className: cn("liano-calendar__day", classNames?.day, classNames?.day_outside), "data-outside-month": "true" }) }, dateKey));
180
+ }
181
+ return (_jsx("span", { className: cn("liano-calendar__cell", classNames?.cell), role: "gridcell", children: _jsx("button", { "aria-label": getDayLabel(date, locale), "aria-pressed": selectedDay, className: cn("liano-calendar__day", classNames?.day, selectedDay ? classNames?.day_selected : undefined, outsideMonth ? classNames?.day_outside : undefined, disabled ? classNames?.day_disabled : undefined, isSameDay(today, date) ? classNames?.day_today : undefined), "data-disabled": disabled ? "true" : undefined, "data-outside-month": outsideMonth ? "true" : undefined, "data-selected": selectedDay ? "true" : undefined, "data-today": isSameDay(today, date) ? "true" : undefined, disabled: disabled, ref: (node) => {
182
+ if (node) {
183
+ dayButtonRefs.current.set(dateKey, node);
184
+ }
185
+ else {
186
+ dayButtonRefs.current.delete(dateKey);
187
+ }
188
+ }, tabIndex: focusedDay ? 0 : -1, type: "button", onClick: () => selectDate(date), onFocus: () => setFocusedDate(normalizedDate), children: date.getDate() }) }, dateKey));
189
+ }) }, rowIndex)))] })] }));
190
+ }
@@ -0,0 +1,2 @@
1
+ export { Calendar } from "./calendar.js";
2
+ export type { CalendarClassNames, CalendarMode, CalendarNativeProps, CalendarProps, CalendarSingleProps } from "./calendar.js";
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export { Calendar } from "./calendar.js";
@@ -0,0 +1,51 @@
1
+ import * as React from "react";
2
+ export type CarouselOrientation = "horizontal" | "vertical";
3
+ export interface CarouselApi {
4
+ scrollPrev: () => void;
5
+ scrollNext: () => void;
6
+ scrollTo: (index: number) => void;
7
+ selectedIndex: () => number;
8
+ slideCount: () => number;
9
+ canScrollPrev: () => boolean;
10
+ canScrollNext: () => boolean;
11
+ subscribe: (listener: () => void) => () => void;
12
+ }
13
+ export interface CarouselProps extends React.HTMLAttributes<HTMLDivElement> {
14
+ orientation?: CarouselOrientation;
15
+ defaultIndex?: number;
16
+ index?: number;
17
+ onIndexChange?: (index: number) => void;
18
+ onApiChange?: (api: CarouselApi | null) => void;
19
+ ref?: React.Ref<HTMLDivElement>;
20
+ }
21
+ export interface CarouselViewportProps extends React.HTMLAttributes<HTMLDivElement> {
22
+ ref?: React.Ref<HTMLDivElement>;
23
+ }
24
+ export interface CarouselTrackProps extends React.HTMLAttributes<HTMLDivElement> {
25
+ ref?: React.Ref<HTMLDivElement>;
26
+ }
27
+ export interface CarouselSlideProps extends React.HTMLAttributes<HTMLDivElement> {
28
+ ref?: React.Ref<HTMLDivElement>;
29
+ }
30
+ export interface CarouselButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
31
+ ref?: React.Ref<HTMLButtonElement>;
32
+ }
33
+ export interface CarouselPageProps extends React.OutputHTMLAttributes<HTMLOutputElement> {
34
+ ref?: React.Ref<HTMLOutputElement>;
35
+ }
36
+ declare function CarouselRoot({ children, className, defaultIndex, index, onApiChange, onIndexChange, onKeyDown, orientation, ref, tabIndex, ...props }: CarouselProps): React.JSX.Element;
37
+ declare function CarouselViewport({ className, ref, ...props }: CarouselViewportProps): React.JSX.Element;
38
+ declare function CarouselTrack({ className, ref, ...props }: CarouselTrackProps): React.JSX.Element;
39
+ declare function CarouselSlide({ className, ref, ...props }: CarouselSlideProps): React.JSX.Element;
40
+ declare function CarouselPrevious({ className, disabled, onClick, ref, type, ...props }: CarouselButtonProps): React.JSX.Element;
41
+ declare function CarouselNext({ className, disabled, onClick, ref, type, ...props }: CarouselButtonProps): React.JSX.Element;
42
+ declare function CarouselPage({ children, className, ref, ...props }: CarouselPageProps): React.JSX.Element;
43
+ export declare const Carousel: typeof CarouselRoot & {
44
+ Next: typeof CarouselNext;
45
+ Page: typeof CarouselPage;
46
+ Previous: typeof CarouselPrevious;
47
+ Slide: typeof CarouselSlide;
48
+ Track: typeof CarouselTrack;
49
+ Viewport: typeof CarouselViewport;
50
+ };
51
+ export {};
@@ -0,0 +1,210 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { composeEventHandlers } from "../../utils/compose-event-handlers.js";
5
+ import { useControllableState } from "../../hooks/use-controllable-state.js";
6
+ import { cn } from "../../utils/cn.js";
7
+ const CarouselContext = React.createContext(null);
8
+ function useCarouselContext(calledBy) {
9
+ const context = React.useContext(CarouselContext);
10
+ if (!context) {
11
+ throw new Error(`"${calledBy}" must be used within <Carousel />`);
12
+ }
13
+ return context;
14
+ }
15
+ function normalizeIndex(value, fallback = 0) {
16
+ if (value === undefined || !Number.isFinite(value)) {
17
+ return fallback;
18
+ }
19
+ return Math.max(0, Math.floor(value));
20
+ }
21
+ function clampIndex(value, slideCount) {
22
+ if (slideCount <= 0) {
23
+ return 0;
24
+ }
25
+ return Math.max(0, Math.min(normalizeIndex(value), slideCount - 1));
26
+ }
27
+ function setRef(ref, value) {
28
+ if (typeof ref === "function") {
29
+ ref(value);
30
+ return;
31
+ }
32
+ if (ref) {
33
+ ref.current = value;
34
+ }
35
+ }
36
+ function CarouselRoot({ children, className, defaultIndex = 0, index, onApiChange, onIndexChange, onKeyDown, orientation = "horizontal", ref, tabIndex, ...props }) {
37
+ const slideRegistry = React.useRef(new Map());
38
+ const listeners = React.useRef(new Set());
39
+ const [slideIds, setSlideIds] = React.useState([]);
40
+ const [currentIndex, setCurrentIndex] = useControllableState({
41
+ ...(index !== undefined ? { value: normalizeIndex(index) } : {}),
42
+ defaultValue: normalizeIndex(defaultIndex),
43
+ ...(onIndexChange ? { onChange: onIndexChange } : {})
44
+ });
45
+ const slideCount = slideIds.length;
46
+ const selectedIndex = clampIndex(currentIndex, slideCount);
47
+ const canScrollPrev = selectedIndex > 0;
48
+ const canScrollNext = selectedIndex < slideCount - 1;
49
+ const stateRef = React.useRef({ selectedIndex, slideCount });
50
+ React.useLayoutEffect(() => {
51
+ stateRef.current = { selectedIndex, slideCount };
52
+ }, [selectedIndex, slideCount]);
53
+ const scrollTo = React.useCallback((nextIndex) => {
54
+ setCurrentIndex(clampIndex(nextIndex, slideIds.length));
55
+ }, [setCurrentIndex, slideIds.length]);
56
+ const scrollPrev = React.useCallback(() => {
57
+ scrollTo(stateRef.current.selectedIndex - 1);
58
+ }, [scrollTo]);
59
+ const scrollNext = React.useCallback(() => {
60
+ scrollTo(stateRef.current.selectedIndex + 1);
61
+ }, [scrollTo]);
62
+ const registerSlide = React.useCallback((id, node) => {
63
+ slideRegistry.current.set(id, node);
64
+ setSlideIds((current) => (current.includes(id) ? current : [...current, id]));
65
+ }, []);
66
+ const unregisterSlide = React.useCallback((id) => {
67
+ slideRegistry.current.delete(id);
68
+ setSlideIds((current) => current.filter((slideId) => slideId !== id));
69
+ }, []);
70
+ const getSlideIndex = React.useCallback((id) => slideIds.indexOf(id), [slideIds]);
71
+ React.useLayoutEffect(() => {
72
+ const nextIndex = clampIndex(currentIndex, slideCount);
73
+ if (nextIndex !== currentIndex) {
74
+ setCurrentIndex(nextIndex);
75
+ }
76
+ }, [currentIndex, setCurrentIndex, slideCount]);
77
+ React.useLayoutEffect(() => {
78
+ const selectedSlideId = slideIds[selectedIndex];
79
+ const selectedSlide = selectedSlideId ? slideRegistry.current.get(selectedSlideId) : null;
80
+ if (typeof selectedSlide?.scrollIntoView === "function") {
81
+ selectedSlide.scrollIntoView({
82
+ behavior: "auto",
83
+ block: orientation === "vertical" ? "start" : "nearest",
84
+ inline: orientation === "horizontal" ? "start" : "nearest"
85
+ });
86
+ }
87
+ }, [orientation, selectedIndex, slideIds]);
88
+ React.useLayoutEffect(() => {
89
+ listeners.current.forEach((listener) => listener());
90
+ }, [selectedIndex, slideCount]);
91
+ const api = React.useMemo(() => ({
92
+ canScrollNext: () => stateRef.current.selectedIndex < stateRef.current.slideCount - 1,
93
+ canScrollPrev: () => stateRef.current.selectedIndex > 0,
94
+ scrollNext,
95
+ scrollPrev,
96
+ scrollTo,
97
+ selectedIndex: () => stateRef.current.selectedIndex,
98
+ slideCount: () => stateRef.current.slideCount,
99
+ subscribe(listener) {
100
+ listeners.current.add(listener);
101
+ return () => {
102
+ listeners.current.delete(listener);
103
+ };
104
+ }
105
+ }), [scrollNext, scrollPrev, scrollTo]);
106
+ React.useLayoutEffect(() => {
107
+ onApiChange?.(api);
108
+ return () => {
109
+ onApiChange?.(null);
110
+ };
111
+ }, [api, onApiChange]);
112
+ const handleKeyDown = React.useCallback((event) => {
113
+ const previousKey = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
114
+ const nextKey = orientation === "horizontal" ? "ArrowRight" : "ArrowDown";
115
+ if (event.key === previousKey) {
116
+ event.preventDefault();
117
+ scrollPrev();
118
+ return;
119
+ }
120
+ if (event.key === nextKey) {
121
+ event.preventDefault();
122
+ scrollNext();
123
+ return;
124
+ }
125
+ if (event.key === "Home") {
126
+ event.preventDefault();
127
+ scrollTo(0);
128
+ return;
129
+ }
130
+ if (event.key === "End") {
131
+ event.preventDefault();
132
+ scrollTo(slideCount - 1);
133
+ }
134
+ }, [orientation, scrollNext, scrollPrev, scrollTo, slideCount]);
135
+ const context = React.useMemo(() => ({
136
+ canScrollNext,
137
+ canScrollPrev,
138
+ getSlideIndex,
139
+ orientation,
140
+ registerSlide,
141
+ scrollNext,
142
+ scrollPrev,
143
+ scrollTo,
144
+ selectedIndex,
145
+ slideCount,
146
+ unregisterSlide
147
+ }), [
148
+ canScrollNext,
149
+ canScrollPrev,
150
+ getSlideIndex,
151
+ orientation,
152
+ registerSlide,
153
+ scrollNext,
154
+ scrollPrev,
155
+ scrollTo,
156
+ selectedIndex,
157
+ slideCount,
158
+ unregisterSlide
159
+ ]);
160
+ return (_jsx(CarouselContext.Provider, { value: context, children: _jsx("div", { ...props, ref: ref, "aria-roledescription": "carousel", className: cn("liano-carousel", className), "data-orientation": orientation, onKeyDown: composeEventHandlers(onKeyDown, handleKeyDown), role: props.role ?? "region", tabIndex: tabIndex ?? 0, children: children }) }));
161
+ }
162
+ function CarouselViewport({ className, ref, ...props }) {
163
+ const context = useCarouselContext("Carousel.Viewport");
164
+ return (_jsx("div", { ...props, ref: ref, className: cn("liano-carousel__viewport", className), "data-orientation": context.orientation }));
165
+ }
166
+ function CarouselTrack({ className, ref, ...props }) {
167
+ const context = useCarouselContext("Carousel.Track");
168
+ return (_jsx("div", { ...props, ref: ref, className: cn("liano-carousel__track", className), "data-orientation": context.orientation }));
169
+ }
170
+ function CarouselSlide({ className, ref, ...props }) {
171
+ const context = useCarouselContext("Carousel.Slide");
172
+ const id = React.useId();
173
+ const slideRef = React.useRef(null);
174
+ const slideIndex = context.getSlideIndex(id);
175
+ const isSelected = slideIndex === context.selectedIndex;
176
+ const safeIndex = slideIndex === -1 ? 0 : slideIndex;
177
+ React.useLayoutEffect(() => {
178
+ context.registerSlide(id, slideRef.current);
179
+ return () => {
180
+ context.unregisterSlide(id);
181
+ };
182
+ }, [context.registerSlide, context.unregisterSlide, id]);
183
+ return (_jsx("div", { ...props, ref: (node) => {
184
+ slideRef.current = node;
185
+ setRef(ref, node);
186
+ }, "aria-label": props["aria-label"] ?? `${safeIndex + 1} of ${context.slideCount}`, "aria-roledescription": "slide", className: cn("liano-carousel__slide", className), "data-orientation": context.orientation, "data-selected": isSelected ? "true" : undefined, role: props.role ?? "group" }));
187
+ }
188
+ function CarouselPrevious({ className, disabled, onClick, ref, type = "button", ...props }) {
189
+ const context = useCarouselContext("Carousel.Previous");
190
+ const isDisabled = disabled === true || !context.canScrollPrev;
191
+ return (_jsx("button", { ...props, ref: ref, "aria-label": props["aria-label"] ?? "Previous slide", className: cn("liano-carousel__button liano-carousel__button--previous", className), "data-disabled": isDisabled ? "true" : undefined, disabled: isDisabled, onClick: composeEventHandlers(onClick, () => context.scrollPrev()), type: type }));
192
+ }
193
+ function CarouselNext({ className, disabled, onClick, ref, type = "button", ...props }) {
194
+ const context = useCarouselContext("Carousel.Next");
195
+ const isDisabled = disabled === true || !context.canScrollNext;
196
+ return (_jsx("button", { ...props, ref: ref, "aria-label": props["aria-label"] ?? "Next slide", className: cn("liano-carousel__button liano-carousel__button--next", className), "data-disabled": isDisabled ? "true" : undefined, disabled: isDisabled, onClick: composeEventHandlers(onClick, () => context.scrollNext()), type: type }));
197
+ }
198
+ function CarouselPage({ children, className, ref, ...props }) {
199
+ const context = useCarouselContext("Carousel.Page");
200
+ const label = context.slideCount === 0 ? "0 / 0" : `${context.selectedIndex + 1} / ${context.slideCount}`;
201
+ return (_jsx("output", { ...props, ref: ref, "aria-live": props["aria-live"] ?? "polite", className: cn("liano-carousel__page", className), children: children ?? label }));
202
+ }
203
+ export const Carousel = Object.assign(CarouselRoot, {
204
+ Next: CarouselNext,
205
+ Page: CarouselPage,
206
+ Previous: CarouselPrevious,
207
+ Slide: CarouselSlide,
208
+ Track: CarouselTrack,
209
+ Viewport: CarouselViewport
210
+ });
@@ -0,0 +1,2 @@
1
+ export { Carousel } from "./carousel.js";
2
+ export type { CarouselApi, CarouselButtonProps, CarouselOrientation, CarouselPageProps, CarouselProps, CarouselSlideProps, CarouselTrackProps, CarouselViewportProps } from "./carousel.js";
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export { Carousel } from "./carousel.js";