@web-my-money/blocks 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/app.d.mts ADDED
@@ -0,0 +1,454 @@
1
+ import * as React from 'react';
2
+ export { L as LightboxGallery, a as LightboxGalleryProps, b as LightboxImageItem, T as Thumbnail, c as ThumbnailProps } from './index-D5sr_PKq.mjs';
3
+
4
+ type BannerVariant = "info" | "success" | "warning" | "danger" | "brand";
5
+ interface NotificationBannerProps {
6
+ variant?: BannerVariant;
7
+ message: React.ReactNode;
8
+ /** Link label + href shown after the message */
9
+ action?: {
10
+ label: string;
11
+ href?: string;
12
+ onClick?: () => void;
13
+ };
14
+ /** Allow dismissal — if omitted, banner is permanent */
15
+ dismissible?: boolean;
16
+ /** Called when banner is dismissed */
17
+ onDismiss?: () => void;
18
+ /** Controlled visibility — manage externally */
19
+ visible?: boolean;
20
+ className?: string;
21
+ }
22
+ declare function NotificationBanner({ variant, message, action, dismissible, onDismiss, visible, className, }: NotificationBannerProps): React.JSX.Element;
23
+
24
+ interface StatCardProps {
25
+ title: string;
26
+ value: string | number;
27
+ /** e.g. "+12.4%" — positive prefixed with + triggers green, negative triggers red */
28
+ delta?: string;
29
+ deltaLabel?: string;
30
+ icon?: React.ReactNode;
31
+ /** Sparkline or chart slot — render anything here */
32
+ chart?: React.ReactNode;
33
+ /** "success" | "warning" | "danger" | "info" — overrides delta-based color */
34
+ status?: "success" | "warning" | "danger" | "info";
35
+ className?: string;
36
+ }
37
+ declare function StatCard({ title, value, delta, deltaLabel, icon, chart, status, className, }: StatCardProps): React.JSX.Element;
38
+
39
+ interface BreadcrumbItem {
40
+ label: string;
41
+ href?: string;
42
+ }
43
+ interface PageHeaderProps {
44
+ /** Main page title */
45
+ title: string;
46
+ /** Short description below the title */
47
+ description?: string;
48
+ /** Array of breadcrumb items; last item is the current page (no href needed) */
49
+ breadcrumb?: BreadcrumbItem[];
50
+ /** Action buttons / selects rendered right-aligned */
51
+ actions?: React.ReactNode;
52
+ /** Extra slot below title row (status badges, tabs, etc.) */
53
+ below?: React.ReactNode;
54
+ className?: string;
55
+ }
56
+ declare function PageHeader({ title, description, breadcrumb, actions, below, className, }: PageHeaderProps): React.JSX.Element;
57
+
58
+ interface EmptyStateProps {
59
+ icon?: React.ReactNode;
60
+ title: string;
61
+ description?: string;
62
+ /** Primary CTA */
63
+ action?: React.ReactNode;
64
+ /** Secondary CTA / link */
65
+ secondaryAction?: React.ReactNode;
66
+ /** "page" = full centred section | "card" = compact inline variant */
67
+ variant?: "page" | "card";
68
+ className?: string;
69
+ }
70
+ declare function EmptyState({ icon, title, description, action, secondaryAction, variant, className, }: EmptyStateProps): React.JSX.Element;
71
+
72
+ interface DashboardHeaderProps {
73
+ pageTitle: string;
74
+ notificationsCount?: number;
75
+ actions?: React.ReactNode;
76
+ className?: string;
77
+ }
78
+ /**
79
+ * @deprecated Use `AppShell`'s `headerActions` slot (or `PageHeader`/`PageHeaderBanner`
80
+ * for in-content headers) instead. `DashboardHeader` was the older pairing for
81
+ * `SidebarNavigation` before `AppShell` unified the chrome. Kept for existing consumers.
82
+ */
83
+ declare function DashboardHeader({ pageTitle, notificationsCount, actions, className, }: DashboardHeaderProps): React.JSX.Element;
84
+
85
+ interface MetricCard {
86
+ title: string;
87
+ value: string;
88
+ description?: string;
89
+ icon?: React.ReactNode;
90
+ }
91
+ interface DataSummaryCardsProps {
92
+ metrics: MetricCard[];
93
+ columns?: 2 | 3 | 4;
94
+ className?: string;
95
+ }
96
+ declare function DataSummaryCards({ metrics, columns, className, }: DataSummaryCardsProps): React.JSX.Element;
97
+
98
+ interface DataTableRow {
99
+ id: string;
100
+ cells: React.ReactNode[];
101
+ isActive?: boolean;
102
+ }
103
+ interface DataTableProps {
104
+ title: string;
105
+ columns: string[];
106
+ rows: DataTableRow[];
107
+ activeBadgeLabel?: string;
108
+ className?: string;
109
+ /** Rows per page. Omit to render every row with no pager (unchanged default behavior). */
110
+ pageSize?: number;
111
+ /** Controlled current page (1-indexed). Uncontrolled (internal state) if omitted. */
112
+ page?: number;
113
+ onPageChange?: (page: number) => void;
114
+ }
115
+ declare function DataTable({ title, columns, rows, activeBadgeLabel, className, pageSize, page: controlledPage, onPageChange, }: DataTableProps): React.JSX.Element;
116
+
117
+ interface SidebarMenuItem {
118
+ label: string;
119
+ active?: boolean;
120
+ href?: string;
121
+ icon?: React.ReactNode;
122
+ }
123
+ interface SidebarNavigationProps {
124
+ appName: string;
125
+ userName?: string;
126
+ menuItems: SidebarMenuItem[];
127
+ footer?: React.ReactNode;
128
+ className?: string;
129
+ }
130
+ /**
131
+ * @deprecated Use `AppShell` (with `layout="sidebar"`) instead — it is responsive
132
+ * (mobile drawer + bottom-tabs), supports grouped/collapsible nav via `AppNavGroup`,
133
+ * and shares the standardized `AppBrand` header. `SidebarNavigation` is desktop-only
134
+ * with no mobile fallback and a thinner `SidebarMenuItem` model. Kept for existing
135
+ * consumers; do not use in new code.
136
+ */
137
+ declare function SidebarNavigation({ appName, userName, menuItems, footer, className, }: SidebarNavigationProps): React.JSX.Element;
138
+
139
+ interface KPIItem {
140
+ label: string;
141
+ value: string | number;
142
+ delta?: string;
143
+ deltaLabel?: string;
144
+ prefix?: string;
145
+ suffix?: string;
146
+ status?: "success" | "warning" | "danger" | "neutral";
147
+ }
148
+ interface KPIRowProps {
149
+ items: KPIItem[];
150
+ /** Dividers between cells */
151
+ dividers?: boolean;
152
+ className?: string;
153
+ }
154
+ declare function KPIRow({ items, dividers, className }: KPIRowProps): React.JSX.Element;
155
+
156
+ type ActivityType = "task" | "comment" | "alert" | "success" | "info" | "user";
157
+ interface ActivityItem {
158
+ id: string;
159
+ type?: ActivityType;
160
+ title: string;
161
+ description?: string;
162
+ timestamp: string;
163
+ /** Avatar URL or initials */
164
+ avatar?: string;
165
+ initials?: string;
166
+ /** Custom icon slot — overrides type-derived icon */
167
+ icon?: React.ReactNode;
168
+ /** Dot color override (Tailwind bg class) */
169
+ dotColor?: string;
170
+ meta?: string;
171
+ }
172
+ interface ActivityFeedProps {
173
+ items: ActivityItem[];
174
+ /** Show timeline connector line */
175
+ timeline?: boolean;
176
+ /** Compact row layout instead of card */
177
+ compact?: boolean;
178
+ className?: string;
179
+ emptyMessage?: string;
180
+ }
181
+ declare function ActivityFeed({ items, timeline, compact, className, emptyMessage, }: ActivityFeedProps): React.JSX.Element;
182
+
183
+ interface AppNavItem {
184
+ label: string;
185
+ href?: string;
186
+ icon?: React.ReactNode;
187
+ active?: boolean;
188
+ /** count badge (e.g. overdue) */
189
+ badge?: number | string;
190
+ onClick?: () => void;
191
+ /** Children — a dropdown (top layout) or an indented sub-list (sidebar). */
192
+ items?: AppNavItem[];
193
+ /** Shorter label for the mobile bottom tab bar (defaults to `label`). */
194
+ shortLabel?: string;
195
+ /** Opens in a new tab (target="_blank" rel="noopener noreferrer"), bypassing `renderLink`. */
196
+ external?: boolean;
197
+ }
198
+ interface AppNavGroup {
199
+ /** Uppercase section header. Omit for an ungrouped run of items. */
200
+ label?: string;
201
+ items: AppNavItem[];
202
+ /** Sidebar: render the section as a collapsible disclosure. */
203
+ collapsible?: boolean;
204
+ /** Initial open state when `collapsible`. Default true. */
205
+ defaultOpen?: boolean;
206
+ }
207
+ /** Flat items OR grouped sections — flat stays valid (no breaking change). */
208
+ type AppNav = AppNavItem[] | AppNavGroup[];
209
+ type AppLayout = "sidebar" | "top";
210
+ interface AppShellProps {
211
+ /** App name shown by the brand lockup */
212
+ appName: string;
213
+ /** Muted prefix before the name (default "WMM"; "" hides it). */
214
+ brandPrefix?: string;
215
+ /** Logo/mark node (defaults to a mini-logo placeholder chip). */
216
+ logo?: React.ReactNode;
217
+ /** Small line under the app name (e.g. "Internal admin"). */
218
+ brandSubtitle?: string;
219
+ /** Trailing brand badge after a divider (e.g. "OS"). */
220
+ brandBadge?: React.ReactNode;
221
+ nav: AppNav;
222
+ /** Bottom-tab subset for mobile (defaults to the first 5 leaf items). */
223
+ mobileTabs?: AppNavItem[];
224
+ /** Footer user block (avatar + name); rendered at sidebar bottom / brand menu. */
225
+ user?: React.ReactNode;
226
+ /** Header actions (theme toggle, notifications, search, LayoutToggle…). */
227
+ headerActions?: React.ReactNode;
228
+ /** Extra sidebar footer content above the user block. */
229
+ sidebarFooter?: React.ReactNode;
230
+ /** "sidebar" (default) or "top". Uncontrolled unless `onLayoutChange` given. */
231
+ layout?: AppLayout;
232
+ /** Uncontrolled initial layout (persisted to localStorage). Default "sidebar". */
233
+ defaultLayout?: AppLayout;
234
+ /** Controlled layout change handler. */
235
+ onLayoutChange?: (layout: AppLayout) => void;
236
+ /** Current route — auto-derives `active` for items whose `active` is unset. */
237
+ pathname?: string;
238
+ /** Center content in a max-w-7xl container. */
239
+ contained?: boolean;
240
+ defaultCollapsed?: boolean;
241
+ /** Render function for links — pass next/link's Link to get client nav. */
242
+ renderLink?: (props: {
243
+ href: string;
244
+ className?: string;
245
+ children: React.ReactNode;
246
+ }) => React.ReactNode;
247
+ children: React.ReactNode;
248
+ className?: string;
249
+ }
250
+ /** Standalone persisted layout preference — for apps driving AppShell in controlled mode. */
251
+ declare function useLayoutPreference(defaultLayout?: AppLayout): [AppLayout, (l: AppLayout) => void];
252
+ /** Button that flips the enclosing AppShell between sidebar and top layouts. */
253
+ declare function LayoutToggle({ className }: {
254
+ className?: string;
255
+ }): React.JSX.Element | null;
256
+ /**
257
+ * WMM app shell — the internal-app chrome used across the OS. One component, two
258
+ * layouts (`sidebar` default, or `top`) sharing one nav model + brand lockup, so a
259
+ * runtime toggle needs no data changes. Sidebar: collapsible rail + mobile drawer +
260
+ * bottom tabs. Top: slim sticky bar with a11y dropdowns + mobile sheet. Brand-agnostic.
261
+ */
262
+ declare function AppShell({ appName, brandPrefix, logo, brandSubtitle, brandBadge, nav, mobileTabs, user, headerActions, sidebarFooter, layout: layoutProp, defaultLayout, onLayoutChange, pathname, contained, defaultCollapsed, renderLink, children, className, }: AppShellProps): React.JSX.Element;
263
+
264
+ interface AppBrandProps {
265
+ /** App name — e.g. "Tasks". Rendered accented after `prefix` ("WMM Tasks"). */
266
+ appName: string;
267
+ /** Muted text before the name. Default "WMM"; pass "" to show `appName` alone. */
268
+ prefix?: string;
269
+ /** Real logo mark (e.g. <WmmLogo variant="mark" />). Omit → mini-logo placeholder. */
270
+ logo?: React.ReactNode;
271
+ /** Small second line under the title (e.g. "Internal admin"). */
272
+ subtitle?: string;
273
+ /** Trailing badge shown after a divider (e.g. "OS"). */
274
+ badge?: React.ReactNode;
275
+ /** Wrap the whole lockup in a link. */
276
+ href?: string;
277
+ /** Icon-only (sidebar rail / collapsed). Hides text + badge + subtitle. */
278
+ collapsed?: boolean;
279
+ /** Visual scale. Default "md". */
280
+ size?: "sm" | "md";
281
+ /** Pass a framework link (e.g. next/link) for client-side nav. */
282
+ renderLink?: (props: {
283
+ href: string;
284
+ className?: string;
285
+ children: React.ReactNode;
286
+ }) => React.ReactNode;
287
+ className?: string;
288
+ }
289
+ /**
290
+ * Standardized WMM app identity lockup — the top-left brand used by BOTH the
291
+ * sidebar and top-nav shells, on web and mobile, so every app reads as one family.
292
+ *
293
+ * Renders `logo` + a two-tone title (muted `prefix` + accented `appName`), with an
294
+ * optional `subtitle` line and trailing `badge`. When no `logo` is supplied it falls
295
+ * back to a mini-logo placeholder: a primary chip with the app's first letter.
296
+ * Brand-agnostic — colors come from token CSS vars, so any brand reskins it.
297
+ */
298
+ declare function AppBrand({ appName, prefix, logo, subtitle, badge, href, collapsed, size, renderLink, className, }: AppBrandProps): React.JSX.Element;
299
+
300
+ interface SubTabItem<T extends string> {
301
+ id: T;
302
+ label: string;
303
+ icon?: React.ReactNode;
304
+ }
305
+ interface SubTabsProps<T extends string> {
306
+ items: SubTabItem<T>[];
307
+ value: T;
308
+ onChange: (id: T) => void;
309
+ className?: string;
310
+ /** Accessible label for the tablist. */
311
+ "aria-label"?: string;
312
+ }
313
+ /**
314
+ * In-page secondary navigation — a segmented pill switcher for splitting one page
315
+ * into sub-views (e.g. Pay People ⊃ {Pay run, Wise}). Pairs with either app shell.
316
+ * Brand-agnostic (token CSS vars). Lifted from wmm-finance-hr's proven pattern.
317
+ */
318
+ declare function SubTabs<T extends string>({ items, value, onChange, className, "aria-label": ariaLabel, }: SubTabsProps<T>): React.JSX.Element;
319
+
320
+ interface PageHeaderBannerProps {
321
+ title: string;
322
+ subtitle?: string;
323
+ /** right-aligned actions (buttons) */
324
+ actions?: React.ReactNode;
325
+ /** gradient wash behind the banner (defaults to the brand primary tint) */
326
+ gradient?: boolean;
327
+ icon?: React.ReactNode;
328
+ className?: string;
329
+ }
330
+ /** OS-style page header — gradient-tinted banner with title, subtitle, actions. */
331
+ declare function PageHeaderBanner({ title, subtitle, actions, gradient, icon, className, }: PageHeaderBannerProps): React.JSX.Element;
332
+
333
+ interface GlassPanelProps extends React.HTMLAttributes<HTMLDivElement> {
334
+ /** stronger frosted fill */
335
+ strong?: boolean;
336
+ /** add the brand glow shadow (dark themes) */
337
+ glow?: boolean;
338
+ }
339
+ /** Glassmorphism panel — frosted blur + hairline border. Reads token glass vars
340
+ * (falls back gracefully on themes that don't define them). */
341
+ declare function GlassPanel({ strong, glow, className, style, ...props }: GlassPanelProps): React.JSX.Element;
342
+
343
+ interface BrandFrameProps extends React.HTMLAttributes<HTMLDivElement> {
344
+ /** Brand mark rendered as a faint watermark inside the frame (pass <WmmLogo …/>). */
345
+ watermark?: React.ReactNode;
346
+ watermarkPosition?: "top-right" | "bottom-right" | "center";
347
+ /** Watermark opacity 0–1 (default 0.06). */
348
+ watermarkOpacity?: number;
349
+ /** Soft brand glow shadow (reads --shadow-glow / --primary). */
350
+ glow?: boolean;
351
+ /** Frosted glass fill instead of solid card. */
352
+ glass?: boolean;
353
+ /** Animated shine sweep across the top edge (brand gradient). */
354
+ animated?: boolean;
355
+ /** Header row (title / actions) above the content. */
356
+ header?: React.ReactNode;
357
+ /** Slot rendered absolutely behind the content (e.g. an AuroraBackground or 3D render). */
358
+ backdrop?: React.ReactNode;
359
+ }
360
+ /**
361
+ * A branded container — rounded token surface with an optional glow, glass fill, a faint
362
+ * logo watermark, an animated brand shine, and a backdrop slot for effects/renders.
363
+ * Brand-agnostic: the watermark is a passed node and all colour comes from token vars, so
364
+ * WMM (pass <WmmLogo/>) or any client brand reuses it. This is the "nice container that
365
+ * accepts animations" — drop content in as children.
366
+ */
367
+ declare function BrandFrame({ watermark, watermarkPosition, watermarkOpacity, glow, glass, animated, header, backdrop, className, children, style, ...props }: BrandFrameProps): React.JSX.Element;
368
+
369
+ /**
370
+ * The shared shape for a Next.js Server Action's return value — pairs with
371
+ * `useActionRunner`/`useOptimisticAction`. Keep every server action returning
372
+ * this instead of throwing, so the client can branch on `.ok` without a
373
+ * try/catch around every call site.
374
+ *
375
+ * "use server";
376
+ * export async function setStatus(id: string, status: string): Promise<ActionResult> {
377
+ * const { error } = await supabase.from("tasks").update({ status }).eq("id", id);
378
+ * return error ? { ok: false, error: error.message } : { ok: true, data: undefined };
379
+ * }
380
+ */
381
+ type ActionResult<T = void> = {
382
+ ok: true;
383
+ data: T;
384
+ } | {
385
+ ok: false;
386
+ error: string;
387
+ };
388
+
389
+ interface RunOptions<T> {
390
+ /** Toast title on success. Function form receives the action's `data`. */
391
+ successMessage?: string | ((data: T) => string);
392
+ /** Toast title on failure. Defaults to the ActionResult's own `error` string. */
393
+ errorMessage?: string | ((error: string) => string);
394
+ /** Adds an inline "Undo" (or custom label) button to the success toast. */
395
+ undo?: {
396
+ label?: string;
397
+ action: () => Promise<ActionResult<unknown>>;
398
+ };
399
+ onSuccess?: (data: T) => void;
400
+ onError?: (error: string) => void;
401
+ /** Runs after either branch, success or failure — for busy-flag cleanup, refetch, etc. */
402
+ onSettled?: () => void;
403
+ }
404
+ /**
405
+ * The "run a server action from a click handler" wrapper used throughout
406
+ * wmm-tasks' slide-over — generalized: busy flag, toast on success/failure,
407
+ * optional inline Undo action. Requires `<ToastProvider>` mounted once near
408
+ * the app root (see `@web-my-money/primitives/toast`).
409
+ *
410
+ * const { run, pending } = useActionRunner();
411
+ * <Button disabled={pending} onClick={() => run(
412
+ * () => archiveContractor(id),
413
+ * { successMessage: "Archived", undo: { action: () => restoreContractor(id) } },
414
+ * )} />
415
+ */
416
+ declare function useActionRunner(): {
417
+ run: <T>(action: () => Promise<ActionResult<T>>, options?: RunOptions<T>) => Promise<ActionResult<T>>;
418
+ pending: boolean;
419
+ };
420
+
421
+ /**
422
+ * Server Actions + optimistic UI, the React 19 way: wraps `useOptimistic` +
423
+ * `useTransition` so the optimistic value is set correctly *inside* a
424
+ * transition (required — React discards/warns on optimistic updates set
425
+ * outside one) and the real mutation runs alongside it. On success the real
426
+ * data eventually replaces the optimistic value on next render; on failure,
427
+ * `useOptimistic` automatically reverts once the transition settles — pair
428
+ * with `onResult` to also toast the error.
429
+ *
430
+ * const [optimisticStatus, applyStatus, pending] = useOptimisticAction(
431
+ * task.status,
432
+ * (_prev, next: Status) => next,
433
+ * );
434
+ * <StatusSelect
435
+ * value={optimisticStatus}
436
+ * disabled={pending}
437
+ * onChange={(next) => applyStatus(next, () => setStatus(task.id, next))}
438
+ * />
439
+ */
440
+ declare function useOptimisticAction<State, Optimistic>(state: State, reducer: (state: State, optimisticValue: Optimistic) => State): readonly [State, <T>(optimisticValue: Optimistic, action: () => Promise<ActionResult<T>>, onResult?: (result: ActionResult<T>) => void) => void, boolean];
441
+
442
+ interface AppearanceSettingsProps {
443
+ className?: string;
444
+ }
445
+ /**
446
+ * Settings → Appearance section — pairs the DS's `ThemeToggle` (light/dark/wmm)
447
+ * with `FontSizeToggle` (md/lg/xl text scale), both from
448
+ * `@web-my-money/tokens/react`. Meant to drop straight into any app's
449
+ * Settings → Appearance page (wmm-os's `/settings` page is the intended first
450
+ * consumer — not wired in from here). Brand-agnostic (token CSS vars only).
451
+ */
452
+ declare function AppearanceSettings({ className }: AppearanceSettingsProps): React.JSX.Element;
453
+
454
+ export { type ActionResult, ActivityFeed, type ActivityFeedProps, type ActivityItem, type ActivityType, AppBrand, type AppBrandProps, type AppLayout, type AppNav, type AppNavGroup, type AppNavItem, AppShell, type AppShellProps, AppearanceSettings, type AppearanceSettingsProps, type BannerVariant, BrandFrame, type BrandFrameProps, type BreadcrumbItem, DashboardHeader, type DashboardHeaderProps, DataSummaryCards, type DataSummaryCardsProps, DataTable, type DataTableProps, type DataTableRow, EmptyState, type EmptyStateProps, GlassPanel, type GlassPanelProps, type KPIItem, KPIRow, type KPIRowProps, LayoutToggle, type MetricCard, NotificationBanner, type NotificationBannerProps, PageHeader, PageHeaderBanner, type PageHeaderBannerProps, type PageHeaderProps, type RunOptions, type SidebarMenuItem, SidebarNavigation, type SidebarNavigationProps, StatCard, type StatCardProps, type SubTabItem, SubTabs, type SubTabsProps, useActionRunner, useLayoutPreference, useOptimisticAction };