@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.
Files changed (145) hide show
  1. package/README.md +46 -0
  2. package/dist/accordion.d.ts +18 -0
  3. package/dist/accordion.js +76 -0
  4. package/dist/agreement-modal.d.ts +16 -0
  5. package/dist/agreement-modal.js +67 -0
  6. package/dist/alert.d.ts +13 -0
  7. package/dist/alert.js +47 -0
  8. package/dist/auth-hero.d.ts +7 -0
  9. package/dist/auth-hero.js +63 -0
  10. package/dist/avatar.d.ts +21 -0
  11. package/dist/avatar.js +114 -0
  12. package/dist/badge.d.ts +13 -0
  13. package/dist/badge.js +36 -0
  14. package/dist/banner.d.ts +14 -0
  15. package/dist/banner.js +57 -0
  16. package/dist/breadcrumb.d.ts +15 -0
  17. package/dist/breadcrumb.js +37 -0
  18. package/dist/button.d.ts +15 -0
  19. package/dist/button.js +81 -0
  20. package/dist/card.d.ts +30 -0
  21. package/dist/card.js +66 -0
  22. package/dist/change-summary-modal.d.ts +35 -0
  23. package/dist/change-summary-modal.js +128 -0
  24. package/dist/channel-badge.d.ts +8 -0
  25. package/dist/channel-badge.js +17 -0
  26. package/dist/checkbox.d.ts +28 -0
  27. package/dist/checkbox.js +108 -0
  28. package/dist/chunk-ORMEWXMH.js +37 -0
  29. package/dist/color-picker.d.ts +15 -0
  30. package/dist/color-picker.js +159 -0
  31. package/dist/confirm-dialog.d.ts +23 -0
  32. package/dist/confirm-dialog.js +108 -0
  33. package/dist/copy-button.d.ts +13 -0
  34. package/dist/copy-button.js +69 -0
  35. package/dist/dashed-add-button.d.ts +8 -0
  36. package/dist/dashed-add-button.js +24 -0
  37. package/dist/data-table.d.ts +27 -0
  38. package/dist/data-table.js +152 -0
  39. package/dist/date-picker.d.ts +19 -0
  40. package/dist/date-picker.js +234 -0
  41. package/dist/date-range-picker.d.ts +25 -0
  42. package/dist/date-range-picker.js +456 -0
  43. package/dist/dev-auto-fill.d.ts +12 -0
  44. package/dist/dev-auto-fill.js +22 -0
  45. package/dist/divider.d.ts +10 -0
  46. package/dist/divider.js +44 -0
  47. package/dist/drawer.d.ts +16 -0
  48. package/dist/drawer.js +111 -0
  49. package/dist/dropdown-menu.d.ts +20 -0
  50. package/dist/dropdown-menu.js +94 -0
  51. package/dist/empty-state.d.ts +13 -0
  52. package/dist/empty-state.js +24 -0
  53. package/dist/file-upload.d.ts +32 -0
  54. package/dist/file-upload.js +212 -0
  55. package/dist/filter-tabs.d.ts +16 -0
  56. package/dist/filter-tabs.js +30 -0
  57. package/dist/footer-action-bar.d.ts +21 -0
  58. package/dist/footer-action-bar.js +95 -0
  59. package/dist/form-input.d.ts +16 -0
  60. package/dist/form-input.js +58 -0
  61. package/dist/form-textarea.d.ts +13 -0
  62. package/dist/form-textarea.js +41 -0
  63. package/dist/icon-button.d.ts +12 -0
  64. package/dist/icon-button.js +54 -0
  65. package/dist/icon-picker.d.ts +15 -0
  66. package/dist/icon-picker.js +311 -0
  67. package/dist/icon-wrapper.d.ts +15 -0
  68. package/dist/icon-wrapper.js +52 -0
  69. package/dist/image-upload.d.ts +24 -0
  70. package/dist/image-upload.js +122 -0
  71. package/dist/index.d.ts +71 -0
  72. package/dist/index.js +155 -0
  73. package/dist/kbd.d.ts +15 -0
  74. package/dist/kbd.js +27 -0
  75. package/dist/mobile-preview.d.ts +36 -0
  76. package/dist/mobile-preview.js +167 -0
  77. package/dist/modal.d.ts +19 -0
  78. package/dist/modal.js +110 -0
  79. package/dist/multi-select.d.ts +30 -0
  80. package/dist/multi-select.js +261 -0
  81. package/dist/number-input.d.ts +21 -0
  82. package/dist/number-input.js +129 -0
  83. package/dist/otp-input.d.ts +13 -0
  84. package/dist/otp-input.js +114 -0
  85. package/dist/page-header.d.ts +15 -0
  86. package/dist/page-header.js +43 -0
  87. package/dist/page-state.d.ts +14 -0
  88. package/dist/page-state.js +29 -0
  89. package/dist/pagination.d.ts +20 -0
  90. package/dist/pagination.js +87 -0
  91. package/dist/popover.d.ts +11 -0
  92. package/dist/popover.js +70 -0
  93. package/dist/preview-drawer.d.ts +33 -0
  94. package/dist/preview-drawer.js +74 -0
  95. package/dist/progress-bar.d.ts +15 -0
  96. package/dist/progress-bar.js +56 -0
  97. package/dist/qr-code-display.d.ts +10 -0
  98. package/dist/qr-code-display.js +43 -0
  99. package/dist/radio-group.d.ts +19 -0
  100. package/dist/radio-group.js +78 -0
  101. package/dist/rating.d.ts +12 -0
  102. package/dist/rating.js +123 -0
  103. package/dist/rich-editor.d.ts +13 -0
  104. package/dist/rich-editor.js +97 -0
  105. package/dist/search-bar.d.ts +14 -0
  106. package/dist/search-bar.js +64 -0
  107. package/dist/section-header.d.ts +12 -0
  108. package/dist/section-header.js +41 -0
  109. package/dist/segmented-control.d.ts +24 -0
  110. package/dist/segmented-control.js +38 -0
  111. package/dist/select-picker.d.ts +24 -0
  112. package/dist/select-picker.js +157 -0
  113. package/dist/skeleton.d.ts +14 -0
  114. package/dist/skeleton.js +53 -0
  115. package/dist/slider.d.ts +17 -0
  116. package/dist/slider.js +151 -0
  117. package/dist/spinner.d.ts +13 -0
  118. package/dist/spinner.js +38 -0
  119. package/dist/stat-card.d.ts +20 -0
  120. package/dist/stat-card.js +87 -0
  121. package/dist/stats-summary.d.ts +13 -0
  122. package/dist/stats-summary.js +28 -0
  123. package/dist/status-badge.d.ts +19 -0
  124. package/dist/status-badge.js +41 -0
  125. package/dist/stepper.d.ts +12 -0
  126. package/dist/stepper.js +89 -0
  127. package/dist/tabs.d.ts +18 -0
  128. package/dist/tabs.js +70 -0
  129. package/dist/tag.d.ts +23 -0
  130. package/dist/tag.js +158 -0
  131. package/dist/time-picker.d.ts +19 -0
  132. package/dist/time-picker.js +222 -0
  133. package/dist/timeline.d.ts +15 -0
  134. package/dist/timeline.js +49 -0
  135. package/dist/toast.d.ts +18 -0
  136. package/dist/toast.js +108 -0
  137. package/dist/toggle-switch.d.ts +12 -0
  138. package/dist/toggle-switch.js +34 -0
  139. package/dist/tooltip.d.ts +9 -0
  140. package/dist/tooltip.js +69 -0
  141. package/dist/trip-day-map-lazy.d.ts +15 -0
  142. package/dist/trip-day-map-lazy.js +16 -0
  143. package/dist/trip-day-map.d.ts +15 -0
  144. package/dist/trip-day-map.js +62 -0
  145. package/package.json +73 -0
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @pichetch08/trip-ui
2
+
3
+ Shared React component library for Trip applications, built with Tailwind v4 and Material Design 3 tokens.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @pichetch08/trip-ui
9
+ ```
10
+
11
+ ### Peer dependencies
12
+
13
+ ```bash
14
+ npm install react react-dom clsx tailwind-merge
15
+ ```
16
+
17
+ > `next` is optional — only required if you use Next.js-specific components (e.g. `TripDayMapLazy`).
18
+
19
+ ## Usage
20
+
21
+ ```tsx
22
+ import { Button, Modal, TimePicker, RichEditor } from "@pichetch08/trip-ui";
23
+ ```
24
+
25
+ All components are tree-shakeable. Import only what you need.
26
+
27
+ ## Requirements
28
+
29
+ - React ≥ 19
30
+ - Tailwind CSS v4 configured in your project with the MD3 design tokens
31
+ - Material Symbols icon font loaded in your app
32
+
33
+ ## Components
34
+
35
+ Over 70 shared components including:
36
+
37
+ - **Form**: `TextField`, `Select`, `TimePicker`, `DatePicker`, `NumberInput`, `Slider`, `RichEditor`, `FileUpload`, `OtpInput`, `TagGroup`, `RadioGroup`, `SegmentedControl`, `MultiSelect`
38
+ - **Feedback**: `Modal`, `Drawer`, `PreviewDrawer`, `Toast`, `Alert`, `Spinner`, `ProgressBar`, `Skeleton`, `PageState`
39
+ - **Display**: `Tag`, `StatusBadge`, `StatCard`, `Tooltip`, `Popover`, `Timeline`, `Stepper`, `Rating`, `Tabs`
40
+ - **Layout**: `SectionHeader`, `StatsSummary`, `MobilePreview`
41
+ - **Maps**: `TripDayMap`, `TripDayMapLazy`
42
+ - **Misc**: `QrCodeDisplay`, `SearchBar`, `Kbd`
43
+
44
+ ## License
45
+
46
+ MIT
@@ -0,0 +1,18 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface AccordionItem {
4
+ id: string;
5
+ title: string;
6
+ icon?: string;
7
+ subtitle?: string;
8
+ badge?: string;
9
+ children: React.ReactNode;
10
+ }
11
+ interface AccordionProps {
12
+ items: AccordionItem[];
13
+ defaultOpen?: string[];
14
+ allowMultiple?: boolean;
15
+ }
16
+ declare function Accordion({ items, defaultOpen, allowMultiple, }: AccordionProps): react_jsx_runtime.JSX.Element;
17
+
18
+ export { Accordion, type AccordionItem };
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useState } from "react";
5
+ function Accordion({
6
+ items,
7
+ defaultOpen = [],
8
+ allowMultiple = false
9
+ }) {
10
+ const [openIds, setOpenIds] = useState(new Set(defaultOpen));
11
+ function toggle(id) {
12
+ setOpenIds((prev) => {
13
+ const next = new Set(prev);
14
+ if (next.has(id)) {
15
+ next.delete(id);
16
+ } else {
17
+ if (!allowMultiple) {
18
+ next.clear();
19
+ }
20
+ next.add(id);
21
+ }
22
+ return next;
23
+ });
24
+ }
25
+ return /* @__PURE__ */ jsx("div", { children: items.map((item) => {
26
+ const isOpen = openIds.has(item.id);
27
+ return /* @__PURE__ */ jsxs(
28
+ "div",
29
+ {
30
+ className: "rounded-2xl border border-outline-variant/30 bg-surface shadow-sm overflow-hidden mb-3",
31
+ children: [
32
+ /* @__PURE__ */ jsxs(
33
+ "button",
34
+ {
35
+ id: `accordion-btn-${item.id}`,
36
+ type: "button",
37
+ onClick: () => toggle(item.id),
38
+ "aria-expanded": isOpen,
39
+ "aria-controls": `accordion-panel-${item.id}`,
40
+ className: "w-full flex items-center gap-3 px-5 py-4 text-left hover:bg-surface-container-low/50 active:bg-surface-container-low transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 focus-visible:ring-inset",
41
+ children: [
42
+ item.icon && /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-xl text-on-surface-variant", children: item.icon }),
43
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
44
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-on-surface block", children: item.title }),
45
+ item.subtitle && /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant block mt-0.5", children: item.subtitle })
46
+ ] }),
47
+ item.badge && !isOpen && /* @__PURE__ */ jsx("span", { className: "bg-primary/10 text-primary text-xs font-medium px-2 py-0.5 rounded-full shrink-0", children: item.badge }),
48
+ /* @__PURE__ */ jsx(
49
+ "span",
50
+ {
51
+ className: `material-symbols-outlined text-xl text-on-surface-variant shrink-0 transition-transform duration-300 ${isOpen ? "rotate-180" : "rotate-0"}`,
52
+ children: "expand_more"
53
+ }
54
+ )
55
+ ]
56
+ }
57
+ ),
58
+ /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ id: `accordion-panel-${item.id}`,
62
+ role: "region",
63
+ "aria-labelledby": `accordion-btn-${item.id}`,
64
+ className: `grid transition-all duration-300 ease-in-out ${isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"}`,
65
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "px-5 pb-5 pt-1", children: item.children }) })
66
+ }
67
+ )
68
+ ]
69
+ },
70
+ item.id
71
+ );
72
+ }) });
73
+ }
74
+ export {
75
+ Accordion
76
+ };
@@ -0,0 +1,16 @@
1
+ interface AgreementModalProps {
2
+ open: boolean;
3
+ onClose: () => void;
4
+ onAccept: () => void;
5
+ title: string;
6
+ children: React.ReactNode;
7
+ scrollHintText?: string;
8
+ scrollDownText?: string;
9
+ readCompleteText?: string;
10
+ closeLabel?: string;
11
+ acceptLabel?: string;
12
+ closeAriaLabel?: string;
13
+ }
14
+ declare function AgreementModal({ open, onClose, onAccept, title, children, scrollHintText, scrollDownText, readCompleteText, closeLabel, acceptLabel, closeAriaLabel, }: AgreementModalProps): React.ReactNode;
15
+
16
+ export { AgreementModal };
@@ -0,0 +1,67 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useRef, useState, useEffect, useCallback } from "react";
5
+ import { Button } from "./button";
6
+ import { IconButton } from "./icon-button";
7
+ function AgreementModal({
8
+ open,
9
+ onClose,
10
+ onAccept,
11
+ title,
12
+ children,
13
+ scrollHintText = "\u0E01\u0E23\u0E38\u0E13\u0E32\u0E40\u0E25\u0E37\u0E48\u0E2D\u0E19\u0E2D\u0E48\u0E32\u0E19\u0E08\u0E19\u0E08\u0E1A\u0E01\u0E48\u0E2D\u0E19\u0E01\u0E14\u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A",
14
+ scrollDownText = "\u0E40\u0E25\u0E37\u0E48\u0E2D\u0E19\u0E25\u0E07\u0E40\u0E1E\u0E37\u0E48\u0E2D\u0E2D\u0E48\u0E32\u0E19\u0E15\u0E48\u0E2D",
15
+ readCompleteText = "\u0E2D\u0E48\u0E32\u0E19\u0E04\u0E23\u0E1A\u0E41\u0E25\u0E49\u0E27",
16
+ closeLabel = "\u0E1B\u0E34\u0E14",
17
+ acceptLabel = "\u0E09\u0E31\u0E19\u0E44\u0E14\u0E49\u0E2D\u0E48\u0E32\u0E19\u0E41\u0E25\u0E30\u0E22\u0E2D\u0E21\u0E23\u0E31\u0E1A",
18
+ closeAriaLabel = "\u0E1B\u0E34\u0E14"
19
+ }) {
20
+ const scrollRef = useRef(null);
21
+ const [scrolledToBottom, setScrolledToBottom] = useState(false);
22
+ const handleScroll = useCallback(() => {
23
+ const el = scrollRef.current;
24
+ if (!el) return;
25
+ const isBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;
26
+ if (isBottom) setScrolledToBottom(true);
27
+ }, []);
28
+ useEffect(() => {
29
+ if (open) setScrolledToBottom(false);
30
+ }, [open]);
31
+ if (!open) return null;
32
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-100 flex items-center justify-center p-4", children: [
33
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/50 backdrop-blur-sm cursor-pointer", onClick: onClose }),
34
+ /* @__PURE__ */ jsxs("div", { className: "relative bg-surface rounded-2xl shadow-2xl w-full max-w-2xl max-h-[85vh] flex flex-col overflow-hidden", children: [
35
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-outline-variant", children: [
36
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-bold text-on-surface", children: title }),
37
+ /* @__PURE__ */ jsx(IconButton, { icon: "close", variant: "ghost", size: "sm", onClick: onClose, "aria-label": closeAriaLabel })
38
+ ] }),
39
+ /* @__PURE__ */ jsx(
40
+ "div",
41
+ {
42
+ ref: scrollRef,
43
+ onScroll: handleScroll,
44
+ className: "flex-1 overflow-y-auto px-6 py-6 text-sm text-on-surface-variant leading-relaxed",
45
+ children
46
+ }
47
+ ),
48
+ !scrolledToBottom && /* @__PURE__ */ jsx("div", { className: "absolute bottom-18 left-0 right-0 h-16 bg-linear-to-t from-white to-transparent pointer-events-none flex items-end justify-center pb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-on-surface-variant animate-bounce", children: [
49
+ /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-sm", children: "keyboard_arrow_down" }),
50
+ scrollDownText
51
+ ] }) }),
52
+ /* @__PURE__ */ jsxs("div", { className: "px-6 py-4 border-t border-outline-variant flex items-center justify-between gap-3", children: [
53
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-on-surface-variant", children: scrolledToBottom ? /* @__PURE__ */ jsxs("span", { className: "text-green-600 flex items-center gap-1", children: [
54
+ /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-sm", children: "check_circle" }),
55
+ readCompleteText
56
+ ] }) : scrollHintText }),
57
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
58
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: onClose, children: closeLabel }),
59
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: onAccept, disabled: !scrolledToBottom, children: acceptLabel })
60
+ ] })
61
+ ] })
62
+ ] })
63
+ ] });
64
+ }
65
+ export {
66
+ AgreementModal
67
+ };
@@ -0,0 +1,13 @@
1
+ type AlertVariant = "info" | "success" | "warning" | "error";
2
+ interface AlertProps {
3
+ variant: AlertVariant;
4
+ title?: string;
5
+ children: React.ReactNode;
6
+ onClose?: () => void;
7
+ className?: string;
8
+ icon?: string;
9
+ closeAriaLabel?: string;
10
+ }
11
+ declare function Alert({ variant, title, children, onClose, className, icon, closeAriaLabel, }: AlertProps): React.ReactNode;
12
+
13
+ export { Alert, type AlertVariant };
package/dist/alert.js ADDED
@@ -0,0 +1,47 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ const VARIANT_STYLES = {
4
+ info: { container: "bg-blue-50 border border-blue-200 text-blue-800", icon: "text-blue-500", defaultIcon: "info" },
5
+ success: { container: "bg-emerald-50 border border-emerald-200 text-emerald-800", icon: "text-emerald-500", defaultIcon: "check_circle" },
6
+ warning: { container: "bg-amber-50 border border-amber-200 text-amber-800", icon: "text-amber-500", defaultIcon: "warning" },
7
+ error: { container: "bg-red-50 border border-red-200 text-red-800", icon: "text-red-500", defaultIcon: "error" }
8
+ };
9
+ function Alert({
10
+ variant,
11
+ title,
12
+ children,
13
+ onClose,
14
+ className = "",
15
+ icon,
16
+ closeAriaLabel = "Close"
17
+ }) {
18
+ const styles = VARIANT_STYLES[variant];
19
+ const resolvedIcon = icon != null ? icon : styles.defaultIcon;
20
+ return /* @__PURE__ */ jsxs(
21
+ "div",
22
+ {
23
+ className: `flex items-start gap-3 p-4 rounded-xl ${styles.container} ${className}`,
24
+ role: "alert",
25
+ children: [
26
+ /* @__PURE__ */ jsx("span", { className: `material-symbols-outlined text-xl shrink-0 ${styles.icon}`, "aria-hidden": "true", children: resolvedIcon }),
27
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
28
+ title && /* @__PURE__ */ jsx("p", { className: "font-semibold text-sm", children: title }),
29
+ /* @__PURE__ */ jsx("div", { className: "text-sm mt-0.5 opacity-90", children })
30
+ ] }),
31
+ onClose && /* @__PURE__ */ jsx(
32
+ "button",
33
+ {
34
+ type: "button",
35
+ onClick: onClose,
36
+ className: "shrink-0 ml-auto -mt-0.5 p-0.5 rounded-md opacity-60 hover:opacity-100 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current",
37
+ "aria-label": closeAriaLabel,
38
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-xl", "aria-hidden": "true", children: "close" })
39
+ }
40
+ )
41
+ ]
42
+ }
43
+ );
44
+ }
45
+ export {
46
+ Alert
47
+ };
@@ -0,0 +1,7 @@
1
+ interface AuthHeroProps {
2
+ imageUrl?: string;
3
+ overlayOpacity?: number;
4
+ }
5
+ declare function AuthHero({ imageUrl, overlayOpacity }: AuthHeroProps): React.ReactNode;
6
+
7
+ export { AuthHero };
@@ -0,0 +1,63 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function AuthHero({ imageUrl, overlayOpacity = 0.35 }) {
4
+ if (imageUrl) {
5
+ return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 w-full h-full overflow-hidden", children: [
6
+ /* @__PURE__ */ jsx(
7
+ "img",
8
+ {
9
+ src: imageUrl,
10
+ alt: "",
11
+ "aria-hidden": "true",
12
+ className: "absolute inset-0 w-full h-full object-cover"
13
+ }
14
+ ),
15
+ /* @__PURE__ */ jsx(
16
+ "div",
17
+ {
18
+ className: "absolute inset-0",
19
+ style: { backgroundColor: `rgba(0,0,0,${overlayOpacity})` }
20
+ }
21
+ ),
22
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-x-0 bottom-0 h-1/2 bg-linear-to-t from-black/40 to-transparent" })
23
+ ] });
24
+ }
25
+ return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 w-full h-full overflow-hidden", children: [
26
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-br from-blue-500 via-blue-700 to-indigo-900" }),
27
+ /* @__PURE__ */ jsx(
28
+ "div",
29
+ {
30
+ className: "absolute inset-0 opacity-50",
31
+ style: {
32
+ background: "radial-gradient(circle at 30% 20%, rgba(255,255,255,0.25) 0%, transparent 50%)"
33
+ }
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsxs(
37
+ "svg",
38
+ {
39
+ className: "absolute inset-0 w-full h-full opacity-[0.08]",
40
+ xmlns: "http://www.w3.org/2000/svg",
41
+ "aria-hidden": "true",
42
+ children: [
43
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("pattern", { id: "hero-dots", x: "0", y: "0", width: "32", height: "32", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx("circle", { cx: "2", cy: "2", r: "1", fill: "white" }) }) }),
44
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: "url(#hero-dots)" })
45
+ ]
46
+ }
47
+ ),
48
+ /* @__PURE__ */ jsx(
49
+ "svg",
50
+ {
51
+ className: "absolute -right-20 -bottom-10 w-[500px] h-[500px] opacity-10 rotate-[-15deg]",
52
+ viewBox: "0 0 24 24",
53
+ xmlns: "http://www.w3.org/2000/svg",
54
+ fill: "white",
55
+ "aria-hidden": "true",
56
+ children: /* @__PURE__ */ jsx("path", { d: "M21 16v-2l-8-5V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5l8 2.5z" })
57
+ }
58
+ )
59
+ ] });
60
+ }
61
+ export {
62
+ AuthHero
63
+ };
@@ -0,0 +1,21 @@
1
+ type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl";
2
+ interface AvatarProps {
3
+ src?: string;
4
+ name?: string;
5
+ size?: AvatarSize;
6
+ className?: string;
7
+ online?: boolean;
8
+ unknownUserLabel?: string;
9
+ onlineLabel?: string;
10
+ }
11
+ interface AvatarGroupProps {
12
+ avatars: Pick<AvatarProps, "src" | "name">[];
13
+ size?: AvatarSize;
14
+ max?: number;
15
+ className?: string;
16
+ moreLabel?: (n: number) => string;
17
+ }
18
+ declare function Avatar({ src, name, size, className, online, unknownUserLabel, onlineLabel, }: AvatarProps): React.ReactNode;
19
+ declare function AvatarGroup({ avatars, size, max, className, moreLabel, }: AvatarGroupProps): React.ReactNode;
20
+
21
+ export { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize };
package/dist/avatar.js ADDED
@@ -0,0 +1,114 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ const SIZE_CLASSES = {
5
+ xs: "w-6 h-6",
6
+ sm: "w-8 h-8",
7
+ md: "w-10 h-10",
8
+ lg: "w-12 h-12",
9
+ xl: "w-16 h-16"
10
+ };
11
+ const TEXT_CLASSES = {
12
+ xs: "text-[10px]",
13
+ sm: "text-xs",
14
+ md: "text-sm",
15
+ lg: "text-base",
16
+ xl: "text-xl"
17
+ };
18
+ const ICON_CLASSES = {
19
+ xs: "text-sm",
20
+ sm: "text-base",
21
+ md: "text-xl",
22
+ lg: "text-2xl",
23
+ xl: "text-3xl"
24
+ };
25
+ function getInitials(name) {
26
+ const parts = name.trim().split(/\s+/);
27
+ const letters = parts.map((p) => {
28
+ var _a, _b;
29
+ return (_b = (_a = p[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
30
+ }).filter(Boolean);
31
+ return letters.slice(0, 2).join("");
32
+ }
33
+ function Avatar({
34
+ src,
35
+ name,
36
+ size = "md",
37
+ className = "",
38
+ online = false,
39
+ unknownUserLabel = "Unknown user",
40
+ onlineLabel = "Online"
41
+ }) {
42
+ const sizeClass = SIZE_CLASSES[size];
43
+ const textClass = TEXT_CLASSES[size];
44
+ const iconClass = ICON_CLASSES[size];
45
+ return /* @__PURE__ */ jsxs("div", { className: `relative inline-flex shrink-0 ${sizeClass} ${className}`, children: [
46
+ src ? /* @__PURE__ */ jsx(
47
+ "img",
48
+ {
49
+ src,
50
+ alt: name != null ? name : "Avatar",
51
+ className: `${sizeClass} rounded-full object-cover`
52
+ }
53
+ ) : name ? /* @__PURE__ */ jsx(
54
+ "span",
55
+ {
56
+ className: `${sizeClass} rounded-full bg-primary-container text-(--on-primary-container) font-bold flex items-center justify-center ${textClass} select-none`,
57
+ "aria-label": name,
58
+ children: getInitials(name)
59
+ }
60
+ ) : /* @__PURE__ */ jsx(
61
+ "span",
62
+ {
63
+ className: `${sizeClass} rounded-full bg-surface-container text-on-surface-variant flex items-center justify-center`,
64
+ "aria-label": unknownUserLabel,
65
+ children: /* @__PURE__ */ jsx("span", { className: `material-symbols-outlined ${iconClass} leading-none`, "aria-hidden": "true", children: "person" })
66
+ }
67
+ ),
68
+ online && /* @__PURE__ */ jsx(
69
+ "span",
70
+ {
71
+ className: "absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full bg-emerald-500 ring-2 ring-white",
72
+ "aria-label": onlineLabel
73
+ }
74
+ )
75
+ ] });
76
+ }
77
+ function AvatarGroup({
78
+ avatars,
79
+ size = "md",
80
+ max = 4,
81
+ className = "",
82
+ moreLabel = (n) => `${n} more`
83
+ }) {
84
+ const visible = avatars.slice(0, max);
85
+ const overflow = avatars.length - visible.length;
86
+ const sizeClass = SIZE_CLASSES[size];
87
+ const textClass = TEXT_CLASSES[size];
88
+ return /* @__PURE__ */ jsxs("div", { className: `flex items-center ${className}`, children: [
89
+ visible.map((avatar, i) => /* @__PURE__ */ jsx("div", { className: i > 0 ? "-ml-2" : "", children: /* @__PURE__ */ jsx(
90
+ Avatar,
91
+ {
92
+ src: avatar.src,
93
+ name: avatar.name,
94
+ size,
95
+ className: "ring-2 ring-white"
96
+ }
97
+ ) }, i)),
98
+ overflow > 0 && /* @__PURE__ */ jsx("div", { className: "-ml-2", children: /* @__PURE__ */ jsxs(
99
+ "span",
100
+ {
101
+ className: `${sizeClass} rounded-full bg-surface-container text-on-surface-variant font-bold flex items-center justify-center ${textClass} ring-2 ring-white select-none`,
102
+ "aria-label": moreLabel(overflow),
103
+ children: [
104
+ "+",
105
+ overflow
106
+ ]
107
+ }
108
+ ) })
109
+ ] });
110
+ }
111
+ export {
112
+ Avatar,
113
+ AvatarGroup
114
+ };
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type BadgeVariant = "default" | "primary" | "secondary" | "success" | "warning" | "error" | "info";
4
+ type BadgeSize = "sm" | "md" | "lg";
5
+ interface BadgeProps {
6
+ children: React.ReactNode;
7
+ variant?: BadgeVariant;
8
+ size?: BadgeSize;
9
+ icon?: string;
10
+ }
11
+ declare function Badge({ children, variant, size, icon }: BadgeProps): react_jsx_runtime.JSX.Element;
12
+
13
+ export { Badge };
package/dist/badge.js ADDED
@@ -0,0 +1,36 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function Badge({ children, variant = "default", size = "md", icon }) {
4
+ const variantClasses = {
5
+ default: "bg-surface-container text-on-surface-variant",
6
+ primary: "bg-primary-container text-(--on-primary-container)",
7
+ secondary: "bg-(--secondary-container) text-(--on-secondary-container)",
8
+ success: "bg-success/10 text-success",
9
+ warning: "bg-warning/10 text-warning",
10
+ error: "bg-error/10 text-error",
11
+ info: "bg-info/10 text-info"
12
+ };
13
+ const sizeClasses = {
14
+ sm: "px-2 py-0.5 text-[10px]",
15
+ md: "px-3 py-1 text-xs",
16
+ lg: "px-4 py-1.5 text-sm"
17
+ };
18
+ const iconSizeClasses = {
19
+ sm: "text-xs",
20
+ md: "text-sm",
21
+ lg: "text-base"
22
+ };
23
+ return /* @__PURE__ */ jsxs(
24
+ "span",
25
+ {
26
+ className: `inline-flex items-center gap-1.5 rounded-full font-medium transition-colors ${sizeClasses[size]} ${variantClasses[variant]}`,
27
+ children: [
28
+ icon && /* @__PURE__ */ jsx("span", { className: `material-symbols-outlined ${iconSizeClasses[size]}`, "aria-hidden": "true", children: icon }),
29
+ children
30
+ ]
31
+ }
32
+ );
33
+ }
34
+ export {
35
+ Badge
36
+ };
@@ -0,0 +1,14 @@
1
+ type BannerVariant = "info" | "success" | "warning" | "danger";
2
+ interface BannerProps {
3
+ variant?: BannerVariant;
4
+ icon?: string;
5
+ title?: string;
6
+ children?: React.ReactNode;
7
+ onDismiss?: () => void;
8
+ action?: React.ReactNode;
9
+ className?: string;
10
+ closeAriaLabel?: string;
11
+ }
12
+ declare function Banner({ variant, icon, title, children, onDismiss, action, className, closeAriaLabel, }: BannerProps): React.ReactNode;
13
+
14
+ export { Banner, type BannerVariant };
package/dist/banner.js ADDED
@@ -0,0 +1,57 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ const VARIANTS = {
5
+ info: { wrap: "bg-info/10 border-info/30", iconColor: "text-info", titleColor: "text-info" },
6
+ success: { wrap: "bg-success/10 border-success/30", iconColor: "text-success", titleColor: "text-success" },
7
+ warning: { wrap: "bg-warning/10 border-warning/30", iconColor: "text-warning", titleColor: "text-warning" },
8
+ danger: { wrap: "bg-error/10 border-error/30", iconColor: "text-error", titleColor: "text-error" }
9
+ };
10
+ const DEFAULT_ICON = {
11
+ info: "info",
12
+ success: "check_circle",
13
+ warning: "warning",
14
+ danger: "error"
15
+ };
16
+ function Banner({
17
+ variant = "info",
18
+ icon,
19
+ title,
20
+ children,
21
+ onDismiss,
22
+ action,
23
+ className = "",
24
+ closeAriaLabel = "\u0E1B\u0E34\u0E14"
25
+ }) {
26
+ const v = VARIANTS[variant];
27
+ const resolvedIcon = icon != null ? icon : DEFAULT_ICON[variant];
28
+ return /* @__PURE__ */ jsxs("div", { className: `border rounded-2xl p-4 flex items-start gap-3 ${v.wrap} ${className}`, children: [
29
+ /* @__PURE__ */ jsx(
30
+ "span",
31
+ {
32
+ className: `material-symbols-outlined mt-0.5 text-2xl ${v.iconColor}`,
33
+ style: { fontVariationSettings: "'FILL' 1" },
34
+ "aria-hidden": "true",
35
+ children: resolvedIcon
36
+ }
37
+ ),
38
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
39
+ title && /* @__PURE__ */ jsx("p", { className: `text-sm font-bold ${v.titleColor}`, children: title }),
40
+ children && (typeof children === "string" ? /* @__PURE__ */ jsx("p", { className: `text-xs ${v.titleColor} opacity-80 ${title ? "mt-1" : ""} leading-relaxed`, children }) : /* @__PURE__ */ jsx("div", { className: title ? "mt-1" : "", children }))
41
+ ] }),
42
+ action && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: action }),
43
+ onDismiss && /* @__PURE__ */ jsx(
44
+ "button",
45
+ {
46
+ type: "button",
47
+ onClick: onDismiss,
48
+ className: `shrink-0 p-1 rounded ${v.iconColor} hover:opacity-70 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-current`,
49
+ "aria-label": closeAriaLabel,
50
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-lg", "aria-hidden": "true", children: "close" })
51
+ }
52
+ )
53
+ ] });
54
+ }
55
+ export {
56
+ Banner
57
+ };
@@ -0,0 +1,15 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface BreadcrumbItem {
4
+ label: string;
5
+ href?: string;
6
+ }
7
+ interface BreadcrumbProps {
8
+ items: BreadcrumbItem[];
9
+ className?: string;
10
+ navAriaLabel?: string;
11
+ homeAriaLabel?: string;
12
+ }
13
+ declare function Breadcrumb({ items, className, navAriaLabel, homeAriaLabel }: BreadcrumbProps): react_jsx_runtime.JSX.Element;
14
+
15
+ export { Breadcrumb, type BreadcrumbItem };