@base-framework/ui 1.0.2014 → 1.0.2015

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 (2) hide show
  1. package/copilot.md +361 -18
  2. package/package.json +1 -1
package/copilot.md CHANGED
@@ -5,11 +5,12 @@ This repo is a UI component library for the Base Framework, organized with Atomi
5
5
  ## How things fit together
6
6
  - Runtime primitives come from external packages:
7
7
  - `@base-framework/base` supplies Component, Atom, Data, Jot, Events, router, NavLink, etc.
8
- - `@base-framework/atoms` supplies DOM tag helpers (Div, Button, Input, Ul, Li, etc.) and reactive helpers (On, OnState, UseParent, OnStateOpen).
8
+ - `@base-framework/atoms` supplies DOM tag helpers (Div, Button, Input, Ul, Li, I, etc.) and reactive helpers (On, OnState, UseParent, OnStateOpen).
9
9
  - Local exports aggregate in `src/ui.js` and sub-entries in `vite.config.js`:
10
10
  - `@base-framework/ui` (index) exports everything from `components/*` and `utils/*`.
11
11
  - Subpath imports are enabled: `@base-framework/ui/atoms`, `.../icons`, `.../molecules`, `.../organisms`, `.../pages`, `.../templates`, `.../utils`.
12
12
  - Styling is Tailwind 4 with custom CSS vars (see `tailwind.config.js`). Use existing design tokens like `text-muted-foreground`, `bg-muted/10`, `border`, `ring`.
13
+ - Icons are provided via the `Icons` object from `@base-framework/ui/icons` and rendered using the `Icon` atom or raw `I` element from `@base-framework/atoms`.
13
14
 
14
15
  ## Build and dev workflow
15
16
  - Install: npm i
@@ -33,6 +34,16 @@ This repo is a UI component library for the Base Framework, organized with Atomi
33
34
  - Subscriptions: `On('key', callback)` or `OnState/Open` utilities to react to state.
34
35
  - Parent context: `UseParent(({ state, ... }) => ...)` to access parent component refs.
35
36
 
37
+ ### Important: Atom argument patterns
38
+ Atoms created with `Atom()` support flexible argument patterns:
39
+ - **Props only**: `Div({ class: 'text' })`
40
+ - **Text child only**: `Div('test')`
41
+ - **Array children only**: `Div([Div('test')])`
42
+ - **Props and text**: `Div({ class: 'text' }, 'test')`
43
+ - **Props and array children**: `Div({ class: 'text' }, [Div('test')])`
44
+
45
+ CRITICAL: When children is an array, pass it as the SECOND argument after props, NOT inside props.
46
+
36
47
  ## File layout to know
37
48
  - `src/components/atoms/**`: Base-level atoms and atom variants (e.g., buttons, icons, badges, tooltips, skeleton, veil).
38
49
  - `src/components/molecules/**`: Composition of atoms with light state (alerts, dropdowns, date/time pickers, theme toggle, counters, uploaders, etc.).
@@ -41,29 +52,239 @@ This repo is a UI component library for the Base Framework, organized with Atomi
41
52
  - `src/utils/**`: Utilities (formatting, image-scaler with pointer/zoom/drag helpers).
42
53
  - `src/ui.js`: Re-exports public surface used by `vite` lib entries.
43
54
 
