@pfern/elements 0.1.2 → 0.1.4

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/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Elements.js
2
2
 
3
- A minimalist declarative UI toolkit designed around purity, immutability, and HTML semantics.
3
+ Elements.js is a minimalist declarative UI toolkit designed around purity,
4
+ immutability, and HTML semantics.
4
5
 
5
6
  ## Features
6
7
 
@@ -14,7 +15,8 @@ A minimalist declarative UI toolkit designed around purity, immutability, and HT
14
15
 
15
16
  ## Why Elements.js?
16
17
 
17
- Modern frameworks introduced declarative UI—but buried it beneath lifecycle hooks, mutable state, and complex diffing algorithms.
18
+ Modern frameworks introduced declarative UI—but buried it beneath lifecycle
19
+ hooks, mutable state, and complex diffing algorithms.
18
20
 
19
21
  **Elements.js goes further:**
20
22
 
@@ -36,7 +38,8 @@ Yes. Elements.js proves it.
36
38
  * No lifecycle methods or effects
37
39
  * Every component is a function
38
40
 
39
- To update a view: just **call the function again** with new arguments. The DOM subtree is replaced in place.
41
+ To update a view: just **call the function again** with new arguments. The DOM
42
+ subtree is replaced in place.
40
43
 
41
44
  ### State lives in the DOM
42
45
 
@@ -49,23 +52,22 @@ The DOM node *is the history*. Input state is passed as an argument.
49
52
  * No transpilation step
50
53
  * No reactive graph to debug
51
54
 
52
- Elements.js embraces the full truth of each function call as the only valid state.
55
+ Elements.js embraces the full truth of each function call as the only valid
56
+ state.
53
57
 
54
58
  ---
55
59
 
56
60
  ## Example: Counter
57
61
 
58
62
  ```js
59
- import { div, pre, button, component, render } from './elements.js';
63
+ import { button, component, div, output } from '@pfern/elements'
60
64
 
61
- const counter = component((count = 0) =>
65
+ export const counter = component((count = 0) =>
62
66
  div(
63
- pre(count),
64
- button({ onclick: () => counter(count + 1) }, 'Increment')
65
- )
66
- )
67
-
68
- render(counter(), document.body);
67
+ output(count),
68
+ button(
69
+ { onclick: () => counter(count + 1) },
70
+ 'Increment')))
69
71
  ```
70
72
 
71
73
  * Each click returns a new call to `counter(count + 1)`
@@ -77,30 +79,36 @@ render(counter(), document.body);
77
79
  ## Form Example: Todos App
78
80
 
79
81
  ```js
80
- import { button, div, component, form, input, li, span, ul } from './elements.js';
81
82
 
82
- export const todos = component((items = []) => {
83
- const add = ({ todo: { value } }) =>
84
- value && todos([...items, { value, done: false }])
83
+ import { button, component, div,
84
+ form, input, li, span, ul } from '@pfern/elements'
85
+
86
+ export const todos = component(
87
+ (items = [{ value: 'Add my first todo', done: true }]) => {
88
+
89
+ const add = ({ todo: { value } }) =>
90
+ value && todos([...items, { value, done: false }])
91
+
92
+ const remove = item =>
93
+ todos(items.filter(i => i !== item))
94
+
95
+ const toggle = item =>
96
+ todos(items.map(i => i === item ? { ...i, done: !item.done } : i))
97
+
98
+ return (
99
+ div({ class: 'todos' },
100
+
101
+ form({ onsubmit: add },
102
+ input({ name: 'todo', placeholder: 'What needs doing?' }),
103
+ button({ type: 'submit' }, 'Add')),
104
+
105
+ ul(...items.map(item =>
106
+ li(
107
+ { style:
108
+ { 'text-decoration': item.done ? 'line-through' : 'none' } },
109
+ span({ onclick: () => toggle(item) }, item.value),
110
+ button({ onclick: () => remove(item) }, '✕'))))))})
85
111
 
86
- const remove = item =>
87
- todos(items.filter(i => i !== item))
88
-
89
- const toggle = item =>
90
- todos(items.map(i => i === item ? { ...i, done: !item.done } : i))
91
-
92
- return div({ class: 'todos' },
93
- form({ onsubmit: add },
94
- input({ name: 'todo', placeholder: 'What needs doing?' }),
95
- button({ type: 'submit' }, 'Add')),
96
- ul(...items.map(item =>
97
- li({ style: { 'text-decoration': item.done ? 'line-through' : 'none' } },
98
- span({ onclick: () => toggle(item) }, item.value),
99
- button({ onclick: () => remove(item) }, '✕')
100
- ))
101
- )
102
- )
103
- })
104
112
  ```
