@vanilla-bean/components 1.1.1 → 2.0.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 (52) hide show
  1. package/Component/Component.js +222 -36
  2. package/Component/Component.test.js +425 -38
  3. package/Component/README.md +480 -0
  4. package/Elem/README.md +373 -0
  5. package/README.md +1 -1
  6. package/components/BottomSheet/BottomSheet.js +8 -16
  7. package/components/Button/Button.js +12 -18
  8. package/components/Calendar/Calendar.js +139 -59
  9. package/components/Calendar/CalendarEvent.js +9 -4
  10. package/components/Calendar/Toolbar.js +28 -20
  11. package/components/Calendar/index.js +1 -0
  12. package/components/Code/Code.js +26 -30
  13. package/components/ColorPicker/ColorPicker.js +57 -57
  14. package/components/Dialog/Dialog.js +78 -72
  15. package/components/Form/Form.js +12 -8
  16. package/components/Icon/Icon.js +19 -11
  17. package/components/Input/Input.js +85 -67
  18. package/components/Input/README.md +0 -2
  19. package/components/Keyboard/Key.js +7 -10
  20. package/components/Keyboard/Keyboard.js +38 -46
  21. package/components/Label/Label.js +52 -50
  22. package/components/Link/Link.js +14 -20
  23. package/components/List/List.js +28 -30
  24. package/components/Menu/Menu.js +19 -10
  25. package/components/Menu/Menu.lld.md +2 -2
  26. package/components/Notify/Notify.js +29 -19
  27. package/components/Popover/Popover.js +49 -44
  28. package/components/RadioButton/RadioButton.js +33 -29
  29. package/components/Router/Router.js +19 -21
  30. package/components/Select/Select.js +24 -30
  31. package/components/Table/Table.js +55 -36
  32. package/components/TagList/Tag.js +16 -14
  33. package/components/TagList/TagList.js +15 -8
  34. package/components/Tooltip/Tooltip.js +12 -25
  35. package/components/TooltipWrapper/TooltipWrapper.js +55 -49
  36. package/components/Whiteboard/Whiteboard.js +45 -43
  37. package/devTools/build.js +43 -0
  38. package/devTools/buildTypes.js +322 -0
  39. package/devTools/createComponent.js +155 -0
  40. package/devTools/extractJSDoc.js +395 -0
  41. package/devTools/processTemplate.js +500 -0
  42. package/devTools/updateComponentIndex.js +16 -0
  43. package/devTools/updateDemoViewIndex.js +90 -0
  44. package/eslint.config.cjs +6 -3
  45. package/index.d.ts +117 -59
  46. package/package.json +67 -22
  47. package/spellcheck.config.cjs +4 -0
  48. package/styled/README.md +329 -0
  49. package/theme/colors.js +15 -12
  50. package/theme/colors.test.js +28 -0
  51. package/utils/element.js +2 -2
  52. package/FontWithASyntaxHighlighter-Regular.woff2 +0 -0