55
+ ## Working with Icons (CRITICAL)
56
+
57
+ Icons in this library come from Heroicons and are defined in `src/components/icons/icons.js`. They are stored as SVG strings in a nested object structure.
58
+
59
+ ### Icon Structure
60
+ - Icons are organized hierarchically: `Icons.home`, `Icons.chat.default`, `Icons.chat.text`, `Icons.arrows.left`, etc.
61
+ - Each icon is a raw SVG string with Heroicon styling
62
+
63
+ ### How to Use Icons (3 methods)
64
+
65
+ #### Method 1: Using the Icon atom (RECOMMENDED)
66
+ ```javascript
67
+ import { Icon } from '@base-framework/ui/atoms';
68
+ import { Icons } from '@base-framework/ui/icons';
69
+
70
+ // Pass icon SVG string as child
71
+ Icon({ size: 'sm', class: 'text-blue-500' }, Icons.home)
72
+ Icon({ size: 'md' }, Icons.chat.default)
73
+ Icon({ size: 'lg' }, Icons.arrows.left)
74
+
75
+ // Sizes: xs, sm, md, lg, xl, 2xl, 3xl (default: sm)
76
+ ```
77
+
78
+ #### Method 2: Using raw I element
79
+ ```javascript
80
+ import { I } from '@base-framework/atoms';
81
+ import { Icons } from '@base-framework/ui/icons';
82
+
83
+ // Use html prop to inject SVG
84
+ I({ html: Icons.home, class: 'w-6 h-6' })
85
+ I({ html: Icons.chat.dots })
86
+ ```
87
+
88
+ #### Method 3: In Button with icon prop
89
+ ```javascript
90
+ import { Button } from '@base-framework/ui/atoms';
91
+ import { Icons } from '@base-framework/ui/icons';
92
+
93
+ // Icon appears on left by default
94
+ Button({ variant: 'withIcon', icon: Icons.plus }, 'Add Item')
95
+
96
+ // Icon on right
97
+ Button({ variant: 'withIcon', icon: Icons.arrows.right, position: 'right' }, 'Next')
98
+ ```
99
+
100
+ ### Common Icon Access Patterns
101
+ ```javascript
102
+ // Simple icons (top-level)
103
+ Icons.home, Icons.star, Icons.help, Icons.plus
104
+
105
+ // Nested icons (use dot notation)
106
+ Icons.chat.default, Icons.chat.text, Icons.chat.dots
107
+ Icons.arrows.left, Icons.arrows.right, Icons.arrows.upDown
108
+ Icons.adjustments.vertical, Icons.adjustments.horizontal
109
+
110
+ // Icons with states
111
+ Icons.locked, Icons.unlocked
112
+ Icons.play, Icons.stop, Icons.playing
113
+ ```
114
+
115
+ ### CRITICAL MISTAKES TO AVOID
116
+ ❌ **WRONG**: `Icon(Icons.home)` - Missing props object
117
+ ❌ **WRONG**: `Icon({ icon: Icons.home })` - Don't use `icon` prop
118
+ ❌ **WRONG**: `I(Icons.home)` - Must use `html` prop
119
+ ❌ **WRONG**: `Icons['home']` - Use dot notation, not bracket
120
+ ❌ **WRONG**: `Icons.chat` - Incomplete path for nested icons
121
+
122
+ ✅ **CORRECT**: `Icon({ size: 'sm' }, Icons.home)`
123
+ ✅ **CORRECT**: `I({ html: Icons.home })`
124
+ ✅ **CORRECT**: `Icons.chat.default` (for nested icons)
125
+
44
126
  ## Tailwind and theming
45
127
  - Tailwind scans `./src/ui.js` and `./src/**/*.{js,ts,jsx,tsx}`. If you add files, keep them under `src` and referenced by exports for purge to include classes.
46
128
  - Use semantic tokens configured in `tailwind.config.js`: `primary`, `secondary`, `destructive`, `warning`, `muted`, `accent`, `popover`, `card`, `border`, `foreground`, with `DEFAULT` and `foreground` pairs.
47
129
  - Dark mode is `media`. Prefer classes already used (`data-[state=active]:...`, rounded tokens via `--radius`).
48
130
 
49
131
  ## Patterns by example
