@mohasinac/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.
@@ -0,0 +1,829 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
3
+ import { PaginationConfig, TableColumn, TableConfig } from '@mohasinac/contracts';
4
+ export { DEFAULT_PAGINATION_CONFIG, DEFAULT_STICKY_CONFIG, DEFAULT_TABLE_CONFIG, PaginationConfig, StickyConfig, TableConfig, TableViewMode, mergeTableConfig } from '@mohasinac/contracts';
5
+
6
+ /**
7
+ * Semantic HTML Wrapper Components
8
+ *
9
+ * Thin wrappers around HTML5 semantic elements.
10
+ * Using these instead of raw tags enables:
11
+ * - Future one-place theming (add default padding/colour here, it applies everywhere)
12
+ * - Enforced accessibility attributes (Nav requires aria-label)
13
+ * - Consistent documentation / IDE autocomplete
14
+ * - Clean migration path if element defaults change
15
+ *
16
+ * All components pass through every standard HTML attribute via `...props`.
17
+ * Style via `className` using Tailwind CSS classes.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * import { Section, Article, Main, Aside, Nav, Ul, Ol, Li } from '@mohasinac/ui';
22
+ *
23
+ * <Main className="max-w-7xl mx-auto px-4">
24
+ * <Section className="py-12">
25
+ * <Article>...</Article>
26
+ * </Section>
27
+ * <Aside className="w-64 shrink-0">...</Aside>
28
+ * </Main>
29
+ *
30
+ * <Nav aria-label="Main navigation">
31
+ * <Ul className="flex gap-4">
32
+ * <Li>Products</Li>
33
+ * </Ul>
34
+ * </Nav>
35
+ * ```
36
+ */
37
+ /**
38
+ * Semantic `<section>` element.
39
+ * Use for thematically grouped content that would appear in an outline.
40
+ * Prefer this over a plain `<div>` when the block has a heading.
41
+ */
42
+ interface SectionProps extends React.HTMLAttributes<HTMLElement> {
43
+ children: React.ReactNode;
44
+ }
45
+ declare const Section: React.ForwardRefExoticComponent<SectionProps & React.RefAttributes<HTMLElement>>;
46
+ /**
47
+ * Semantic `<article>` element.
48
+ * Use for self-contained compositions: blog posts, product cards, reviews, forum posts.
49
+ */
50
+ interface ArticleProps extends React.HTMLAttributes<HTMLElement> {
51
+ children?: React.ReactNode;
52
+ }
53
+ declare function Article({ className, children, ...props }: ArticleProps): react_jsx_runtime.JSX.Element;
54
+ /**
55
+ * Semantic `<main>` element.
56
+ * Wraps the primary content of the document. Should appear only once per page.
57
+ */
58
+ interface MainProps extends React.HTMLAttributes<HTMLElement> {
59
+ children: React.ReactNode;
60
+ }
61
+ declare function Main({ className, children, ...props }: MainProps): react_jsx_runtime.JSX.Element;
62
+ /**
63
+ * Semantic `<aside>` element.
64
+ * Use for supplementary content tangentially related to the main content:
65
+ * sidebars, callout boxes, related-link panels.
66
+ */
67
+ interface AsideProps extends React.HTMLAttributes<HTMLElement> {
68
+ children: React.ReactNode;
69
+ }
70
+ declare const Aside: React.ForwardRefExoticComponent<AsideProps & React.RefAttributes<HTMLElement>>;
71
+ /**
72
+ * Semantic `<nav>` element with enforced `aria-label`.
73
+ *
74
+ * Every `<nav>` on a page MUST have a unique `aria-label` so assistive
75
+ * technologies can distinguish between multiple navigation landmarks.
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * <Nav aria-label="Breadcrumb">...</Nav>
80
+ * <Nav aria-label="Product categories">...</Nav>
81
+ * ```
82
+ */
83
+ interface NavProps extends React.HTMLAttributes<HTMLElement> {
84
+ /** REQUIRED — describes the purpose of this navigation region for screen readers. */
85
+ "aria-label": string;
86
+ children: React.ReactNode;
87
+ }
88
+ declare function Nav({ className, children, ...props }: NavProps): react_jsx_runtime.JSX.Element;
89
+ /**
90
+ * Semantic `<header>` element for block-level component headers.
91
+ * Use inside `Section`, `Article`, or card bodies — NOT as the page-level header.
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * <Article>
96
+ * <BlockHeader className="mb-4">
97
+ * <Heading level={2}>Post title</Heading>
98
+ * </BlockHeader>
99
+ * </Article>
100
+ * ```
101
+ */
102
+ interface BlockHeaderProps extends React.HTMLAttributes<HTMLElement> {
103
+ children: React.ReactNode;
104
+ }
105
+ declare function BlockHeader({ className, children, ...props }: BlockHeaderProps): react_jsx_runtime.JSX.Element;
106
+ /**
107
+ * Semantic `<footer>` element for block-level component footers.
108
+ * Use inside `Section`, `Article`, or card bodies — NOT as the page-level footer.
109
+ */
110
+ interface BlockFooterProps extends React.HTMLAttributes<HTMLElement> {
111
+ children: React.ReactNode;
112
+ }
113
+ declare function BlockFooter({ className, children, ...props }: BlockFooterProps): react_jsx_runtime.JSX.Element;
114
+ /**
115
+ * Semantic `<ul>` (unordered list) element.
116
+ *
117
+ * @example
118
+ * ```tsx
119
+ * <Ul className="space-y-2">
120
+ * <Li>Item one</Li>
121
+ * <Li>Item two</Li>
122
+ * </Ul>
123
+ * ```
124
+ */
125
+ interface UlProps extends React.HTMLAttributes<HTMLUListElement> {
126
+ children: React.ReactNode;
127
+ }
128
+ declare function Ul({ className, children, ...props }: UlProps): react_jsx_runtime.JSX.Element;
129
+ /**
130
+ * Semantic `<ol>` (ordered list) element.
131
+ *
132
+ * @example
133
+ * ```tsx
134
+ * <Ol className="list-decimal pl-4 space-y-1">
135
+ * <Li>Step one</Li>
136
+ * <Li>Step two</Li>
137
+ * </Ol>
138
+ * ```
139
+ */
140
+ interface OlProps extends React.HTMLAttributes<HTMLOListElement> {
141
+ children: React.ReactNode;
142
+ }
143
+ declare function Ol({ className, children, ...props }: OlProps): react_jsx_runtime.JSX.Element;
144
+ /**
145
+ * Semantic `<li>` (list item) element. Use inside `Ul` or `Ol`.
146
+ */
147
+ interface LiProps extends React.LiHTMLAttributes<HTMLLIElement> {
148
+ children: React.ReactNode;
149
+ }
150
+ declare function Li({ className, children, ...props }: LiProps): react_jsx_runtime.JSX.Element;
151
+
152
+ interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
153
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
154
+ variant?: "primary" | "secondary" | "muted" | "none";
155
+ children: React.ReactNode;
156
+ }
157
+ declare function Heading({ level, variant, className, children, ...props }: HeadingProps): react_jsx_runtime.JSX.Element;
158
+ interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
159
+ variant?: "primary" | "secondary" | "muted" | "error" | "success" | "none";
160
+ size?: "xs" | "sm" | "base" | "lg" | "xl";
161
+ weight?: "normal" | "medium" | "semibold" | "bold";
162
+ children: React.ReactNode;
163
+ }
164
+ declare function Text({ variant, size, weight, className, children, ...props }: TextProps): react_jsx_runtime.JSX.Element;
165
+ interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
166
+ required?: boolean;
167
+ children: React.ReactNode;
168
+ }
169
+ declare function Label({ required, className, children, ...props }: LabelProps): react_jsx_runtime.JSX.Element;
170
+ interface CaptionProps extends React.HTMLAttributes<HTMLSpanElement> {
171
+ /** "default" — muted grey (default); "accent" — indigo, semibold; "inverse" — light indigo for use on dark indigo backgrounds */
172
+ variant?: "default" | "accent" | "inverse";
173
+ children: React.ReactNode;
174
+ }
175
+ declare function Caption({ variant, className, children, ...props }: CaptionProps): react_jsx_runtime.JSX.Element;
176
+ /**
177
+ * Inline wrapper for styled text fragments. Use instead of a raw `<span>`.
178
+ * When `variant` is "inherit" (default) the element carries no colour classes
179
+ * so it blends with its parent — perfect for purely structural/CSS wrappers.
180
+ *
181
+ * @example
182
+ * ```tsx
183
+ * <Span className="bg-gradient-to-r from-indigo-500 to-purple-500 bg-clip-text text-transparent">
184
+ * Highlighted
185
+ * </Span>
186
+ *
187
+ * <Span variant="error" weight="semibold">Required</Span>
188
+ * ```
189
+ */
190
+ interface SpanProps extends React.HTMLAttributes<HTMLSpanElement> {
191
+ /** Colour variant. "inherit" (default) applies no colour class. */
192
+ variant?: "inherit" | "primary" | "secondary" | "muted" | "error" | "success" | "accent";
193
+ size?: "xs" | "sm" | "base" | "lg" | "xl";
194
+ weight?: "normal" | "medium" | "semibold" | "bold";
195
+ children?: React.ReactNode;
196
+ }
197
+ declare function Span({ variant, size, weight, className, children, ...props }: SpanProps): react_jsx_runtime.JSX.Element;
198
+
199
+ /**
200
+ * Spinner — generic loading indicator.
201
+ *
202
+ * Extracted from src/components/ui/Spinner.tsx for @mohasinac/ui.
203
+ * No app-specific imports; pure Tailwind CSS.
204
+ */
205
+ interface SpinnerProps {
206
+ size?: "sm" | "md" | "lg" | "xl";
207
+ variant?: "primary" | "white" | "current";
208
+ className?: string;
209
+ label?: string;
210
+ }
211
+ declare function Spinner({ size, variant, className, label, }: SpinnerProps): react_jsx_runtime.JSX.Element;
212
+
213
+ /**
214
+ * Skeleton — content placeholder with pulse or wave animation.
215
+ *
216
+ * Extracted from src/components/ui/Skeleton.tsx for @mohasinac/ui.
217
+ * Wave animation uses a plain <style> element (no styled-jsx dependency).
218
+ */
219
+ interface SkeletonProps {
220
+ variant?: "text" | "circular" | "rectangular";
221
+ width?: string | number;
222
+ height?: string | number;
223
+ className?: string;
224
+ animation?: "pulse" | "wave" | "none";
225
+ }
226
+ declare function Skeleton({ variant, width, height, className, animation, }: SkeletonProps): react_jsx_runtime.JSX.Element;
227
+
228
+ /**
229
+ * Button — versatile button with multiple variants, sizes, and loading state.
230
+ *
231
+ * Extracted from src/components/ui/Button.tsx for @mohasinac/ui.
232
+ * Theme values inlined from THEME_CONSTANTS.button and THEME_CONSTANTS.colors.button.
233
+ */
234
+ declare const UI_BUTTON: {
235
+ readonly base: "inline-flex items-center justify-center font-medium rounded-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed";
236
+ readonly active: "active:scale-95";
237
+ readonly variants: {
238
+ readonly primary: "bg-primary-600 text-white hover:bg-primary-700 active:bg-primary-800 shadow-sm focus:ring-primary-500/30 dark:bg-secondary-500 dark:text-white dark:hover:bg-secondary-400 dark:active:bg-secondary-600 dark:focus:ring-secondary-400/30";
239
+ readonly secondary: "bg-primary-700 text-white hover:bg-primary-600 active:bg-primary-800 shadow-md focus:ring-primary-500 dark:bg-secondary-700 dark:text-white dark:hover:bg-secondary-600 dark:active:bg-secondary-800 dark:focus:ring-secondary-500";
240
+ readonly outline: "border border-zinc-200 dark:border-slate-700 bg-white dark:bg-transparent text-zinc-900 dark:text-zinc-100 hover:bg-zinc-50 dark:hover:bg-slate-800 focus:ring-zinc-400";
241
+ readonly ghost: "text-zinc-700 dark:text-zinc-300 hover:bg-zinc-100 dark:hover:bg-slate-800 focus:ring-zinc-400";
242
+ readonly danger: "bg-red-600 text-white hover:bg-red-500 active:bg-red-700 shadow-sm shadow-red-600/10 focus:ring-red-500";
243
+ readonly warning: "bg-amber-500 text-white hover:bg-amber-400 active:bg-amber-600 shadow-sm shadow-amber-500/10 focus:ring-amber-500";
244
+ };
245
+ readonly sizes: {
246
+ readonly sm: "px-2.5 py-1.5 text-xs sm:px-3 sm:text-sm gap-1.5 min-h-[36px]";
247
+ readonly md: "px-3 py-2 text-sm sm:px-4 sm:py-2.5 sm:text-base gap-2 min-h-[44px]";
248
+ readonly lg: "px-4 py-2.5 text-base sm:px-6 sm:py-3 sm:text-lg gap-2.5 min-h-[44px]";
249
+ };
250
+ };
251
+ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
252
+ variant?: keyof typeof UI_BUTTON.variants;
253
+ size?: keyof typeof UI_BUTTON.sizes;
254
+ isLoading?: boolean;
255
+ children?: React.ReactNode;
256
+ }
257
+ declare function Button({ variant, size, className, isLoading, disabled, children, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
258
+
259
+ /**
260
+ * Badge — compact label with ring border variants for status, roles, and categories.
261
+ *
262
+ * Extracted from src/components/ui/Badge.tsx for @mohasinac/ui.
263
+ * Theme values inlined from THEME_CONSTANTS.badge and THEME_CONSTANTS.colors.badge.
264
+ */
265
+ declare const BADGE_CLASSES: {
266
+ readonly active: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20";
267
+ readonly inactive: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-600 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-400 dark:ring-zinc-400/20";
268
+ readonly pending: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20";
269
+ readonly approved: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20";
270
+ readonly rejected: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20";
271
+ readonly success: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-emerald-50 text-emerald-700 ring-1 ring-emerald-600/20 dark:bg-emerald-900/30 dark:text-emerald-300 dark:ring-emerald-400/20";
272
+ readonly warning: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-amber-50 text-amber-700 ring-1 ring-amber-600/20 dark:bg-amber-900/30 dark:text-amber-300 dark:ring-amber-400/20";
273
+ readonly danger: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-rose-50 text-rose-700 ring-1 ring-rose-600/20 dark:bg-rose-900/30 dark:text-rose-300 dark:ring-rose-400/20";
274
+ readonly info: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20";
275
+ readonly admin: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-purple-50 text-purple-700 ring-1 ring-purple-600/20 dark:bg-purple-900/30 dark:text-purple-300 dark:ring-purple-400/20";
276
+ readonly moderator: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-sky-50 text-sky-700 ring-1 ring-sky-600/20 dark:bg-sky-900/30 dark:text-sky-300 dark:ring-sky-400/20";
277
+ readonly seller: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-teal-50 text-teal-700 ring-1 ring-teal-600/20 dark:bg-teal-900/30 dark:text-teal-300 dark:ring-teal-400/20";
278
+ readonly user: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20";
279
+ readonly default: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-zinc-100 text-zinc-700 ring-1 ring-zinc-500/10 dark:bg-slate-800 dark:text-zinc-300 dark:ring-zinc-400/20";
280
+ readonly primary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300";
281
+ readonly secondary: "inline-flex items-center gap-1 px-2.5 py-0.5 text-xs font-semibold rounded-full bg-primary-100 text-primary-700 dark:bg-primary-900/50 dark:text-primary-300";
282
+ };
283
+ type BadgeVariant = keyof typeof BADGE_CLASSES;
284
+ interface BadgeProps {
285
+ children: React.ReactNode;
286
+ variant?: BadgeVariant;
287
+ className?: string;
288
+ }
289
+ declare function Badge({ children, variant, className, }: BadgeProps): react_jsx_runtime.JSX.Element;
290
+
291
+ /**
292
+ * Alert — flexible alert/notification with variant icons and optional dismiss.
293
+ *
294
+ * Extracted from src/components/feedback/Alert.tsx for @mohasinac/ui.
295
+ * Theme values inlined from THEME_CONSTANTS.colors.alert and THEME_CONSTANTS.colors.button.
296
+ */
297
+ declare const ALERT_STYLES: {
298
+ readonly info: {
299
+ readonly container: "bg-sky-50 border-sky-200/80 dark:bg-sky-950/30 dark:border-sky-800/50";
300
+ readonly icon: "text-sky-600 dark:text-sky-400";
301
+ readonly title: "text-sky-900 dark:text-sky-200";
302
+ readonly text: "text-sky-800 dark:text-sky-300";
303
+ };
304
+ readonly success: {
305
+ readonly container: "bg-emerald-50 border-emerald-200/80 dark:bg-emerald-950/30 dark:border-emerald-800/50";
306
+ readonly icon: "text-emerald-600 dark:text-emerald-400";
307
+ readonly title: "text-emerald-900 dark:text-emerald-200";
308
+ readonly text: "text-emerald-800 dark:text-emerald-300";
309
+ };
310
+ readonly warning: {
311
+ readonly container: "bg-amber-50 border-amber-200/80 dark:bg-amber-950/30 dark:border-amber-800/50";
312
+ readonly icon: "text-amber-600 dark:text-amber-400";
313
+ readonly title: "text-amber-900 dark:text-amber-200";
314
+ readonly text: "text-amber-800 dark:text-amber-300";
315
+ };
316
+ readonly error: {
317
+ readonly container: "bg-red-50 border-red-200/80 dark:bg-red-950/30 dark:border-red-800/50";
318
+ readonly icon: "text-red-600 dark:text-red-400";
319
+ readonly title: "text-red-900 dark:text-red-200";
320
+ readonly text: "text-red-800 dark:text-red-300";
321
+ };
322
+ };
323
+ interface AlertProps {
324
+ children: React.ReactNode;
325
+ variant?: keyof typeof ALERT_STYLES;
326
+ title?: string;
327
+ onClose?: () => void;
328
+ className?: string;
329
+ }
330
+ declare function Alert({ children, variant, title, onClose, className, }: AlertProps): react_jsx_runtime.JSX.Element;
331
+
332
+ interface DividerProps {
333
+ label?: string;
334
+ orientation?: "horizontal" | "vertical";
335
+ className?: string;
336
+ }
337
+ declare function Divider({ label, orientation, className, }: DividerProps): react_jsx_runtime.JSX.Element;
338
+
339
+ interface ProgressProps {
340
+ value: number;
341
+ max?: number;
342
+ variant?: "primary" | "success" | "warning" | "error";
343
+ size?: "sm" | "md" | "lg";
344
+ label?: string;
345
+ showValue?: boolean;
346
+ className?: string;
347
+ }
348
+ declare function Progress({ value, max, variant, size, label, showValue, className, }: ProgressProps): react_jsx_runtime.JSX.Element;
349
+ interface IndeterminateProgressProps {
350
+ variant?: "primary" | "success" | "warning" | "error";
351
+ size?: "sm" | "md" | "lg";
352
+ label?: string;
353
+ className?: string;
354
+ }
355
+ declare function IndeterminateProgress({ variant, size, label, className, }: IndeterminateProgressProps): react_jsx_runtime.JSX.Element;
356
+
357
+ /**
358
+ * Pagination — smart ellipsis pagination with prev/next chevrons.
359
+ *
360
+ * Accepts either individual props OR a `paginationConfig` object
361
+ * (merged with DEFAULT_PAGINATION_CONFIG). Individual props take precedence.
362
+ */
363
+ interface PaginationProps {
364
+ currentPage: number;
365
+ totalPages: number;
366
+ onPageChange: (page: number) => void;
367
+ /**
368
+ * Composable pagination config. Merged with DEFAULT_PAGINATION_CONFIG.
369
+ * Individual flat props override this.
370
+ */
371
+ paginationConfig?: Partial<PaginationConfig>;
372
+ /** Max visible page buttons before ellipsis kicks in. Default: 7 */
373
+ maxVisible?: number;
374
+ showFirstLast?: boolean;
375
+ showPrevNext?: boolean;
376
+ disabled?: boolean;
377
+ size?: "sm" | "md" | "lg";
378
+ className?: string;
379
+ }
380
+ declare function Pagination({ currentPage, totalPages, onPageChange, paginationConfig, maxVisible: maxVisibleProp, showFirstLast: showFirstLastProp, showPrevNext: showPrevNextProp, disabled, size: sizeProp, className, }: PaginationProps): react_jsx_runtime.JSX.Element;
381
+
382
+ /**
383
+ * StatusBadge — semantic color map for order/payment/review/ticket status strings.
384
+ *
385
+ * Wraps @mohasinac/ui Badge with a pre-defined status → variant mapping.
386
+ * No app-specific imports.
387
+ */
388
+ type OrderStatus = "pending" | "confirmed" | "processing" | "shipped" | "delivered" | "cancelled" | "refunded" | "failed";
389
+ type PaymentStatus = "pending" | "paid" | "failed" | "refunded" | "partially_refunded";
390
+ type ReviewStatus = "pending" | "approved" | "rejected";
391
+ type TicketStatus = "open" | "in_progress" | "resolved" | "closed";
392
+ type GenericStatus = "active" | "inactive" | "pending" | "approved" | "rejected" | "success" | "warning" | "danger" | "info";
393
+ type StatusBadgeStatus = OrderStatus | PaymentStatus | ReviewStatus | TicketStatus | GenericStatus;
394
+ interface StatusBadgeProps {
395
+ status: StatusBadgeStatus;
396
+ label?: string;
397
+ className?: string;
398
+ }
399
+ declare function StatusBadge({ status, label, className }: StatusBadgeProps): react_jsx_runtime.JSX.Element;
400
+
401
+ /**
402
+ * Modal — centered dialog with backdrop, multiple sizes, ESC-to-close, and scroll lock.
403
+ *
404
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
405
+ * Renders via React Portal for correct z-index layering.
406
+ */
407
+ interface ModalProps {
408
+ isOpen: boolean;
409
+ onClose: () => void;
410
+ title?: string;
411
+ children: React.ReactNode;
412
+ size?: "sm" | "md" | "lg" | "xl" | "full";
413
+ showCloseButton?: boolean;
414
+ /** Additional classNames for the modal panel */
415
+ className?: string;
416
+ }
417
+ declare function Modal({ isOpen, onClose, title, children, size, showCloseButton, className, }: ModalProps): React.ReactPortal | null;
418
+
419
+ /**
420
+ * Drawer — slide-in panel from left, right, or bottom.
421
+ *
422
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
423
+ * Bottom variant gets `rounded-t-2xl` and can be swipe-dismissed via drag handle.
424
+ */
425
+ interface DrawerProps {
426
+ isOpen: boolean;
427
+ onClose: () => void;
428
+ title?: string;
429
+ children: React.ReactNode;
430
+ footer?: React.ReactNode;
431
+ side?: "left" | "right" | "bottom";
432
+ /** Width for left/right drawers. Default: 'md' */
433
+ size?: "sm" | "md" | "lg" | "full";
434
+ showCloseButton?: boolean;
435
+ className?: string;
436
+ }
437
+ declare function Drawer({ isOpen, onClose, title, children, footer, side, size, showCloseButton, className, }: DrawerProps): React.ReactPortal | null;
438
+
439
+ /**
440
+ * Select — accessible combobox with label, error state, and disabled support.
441
+ *
442
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
443
+ */
444
+ interface SelectOption<V = string> {
445
+ label: string;
446
+ value: V;
447
+ disabled?: boolean;
448
+ }
449
+ interface SelectProps<V extends string = string> {
450
+ options: SelectOption<V>[];
451
+ value?: V;
452
+ onChange?: (value: V) => void;
453
+ placeholder?: string;
454
+ label?: string;
455
+ error?: string;
456
+ disabled?: boolean;
457
+ required?: boolean;
458
+ className?: string;
459
+ id?: string;
460
+ }
461
+ declare function Select<V extends string = string>({ options, value, onChange, placeholder, label, error, disabled, required, className, id: externalId, }: SelectProps<V>): react_jsx_runtime.JSX.Element;
462
+
463
+ /**
464
+ * StarRating — 0–5 star display/interactive rating.
465
+ *
466
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
467
+ * Use `readOnly` for display, omit it for interactive mode with hover preview.
468
+ */
469
+ interface StarRatingProps {
470
+ value?: number;
471
+ onChange?: (value: number) => void;
472
+ max?: number;
473
+ size?: "sm" | "md" | "lg";
474
+ readOnly?: boolean;
475
+ className?: string;
476
+ /** Accessible label describing what is being rated */
477
+ label?: string;
478
+ }
479
+ declare function StarRating({ value, onChange, max, size, readOnly, className, label, }: StarRatingProps): react_jsx_runtime.JSX.Element;
480
+
481
+ /**
482
+ * Breadcrumb — accessible navigation trail with ChevronRight separators.
483
+ *
484
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
485
+ * Last item is displayed with `font-medium` (non-link, current page).
486
+ */
487
+ interface BreadcrumbItem {
488
+ label: string;
489
+ href?: string;
490
+ }
491
+ interface BreadcrumbProps {
492
+ items: BreadcrumbItem[];
493
+ className?: string;
494
+ }
495
+ declare function Breadcrumb({ items, className }: BreadcrumbProps): react_jsx_runtime.JSX.Element;
496
+
497
+ /**
498
+ * ImageLightbox — full-screen image overlay with keyboard navigation.
499
+ *
500
+ * Standalone @mohasinac/ui primitive. No app-specific imports.
501
+ * Navigation: ← / → arrow keys, Esc to close. Displays item counter.
502
+ *
503
+ * Uses a standard <img> tag for framework portability.
504
+ * In a Next.js app, callers may swap src with a blurDataURL if desired.
505
+ */
506
+ interface LightboxImage {
507
+ src: string;
508
+ alt?: string;
509
+ caption?: string;
510
+ }
511
+ interface ImageLightboxProps {
512
+ images: LightboxImage[];
513
+ /** The index to open. Pass `null` or `-1` to close. */
514
+ activeIndex: number | null;
515
+ onClose: () => void;
516
+ onNavigate?: (index: number) => void;
517
+ }
518
+ declare function ImageLightbox({ images, activeIndex, onClose, onNavigate, }: ImageLightboxProps): React.ReactPortal | null;
519
+
520
+ /**
521
+ * Layout Primitives — Container, Stack, Row, Grid
522
+ *
523
+ * Thin component wrappers that turn semantic prop names into the correct
524
+ * Tailwind class strings from the app's THEME_CONSTANTS token map.
525
+ * Eliminates repeated inline class strings like "grid grid-cols-1 sm:grid-cols-2
526
+ * lg:grid-cols-3 gap-4" and "flex flex-row items-center justify-between gap-2".
527
+ *
528
+ * Token maps are inlined here (like UI_THEME in Typography.tsx) so the package
529
+ * stays independent of the host app's @/constants import path.
530
+ *
531
+ * @example
532
+ * ```tsx
533
+ * // Before
534
+ * <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
535
+ * <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
536
+ * <div className="flex flex-row items-center justify-between gap-2">
537
+ * <div className="flex flex-col gap-4">
538
+ *
539
+ * // After
540
+ * <Container>
541
+ * <Grid cols={3} gap="md">
542
+ * <Row justify="between" gap="sm">
543
+ * <Stack gap="md">
544
+ * ```
545
+ */
546
+ /**
547
+ * Gap tokens — maps to `gap-*` Tailwind classes.
548
+ * Mirrors THEME_CONSTANTS.spacing.gap in the host app.
549
+ */
550
+ declare const GAP_MAP: {
551
+ readonly none: "";
552
+ readonly px: "gap-px";
553
+ readonly xs: "gap-1";
554
+ readonly sm: "gap-2";
555
+ readonly "2.5": "gap-2.5";
556
+ readonly "3": "gap-3";
557
+ readonly md: "gap-4";
558
+ readonly lg: "gap-6";
559
+ readonly xl: "gap-8";
560
+ readonly "2xl": "gap-12";
561
+ };
562
+ type GapKey = keyof typeof GAP_MAP;
563
+ /**
564
+ * Page container sizes.
565
+ * Mirrors THEME_CONSTANTS.page.container in the host app.
566
+ */
567
+ declare const CONTAINER_MAP: {
568
+ /** `max-w-3xl` — blog posts, legal / policy pages */
569
+ readonly sm: "max-w-3xl mx-auto px-4 sm:px-6 lg:px-8";
570
+ /** `max-w-4xl` — narrow content, contact, about */
571
+ readonly md: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8";
572
+ /** `max-w-5xl` — medium content, checkout, help */
573
+ readonly lg: "max-w-5xl mx-auto px-4 sm:px-6 lg:px-8";
574
+ /** `max-w-6xl` — product detail, cart */
575
+ readonly xl: "max-w-6xl mx-auto px-4 sm:px-6 lg:px-8";
576
+ /** `max-w-7xl` — main content grids (default) */
577
+ readonly "2xl": "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8";
578
+ /** `max-w-screen-2xl` — full-bleed wide content */
579
+ readonly full: "max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8";
580
+ /** `max-w-screen-2xl` — wide store/seller layouts (no lg:px-8) */
581
+ readonly wide: "max-w-screen-2xl mx-auto px-4 sm:px-6";
582
+ };
583
+ type ContainerSize = keyof typeof CONTAINER_MAP;
584
+ /**
585
+ * Responsive grid column presets.
586
+ * Mirrors THEME_CONSTANTS.grid in the host app.
587
+ */
588
+ declare const GRID_MAP: {
589
+ readonly 1: "grid grid-cols-1";
590
+ readonly 2: "grid grid-cols-1 sm:grid-cols-2";
591
+ readonly 3: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-3";
592
+ readonly 4: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
593
+ readonly 5: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5";
594
+ readonly 6: "grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6";
595
+ /** Card grid — starts at 2 on mobile, max 5 on 2xl */
596
+ readonly cards: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4 2xl:grid-cols-5";
597
+ /** Equal halves on md+ */
598
+ readonly halves: "grid grid-cols-1 md:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2";
599
+ /** 2fr / 1fr split on md+ */
600
+ readonly twoThird: "grid grid-cols-1 md:grid-cols-[2fr_1fr]";
601
+ /** 1fr / 2fr split on md+ */
602
+ readonly oneThird: "grid grid-cols-1 md:grid-cols-[1fr_2fr]";
603
+ /** Fixed 280px left sidebar + 1fr on lg+ */
604
+ readonly sidebar: "grid grid-cols-1 lg:grid-cols-[280px_1fr]";
605
+ /** 1fr + fixed 280px right sidebar on lg+ */
606
+ readonly sidebarRight: "grid grid-cols-1 lg:grid-cols-[1fr_280px]";
607
+ /** Fixed 320px left sidebar + 1fr on lg+ (admin layout) */
608
+ readonly sidebarWide: "grid grid-cols-1 lg:grid-cols-[320px_1fr]";
609
+ /** CSS auto-fill, min 200px columns */
610
+ readonly autoSm: "grid grid-cols-[repeat(auto-fill,minmax(200px,1fr))]";
611
+ /** CSS auto-fill, min 280px columns */
612
+ readonly autoMd: "grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))]";
613
+ /** CSS auto-fill, min 360px columns */
614
+ readonly autoLg: "grid grid-cols-[repeat(auto-fill,minmax(360px,1fr))]";
615
+ };
616
+ type GridCols = keyof typeof GRID_MAP;
617
+ declare const ITEMS_MAP: {
618
+ readonly start: "items-start";
619
+ readonly center: "items-center";
620
+ readonly end: "items-end";
621
+ readonly stretch: "items-stretch";
622
+ readonly baseline: "items-baseline";
623
+ };
624
+ type ItemsAlign = keyof typeof ITEMS_MAP;
625
+ declare const JUSTIFY_MAP: {
626
+ readonly start: "justify-start";
627
+ readonly center: "justify-center";
628
+ readonly end: "justify-end";
629
+ readonly between: "justify-between";
630
+ readonly around: "justify-around";
631
+ readonly evenly: "justify-evenly";
632
+ };
633
+ type JustifyContent = keyof typeof JUSTIFY_MAP;
634
+ /**
635
+ * Page-level container with max-width + centering + responsive horizontal padding.
636
+ * Replaces repeated `max-w-7xl mx-auto px-4 sm:px-6 lg:px-8` strings.
637
+ *
638
+ * @example
639
+ * ```tsx
640
+ * <Container>...</Container> // max-w-7xl (default)
641
+ * <Container size="lg">...</Container> // max-w-5xl
642
+ * <Container size="full" as="main">...</Container>
643
+ * ```
644
+ */
645
+ interface ContainerProps extends React.HTMLAttributes<HTMLElement> {
646
+ /**
647
+ * Max-width breakpoint preset.
648
+ * - `sm` → `max-w-3xl` (blog / policy)
649
+ * - `md` → `max-w-4xl` (contact / about)
650
+ * - `lg` → `max-w-5xl` (checkout / help)
651
+ * - `xl` → `max-w-6xl` (product detail / cart)
652
+ * - `2xl` → `max-w-7xl` (main content grids — **default**)
653
+ * - `full`→ `max-w-screen-2xl` (full-bleed)
654
+ * - `wide`→ `max-w-screen-2xl` (compact px, no lg step)
655
+ */
656
+ size?: ContainerSize;
657
+ /** Render as a different element (e.g. `"main"`, `"section"`). Defaults to `"div"`. */
658
+ as?: React.ElementType;
659
+ children?: React.ReactNode;
660
+ }
661
+ declare function Container({ size, as, className, children, ...props }: ContainerProps): react_jsx_runtime.JSX.Element;
662
+ /**
663
+ * Vertical flex column. Use instead of `<div className="flex flex-col gap-4">`.
664
+ *
665
+ * @example
666
+ * ```tsx
667
+ * <Stack gap="sm">
668
+ * <Text>Line one</Text>
669
+ * <Text>Line two</Text>
670
+ * </Stack>
671
+ *
672
+ * // As a list
673
+ * <Stack as="ul" gap="xs">
674
+ * <Li>Item</Li>
675
+ * </Stack>
676
+ * ```
677
+ */
678
+ interface StackProps extends React.HTMLAttributes<HTMLElement> {
679
+ /** Space between children. Defaults to `"md"` (`gap-4`). */
680
+ gap?: GapKey;
681
+ /** Cross-axis (horizontal) alignment. Defaults to `"stretch"`. */
682
+ align?: Extract<ItemsAlign, "start" | "center" | "end" | "stretch">;
683
+ /** Render as a different element. Defaults to `"div"`. */
684
+ as?: React.ElementType;
685
+ children?: React.ReactNode;
686
+ }
687
+ declare function Stack({ gap, align, as, className, children, ...props }: StackProps): react_jsx_runtime.JSX.Element;
688
+ /**
689
+ * Horizontal flex row. Use instead of `<div className="flex items-center gap-3">`.
690
+ *
691
+ * @example
692
+ * ```tsx
693
+ * <Row gap="sm" justify="between">
694
+ * <Heading level={3}>Title</Heading>
695
+ * <Button>Action</Button>
696
+ * </Row>
697
+ *
698
+ * <Row gap="xs" wrap>
699
+ * <Badge>tag</Badge>
700
+ * <Badge>other</Badge>
701
+ * </Row>
702
+ * ```
703
+ */
704
+ interface RowProps extends React.HTMLAttributes<HTMLElement> {
705
+ /** Space between children. Defaults to `"md"` (`gap-4`). */
706
+ gap?: GapKey;
707
+ /** Cross-axis (vertical) alignment. Defaults to `"center"`. */
708
+ align?: ItemsAlign;
709
+ /** Main-axis (horizontal) distribution. Defaults to `"start"`. */
710
+ justify?: JustifyContent;
711
+ /** Allow children to wrap onto multiple lines. */
712
+ wrap?: boolean;
713
+ /** Render as a different element. Defaults to `"div"`. */
714
+ as?: React.ElementType;
715
+ children?: React.ReactNode;
716
+ }
717
+ declare function Row({ gap, align, justify, wrap, as, className, children, ...props }: RowProps): react_jsx_runtime.JSX.Element;
718
+ /**
719
+ * Responsive CSS grid. Use instead of `<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">`.
720
+ *
721
+ * @example
722
+ * ```tsx
723
+ * <Grid cols={3} gap="md">
724
+ * <ProductCard />
725
+ * <ProductCard />
726
+ * </Grid>
727
+ *
728
+ * <Grid cols="sidebar" gap="lg">
729
+ * <Aside>Filters</Aside>
730
+ * <Main>Results</Main>
731
+ * </Grid>
732
+ * ```
733
+ */
734
+ interface GridProps extends React.HTMLAttributes<HTMLElement> {
735
+ /**
736
+ * Column preset.
737
+ * - Numbers `1`–`6` → mobile-first responsive stacks
738
+ * - `"halves"` → equal 2-col on md+
739
+ * - `"sidebar"` / `"sidebarRight"` / `"sidebarWide"` → fixed+flexible splits
740
+ * - `"twoThird"` / `"oneThird"` → 2fr/1fr splits
741
+ * - `"autoSm"` / `"autoMd"` / `"autoLg"` → CSS auto-fill grids
742
+ * - Omit (or `undefined`) to use a raw `grid` base and supply columns via
743
+ * the `className` prop directly (e.g. `className="grid-cols-2"`). Useful
744
+ * for fixed non-responsive column counts (form field pairs, button rows).
745
+ */
746
+ cols?: GridCols;
747
+ /** Space between grid cells. Defaults to `"md"` (`gap-4`). */
748
+ gap?: GapKey;
749
+ /** Render as a different element. Defaults to `"div"`. */
750
+ as?: React.ElementType;
751
+ children?: React.ReactNode;
752
+ }
753
+ declare function Grid({ cols, gap, as, className, children, ...props }: GridProps): react_jsx_runtime.JSX.Element;
754
+
755
+ /**
756
+ * DataTable — generic sortable + paginated table promoted to @mohasinac/ui.
757
+ *
758
+ * Accepts `tableConfig` and `paginationConfig` for composable configuration.
759
+ * Apps can spread-merge DEFAULT_TABLE_CONFIG / DEFAULT_PAGINATION_CONFIG and
760
+ * override only the values they need, then pass the result once.
761
+ *
762
+ * Individual flat props (pageSize, stickyHeader, striped, …) still work and
763
+ * take precedence over anything in tableConfig when explicitly provided.
764
+ */
765
+ type ViewMode = "table" | "grid" | "list";
766
+ /**
767
+ * Column descriptor for the DataTable component.
768
+ * Narrows `render` to return `ReactNode` (TableColumn uses `unknown` so
769
+ * contracts stays React-free). Fully compatible with `TableColumn<T>`.
770
+ */
771
+ type DataTableColumn<T> = Omit<TableColumn<T>, "render"> & {
772
+ render?: (item: T) => ReactNode;
773
+ };
774
+ interface DataTableProps<T> {
775
+ data: T[];
776
+ columns: DataTableColumn<T>[];
777
+ keyExtractor: (item: T) => string;
778
+ onRowClick?: (item: T) => void;
779
+ loading?: boolean;
780
+ emptyMessage?: string;
781
+ actions?: (item: T) => ReactNode;
782
+ /** When true, disables internal pagination — render your own externally. Default: false */
783
+ externalPagination?: boolean;
784
+ /**
785
+ * Composable table configuration.
786
+ * Deep-merged with DEFAULT_TABLE_CONFIG. Individual flat props (pageSize,
787
+ * stickyHeader, etc.) override this when explicitly provided.
788
+ */
789
+ tableConfig?: Partial<TableConfig>;
790
+ /**
791
+ * Composable pagination configuration.
792
+ * Merged with DEFAULT_PAGINATION_CONFIG. Individual flat props override this.
793
+ */
794
+ paginationConfig?: Partial<PaginationConfig>;
795
+ /** Items per page. Explicit value overrides tableConfig.pageSize. Default: 20 */
796
+ pageSize?: number;
797
+ mobileCardRender?: (item: T) => ReactNode;
798
+ emptyState?: ReactNode;
799
+ emptyIcon?: ReactNode;
800
+ emptyTitle?: string;
801
+ stickyHeader?: boolean;
802
+ striped?: boolean;
803
+ showViewToggle?: boolean;
804
+ showTableView?: boolean;
805
+ viewMode?: ViewMode;
806
+ defaultViewMode?: ViewMode;
807
+ onViewModeChange?: (mode: ViewMode) => void;
808
+ selectable?: boolean;
809
+ selectedIds?: string[];
810
+ onSelectionChange?: (ids: string[]) => void;
811
+ /**
812
+ * Number of grid columns for card grid view.
813
+ * Matches Layout GRID_MAP keys: 1–6, "autoSm", "autoMd", "autoLg".
814
+ * Default: 6 (2→3→4→5→6 across breakpoints).
815
+ */
816
+ gridCols?: GridCols;
817
+ labels?: {
818
+ loading?: string;
819
+ noDataTitle?: string;
820
+ noDataDescription?: string;
821
+ actions?: string;
822
+ tableView?: string;
823
+ gridView?: string;
824
+ listView?: string;
825
+ };
826
+ }
827
+ declare function DataTable<T extends Record<string, any>>({ data, columns, keyExtractor, onRowClick, loading, emptyMessage, actions, mobileCardRender, emptyState, emptyIcon, emptyTitle, tableConfig, paginationConfig, externalPagination, pageSize: pageSizeProp, stickyHeader: stickyHeaderProp, striped: stripedProp, showViewToggle: showViewToggleProp, showTableView, viewMode: controlledViewMode, defaultViewMode: defaultViewModeProp, onViewModeChange, selectable: selectableProp, selectedIds, onSelectionChange, gridCols, labels, }: DataTableProps<T>): react_jsx_runtime.JSX.Element;
828
+
829
+ export { Alert, type AlertProps, Article, type ArticleProps, Aside, type AsideProps, Badge, type BadgeProps, type BadgeVariant, BlockFooter, type BlockFooterProps, BlockHeader, type BlockHeaderProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Caption, Container, type ContainerProps, type ContainerSize, DataTable, type DataTableColumn, type DataTableProps, Divider, type DividerProps, Drawer, type DrawerProps, GRID_MAP, type GapKey, type GenericStatus, Grid, type GridCols, type GridProps, Heading, ImageLightbox, type ImageLightboxProps, IndeterminateProgress, type IndeterminateProgressProps, Label, Li, type LiProps, type LightboxImage, Main, type MainProps, Modal, type ModalProps, Nav, type NavProps, Ol, type OlProps, type OrderStatus, Pagination, type PaginationProps, type PaymentStatus, Progress, type ProgressProps, type ReviewStatus, Row, type RowProps, Section, type SectionProps, Select, type SelectOption, type SelectProps, Skeleton, type SkeletonProps, Span, Spinner, type SpinnerProps, Stack, type StackProps, StarRating, type StarRatingProps, StatusBadge, type StatusBadgeProps, type StatusBadgeStatus, Text, type TicketStatus, Ul, type UlProps };