package/Elem/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # Elem
2
+
3
+ Enhanced DOM element wrapper providing fluent API methods while maintaining direct access to the underlying HTMLElement.
4
+
5
+ ## Basic Usage
6
+
7
+ ### Simple Element Creation
8
+
9
+ Create DOM elements with enhanced manipulation capabilities:
10
+
11
+ ```js
12
+ import { Elem } from '@vanilla-bean/components';
13
+
14
+ const button = new Elem({
15
+ tag: 'button',
16
+ textContent: 'Click me',
17
+ className: 'btn btn-primary',
18
+ onclick: () => alert('Clicked!'),
19
+ appendTo: document.body,
20
+ });
21
+ ```
22
+
23
+ ### Complex Nested Structures
24
+
25
+ Build complex DOM hierarchies with nested elements:
26
+
27
+ ```js
28
+ const card = new Elem(
29
+ {
30
+ tag: 'div',
31
+ className: 'card',
32
+ style: { padding: '20px', margin: '10px' },
33
+ },
34
+ new Elem({ tag: 'h3', textContent: 'Card Title' }),
35
+ new Elem({ tag: 'p', textContent: 'Card content goes here.' }),
36
+ );
37
+ ```
38
+
39
+ ### Method Chaining
40
+
41
+ Chain methods for fluent DOM construction:
42
+
43
+ ```js
44
+ const navigation = new Elem({ tag: 'nav' })
45
+ .addClass('menu', 'horizontal')
46
+ .setStyle({ display: 'flex', gap: '16px' })
47
+ .append(
48
+ new Elem({ tag: 'a', textContent: 'Home', href: '/' }),
49
+ new Elem({ tag: 'a', textContent: 'About', href: '/about' }),
50
+ new Elem({ tag: 'a', textContent: 'Contact', href: '/contact' }),
51
+ )
52
+ .appendTo(document.body);
53
+ ```
54
+
55
+ ### Direct DOM Access
56
+
57
+ Access the full HTMLElement API when needed:
58
+
59
+ ```js
60
+ const input = new Elem({ tag: 'input', type: 'text' });
61
+
62
+ // Enhanced methods
63
+ input.addClass('form-control').setStyle({ width: '100%' });
64
+
65
+ // Direct DOM access
66
+ input.elem.focus();
67
+ input.elem.select();
68
+ input.elem.scrollIntoView({ behavior: 'smooth' });
69
+ ```
70
+
71
+ ## Configuration Options
72
+
73
+ ### Constructor Syntax
74
+
75
+ ```js
76
+ new Elem(options?, ...children)
77
+ ```
78
+
79
+ **Parameters:**
80
+
81
+ - `options` (Object) - Configuration options and HTML properties
82
+ - `children` (...Elem|HTMLElement|string) - Child elements or text content
83
+
84
+ ### Core Options
85
+
86
+ | Option | Type | Description |
87
+ | ------------ | --------------------------- | ---------------------------------- |
88
+ | `tag` | `string` | HTML tag name (default: 'div') |
89
+ | `style` | `object` | CSS properties as key-value pairs |
90
+ | `attributes` | `object` | HTML attributes as key-value pairs |
91
+ | `content` | `string\|Elem\|HTMLElement` | Element content |
92
+ | `appendTo` | `Elem\|HTMLElement` | Parent element to append to |
93
+ | `prependTo` | `Elem\|HTMLElement` | Parent element to prepend to |
94
+ | `append` | `Array` | Child elements to append |
95
+ | `prepend` | `Array` | Child elements to prepend |
96
+
97
+ ### HTML Properties
98
+
99
+ All standard HTMLElement properties work as options:
100
+
101
+ ```js
102
+ new Elem({
103
+ // Content properties
104
+ textContent: 'Button text',
105
+ innerHTML: '<span>HTML content</span>',
106
+
107
+ // Form properties
108
+ value: 'input value',
109
+ checked: true,
110
+ disabled: false,
111
+
112
+ // Element properties
113
+ id: 'unique-id',
114
+ className: 'btn primary',
115
+ title: 'Tooltip text',
116
+
117
+ // Link properties
118
+ href: 'https://example.com',
119
+ target: '_blank',
120
+
121
+ // Image properties
122
+ src: 'image.jpg',
123
+ alt: 'Image description',
124
+ });
125
+ ```
126
+
127
+ ### Event Handler Properties
128
+
129
+ Event handlers can be assigned directly:
130
+
131
+ ```js
132
+ new Elem({
133
+ tag: 'button',
134
+ onclick: event => console.log('clicked'),
135
+ onmouseover: event => console.log('hover'),
136
+ onchange: event => console.log('changed'),
137
+ onfocus: event => console.log('focused'),
138
+ });
139
+ ```
140
+
141
+ ## DOM Manipulation
142
+
143
+ ### Content Management
144
+
145
+ ```js
146
+ // Set content (replaces existing)
147
+ elem.content('New text content');
148
+ elem.content(new Elem({ tag: 'span', textContent: 'HTML element' }));
149
+
150
+ // Clear all content
151
+ elem.empty();
152
+ ```
153
+
154
+ ### Child Element Management
155
+
156
+ ```js
157
+ // Add children
158
+ elem.append(child1, child2, 'text content');
159
+ elem.prepend(child1, child2);
160
+
161
+ // Access children
162
+ const childElements = elem.children; // Array of Elem instances
163
+ const nativeChildren = elem.elem.children; // HTMLCollection
164
+ ```
165
+
166
+ ### Hierarchy Management
167
+
168
+ ```js
169
+ // Add to DOM
170
+ elem.appendTo(document.body);
171
+ elem.prependTo(document.querySelector('.container'));
172
+
173
+ // Navigate hierarchy
174
+ const parentElem = elem.parent; // Parent Elem instance (if exists)
175
+ const nativeParent = elem.parentElem; // Parent HTMLElement
176
+ ```
177
+
178
+ ### Style and Attribute Management
179
+
180
+ ```js
181
+ // Set multiple styles
182
+ elem.setStyle({
183
+ color: 'red',
184
+ fontSize: '16px',
185
+ backgroundColor: '#f0f0f0',
186
+ });
187
+
188
+ // Set multiple attributes
189
+ elem.setAttributes({
190
+ 'data-id': '123',
191
+ 'aria-label': 'Close button',
192
+ role: 'button',
193
+ });
194
+ ```
195
+
196
+ ## Class Management
197
+
198
+ ### Enhanced Class Operations
199
+
200
+ Elem provides enhanced class manipulation with regular expression support:
201
+
202
+ ```js
203
+ // Check for classes
204
+ elem.hasClass('active'); // Check single class
205
+ elem.hasClass('btn', 'primary'); // Check multiple classes
206
+ elem.hasClass(/^btn-/); // Check with regex pattern
207
+
208
+ // Add classes
209
+ elem.addClass('new-class');
210
+ elem.addClass('class1', 'class2', 'class3');
211
+
212
+ // Remove classes
213
+ elem.removeClass('old-class');
214
+ elem.removeClass(/^temp-/); // Remove all classes starting with 'temp-'
215
+ elem.removeClass(/\bmobile-\w+/g); // Remove classes matching pattern
216
+
217
+ // Toggle class based on a condition (add when true, remove when false)
218
+ elem.toggleClass('active', isActive);
219
+ ```
220
+
221
+ ### Class Manipulation Examples
222
+
223
+ ```js
224
+ const button = new Elem({ tag: 'button', className: 'btn btn-primary temp-123' });
225
+
226
+ // Remove all temporary classes
227
+ button.removeClass(/^temp-/);
228
+
229
+ // Add state classes
230
+ button.addClass('btn-large', 'btn-rounded');
231
+
232
+ // Conditional classes
233
+ if (isActive) {
234
+ button.addClass('active', 'selected');
235
+ }
236
+
237
+ // Check for button variants
238
+ if (button.hasClass(/^btn-(primary|secondary|danger)$/)) {
239
+ console.log('Has button variant class');
240
+ }
241
+ ```
242
+
243
+ ## Event Handling
244
+
245
+ ### EventTarget Integration
246
+
247
+ Elem extends EventTarget, providing full event capabilities:
248
+
249
+ ```js
250
+ const button = new Elem({ tag: 'button', textContent: 'Click me' });
251
+
252
+ // Option-based event handlers
253
+ new Elem({
254
+ tag: 'input',
255
+ onchange: event => console.log('Value changed:', event.target.value),
256
+ onfocus: event => event.target.select(),
257
+ });
258
+
259
+ // addEventListener method
260
+ button.addEventListener('click', event => {
261
+ console.log('Button clicked');
262
+ });
263
+
264
+ // Custom events
265
+ button.addEventListener('customEvent', event => {
266
+ console.log('Custom event data:', event.detail);
267
+ });
268
+
269
+ // Dispatch events
270
+ button.dispatchEvent(
271
+ new CustomEvent('customEvent', {
272
+ detail: { message: 'Hello' },
273
+ }),
274
+ );
275
+ ```
276
+
277
+ ### Event Handler Options vs Methods
278
+
279
+ ```js
280
+ // Via constructor options (preferred for initial setup)
281
+ const elem = new Elem({
282
+ tag: 'button',
283
+ onclick: handleClick,
284
+ onmouseover: handleHover,
285
+ });
286
+
287
+ // Via addEventListener (preferred for dynamic binding)
288
+ elem.addEventListener('click', handleClick);
289
+ elem.addEventListener('mouseover', handleHover);
290
+
291
+ // Via native element
292
+ elem.elem.addEventListener('click', handleClick);
293
+ ```
294
+
295
+ ## API Reference
296
+
297
+ ### Constructor
298
+
299
+ ```js
300
+ new Elem(options?, ...children)
301
+ ```
302
+
303
+ ### Core Methods
304
+
305
+ #### Content Methods
306
+
307
+ ```js
308
+ elem.content(content); // Set element content
309
+ elem.empty(); // Remove all child elements
310
+ ```
311
+
312
+ #### Child Management Methods
313
+
314
+ ```js
315
+ elem.append(...children); // Append child elements
316
+ elem.prepend(...children); // Prepend child elements
317
+ elem.appendTo(parent); // Append to parent element
318
+ elem.prependTo(parent); // Prepend to parent element
319
+ ```
320
+
321
+ #### Style and Attribute Methods
322
+
323
+ ```js
324
+ elem.setStyle(styles); // Set CSS properties
325
+ elem.setAttributes(attributes); // Set HTML attributes
326
+ elem.setOptions(options); // Set multiple options at once
327
+ ```
328
+
329
+ #### Class Methods
330
+
331
+ ```js
332
+ elem.hasClass(...classes); // Check for classes (supports regex)
333
+ elem.addClass(...classes); // Add CSS classes
334
+ elem.removeClass(...classes); // Remove CSS classes (supports regex)
335
+ elem.toggleClass(className, condition); // Add when condition is true, remove when false
336
+ ```
337
+
338
+ ### Properties
339
+
340
+ ```js
341
+ elem.elem; // Underlying HTMLElement
342
+ elem.parent; // Parent Elem instance (if created by Elem)
343
+ elem.parentElem; // Parent HTMLElement
344
+ elem.children; // Array of child Elem instances
345
+ elem.options; // Configuration options object
346
+ ```
347
+
348
+ ### Utility Methods
349
+
350
+ ```js
351
+ elem.toString(); // Returns '[object Elem]'
352
+ ```
353
+
354
+ ## Integration with Component
355
+
356
+ Elem serves as the foundation for the Component class:
357
+
358
+ ```js
359
+ import { Component } from '@vanilla-bean/components';
360
+
361
+ // Component extends Elem with reactive options
362
+ const component = new Component({
363
+ tag: 'div',
364
+ textContent: 'I am reactive!',
365
+ });
366
+
367
+ // All Elem methods available
368
+ component.addClass('component-class');
369
+ component.setStyle({ padding: '16px' });
370
+
371
+ // Plus Component-specific features
372
+ component.options.textContent = 'Updated reactively!';
373
+ ```
package/README.md CHANGED
@@ -124,7 +124,7 @@ const Card = styled(
124
124
  ({ colors }) => `
125
125
  background: ${colors.white};
126
126
  border-radius: 8px;
127
- box-shadow: 0 2px 8px ${colors.black.setAlpha(0.1)};
127
+ box-shadow: 0 2px 8px ${colors.alpha(colors.black, 0.1)};
128
128
  padding: 24px;
129
129
 
130
130
  &:hover {
@@ -2,12 +2,6 @@ import { styled } from '../../styled';
2
2
  import { Component } from '../../Component';
3
3
  import { Elem } from '../../Elem';
4
4
 
5
- const defaultOptions = {
6
- get appendTo() {
7
- return document.body;
8
- },
9
- };
10
-
11
5
  /**
12
6
  * Mobile-friendly bottom sheet with drag-to-close gesture.
13
7
  *
@@ -65,18 +59,16 @@ class BottomSheet extends styled(
65
59
  }
66
60
  `,
67
61
  ) {
68
- defaultOptions = { ...super.defaultOptions, ...defaultOptions };
69
-
70
- // Empty handler prevents _standardSetOption from routing onClose through the event system.
71
- // The value is accessed directly as this.options.onClose in hide().
72
- static handlers = {
73
- onClose() {},
62
+ static schema = {
63
+ appendTo: {
64
+ get default() {
65
+ return document.body;
66
+ },
67
+ },
68
+ // Read directly as this.options.onClose in hide()
69
+ onClose: {},
74
70
  };
75
71
 
76
- constructor(options = {}, ...children) {
77
- super({ ...defaultOptions, ...options }, ...children);
78
- }
79
-
80
72
  build() {
81
73
  this._dragZone = new Elem({ tag: 'div', appendTo: this, addClass: 'sheet-drag-zone' });
82
74
  new Elem({ tag: 'div', appendTo: this._dragZone, addClass: 'sheet-handle' });
@@ -1,7 +1,5 @@
1
1
  import { TooltipWrapper } from '../TooltipWrapper';
2
2
 
3
- const defaultOptions = { tag: 'button' };
4
-
5
3
  /**
6
4
  * Interactive button component with keyboard accessibility and tooltip support.
7
5
  *
@@ -31,23 +29,19 @@ const defaultOptions = { tag: 'button' };
31
29
  * });
32
30
  */
33
31
  export default class Button extends TooltipWrapper {
34
- defaultOptions = { ...super.defaultOptions, ...defaultOptions };
35
-
36
- constructor(options = {}, ...children) {
37
- const userOnKeyUp = options.onKeyUp;
32
+ static schema = {
33
+ tag: { default: 'button' },
34
+ };
38
35
 
39
- super(
40
- {
41
- ...defaultOptions,
42
- ...options,
43
- onKeyUp: event => {
44
- userOnKeyUp?.call(this, event);
45
- if (event.code === 'Space' || event.code === 'Enter') {
46
- this.options.onPointerPress?.(event);
47
- }
48
- },
36
+ build() {
37
+ this.on({
38
+ targetEvent: 'keyup',
39
+ id: 'buttonKeyboardActivate',
40
+ callback: event => {
41
+ if (event.code === 'Space' || event.code === 'Enter') {
42
+ this.options.onPointerPress?.(event);
43
+ }
49
44
  },
50
- ...children,
51
- );
45
+ });
52
46
  }
53
47
  }