50
- - Functional Atom example (from `molecules/alert.js`):
51
- - Compose small atoms: `Div` containers + `I` for icons + `H5/P` for text
52
- - Type variants use lookup table → apply Tailwind classes from map
53
- - Variant pattern (from `atoms/buttons/buttons.js`):
54
- - Define variant factories, then export a single `Button` Atom that dispatches by `props.variant`
55
- - Icon handling via a shared `IconButton` Atom; support `position: 'right'`
56
- - Data-driven lists (from `molecules/dropdowns/dropdown.js`):
57
- - `for: ['groups', (group) => ...]` to render nested collections
58
- - Stateful Component (from `organisms/panel.js`):
59
- - `class Panel extends Component { declareProps() { this.class = '' } render() { return Div({ class: this.class }, this.children) } }`
60
-
61
- ## Coding rules (do/don’t)
62
- - Do: import primitives from `@base-framework/atoms` and state tools from `@base-framework/base`; keep them as externals.
63
- - Do: export new public pieces from the appropriate barrel files (`components/*/atoms.js`, `.../molecules.js`, `.../organisms.js`, `pages.js`, `templates.js`, `utils.js`) so they are part of the library entry.
64
- - Do: keep Tailwind classes consistent with existing tokens; avoid raw hex colors.
65
- - Don’t: introduce React/Vue/JSX; this project uses Base’s declarative atoms/components.
66
- - Don’t: mutate DOM directly; use Atom/Component APIs and Data bindings.
132
+
133
+ ### Functional Atom (from `molecules/alert.js`)
134
+ Compose small atoms: `Div` containers + `I` for icons + `H5/P` for text. Type variants use lookup table → apply Tailwind classes from map.
135
+
136
+ ```javascript
137
+ import { Div, H5, I, P } from '@base-framework/atoms';
138
+ import { Atom } from '@base-framework/base';
139
+
140
+ const AlertIcon = (icon, iconColor) => (
141
+ Div({ class: `flex items-center justify-center h-6 w-6 mr-3 ${iconColor}` }, [
142
+ I({ html: icon })
143
+ ])
144
+ );
145
+
146
+ export const Alert = Atom(({ title, description, icon, type = 'default' }) => {
147
+ const { borderColor, bgColor, iconColor } = typeStyles[type];
148
+ return Div({ class: `flex items-start p-4 border rounded-lg ${bgColor} ${borderColor}` }, [
149
+ icon && AlertIcon(icon, iconColor),
150
+ Div({ class: 'flex flex-col' }, [
151
+ H5({ class: 'font-semibold' }, title),
152
+ P({ class: 'text-sm text-muted-foreground' }, description)
153
+ ])
154
+ ]);
155
+ });
156
+ ```
157
+
158
+ ### Variant pattern (from `atoms/buttons/buttons.js`)
159
+ Define variant factories, then export a single `Button` Atom that dispatches by `props.variant`. Icon handling via a shared `IconButton` Atom; support `position: 'right'`.
160
+
161
+ ```javascript
162
+ import { Button as BaseButton } from '@base-framework/atoms';
163
+ import { Atom } from '@base-framework/base';
164
+ import { Icon } from '../icon.js';
165
+
166
+ const IconButton = Atom((props, children) => (
167
+ BaseButton({
168
+ ...props,
169
+ class: props.class
170
+ }, [
171
+ props.icon && props.position !== 'right' ? Icon({ size: 'sm' }, props.icon) : null,
172
+ ...(children || []),
173
+ props.icon && props.position === 'right' ? Icon({ size: 'sm' }, props.icon) : null
174
+ ])
175
+ ));
176
+
177
+ const BUTTON_VARIANTS = {
178
+ primary: DefaultVariant({ class: 'primary' }),
179
+ withIcon: WithIconVariant({ class: 'with-icon' })
180
+ };
181
+
182
+ export const Button = Atom((props, children) => {
183
+ const VariantButton = BUTTON_VARIANTS[props.variant] || BUTTON_VARIANTS.primary;
184
+ return VariantButton(props, children);
185
+ });
186
+ ```
187
+
188
+ ### Data-driven lists (from `molecules/dropdowns/dropdown.js`)
189
+ Use `for: ['collectionKey', (item) => ...]` to render nested collections from component state.
190
+
191
+ ```javascript
192
+ export const Dropdown = (onSelect) => (
193
+ Div({ class: 'w-full z-10' }, [
194
+ Div({
195
+ class: 'max-h-60 border rounded-md',
196
+ for: ['groups', (group) => Group(group, onSelect)]
197
+ })
198
+ ])
199
+ );
200
+ ```
201
+
202
+ ### Stateful Component (from `organisms/lists/data-table.js`)
203
+ Use `Component` with `Data` for state management and `declareProps()` for type hints.
204
+
205
+ ```javascript
206
+ import { Component, Data } from '@base-framework/base';
207
+
208
+ export class DataTable extends Component {
209
+ declareProps() {
210
+ this.rows = [];
211
+ this.headers = [];
212
+ }
213
+
214
+ setData() {
215
+ return new Data({
216
+ selectedRows: [],
217
+ hasItems: this.rows && this.rows.length > 0
218
+ });
219
+ }
220
+
221
+ render() {
222
+ return Div({ class: 'w-full' }, [
223
+ Table([
224
+ TableHeader({ headers: this.headers }),
225
+ DataTableBody({ rows: this.rows })
226
+ ])
227
+ ]);
228
+ }
229
+ }
230
+ ```
231
+
232
+ ## Import Patterns (CRITICAL)
233
+
234
+ ### External Framework Imports
235
+ ```javascript
236
+ // DOM elements and reactive utilities
237
+ import { Div, Button, Input, I, Ul, Li, H5, P } from '@base-framework/atoms';
238
+ import { On, OnState, UseParent } from '@base-framework/atoms';
239
+
240
+ // Core framework classes and utilities
241
+ import { Atom, Component, Data, Jot } from '@base-framework/base';
242
+ ```
243
+
244
+ ### Internal Library Imports
245
+ ```javascript
246
+ // Icons (most common mistake area)
247
+ import { Icons } from '@base-framework/ui/icons';
248
+ import { Icon } from '@base-framework/ui/atoms';
249
+
250
+ // Components from this library
251
+ import { Button, Alert } from '@base-framework/ui/atoms';
252
+ import { Form, Dropdown } from '@base-framework/ui/molecules';
253
+ import { DataTable } from '@base-framework/ui/organisms';
254
+ ```
255
+
256
+ ### Relative Imports (when authoring components IN this library)
257
+ ```javascript
258
+ // From within src/components/
259
+ import { Icons } from '../../icons/icons.js';
260
+ import { Icon } from '../icon.js';
261
+ import { Button as BaseButton } from '@base-framework/atoms';
262
+ ```
263
+
264
+ ## Coding rules (do/don't)
265
+
266
+ ### DO:
267
+ - ✅ Import primitives from `@base-framework/atoms` (Div, Button, I, etc.)
268
+ - ✅ Import framework tools from `@base-framework/base` (Atom, Component, Data)
269
+ - ✅ Pass children array as SECOND argument: `Div({ class: 'wrapper' }, [child1, child2])`
270
+ - ✅ Use `Icons` object from `@base-framework/ui/icons` for all icons
271
+ - ✅ Use `Icon` atom with SVG string as child: `Icon({ size: 'sm' }, Icons.home)`
272
+ - ✅ Use `I({ html: iconString })` for raw icon rendering
273
+ - ✅ Export new components from appropriate barrel files
274
+ - ✅ Use Tailwind semantic tokens (primary, muted-foreground, etc.)
275
+ - ✅ Use `map: [array, fn]` or `for: ['key', fn]` for lists
276
+ - ✅ Use `bind: 'path'` or `bind: [state, 'key']` for two-way binding
277
+
278
+ ### DON'T:
279
+ - ❌ Pass children inside props object: `Div({ children: [...] })`
280
+ - ❌ Use `icon` prop on Icon atom: `Icon({ icon: Icons.home })`
281
+ - ❌ Pass icon directly without props: `Icon(Icons.home)`
282
+ - ❌ Use React/Vue/JSX syntax
283
+ - ❌ Mutate DOM directly (use Data bindings instead)
284
+ - ❌ Use raw hex colors (use Tailwind tokens)
285
+ - ❌ Import Icons from wrong path
286
+ - ❌ Create new icon implementations (use existing Icon atom)
287
+ - ❌ Forget to spread props: always use `{ ...defaultProps, ...props }`
67
288
 
