@fayz-ai/ui 0.9.0 → 0.10.1

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 (156) hide show
  1. package/README.md +2 -2
  2. package/dist/analytics/AnalyticsCard.d.ts +10 -0
  3. package/dist/analytics/AnalyticsCard.d.ts.map +1 -0
  4. package/dist/analytics/AnalyticsControls.d.ts +18 -0
  5. package/dist/analytics/AnalyticsControls.d.ts.map +1 -0
  6. package/dist/analytics/AnalyticsGrid.d.ts +16 -0
  7. package/dist/analytics/AnalyticsGrid.d.ts.map +1 -0
  8. package/dist/analytics/context.d.ts +58 -0
  9. package/dist/analytics/context.d.ts.map +1 -0
  10. package/dist/analytics/derive.d.ts +81 -0
  11. package/dist/analytics/derive.d.ts.map +1 -0
  12. package/dist/analytics/index.d.ts +13 -0
  13. package/dist/analytics/index.d.ts.map +1 -0
  14. package/dist/analytics/range.d.ts +22 -0
  15. package/dist/analytics/range.d.ts.map +1 -0
  16. package/dist/{chunk-PVIB724L.js → chunk-22EVFMS3.js} +5 -3
  17. package/dist/chunk-22EVFMS3.js.map +1 -0
  18. package/dist/{chunk-G6OKZ7WL.js → chunk-6V5MGYXH.js} +13 -9
  19. package/dist/chunk-6V5MGYXH.js.map +1 -0
  20. package/dist/{chunk-KV3MHB6N.js → chunk-H63TOSQ7.js} +196 -53
  21. package/dist/chunk-H63TOSQ7.js.map +1 -0
  22. package/dist/{chunk-OUPJDGKE.js → chunk-I6CPKAOD.js} +134 -37
  23. package/dist/chunk-I6CPKAOD.js.map +1 -0
  24. package/dist/{chunk-YRVE4FOD.js → chunk-OKZ6WQB3.js} +3 -3
  25. package/dist/chunk-OKZ6WQB3.js.map +1 -0
  26. package/dist/{chunk-S5KNM4D2.js → chunk-SEIY2F5F.js} +235 -107
  27. package/dist/chunk-SEIY2F5F.js.map +1 -0
  28. package/dist/{chunk-75EFDLST.js → chunk-VAKWUUVC.js} +157 -6
  29. package/dist/chunk-VAKWUUVC.js.map +1 -0
  30. package/dist/dashboard/OnboardingWidget.d.ts +2 -14
  31. package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
  32. package/dist/dashboard/SidebarOnboarding.d.ts +28 -0
  33. package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -0
  34. package/dist/dashboard/index.d.ts +2 -0
  35. package/dist/dashboard/index.d.ts.map +1 -1
  36. package/dist/dashboard/index.js +4 -4
  37. package/dist/dashboard/types.d.ts +18 -0
  38. package/dist/dashboard/types.d.ts.map +1 -1
  39. package/dist/dashboard/useOnboardingProgress.d.ts +28 -0
  40. package/dist/dashboard/useOnboardingProgress.d.ts.map +1 -0
  41. package/dist/icons.js +1 -1
  42. package/dist/index.d.ts +5 -4
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +960 -14
  45. package/dist/index.js.map +1 -1
  46. package/dist/layout/AppShell.d.ts +14 -1
  47. package/dist/layout/AppShell.d.ts.map +1 -1
  48. package/dist/layout/ModulePage.d.ts +11 -2
  49. package/dist/layout/ModulePage.d.ts.map +1 -1
  50. package/dist/layout/Sidebar.d.ts +8 -1
  51. package/dist/layout/Sidebar.d.ts.map +1 -1
  52. package/dist/layout/index.js +4 -4
  53. package/dist/lib/cn.d.ts.map +1 -0
  54. package/dist/preset.d.ts +3 -0
  55. package/dist/preset.d.ts.map +1 -0
  56. package/dist/primitives/data-table.d.ts +19 -4
  57. package/dist/primitives/data-table.d.ts.map +1 -1
  58. package/dist/primitives/date-picker.d.ts +4 -2
  59. package/dist/primitives/date-picker.d.ts.map +1 -1
  60. package/dist/primitives/filter-chip.d.ts +26 -0
  61. package/dist/primitives/filter-chip.d.ts.map +1 -0
  62. package/dist/primitives/header-tabs.d.ts +32 -0
  63. package/dist/primitives/header-tabs.d.ts.map +1 -0
  64. package/dist/primitives/hint.d.ts +25 -0
  65. package/dist/primitives/hint.d.ts.map +1 -0
  66. package/dist/primitives/index.d.ts +7 -0
  67. package/dist/primitives/index.d.ts.map +1 -1
  68. package/dist/primitives/index.js +4 -4
  69. package/dist/primitives/list-view.d.ts +14 -1
  70. package/dist/primitives/list-view.d.ts.map +1 -1
  71. package/dist/primitives/page-header.d.ts +23 -0
  72. package/dist/primitives/page-header.d.ts.map +1 -0
  73. package/dist/primitives/stat-tiles.d.ts +30 -0
  74. package/dist/primitives/stat-tiles.d.ts.map +1 -0
  75. package/dist/primitives/switch.d.ts +11 -0
  76. package/dist/primitives/switch.d.ts.map +1 -0
  77. package/dist/stores/index.d.ts +1 -0
  78. package/dist/stores/index.d.ts.map +1 -1
  79. package/dist/stores/page-header.store.d.ts +69 -0
  80. package/dist/stores/page-header.store.d.ts.map +1 -0
  81. package/package.json +6 -15
  82. package/dist/chunk-75EFDLST.js.map +0 -1
  83. package/dist/chunk-G6OKZ7WL.js.map +0 -1
  84. package/dist/chunk-KV3MHB6N.js.map +0 -1
  85. package/dist/chunk-OUPJDGKE.js.map +0 -1
  86. package/dist/chunk-PVIB724L.js.map +0 -1
  87. package/dist/chunk-S5KNM4D2.js.map +0 -1
  88. package/dist/chunk-YRVE4FOD.js.map +0 -1
  89. package/dist/utils/cn.d.ts.map +0 -1
  90. package/src/dashboard/ChartWidget.tsx +0 -50
  91. package/src/dashboard/ChartWidgetInner.tsx +0 -83
  92. package/src/dashboard/DashboardCanvas.tsx +0 -210
  93. package/src/dashboard/DashboardCustomizeMenu.tsx +0 -53
  94. package/src/dashboard/DashboardGrid.tsx +0 -35
  95. package/src/dashboard/DashboardRange.tsx +0 -62
  96. package/src/dashboard/GoldCard.tsx +0 -38
  97. package/src/dashboard/KpiCard.tsx +0 -238
  98. package/src/dashboard/OnboardingWidget.tsx +0 -140
  99. package/src/dashboard/TableWidget.tsx +0 -51
  100. package/src/dashboard/define.ts +0 -53
  101. package/src/dashboard/icon.ts +0 -13
  102. package/src/dashboard/index.ts +0 -38
  103. package/src/dashboard/layout.ts +0 -50
  104. package/src/dashboard/preferences.ts +0 -71
  105. package/src/dashboard/types.ts +0 -41
  106. package/src/icons.ts +0 -66
  107. package/src/index.ts +0 -238
  108. package/src/layout/AppShell.tsx +0 -987
  109. package/src/layout/ContentSplit.tsx +0 -153
  110. package/src/layout/ModulePage.tsx +0 -466
  111. package/src/layout/PageTransition.tsx +0 -57
  112. package/src/layout/SaveBar.tsx +0 -247
  113. package/src/layout/Sidebar.tsx +0 -535
  114. package/src/layout/Topbar.tsx +0 -462
  115. package/src/layout/index.ts +0 -39
  116. package/src/layout/useCrossModuleBack.ts +0 -30
  117. package/src/primitives/Avatar.tsx +0 -48
  118. package/src/primitives/SearchCombobox.tsx +0 -216
  119. package/src/primitives/badge.tsx +0 -68
  120. package/src/primitives/breadcrumb.tsx +0 -43
  121. package/src/primitives/button.tsx +0 -60
  122. package/src/primitives/card.tsx +0 -79
  123. package/src/primitives/checkbox.tsx +0 -53
  124. package/src/primitives/confirm-dialog.tsx +0 -125
  125. package/src/primitives/currency-input.tsx +0 -121
  126. package/src/primitives/data-table.tsx +0 -160
  127. package/src/primitives/date-picker.tsx +0 -225
  128. package/src/primitives/dropdown.tsx +0 -196
  129. package/src/primitives/index.ts +0 -87
  130. package/src/primitives/input.tsx +0 -50
  131. package/src/primitives/list-view.tsx +0 -252
  132. package/src/primitives/markdown-editor.tsx +0 -75
  133. package/src/primitives/markdown.tsx +0 -169
  134. package/src/primitives/modal.tsx +0 -156
  135. package/src/primitives/phone-link.tsx +0 -138
  136. package/src/primitives/popover.tsx +0 -30
  137. package/src/primitives/search-select.tsx +0 -314
  138. package/src/primitives/segmented-control.tsx +0 -66
  139. package/src/primitives/select.tsx +0 -157
  140. package/src/primitives/separator.tsx +0 -29
  141. package/src/primitives/sheet.tsx +0 -181
  142. package/src/primitives/skeleton.tsx +0 -46
  143. package/src/primitives/tabs.tsx +0 -53
  144. package/src/primitives/time-picker.tsx +0 -148
  145. package/src/primitives/toast.tsx +0 -46
  146. package/src/primitives/tooltip.tsx +0 -28
  147. package/src/stores/index.ts +0 -10
  148. package/src/stores/layout.store.ts +0 -31
  149. package/src/stores/theme.store.ts +0 -457
  150. package/src/tailwind.ts +0 -43
  151. package/src/theme/index.ts +0 -94
  152. package/src/theme/preset.ts +0 -209
  153. package/src/theme/presets.ts +0 -106
  154. package/src/utils/cn.ts +0 -6
  155. /package/dist/{utils → lib}/cn.d.ts +0 -0
  156. /package/{src → dist}/styles.css +0 -0
