@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/dist/slider.js ADDED
@@ -0,0 +1,151 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useRef } from "react";
5
+ function Slider({
6
+ value,
7
+ onChange,
8
+ min = 0,
9
+ max = 100,
10
+ step = 1,
11
+ label,
12
+ showValue = false,
13
+ formatValue,
14
+ disabled = false,
15
+ minRangeLabel = "Minimum value",
16
+ maxRangeLabel = "Maximum value",
17
+ valueLabel
18
+ }) {
19
+ var _a;
20
+ const isRange = Array.isArray(value);
21
+ const fmt = formatValue != null ? formatValue : ((v) => String(v));
22
+ const rangeContainerRef = useRef(null);
23
+ if (isRange) {
24
+ const [low, high] = value;
25
+ const lowPct = (low - min) / (max - min) * 100;
26
+ const highPct = (high - min) / (max - min) * 100;
27
+ const handleLowChange = (e) => {
28
+ const next = Math.min(Number(e.target.value), high - step);
29
+ onChange([next, high]);
30
+ };
31
+ const handleHighChange = (e) => {
32
+ const next = Math.max(Number(e.target.value), low + step);
33
+ onChange([low, next]);
34
+ };
35
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
36
+ (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
37
+ label && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-on-surface", children: label }),
38
+ showValue && /* @__PURE__ */ jsxs("span", { className: "text-sm font-bold text-primary", children: [
39
+ fmt(low),
40
+ " \u2013 ",
41
+ fmt(high)
42
+ ] })
43
+ ] }),
44
+ /* @__PURE__ */ jsxs("div", { className: "relative h-2 my-3", ref: rangeContainerRef, children: [
45
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-surface-container-high" }),
46
+ /* @__PURE__ */ jsx(
47
+ "div",
48
+ {
49
+ className: "absolute top-0 h-2 rounded-full bg-primary",
50
+ style: { left: `${lowPct}%`, right: `${100 - highPct}%` }
51
+ }
52
+ ),
53
+ /* @__PURE__ */ jsx(
54
+ "input",
55
+ {
56
+ type: "range",
57
+ min,
58
+ max,
59
+ step,
60
+ value: low,
61
+ disabled,
62
+ onChange: handleLowChange,
63
+ "aria-label": minRangeLabel,
64
+ className: "peer/low absolute w-full h-2 opacity-0 cursor-pointer disabled:cursor-not-allowed",
65
+ style: { zIndex: low > max - (max - min) / 2 ? 5 : 3 }
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(
69
+ "input",
70
+ {
71
+ type: "range",
72
+ min,
73
+ max,
74
+ step,
75
+ value: high,
76
+ disabled,
77
+ onChange: handleHighChange,
78
+ "aria-label": maxRangeLabel,
79
+ className: "peer/high absolute w-full h-2 opacity-0 cursor-pointer disabled:cursor-not-allowed",
80
+ style: { zIndex: 4 }
81
+ }
82
+ ),
83
+ /* @__PURE__ */ jsx(
84
+ "div",
85
+ {
86
+ className: "absolute top-1/2 -translate-y-1/2 w-4 h-4 rounded-full bg-white border-2 border-primary shadow pointer-events-none peer-focus-visible/low:ring-2 peer-focus-visible/low:ring-primary/30",
87
+ style: { left: `calc(${lowPct}% - 8px)` }
88
+ }
89
+ ),
90
+ /* @__PURE__ */ jsx(
91
+ "div",
92
+ {
93
+ className: "absolute top-1/2 -translate-y-1/2 w-4 h-4 rounded-full bg-white border-2 border-primary shadow pointer-events-none peer-focus-visible/high:ring-2 peer-focus-visible/high:ring-primary/30",
94
+ style: { left: `calc(${highPct}% - 8px)` }
95
+ }
96
+ )
97
+ ] }),
98
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
99
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant", children: fmt(min) }),
100
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant", children: fmt(max) })
101
+ ] })
102
+ ] });
103
+ }
104
+ const single = value;
105
+ const pct = (single - min) / (max - min) * 100;
106
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
107
+ (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
108
+ label && /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-on-surface", children: label }),
109
+ showValue && /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-primary", children: fmt(single) })
110
+ ] }),
111
+ /* @__PURE__ */ jsxs("div", { className: "relative h-2 my-3", children: [
112
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-surface-container-high" }),
113
+ /* @__PURE__ */ jsx(
114
+ "div",
115
+ {
116
+ className: "absolute top-0 left-0 h-2 rounded-full bg-primary",
117
+ style: { width: `${pct}%` }
118
+ }
119
+ ),
120
+ /* @__PURE__ */ jsx(
121
+ "input",
122
+ {
123
+ type: "range",
124
+ min,
125
+ max,
126
+ step,
127
+ value: single,
128
+ disabled,
129
+ onChange: (e) => onChange(Number(e.target.value)),
130
+ "aria-label": (_a = valueLabel != null ? valueLabel : label) != null ? _a : "Value",
131
+ className: "peer absolute w-full h-2 opacity-0 cursor-pointer disabled:cursor-not-allowed",
132
+ style: { zIndex: 3 }
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsx(
136
+ "div",
137
+ {
138
+ className: "absolute top-1/2 -translate-y-1/2 w-4 h-4 rounded-full bg-white border-2 border-primary shadow pointer-events-none peer-focus-visible:ring-2 peer-focus-visible:ring-primary/30",
139
+ style: { left: `calc(${pct}% - 8px)` }
140
+ }
141
+ )
142
+ ] }),
143
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between", children: [
144
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant", children: fmt(min) }),
145
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-on-surface-variant", children: fmt(max) })
146
+ ] })
147
+ ] });
148
+ }
149
+ export {
150
+ Slider
151
+ };
@@ -0,0 +1,13 @@
1
+ interface SpinnerProps {
2
+ size?: "xs" | "sm" | "md" | "lg";
3
+ color?: "primary" | "white" | "current";
4
+ className?: string;
5
+ loadingAriaLabel?: string;
6
+ }
7
+ declare function Spinner({ size, color, className, loadingAriaLabel, }: SpinnerProps): React.ReactNode;
8
+ interface FullPageSpinnerProps {
9
+ message?: string;
10
+ }
11
+ declare function FullPageSpinner({ message }: FullPageSpinnerProps): React.ReactNode;
12
+
13
+ export { FullPageSpinner, Spinner };
@@ -0,0 +1,38 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ const SIZE_CLASSES = {
4
+ xs: "w-3 h-3 border-2",
5
+ sm: "w-4 h-4 border-2",
6
+ md: "w-6 h-6 border-2",
7
+ lg: "w-8 h-8 border-[3px]"
8
+ };
9
+ const COLOR_CLASSES = {
10
+ primary: "border-primary/20 border-t-primary",
11
+ white: "border-white/20 border-t-white",
12
+ current: "border-current/20 border-t-current"
13
+ };
14
+ function Spinner({
15
+ size = "md",
16
+ color = "primary",
17
+ className = "",
18
+ loadingAriaLabel = "Loading"
19
+ }) {
20
+ return /* @__PURE__ */ jsx(
21
+ "span",
22
+ {
23
+ role: "status",
24
+ "aria-label": loadingAriaLabel,
25
+ className: `inline-block rounded-full animate-spin ${SIZE_CLASSES[size]} ${COLOR_CLASSES[color]} ${className}`
26
+ }
27
+ );
28
+ }
29
+ function FullPageSpinner({ message }) {
30
+ return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 flex flex-col items-center justify-center gap-3 bg-white/80 backdrop-blur-sm z-50", children: [
31
+ /* @__PURE__ */ jsx(Spinner, { size: "lg", color: "primary" }),
32
+ message && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-on-surface-variant", children: message })
33
+ ] });
34
+ }
35
+ export {
36
+ FullPageSpinner,
37
+ Spinner
38
+ };
@@ -0,0 +1,20 @@
1
+ import { AppColor } from './icon-wrapper.js';
2
+
3
+ /** @deprecated use AppColor */
4
+ type StatCardTone = AppColor;
5
+ interface StatCardProps {
6
+ icon: string;
7
+ iconColor?: AppColor;
8
+ iconGradient?: string;
9
+ title: string;
10
+ value: string | number;
11
+ subtitle?: string;
12
+ limit?: number;
13
+ suffix?: string;
14
+ variant?: "default" | "pastel" | "hero" | "compact";
15
+ tone?: AppColor;
16
+ children?: React.ReactNode;
17
+ }
18
+ declare function StatCard({ icon, iconColor, iconGradient, title, value, subtitle, limit, suffix, variant, tone, children, }: StatCardProps): React.ReactNode;
19
+
20
+ export { StatCard, type StatCardTone };
@@ -0,0 +1,87 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { IconWrapper, appColorFg } from "./icon-wrapper";
4
+ const TONE_BG = {
5
+ primary: "bg-primary-container",
6
+ emerald: "bg-emerald-50",
7
+ amber: "bg-amber-50",
8
+ rose: "bg-rose-50",
9
+ red: "bg-red-50",
10
+ violet: "bg-violet-50",
11
+ blue: "bg-blue-50",
12
+ slate: "bg-slate-100",
13
+ cyan: "bg-cyan-50"
14
+ };
15
+ function StatCard({
16
+ icon,
17
+ iconColor = "primary",
18
+ iconGradient = "from-blue-100 to-blue-50",
19
+ title,
20
+ value,
21
+ subtitle,
22
+ limit,
23
+ suffix,
24
+ variant = "default",
25
+ tone = "primary",
26
+ children
27
+ }) {
28
+ if (variant === "compact") {
29
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-lg border border-outline-variant/50 px-4 py-3 flex items-center gap-3", children: [
30
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `material-symbols-outlined text-lg ${appColorFg[tone]} opacity-50`, style: { fontVariationSettings: "'FILL' 1" }, children: icon }),
31
+ /* @__PURE__ */ jsxs("div", { children: [
32
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-black text-on-surface leading-none tabular-nums", children: value }),
33
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-on-surface-variant mt-0.5", children: title })
34
+ ] })
35
+ ] });
36
+ }
37
+ if (variant === "hero") {
38
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white p-6 rounded-2xl border border-surface-container-high shadow-sm flex flex-col justify-center text-center space-y-3", children: [
39
+ /* @__PURE__ */ jsx("div", { className: `w-14 h-14 mx-auto flex items-center justify-center rounded-2xl ${TONE_BG[tone]}`, children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `material-symbols-outlined text-2xl ${appColorFg[tone]}`, style: { fontVariationSettings: "'FILL' 1" }, children: icon }) }),
40
+ /* @__PURE__ */ jsxs("div", { children: [
41
+ /* @__PURE__ */ jsx("p", { className: "text-xs uppercase tracking-widest font-bold text-outline", children: title }),
42
+ /* @__PURE__ */ jsx("p", { className: "text-2xl md:text-3xl font-black text-on-surface mt-2", children: value }),
43
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs text-on-surface-variant mt-1", children: subtitle })
44
+ ] }),
45
+ children
46
+ ] });
47
+ }
48
+ if (variant === "pastel") {
49
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-3xl border border-outline-variant/50 p-5 md:p-6 flex items-center gap-4 hover:shadow-md transition-shadow", children: [
50
+ /* @__PURE__ */ jsx("div", { className: `w-11 h-11 rounded-2xl bg-linear-to-br ${iconGradient} flex items-center justify-center shrink-0`, children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `material-symbols-outlined ${appColorFg[iconColor]}`, style: { fontVariationSettings: "'FILL' 1" }, children: icon }) }),
51
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
52
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] uppercase tracking-widest font-bold text-on-surface-variant", children: title }),
53
+ /* @__PURE__ */ jsx("p", { className: "text-2xl md:text-3xl font-black text-on-surface mt-0.5", children: value }),
54
+ children
55
+ ] })
56
+ ] });
57
+ }
58
+ const pct = limit ? Math.round(Number(value) / limit * 100) : 0;
59
+ return /* @__PURE__ */ jsxs("div", { className: "bg-white rounded-2xl p-6 border border-outline-variant/10 shadow-sm hover:shadow-md transition-shadow", children: [
60
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
61
+ /* @__PURE__ */ jsx(IconWrapper, { icon, color: iconColor, size: "md" }),
62
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-on-surface", children: title })
63
+ ] }),
64
+ /* @__PURE__ */ jsxs("p", { className: "text-2xl font-bold text-on-surface", children: [
65
+ value,
66
+ limit != null && /* @__PURE__ */ jsxs("span", { className: "text-sm font-normal text-on-surface-variant", children: [
67
+ " / ",
68
+ limit
69
+ ] }),
70
+ suffix && /* @__PURE__ */ jsxs("span", { className: "text-sm font-normal text-on-surface-variant", children: [
71
+ " ",
72
+ suffix
73
+ ] })
74
+ ] }),
75
+ limit != null && /* @__PURE__ */ jsx("div", { className: "h-2 rounded-full bg-slate-100 mt-3", children: /* @__PURE__ */ jsx(
76
+ "div",
77
+ {
78
+ className: "h-full rounded-full bg-primary transition-[width] duration-500",
79
+ style: { width: `${Math.min(pct, 100)}%` }
80
+ }
81
+ ) }),
82
+ children
83
+ ] });
84
+ }
85
+ export {
86
+ StatCard
87
+ };
@@ -0,0 +1,13 @@
1
+ interface StatItem {
2
+ value: string | number;
3
+ label: string;
4
+ icon?: string;
5
+ }
6
+ interface StatsSummaryProps {
7
+ stats: StatItem[];
8
+ columns?: 2 | 3 | 4;
9
+ className?: string;
10
+ }
11
+ declare function StatsSummary({ stats, columns, className, }: StatsSummaryProps): React.ReactNode;
12
+
13
+ export { StatsSummary };
@@ -0,0 +1,28 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ const COLS = {
4
+ 2: "grid-cols-2",
5
+ 3: "grid-cols-3",
6
+ 4: "grid-cols-4"
7
+ };
8
+ function StatsSummary({
9
+ stats,
10
+ columns = 3,
11
+ className = ""
12
+ }) {
13
+ return /* @__PURE__ */ jsx("div", { className: `grid ${COLS[columns]} ${className}`, children: stats.map((stat, i) => /* @__PURE__ */ jsxs(
14
+ "div",
15
+ {
16
+ className: `text-center px-4 py-2 ${i > 0 ? "border-l border-outline-variant/30" : ""}`,
17
+ children: [
18
+ stat.icon && /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-base text-on-surface-variant mb-0.5 block", "aria-hidden": "true", children: stat.icon }),
19
+ /* @__PURE__ */ jsx("p", { className: "text-2xl font-black text-on-surface tabular-nums leading-tight", children: stat.value }),
20
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-on-surface-variant font-semibold uppercase tracking-wide mt-0.5", children: stat.label })
21
+ ]
22
+ },
23
+ stat.label
24
+ )) });
25
+ }
26
+ export {
27
+ StatsSummary
28
+ };
@@ -0,0 +1,19 @@
1
+ import { AppColor } from './icon-wrapper.js';
2
+
3
+ /** @deprecated use AppColor */
4
+ type StatusTone = AppColor;
5
+ interface StatusConfig {
6
+ label: string;
7
+ tone?: AppColor;
8
+ /** Raw class override — use only when named tones don't cover the case */
9
+ cls?: string;
10
+ }
11
+ interface StatusBadgeProps {
12
+ status: string;
13
+ config?: Record<string, StatusConfig>;
14
+ variant?: "pill" | "dot";
15
+ className?: string;
16
+ }
17
+ declare function StatusBadge({ status, config, variant, className }: StatusBadgeProps): React.ReactNode;
18
+
19
+ export { StatusBadge, type StatusConfig, type StatusTone };
@@ -0,0 +1,41 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { appColorFg } from "./icon-wrapper";
4
+ const PILL_BG = {
5
+ primary: "bg-primary-container",
6
+ emerald: "bg-emerald-100",
7
+ amber: "bg-amber-100",
8
+ rose: "bg-rose-100",
9
+ red: "bg-red-100",
10
+ violet: "bg-violet-100",
11
+ blue: "bg-blue-100",
12
+ slate: "bg-surface-container",
13
+ cyan: "bg-cyan-100"
14
+ };
15
+ const DOT_COLOR = {
16
+ primary: "bg-primary",
17
+ emerald: "bg-emerald-500",
18
+ amber: "bg-amber-500",
19
+ rose: "bg-rose-500",
20
+ red: "bg-red-500",
21
+ violet: "bg-violet-500",
22
+ blue: "bg-blue-500",
23
+ slate: "bg-outline",
24
+ cyan: "bg-cyan-500"
25
+ };
26
+ function StatusBadge({ status, config = {}, variant = "pill", className = "" }) {
27
+ var _a, _b, _c;
28
+ const c = (_a = config[status]) != null ? _a : { label: status, tone: "slate" };
29
+ const tone = (_b = c.tone) != null ? _b : "slate";
30
+ if (variant === "dot") {
31
+ return /* @__PURE__ */ jsxs("span", { className: `inline-flex items-center gap-1.5 text-xs font-semibold ${appColorFg[tone]} ${className}`, children: [
32
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `w-1.5 h-1.5 rounded-full ${DOT_COLOR[tone]}` }),
33
+ c.label
34
+ ] });
35
+ }
36
+ const pillClass = (_c = c.cls) != null ? _c : `${PILL_BG[tone]} ${appColorFg[tone]}`;
37
+ return /* @__PURE__ */ jsx("span", { className: `px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-widest ${pillClass} ${className}`, children: c.label });
38
+ }
39
+ export {
40
+ StatusBadge
41
+ };
@@ -0,0 +1,12 @@
1
+ interface StepItem {
2
+ label: string;
3
+ description?: string;
4
+ }
5
+ interface StepperProps {
6
+ steps: StepItem[];
7
+ currentStep: number;
8
+ orientation?: "horizontal" | "vertical";
9
+ }
10
+ declare function Stepper({ steps, currentStep, orientation, }: StepperProps): React.ReactNode;
11
+
12
+ export { type StepItem, Stepper };
@@ -0,0 +1,89 @@
1
+ import "./chunk-ORMEWXMH.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ function Stepper({
4
+ steps,
5
+ currentStep,
6
+ orientation = "horizontal"
7
+ }) {
8
+ if (orientation === "vertical") {
9
+ return /* @__PURE__ */ jsx("ol", { className: "flex flex-col", "aria-label": "Steps", children: steps.map((step, index) => {
10
+ const isCompleted = index < currentStep;
11
+ const isCurrent = index === currentStep;
12
+ return /* @__PURE__ */ jsxs("li", { className: "flex gap-3", "aria-current": isCurrent ? "step" : void 0, children: [
13
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
14
+ /* @__PURE__ */ jsx(
15
+ "div",
16
+ {
17
+ className: `w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold shrink-0 ${isCompleted ? "bg-emerald-500 text-white" : isCurrent ? "bg-primary text-on-primary shadow-lg" : "bg-surface-container-high text-on-surface-variant"}`,
18
+ children: isCompleted ? /* @__PURE__ */ jsx(
19
+ "span",
20
+ {
21
+ className: "material-symbols-outlined text-base",
22
+ style: { fontVariationSettings: "'FILL' 1", fontSize: "16px" },
23
+ children: "check"
24
+ }
25
+ ) : /* @__PURE__ */ jsx("span", { children: index + 1 })
26
+ }
27
+ ),
28
+ index < steps.length - 1 && /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ className: `w-0.5 h-8 ml-0 mt-1 ${isCompleted ? "bg-emerald-500" : "bg-outline-variant/30"}`
32
+ }
33
+ )
34
+ ] }),
35
+ /* @__PURE__ */ jsxs("div", { className: `pb-6 ${index === steps.length - 1 ? "pb-0" : ""}`, children: [
36
+ /* @__PURE__ */ jsx(
37
+ "p",
38
+ {
39
+ className: `text-xs font-semibold leading-8 ${isCurrent ? "text-primary" : isCompleted ? "text-emerald-600" : "text-on-surface-variant"}`,
40
+ children: step.label
41
+ }
42
+ ),
43
+ step.description && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-on-surface-variant -mt-1", children: step.description })
44
+ ] })
45
+ ] }, index);
46
+ }) });
47
+ }
48
+ return /* @__PURE__ */ jsx("ol", { className: "flex items-center w-full", "aria-label": "Steps", children: steps.map((step, index) => {
49
+ const isCompleted = index < currentStep;
50
+ const isCurrent = index === currentStep;
51
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-center flex-1 last:flex-none", "aria-current": isCurrent ? "step" : void 0, children: [
52
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1.5", children: [
53
+ /* @__PURE__ */ jsx(
54
+ "div",
55
+ {
56
+ className: `w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold shrink-0 ${isCompleted ? "bg-emerald-500 text-white" : isCurrent ? "bg-primary text-on-primary shadow-lg" : "bg-surface-container-high text-on-surface-variant"}`,
57
+ children: isCompleted ? /* @__PURE__ */ jsx(
58
+ "span",
59
+ {
60
+ className: "material-symbols-outlined text-base",
61
+ style: { fontVariationSettings: "'FILL' 1", fontSize: "16px" },
62
+ children: "check"
63
+ }
64
+ ) : /* @__PURE__ */ jsx("span", { children: index + 1 })
65
+ }
66
+ ),
67
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
68
+ /* @__PURE__ */ jsx(
69
+ "p",
70
+ {
71
+ className: `text-xs font-semibold ${isCurrent ? "text-primary" : isCompleted ? "text-emerald-600" : "text-on-surface-variant"}`,
72
+ children: step.label
73
+ }
74
+ ),
75
+ step.description && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-on-surface-variant", children: step.description })
76
+ ] })
77
+ ] }),
78
+ index < steps.length - 1 && /* @__PURE__ */ jsx(
79
+ "div",
80
+ {
81
+ className: `h-0.5 flex-1 mx-2 mb-6 ${isCompleted ? "bg-emerald-500" : "bg-outline-variant/30"}`
82
+ }
83
+ )
84
+ ] }, index);
85
+ }) });
86
+ }
87
+ export {
88
+ Stepper
89
+ };
package/dist/tabs.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ interface TabItem {
4
+ id: string;
5
+ label: string;
6
+ icon?: string;
7
+ badge?: string | number;
8
+ disabled?: boolean;
9
+ }
10
+ interface TabsProps {
11
+ items: TabItem[];
12
+ value: string;
13
+ onChange: (id: string) => void;
14
+ variant?: "line" | "pill";
15
+ }
16
+ declare function Tabs({ items, value, onChange, variant, }: TabsProps): react_jsx_runtime.JSX.Element;
17
+
18
+ export { type TabItem, Tabs };
package/dist/tabs.js ADDED
@@ -0,0 +1,70 @@
1
+ "use client";
2
+ import "./chunk-ORMEWXMH.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ function Tabs({
5
+ items,
6
+ value,
7
+ onChange,
8
+ variant = "line"
9
+ }) {
10
+ if (variant === "pill") {
11
+ return /* @__PURE__ */ jsx(
12
+ "div",
13
+ {
14
+ role: "tablist",
15
+ className: "flex gap-2 p-1 bg-surface-container rounded-xl",
16
+ children: items.map((item) => {
17
+ const isActive = value === item.id;
18
+ return /* @__PURE__ */ jsxs(
19
+ "button",
20
+ {
21
+ role: "tab",
22
+ type: "button",
23
+ "aria-selected": isActive,
24
+ disabled: item.disabled,
25
+ onClick: () => !item.disabled && onChange(item.id),
26
+ className: `flex items-center gap-1.5 px-4 py-2 text-sm font-semibold transition-colors duration-200 rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 ${item.disabled ? "opacity-40 cursor-not-allowed" : "active:scale-[0.98]"} ${isActive ? "bg-surface shadow-sm text-on-surface" : "text-on-surface-variant hover:text-on-surface"}`,
27
+ children: [
28
+ item.icon && /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-base", "aria-hidden": "true", children: item.icon }),
29
+ /* @__PURE__ */ jsx("span", { children: item.label }),
30
+ item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-0.5 bg-surface-container-high text-on-surface-variant text-xs font-medium px-1.5 py-0.5 rounded-full", children: item.badge })
31
+ ]
32
+ },
33
+ item.id
34
+ );
35
+ })
36
+ }
37
+ );
38
+ }
39
+ return /* @__PURE__ */ jsx(
40
+ "div",
41
+ {
42
+ role: "tablist",
43
+ className: "flex border-b border-outline-variant/30 overflow-x-auto",
44
+ children: items.map((item) => {
45
+ const isActive = value === item.id;
46
+ return /* @__PURE__ */ jsxs(
47
+ "button",
48
+ {
49
+ role: "tab",
50
+ type: "button",
51
+ "aria-selected": isActive,
52
+ disabled: item.disabled,
53
+ onClick: () => !item.disabled && onChange(item.id),
54
+ className: `flex items-center gap-1.5 px-4 py-3 text-sm font-semibold transition-colors duration-200 relative whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/30 ${item.disabled ? "opacity-40 cursor-not-allowed" : ""} ${isActive ? "text-primary" : "text-on-surface-variant hover:text-on-surface"}`,
55
+ children: [
56
+ item.icon && /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined text-base", "aria-hidden": "true", children: item.icon }),
57
+ /* @__PURE__ */ jsx("span", { children: item.label }),
58
+ item.badge !== void 0 && /* @__PURE__ */ jsx("span", { className: "ml-0.5 bg-surface-container text-on-surface-variant text-xs font-medium px-1.5 py-0.5 rounded-full", children: item.badge }),
59
+ isActive && /* @__PURE__ */ jsx("span", { className: "absolute bottom-0 left-0 right-0 h-0.5 bg-primary rounded-full" })
60
+ ]
61
+ },
62
+ item.id
63
+ );
64
+ })
65
+ }
66
+ );
67
+ }
68
+ export {
69
+ Tabs
70
+ };
package/dist/tag.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type AppColor = "primary" | "emerald" | "amber" | "rose" | "red" | "violet" | "blue" | "slate" | "cyan";
4
+ interface TagProps {
5
+ label: string;
6
+ onRemove?: () => void;
7
+ color?: AppColor;
8
+ size?: "sm" | "md";
9
+ icon?: string;
10
+ selected?: boolean;
11
+ onClick?: () => void;
12
+ }
13
+ declare function Tag({ label, onRemove, color, size, icon, selected, onClick, }: TagProps): react_jsx_runtime.JSX.Element;
14
+ interface TagGroupProps {
15
+ value: string[];
16
+ onChange: (tags: string[]) => void;
17
+ placeholder?: string;
18
+ label?: string;
19
+ maxTags?: number;
20
+ }
21
+ declare function TagGroup({ value, onChange, placeholder, label, maxTags, }: TagGroupProps): react_jsx_runtime.JSX.Element;
22
+
23
+ export { type AppColor, Tag, TagGroup };