68
289
  ## Adding a new component (checklist)
69
290
  1) Decide Atom vs Component (stateless vs stateful/interactive)
@@ -72,9 +293,131 @@ This repo is a UI component library for the Base Framework, organized with Atomi
72
293
  4) If it needs data/state, use `Data`/`Jot`, `On`, `bind`, `for` as seen in existing components
73
294
  5) Run dev server and verify render; run build to ensure types emit
74
295
 
296
+ ## Common Mistakes & Troubleshooting
297
+
298
+ ### Issue: Icons not rendering
299
+ **Symptoms**: Icons appear as blank or broken
300
+ **Causes**:
301
+ 1. Wrong import path for Icons
302
+ 2. Incorrect Icon usage syntax
303
+ 3. Missing `html` prop on I element
304
+
305
+ **Solutions**:
306
+ ```javascript
307
+ // ✅ Correct ways
308
+ import { Icons } from '@base-framework/ui/icons';
309
+ Icon({ size: 'sm' }, Icons.home)
310
+ I({ html: Icons.home })
311
+
312
+ // ❌ Wrong ways
313
+ Icon(Icons.home) // Missing props object
314
+ Icon({ icon: Icons.home }) // Wrong prop name
315
+ I(Icons.home) // Missing html prop
316
+ ```
317
+
318
+ ### Issue: Children not rendering
319
+ **Symptoms**: Child components/text not appearing
320
+ **Cause**: Passing children in props object instead of as second argument
321
+
322
+ **Solution**:
323
+ ```javascript
324
+ // ✅ Correct
325
+ Div({ class: 'wrapper' }, [
326
+ Div('child 1'),
327
+ Div('child 2')
328
+ ])
329
+
330
+ // ❌ Wrong
331
+ Div({
332
+ class: 'wrapper',
333
+ children: [Div('child')]
334
+ })
335
+ ```
336
+
337
+ ### Issue: Component not reactive
338
+ **Symptoms**: UI doesn't update when data changes
339
+ **Cause**: Not using Data or proper bindings
340
+
341
+ **Solution**:
342
+ ```javascript
343
+ // ✅ Use Data in Component
344
+ setData() {
345
+ return new Data({ count: 0 });
346
+ }
347
+
348
+ // ✅ Use bind for two-way binding
349
+ Input({ bind: 'username' })
350
+ Input({ bind: [externalState, 'email'] })
351
+ ```
352
+
353
+ ### Issue: List not rendering
354
+ **Symptoms**: Array of items not displaying
355
+ **Cause**: Using regular map instead of Base's reactive patterns
356
+
357
+ **Solution**:
358
+ ```javascript
359
+ // ✅ Use map prop
360
+ Ul({ map: [items, (item) => Li(item.name)] })
361
+
362
+ // ✅ Use for with state key
363
+ Div({ for: ['items', (item) => ItemComponent(item)] })
364
+
365
+ // ❌ Wrong - regular JS map
366
+ Ul([items.map(item => Li(item.name))])
367
+ ```
368
+
75
369
  ## Commands reference
