@schandlergarcia/sf-web-components 1.9.41 → 1.9.43

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/INSTALL.md ADDED
@@ -0,0 +1,200 @@
1
+ # Installation Guide
2
+
3
+ Quick start guide for installing `@schandlergarcia/sf-web-components` in your Salesforce web application.
4
+
5
+ ## Prerequisites
6
+
7
+ - Salesforce web application created with `sf webapp generate --template react-ts`
8
+ - Node.js 18+ and npm installed
9
+ - Tailwind CSS v4 configured in your project
10
+
11
+ ## Installation Steps
12
+
13
+ ### 1. Navigate to Your Web App
14
+
15
+ ```bash
16
+ cd force-app/main/default/webapplications/YOUR_APP_NAME
17
+ ```
18
+
19
+ ### 2. Install the Package
20
+
21
+ ```bash
22
+ npm install @schandlergarcia/sf-web-components@latest
23
+ ```
24
+
25
+ The postinstall script runs automatically and:
26
+ - ✅ Copies 102+ component files to `src/components/library/`
27
+ - ✅ Installs page templates to `src/pages/`
28
+ - ✅ Installs workspace files to `src/components/workspace/`
29
+ - ✅ Copies AI assistant rules to project root `.a4drules/`
30
+ - ✅ Adds `reset:command-center` and `validate:dashboard` scripts
31
+ - ✅ Updates imports in existing files
32
+
33
+ ### 3. Install Type Definitions
34
+
35
+ ```bash
36
+ npm install --save-dev @types/d3 @types/topojson-client
37
+ ```
38
+
39
+ ### 4. Verify Installation
40
+
41
+ ```bash
42
+ npm run build
43
+ npm run dev
44
+ ```
45
+
46
+ Visit `http://localhost:5173` - you should see the CommandCenter with BlankDashboard.
47
+
48
+ ## What You Get
49
+
50
+ After installation:
51
+
52
+ ```
53
+ src/
54
+ ├── components/
55
+ │ ├── library/ # 102+ UI components
56
+ │ │ ├── ui/ # Buttons, inputs, cards, alerts
57
+ │ │ ├── cards/ # MetricCard, ChartCard, TableCard, etc.
58
+ │ │ ├── charts/ # D3Chart, GeoMap
59
+ │ │ ├── forms/ # FormRenderer, FormField
60
+ │ │ ├── filters/ # SearchFilter, SelectFilter
61
+ │ │ └── ...
62
+ │ └── workspace/
63
+ │ └── CommandCenter.tsx # Dashboard wrapper
64
+ ├── pages/
65
+ │ ├── Home.tsx # Renders CommandCenter
66
+ │ ├── BlankDashboard.tsx # Empty template
67
+ │ ├── Search.tsx # Search interface
68
+ │ └── NotFound.tsx # 404 page
69
+ ├── lib/
70
+ │ └── utils.ts # Utility functions
71
+ └── types/
72
+ └── conversation.ts # AgentforceConversationClient types
73
+
74
+ package.json # Added scripts:
75
+ # - reset:command-center
76
+ # - validate:dashboard
77
+
78
+ .a4drules/ # AI assistant rules (at project root)
79
+ ├── skills/
80
+ │ └── command-center-builder/
81
+ │ └── SKILL.md
82
+ └── features/
83
+ └── command-center-dashboard-rule.md
84
+ ```
85
+
86
+ ## Next Steps
87
+
88
+ ### Option 1: Build a Dashboard with AI
89
+
90
+ Have an AI assistant (Agentforce, Claude, etc.) build your dashboard:
91
+
92
+ ```
93
+ Build me a Sales Dashboard with KPI metrics, revenue chart, and top accounts table
94
+ ```
95
+
96
+ The AI will:
97
+ 1. Load the command-center-builder skill
98
+ 2. Create your dashboard file in `src/pages/`
99
+ 3. Wire it to CommandCenter
100
+ 4. Update Home.tsx
101
+ 5. Validate with `npm run validate:dashboard`
102
+
103
+ ### Option 2: Build Manually
104
+
105
+ ```bash
106
+ # 1. Create dashboard file
107
+ cat > src/pages/MyDashboard.tsx << 'EOF'
108
+ import { MetricCard, ChartCard } from '@/components/library';
109
+
110
+ export default function MyDashboard() {
111
+ return (
112
+ <div className="space-y-6 p-6">
113
+ <div className="grid grid-cols-3 gap-6">
114
+ <MetricCard title="Revenue" value="$1.2M" change="+12%" changeType="positive" />
115
+ <MetricCard title="Users" value={1284} change="+8%" changeType="positive" />
116
+ <MetricCard title="Conversion" value="3.2%" change="-0.5%" changeType="negative" />
117
+ </div>
118
+ </div>
119
+ );
120
+ }
121
+ EOF
122
+
123
+ # 2. Wire to CommandCenter
124
+ # Edit src/components/workspace/CommandCenter.tsx
125
+ # Change: import BlankDashboard from "../../pages/BlankDashboard";
126
+ # To: import MyDashboard from "../../pages/MyDashboard";
127
+ # Change: <BlankDashboard />
128
+ # To: <MyDashboard />
129
+
130
+ # 3. Update Home
131
+ # Home.tsx should already render CommandCenter
132
+
133
+ # 4. Validate
134
+ npm run validate:dashboard
135
+ ```
136
+
137
+ ## Useful Commands
138
+
139
+ ```bash
140
+ # Development
141
+ npm run dev # Start dev server
142
+ npm run build # Build for production
143
+
144
+ # Dashboard Management
145
+ npm run reset:command-center # Reset to blank state
146
+ npm run validate:dashboard # Check dashboard rules
147
+
148
+ # GraphQL (if using Salesforce data)
149
+ npm run graphql:schema # Fetch schema
150
+ npm run graphql:codegen # Generate types
151
+ ```
152
+
153
+ ## Troubleshooting
154
+
155
+ ### Postinstall didn't run
156
+
157
+ ```bash
158
+ node node_modules/@schandlergarcia/sf-web-components/scripts/postinstall.mjs
159
+ ```
160
+
161
+ ### Build errors about missing D3 types
162
+
163
+ ```bash
164
+ npm install --save-dev @types/d3 @types/topojson-client
165
+ ```
166
+
167
+ ### Home page shows blank/wrong content
168
+
169
+ ```bash
170
+ # Re-run postinstall to restore templates
171
+ node node_modules/@schandlergarcia/sf-web-components/scripts/postinstall.mjs
172
+ ```
173
+
174
+ ### AI assistant not following rules
175
+
176
+ Check that `.a4drules/` exists at your **project root** (not in the webapp directory):
177
+
178
+ ```bash
179
+ # From webapp directory
180
+ ls ../../../../../.a4drules/skills/command-center-builder/SKILL.md
181
+ ```
182
+
183
+ If missing, re-run postinstall:
184
+
185
+ ```bash
186
+ node node_modules/@schandlergarcia/sf-web-components/scripts/postinstall.mjs
187
+ ```
188
+
189
+ ## Support
190
+
191
+ - **Documentation:** [README.md](./README.md)
192
+ - **Issues:** [GitHub Issues](https://github.com/schandlergarcia/sf-web-components/issues)
193
+ - **Package:** [npm](https://www.npmjs.com/package/@schandlergarcia/sf-web-components)
194
+
195
+ ## Next Steps
196
+
197
+ - Read the [Component Documentation](./README.md#using-the-dashboard-framework)
198
+ - Check [AI Assistant Rules](./.a4drules/skills/command-center-builder/SKILL.md) (after install)
199
+ - Browse example pages in `src/pages/`
200
+ - Explore component library in `src/components/library/`
@@ -1,6 +1,6 @@
1
1
  import { jsxs as i, jsx as r } from "react/jsx-runtime";
2
2
  import "react";
3
- import m from "../ui/Button.js";
3
+ import m from "../ui/UIButton.js";
4
4
  function x({
5
5
  actions: s = [],
6
6
  title: t,
@@ -1 +1 @@
1
- {"version":3,"file":"ActionList.js","sources":["../../../../src/components/library/cards/ActionList.jsx"],"sourcesContent":["import React from \"react\";\nimport UIButton from \"../ui/Button\";\n\n/**\n * Row of action buttons — typically used at the bottom of a dashboard section.\n *\n * @param {{ label: string, [key]: any }[] | string[]} actions\n * @param {string} title\n * @param {Function} onAction Called with the action object/string when clicked\n */\nexport default function ActionList({\n actions = [],\n title,\n onAction,\n className = \"\",\n}) {\n return (\n <div className={`rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-900 ${className}`}>\n {title && (\n <div className=\"mb-3 text-sm font-medium text-slate-900 dark:text-slate-50\">\n {title}\n </div>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {actions.map((action, i) => (\n <UIButton\n key={i}\n size=\"sm\"\n variant={i === 0 ? \"primary\" : \"outline\"}\n onClick={() => onAction?.(action)}\n >\n {typeof action === \"string\" ? action : action.label}\n </UIButton>\n ))}\n </div>\n </div>\n );\n}\n"],"names":["ActionList","actions","title","onAction","className","jsxs","jsx","action","i","UIButton"],"mappings":";;;AAUA,SAAwBA,EAAW;AAAA,EACjC,SAAAC,IAAU,CAAA;AAAA,EACV,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC,IAAY;AACd,GAAG;AACD,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAW,4FAA4FD,CAAS,IAClH,UAAA;AAAA,IAAAF,KACC,gBAAAI,EAAC,OAAA,EAAI,WAAU,8DACZ,UAAAJ,GACH;AAAA,IAEF,gBAAAI,EAAC,SAAI,WAAU,wBACZ,YAAQ,IAAI,CAACC,GAAQC,MACpB,gBAAAF;AAAA,MAACG;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAASD,MAAM,IAAI,YAAY;AAAA,QAC/B,SAAS,MAAML,IAAWI,CAAM;AAAA,QAE/B,UAAA,OAAOA,KAAW,WAAWA,IAASA,EAAO;AAAA,MAAA;AAAA,MALzCC;AAAA,IAAA,CAOR,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"ActionList.js","sources":["../../../../src/components/library/cards/ActionList.jsx"],"sourcesContent":["import React from \"react\";\nimport UIButton from \"../ui/UIButton\";\n\n/**\n * Row of action buttons — typically used at the bottom of a dashboard section.\n *\n * @param {{ label: string, [key]: any }[] | string[]} actions\n * @param {string} title\n * @param {Function} onAction Called with the action object/string when clicked\n */\nexport default function ActionList({\n actions = [],\n title,\n onAction,\n className = \"\",\n}) {\n return (\n <div className={`rounded-2xl border border-slate-200 bg-white p-4 dark:border-slate-800 dark:bg-slate-900 ${className}`}>\n {title && (\n <div className=\"mb-3 text-sm font-medium text-slate-900 dark:text-slate-50\">\n {title}\n </div>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {actions.map((action, i) => (\n <UIButton\n key={i}\n size=\"sm\"\n variant={i === 0 ? \"primary\" : \"outline\"}\n onClick={() => onAction?.(action)}\n >\n {typeof action === \"string\" ? action : action.label}\n </UIButton>\n ))}\n </div>\n </div>\n );\n}\n"],"names":["ActionList","actions","title","onAction","className","jsxs","jsx","action","i","UIButton"],"mappings":";;;AAUA,SAAwBA,EAAW;AAAA,EACjC,SAAAC,IAAU,CAAA;AAAA,EACV,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,WAAAC,IAAY;AACd,GAAG;AACD,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAW,4FAA4FD,CAAS,IAClH,UAAA;AAAA,IAAAF,KACC,gBAAAI,EAAC,OAAA,EAAI,WAAU,8DACZ,UAAAJ,GACH;AAAA,IAEF,gBAAAI,EAAC,SAAI,WAAU,wBACZ,YAAQ,IAAI,CAACC,GAAQC,MACpB,gBAAAF;AAAA,MAACG;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAASD,MAAM,IAAI,YAAY;AAAA,QAC/B,SAAS,MAAML,IAAWI,CAAM;AAAA,QAE/B,UAAA,OAAOA,KAAW,WAAWA,IAASA,EAAO;AAAA,MAAA;AAAA,MALzCC;AAAA,IAAA,CAOR,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as t, jsxs as d } from "react/jsx-runtime";
2
2
  import i from "react";
3
3
  import I from "./BaseCard.js";
4
- import te from "../ui/Input.js";
5
- import K from "../ui/Button.js";
4
+ import te from "../ui/UIInput.js";
5
+ import K from "../ui/UIButton.js";
6
6
  import Q from "../ui/Text.js";
7
7
  function re(o, s) {
8
8
  if (s == null) return "";
@@ -1 +1 @@
1
- {"version":3,"file":"TableCard.js","sources":["../../../../src/components/library/cards/TableCard.jsx"],"sourcesContent":["import React from \"react\";\nimport BaseCard from \"./BaseCard\";\nimport UIInput from \"../ui/Input\";\nimport UIButton from \"../ui/Button\";\nimport UIText from \"../ui/Text\";\n\nfunction defaultTypeFormat(type, value) {\n if (value == null) return \"\";\n if (!type) return String(value);\n\n if (type === \"currency\") {\n const n = Number(value);\n if (Number.isFinite(n)) return n.toLocaleString(undefined, { style: \"currency\", currency: \"USD\" });\n }\n if (type === \"percentage\") {\n const n = Number(value);\n if (Number.isFinite(n)) return `${n}%`;\n }\n if (type === \"number\") {\n const n = Number(value);\n if (Number.isFinite(n)) return n.toLocaleString();\n }\n return String(value);\n}\n\nfunction stableSort(data, compare) {\n return data\n .map((item, idx) => ({ item, idx }))\n .sort((a, b) => {\n const c = compare(a.item, b.item);\n return c !== 0 ? c : a.idx - b.idx;\n })\n .map((x) => x.item);\n}\n\nexport default function TableCard({\n data = [],\n columns = [],\n title,\n subtitle,\n searchable = false,\n sortable = false,\n paginated = false,\n selectable = false,\n pageSize = 10,\n actions,\n rowActions,\n onRowSelect,\n onSort,\n onSearch,\n loading = false,\n error,\n emptyMessage = \"No results.\",\n simulateInitialLoad = false,\n minInitialDelayMs = 350,\n maxInitialDelayMs = 900,\n ...cardProps\n}) {\n const [query, setQuery] = React.useState(\"\");\n const [sortKey, setSortKey] = React.useState(null);\n const [sortDir, setSortDir] = React.useState(\"asc\");\n const [page, setPage] = React.useState(1);\n const [selectedId, setSelectedId] = React.useState(null);\n const [simLoading, setSimLoading] = React.useState(simulateInitialLoad);\n\n React.useEffect(() => {\n if (!simulateInitialLoad) return;\n const delay =\n Math.floor(Math.random() * (maxInitialDelayMs - minInitialDelayMs + 1)) + minInitialDelayMs;\n const t = setTimeout(() => setSimLoading(false), delay);\n return () => clearTimeout(t);\n }, [simulateInitialLoad, minInitialDelayMs, maxInitialDelayMs]);\n\n const effectiveLoading = loading || simLoading;\n\n const filtered = React.useMemo(() => {\n if (!searchable || !query.trim()) return data;\n const q = query.trim().toLowerCase();\n return data.filter((row) =>\n columns.some((col) => {\n const raw = row?.[col.key];\n if (raw == null) return false;\n return String(raw).toLowerCase().includes(q);\n })\n );\n }, [data, columns, query, searchable]);\n\n const sorted = React.useMemo(() => {\n if (!sortable || !sortKey) return filtered;\n const col = columns.find((c) => c.key === sortKey);\n if (!col) return filtered;\n const dir = sortDir === \"desc\" ? -1 : 1;\n return stableSort(filtered, (a, b) => {\n const av = a?.[sortKey];\n const bv = b?.[sortKey];\n if (av == null && bv == null) return 0;\n if (av == null) return -1 * dir;\n if (bv == null) return 1 * dir;\n if (typeof av === \"number\" && typeof bv === \"number\") return (av - bv) * dir;\n return String(av).localeCompare(String(bv)) * dir;\n });\n }, [filtered, sortable, sortKey, sortDir, columns]);\n\n const total = sorted.length;\n const totalPages = paginated ? Math.max(1, Math.ceil(total / pageSize)) : 1;\n const clampedPage = Math.min(page, totalPages);\n\n const pageData = React.useMemo(() => {\n if (!paginated) return sorted;\n const start = (clampedPage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, paginated, clampedPage, pageSize]);\n\n React.useEffect(() => {\n if (page !== clampedPage) setPage(clampedPage);\n }, [page, clampedPage]);\n\n const header = (\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n <div className=\"min-w-0\">\n {title ? (\n <UIText as=\"div\" size=\"sm\" weight=\"medium\">\n {title}\n </UIText>\n ) : null}\n {subtitle ? (\n <UIText as=\"div\" size=\"xs\" muted className=\"mt-1\">\n {subtitle}\n </UIText>\n ) : null}\n </div>\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-end\">\n {searchable ? (\n <div className=\"w-full sm:w-64\">\n <UIInput\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setPage(1);\n onSearch?.(e.target.value);\n }}\n placeholder=\"Search…\"\n aria-label=\"Search table\"\n />\n </div>\n ) : null}\n {actions ? <div className=\"flex items-center gap-2\">{actions}</div> : null}\n </div>\n </div>\n );\n\n if (error) {\n return (\n <BaseCard\n header={header}\n body={\n <div className=\"mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-900 dark:border-rose-900/40 dark:bg-rose-950/30 dark:text-rose-100\">\n {String(error)}\n </div>\n }\n {...cardProps}\n />\n );\n }\n\n const canSort = (col) => sortable && (col.sortable ?? true);\n\n return (\n <BaseCard\n variant=\"table\"\n header={header}\n body={\n <div className=\"mt-4 overflow-hidden rounded-xl border border-slate-200 dark:border-slate-800\">\n <div className=\"w-full overflow-x-auto\">\n <table className=\"min-w-full border-separate border-spacing-0\">\n <thead className=\"bg-slate-50 dark:bg-slate-950/30\">\n <tr>\n {columns.map((col) => {\n const active = sortKey === col.key;\n return (\n <th\n key={col.key}\n scope=\"col\"\n className={[\n \"whitespace-nowrap border-b border-slate-200 px-4 py-3 text-left text-xs font-semibold text-slate-600 dark:border-slate-800 dark:text-slate-300\",\n col.className ?? \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {canSort(col) ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-2 hover:text-slate-900 dark:hover:text-slate-50\"\n onClick={() => {\n const nextDir = active && sortDir === \"asc\" ? \"desc\" : \"asc\";\n setSortKey(col.key);\n setSortDir(nextDir);\n onSort?.({ key: col.key, direction: nextDir });\n }}\n >\n <span>{col.label}</span>\n <span className=\"text-[10px] opacity-70\">\n {active ? (sortDir === \"asc\" ? \"▲\" : \"▼\") : \"↕\"}\n </span>\n </button>\n ) : (\n col.label\n )}\n </th>\n );\n })}\n {rowActions ? (\n <th className=\"border-b border-slate-200 px-4 py-3 text-right text-xs font-semibold text-slate-600 dark:border-slate-800 dark:text-slate-300\">\n Actions\n </th>\n ) : null}\n </tr>\n </thead>\n\n <tbody className=\"bg-white dark:bg-slate-900\">\n {effectiveLoading ? (\n Array.from({ length: Math.min(pageSize, 6) }).map((_, idx) => (\n <tr key={idx}>\n {columns.map((col) => (\n <td\n key={col.key}\n className=\"border-b border-slate-200 px-4 py-3 dark:border-slate-800\"\n >\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-slate-200 dark:bg-slate-800\" />\n </td>\n ))}\n {rowActions ? (\n <td className=\"border-b border-slate-200 px-4 py-3 dark:border-slate-800\">\n <div className=\"h-4 w-10 animate-pulse rounded bg-slate-200 dark:bg-slate-800\" />\n </td>\n ) : null}\n </tr>\n ))\n ) : pageData.length === 0 ? (\n <tr>\n <td\n colSpan={columns.length + (rowActions ? 1 : 0)}\n className=\"px-4 py-10 text-center text-sm text-slate-600 dark:text-slate-300\"\n >\n {emptyMessage}\n </td>\n </tr>\n ) : (\n pageData.map((row, idx) => {\n const rowId = row?.id ?? idx;\n const selected = selectable && selectedId === rowId;\n return (\n <tr\n key={rowId}\n className={[\n \"group\",\n selectable ? \"cursor-pointer\" : \"\",\n selected ? \"bg-brand-50 dark:bg-brand-950/30\" : \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n onClick={() => {\n if (!selectable) return;\n setSelectedId(rowId);\n onRowSelect?.(row);\n }}\n >\n {columns.map((col) => {\n const raw = row?.[col.key];\n const content = col.render ? col.render(raw, row) : defaultTypeFormat(col.type, raw);\n return (\n <td\n key={col.key}\n className={[\n \"border-b border-slate-200 px-4 py-3 text-sm text-slate-700 dark:border-slate-800 dark:text-slate-200\",\n col.mono ? \"font-mono text-[13px]\" : \"\",\n col.className ?? \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {content}\n </td>\n );\n })}\n {rowActions ? (\n <td className=\"border-b border-slate-200 px-4 py-3 text-right text-sm dark:border-slate-800\">\n <div className=\"inline-flex items-center justify-end gap-2 opacity-100 sm:opacity-0 sm:group-hover:opacity-100\">\n {rowActions(row)}\n </div>\n </td>\n ) : null}\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n\n {paginated && !effectiveLoading ? (\n <div className=\"flex flex-col gap-2 border-t border-slate-200 bg-slate-50 px-4 py-3 dark:border-slate-800 dark:bg-slate-950/30 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"text-xs text-slate-600 dark:text-slate-300\">\n {total === 0 ? \"0 results\" : `Showing ${(clampedPage - 1) * pageSize + 1}-${Math.min(clampedPage * pageSize, total)} of ${total}`}\n </div>\n <div className=\"flex items-center gap-2\">\n <UIButton\n variant=\"outline\"\n size=\"sm\"\n disabled={clampedPage <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n Prev\n </UIButton>\n <div className=\"text-xs text-slate-600 dark:text-slate-300\">\n Page {clampedPage} / {totalPages}\n </div>\n <UIButton\n variant=\"outline\"\n size=\"sm\"\n disabled={clampedPage >= totalPages}\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n >\n Next\n </UIButton>\n </div>\n </div>\n ) : null}\n </div>\n }\n {...cardProps}\n />\n );\n}\n\n\n"],"names":["defaultTypeFormat","type","value","n","stableSort","data","compare","item","idx","a","b","c","x","TableCard","columns","title","subtitle","searchable","sortable","paginated","selectable","pageSize","actions","rowActions","onRowSelect","onSort","onSearch","loading","error","emptyMessage","simulateInitialLoad","minInitialDelayMs","maxInitialDelayMs","cardProps","query","setQuery","React","sortKey","setSortKey","sortDir","setSortDir","page","setPage","selectedId","setSelectedId","simLoading","setSimLoading","delay","t","effectiveLoading","filtered","q","row","col","raw","sorted","dir","av","bv","total","totalPages","clampedPage","pageData","start","header","jsxs","jsx","UIText","UIInput","BaseCard","canSort","active","nextDir","_","rowId","content","UIButton","p"],"mappings":"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"}
1
+ {"version":3,"file":"TableCard.js","sources":["../../../../src/components/library/cards/TableCard.jsx"],"sourcesContent":["import React from \"react\";\nimport BaseCard from \"./BaseCard\";\nimport UIInput from \"../ui/UIInput\";\nimport UIButton from \"../ui/UIButton\";\nimport UIText from \"../ui/Text\";\n\nfunction defaultTypeFormat(type, value) {\n if (value == null) return \"\";\n if (!type) return String(value);\n\n if (type === \"currency\") {\n const n = Number(value);\n if (Number.isFinite(n)) return n.toLocaleString(undefined, { style: \"currency\", currency: \"USD\" });\n }\n if (type === \"percentage\") {\n const n = Number(value);\n if (Number.isFinite(n)) return `${n}%`;\n }\n if (type === \"number\") {\n const n = Number(value);\n if (Number.isFinite(n)) return n.toLocaleString();\n }\n return String(value);\n}\n\nfunction stableSort(data, compare) {\n return data\n .map((item, idx) => ({ item, idx }))\n .sort((a, b) => {\n const c = compare(a.item, b.item);\n return c !== 0 ? c : a.idx - b.idx;\n })\n .map((x) => x.item);\n}\n\nexport default function TableCard({\n data = [],\n columns = [],\n title,\n subtitle,\n searchable = false,\n sortable = false,\n paginated = false,\n selectable = false,\n pageSize = 10,\n actions,\n rowActions,\n onRowSelect,\n onSort,\n onSearch,\n loading = false,\n error,\n emptyMessage = \"No results.\",\n simulateInitialLoad = false,\n minInitialDelayMs = 350,\n maxInitialDelayMs = 900,\n ...cardProps\n}) {\n const [query, setQuery] = React.useState(\"\");\n const [sortKey, setSortKey] = React.useState(null);\n const [sortDir, setSortDir] = React.useState(\"asc\");\n const [page, setPage] = React.useState(1);\n const [selectedId, setSelectedId] = React.useState(null);\n const [simLoading, setSimLoading] = React.useState(simulateInitialLoad);\n\n React.useEffect(() => {\n if (!simulateInitialLoad) return;\n const delay =\n Math.floor(Math.random() * (maxInitialDelayMs - minInitialDelayMs + 1)) + minInitialDelayMs;\n const t = setTimeout(() => setSimLoading(false), delay);\n return () => clearTimeout(t);\n }, [simulateInitialLoad, minInitialDelayMs, maxInitialDelayMs]);\n\n const effectiveLoading = loading || simLoading;\n\n const filtered = React.useMemo(() => {\n if (!searchable || !query.trim()) return data;\n const q = query.trim().toLowerCase();\n return data.filter((row) =>\n columns.some((col) => {\n const raw = row?.[col.key];\n if (raw == null) return false;\n return String(raw).toLowerCase().includes(q);\n })\n );\n }, [data, columns, query, searchable]);\n\n const sorted = React.useMemo(() => {\n if (!sortable || !sortKey) return filtered;\n const col = columns.find((c) => c.key === sortKey);\n if (!col) return filtered;\n const dir = sortDir === \"desc\" ? -1 : 1;\n return stableSort(filtered, (a, b) => {\n const av = a?.[sortKey];\n const bv = b?.[sortKey];\n if (av == null && bv == null) return 0;\n if (av == null) return -1 * dir;\n if (bv == null) return 1 * dir;\n if (typeof av === \"number\" && typeof bv === \"number\") return (av - bv) * dir;\n return String(av).localeCompare(String(bv)) * dir;\n });\n }, [filtered, sortable, sortKey, sortDir, columns]);\n\n const total = sorted.length;\n const totalPages = paginated ? Math.max(1, Math.ceil(total / pageSize)) : 1;\n const clampedPage = Math.min(page, totalPages);\n\n const pageData = React.useMemo(() => {\n if (!paginated) return sorted;\n const start = (clampedPage - 1) * pageSize;\n return sorted.slice(start, start + pageSize);\n }, [sorted, paginated, clampedPage, pageSize]);\n\n React.useEffect(() => {\n if (page !== clampedPage) setPage(clampedPage);\n }, [page, clampedPage]);\n\n const header = (\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n <div className=\"min-w-0\">\n {title ? (\n <UIText as=\"div\" size=\"sm\" weight=\"medium\">\n {title}\n </UIText>\n ) : null}\n {subtitle ? (\n <UIText as=\"div\" size=\"xs\" muted className=\"mt-1\">\n {subtitle}\n </UIText>\n ) : null}\n </div>\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-end\">\n {searchable ? (\n <div className=\"w-full sm:w-64\">\n <UIInput\n value={query}\n onChange={(e) => {\n setQuery(e.target.value);\n setPage(1);\n onSearch?.(e.target.value);\n }}\n placeholder=\"Search…\"\n aria-label=\"Search table\"\n />\n </div>\n ) : null}\n {actions ? <div className=\"flex items-center gap-2\">{actions}</div> : null}\n </div>\n </div>\n );\n\n if (error) {\n return (\n <BaseCard\n header={header}\n body={\n <div className=\"mt-4 rounded-xl border border-rose-200 bg-rose-50 p-4 text-sm text-rose-900 dark:border-rose-900/40 dark:bg-rose-950/30 dark:text-rose-100\">\n {String(error)}\n </div>\n }\n {...cardProps}\n />\n );\n }\n\n const canSort = (col) => sortable && (col.sortable ?? true);\n\n return (\n <BaseCard\n variant=\"table\"\n header={header}\n body={\n <div className=\"mt-4 overflow-hidden rounded-xl border border-slate-200 dark:border-slate-800\">\n <div className=\"w-full overflow-x-auto\">\n <table className=\"min-w-full border-separate border-spacing-0\">\n <thead className=\"bg-slate-50 dark:bg-slate-950/30\">\n <tr>\n {columns.map((col) => {\n const active = sortKey === col.key;\n return (\n <th\n key={col.key}\n scope=\"col\"\n className={[\n \"whitespace-nowrap border-b border-slate-200 px-4 py-3 text-left text-xs font-semibold text-slate-600 dark:border-slate-800 dark:text-slate-300\",\n col.className ?? \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {canSort(col) ? (\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-2 hover:text-slate-900 dark:hover:text-slate-50\"\n onClick={() => {\n const nextDir = active && sortDir === \"asc\" ? \"desc\" : \"asc\";\n setSortKey(col.key);\n setSortDir(nextDir);\n onSort?.({ key: col.key, direction: nextDir });\n }}\n >\n <span>{col.label}</span>\n <span className=\"text-[10px] opacity-70\">\n {active ? (sortDir === \"asc\" ? \"▲\" : \"▼\") : \"↕\"}\n </span>\n </button>\n ) : (\n col.label\n )}\n </th>\n );\n })}\n {rowActions ? (\n <th className=\"border-b border-slate-200 px-4 py-3 text-right text-xs font-semibold text-slate-600 dark:border-slate-800 dark:text-slate-300\">\n Actions\n </th>\n ) : null}\n </tr>\n </thead>\n\n <tbody className=\"bg-white dark:bg-slate-900\">\n {effectiveLoading ? (\n Array.from({ length: Math.min(pageSize, 6) }).map((_, idx) => (\n <tr key={idx}>\n {columns.map((col) => (\n <td\n key={col.key}\n className=\"border-b border-slate-200 px-4 py-3 dark:border-slate-800\"\n >\n <div className=\"h-4 w-3/4 animate-pulse rounded bg-slate-200 dark:bg-slate-800\" />\n </td>\n ))}\n {rowActions ? (\n <td className=\"border-b border-slate-200 px-4 py-3 dark:border-slate-800\">\n <div className=\"h-4 w-10 animate-pulse rounded bg-slate-200 dark:bg-slate-800\" />\n </td>\n ) : null}\n </tr>\n ))\n ) : pageData.length === 0 ? (\n <tr>\n <td\n colSpan={columns.length + (rowActions ? 1 : 0)}\n className=\"px-4 py-10 text-center text-sm text-slate-600 dark:text-slate-300\"\n >\n {emptyMessage}\n </td>\n </tr>\n ) : (\n pageData.map((row, idx) => {\n const rowId = row?.id ?? idx;\n const selected = selectable && selectedId === rowId;\n return (\n <tr\n key={rowId}\n className={[\n \"group\",\n selectable ? \"cursor-pointer\" : \"\",\n selected ? \"bg-brand-50 dark:bg-brand-950/30\" : \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n onClick={() => {\n if (!selectable) return;\n setSelectedId(rowId);\n onRowSelect?.(row);\n }}\n >\n {columns.map((col) => {\n const raw = row?.[col.key];\n const content = col.render ? col.render(raw, row) : defaultTypeFormat(col.type, raw);\n return (\n <td\n key={col.key}\n className={[\n \"border-b border-slate-200 px-4 py-3 text-sm text-slate-700 dark:border-slate-800 dark:text-slate-200\",\n col.mono ? \"font-mono text-[13px]\" : \"\",\n col.className ?? \"\"\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {content}\n </td>\n );\n })}\n {rowActions ? (\n <td className=\"border-b border-slate-200 px-4 py-3 text-right text-sm dark:border-slate-800\">\n <div className=\"inline-flex items-center justify-end gap-2 opacity-100 sm:opacity-0 sm:group-hover:opacity-100\">\n {rowActions(row)}\n </div>\n </td>\n ) : null}\n </tr>\n );\n })\n )}\n </tbody>\n </table>\n </div>\n\n {paginated && !effectiveLoading ? (\n <div className=\"flex flex-col gap-2 border-t border-slate-200 bg-slate-50 px-4 py-3 dark:border-slate-800 dark:bg-slate-950/30 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"text-xs text-slate-600 dark:text-slate-300\">\n {total === 0 ? \"0 results\" : `Showing ${(clampedPage - 1) * pageSize + 1}-${Math.min(clampedPage * pageSize, total)} of ${total}`}\n </div>\n <div className=\"flex items-center gap-2\">\n <UIButton\n variant=\"outline\"\n size=\"sm\"\n disabled={clampedPage <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n Prev\n </UIButton>\n <div className=\"text-xs text-slate-600 dark:text-slate-300\">\n Page {clampedPage} / {totalPages}\n </div>\n <UIButton\n variant=\"outline\"\n size=\"sm\"\n disabled={clampedPage >= totalPages}\n onClick={() => setPage((p) => Math.min(totalPages, p + 1))}\n >\n Next\n </UIButton>\n </div>\n </div>\n ) : null}\n </div>\n }\n {...cardProps}\n />\n );\n}\n\n\n"],"names":["defaultTypeFormat","type","value","n","stableSort","data","compare","item","idx","a","b","c","x","TableCard","columns","title","subtitle","searchable","sortable","paginated","selectable","pageSize","actions","rowActions","onRowSelect","onSort","onSearch","loading","error","emptyMessage","simulateInitialLoad","minInitialDelayMs","maxInitialDelayMs","cardProps","query","setQuery","React","sortKey","setSortKey","sortDir","setSortDir","page","setPage","selectedId","setSelectedId","simLoading","setSimLoading","delay","t","effectiveLoading","filtered","q","row","col","raw","sorted","dir","av","bv","total","totalPages","clampedPage","pageData","start","header","jsxs","jsx","UIText","UIInput","BaseCard","canSort","active","nextDir","_","rowId","content","UIButton","p"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/components/library/index.jsx"],"sourcesContent":["export { default as AppThemeProvider, useThemeMode } from \"./theme/AppThemeProvider\";\n\n// UI primitives\nexport { default as UIButton } from \"./ui/Button\";\nexport { default as UIInput } from \"./ui/Input\";\nexport { default as UIToggle } from \"./ui/Toggle\";\nexport { default as UIText } from \"./ui/Text\";\nexport { default as UICard, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from \"./ui/Card\";\nexport { default as UIContainer } from \"./ui/Container\";\nexport { default as UIChip } from \"./ui/Chip\";\nexport { default as Avatar } from \"./ui/Avatar\";\nexport { default as Spinner } from \"./ui/Spinner\";\nexport { default as EmptyState } from \"./ui/EmptyState\";\nexport { default as Label } from \"./ui/Label\";\nexport { default as Checkbox } from \"./ui/Checkbox\";\nexport { default as FieldGroup } from \"./ui/FieldGroup\";\n\n// Cards\nexport { default as BaseCard } from \"./cards/BaseCard\";\nexport { default as ChartCard } from \"./cards/ChartCard\";\nexport { default as ListCard } from \"./cards/ListCard\";\nexport { default as MetricCard } from \"./cards/MetricCard\";\nexport { default as SectionCard } from \"./cards/SectionCard\";\nexport { default as StatusCard } from \"./cards/StatusCard\";\nexport { default as TableCard } from \"./cards/TableCard\";\nexport { default as WidgetCard } from \"./cards/WidgetCard\";\nexport { default as FeedPanel } from \"./cards/FeedPanel\";\nexport { default as ActivityCard } from \"./cards/ActivityCard\";\nexport { default as MetricsStrip } from \"./cards/MetricsStrip\";\nexport { default as CalloutCard } from \"./cards/CalloutCard\";\nexport { default as ActionList } from \"./cards/ActionList\";\n\n// Charts\nexport { default as D3Chart } from \"./charts/D3Chart\";\nexport { D3ChartTemplates } from \"./charts/D3ChartTemplates\";\nexport { default as GeoMap } from \"./charts/GeoMap\";\n\n// Layout\nexport { default as PageContainer } from \"./layout/PageContainer\";\n\n// Skeletons\nexport { default as CardSkeleton } from \"./skeletons/CardSkeleton\";\n\n// Forms\nexport { FormModal, FormRenderer, FormSection, FormField, useFormState } from \"./forms\";\n\n// Filters\nexport { FilterBar, SearchFilter, SelectFilter, ToggleFilter } from \"./filters\";\n\n// Data mode\nexport { default as DataModeProvider, useDataMode } from \"./data/DataModeProvider\";\nexport { default as DataModeToggle } from \"./data/DataModeToggle\";\nexport { default as useDataSource } from \"./data/useDataSource\";\n\n// Data utilities\nexport { default as usePageFilters } from \"./data/usePageFilters\";\nexport {\n filterBySearch,\n filterByValue,\n filterByToggle,\n filterByDateRange,\n sortByKey,\n applyFilters,\n} from \"./data/filterUtils\";\n\n// Chat / AI agent\nexport {\n ChatPanel,\n ChatBar,\n ChatMessageList,\n ChatMessage,\n ChatInput,\n ChatTypingIndicator,\n ChatSuggestions,\n ChatToolCall,\n ChatWelcome,\n useChatState,\n} from \"./chat\";\n\n// HeroUI wrappers — existing\nexport { default as HeroUIButton, Button } from \"./heroui/Button\";\nexport { default as HeroUIInput } from \"./heroui/Input\";\nexport { default as HeroUICard } from \"./heroui/Card\";\nexport { default as HeroUIToggle } from \"./heroui/Toggle\";\n\n// HeroUI wrappers — navigation & layout\nexport { default as HeroUITabs, Tabs } from \"./heroui/Tabs\";\nexport { default as HeroUIAccordion, Accordion } from \"./heroui/Accordion\";\nexport { default as HeroUIBreadcrumbs, Breadcrumbs } from \"./heroui/Breadcrumbs\";\nexport { default as HeroUISeparator, Separator } from \"./heroui/Separator\";\nexport { default as HeroUIPagination, Pagination } from \"./heroui/Pagination\";\n\n// Breadcrumb subcomponents for shadcn compatibility\nexport const Breadcrumb = ({ children, ...props }) => <nav aria-label=\"breadcrumb\" {...props}>{children}</nav>;\nexport const BreadcrumbList = ({ children, ...props }) => <ol className=\"flex flex-wrap items-center gap-1.5 break-words text-sm text-slate-500 dark:text-slate-400\" {...props}>{children}</ol>;\nexport const BreadcrumbItem = ({ children, ...props }) => <li className=\"inline-flex items-center gap-1.5\" {...props}>{children}</li>;\nexport const BreadcrumbLink = ({ href, children, asChild, ...props }) => asChild ? <span {...props}>{children}</span> : <a href={href} className=\"transition-colors hover:text-slate-900 dark:hover:text-slate-50\" {...props}>{children}</a>;\nexport const BreadcrumbPage = ({ children, ...props }) => <span role=\"link\" aria-disabled=\"true\" aria-current=\"page\" className=\"font-normal text-slate-900 dark:text-slate-50\" {...props}>{children}</span>;\nexport const BreadcrumbSeparator = ({ children, ...props }) => <li role=\"presentation\" aria-hidden=\"true\" {...props}>{children ?? \"/\"}</li>;\nexport const BreadcrumbEllipsis = (props) => <span role=\"presentation\" aria-hidden=\"true\" {...props}>...</span>;\n\n// Pagination subcomponents for shadcn compatibility\nexport const PaginationContent = ({ children, ...props }) => <ul className=\"flex flex-row items-center gap-1\" {...props}>{children}</ul>;\nexport const PaginationItem = ({ children, ...props }) => <li {...props}>{children}</li>;\nexport const PaginationLink = ({ href, isActive, children, ...props }) => <a href={href} aria-current={isActive ? \"page\" : undefined} className={`inline-flex items-center justify-center rounded-md text-sm font-medium h-9 min-w-9 px-4 py-2 ${isActive ? \"bg-slate-900 text-white dark:bg-slate-50 dark:text-slate-900\" : \"hover:bg-slate-100 dark:hover:bg-slate-800\"}`} {...props}>{children}</a>;\nexport const PaginationPrevious = ({ href, ...props }) => <PaginationLink href={href} {...props}>Previous</PaginationLink>;\nexport const PaginationNext = ({ href, ...props }) => <PaginationLink href={href} {...props}>Next</PaginationLink>;\nexport const PaginationEllipsis = (props) => <span aria-hidden {...props}>...</span>;\n\n// HeroUI wrappers — overlays\nexport { default as HeroUIDrawer, Drawer } from \"./heroui/Drawer\";\nexport { default as HeroUIModal, Modal } from \"./heroui/Modal\";\nexport { default as HeroUIDropdown, Dropdown } from \"./heroui/Dropdown\";\nexport { default as HeroUITooltip, Tooltip } from \"./heroui/Tooltip\";\nexport { default as HeroUIToast, Toast, toast } from \"./heroui/Toast\";\n\n// HeroUI wrappers — feedback\nexport { default as HeroUIAlert } from \"./heroui/Alert\";\nexport { default as HeroUIBadge, Badge } from \"./heroui/Badge\";\nexport { default as HeroUIProgressBar, ProgressBar } from \"./heroui/ProgressBar\";\nexport { default as HeroUIProgressCircle, ProgressCircle } from \"./heroui/ProgressCircle\";\nexport { default as HeroUIMeter, Meter } from \"./heroui/Meter\";\nexport { default as HeroUISkeleton, Skeleton } from \"./heroui/Skeleton\";\n\n// shadcn-compatible components from ui/\nexport { default as Alert, AlertTitle, AlertDescription, AlertAction } from \"./ui/Alert\";\n\n// shadcn-compatible components from heroui/ (HeroUI-based)\nexport { default as HeroUIDialog, Dialog, DialogTrigger, DialogPortal, DialogClose, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription } from \"./heroui/Dialog\";\nexport { default as HeroUIField, Field, FieldLabel, FieldDescription, FieldError } from \"./heroui/Field\";\nexport { default as HeroUICollapsible, Collapsible, CollapsibleTrigger, CollapsibleContent } from \"./heroui/Collapsible\";\nexport { default as HeroUIPopover, Popover, PopoverTrigger, PopoverContent } from \"./heroui/Popover\";\nexport { default as HeroUIDatePicker, DatePicker, DatePickerTrigger, DatePickerContent, DatePickerCalendar, DatePickerRangeTrigger } from \"./heroui/DatePicker\";\n\n// HeroUI wrappers — pickers & forms\nexport { default as HeroUISelect, Select } from \"./heroui/Select\";\n\n// Re-export Select subcomponents for shadcn compatibility\nexport const SelectTrigger = ({ children, size, ...props }) => <button {...props}>{children}</button>;\nexport const SelectValue = ({ placeholder, ...props }) => <span {...props}>{placeholder}</span>;\nexport const SelectContent = ({ children, ...props }) => <div {...props}>{children}</div>;\nexport const SelectItem = ({ children, ...props }) => <div {...props}>{children}</div>;\n\n// HeroUI wrappers — utilities\nexport { default as HeroUIKbd, Kbd } from \"./heroui/Kbd\";\nexport { default as HeroUIScrollShadow, ScrollShadow } from \"./heroui/ScrollShadow\";\n"],"names":["Breadcrumb","children","props","jsx","BreadcrumbList","BreadcrumbItem","BreadcrumbLink","href","asChild","BreadcrumbPage","BreadcrumbSeparator","BreadcrumbEllipsis","PaginationContent","PaginationItem","PaginationLink","isActive","PaginationPrevious","PaginationNext","PaginationEllipsis","SelectTrigger","size","SelectValue","placeholder","SelectContent","SelectItem"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/components/library/index.jsx"],"sourcesContent":["export { default as AppThemeProvider, useThemeMode } from \"./theme/AppThemeProvider\";\n\n// UI primitives\nexport { default as UIButton } from \"./ui/UIButton\";\nexport { default as UIInput } from \"./ui/UIInput\";\nexport { default as UIToggle } from \"./ui/Toggle\";\nexport { default as UIText } from \"./ui/Text\";\nexport { default as UICard, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from \"./ui/Card\";\nexport { default as UIContainer } from \"./ui/Container\";\nexport { default as UIChip } from \"./ui/Chip\";\nexport { default as Avatar } from \"./ui/Avatar\";\nexport { default as Spinner } from \"./ui/Spinner\";\nexport { default as EmptyState } from \"./ui/EmptyState\";\nexport { default as Label } from \"./ui/Label\";\nexport { default as Checkbox } from \"./ui/Checkbox\";\nexport { default as FieldGroup } from \"./ui/FieldGroup\";\n\n// Cards\nexport { default as BaseCard } from \"./cards/BaseCard\";\nexport { default as ChartCard } from \"./cards/ChartCard\";\nexport { default as ListCard } from \"./cards/ListCard\";\nexport { default as MetricCard } from \"./cards/MetricCard\";\nexport { default as SectionCard } from \"./cards/SectionCard\";\nexport { default as StatusCard } from \"./cards/StatusCard\";\nexport { default as TableCard } from \"./cards/TableCard\";\nexport { default as WidgetCard } from \"./cards/WidgetCard\";\nexport { default as FeedPanel } from \"./cards/FeedPanel\";\nexport { default as ActivityCard } from \"./cards/ActivityCard\";\nexport { default as MetricsStrip } from \"./cards/MetricsStrip\";\nexport { default as CalloutCard } from \"./cards/CalloutCard\";\nexport { default as ActionList } from \"./cards/ActionList\";\n\n// Charts\nexport { default as D3Chart } from \"./charts/D3Chart\";\nexport { D3ChartTemplates } from \"./charts/D3ChartTemplates\";\nexport { default as GeoMap } from \"./charts/GeoMap\";\n\n// Layout\nexport { default as PageContainer } from \"./layout/PageContainer\";\n\n// Skeletons\nexport { default as CardSkeleton } from \"./skeletons/CardSkeleton\";\n\n// Forms\nexport { FormModal, FormRenderer, FormSection, FormField, useFormState } from \"./forms\";\n\n// Filters\nexport { FilterBar, SearchFilter, SelectFilter, ToggleFilter } from \"./filters\";\n\n// Data mode\nexport { default as DataModeProvider, useDataMode } from \"./data/DataModeProvider\";\nexport { default as DataModeToggle } from \"./data/DataModeToggle\";\nexport { default as useDataSource } from \"./data/useDataSource\";\n\n// Data utilities\nexport { default as usePageFilters } from \"./data/usePageFilters\";\nexport {\n filterBySearch,\n filterByValue,\n filterByToggle,\n filterByDateRange,\n sortByKey,\n applyFilters,\n} from \"./data/filterUtils\";\n\n// Chat / AI agent\nexport {\n ChatPanel,\n ChatBar,\n ChatMessageList,\n ChatMessage,\n ChatInput,\n ChatTypingIndicator,\n ChatSuggestions,\n ChatToolCall,\n ChatWelcome,\n useChatState,\n} from \"./chat\";\n\n// HeroUI wrappers — existing\nexport { default as HeroUIButton, Button } from \"./heroui/Button\";\nexport { default as HeroUIInput } from \"./heroui/Input\";\nexport { default as HeroUICard } from \"./heroui/Card\";\nexport { default as HeroUIToggle } from \"./heroui/Toggle\";\n\n// HeroUI wrappers — navigation & layout\nexport { default as HeroUITabs, Tabs } from \"./heroui/Tabs\";\nexport { default as HeroUIAccordion, Accordion } from \"./heroui/Accordion\";\nexport { default as HeroUIBreadcrumbs, Breadcrumbs } from \"./heroui/Breadcrumbs\";\nexport { default as HeroUISeparator, Separator } from \"./heroui/Separator\";\nexport { default as HeroUIPagination, Pagination } from \"./heroui/Pagination\";\n\n// Breadcrumb subcomponents for shadcn compatibility\nexport const Breadcrumb = ({ children, ...props }) => <nav aria-label=\"breadcrumb\" {...props}>{children}</nav>;\nexport const BreadcrumbList = ({ children, ...props }) => <ol className=\"flex flex-wrap items-center gap-1.5 break-words text-sm text-slate-500 dark:text-slate-400\" {...props}>{children}</ol>;\nexport const BreadcrumbItem = ({ children, ...props }) => <li className=\"inline-flex items-center gap-1.5\" {...props}>{children}</li>;\nexport const BreadcrumbLink = ({ href, children, asChild, ...props }) => asChild ? <span {...props}>{children}</span> : <a href={href} className=\"transition-colors hover:text-slate-900 dark:hover:text-slate-50\" {...props}>{children}</a>;\nexport const BreadcrumbPage = ({ children, ...props }) => <span role=\"link\" aria-disabled=\"true\" aria-current=\"page\" className=\"font-normal text-slate-900 dark:text-slate-50\" {...props}>{children}</span>;\nexport const BreadcrumbSeparator = ({ children, ...props }) => <li role=\"presentation\" aria-hidden=\"true\" {...props}>{children ?? \"/\"}</li>;\nexport const BreadcrumbEllipsis = (props) => <span role=\"presentation\" aria-hidden=\"true\" {...props}>...</span>;\n\n// Pagination subcomponents for shadcn compatibility\nexport const PaginationContent = ({ children, ...props }) => <ul className=\"flex flex-row items-center gap-1\" {...props}>{children}</ul>;\nexport const PaginationItem = ({ children, ...props }) => <li {...props}>{children}</li>;\nexport const PaginationLink = ({ href, isActive, children, ...props }) => <a href={href} aria-current={isActive ? \"page\" : undefined} className={`inline-flex items-center justify-center rounded-md text-sm font-medium h-9 min-w-9 px-4 py-2 ${isActive ? \"bg-slate-900 text-white dark:bg-slate-50 dark:text-slate-900\" : \"hover:bg-slate-100 dark:hover:bg-slate-800\"}`} {...props}>{children}</a>;\nexport const PaginationPrevious = ({ href, ...props }) => <PaginationLink href={href} {...props}>Previous</PaginationLink>;\nexport const PaginationNext = ({ href, ...props }) => <PaginationLink href={href} {...props}>Next</PaginationLink>;\nexport const PaginationEllipsis = (props) => <span aria-hidden {...props}>...</span>;\n\n// HeroUI wrappers — overlays\nexport { default as HeroUIDrawer, Drawer } from \"./heroui/Drawer\";\nexport { default as HeroUIModal, Modal } from \"./heroui/Modal\";\nexport { default as HeroUIDropdown, Dropdown } from \"./heroui/Dropdown\";\nexport { default as HeroUITooltip, Tooltip } from \"./heroui/Tooltip\";\nexport { default as HeroUIToast, Toast, toast } from \"./heroui/Toast\";\n\n// HeroUI wrappers — feedback\nexport { default as HeroUIAlert } from \"./heroui/Alert\";\nexport { default as HeroUIBadge, Badge } from \"./heroui/Badge\";\nexport { default as HeroUIProgressBar, ProgressBar } from \"./heroui/ProgressBar\";\nexport { default as HeroUIProgressCircle, ProgressCircle } from \"./heroui/ProgressCircle\";\nexport { default as HeroUIMeter, Meter } from \"./heroui/Meter\";\nexport { default as HeroUISkeleton, Skeleton } from \"./heroui/Skeleton\";\n\n// shadcn-compatible components from ui/\nexport { default as Alert, AlertTitle, AlertDescription, AlertAction } from \"./ui/Alert\";\n\n// shadcn-compatible components from heroui/ (HeroUI-based)\nexport { default as HeroUIDialog, Dialog, DialogTrigger, DialogPortal, DialogClose, DialogOverlay, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription } from \"./heroui/Dialog\";\nexport { default as HeroUIField, Field, FieldLabel, FieldDescription, FieldError } from \"./heroui/Field\";\nexport { default as HeroUICollapsible, Collapsible, CollapsibleTrigger, CollapsibleContent } from \"./heroui/Collapsible\";\nexport { default as HeroUIPopover, Popover, PopoverTrigger, PopoverContent } from \"./heroui/Popover\";\nexport { default as HeroUIDatePicker, DatePicker, DatePickerTrigger, DatePickerContent, DatePickerCalendar, DatePickerRangeTrigger } from \"./heroui/DatePicker\";\n\n// HeroUI wrappers — pickers & forms\nexport { default as HeroUISelect, Select } from \"./heroui/Select\";\n\n// Re-export Select subcomponents for shadcn compatibility\nexport const SelectTrigger = ({ children, size, ...props }) => <button {...props}>{children}</button>;\nexport const SelectValue = ({ placeholder, ...props }) => <span {...props}>{placeholder}</span>;\nexport const SelectContent = ({ children, ...props }) => <div {...props}>{children}</div>;\nexport const SelectItem = ({ children, ...props }) => <div {...props}>{children}</div>;\n\n// HeroUI wrappers — utilities\nexport { default as HeroUIKbd, Kbd } from \"./heroui/Kbd\";\nexport { default as HeroUIScrollShadow, ScrollShadow } from \"./heroui/ScrollShadow\";\n"],"names":["Breadcrumb","children","props","jsx","BreadcrumbList","BreadcrumbItem","BreadcrumbLink","href","asChild","BreadcrumbPage","BreadcrumbSeparator","BreadcrumbEllipsis","PaginationContent","PaginationItem","PaginationLink","isActive","PaginationPrevious","PaginationNext","PaginationEllipsis","SelectTrigger","size","SelectValue","placeholder","SelectContent","SelectItem"],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { jsx as d } from "react/jsx-runtime";
2
+ const i = {
3
+ primary: "bg-blue-600 text-white hover:bg-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400 border-transparent",
4
+ secondary: "bg-slate-900 text-white hover:bg-slate-800 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 border-transparent",
5
+ destructive: "bg-red-600 text-white hover:bg-red-500 dark:bg-red-500 dark:hover:bg-red-400 border-transparent",
6
+ outline: "bg-transparent text-slate-900 hover:bg-slate-50 dark:text-slate-50 dark:hover:bg-slate-900 border-slate-200 dark:border-slate-800",
7
+ ghost: "bg-transparent text-slate-900 hover:bg-slate-100 dark:text-slate-50 dark:hover:bg-slate-900 border-transparent",
8
+ link: "text-blue-600 underline-offset-4 hover:underline dark:text-blue-400 border-transparent"
9
+ }, u = {
10
+ sm: "h-8 px-3 text-sm",
11
+ md: "h-10 px-4 text-sm",
12
+ lg: "h-12 px-5 text-base",
13
+ icon: "h-10 w-10 p-0"
14
+ };
15
+ function f({
16
+ variant: e = "primary",
17
+ size: t = "md",
18
+ fullWidth: r = !1,
19
+ disabled: a = !1,
20
+ className: s = "",
21
+ children: o,
22
+ ...n
23
+ }) {
24
+ const l = i[e], b = u[t];
25
+ return /* @__PURE__ */ d(
26
+ "button",
27
+ {
28
+ type: "button",
29
+ disabled: a,
30
+ className: [
31
+ "inline-flex items-center justify-center gap-2 rounded-lg border font-medium shadow-sm transition",
32
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950",
33
+ "disabled:cursor-not-allowed disabled:opacity-60",
34
+ l,
35
+ b,
36
+ r ? "w-full" : "",
37
+ s
38
+ ].filter(Boolean).join(" "),
39
+ ...n,
40
+ children: o
41
+ }
42
+ );
43
+ }
44
+ export {
45
+ f as default
46
+ };
47
+ //# sourceMappingURL=UIButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UIButton.js","sources":["../../../../src/components/library/ui/UIButton.tsx"],"sourcesContent":["import * as React from \"react\";\n\nconst VARIANT_CLASSES = {\n primary:\n \"bg-blue-600 text-white hover:bg-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400 border-transparent\",\n secondary:\n \"bg-slate-900 text-white hover:bg-slate-800 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 border-transparent\",\n destructive:\n \"bg-red-600 text-white hover:bg-red-500 dark:bg-red-500 dark:hover:bg-red-400 border-transparent\",\n outline:\n \"bg-transparent text-slate-900 hover:bg-slate-50 dark:text-slate-50 dark:hover:bg-slate-900 border-slate-200 dark:border-slate-800\",\n ghost:\n \"bg-transparent text-slate-900 hover:bg-slate-100 dark:text-slate-50 dark:hover:bg-slate-900 border-transparent\",\n link: \"text-blue-600 underline-offset-4 hover:underline dark:text-blue-400 border-transparent\"\n} as const;\n\nconst SIZE_CLASSES = {\n sm: \"h-8 px-3 text-sm\",\n md: \"h-10 px-4 text-sm\",\n lg: \"h-12 px-5 text-base\",\n icon: \"h-10 w-10 p-0\"\n} as const;\n\nexport interface UIButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: keyof typeof VARIANT_CLASSES;\n size?: keyof typeof SIZE_CLASSES;\n fullWidth?: boolean;\n}\n\nexport default function UIButton({\n variant = \"primary\",\n size = \"md\",\n fullWidth = false,\n disabled = false,\n className = \"\",\n children,\n ...rest\n}: UIButtonProps) {\n const variantClass = VARIANT_CLASSES[variant];\n const sizeClass = SIZE_CLASSES[size];\n\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={[\n \"inline-flex items-center justify-center gap-2 rounded-lg border font-medium shadow-sm transition\",\n \"focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n variantClass,\n sizeClass,\n fullWidth ? \"w-full\" : \"\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n >\n {children}\n </button>\n );\n}\n"],"names":["VARIANT_CLASSES","SIZE_CLASSES","UIButton","variant","size","fullWidth","disabled","className","children","rest","variantClass","sizeClass","jsx"],"mappings":";AAEA,MAAMA,IAAkB;AAAA,EACtB,SACE;AAAA,EACF,WACE;AAAA,EACF,aACE;AAAA,EACF,SACE;AAAA,EACF,OACE;AAAA,EACF,MAAM;AACR,GAEMC,IAAe;AAAA,EACnB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM;AACR;AAQA,SAAwBC,EAAS;AAAA,EAC/B,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAAA,EACZ,UAAAC,IAAW;AAAA,EACX,WAAAC,IAAY;AAAA,EACZ,UAAAC;AAAA,EACA,GAAGC;AACL,GAAkB;AAChB,QAAMC,IAAeV,EAAgBG,CAAO,GACtCQ,IAAYV,EAAaG,CAAI;AAEnC,SACE,gBAAAQ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,UAAAN;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACAI;AAAA,QACAC;AAAA,QACAN,IAAY,WAAW;AAAA,QACvBE;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACV,GAAGE;AAAA,MAEH,UAAAD;AAAA,IAAA;AAAA,EAAA;AAGP;"}
@@ -0,0 +1,21 @@
1
+ import { jsx as o } from "react/jsx-runtime";
2
+ function a({ className: e = "", ...t }) {
3
+ return /* @__PURE__ */ o(
4
+ "input",
5
+ {
6
+ className: [
7
+ "h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 shadow-sm",
8
+ "placeholder:text-slate-400",
9
+ "focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:focus:ring-offset-slate-950",
10
+ "dark:border-slate-800 dark:bg-slate-900 dark:text-slate-50 dark:placeholder:text-slate-500",
11
+ "disabled:cursor-not-allowed disabled:opacity-50",
12
+ e
13
+ ].filter(Boolean).join(" "),
14
+ ...t
15
+ }
16
+ );
17
+ }
18
+ export {
19
+ a as default
20
+ };
21
+ //# sourceMappingURL=UIInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UIInput.js","sources":["../../../../src/components/library/ui/UIInput.tsx"],"sourcesContent":["import * as React from \"react\";\n\nexport interface UIInputProps extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nexport default function UIInput({ className = \"\", ...rest }: UIInputProps) {\n return (\n <input\n className={[\n \"h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 shadow-sm\",\n \"placeholder:text-slate-400\",\n \"focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:focus:ring-offset-slate-950\",\n \"dark:border-slate-800 dark:bg-slate-900 dark:text-slate-50 dark:placeholder:text-slate-500\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n className\n ]\n .filter(Boolean)\n .join(\" \")}\n {...rest}\n />\n );\n}\n"],"names":["UIInput","className","rest","jsx"],"mappings":";AAIA,SAAwBA,EAAQ,EAAE,WAAAC,IAAY,IAAI,GAAGC,KAAsB;AACzE,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACAF;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MACV,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGV;"}
@@ -1,7 +1,7 @@
1
1
  import { jsxs as i, jsx as e } from "react/jsx-runtime";
2
2
  import b from "react";
3
3
  import "../library/theme/AppThemeProvider.js";
4
- import u from "../library/ui/Button.js";
4
+ import u from "../library/ui/UIButton.js";
5
5
  import p from "../library/ui/Chip.js";
6
6
  import h from "../library/cards/ChartCard.js";
7
7
  import g from "../library/cards/MetricCard.js";
package/dist/index.js CHANGED
@@ -71,11 +71,11 @@ import { default as ho } from "./components/library/ui/Spinner.js";
71
71
  import { default as Mo } from "./components/library/cards/StatusCard.js";
72
72
  import { default as Ao } from "./components/library/cards/TableCard.js";
73
73
  import { default as vo } from "./components/library/filters/ToggleFilter.js";
74
- import { default as wo } from "./components/library/ui/Button.js";
74
+ import { default as wo } from "./components/library/ui/UIButton.js";
75
75
  import { Card as Ko, CardContent as Ro, CardDescription as Go, CardFooter as Vo, CardHeader as Wo, CardTitle as No, default as Oo } from "./components/library/ui/Card.js";
76
76
  import { default as qo } from "./components/library/ui/Chip.js";
77
77
  import { default as Jo } from "./components/library/ui/Container.js";
78
- import { default as Xo } from "./components/library/ui/Input.js";
78
+ import { default as Xo } from "./components/library/ui/UIInput.js";
79
79
  import { default as Zo } from "./components/library/ui/Text.js";
80
80
  import { default as $o } from "./components/library/ui/Toggle.js";
81
81
  import { default as ra } from "./components/library/cards/WidgetCard.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schandlergarcia/sf-web-components",
3
- "version": "1.9.41",
3
+ "version": "1.9.43",
4
4
  "description": "Reusable Salesforce web components library with Tailwind CSS v4 and shadcn/ui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,10 +28,12 @@
28
28
  "dist",
29
29
  "scripts",
30
30
  "data",
31
+ "src/templates",
31
32
  "src/components",
32
33
  "src/lib",
33
34
  "src/types",
34
35
  "README.md",
36
+ "INSTALL.md",
35
37
  ".a4drules"
36
38
  ],
37
39
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import UIButton from "../ui/Button";
2
+ import UIButton from "../ui/UIButton";
3
3
 
4
4
  /**
5
5
  * Row of action buttons — typically used at the bottom of a dashboard section.
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import BaseCard from "./BaseCard";
3
- import UIInput from "../ui/Input";
4
- import UIButton from "../ui/Button";
3
+ import UIInput from "../ui/UIInput";
4
+ import UIButton from "../ui/UIButton";
5
5
  import UIText from "../ui/Text";
6
6
 
7
7
  function defaultTypeFormat(type, value) {
@@ -1,8 +1,8 @@
1
1
  export { default as AppThemeProvider, useThemeMode } from "./theme/AppThemeProvider";
2
2
 
3
3
  // UI primitives
4
- export { default as UIButton } from "./ui/Button";
5
- export { default as UIInput } from "./ui/Input";
4
+ export { default as UIButton } from "./ui/UIButton";
5
+ export { default as UIInput } from "./ui/UIInput";
6
6
  export { default as UIToggle } from "./ui/Toggle";
7
7
  export { default as UIText } from "./ui/Text";
8
8
  export { default as UICard, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./ui/Card";
@@ -1,8 +1,8 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
 
3
3
  const VARIANT_CLASSES = {
4
4
  primary:
5
- "bg-brand-600 text-white hover:bg-brand-500 dark:bg-brand-500 dark:hover:bg-brand-400 border-transparent",
5
+ "bg-blue-600 text-white hover:bg-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400 border-transparent",
6
6
  secondary:
7
7
  "bg-slate-900 text-white hover:bg-slate-800 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200 border-transparent",
8
8
  destructive:
@@ -10,39 +10,42 @@ const VARIANT_CLASSES = {
10
10
  outline:
11
11
  "bg-transparent text-slate-900 hover:bg-slate-50 dark:text-slate-50 dark:hover:bg-slate-900 border-slate-200 dark:border-slate-800",
12
12
  ghost:
13
- "bg-transparent text-slate-900 hover:bg-slate-100 dark:text-slate-50 dark:hover:bg-slate-900 border-transparent"
14
- };
13
+ "bg-transparent text-slate-900 hover:bg-slate-100 dark:text-slate-50 dark:hover:bg-slate-900 border-transparent",
14
+ link: "text-blue-600 underline-offset-4 hover:underline dark:text-blue-400 border-transparent"
15
+ } as const;
15
16
 
16
17
  const SIZE_CLASSES = {
17
18
  sm: "h-8 px-3 text-sm",
18
19
  md: "h-10 px-4 text-sm",
19
20
  lg: "h-12 px-5 text-base",
20
21
  icon: "h-10 w-10 p-0"
21
- };
22
+ } as const;
23
+
24
+ export interface UIButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
25
+ variant?: keyof typeof VARIANT_CLASSES;
26
+ size?: keyof typeof SIZE_CLASSES;
27
+ fullWidth?: boolean;
28
+ }
22
29
 
23
30
  export default function UIButton({
24
31
  variant = "primary",
25
32
  size = "md",
26
33
  fullWidth = false,
27
34
  disabled = false,
28
- onClick = () => {},
29
- children,
30
- style = undefined,
31
35
  className = "",
36
+ children,
32
37
  ...rest
33
- }) {
34
- const variantClass = VARIANT_CLASSES[variant] ?? VARIANT_CLASSES.primary;
35
- const sizeClass = SIZE_CLASSES[size] ?? SIZE_CLASSES.md;
38
+ }: UIButtonProps) {
39
+ const variantClass = VARIANT_CLASSES[variant];
40
+ const sizeClass = SIZE_CLASSES[size];
36
41
 
37
42
  return (
38
43
  <button
39
44
  type="button"
40
- onClick={onClick}
41
45
  disabled={disabled}
42
- style={style}
43
46
  className={[
44
47
  "inline-flex items-center justify-center gap-2 rounded-lg border font-medium shadow-sm transition",
45
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950",
48
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-950",
46
49
  "disabled:cursor-not-allowed disabled:opacity-60",
47
50
  variantClass,
48
51
  sizeClass,
@@ -57,5 +60,3 @@ export default function UIButton({
57
60
  </button>
58
61
  );
59
62
  }
60
-
61
-
@@ -1,14 +1,16 @@
1
- import React from "react";
1
+ import * as React from "react";
2
2
 
3
- export default function UIInput({ style = undefined, className = "", ...rest }) {
3
+ export interface UIInputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
4
+
5
+ export default function UIInput({ className = "", ...rest }: UIInputProps) {
4
6
  return (
5
7
  <input
6
- style={style}
7
8
  className={[
8
9
  "h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 shadow-sm",
9
10
  "placeholder:text-slate-400",
10
11
  "focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:focus:ring-offset-slate-950",
11
12
  "dark:border-slate-800 dark:bg-slate-900 dark:text-slate-50 dark:placeholder:text-slate-500",
13
+ "disabled:cursor-not-allowed disabled:opacity-50",
12
14
  className
13
15
  ]
14
16
  .filter(Boolean)
@@ -17,5 +19,3 @@ export default function UIInput({ style = undefined, className = "", ...rest })
17
19
  />
18
20
  );
19
21
  }
20
-
21
-
@@ -0,0 +1,33 @@
1
+ import type { RouteObject } from 'react-router';
2
+ import AppLayout from './appLayout';
3
+ import Home from './pages/Home';
4
+ import AccountSearch from './features/object-search/__examples__/pages/AccountSearch';
5
+ import AccountObjectDetailPage from './features/object-search/__examples__/pages/AccountObjectDetailPage';
6
+ import NotFound from './pages/NotFound';
7
+
8
+ export const routes: RouteObject[] = [
9
+ {
10
+ path: "/",
11
+ element: <AppLayout />,
12
+ children: [
13
+ {
14
+ index: true,
15
+ element: <Home />,
16
+ handle: { showInNavigation: true, label: "Home" }
17
+ },
18
+ {
19
+ path: 'accounts',
20
+ element: <AccountSearch />,
21
+ handle: { showInNavigation: true, label: "Accounts" }
22
+ },
23
+ {
24
+ path: 'accounts/:recordId',
25
+ element: <AccountObjectDetailPage />
26
+ },
27
+ {
28
+ path: '*',
29
+ element: <NotFound />
30
+ }
31
+ ]
32
+ }
33
+ ];
@@ -0,0 +1,15 @@
1
+ import { RocketLaunchIcon } from "@heroicons/react/24/outline";
2
+ import { EmptyState } from "@/components/library";
3
+
4
+ export default function BlankDashboard() {
5
+ return (
6
+ <div className="flex min-h-screen items-center justify-center bg-slate-50 dark:bg-slate-950 transition-colors">
7
+ <EmptyState
8
+ size="lg"
9
+ icon={<RocketLaunchIcon className="h-14 w-14" />}
10
+ heading="Bespoke App Template"
11
+ body="Component library loaded and ready to go."
12
+ />
13
+ </div>
14
+ );
15
+ }
@@ -0,0 +1,58 @@
1
+ import { useState } from "react";
2
+ import { useNavigate } from "react-router";
3
+ import UIInput from '@/components/library/ui/UIInput';
4
+ import UIButton from '@/components/library/ui/UIButton';
5
+ import { Search } from "lucide-react";
6
+
7
+ export default function HomePage() {
8
+ const [searchQuery, setSearchQuery] = useState("");
9
+ const navigate = useNavigate();
10
+
11
+ const handleSearch = () => {
12
+ const trimmed = searchQuery.trim();
13
+ if (trimmed) {
14
+ navigate(`/accounts?search=${encodeURIComponent(trimmed)}`);
15
+ } else {
16
+ navigate('/accounts');
17
+ }
18
+ };
19
+
20
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
21
+ if (e.key === "Enter") {
22
+ e.preventDefault();
23
+ handleSearch();
24
+ }
25
+ };
26
+
27
+ return (
28
+ <div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
29
+ <div className="w-full max-w-4xl">
30
+ <div className="text-center mb-8">
31
+ <h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
32
+ <p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
33
+ </div>
34
+ <div className="flex flex-col gap-4">
35
+ <div className="relative">
36
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-slate-400" />
37
+ <UIInput
38
+ type="text"
39
+ value={searchQuery}
40
+ onChange={(e) => setSearchQuery(e.target.value)}
41
+ onKeyDown={handleKeyDown}
42
+ placeholder="Search..."
43
+ className="pl-10 w-full"
44
+ />
45
+ </div>
46
+ <div className="flex gap-3 justify-center">
47
+ <UIButton onClick={handleSearch} variant="primary">
48
+ Search
49
+ </UIButton>
50
+ <UIButton onClick={() => navigate('/accounts')} variant="secondary">
51
+ Browse All
52
+ </UIButton>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ );
58
+ }
@@ -0,0 +1,19 @@
1
+ import { useNavigate } from "react-router";
2
+ import UIButton from '@/components/library/ui/UIButton';
3
+
4
+ export default function NotFound() {
5
+ const navigate = useNavigate();
6
+
7
+ return (
8
+ <div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8">
9
+ <div className="w-full max-w-2xl text-center">
10
+ <h1 className="text-6xl font-bold text-slate-900 dark:text-slate-50 mb-4">404</h1>
11
+ <h2 className="text-2xl font-semibold text-slate-700 dark:text-slate-300 mb-4">Page Not Found</h2>
12
+ <p className="text-lg text-slate-600 dark:text-slate-400 mb-8">
13
+ The page you're looking for doesn't exist.
14
+ </p>
15
+ <UIButton onClick={() => navigate("/")}>Go Home</UIButton>
16
+ </div>
17
+ </div>
18
+ );
19
+ }
@@ -0,0 +1,13 @@
1
+ export default function Search() {
2
+ return (
3
+ <div className="flex min-h-[80vh] items-center justify-center px-4 sm:px-6 lg:px-8 bg-slate-50 dark:bg-slate-950 transition-colors">
4
+ <div className="w-full max-w-4xl">
5
+ <div className="text-center mb-8">
6
+ <h1 className="text-4xl font-bold text-slate-900 dark:text-slate-50 mb-4">Search</h1>
7
+ <p className="text-lg text-slate-600 dark:text-slate-300">Find records across your organization.</p>
8
+ </div>
9
+ <p className="text-center text-slate-500 dark:text-slate-400">Search functionality coming soon...</p>
10
+ </div>
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,15 @@
1
+ import AppThemeProvider from "@/components/library/theme/AppThemeProvider";
2
+ import DataModeProvider from "@/components/library/data/DataModeProvider";
3
+ import { Toaster } from "sonner";
4
+ import BlankDashboard from "../pages/BlankDashboard";
5
+
6
+ export default function CommandCenter() {
7
+ return (
8
+ <AppThemeProvider initialMode="light">
9
+ <DataModeProvider initialMode="sample">
10
+ <BlankDashboard />
11
+ <Toaster position="bottom-right" />
12
+ </DataModeProvider>
13
+ </AppThemeProvider>
14
+ );
15
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Type definitions for Agentforce Conversation Client
3
+ */
4
+
5
+ export interface ResolvedEmbedOptions {
6
+ salesforceOrigin?: string;
7
+ frontdoorUrl?: string;
8
+ }
9
+
10
+ export interface RenderingConfig {
11
+ mode?: 'inline' | 'modal' | 'sidebar' | 'floating';
12
+ theme?: 'light' | 'dark' | 'auto';
13
+ width?: string | number;
14
+ height?: string | number;
15
+ headerEnabled?: boolean;
16
+ }
17
+
18
+ export interface AgentforceClientConfig {
19
+ agentId?: string;
20
+ devName?: string;
21
+ renderingConfig?: RenderingConfig;
22
+ locale?: string;
23
+ styleTokens?: Record<string, string>;
24
+ [key: string]: any;
25
+ }
26
+
27
+ /**
28
+ * Props interface for AgentforceConversationClient component.
29
+ * Uses flat props that get normalized to AgentforceClientConfig internally.
30
+ */
31
+ export interface AgentforceConversationClientProps {
32
+ /** Agent ID to load */
33
+ agentId?: string;
34
+ /** Whether to render inline (true) or floating (false) */
35
+ inline?: boolean;
36
+ /** Whether to show the header in the conversation UI */
37
+ headerEnabled?: boolean;
38
+ /** Width of the conversation UI */
39
+ width?: string | number;
40
+ /** Height of the conversation UI */
41
+ height?: string | number;
42
+ /** Custom style tokens for theming */
43
+ styleTokens?: Record<string, string>;
44
+ /** Salesforce origin URL */
45
+ salesforceOrigin?: string;
46
+ /** Frontdoor URL for authentication */
47
+ frontdoorUrl?: string;
48
+ }