@avenue-ticketing/ui 0.2.0 → 0.3.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.
@@ -0,0 +1,263 @@
1
+ import * as React from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { jsx, jsxs } from 'react/jsx-runtime';
5
+
6
+ function cn(...inputs) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+ var TabsContext = React.createContext(null);
10
+ function useTabs() {
11
+ const context = React.useContext(TabsContext);
12
+ if (!context) {
13
+ throw new Error("Tabs components must be used within a <Tabs />");
14
+ }
15
+ return context;
16
+ }
17
+ var Tabs = ({
18
+ defaultValue,
19
+ value: controlledValue,
20
+ onValueChange,
21
+ children,
22
+ className,
23
+ variant = "pill",
24
+ ...props
25
+ }) => {
26
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
27
+ const isControlled = controlledValue !== void 0;
28
+ const value = isControlled ? controlledValue : internalValue;
29
+ const handleValueChange = React.useCallback(
30
+ (newValue) => {
31
+ if (!isControlled) {
32
+ setInternalValue(newValue);
33
+ }
34
+ onValueChange?.(newValue);
35
+ },
36
+ [isControlled, onValueChange]
37
+ );
38
+ return /* @__PURE__ */ jsx(
39
+ TabsContext.Provider,
40
+ {
41
+ value: { value, onValueChange: handleValueChange, variant },
42
+ children: /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-4", className), ...props, children })
43
+ }
44
+ );
45
+ };
46
+ var TabsList = ({
47
+ children,
48
+ className,
49
+ ...props
50
+ }) => {
51
+ const { value: activeValue, onValueChange, variant } = useTabs();
52
+ const rowRef = React.useRef(null);
53
+ const updateIndicatorClip = React.useCallback(() => {
54
+ const row = rowRef.current;
55
+ if (!row || variant !== "pill" && variant !== "underline") return;
56
+ const tab = row.querySelector(
57
+ '[role="tab"][aria-selected="true"]'
58
+ );
59
+ if (!tab) {
60
+ row.style.setProperty("--tab-indicator-start", "0px");
61
+ row.style.setProperty("--tab-indicator-end", "0px");
62
+ return;
63
+ }
64
+ const start = tab.offsetLeft;
65
+ const end = tab.offsetLeft + tab.offsetWidth;
66
+ row.style.setProperty("--tab-indicator-start", `${start}px`);
67
+ row.style.setProperty("--tab-indicator-end", `${end}px`);
68
+ }, [variant]);
69
+ React.useLayoutEffect(() => {
70
+ if (variant === "pill" || variant === "underline") updateIndicatorClip();
71
+ }, [activeValue, children, updateIndicatorClip, variant]);
72
+ React.useEffect(() => {
73
+ if (variant !== "pill" && variant !== "underline") return;
74
+ const onResize = () => updateIndicatorClip();
75
+ window.addEventListener("resize", onResize, { passive: true });
76
+ return () => window.removeEventListener("resize", onResize);
77
+ }, [updateIndicatorClip, activeValue, variant]);
78
+ React.useEffect(() => {
79
+ if (variant !== "pill" && variant !== "underline") return;
80
+ const el = rowRef.current;
81
+ if (!el || typeof ResizeObserver === "undefined") return;
82
+ const ro = new ResizeObserver(() => updateIndicatorClip());
83
+ ro.observe(el);
84
+ return () => ro.disconnect();
85
+ }, [updateIndicatorClip, variant]);
86
+ const handleKeyDown = React.useCallback(
87
+ (e) => {
88
+ const dir = e.key === "ArrowRight" ? 1 : e.key === "ArrowLeft" ? -1 : 0;
89
+ if (!dir) return;
90
+ const row = rowRef.current;
91
+ if (!row) return;
92
+ const tabs = Array.from(
93
+ row.querySelectorAll('[role="tab"][data-tab-value]')
94
+ );
95
+ if (tabs.length === 0) return;
96
+ const values = tabs.map((t) => t.dataset.tabValue);
97
+ let idx = activeValue ? values.indexOf(activeValue) : 0;
98
+ if (idx < 0) idx = 0;
99
+ const next = (idx + dir + values.length) % values.length;
100
+ const nextValue = values[next];
101
+ if (nextValue) {
102
+ e.preventDefault();
103
+ onValueChange(nextValue);
104
+ tabs[next]?.focus();
105
+ }
106
+ },
107
+ [activeValue, onValueChange]
108
+ );
109
+ return /* @__PURE__ */ jsx(
110
+ "div",
111
+ {
112
+ onKeyDown: handleKeyDown,
113
+ className: cn(
114
+ "max-w-full overflow-x-auto no-scrollbar",
115
+ variant === "pill" ? "pb-1" : "pb-0",
116
+ className
117
+ ),
118
+ ...props,
119
+ children: /* @__PURE__ */ jsxs(
120
+ "div",
121
+ {
122
+ ref: rowRef,
123
+ role: "tablist",
124
+ className: cn(
125
+ "inline-flex w-max min-w-full items-center",
126
+ (variant === "pill" || variant === "underline") && "relative",
127
+ variant === "pill" && "gap-1",
128
+ variant === "underline" && "gap-2 rounded-none border-b border-border bg-transparent py-0"
129
+ ),
130
+ children: [
131
+ variant === "pill" && /* @__PURE__ */ jsx(
132
+ "div",
133
+ {
134
+ "aria-hidden": "true",
135
+ "data-slot": "tabs-indicator",
136
+ style: {
137
+ clipPath: "inset(0 calc(100% - var(--tab-indicator-end, 0px)) 0 var(--tab-indicator-start, 0px) round 9999px)"
138
+ },
139
+ className: cn(
140
+ "pointer-events-none absolute inset-x-0 top-0 z-0 h-9 rounded-full bg-primary",
141
+ "motion-reduce:transition-none",
142
+ "motion-safe:transition-[clip-path] motion-safe:duration-300 motion-safe:ease-[cubic-bezier(0,0.55,0.45,1)]"
143
+ )
144
+ }
145
+ ),
146
+ variant === "underline" && /* @__PURE__ */ jsx(
147
+ "div",
148
+ {
149
+ "aria-hidden": "true",
150
+ "data-slot": "tabs-underline-indicator",
151
+ style: {
152
+ clipPath: "inset(0 calc(100% - var(--tab-indicator-end, 0px)) 0 var(--tab-indicator-start, 0px))"
153
+ },
154
+ className: cn(
155
+ "pointer-events-none absolute inset-x-0 bottom-0 z-0 h-0.5 bg-primary",
156
+ "motion-reduce:transition-none",
157
+ "motion-safe:transition-[clip-path] motion-safe:duration-300 motion-safe:ease-[cubic-bezier(0,0.55,0.45,1)]"
158
+ )
159
+ }
160
+ ),
161
+ children
162
+ ]
163
+ }
164
+ )
165
+ }
166
+ );
167
+ };
168
+ var TabsTrigger = ({
169
+ value,
170
+ children,
171
+ icon,
172
+ iconPosition = "left",
173
+ onClick,
174
+ className,
175
+ disabled,
176
+ ...props
177
+ }) => {
178
+ const { value: activeValue, onValueChange, variant } = useTabs();
179
+ const isActive = value ? activeValue === value : false;
180
+ return /* @__PURE__ */ jsxs(
181
+ "button",
182
+ {
183
+ type: "button",
184
+ role: "tab",
185
+ "aria-selected": isActive,
186
+ tabIndex: value !== void 0 ? isActive ? 0 : -1 : void 0,
187
+ disabled,
188
+ "data-tab-value": value,
189
+ onClick: (e) => {
190
+ if (value) onValueChange(value);
191
+ onClick?.(e);
192
+ },
193
+ className: cn(
194
+ "relative z-1 inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap touch-manipulation [-webkit-tap-highlight-color:transparent]",
195
+ variant === "pill" && [
196
+ "h-9 rounded-full px-4 font-semibold leading-5 text-[13px] md:text-[15px]",
197
+ "[transition:background-color_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),border-color_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),scale_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),color_var(--duration-short-m,0.2s)_var(--ease-in-out,cubic-bezier(.85,0,.15,1))]",
198
+ "active:scale-[0.96] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
199
+ isActive ? [
200
+ "text-background",
201
+ "**:data-[slot=badge]:border-none **:data-[slot=badge]:bg-background/20 **:data-[slot=badge]:text-background"
202
+ ] : "bg-primary/4 text-primary/50 [@media(hover:hover)_and_(pointer:fine)]:hover:bg-primary/10 active:bg-primary/10"
203
+ ],
204
+ variant === "underline" && [
205
+ "h-auto rounded-none border-0 bg-transparent px-2 py-2 text-sm font-medium shadow-none",
206
+ "transition-[color,transform] duration-200 ease-in-out",
207
+ "motion-reduce:transition-colors motion-reduce:active:scale-100",
208
+ "active:scale-[0.98]",
209
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
210
+ isActive ? "text-primary" : "text-primary/50 [@media(hover:hover)_and_(pointer:fine)]:hover:text-primary/70"
211
+ ],
212
+ "disabled:cursor-not-allowed disabled:opacity-50",
213
+ className
214
+ ),
215
+ ...props,
216
+ children: [
217
+ icon && iconPosition === "left" && /* @__PURE__ */ jsx(
218
+ "span",
219
+ {
220
+ className: "flex size-4 shrink-0 items-center justify-center",
221
+ "aria-hidden": true,
222
+ children: icon
223
+ }
224
+ ),
225
+ children,
226
+ icon && iconPosition === "right" && /* @__PURE__ */ jsx(
227
+ "span",
228
+ {
229
+ className: "flex size-4 shrink-0 items-center justify-center",
230
+ "aria-hidden": true,
231
+ children: icon
232
+ }
233
+ )
234
+ ]
235
+ }
236
+ );
237
+ };
238
+ var TabsContent = ({
239
+ value,
240
+ children,
241
+ className,
242
+ ...props
243
+ }) => {
244
+ const { value: activeValue } = useTabs();
245
+ if (activeValue !== value) return null;
246
+ return /* @__PURE__ */ jsx(
247
+ "div",
248
+ {
249
+ role: "tabpanel",
250
+ className: cn(
251
+ "animate-in fade-in-0 slide-in-from-top-1 duration-200",
252
+ "ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
253
+ className
254
+ ),
255
+ ...props,
256
+ children
257
+ }
258
+ );
259
+ };
260
+
261
+ export { Tabs, TabsContent, TabsList, TabsTrigger };
262
+ //# sourceMappingURL=tabs.js.map
263
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/utils.ts","../../src/react/tabs.tsx"],"names":[],"mappings":"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","file":"tabs.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n//////////////////////////////////////////////// CONTEXT\n\nexport type TabsVariant = \"pill\" | \"underline\";\n\ninterface TabsProps extends React.HTMLAttributes<HTMLDivElement> {\n defaultValue?: string;\n value?: string;\n onValueChange?: (value: string) => void;\n /** `pill` — segmented control with sliding primary fill (default). `underline` — bottom border row + clip-path sliding primary underline. */\n variant?: TabsVariant;\n children: React.ReactNode;\n}\n\nconst TabsContext = React.createContext<{\n value?: string;\n onValueChange: (value: string) => void;\n variant: TabsVariant;\n} | null>(null);\n\nfunction useTabs() {\n const context = React.useContext(TabsContext);\n if (!context) {\n throw new Error(\"Tabs components must be used within a <Tabs />\");\n }\n return context;\n}\n\nexport const Tabs: React.FC<TabsProps> = ({\n defaultValue,\n value: controlledValue,\n onValueChange,\n children,\n className,\n variant = \"pill\",\n ...props\n}) => {\n const [internalValue, setInternalValue] = React.useState(defaultValue);\n const isControlled = controlledValue !== undefined;\n const value = isControlled ? controlledValue : internalValue;\n\n const handleValueChange = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return (\n <TabsContext.Provider\n value={{ value, onValueChange: handleValueChange, variant }}\n >\n <div className={cn(\"flex flex-col gap-4\", className)} {...props}>\n {children}\n </div>\n </TabsContext.Provider>\n );\n};\n\ninterface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const TabsList: React.FC<TabsListProps> = ({\n children,\n className,\n ...props\n}) => {\n const { value: activeValue, onValueChange, variant } = useTabs();\n const rowRef = React.useRef<HTMLDivElement>(null);\n\n /** Drives horizontal `clip-path` via `--tab-indicator-start` / `--tab-indicator-end` (px from row left). */\n const updateIndicatorClip = React.useCallback(() => {\n const row = rowRef.current;\n if (!row || (variant !== \"pill\" && variant !== \"underline\")) return;\n\n const tab = row.querySelector<HTMLElement>(\n '[role=\"tab\"][aria-selected=\"true\"]',\n );\n if (!tab) {\n row.style.setProperty(\"--tab-indicator-start\", \"0px\");\n row.style.setProperty(\"--tab-indicator-end\", \"0px\");\n return;\n }\n\n const start = tab.offsetLeft;\n const end = tab.offsetLeft + tab.offsetWidth;\n row.style.setProperty(\"--tab-indicator-start\", `${start}px`);\n row.style.setProperty(\"--tab-indicator-end\", `${end}px`);\n }, [variant]);\n\n React.useLayoutEffect(() => {\n if (variant === \"pill\" || variant === \"underline\") updateIndicatorClip();\n }, [activeValue, children, updateIndicatorClip, variant]);\n\n React.useEffect(() => {\n if (variant !== \"pill\" && variant !== \"underline\") return;\n const onResize = () => updateIndicatorClip();\n window.addEventListener(\"resize\", onResize, { passive: true });\n return () => window.removeEventListener(\"resize\", onResize);\n }, [updateIndicatorClip, activeValue, variant]);\n\n React.useEffect(() => {\n if (variant !== \"pill\" && variant !== \"underline\") return;\n const el = rowRef.current;\n if (!el || typeof ResizeObserver === \"undefined\") return;\n const ro = new ResizeObserver(() => updateIndicatorClip());\n ro.observe(el);\n return () => ro.disconnect();\n }, [updateIndicatorClip, variant]);\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n const dir = e.key === \"ArrowRight\" ? 1 : e.key === \"ArrowLeft\" ? -1 : 0;\n if (!dir) return;\n const row = rowRef.current;\n if (!row) return;\n const tabs = Array.from(\n row.querySelectorAll<HTMLButtonElement>('[role=\"tab\"][data-tab-value]'),\n );\n if (tabs.length === 0) return;\n const values = tabs.map((t) => t.dataset.tabValue!);\n let idx = activeValue ? values.indexOf(activeValue) : 0;\n if (idx < 0) idx = 0;\n const next = (idx + dir + values.length) % values.length;\n const nextValue = values[next];\n if (nextValue) {\n e.preventDefault();\n onValueChange(nextValue);\n tabs[next]?.focus();\n }\n },\n [activeValue, onValueChange],\n );\n\n return (\n <div\n onKeyDown={handleKeyDown}\n className={cn(\n \"max-w-full overflow-x-auto no-scrollbar\",\n variant === \"pill\" ? \"pb-1\" : \"pb-0\",\n className,\n )}\n {...props}\n >\n <div\n ref={rowRef}\n role=\"tablist\"\n className={cn(\n \"inline-flex w-max min-w-full items-center\",\n (variant === \"pill\" || variant === \"underline\") && \"relative\",\n variant === \"pill\" && \"gap-1\",\n variant === \"underline\" &&\n \"gap-2 rounded-none border-b border-border bg-transparent py-0\",\n )}\n >\n {variant === \"pill\" && (\n <div\n aria-hidden=\"true\"\n data-slot=\"tabs-indicator\"\n style={{\n clipPath:\n \"inset(0 calc(100% - var(--tab-indicator-end, 0px)) 0 var(--tab-indicator-start, 0px) round 9999px)\",\n }}\n className={cn(\n \"pointer-events-none absolute inset-x-0 top-0 z-0 h-9 rounded-full bg-primary\",\n \"motion-reduce:transition-none\",\n \"motion-safe:transition-[clip-path] motion-safe:duration-300 motion-safe:ease-[cubic-bezier(0,0.55,0.45,1)]\",\n )}\n />\n )}\n {variant === \"underline\" && (\n <div\n aria-hidden=\"true\"\n data-slot=\"tabs-underline-indicator\"\n style={{\n clipPath:\n \"inset(0 calc(100% - var(--tab-indicator-end, 0px)) 0 var(--tab-indicator-start, 0px))\",\n }}\n className={cn(\n \"pointer-events-none absolute inset-x-0 bottom-0 z-0 h-0.5 bg-primary\",\n \"motion-reduce:transition-none\",\n \"motion-safe:transition-[clip-path] motion-safe:duration-300 motion-safe:ease-[cubic-bezier(0,0.55,0.45,1)]\",\n )}\n />\n )}\n {children}\n </div>\n </div>\n );\n};\n\ninterface TabsTriggerProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"onClick\"\n> {\n value?: string;\n icon?: React.ReactNode;\n iconPosition?: \"left\" | \"right\";\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n}\n\nexport const TabsTrigger: React.FC<TabsTriggerProps> = ({\n value,\n children,\n icon,\n iconPosition = \"left\",\n onClick,\n className,\n disabled,\n ...props\n}) => {\n const { value: activeValue, onValueChange, variant } = useTabs();\n const isActive = value ? activeValue === value : false;\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n tabIndex={value !== undefined ? (isActive ? 0 : -1) : undefined}\n disabled={disabled}\n data-tab-value={value}\n onClick={(e) => {\n if (value) onValueChange(value);\n onClick?.(e);\n }}\n className={cn(\n \"relative z-1 inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap touch-manipulation [-webkit-tap-highlight-color:transparent]\",\n variant === \"pill\" && [\n \"h-9 rounded-full px-4 font-semibold leading-5 text-[13px] md:text-[15px]\",\n \"[transition:background-color_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),border-color_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),scale_var(--duration-short-s,0.1s)_var(--ease-out,cubic-bezier(0,.55,.45,1)),color_var(--duration-short-m,0.2s)_var(--ease-in-out,cubic-bezier(.85,0,.15,1))]\",\n \"active:scale-[0.96] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n isActive\n ? [\n \"text-background\",\n \"**:data-[slot=badge]:border-none **:data-[slot=badge]:bg-background/20 **:data-[slot=badge]:text-background\",\n ]\n : \"bg-primary/4 text-primary/50 [@media(hover:hover)_and_(pointer:fine)]:hover:bg-primary/10 active:bg-primary/10\",\n ],\n variant === \"underline\" && [\n \"h-auto rounded-none border-0 bg-transparent px-2 py-2 text-sm font-medium shadow-none\",\n \"transition-[color,transform] duration-200 ease-in-out\",\n \"motion-reduce:transition-colors motion-reduce:active:scale-100\",\n \"active:scale-[0.98]\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n isActive\n ? \"text-primary\"\n : \"text-primary/50 [@media(hover:hover)_and_(pointer:fine)]:hover:text-primary/70\",\n ],\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n {icon && iconPosition === \"left\" && (\n <span\n className=\"flex size-4 shrink-0 items-center justify-center\"\n aria-hidden\n >\n {icon}\n </span>\n )}\n {children}\n {icon && iconPosition === \"right\" && (\n <span\n className=\"flex size-4 shrink-0 items-center justify-center\"\n aria-hidden\n >\n {icon}\n </span>\n )}\n </button>\n );\n};\n\ninterface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {\n value: string;\n}\n\nexport const TabsContent: React.FC<TabsContentProps> = ({\n value,\n children,\n className,\n ...props\n}) => {\n const { value: activeValue } = useTabs();\n\n if (activeValue !== value) return null;\n\n return (\n <div\n role=\"tabpanel\"\n className={cn(\n \"animate-in fade-in-0 slide-in-from-top-1 duration-200\",\n \"ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avenue-ticketing/ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Avenue UI components for React",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,