76
370
  - Dev: `npm run dev`
77
371
  - Build: `npm run build`
78
372
  - Preview: `npm run preview`
79
373
 
374
+ ## Quick Reference Card
375
+
376
+ ### Component Creation
377
+ ```javascript
378
+ // Atom (stateless)
379
+ export const MyAtom = Atom((props, children) => (
380
+ Div({ class: props.class }, children)
381
+ ));
382
+
383
+ // Component (stateful)
384
+ export class MyComponent extends Component {
385
+ declareProps() {
386
+ this.items = [];
387
+ }
388
+
389
+ setData() {
390
+ return new Data({ selected: null });
391
+ }
392
+
393
+ render() {
394
+ return Div([/* ... */]);
395
+ }
396
+ }
397
+ ```
398
+
399
+ ### Icon Usage Quick Reference
400
+ ```javascript
401
+ // In Button
402
+ Button({ variant: 'withIcon', icon: Icons.plus }, 'Add')
403
+
404
+ // Standalone
405
+ Icon({ size: 'md', class: 'text-primary' }, Icons.home)
406
+
407
+ // Raw SVG
408
+ I({ html: Icons.check, class: 'w-5 h-5' })
409
+ ```
410
+
411
+ ### Event Handlers
412
+ ```javascript
413
+ // Click
414
+ Button({ click: (e) => console.log('clicked') }, 'Click')
415
+
416
+ // Submit (in Form)
417
+ Form({ submit: (e, parent) => handleSubmit(e) }, [...])
418
+
419
+ // State-based callbacks
420
+ Button({ onState: ['key', { key: 'value' }] }, 'State Button')
421
+ ```
422
+
80
423
  If anything seems unclear (e.g., preferred binding patterns or where to export), ask for confirmation before large changes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base-framework/ui",
3
- "version": "1.0.2014",
3
+ "version": "1.0.2015",
4
4
  "description": "This is a UI package that adds components and atoms that use Tailwind CSS and a theme based on Shadcn.",
5
5
  "main": "./dist/index.es.js",
6
6
  "scripts": {