@@ -1,140 +0,0 @@
1
- import * as React from 'react'
2
- import { Check, Circle } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '../primitives/card'
5
- import { Button } from '../primitives/button'
6
- import { Skeleton } from '../primitives/skeleton'
7
- import { renderIcon } from './icon'
8
- import type { IconRef } from './types'
9
-
10
- export interface OnboardingStepInput {
11
- id: string
12
- title: string
13
- description?: string
14
- icon?: IconRef
15
- /** Async check: resolves true when the step is already complete. */
16
- check?: () => Promise<boolean>
17
- /** Pre-resolved completion (takes precedence over `check`). */
18
- done?: boolean
19
- /** Route string (uses onNavigate) or a callback. */
20
- action?: string | (() => void)
21
- actionLabel?: string
22
- }
23
-
24
- export interface OnboardingWidgetProps {
25
- title?: string
26
- subtitle?: string
27
- steps: OnboardingStepInput[]
28
- onNavigate?: (path: string) => void
29
- /** Hide the whole widget once every step is complete. Default: true. */
30
- hideWhenComplete?: boolean
31
- className?: string
32
- }
33
-
34
- /** Placeholder mirroring the widget's layout while the async checks resolve. */
35
- function OnboardingSkeleton({ rows, className }: { rows: number; className?: string }) {
36
- return (
37
- <Card className={className} aria-busy="true">
38
- <CardHeader>
39
- <Skeleton className="h-5 w-40" />
40
- <Skeleton className="mt-1.5 h-3.5 w-64 max-w-full" />
41
- <div className="mt-2 flex items-center gap-3">
42
- <Skeleton className="h-1.5 flex-1 rounded-full" />
43
- <Skeleton className="h-3 w-8" />
44
- </div>
45
- </CardHeader>
46
- <CardContent className="space-y-1 pt-0">
47
- {Array.from({ length: Math.max(rows, 1) }).map((_, i) => (
48
- <div key={i} className="flex items-center gap-3 px-2 py-2.5">
49
- <Skeleton className="h-7 w-7 shrink-0 rounded-full" />
50
- <div className="min-w-0 flex-1 space-y-1.5">
51
- <Skeleton className="h-3.5 w-1/2" />
52
- <Skeleton className="h-3 w-3/4" />
53
- </div>
54
- </div>
55
- ))}
56
- </CardContent>
57
- </Card>
58
- )
59
- }
60
-
61
- /** Getting-started checklist ("first steps to set up") with progress. */
62
- export function OnboardingWidget({
63
- title = 'Getting started', subtitle, steps, onNavigate, hideWhenComplete = true, className,
64
- }: OnboardingWidgetProps) {
65
- const [completed, setCompleted] = React.useState<Record<string, boolean>>(() =>
66
- Object.fromEntries(steps.map((s) => [s.id, Boolean(s.done)])),
67
- )
68
- // Async checks start unresolved: don't paint until they settle, or an
69
- // already-onboarded tenant flashes the checklist for the query round-trip
70
- // before allDone hides it (mount → visible 0/N → resolve → null).
71
- const [resolved, setResolved] = React.useState(() => steps.every((s) => s.done != null || !s.check))
72
-
73
- React.useEffect(() => {
74
- let cancelled = false
75
- Promise.all(steps.map(async (s) => {
76
- if (s.done != null) return [s.id, s.done] as const
77
- if (!s.check) return [s.id, false] as const
78
- try { return [s.id, await s.check()] as const } catch { return [s.id, false] as const }
79
- })).then((entries) => {
80
- if (cancelled) return
81
- setCompleted(Object.fromEntries(entries))
82
- setResolved(true)
83
- })
84
- return () => { cancelled = true }
85
- }, [steps])
86
-
87
- const doneCount = steps.filter((s) => completed[s.id]).length
88
- const allDone = doneCount === steps.length
89
- // Hold the card's real shape while the checks settle. Painting the resolved
90
- // checklist here would flash 0/N at an already-onboarded tenant, and painting
91
- // nothing collapsed the row and shifted the dashboard on resolve.
92
- if (!resolved) return <OnboardingSkeleton rows={steps.length} className={className} />
93
- if (allDone && hideWhenComplete) return null
94
-
95
- const runAction = (action: OnboardingStepInput['action']) => {
96
- if (!action) return
97
- if (typeof action === 'string') onNavigate?.(action)
98
- else action()
99
- }
100
-
101
- return (
102
- <Card className={className}>
103
- <CardHeader>
104
- <CardTitle>{title}</CardTitle>
105
- {subtitle ? <CardDescription>{subtitle}</CardDescription> : null}
106
- <div className="mt-2 flex items-center gap-3">
107
- <div className="h-1.5 flex-1 overflow-hidden rounded-full bg-muted">
108
- <div className="h-full rounded-full bg-primary transition-all"
109
- style={{ width: `${steps.length ? (doneCount / steps.length) * 100 : 0}%` }} />
110
- </div>
111
- <span className="text-xs font-medium text-muted-foreground">{doneCount}/{steps.length}</span>
112
- </div>
113
- </CardHeader>
114
- <CardContent className="space-y-1 pt-0">
115
- {steps.map((step) => {
116
- const isDone = completed[step.id]
117
- return (
118
- <div key={step.id} className="flex items-center gap-3 rounded-lg px-2 py-2.5 hover:bg-muted/50">
119
- <span className={cn(
120
- 'flex h-7 w-7 shrink-0 items-center justify-center rounded-full',
121
- isDone ? 'bg-emerald-100 text-emerald-600' : 'bg-muted text-muted-foreground',
122
- )}>
123
- {isDone ? <Check className="h-4 w-4" /> : (renderIcon(step.icon, 'h-4 w-4') ?? <Circle className="h-4 w-4" />)}
124
- </span>
125
- <div className="min-w-0 flex-1">
126
- <p className={cn('text-sm font-medium', isDone && 'text-muted-foreground line-through')}>{step.title}</p>
127
- {step.description ? <p className="truncate text-xs text-muted-foreground">{step.description}</p> : null}
128
- </div>
129
- {!isDone && step.action ? (
130
- <Button size="sm" variant="outline" onClick={() => runAction(step.action)}>
131
- {step.actionLabel ?? 'Start'}
132
- </Button>
133
- ) : null}
134
- </div>
135
- )
136
- })}
137
- </CardContent>
138
- </Card>
139
- )
140
- }
@@ -1,51 +0,0 @@
1
- import * as React from 'react'
2
- import type { ColumnDef } from '@tanstack/react-table'
3
- import { Card, CardContent, CardHeader, CardTitle } from '../primitives/card'
4
- import { DataTable } from '../primitives/data-table'
5
- import { renderIcon } from './icon'
6
- import type { IconRef } from './types'
7
-
8
- export interface TableWidgetProps<TData> {
9
- title?: string
10
- icon?: IconRef
11
- columns: ColumnDef<TData, unknown>[]
12
- data: TData[]
13
- loading?: boolean
14
- emptyMessage?: string
15
- onRowClick?: (row: TData) => void
16
- /** Right-aligned header content (e.g. a "view all" link). */
17
- headerAction?: React.ReactNode
18
- className?: string
19
- }
20
-
21
- /** "Recent N" table in a Card — wraps the shared DataTable primitive. */
22
- export function TableWidget<TData>({
23
- title, icon, columns, data, loading, emptyMessage, onRowClick, headerAction, className,
24
- }: TableWidgetProps<TData>) {
25
- return (
26
- <Card className={className}>
27
- {(title || headerAction) && (
28
- <CardHeader className="flex-row items-center justify-between space-y-0">
29
- {title ? (
30
- <CardTitle className="flex items-center gap-2">
31
- {renderIcon(icon)}
32
- {title}
33
- </CardTitle>
34
- ) : <span />}
35
- {headerAction}
36
- </CardHeader>
37
- )}
38
- <CardContent className="p-0">
39
- <DataTable
40
- columns={columns}
41
- data={data}
42
- loading={loading}
43
- emptyMessage={emptyMessage}
44
- onRowClick={onRowClick}
45
- variant="flat"
46
- compact
47
- />
48
- </CardContent>
49
- </Card>
50
- )
51
- }
@@ -1,53 +0,0 @@
1
- import type { DashboardWidgetDef, DashboardWidgetKind, DashboardSurface } from '@fayz-ai/core'
2
-
3
- // ---------------------------------------------------------------------------
4
- // Widget-definition builders. Each sets the right `kind` + default `span` so a
5
- // plugin author writes data, not layout. The widget's component renders the
6
- // presentational primitives (KpiCard, ChartWidget, TableWidget, ...).
7
- // ---------------------------------------------------------------------------
8
-
9
- export interface DefineWidgetInput {
10
- id: string
11
- title: string
12
- component: React.ComponentType<unknown>
13
- description?: string
14
- icon?: string
15
- domain?: string
16
- span?: 1 | 2 | 3 | 4
17
- defaultVisible?: boolean
18
- defaultOrder?: number
19
- surfaces?: DashboardSurface[]
20
- verticalId?: DashboardWidgetDef['verticalId']
21
- permission?: DashboardWidgetDef['permission']
22
- props?: Record<string, unknown>
23
- }
24
-
25
- function build(kind: DashboardWidgetKind, defaultSpan: 1 | 2 | 3 | 4, input: DefineWidgetInput): DashboardWidgetDef {
26
- return {
27
- kind,
28
- span: input.span ?? defaultSpan,
29
- defaultVisible: input.defaultVisible ?? true,
30
- id: input.id,
31
- title: input.title,
32
- description: input.description,
33
- icon: input.icon,
34
- domain: input.domain,
35
- defaultOrder: input.defaultOrder,
36
- surfaces: input.surfaces,
37
- verticalId: input.verticalId,
38
- permission: input.permission,
39
- component: input.component,
40
- props: input.props,
41
- }
42
- }
43
-
44
- /** KPI card widget — spans 1 column (forms the 4-up top row). */
45
- export const defineKpiWidget = (input: DefineWidgetInput): DashboardWidgetDef => build('kpi', 1, input)
46
- /** Chart widget — spans 2 columns by default. */
47
- export const defineChartWidget = (input: DefineWidgetInput): DashboardWidgetDef => build('chart', 2, input)
48
- /** Table widget — spans the full row by default. */
49
- export const defineTableWidget = (input: DefineWidgetInput): DashboardWidgetDef => build('table', 4, input)
50
- /** Onboarding checklist widget — spans half the row (2 cols) by default. */
51
- export const defineOnboardingWidget = (input: DefineWidgetInput): DashboardWidgetDef => build('onboarding', 2, input)
52
- /** Custom client-provided widget — spans 2 columns by default. */
53
- export const defineCustomWidget = (input: DefineWidgetInput): DashboardWidgetDef => build('custom', 2, input)
@@ -1,13 +0,0 @@
1
- import * as React from 'react'
2
- import { getLucideIcon } from '../icons'
3
- import type { IconRef } from './types'
4
-
5
- /** Resolve an IconRef (lucide name or component) to a renderable element. */
6
- export function renderIcon(icon: IconRef | undefined, className = 'h-4 w-4'): React.ReactNode {
7
- if (!icon) return null
8
- if (typeof icon === 'string') {
9
- const Comp = getLucideIcon(icon)
10
- return Comp ? React.createElement(Comp, { className }) : null
11
- }
12
- return React.createElement(icon, { className })
13
- }
@@ -1,38 +0,0 @@
1
- // Dashboard widget kit — rendering engine + presentational primitives + builders.
2
- export {
3
- DashboardCanvas,
4
- WidgetGrid,
5
- DashboardNavigateProvider,
6
- useDashboardNavigate,
7
- type DashboardCanvasProps,
8
- } from './DashboardCanvas'
9
- export { resolveDashboardLayout, type LaidOutWidget } from './layout'
10
- export { useDashboardPreferences, type DashboardPreferencesState } from './preferences'
11
- export { DashboardCustomizeMenu, type DashboardCustomizeMenuProps } from './DashboardCustomizeMenu'
12
- export { DashboardGrid, type DashboardGridItem, type DashboardGridProps } from './DashboardGrid'
13
- export { GoldCard, type GoldCardProps } from './GoldCard'
14
- export {
15
- DashboardRangeProvider,
16
- DashboardRangeControl,
17
- useDashboardRange,
18
- DEFAULT_RANGE_OPTIONS,
19
- type DashboardRange,
20
- type DashboardRangeProviderProps,
21
- } from './DashboardRange'
22
- export type { DashboardRangeOptions } from './DashboardCanvas'
23
- export { KpiCard, formatKpiValue, type KpiCardProps } from './KpiCard'
24
- export { ChartWidget, type ChartWidgetProps } from './ChartWidget'
25
- export { TableWidget, type TableWidgetProps } from './TableWidget'
26
- export { OnboardingWidget, type OnboardingStepInput, type OnboardingWidgetProps } from './OnboardingWidget'
27
- export { renderIcon } from './icon'
28
- export {
29
- defineKpiWidget,
30
- defineChartWidget,
31
- defineTableWidget,
32
- defineOnboardingWidget,
33
- defineCustomWidget,
34
- type DefineWidgetInput,
35
- } from './define'
36
- export type {
37
- KpiFormat, KpiTrend, KpiValue, KpiCurrency, IconRef, ChartType, ChartSeries,
38
- } from './types'
@@ -1,50 +0,0 @@
1
- import type { DashboardLayoutConfig, DashboardWidgetDef } from '@fayz-ai/core'
2
-
3
- export interface LaidOutWidget {
4
- def: DashboardWidgetDef
5
- /** Effective span after applying overrides (1–4). */
6
- span: number
7
- order: number
8
- }
9
-
10
- /**
11
- * Resolve the widgets to render on a surface, in order, applying three layers:
12
- * 1. registration defaults (defaultVisible / defaultOrder / span)
13
- * 2. app config (the app curates the home surface)
14
- * 3. user preferences (show/hide/reorder — read but currently empty)
15
- *
16
- * Later layers win. Returns only visible widgets, sorted by effective order.
17
- * Accepts any DashboardWidgetDef (registry-resolved or shim-built).
18
- */
19
- export function resolveDashboardLayout(
20
- registered: DashboardWidgetDef[],
21
- appConfig?: DashboardLayoutConfig,
22
- userPrefs?: DashboardLayoutConfig,
23
- /** When true, widgets are visible by default regardless of their
24
- * `defaultVisible` (used on a plugin-home to show everything; the global
25
- * home leaves this false so `defaultVisible:false` curates the start set). */
26
- forceVisibleByDefault = false,
27
- ): LaidOutWidget[] {
28
- type Override = { visible?: boolean; order?: number; span?: number }
29
- const overrides = new Map<string, Override>()
30
- const merge = (cfg?: DashboardLayoutConfig) => {
31
- for (const w of cfg?.widgets ?? []) {
32
- overrides.set(w.id, { ...overrides.get(w.id), ...w })
33
- }
34
- }
35
- merge(appConfig)
36
- merge(userPrefs)
37
-
38
- return registered
39
- .map((def, index) => {
40
- const o = overrides.get(def.id)
41
- const baseVisible = forceVisibleByDefault ? true : (def.defaultVisible ?? true)
42
- const visible = o?.visible ?? baseVisible
43
- const order = o?.order ?? def.defaultOrder ?? index
44
- const span = Math.min(Math.max(o?.span ?? def.span ?? 1, 1), 4)
45
- return { def, visible, order, span }
46
- })
47
- .filter((x) => x.visible)
48
- .sort((a, b) => a.order - b.order)
49
- .map(({ def, span, order }) => ({ def, span, order }))
50
- }
@@ -1,71 +0,0 @@
1
- import * as React from 'react'
2
- import type { DashboardLayoutConfig, DashboardSurface } from '@fayz-ai/core'
3
-
4
- export interface DashboardPreferencesState {
5
- /** User-level layout overrides for this surface (null when none saved). */
6
- prefs: DashboardLayoutConfig | null
7
- /** Persist updated overrides. */
8
- save: (next: DashboardLayoutConfig) => void
9
- /** Toggle a single widget's visibility and persist. */
10
- setVisible: (widgetId: string, visible: boolean) => void
11
- /** Clear all overrides (reset to registration + app defaults). */
12
- reset: () => void
13
- }
14
-
15
- const KEY = (surface: DashboardSurface, scope: string) => `fayz.dashboard.prefs.${scope}.${surface}`
16
-
17
- function read(key: string): DashboardLayoutConfig | null {
18
- if (typeof window === 'undefined') return null
19
- try {
20
- const raw = window.localStorage.getItem(key)
21
- return raw ? (JSON.parse(raw) as DashboardLayoutConfig) : null
22
- } catch {
23
- return null
24
- }
25
- }
26
-
27
- /**
28
- * Per-user dashboard preferences, persisted to localStorage.
29
- *
30
- * `scope` lets a plugin-home keep its own prefs separate from the global home
31
- * (pass the domain). A future pass can swap the storage for the tenant/plugin
32
- * binding store without touching callers — `resolveDashboardLayout` already
33
- * consumes whatever this returns as the `userPrefs` layer.
34
- */
35
- export function useDashboardPreferences(surface: DashboardSurface, scope = 'home'): DashboardPreferencesState {
36
- const key = KEY(surface, scope)
37
- const [prefs, setPrefs] = React.useState<DashboardLayoutConfig | null>(() => read(key))
38
-
39
- // Re-read when the target surface/scope changes.
40
- React.useEffect(() => { setPrefs(read(key)) }, [key])
41
-
42
- const save = React.useCallback((next: DashboardLayoutConfig) => {
43
- setPrefs(next)
44
- if (typeof window !== 'undefined') {
45
- try { window.localStorage.setItem(key, JSON.stringify(next)) } catch { /* ignore quota/availability */ }
46
- }
47
- }, [key])
48
-
49
- const setVisible = React.useCallback((widgetId: string, visible: boolean) => {
50
- setPrefs((cur) => {
51
- const widgets = [...(cur?.widgets ?? [])]
52
- const i = widgets.findIndex((w) => w.id === widgetId)
53
- if (i >= 0) widgets[i] = { ...widgets[i]!, visible }
54
- else widgets.push({ id: widgetId, visible })
55
- const next = { ...cur, widgets }
56
- if (typeof window !== 'undefined') {
57
- try { window.localStorage.setItem(key, JSON.stringify(next)) } catch { /* ignore */ }
58
- }
59
- return next
60
- })
61
- }, [key])
62
-
63
- const reset = React.useCallback(() => {
64
- setPrefs(null)
65
- if (typeof window !== 'undefined') {
66
- try { window.localStorage.removeItem(key) } catch { /* ignore */ }
67
- }
68
- }, [key])
69
-
70
- return { prefs, save, setVisible, reset }
71
- }
@@ -1,41 +0,0 @@
1
- import type React from 'react'
2
-
3
- // ---------------------------------------------------------------------------
4
- // Shared, dependency-free types for the dashboard widget kit. These mirror the
5
- // shapes in plugin-dashboard but live here so plugins can render widgets
6
- // without depending on plugin-dashboard.
7
- // ---------------------------------------------------------------------------
8
-
9
- export type KpiFormat = 'number' | 'currency' | 'percent' | 'duration'
10
- export type KpiTrend = 'up' | 'down' | 'neutral'
11
-
12
- export interface KpiValue {
13
- value: number
14
- /** Comparison value used to derive the trend chip. */
15
- previousValue?: number
16
- /** Unit suffix (e.g. 'min'). */
17
- unit?: string
18
- trend?: KpiTrend
19
- /** Optional series (oldest → newest) rendered as an inline sparkline. */
20
- spark?: number[]
21
- }
22
-
23
- export interface KpiCurrency {
24
- code?: string
25
- locale?: string
26
- symbol?: string
27
- }
28
-
29
- /** A lucide icon name (resolved at render) or a React component. */
30
- export type IconRef = string | React.ComponentType<{ className?: string }>
31
-
32
- export type ChartType = 'line' | 'bar' | 'area' | 'pie'
33
-
34
- export interface ChartSeries {
35
- /** Key into each data row. */
36
- dataKey: string
37
- /** Display label (legend/tooltip). */
38
- label?: string
39
- /** Explicit color; falls back to the theme palette. */
40
- color?: string
41
- }
package/src/icons.ts DELETED
@@ -1,66 +0,0 @@
1
- import type { LucideIcon } from 'lucide-react'
2
- import {
3
- Activity, AlertTriangle, Apple, ArrowDownCircle, ArrowDownRight, ArrowLeftRight, ArrowUpCircle, ArrowUpRight,
4
- Award, BadgeDollarSign, Ban, Banknote, BarChart3, Bell, Bike, BookOpen,
5
- BookOpenCheck, Box, Boxes, Briefcase, Building2, Calendar, CalendarCheck, CalendarCheck2,
6
- CalendarClock, CalendarDays, CalendarPlus, CalendarX, Camera, Cat, Check, CheckCircle,
7
- CheckSquare, ChefHat, ChevronsUpDown, Circle, CircleCheck, CircleDollarSign, Clapperboard, ClipboardList,
8
- Clock, Clock3, Command, Compass, Contact, CreditCard, Disc3, Dog,
9
- DollarSign, DoorOpen, Egg, ExternalLink, Eye, FileCheck2, FileDown,
10
- FileText, Filter, Flame, FolderOpen, Globe, GraduationCap, Handshake, Heart,
11
- Home, Image, Inbox, Instagram, Landmark, Layers, LayoutDashboard, LayoutTemplate,
12
- Leaf, LeafyGreen, Link, List, ListChecks, ListMusic, ListPlus, Lock,
13
- Mail, Map, MapPin, Megaphone, MessageCircle, MessageSquare, Mic, MoreHorizontal,
14
- MousePointerClick, Music, Newspaper, Package, PackageCheck, Palette, PartyPopper, PawPrint,
15
- Pencil, Percent, Phone, PieChart, Plug, Plus, PlusCircle, Puzzle, Radio,
16
- Receipt, Repeat, RotateCcw, Ruler, Search, Send, Settings, Shield,
17
- ShieldCheck, ShoppingBag, ShoppingCart, Sigma, SlidersHorizontal, Sparkles, Star, Tag,
18
- Tags, Target, ToggleLeft, TreePalm, TrendingDown, TrendingUp, Trophy, Truck,
19
- User, UserCheck, UserCog, UserPlus, UserX, Users, UsersRound, Utensils,
20
- UtensilsCrossed, Wallet, Warehouse, Wheat, Workflow, Wrench, X, XCircle,
21
- Zap,
22
- } from 'lucide-react'
23
-
24
- // ---------------------------------------------------------------------------
25
- // Central lucide icon registry. The SDK's manifest-driven surfaces resolve
26
- // icons by string name; a namespace import (`import * as LucideIcons`) defeats
27
- // tree-shaking and drags all ~1,500 icons (~500 KB min) into every bundle, so
28
- // the SDK ships this curated set instead — the union of every icon name the
29
- // SDK, plugins, and app templates reference. Apps using names outside the set
30
- // call registerIcons({ Name: Component }) with their own named imports.
31
- // ---------------------------------------------------------------------------
32
-
33
- const registry: Record<string, LucideIcon> = {
34
- Activity, AlertTriangle, Apple, ArrowDownCircle, ArrowDownRight, ArrowLeftRight, ArrowUpCircle, ArrowUpRight,
35
- Award, BadgeDollarSign, Ban, Banknote, BarChart3, Bell, Bike, BookOpen,
36
- BookOpenCheck, Box, Boxes, Briefcase, Building2, Calendar, CalendarCheck, CalendarCheck2,
37
- CalendarClock, CalendarDays, CalendarPlus, CalendarX, Camera, Cat, Check, CheckCircle,
38
- CheckSquare, ChefHat, ChevronsUpDown, Circle, CircleCheck, CircleDollarSign, Clapperboard, ClipboardList,
39
- Clock, Clock3, Command, Compass, Contact, CreditCard, Disc3, Dog,
40
- DollarSign, DoorOpen, Egg, ExternalLink, Eye, FileCheck2, FileDown,
41
- FileText, Filter, Flame, FolderOpen, Globe, GraduationCap, Handshake, Heart,
42
- Home, Image, Inbox, Instagram, Landmark, Layers, LayoutDashboard, LayoutTemplate,
43
- Leaf, LeafyGreen, Link, List, ListChecks, ListMusic, ListPlus, Lock,
44
- Mail, Map, MapPin, Megaphone, MessageCircle, MessageSquare, Mic, MoreHorizontal,
45
- MousePointerClick, Music, Newspaper, Package, PackageCheck, Palette, PartyPopper, PawPrint,
46
- Pencil, Percent, Phone, PieChart, Plug, Plus, PlusCircle, Puzzle, Radio,
47
- Receipt, Repeat, RotateCcw, Ruler, Search, Send, Settings, Shield,
48
- ShieldCheck, ShoppingBag, ShoppingCart, Sigma, SlidersHorizontal, Sparkles, Star, Tag,
49
- Tags, Target, ToggleLeft, TreePalm, TrendingDown, TrendingUp, Trophy, Truck,
50
- User, UserCheck, UserCog, UserPlus, UserX, Users, UsersRound, Utensils,
51
- UtensilsCrossed, Wallet, Warehouse, Wheat, Workflow, Wrench, X, XCircle,
52
- Zap,
53
- }
54
-
55
- /** Add or override icons resolvable by string name (e.g. from app manifests). */
56
- export function registerIcons(icons: Record<string, LucideIcon>): void {
57
- Object.assign(registry, icons)
58
- }
59
-
60
- /** Resolve a lucide icon by name; undefined when not registered. */
61
- export function getLucideIcon(name: string): LucideIcon | undefined {
62
- return registry[name]
63
- }
64
-
65
- /** The registered icon map (live reference — do not mutate directly). */
66
- export const ICON_MAP = registry