105
113
 
106
114
  This is a complete MVC-style app:
@@ -109,11 +117,17 @@ This is a complete MVC-style app:
109
117
  * Immutable
110
118
  * Pure
111
119
 
120
+ You can view these examples live on [Github
121
+ Pages](https://pfernandez.github.io/elements/) or by running them locally with
122
+ `npm run dev`.
123
+
112
124
  ---
113
125
 
114
126
  ## Root Rendering Shortcut
115
127
 
116
- If you use `html`, `head`, or `body` as the top-level tag, `render()` will automatically mount into the corresponding document element—no need to pass a container.
128
+ If you use `html`, `head`, or `body` as the top-level tag, `render()` will
129
+ automatically mount into the corresponding document element—no need to pass a
130
+ container.
117
131
 
118
132
  ```js
119
133
  import {
@@ -126,7 +140,8 @@ render(
126
140
  html(
127
141
  head(
128
142
  title('Elements.js'),
129
- meta({ name: 'viewport', content: 'width=device-width, initial-scale=1.0' }),
143
+ meta({ name: 'viewport',
144
+ content: 'width=device-width, initial-scale=1.0' }),
130
145
  link({ rel: 'stylesheet', href: 'css/style.css' })
131
146
  ),
132
147
  body(
@@ -134,29 +149,29 @@ render(
134
149
  main(
135
150
  section(
136
151
  h2('Todos'),
137
- todos()
138
- )
139
- )
140
- )
141
- )
142
- )
152
+ todos())))))
143
153
  ```
144
154
 
145
155
  ---
146
156
 
147
157
  ## Declarative Events
148
158
 
149
- All event listeners in Elements.js are pure functions. You can return a vnode from a listener to declaratively update the component tree—no mutation or imperative logic required.
159
+ All event listeners in Elements.js are pure functions. You can return a vnode
160
+ from a listener to declaratively update the component tree—- no mutation or
161
+ imperative logic required.
150
162
 
151
163
  ### General Behavior
152
164
 
153
- * Any event handler (e.g. `onclick`, `onsubmit`, `oninput`) may return a new vnode to trigger a subtree replacement.
154
- * If the handler returns `undefined`, the event is treated as passive (no update occurs).
165
+ * Any event handler (e.g. `onclick`, `onsubmit`, `oninput`) may return a new
166
+ vnode to trigger a subtree replacement.
167
+ * If the handler returns `undefined`, the event is treated as passive (no update
168
+ occurs).
155
169
  * Returned vnodes are passed to `component()` to re-render declaratively.
156
170
 
157
171
  ### Form Events
158
172
 
159
- For `onsubmit`, `oninput`, and `onchange`, Elements.js provides a special signature:
173
+ For `onsubmit`, `oninput`, and `onchange`, Elements.js provides a special
174
+ signature:
160
175
 
161
176
  ```js
162
177
  (event.target.elements, event)
@@ -167,7 +182,8 @@ That is, your handler receives:
167
182
  1. `elements`: the HTML form’s named inputs
168
183
  2. `event`: the original DOM event object
169
184
 
170
- Elements.js will automatically call `event.preventDefault()` *only if* your handler returns a vnode.
185
+ Elements.js will automatically call `event.preventDefault()` *only if* your
186
+ handler returns a vnode.
171
187
 
172
188
  ```js
173
189
  form({
@@ -176,7 +192,8 @@ form({
176
192
  })
177
193
  ```
178
194
 
179
- If the handler returns nothing, `preventDefault()` is skipped and the form submits natively.
195
+ If the handler returns nothing, `preventDefault()` is skipped and the form
196
+ submits natively.
180
197
 
181
198
  ---
182
199
 
@@ -188,7 +205,8 @@ Wrap a recursive pure function that returns a vnode.
188
205
 
189
206
  ### `render(vnode[, container])`
190
207
 
191
- Render a vnode into the DOM. If `vnode[0]` is `html`, `head`, or `body`, no `container` is required.
208
+ Render a vnode into the DOM. If `vnode[0]` is `html`, `head`, or `body`, no
209
+ `container` is required.
192
210
 
193
211
  ### DOM Elements
194
212
 
@@ -201,17 +219,23 @@ svg({ width: 100 }, circle({ r: 10 }))
201
219
 
202
220
  ### TypeScript & JSDoc
203
221
 
204
- Each tag function (e.g. `div`, `button`, `svg`) includes a `@typedef` and MDN-sourced description to:
222
+ Each tag function (e.g. `div`, `button`, `svg`) includes a `@typedef` and
223
+ MDN-sourced description to:
205
224
 
206
225
  * Provide editor hints
207
226
  * Encourage accessibility and semantic markup
208
227
  * Enable intelligent autocomplete
209
228
 
229
+ ### Testing Philosophy
230
+
231
+ Elements are data-in, data-out only, so mocking and headless browsers like
232
+ `jsdom` are unnecessary out of the box. See the tests [in this
233
+ repository](test/README.md) for some examples.
234
+
210
235
  ---
211
236
 
212
237
  ## Status
213
238
 
214
- * ✅ Production-ready core
215
239
  * 🧪 Fully tested (data-in/data-out behavior)
216
240
  * ⚡ Under 2kB min+gzip
217
241
  * ✅ Node and browser compatible
package/elements.js CHANGED
@@ -61,14 +61,14 @@ const diffTree = (a, b) => {
61
61
  }
62
62
  }
63
63
 
64
-
65
64
  /**
66
65
  * Compares the children of two vnodes and returns patch list.
67
66
  *
68
67
  * @param {Array} aChildren - Previous vnode children
69
68
  * @param {Array} bChildren - New vnode children
70
69
  * @returns {Array} patches - One per child node
71
- */const diffChildren = (aChildren, bChildren) => {
70
+ */
71
+ const diffChildren = (aChildren, bChildren) => {
72
72
  const patches = []
73
73
  const len = Math.max(aChildren.length, bChildren.length)
74
74
  for (let i = 0; i < len; i++) {
@@ -85,6 +85,8 @@ const diffTree = (a, b) => {
85
85
  * *if* the listener returns a vnode (to support declarative form updates).
86
86
  * - Handlers for these event types receive `(elements, event)` as arguments,
87
87
  * where `elements` is `event.target.elements` if available.
88
+ * - Async handlers are supported: if the listener returns a Promise,
89
+ * it will be awaited and the resulting vnode (if any) will be rendered.
88
90
  *
89
91
  * @param {HTMLElement} el - The DOM element to receive props
90
92
  * @param {Object} props - Attributes and event listeners to assign
@@ -92,7 +94,7 @@ const diffTree = (a, b) => {
92
94
  const assignProperties = (el, props) =>
93
95
  Object.entries(props).forEach(([key, value]) => {
94
96
  if (key.startsWith('on') && typeof value === 'function') {
95
- el[key] = (...args) => {
97
+ el[key] = async (...args) => {
96
98
  let target = el
97
99
  while (target && !target.__root) target = target.parentNode
98
100
  if (!target) return
@@ -102,9 +104,9 @@ const assignProperties = (el, props) =>
102
104
  const isFormEvent = /^(oninput|onsubmit|onchange)$/.test(key)
103
105
  const elements = isFormEvent && event?.target?.elements || null
104
106
 
105
- const result = isFormEvent
107
+ const result = await (isFormEvent
106
108
  ? value.call(el, elements, event)
107
- : value.call(el, event)
109
+ : value.call(el, event))
108
110
 
109
111
  if (isFormEvent && result !== undefined) {
110
112
  event.preventDefault()
@@ -119,11 +121,12 @@ const assignProperties = (el, props) =>
119
121
 
120
122
  if (DEBUG && result !== undefined && !Array.isArray(result)) {
121
123
  isFormEvent && event.preventDefault()
122
- DEBUG && console.warn(
123
- `Listener '${key}' on <${el.tagName.toLowerCase()}> returned "${result}".\n`
124
- + 'If you intended a UI update, return a vnode array like: div({}, ...).\n'
125
- + 'Otherwise, return undefined (or nothing) for native event listener behavior.'
126
- )
124
+ DEBUG
125
+ && console.warn(
126
+ `Listener '${key}' on <${el.tagName.toLowerCase()}> returned "${result}".\n`
127
+ + 'If you intended a UI update, return a vnode array like: div({}, ...).\n'
128
+ + 'Otherwise, return undefined (or nothing) for native event listener behavior.'
129
+ )
127
130
  }
128
131
 
129
132
  if (Array.isArray(result)) {
@@ -153,8 +156,10 @@ const assignProperties = (el, props) =>
153
156
  el.setAttribute(key, value)
154
157
  }
155
158
  } catch {
156
- DEBUG && console.warn(
157
- `Illegal DOM property assignment for ${el.tagName}: ${key}: ${value}`)
159
+ DEBUG
160
+ && console.warn(
161
+ `Illegal DOM property assignment for ${el.tagName}: ${key}: ${value}`
162
+ )
158
163
  }
159
164
  }
160
165
  })
@@ -194,9 +199,12 @@ const renderTree = (node, isRoot = true) => {
194
199
  }
195
200
 
196
201
  let el =
197
- tag === 'html' ? document.documentElement
198
- : tag === 'head' ? document.head
199
- : tag === 'body' ? document.body
202
+ tag === 'html'
203
+ ? document.documentElement
204
+ : tag === 'head'
205
+ ? document.head
206
+ : tag === 'body'
207
+ ? document.body
200
208
  : svgTagNames.includes(tag)
201
209
  ? document.createElementNS(svgNS, tag)
202
210
  : document.createElement(tag)
@@ -311,88 +319,232 @@ export const component = fn => {
311
319
 
312
320
  const htmlTagNames = [
313
321
  // Document metadata
314
- 'html', 'head', 'base', 'link', 'meta', 'title',
322
+ 'html',
323
+ 'head',
324
+ 'base',
325
+ 'link',
326
+ 'meta',
327
+ 'title',
315
328
 
316
329
  // Sections
317
- 'body', 'header', 'hgroup', 'nav', 'main', 'section', 'article',
318
- 'aside', 'footer', 'address',
330
+ 'body',
331
+ 'header',
332
+ 'hgroup',
333
+ 'nav',
334
+ 'main',
335
+ 'section',
336
+ 'article',
337
+ 'aside',
338
+ 'footer',
339
+ 'address',
319
340
 
320
341
  // Text content
321
- 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'hr', 'menu', 'pre', 'blockquote',
322
- 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'figure', 'figcaption',
342
+ 'h1',
343
+ 'h2',
344
+ 'h3',
345
+ 'h4',
346
+ 'h5',
347
+ 'h6',
348
+ 'p',
349
+ 'hr',
350
+ 'menu',
351
+ 'pre',
352
+ 'blockquote',
353
+ 'ol',
354
+ 'ul',
355
+ 'li',
356
+ 'dl',
357
+ 'dt',
358
+ 'dd',
359
+ 'figure',
360
+ 'figcaption',
323
361
  'div',
324
362
 
325
363
  // Inline text semantics
326
- 'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code',
327
- 'data', 'dfn', 'em', 'i', 'kbd', 'mark', 'q', 'rb', 'rp',
328
- 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong',
329
- 'sub', 'sup', 'time', 'u', 'var', 'wbr',
364
+ 'a',
365
+ 'abbr',
366
+ 'b',
367
+ 'bdi',
368
+ 'bdo',
369
+ 'br',
370
+ 'cite',
371
+ 'code',
372
+ 'data',
373
+ 'dfn',
374
+ 'em',
375
+ 'i',
376
+ 'kbd',
377
+ 'mark',
378
+ 'q',
379
+ 'rb',
380
+ 'rp',
381
+ 'rt',
382
+ 'rtc',
383
+ 'ruby',
384
+ 's',
385
+ 'samp',
386
+ 'small',
387
+ 'span',
388
+ 'strong',
389
+ 'sub',
390
+ 'sup',
391
+ 'time',
392
+ 'u',
393
+ 'var',
394
+ 'wbr',
330
395
 
331
396
  // Edits
332
- 'ins', 'del',
397
+ 'ins',
398
+ 'del',
333
399
 
334
400
  // Embedded content
335
- 'img', 'iframe', 'embed', 'object', 'param', 'video', 'audio',
336
- 'source', 'track', 'picture',
401
+ 'img',
402
+ 'iframe',
403
+ 'embed',
404
+ 'object',
405
+ 'param',
406
+ 'video',
407
+ 'audio',
408
+ 'source',
409
+ 'track',
410
+ 'picture',
337
411
 
338
412
  // Table content
339
- 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr',
340
- 'th', 'td', 'colgroup', 'col',
413
+ 'table',
414
+ 'caption',
415
+ 'thead',
416
+ 'tbody',
417
+ 'tfoot',
418
+ 'tr',
419
+ 'th',
420
+ 'td',
421
+ 'colgroup',
422
+ 'col',
341
423
 
342
424
  // Forms
343
- 'form', 'fieldset', 'legend', 'label', 'input', 'button',
344
- 'select', 'datalist', 'optgroup', 'option', 'textarea',
345
- 'output', 'progress', 'meter',
425
+ 'form',
426
+ 'fieldset',
427
+ 'legend',
428
+ 'label',
429
+ 'input',
430
+ 'button',
431
+ 'select',
432
+ 'datalist',
433
+ 'optgroup',
434
+ 'option',
435
+ 'textarea',
436
+ 'output',
437
+ 'progress',
438
+ 'meter',
346
439
 
347
440
  // Interactive elements
348
- 'details', 'search', 'summary', 'dialog', 'slot', 'template',
441
+ 'details',
442
+ 'search',
443
+ 'summary',
444
+ 'dialog',
445
+ 'slot',
446
+ 'template',
349
447
 
350
448
  // Scripting and style
351
- 'script', 'noscript', 'style',
449
+ 'script',
450
+ 'noscript',
451
+ 'style',
352
452
 
353
453
  // Web components and others
354
- 'canvas', 'picture', 'map', 'area', 'slot'
454
+ 'canvas',
455
+ 'picture',
456
+ 'map',
457
+ 'area',
458
+ 'slot'
355
459
  ]
356
460
 
357
461
  const svgTagNames = [
358
462
  // Animation elements
359
- 'a', 'animate', 'animateMotion', 'animateTransform', 'mpath', 'set',
463
+ 'a',
464
+ 'animate',
465
+ 'animateMotion',
466
+ 'animateTransform',
467
+ 'mpath',
468
+ 'set',
360
469
 
361
470
  // Basic shapes
362
- 'circle', 'ellipse', 'line', 'path', 'polygon', 'polyline', 'rect',
471
+ 'circle',
472
+ 'ellipse',
473
+ 'line',
474
+ 'path',
475
+ 'polygon',
476
+ 'polyline',
477
+ 'rect',
363
478
 
364
479
  // Container / structural
365
- 'defs', 'g', 'marker', 'mask', 'pattern', 'svg', 'switch', 'symbol', 'use',
480
+ 'defs',
481
+ 'g',
482
+ 'marker',
483
+ 'mask',
484
+ 'pattern',
485
+ 'svg',
486
+ 'switch',
487
+ 'symbol',
488
+ 'use',
366
489
 
367
490
  // Descriptive
368
- 'desc', 'metadata', 'title',
491
+ 'desc',
492
+ 'metadata',
493
+ 'title',
369
494
 
370
495
  // Filter primitives
371
- 'filter', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite',
372
- 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap',
373
- 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB',
374
- 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge',
375
- 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight',
376
- 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence',
496
+ 'filter',
497
+ 'feBlend',
498
+ 'feColorMatrix',
499
+ 'feComponentTransfer',
500
+ 'feComposite',
501
+ 'feConvolveMatrix',
502
+ 'feDiffuseLighting',
503
+ 'feDisplacementMap',
504
+ 'feDistantLight',
505
+ 'feDropShadow',
506
+ 'feFlood',
507
+ 'feFuncA',
508
+ 'feFuncB',
509
+ 'feFuncG',
510
+ 'feFuncR',
511
+ 'feGaussianBlur',
512
+ 'feImage',
513
+ 'feMerge',
514
+ 'feMergeNode',
515
+ 'feMorphology',
516
+ 'feOffset',
517
+ 'fePointLight',
518
+ 'feSpecularLighting',
519
+ 'feSpotLight',
520
+ 'feTile',
521
+ 'feTurbulence',
377
522
 
378
523
  // Gradient / paint servers
379
- 'linearGradient', 'radialGradient', 'stop',
524
+ 'linearGradient',
525
+ 'radialGradient',
526
+ 'stop',
380
527
 
381
528
  // Graphics elements
382
- 'image', 'foreignObject', // included in graphics section as non‑standard children
529
+ 'image',
530
+ 'foreignObject', // included in graphics section as non‑standard children
383
531
 
384
532
  // Text and text-path
385
- 'text', 'textPath', 'tspan',
533
+ 'text',
534
+ 'textPath',
535
+ 'tspan',
386
536
 
387
537
  // Scripting/style
388
- 'script', 'style',
538
+ 'script',
539
+ 'style',
389
540
 
390
541
  // View
391
542
  'view'
392
543
  ]
393
544
 
394
545
  const tagNames = [...htmlTagNames, ...svgTagNames]
395
- const isPropsObject = x => typeof x === 'object'
546
+ const isPropsObject = x =>
547
+ typeof x === 'object'
396
548
  && x !== null
397
549
  && !Array.isArray(x)
398
550
  && !(typeof Node !== 'undefined' && x instanceof Node)
@@ -422,18 +574,20 @@ const isPropsObject = x => typeof x === 'object'
422
574
  *
423
575
  * @type {Record<string, ElementHelper>}
424
576
  */
425
- export const elements = tagNames.reduce((acc, tag) => ({
426
- ...acc,
427
- [tag]: (propsOrChild, ...children) => {
428
- const props = isPropsObject(propsOrChild) ? propsOrChild : {}
429
- const actualChildren = props === propsOrChild
430
- ? children
431
- : [propsOrChild, ...children]
432
- return [tag, props, ...actualChildren]
577
+ export const elements = tagNames.reduce(
578
+ (acc, tag) => ({
579
+ ...acc,
580
+ [tag]: (propsOrChild, ...children) => {
581
+ const props = isPropsObject(propsOrChild) ? propsOrChild : {}
582
+ const actualChildren =
583
+ props === propsOrChild ? children : [propsOrChild, ...children]
584
+ return [tag, props, ...actualChildren]
585
+ }
586
+ }),
587
+ {
588
+ fragment: (...children) => ['fragment', {}, ...children]
433
589
  }
434
- }), {
435
- fragment: (...children) => ['fragment', {}, ...children]
436
- })
590
+ )
437
591
 
438
592
  /**
439
593
  * <html>
@@ -1928,4 +2082,3 @@ export const view = elements.view
1928
2082
 
1929
2083
  // TODO: MathML
1930
2084
  // https://developer.mozilla.org/en-US/docs/Web/MathML/Reference/Element
1931
-
package/package.json CHANGED
@@ -1,12 +1,20 @@
1
1
  {
2
2
  "name": "@pfern/elements",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "A minimalist, pure functional declarative UI toolkit.",
5
- "main": "elements.js",
6
5
  "type": "module",
6
+ "main": "elements.js",
7
+ "types": "./types/index.d.ts",
7
8
  "exports": {
8
- ".": "./elements.js"
9
+ ".": {
10
+ "types": "./types/index.d.ts",
11
+ "default": "./elements.js"
12
+ }
9
13
  },
14
+ "files": [
15
+ "./elements.js",
16
+ "./types"
17
+ ],
10
18
  "keywords": [
11
19
  "ui",
12
20
  "functional",
@@ -19,20 +27,21 @@
19
27
  "html"
20
28
  ],
21
29
  "scripts": {
22
- "dev": "vite examples/",
30
+ "dev": "vite",
23
31
  "build": "vite build",
24
32
  "preview": "vite preview",
25
33
  "test": "node --test test/*.test.* --test-reporter spec"
26
34
  },
27
35
  "repository": {
28
36
  "type": "git",
29
- "url": "https://github.com/pfernandez/elements.git"
37
+ "url": "git+https://github.com/pfernandez/elements.git"
30
38
  },
31
39
  "author": "Paul Fernandez",
32
40
  "license": "MIT",
33
41
  "devDependencies": {
42
+ "@types/node": "^25.0.10",
34
43
  "eslint": "^7.32.0",
35
- "vite": "^5.0.0"
44
+ "typescript": "^5.9.3",
45
+ "vite": "^7.3.1"
36
46
  }
37
47
  }
38
-