@pichetch08/trip-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/accordion.d.ts +18 -0
- package/dist/accordion.js +76 -0
- package/dist/agreement-modal.d.ts +16 -0
- package/dist/agreement-modal.js +67 -0
- package/dist/alert.d.ts +13 -0
- package/dist/alert.js +47 -0
- package/dist/auth-hero.d.ts +7 -0
- package/dist/auth-hero.js +63 -0
- package/dist/avatar.d.ts +21 -0
- package/dist/avatar.js +114 -0
- package/dist/badge.d.ts +13 -0
- package/dist/badge.js +36 -0
- package/dist/banner.d.ts +14 -0
- package/dist/banner.js +57 -0
- package/dist/breadcrumb.d.ts +15 -0
- package/dist/breadcrumb.js +37 -0
- package/dist/button.d.ts +15 -0
- package/dist/button.js +81 -0
- package/dist/card.d.ts +30 -0
- package/dist/card.js +66 -0
- package/dist/change-summary-modal.d.ts +35 -0
- package/dist/change-summary-modal.js +128 -0
- package/dist/channel-badge.d.ts +8 -0
- package/dist/channel-badge.js +17 -0
- package/dist/checkbox.d.ts +28 -0
- package/dist/checkbox.js +108 -0
- package/dist/chunk-ORMEWXMH.js +37 -0
- package/dist/color-picker.d.ts +15 -0
- package/dist/color-picker.js +159 -0
- package/dist/confirm-dialog.d.ts +23 -0
- package/dist/confirm-dialog.js +108 -0
- package/dist/copy-button.d.ts +13 -0
- package/dist/copy-button.js +69 -0
- package/dist/dashed-add-button.d.ts +8 -0
- package/dist/dashed-add-button.js +24 -0
- package/dist/data-table.d.ts +27 -0
- package/dist/data-table.js +152 -0
- package/dist/date-picker.d.ts +19 -0
- package/dist/date-picker.js +234 -0
- package/dist/date-range-picker.d.ts +25 -0
- package/dist/date-range-picker.js +456 -0
- package/dist/dev-auto-fill.d.ts +12 -0
- package/dist/dev-auto-fill.js +22 -0
- package/dist/divider.d.ts +10 -0
- package/dist/divider.js +44 -0
- package/dist/drawer.d.ts +16 -0
- package/dist/drawer.js +111 -0
- package/dist/dropdown-menu.d.ts +20 -0
- package/dist/dropdown-menu.js +94 -0
- package/dist/empty-state.d.ts +13 -0
- package/dist/empty-state.js +24 -0
- package/dist/file-upload.d.ts +32 -0
- package/dist/file-upload.js +212 -0
- package/dist/filter-tabs.d.ts +16 -0
- package/dist/filter-tabs.js +30 -0
- package/dist/footer-action-bar.d.ts +21 -0
- package/dist/footer-action-bar.js +95 -0
- package/dist/form-input.d.ts +16 -0
- package/dist/form-input.js +58 -0
- package/dist/form-textarea.d.ts +13 -0
- package/dist/form-textarea.js +41 -0
- package/dist/icon-button.d.ts +12 -0
- package/dist/icon-button.js +54 -0
- package/dist/icon-picker.d.ts +15 -0
- package/dist/icon-picker.js +311 -0
- package/dist/icon-wrapper.d.ts +15 -0
- package/dist/icon-wrapper.js +52 -0
- package/dist/image-upload.d.ts +24 -0
- package/dist/image-upload.js +122 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.js +155 -0
- package/dist/kbd.d.ts +15 -0
- package/dist/kbd.js +27 -0
- package/dist/mobile-preview.d.ts +36 -0
- package/dist/mobile-preview.js +167 -0
- package/dist/modal.d.ts +19 -0
- package/dist/modal.js +110 -0
- package/dist/multi-select.d.ts +30 -0
- package/dist/multi-select.js +261 -0
- package/dist/number-input.d.ts +21 -0
- package/dist/number-input.js +129 -0
- package/dist/otp-input.d.ts +13 -0
- package/dist/otp-input.js +114 -0
- package/dist/page-header.d.ts +15 -0
- package/dist/page-header.js +43 -0
- package/dist/page-state.d.ts +14 -0
- package/dist/page-state.js +29 -0
- package/dist/pagination.d.ts +20 -0
- package/dist/pagination.js +87 -0
- package/dist/popover.d.ts +11 -0
- package/dist/popover.js +70 -0
- package/dist/preview-drawer.d.ts +33 -0
- package/dist/preview-drawer.js +74 -0
- package/dist/progress-bar.d.ts +15 -0
- package/dist/progress-bar.js +56 -0
- package/dist/qr-code-display.d.ts +10 -0
- package/dist/qr-code-display.js +43 -0
- package/dist/radio-group.d.ts +19 -0
- package/dist/radio-group.js +78 -0
- package/dist/rating.d.ts +12 -0
- package/dist/rating.js +123 -0
- package/dist/rich-editor.d.ts +13 -0
- package/dist/rich-editor.js +97 -0
- package/dist/search-bar.d.ts +14 -0
- package/dist/search-bar.js +64 -0
- package/dist/section-header.d.ts +12 -0
- package/dist/section-header.js +41 -0
- package/dist/segmented-control.d.ts +24 -0
- package/dist/segmented-control.js +38 -0
- package/dist/select-picker.d.ts +24 -0
- package/dist/select-picker.js +157 -0
- package/dist/skeleton.d.ts +14 -0
- package/dist/skeleton.js +53 -0
- package/dist/slider.d.ts +17 -0
- package/dist/slider.js +151 -0
- package/dist/spinner.d.ts +13 -0
- package/dist/spinner.js +38 -0
- package/dist/stat-card.d.ts +20 -0
- package/dist/stat-card.js +87 -0
- package/dist/stats-summary.d.ts +13 -0
- package/dist/stats-summary.js +28 -0
- package/dist/status-badge.d.ts +19 -0
- package/dist/status-badge.js +41 -0
- package/dist/stepper.d.ts +12 -0
- package/dist/stepper.js +89 -0
- package/dist/tabs.d.ts +18 -0
- package/dist/tabs.js +70 -0
- package/dist/tag.d.ts +23 -0
- package/dist/tag.js +158 -0
- package/dist/time-picker.d.ts +19 -0
- package/dist/time-picker.js +222 -0
- package/dist/timeline.d.ts +15 -0
- package/dist/timeline.js +49 -0
- package/dist/toast.d.ts +18 -0
- package/dist/toast.js +108 -0
- package/dist/toggle-switch.d.ts +12 -0
- package/dist/toggle-switch.js +34 -0
- package/dist/tooltip.d.ts +9 -0
- package/dist/tooltip.js +69 -0
- package/dist/trip-day-map-lazy.d.ts +15 -0
- package/dist/trip-day-map-lazy.js +16 -0
- package/dist/trip-day-map.d.ts +15 -0
- package/dist/trip-day-map.js +62 -0
- package/package.json +73 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
__spreadValues
|
|
4
|
+
} from "./chunk-ORMEWXMH.js";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
const defaultLabels = {
|
|
7
|
+
showing: (from, to, total) => `\u0E41\u0E2A\u0E14\u0E07 ${from}\u2013${to} \u0E08\u0E32\u0E01 ${total} \u0E23\u0E32\u0E22\u0E01\u0E32\u0E23`,
|
|
8
|
+
page: (current, total) => `\u0E2B\u0E19\u0E49\u0E32 ${current} \u0E08\u0E32\u0E01 ${total}`,
|
|
9
|
+
prevPage: "\u0E2B\u0E19\u0E49\u0E32\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32",
|
|
10
|
+
nextPage: "\u0E2B\u0E19\u0E49\u0E32\u0E16\u0E31\u0E14\u0E44\u0E1B",
|
|
11
|
+
pageLabel: (page) => `\u0E2B\u0E19\u0E49\u0E32 ${page}`,
|
|
12
|
+
nav: "\u0E01\u0E32\u0E23\u0E41\u0E1A\u0E48\u0E07\u0E2B\u0E19\u0E49\u0E32"
|
|
13
|
+
};
|
|
14
|
+
function Pagination({
|
|
15
|
+
currentPage,
|
|
16
|
+
totalPages,
|
|
17
|
+
onPageChange,
|
|
18
|
+
totalItems,
|
|
19
|
+
pageSize,
|
|
20
|
+
labels = {}
|
|
21
|
+
}) {
|
|
22
|
+
const L = __spreadValues(__spreadValues({}, defaultLabels), labels);
|
|
23
|
+
const pages = [];
|
|
24
|
+
const maxVisible = 5;
|
|
25
|
+
let start = Math.max(1, currentPage - 2);
|
|
26
|
+
let end = Math.min(totalPages, start + maxVisible - 1);
|
|
27
|
+
if (end - start < maxVisible - 1) start = Math.max(1, end - maxVisible + 1);
|
|
28
|
+
if (start > 1) {
|
|
29
|
+
pages.push(1);
|
|
30
|
+
if (start > 2) pages.push(null);
|
|
31
|
+
}
|
|
32
|
+
for (let i = start; i <= end; i++) pages.push(i);
|
|
33
|
+
if (end < totalPages) {
|
|
34
|
+
if (end < totalPages - 1) pages.push(null);
|
|
35
|
+
pages.push(totalPages);
|
|
36
|
+
}
|
|
37
|
+
const showCount = totalItems != null && pageSize != null;
|
|
38
|
+
const from = showCount ? (currentPage - 1) * pageSize + 1 : null;
|
|
39
|
+
const to = showCount ? Math.min(currentPage * pageSize, totalItems) : null;
|
|
40
|
+
return /* @__PURE__ */ jsxs("nav", { className: "flex items-center justify-between px-1", "aria-label": L.nav, children: [
|
|
41
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-on-surface-variant", "aria-live": "polite", "aria-atomic": "true", children: showCount ? L.showing(from, to, totalItems) : L.page(currentPage, totalPages) }),
|
|
42
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
"button",
|
|
45
|
+
{
|
|
46
|
+
type: "button",
|
|
47
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
48
|
+
disabled: currentPage === 1,
|
|
49
|
+
"aria-label": L.prevPage,
|
|
50
|
+
className: "p-2 rounded-lg border border-outline-variant/20 hover:bg-surface-container-low disabled:opacity-50 disabled:cursor-not-allowed transition-colors active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
|
|
51
|
+
children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-base leading-none", "aria-hidden": "true", children: "chevron_left" })
|
|
52
|
+
}
|
|
53
|
+
),
|
|
54
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", role: "list", children: pages.map((page, idx) => {
|
|
55
|
+
if (page === null) {
|
|
56
|
+
return /* @__PURE__ */ jsx("span", { className: "px-2 text-on-surface-variant text-sm", "aria-hidden": "true", children: "\u2026" }, `ellipsis-${idx}`);
|
|
57
|
+
}
|
|
58
|
+
return /* @__PURE__ */ jsx(
|
|
59
|
+
"button",
|
|
60
|
+
{
|
|
61
|
+
type: "button",
|
|
62
|
+
onClick: () => onPageChange(page),
|
|
63
|
+
"aria-label": L.pageLabel(page),
|
|
64
|
+
"aria-current": currentPage === page ? "page" : void 0,
|
|
65
|
+
className: `w-9 h-9 rounded-lg text-sm font-medium transition-colors active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 ${currentPage === page ? "bg-primary text-on-primary" : "border border-outline-variant/20 text-on-surface hover:bg-surface-container-low"}`,
|
|
66
|
+
children: page
|
|
67
|
+
},
|
|
68
|
+
page
|
|
69
|
+
);
|
|
70
|
+
}) }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"button",
|
|
73
|
+
{
|
|
74
|
+
type: "button",
|
|
75
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
76
|
+
disabled: currentPage === totalPages,
|
|
77
|
+
"aria-label": L.nextPage,
|
|
78
|
+
className: "p-2 rounded-lg border border-outline-variant/20 hover:bg-surface-container-low disabled:opacity-50 disabled:cursor-not-allowed transition-colors active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30",
|
|
79
|
+
children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-base leading-none", "aria-hidden": "true", children: "chevron_right" })
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] })
|
|
83
|
+
] });
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
Pagination
|
|
87
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface PopoverProps {
|
|
2
|
+
trigger: React.ReactNode;
|
|
3
|
+
children: React.ReactNode;
|
|
4
|
+
placement?: "top" | "bottom" | "left" | "right";
|
|
5
|
+
align?: "start" | "center" | "end";
|
|
6
|
+
className?: string;
|
|
7
|
+
width?: number | "auto";
|
|
8
|
+
}
|
|
9
|
+
declare function Popover({ trigger, children, placement, align, className, width, }: PopoverProps): React.ReactNode;
|
|
10
|
+
|
|
11
|
+
export { Popover };
|
package/dist/popover.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./chunk-ORMEWXMH.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
function getPositionClass(placement, align) {
|
|
6
|
+
if (placement === "bottom") {
|
|
7
|
+
const alignClass = align === "start" ? "left-0" : align === "center" ? "left-1/2 -translate-x-1/2" : "right-0";
|
|
8
|
+
return `top-full mt-2 ${alignClass}`;
|
|
9
|
+
}
|
|
10
|
+
if (placement === "top") {
|
|
11
|
+
const alignClass = align === "start" ? "left-0" : align === "center" ? "left-1/2 -translate-x-1/2" : "right-0";
|
|
12
|
+
return `bottom-full mb-2 ${alignClass}`;
|
|
13
|
+
}
|
|
14
|
+
if (placement === "left") {
|
|
15
|
+
return "right-full mr-2 top-0";
|
|
16
|
+
}
|
|
17
|
+
return "left-full ml-2 top-0";
|
|
18
|
+
}
|
|
19
|
+
function Popover({
|
|
20
|
+
trigger,
|
|
21
|
+
children,
|
|
22
|
+
placement = "bottom",
|
|
23
|
+
align = "start",
|
|
24
|
+
className = "",
|
|
25
|
+
width = "auto"
|
|
26
|
+
}) {
|
|
27
|
+
const [open, setOpen] = useState(false);
|
|
28
|
+
const containerRef = useRef(null);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!open) return;
|
|
31
|
+
const handleMouseDown = (e) => {
|
|
32
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
33
|
+
setOpen(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const handleKeyDown = (e) => {
|
|
37
|
+
if (e.key === "Escape") {
|
|
38
|
+
setOpen(false);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
document.addEventListener("mousedown", handleMouseDown);
|
|
42
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
43
|
+
return () => {
|
|
44
|
+
document.removeEventListener("mousedown", handleMouseDown);
|
|
45
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
46
|
+
};
|
|
47
|
+
}, [open]);
|
|
48
|
+
const positionClass = getPositionClass(placement, align);
|
|
49
|
+
return /* @__PURE__ */ jsxs("div", { ref: containerRef, className: "relative inline-block", children: [
|
|
50
|
+
/* @__PURE__ */ jsx(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
onClick: () => setOpen((v) => !v),
|
|
54
|
+
style: { display: "contents" },
|
|
55
|
+
children: trigger
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
open && /* @__PURE__ */ jsx(
|
|
59
|
+
"div",
|
|
60
|
+
{
|
|
61
|
+
className: `absolute z-50 bg-surface rounded-2xl shadow-xl border border-outline-variant/20 p-4 animate-in fade-in zoom-in-95 duration-150 ${positionClass} ${className}`,
|
|
62
|
+
style: width !== "auto" ? { width } : void 0,
|
|
63
|
+
children
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] });
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
Popover
|
|
70
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
interface DayLite {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
date: string | null;
|
|
5
|
+
coverImageUrl: string | null;
|
|
6
|
+
activities: {
|
|
7
|
+
id: string;
|
|
8
|
+
time: string | null;
|
|
9
|
+
name: string;
|
|
10
|
+
description: string | null;
|
|
11
|
+
emoji: string | null;
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
interface PreviewDrawerProps {
|
|
15
|
+
open: boolean;
|
|
16
|
+
onClose: () => void;
|
|
17
|
+
title: string;
|
|
18
|
+
startDate: string;
|
|
19
|
+
endDate: string;
|
|
20
|
+
totalDays: number;
|
|
21
|
+
travelersCount: number;
|
|
22
|
+
coverImageUrl: string | null;
|
|
23
|
+
airlineName: string | null;
|
|
24
|
+
accommodationsCount: number;
|
|
25
|
+
countdownDays: number;
|
|
26
|
+
days: DayLite[];
|
|
27
|
+
drawerTitle?: string;
|
|
28
|
+
closeAriaLabel?: string;
|
|
29
|
+
previewOnlyLabel?: string;
|
|
30
|
+
}
|
|
31
|
+
declare function PreviewDrawer({ open, onClose, drawerTitle, closeAriaLabel, previewOnlyLabel, ...previewProps }: PreviewDrawerProps): React.ReactNode;
|
|
32
|
+
|
|
33
|
+
export { PreviewDrawer };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
__objRest,
|
|
4
|
+
__spreadProps,
|
|
5
|
+
__spreadValues
|
|
6
|
+
} from "./chunk-ORMEWXMH.js";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { useRef, useState } from "react";
|
|
9
|
+
import { MobilePreview } from "./mobile-preview";
|
|
10
|
+
import { IconButton } from "./icon-button";
|
|
11
|
+
function PreviewDrawer(_a) {
|
|
12
|
+
var _b = _a, {
|
|
13
|
+
open,
|
|
14
|
+
onClose,
|
|
15
|
+
drawerTitle = "\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E1A\u0E19\u0E21\u0E37\u0E2D\u0E16\u0E37\u0E2D",
|
|
16
|
+
closeAriaLabel = "\u0E1B\u0E34\u0E14",
|
|
17
|
+
previewOnlyLabel = "\u0E15\u0E31\u0E27\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E40\u0E17\u0E48\u0E32\u0E19\u0E31\u0E49\u0E19"
|
|
18
|
+
} = _b, previewProps = __objRest(_b, [
|
|
19
|
+
"open",
|
|
20
|
+
"onClose",
|
|
21
|
+
"drawerTitle",
|
|
22
|
+
"closeAriaLabel",
|
|
23
|
+
"previewOnlyLabel"
|
|
24
|
+
]);
|
|
25
|
+
const [activeDay, setActiveDay] = useState(0);
|
|
26
|
+
const touchStartX = useRef(0);
|
|
27
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
|
+
/* @__PURE__ */ jsx(
|
|
29
|
+
"div",
|
|
30
|
+
{
|
|
31
|
+
className: `fixed inset-0 z-49 transition-opacity duration-300 ${open ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"}`,
|
|
32
|
+
onClick: onClose,
|
|
33
|
+
"aria-hidden": true
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
/* @__PURE__ */ jsxs(
|
|
37
|
+
"div",
|
|
38
|
+
{
|
|
39
|
+
className: `fixed top-0 right-0 h-full w-90 z-50 bg-surface border-l border-outline-variant/40 shadow-2xl flex flex-col transition-transform duration-300 ease-in-out ${open ? "translate-x-0" : "translate-x-full"}`,
|
|
40
|
+
onTouchStart: (e) => {
|
|
41
|
+
touchStartX.current = e.touches[0].clientX;
|
|
42
|
+
},
|
|
43
|
+
onTouchEnd: (e) => {
|
|
44
|
+
if (e.changedTouches[0].clientX - touchStartX.current > 80) onClose();
|
|
45
|
+
},
|
|
46
|
+
"aria-labelledby": "preview-drawer-title",
|
|
47
|
+
role: "dialog",
|
|
48
|
+
"aria-modal": true,
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-outline-variant/30 shrink-0", children: [
|
|
51
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
52
|
+
/* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-lg text-primary", children: "phone_iphone" }),
|
|
53
|
+
/* @__PURE__ */ jsx("h2", { id: "preview-drawer-title", className: "text-sm font-bold text-on-surface", children: drawerTitle })
|
|
54
|
+
] }),
|
|
55
|
+
/* @__PURE__ */ jsx(IconButton, { icon: "close", variant: "ghost", size: "sm", onClick: onClose, "aria-label": closeAriaLabel })
|
|
56
|
+
] }),
|
|
57
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 flex flex-col items-center gap-3", children: [
|
|
58
|
+
/* @__PURE__ */ jsx(
|
|
59
|
+
MobilePreview,
|
|
60
|
+
__spreadProps(__spreadValues({}, previewProps), {
|
|
61
|
+
activeDayIndex: activeDay,
|
|
62
|
+
onActiveDayChange: setActiveDay
|
|
63
|
+
})
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx("p", { className: "text-[10px] text-on-surface-variant uppercase tracking-wider font-semibold", children: previewOnlyLabel })
|
|
66
|
+
] })
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
] });
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
PreviewDrawer
|
|
74
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface ProgressBarProps {
|
|
4
|
+
value: number;
|
|
5
|
+
max?: number;
|
|
6
|
+
label?: string;
|
|
7
|
+
showValue?: boolean;
|
|
8
|
+
size?: "sm" | "md" | "lg";
|
|
9
|
+
color?: "primary" | "emerald" | "amber" | "red";
|
|
10
|
+
animated?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
declare function ProgressBar({ value, max, label, showValue, size, color, animated, className, }: ProgressBarProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { ProgressBar };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import "./chunk-ORMEWXMH.js";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
const SIZE_CLASSES = {
|
|
4
|
+
sm: "h-1.5",
|
|
5
|
+
md: "h-2.5",
|
|
6
|
+
lg: "h-4"
|
|
7
|
+
};
|
|
8
|
+
const COLOR_CLASSES = {
|
|
9
|
+
primary: "bg-primary",
|
|
10
|
+
emerald: "bg-emerald-500",
|
|
11
|
+
amber: "bg-amber-500",
|
|
12
|
+
red: "bg-red-500"
|
|
13
|
+
};
|
|
14
|
+
function ProgressBar({
|
|
15
|
+
value,
|
|
16
|
+
max = 100,
|
|
17
|
+
label,
|
|
18
|
+
showValue = false,
|
|
19
|
+
size = "md",
|
|
20
|
+
color = "primary",
|
|
21
|
+
animated = false,
|
|
22
|
+
className = ""
|
|
23
|
+
}) {
|
|
24
|
+
const percentage = Math.min(100, Math.max(0, value / max * 100));
|
|
25
|
+
const displayPercent = Math.round(percentage);
|
|
26
|
+
return /* @__PURE__ */ jsxs("div", { className: `w-full ${className}`, children: [
|
|
27
|
+
(label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-1.5", children: [
|
|
28
|
+
label && /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant", children: label }),
|
|
29
|
+
showValue && /* @__PURE__ */ jsxs("span", { className: "text-xs text-on-surface-variant tabular-nums ml-auto", children: [
|
|
30
|
+
displayPercent,
|
|
31
|
+
"%"
|
|
32
|
+
] })
|
|
33
|
+
] }),
|
|
34
|
+
/* @__PURE__ */ jsx(
|
|
35
|
+
"div",
|
|
36
|
+
{
|
|
37
|
+
className: `w-full rounded-full bg-surface-container-high ${SIZE_CLASSES[size]}`,
|
|
38
|
+
role: "progressbar",
|
|
39
|
+
"aria-valuenow": value,
|
|
40
|
+
"aria-valuemin": 0,
|
|
41
|
+
"aria-valuemax": max,
|
|
42
|
+
"aria-label": label,
|
|
43
|
+
children: /* @__PURE__ */ jsx(
|
|
44
|
+
"div",
|
|
45
|
+
{
|
|
46
|
+
className: `${SIZE_CLASSES[size]} rounded-full transition-all duration-500 ${COLOR_CLASSES[color]} ${animated ? "animate-pulse" : ""}`,
|
|
47
|
+
style: { width: `${percentage}%` }
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
] });
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
ProgressBar
|
|
56
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface QRCodeDisplayProps {
|
|
2
|
+
url: string;
|
|
3
|
+
size?: number;
|
|
4
|
+
icon?: string;
|
|
5
|
+
iconImageUrl?: string;
|
|
6
|
+
iconSize?: number;
|
|
7
|
+
}
|
|
8
|
+
declare function QRCodeDisplay({ url, size, icon, iconImageUrl, iconSize }: QRCodeDisplayProps): React.ReactNode;
|
|
9
|
+
|
|
10
|
+
export { QRCodeDisplay };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./chunk-ORMEWXMH.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import QRCode from "qrcode";
|
|
6
|
+
function QRCodeDisplay({ url, size = 200, icon, iconImageUrl, iconSize }) {
|
|
7
|
+
const [dataUrl, setDataUrl] = useState("");
|
|
8
|
+
const hasOverlay = !!(icon || iconImageUrl);
|
|
9
|
+
const resolvedIconSize = iconSize != null ? iconSize : Math.round(size * 0.22);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
QRCode.toDataURL(url, {
|
|
12
|
+
width: size,
|
|
13
|
+
margin: 2,
|
|
14
|
+
color: { dark: "#1e293b", light: "#ffffff" },
|
|
15
|
+
errorCorrectionLevel: hasOverlay ? "H" : "M"
|
|
16
|
+
}).then(setDataUrl).catch(() => {
|
|
17
|
+
});
|
|
18
|
+
}, [url, size, hasOverlay]);
|
|
19
|
+
if (!dataUrl) {
|
|
20
|
+
return /* @__PURE__ */ jsx("div", { className: "animate-pulse bg-surface-container rounded-xl", style: { width: size, height: size } });
|
|
21
|
+
}
|
|
22
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative inline-flex", style: { width: size, height: size }, children: [
|
|
23
|
+
/* @__PURE__ */ jsx("img", { src: dataUrl, alt: "QR Code", width: size, height: size, className: "rounded-xl" }),
|
|
24
|
+
hasOverlay && /* @__PURE__ */ jsx(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white rounded-xl flex items-center justify-center shadow-lg ring-1 ring-black/8 overflow-hidden",
|
|
28
|
+
style: { width: resolvedIconSize + 14, height: resolvedIconSize + 14 },
|
|
29
|
+
children: iconImageUrl ? /* @__PURE__ */ jsx("img", { src: iconImageUrl, alt: "logo", width: resolvedIconSize, height: resolvedIconSize, className: "object-contain" }) : /* @__PURE__ */ jsx(
|
|
30
|
+
"span",
|
|
31
|
+
{
|
|
32
|
+
className: "material-symbols-outlined text-primary",
|
|
33
|
+
style: { fontSize: resolvedIconSize, fontVariationSettings: "'FILL' 1" },
|
|
34
|
+
children: icon
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
QRCodeDisplay
|
|
43
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface RadioOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
interface RadioGroupProps {
|
|
7
|
+
label?: string;
|
|
8
|
+
options: RadioOption[];
|
|
9
|
+
value: string;
|
|
10
|
+
onChange: (value: string) => void;
|
|
11
|
+
error?: string;
|
|
12
|
+
required?: boolean;
|
|
13
|
+
orientation?: "vertical" | "horizontal";
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
name?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function RadioGroup({ label, options, value, onChange, error, required, orientation, disabled, name, }: RadioGroupProps): React.ReactNode;
|
|
18
|
+
|
|
19
|
+
export { RadioGroup };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./chunk-ORMEWXMH.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
function RadioGroup({
|
|
5
|
+
label,
|
|
6
|
+
options,
|
|
7
|
+
value,
|
|
8
|
+
onChange,
|
|
9
|
+
error,
|
|
10
|
+
required,
|
|
11
|
+
orientation = "vertical",
|
|
12
|
+
disabled = false,
|
|
13
|
+
name
|
|
14
|
+
}) {
|
|
15
|
+
var _a;
|
|
16
|
+
const resolvedName = (_a = name != null ? name : label) != null ? _a : "radio-group";
|
|
17
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
18
|
+
label && /* @__PURE__ */ jsxs("span", { className: "text-xs font-bold text-on-surface-variant uppercase tracking-widest px-1", children: [
|
|
19
|
+
label,
|
|
20
|
+
required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-0.5", children: "*" })
|
|
21
|
+
] }),
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
"div",
|
|
24
|
+
{
|
|
25
|
+
role: "group",
|
|
26
|
+
"aria-required": required,
|
|
27
|
+
className: `flex ${orientation === "horizontal" ? "flex-row flex-wrap gap-4" : "flex-col gap-3"}`,
|
|
28
|
+
children: options.map((opt) => {
|
|
29
|
+
const isSelected = opt.value === value;
|
|
30
|
+
const isDisabled = disabled;
|
|
31
|
+
return /* @__PURE__ */ jsxs(
|
|
32
|
+
"label",
|
|
33
|
+
{
|
|
34
|
+
className: `flex items-start gap-3 ${isDisabled ? "cursor-not-allowed opacity-40" : "cursor-pointer"}`,
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsxs("span", { className: "relative shrink-0 mt-0.5", children: [
|
|
37
|
+
/* @__PURE__ */ jsx(
|
|
38
|
+
"input",
|
|
39
|
+
{
|
|
40
|
+
type: "radio",
|
|
41
|
+
name: resolvedName,
|
|
42
|
+
value: opt.value,
|
|
43
|
+
checked: isSelected,
|
|
44
|
+
onChange: () => !isDisabled && onChange(opt.value),
|
|
45
|
+
disabled: isDisabled,
|
|
46
|
+
className: "sr-only peer"
|
|
47
|
+
}
|
|
48
|
+
),
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
"span",
|
|
51
|
+
{
|
|
52
|
+
className: `flex items-center justify-center w-5 h-5 rounded-full border-2 transition-all
|
|
53
|
+
peer-focus-visible:ring-2 peer-focus-visible:ring-primary/20
|
|
54
|
+
${isSelected ? "border-primary" : "bg-surface border-outline-variant hover:border-primary/60"}`,
|
|
55
|
+
children: isSelected && /* @__PURE__ */ jsx("span", { className: "w-2.5 h-2.5 rounded-full bg-primary shrink-0" })
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
] }),
|
|
59
|
+
(opt.label || opt.description) && /* @__PURE__ */ jsxs("span", { className: "flex flex-col gap-0.5", children: [
|
|
60
|
+
opt.label && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-on-surface leading-snug", children: opt.label }),
|
|
61
|
+
opt.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant leading-snug", children: opt.description })
|
|
62
|
+
] })
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
opt.value
|
|
66
|
+
);
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
error && /* @__PURE__ */ jsxs("p", { className: "text-xs text-red-500 flex items-center gap-1 px-1", children: [
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-sm", children: "error" }),
|
|
72
|
+
error
|
|
73
|
+
] })
|
|
74
|
+
] });
|
|
75
|
+
}
|
|
76
|
+
export {
|
|
77
|
+
RadioGroup
|
|
78
|
+
};
|
package/dist/rating.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface RatingProps {
|
|
2
|
+
value: number;
|
|
3
|
+
onChange?: (value: number) => void;
|
|
4
|
+
max?: number;
|
|
5
|
+
size?: "sm" | "md" | "lg";
|
|
6
|
+
showValue?: boolean;
|
|
7
|
+
label?: string;
|
|
8
|
+
readOnly?: boolean;
|
|
9
|
+
}
|
|
10
|
+
declare function Rating({ value, onChange, max, size, showValue, label, readOnly, }: RatingProps): React.ReactNode;
|
|
11
|
+
|
|
12
|
+
export { Rating, type RatingProps };
|
package/dist/rating.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "./chunk-ORMEWXMH.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
const SIZE_CLASSES = {
|
|
6
|
+
sm: "text-base",
|
|
7
|
+
md: "text-xl",
|
|
8
|
+
lg: "text-3xl"
|
|
9
|
+
};
|
|
10
|
+
function StarIcon({
|
|
11
|
+
fill,
|
|
12
|
+
sizeClass,
|
|
13
|
+
className = ""
|
|
14
|
+
}) {
|
|
15
|
+
if (fill === "half") {
|
|
16
|
+
return /* @__PURE__ */ jsx(
|
|
17
|
+
"span",
|
|
18
|
+
{
|
|
19
|
+
className: `material-symbols-outlined leading-none ${sizeClass} ${className}`,
|
|
20
|
+
style: { fontVariationSettings: "'FILL' 0" },
|
|
21
|
+
"aria-hidden": "true",
|
|
22
|
+
children: "star_half"
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (fill === "full") {
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
"span",
|
|
29
|
+
{
|
|
30
|
+
className: `material-symbols-outlined leading-none ${sizeClass} ${className}`,
|
|
31
|
+
style: { fontVariationSettings: "'FILL' 1" },
|
|
32
|
+
"aria-hidden": "true",
|
|
33
|
+
children: "star"
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
"span",
|
|
39
|
+
{
|
|
40
|
+
className: `material-symbols-outlined leading-none ${sizeClass} ${className}`,
|
|
41
|
+
style: { fontVariationSettings: "'FILL' 0" },
|
|
42
|
+
"aria-hidden": "true",
|
|
43
|
+
children: "star"
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
function getStarFill(index, value) {
|
|
48
|
+
const starValue = index + 1;
|
|
49
|
+
if (value >= starValue) return "full";
|
|
50
|
+
if (value >= starValue - 0.5) return "half";
|
|
51
|
+
return "empty";
|
|
52
|
+
}
|
|
53
|
+
function Rating({
|
|
54
|
+
value,
|
|
55
|
+
onChange,
|
|
56
|
+
max = 5,
|
|
57
|
+
size = "md",
|
|
58
|
+
showValue = false,
|
|
59
|
+
label,
|
|
60
|
+
readOnly = false
|
|
61
|
+
}) {
|
|
62
|
+
const [hovered, setHovered] = useState(null);
|
|
63
|
+
const isInteractive = !readOnly && !!onChange;
|
|
64
|
+
const sizeClass = SIZE_CLASSES[size];
|
|
65
|
+
const displayValue = hovered !== null ? hovered : value;
|
|
66
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
67
|
+
label && /* @__PURE__ */ jsx("span", { className: "text-xs font-bold text-on-surface-variant uppercase tracking-widest", children: label }),
|
|
68
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
|
|
69
|
+
/* @__PURE__ */ jsx(
|
|
70
|
+
"div",
|
|
71
|
+
{
|
|
72
|
+
className: `flex items-center ${isInteractive ? "cursor-pointer" : ""}`,
|
|
73
|
+
role: isInteractive ? "radiogroup" : void 0,
|
|
74
|
+
"aria-label": label != null ? label : `Rating: ${value} out of ${max}`,
|
|
75
|
+
onMouseLeave: () => isInteractive && setHovered(null),
|
|
76
|
+
onKeyDown: isInteractive ? (e) => {
|
|
77
|
+
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
onChange(Math.min(value + 1, max));
|
|
80
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
81
|
+
e.preventDefault();
|
|
82
|
+
onChange(Math.max(value - 1, 1));
|
|
83
|
+
}
|
|
84
|
+
} : void 0,
|
|
85
|
+
children: Array.from({ length: max }).map((_, i) => {
|
|
86
|
+
const starValue = i + 1;
|
|
87
|
+
const fill = isInteractive && hovered !== null ? hovered >= starValue ? "full" : "empty" : getStarFill(i, displayValue);
|
|
88
|
+
const colorClass = fill === "empty" ? "text-outline-variant" : "text-amber-400";
|
|
89
|
+
if (isInteractive) {
|
|
90
|
+
return /* @__PURE__ */ jsx(
|
|
91
|
+
"button",
|
|
92
|
+
{
|
|
93
|
+
type: "button",
|
|
94
|
+
role: "radio",
|
|
95
|
+
"aria-checked": Math.round(value) === starValue,
|
|
96
|
+
"aria-label": `${starValue} star${starValue !== 1 ? "s" : ""}`,
|
|
97
|
+
className: `${colorClass} transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 rounded active:scale-[0.95]`,
|
|
98
|
+
onMouseEnter: () => setHovered(starValue),
|
|
99
|
+
onClick: () => onChange(starValue),
|
|
100
|
+
children: /* @__PURE__ */ jsx(StarIcon, { fill, sizeClass })
|
|
101
|
+
},
|
|
102
|
+
i
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return /* @__PURE__ */ jsx(
|
|
106
|
+
StarIcon,
|
|
107
|
+
{
|
|
108
|
+
fill,
|
|
109
|
+
sizeClass,
|
|
110
|
+
className: colorClass
|
|
111
|
+
},
|
|
112
|
+
i
|
|
113
|
+
);
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
),
|
|
117
|
+
showValue && /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-sm font-medium text-on-surface-variant", children: value.toFixed(1) })
|
|
118
|
+
] })
|
|
119
|
+
] });
|
|
120
|
+
}
|
|
121
|
+
export {
|
|
122
|
+
Rating
|
|
123
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface RichEditorProps {
|
|
4
|
+
value: string;
|
|
5
|
+
onChange: (html: string) => void;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
minHeight?: number;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
loadingAriaLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
declare function RichEditor({ value, onChange, placeholder, minHeight, disabled, loadingAriaLabel }: RichEditorProps): react_jsx_runtime.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { RichEditor };
|