@knowark/componarkjs 1.14.0 → 1.14.2

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 (102) hide show
  1. package/README.md +57 -45
  2. package/lib/base/component/README.md +127 -0
  3. package/lib/base/component/component.js +127 -21
  4. package/lib/base/component/component.test.js +296 -3
  5. package/lib/base/component/index.js +3 -0
  6. package/lib/base/styles/index.js +4 -1
  7. package/lib/base/utils/define.js +2 -1
  8. package/lib/base/utils/format.js +12 -6
  9. package/lib/base/utils/helpers.js +31 -5
  10. package/lib/base/utils/index.js +1 -0
  11. package/lib/base/utils/slots.js +3 -2
  12. package/lib/base/utils/uuid.js +1 -1
  13. package/lib/components/audio/components/audio.js +17 -2
  14. package/lib/components/audio/index.js +1 -0
  15. package/lib/components/audio/styles/index.js +5 -1
  16. package/lib/components/camera/components/camera.js +10 -0
  17. package/lib/components/camera/index.js +1 -0
  18. package/lib/components/camera/styles/index.js +5 -1
  19. package/lib/components/capture/components/capture.js +18 -2
  20. package/lib/components/capture/index.js +1 -0
  21. package/lib/components/droparea/components/droparea-preview.js +58 -13
  22. package/lib/components/droparea/components/droparea-preview.test.js +82 -0
  23. package/lib/components/droparea/components/droparea.js +41 -2
  24. package/lib/components/droparea/index.js +1 -0
  25. package/lib/components/droparea/styles/index.js +5 -1
  26. package/lib/components/emit/components/emit.js +11 -1
  27. package/lib/components/emit/index.js +1 -0
  28. package/lib/components/index.js +2 -1
  29. package/lib/components/list/components/item.js +6 -0
  30. package/lib/components/list/components/list.js +18 -4
  31. package/lib/components/list/index.js +1 -0
  32. package/lib/components/paginator/components/paginator.js +34 -8
  33. package/lib/components/paginator/index.js +1 -0
  34. package/lib/components/paginator/styles/index.js +5 -1
  35. package/lib/components/spinner/components/spinner.js +10 -0
  36. package/lib/components/spinner/index.js +1 -0
  37. package/lib/components/spinner/styles/index.js +5 -1
  38. package/lib/components/splitview/components/splitview.detail.js +10 -1
  39. package/lib/components/splitview/components/splitview.js +18 -3
  40. package/lib/components/splitview/components/splitview.master.js +10 -0
  41. package/lib/components/splitview/index.js +1 -0
  42. package/lib/components/translate/components/translate.js +42 -11
  43. package/lib/components/translate/components/translate.test.js +169 -1
  44. package/lib/components/translate/index.js +1 -0
  45. package/lib/index.js +3 -0
  46. package/package.json +2 -1
  47. package/tsconfig.json +1 -1
  48. package/types/base/component/component.d.ts +43 -8
  49. package/types/base/component/component.d.ts.map +1 -1
  50. package/types/base/component/index.d.ts +4 -6
  51. package/types/base/component/index.d.ts.map +1 -1
  52. package/types/base/styles/index.d.ts +3 -2
  53. package/types/base/styles/index.d.ts.map +1 -1
  54. package/types/base/utils/define.d.ts +3 -2
  55. package/types/base/utils/define.d.ts.map +1 -1
  56. package/types/base/utils/format.d.ts +12 -6
  57. package/types/base/utils/format.d.ts.map +1 -1
  58. package/types/base/utils/helpers.d.ts +27 -7
  59. package/types/base/utils/helpers.d.ts.map +1 -1
  60. package/types/base/utils/slots.d.ts +8 -10
  61. package/types/base/utils/slots.d.ts.map +1 -1
  62. package/types/base/utils/uuid.d.ts +1 -1
  63. package/types/base/utils/uuid.d.ts.map +1 -1
  64. package/types/components/audio/components/audio.d.ts +23 -9
  65. package/types/components/audio/components/audio.d.ts.map +1 -1
  66. package/types/components/audio/styles/index.d.ts +3 -2
  67. package/types/components/audio/styles/index.d.ts.map +1 -1
  68. package/types/components/camera/components/camera.d.ts +11 -3
  69. package/types/components/camera/components/camera.d.ts.map +1 -1
  70. package/types/components/camera/styles/index.d.ts +3 -2
  71. package/types/components/camera/styles/index.d.ts.map +1 -1
  72. package/types/components/capture/components/capture.d.ts +23 -3
  73. package/types/components/capture/components/capture.d.ts.map +1 -1
  74. package/types/components/droparea/components/droparea-preview.d.ts +64 -11
  75. package/types/components/droparea/components/droparea-preview.d.ts.map +1 -1
  76. package/types/components/droparea/components/droparea.d.ts +58 -13
  77. package/types/components/droparea/components/droparea.d.ts.map +1 -1
  78. package/types/components/droparea/styles/index.d.ts +3 -2
  79. package/types/components/droparea/styles/index.d.ts.map +1 -1
  80. package/types/components/emit/components/emit.d.ts +15 -3
  81. package/types/components/emit/components/emit.d.ts.map +1 -1
  82. package/types/components/list/components/item.d.ts +8 -1
  83. package/types/components/list/components/item.d.ts.map +1 -1
  84. package/types/components/list/components/list.d.ts +23 -5
  85. package/types/components/list/components/list.d.ts.map +1 -1
  86. package/types/components/paginator/components/paginator.d.ts +32 -8
  87. package/types/components/paginator/components/paginator.d.ts.map +1 -1
  88. package/types/components/paginator/styles/index.d.ts +3 -2
  89. package/types/components/paginator/styles/index.d.ts.map +1 -1
  90. package/types/components/spinner/components/spinner.d.ts +14 -3
  91. package/types/components/spinner/components/spinner.d.ts.map +1 -1
  92. package/types/components/spinner/styles/index.d.ts +3 -2
  93. package/types/components/spinner/styles/index.d.ts.map +1 -1
  94. package/types/components/splitview/components/splitview.d.ts +22 -4
  95. package/types/components/splitview/components/splitview.d.ts.map +1 -1
  96. package/types/components/splitview/components/splitview.detail.d.ts +12 -2
  97. package/types/components/splitview/components/splitview.detail.d.ts.map +1 -1
  98. package/types/components/splitview/components/splitview.master.d.ts +12 -1
  99. package/types/components/splitview/components/splitview.master.d.ts.map +1 -1
  100. package/types/components/translate/components/translate.d.ts +44 -10
  101. package/types/components/translate/components/translate.d.ts.map +1 -1
  102. package/lib/base/component/README.rst +0 -113
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  <p align="center">
2
2
  <a href="https://codecov.io/gh/librark/componark">
3
- <img src="https://codecov.io/gh/librark/componark/graph/badge.svg?token=IWNapsPUch"/>
3
+ <img src="https://codecov.io/gh/librark/componark/graph/badge.svg?token=IWNapsPUch" alt="codecov" />
4
4
  </a>
5
5
  </p>
6
6
  <p align="center">
7
7
  <a href="https://codecov.io/gh/librark/componark">
8
- <img src="https://codecov.io/gh/librark/componark/graphs/sunburst.svg?token=IWNapsPUch"/>
8
+ <img src="https://codecov.io/gh/librark/componark/graphs/sunburst.svg?token=IWNapsPUch" alt="coverage sunburst" />
9
9
  </a>
10
10
  </p>
11
11
 
@@ -13,46 +13,58 @@
13
13
 
14
14
  Pragmatic Web Components Library
15
15
 
16
- Introduction
17
- ============
18
-
19
- Componark is a collection of ready to use web components to propel the creation
20
- of user interfaces. A common *Component* base class is provided to ensure
21
- inter-component compatibility and common development idioms. This class is only
22
- a thin wrapper on top of the *HTMLElement* custom elements class, and might be
23
- extended in your own application code to create new components.
24
-
25
- Reference
26
- =========
27
-
28
- - `Base Component <lib/base/component>`_
29
-
30
- Components library
31
- ------------------
32
-
33
- - `<ark-accordion> <lib/components/accordion>`_
34
- - `<ark-alert> <lib/components/alert>`_
35
- - `<ark-audio> <lib/components/audio>`_
36
- - `<ark-button> <lib/components/button>`_
37
- - `<ark-camera> <lib/components/camera>`_
38
- - `<ark-card> <lib/components/card>`_
39
- - `<ark-chart> <lib/components/chart>`_
40
- - `<ark-checkbox> <lib/components/checkbox>`_
41
- - `<ark-droparea> <lib/components/droparea>`_
42
- - `<ark-gallery> <lib/components/gallery>`_
43
- - `<ark-icon> <lib/components/icon>`_
44
- - `<ark-list> <lib/components/list>`_
45
- - `<ark-input> <lib/components/input>`_
46
- - `<ark-location> <lib/components/location>`_
47
- - `<ark-map> <lib/components/map>`_
48
- - `<ark-modal> <lib/components/modal>`_
49
- - `<ark-multiselect> <lib/components/multiselect>`_
50
- - `<ark-paginator> <lib/components/paginator>`_
51
- - `<ark-radio> <lib/components/radio>`_
52
- - `<ark-select> <lib/components/select>`_
53
- - `<ark-sidebar> <lib/components/sidebar>`_
54
- - `<ark-signature> <lib/components/signature>`_
55
- - `<ark-spinner> <lib/components/spinner>`_
56
- - `<ark-splitview> <lib/components/splitview>`_
57
- - `<ark-tabs> <lib/components/tabs>`_
58
- - `<ark-tooltip> <lib/components/tooltip>`_
16
+ ## Introduction
17
+
18
+ ComponArk is a lightweight Web Components library with a shared base class for
19
+ consistency and event-driven composition.
20
+
21
+ The library is organized as custom elements that can be used directly in HTML or
22
+ combined with your application code.
23
+
24
+ ## Reference
25
+
26
+ - [Base Component](lib/base/component)
27
+ - [Showcase](showcase)
28
+
29
+ ## Components library
30
+
31
+ > Components marked in **bold** are available in this repository.
32
+
33
+ - **`ark-audio`** ([docs](lib/components/audio/README.md))
34
+ - **`ark-camera`** ([docs](lib/components/camera/README.md))
35
+ - **`ark-capture`** ([docs](lib/components/capture/README.md))
36
+ - **`ark-droparea`** ([docs](lib/components/droparea/README.md))
37
+ - **`ark-emit`** ([docs](lib/components/emit/README.md))
38
+ - **`ark-list`** ([docs](lib/components/list/README.md))
39
+ - **`ark-paginator`** ([docs](lib/components/paginator/README.md))
40
+ - **`ark-spinner`** ([docs](lib/components/spinner/README.md))
41
+ - **`ark-splitview`** ([docs](lib/components/splitview/README.md))
42
+ - **`ark-translate`** ([docs](lib/components/translate/README.md))
43
+
44
+ ## Why this exists
45
+
46
+ - Minimal, reusable base (`Component`) with lifecycle hooks and dependency
47
+ resolution.
48
+ - Template/event binding helper (`listen`) with custom attribute syntax.
49
+ - Lightweight styling support with constructor stylesheet + fallback support.
50
+ - Small test surface included with native Node test runner.
51
+
52
+ ## Basic usage
53
+
54
+ ```html
55
+ <ark-translate languages="en,es"></ark-translate>
56
+
57
+ <span data-i18n="hello">Hello</span>
58
+ ```
59
+
60
+ ## Development
61
+
62
+ - Run tests: `npm test`
63
+ - Build production bundle: `npm run prod`
64
+ - Start local dev server: `npm run dev`
65
+
66
+ ## Notes
67
+
68
+ Some older docs in the previous release referenced components that are not in the
69
+ current snapshot of this repository. If you need one of those modules, check
70
+ the release tags or open a request with expected parity.
@@ -0,0 +1,127 @@
1
+ # Component
2
+
3
+ `Component` is the base class for Componark custom elements. It extends `HTMLElement` with:
4
+
5
+ - Declarative event bindings (`listen` + `on-*` attributes)
6
+ - Attribute-to-property reflection
7
+ - Dependency resolution through bubbling `resolve` events
8
+ - Cleanup registration for disconnect lifecycle
9
+
10
+ ## Usage
11
+
12
+ ```javascript
13
+ import { Component } from 'base/component'
14
+
15
+ class MyComponent extends Component {
16
+ reflectedProperties () {
17
+ return ['title']
18
+ }
19
+
20
+ init (context = {}) {
21
+ this.local.count = this.local.count ?? 0
22
+ return super.init(context)
23
+ }
24
+
25
+ increment () {
26
+ this.local.count += 1
27
+ this.render()
28
+ }
29
+
30
+ render () {
31
+ this.content = `
32
+ <button listen on-click="increment">
33
+ ${this.title}: ${this.local.count}
34
+ </button>
35
+ `
36
+ return super.render()
37
+ }
38
+
39
+ async load (_context = {}) {
40
+ // Optional async work after render.
41
+ }
42
+ }
43
+
44
+ Component.define('my-component', MyComponent)
45
+ ```
46
+
47
+ ## Lifecycle
48
+
49
+ 1. `constructor()`
50
+ - Initializes internal state (`binding`, `local`, cleanup registry, etc.).
51
+ - Applies reflected properties using `reflectedProperties()`.
52
+ 2. `connectedCallback()`
53
+ - Marks the component as connected.
54
+ - Calls `init({})` only when `local` is empty.
55
+ - Calls `render()`.
56
+ - Calls `load({})` (sync or async).
57
+ 3. `disconnectedCallback()`
58
+ - Marks the component as disconnected.
59
+ - Runs registered cleanup callbacks.
60
+
61
+ Errors from `init`/`render`, `load`, and cleanup callbacks are emitted as bubbling `error` events. Enhanced errors include:
62
+
63
+ - `phase`: `init-render`, `load`, or `cleanup`
64
+ - `component`: current tag name (for example, `MY-COMPONENT`)
65
+
66
+ ## Public API
67
+
68
+ ### Static API
69
+
70
+ | Method | Description |
71
+ | --- | --- |
72
+ | `Component.define(tagName, element, styles?)` | Registers a custom element. If `styles` are provided, they are registered for that tag. |
73
+
74
+ ### Instance API
75
+
76
+ | Member | Returns | Description |
77
+ | --- | --- | --- |
78
+ | `init(context = {})` | `this` | Component state initialization hook. |
79
+ | `reflectedProperties()` | `string[]` | Attribute names to expose as reflected properties. |
80
+ | `slots` | `Record<string, HTMLElement[]>` | Child elements grouped by `slot` (`general` by default). |
81
+ | `content` | `string` | Proxy for `innerHTML`. Setting it flags listeners for re-binding. |
82
+ | `render()` | `this` | Adds the tag-name class and binds declarative listeners when needed. |
83
+ | `load(context = {})` | `void \| Promise<void>` | Async hook called after `render()`. |
84
+ | `registerCleanup(callback)` | `() => void` | Registers disconnect cleanup and returns an unregister function. |
85
+ | `select(selector)` | `Component` | `querySelector` helper. |
86
+ | `selectAll(selector)` | `NodeListOf<Component>` | `querySelectorAll` helper. |
87
+ | `emit(type, detail)` | `void` | Dispatches a bubbling, cancelable event with `detail`. |
88
+ | `resolve(resource)` | `any` | Requests a dependency through a bubbling `resolve` event. |
89
+ | `styleNames(styleMap)` | `string` | Returns truthy class names from an object map. |
90
+
91
+ ## Declarative listeners
92
+
93
+ `render()` triggers listener wiring on descendants marked with `listen`.
94
+
95
+ ```html
96
+ <input listen on-input="{{ local.query = data }}">
97
+ <input listen on-input="{{ local.total = data | number }}">
98
+ <button listen on-click="submit"></button>
99
+ <button listen on-click="submit@#child"></button>
100
+ <div listen on-change="replaceChildren%detail.name@#target"></div>
101
+ ```
102
+
103
+ Rules:
104
+
105
+ - Use `on-<event>` attributes to define handlers.
106
+ - `{{ ... }}` expressions perform state assignment.
107
+ - Pipes support `string`, `number`, `boolean`, and `object`.
108
+ - `handler@<selector>` routes execution to another element/component.
109
+ - Handler failures emit bubbling `error` events.
110
+
111
+ ## Dependency resolution
112
+
113
+ `resolve(resource)` dispatches a bubbling `resolve` event with `{ resource }`. Ancestors can provide values by implementing `provide(resource)`.
114
+
115
+ ```javascript
116
+ class ParentComponent extends Component {
117
+ provide (resource) {
118
+ if (resource === 'state') return this.local
119
+ }
120
+ }
121
+ ```
122
+
123
+ Then in a child:
124
+
125
+ ```javascript
126
+ const state = this.resolve('state')
127
+ ```
@@ -2,21 +2,31 @@ import { define, listen, reflect, slot, keys } from '../utils/index.js'
2
2
  import styles from '../styles/index.js'
3
3
 
4
4
  const tag = 'ark-component'
5
+ /**
6
+ * Base composable UI component.
7
+ * @extends {globalThis.HTMLElement}
8
+ */
5
9
  export class Component extends globalThis.HTMLElement {
6
10
  constructor () {
7
11
  super()
8
12
  this.binding = 'listen'
9
13
  this.local = {}
10
14
  this._isConnected = false
15
+ this._cleanupCallbacks = []
16
+ this._needsBinding = true
17
+ this.global = globalThis
11
18
  reflect(this, this.reflectedProperties())
12
19
  }
13
20
 
14
21
  /**
15
- * @param {string} tag
22
+ * Register a custom element and optional CSS for the same tag.
23
+ * @param {string} tagName
16
24
  * @param {CustomElementConstructor} element
17
- * @param {string} styles **/
18
- static define (tag, element, styles = null) {
19
- define(tag, element, styles)
25
+ * @param {string} [styles]
26
+ * @returns {void}
27
+ */
28
+ static define (tagName, element, styles = null) {
29
+ define(tagName, element, styles)
20
30
  }
21
31
 
22
32
  /**
@@ -28,7 +38,7 @@ export class Component extends globalThis.HTMLElement {
28
38
 
29
39
  /**
30
40
  * @param {object} context
31
- * @return {Component} */
41
+ * @return {this} */
32
42
  init (context = {}) {
33
43
  return this
34
44
  }
@@ -45,6 +55,7 @@ export class Component extends globalThis.HTMLElement {
45
55
  /** @param {string} content */
46
56
  set content (content) {
47
57
  this.innerHTML = content
58
+ this._needsBinding = true
48
59
  }
49
60
 
50
61
  /** @return {string} */
@@ -52,41 +63,62 @@ export class Component extends globalThis.HTMLElement {
52
63
  return this.innerHTML
53
64
  }
54
65
 
66
+ /** @returns {void} */
55
67
  connectedCallback () {
56
68
  this._isConnected = true
57
69
  try {
58
70
  !Boolean(Object.keys(this.local).length) && this.init({})
59
71
  this.render()
60
72
  } catch (error) {
61
- this.emit('error', error)
73
+ this.emit('error', this._enhanceError(error, 'init-render'))
62
74
  throw error
63
75
  }
64
76
  try {
65
77
  const load = this.load({})
66
78
  if (load && typeof load.catch === 'function') {
67
79
  load.catch(error => {
68
- this.emit('error', error)
80
+ this.emit('error', this._enhanceError(error, 'load'))
69
81
  })
70
82
  }
71
83
  } catch (error) {
72
- this.emit('error', error)
84
+ this.emit('error', this._enhanceError(error, 'load'))
73
85
  throw error
74
86
  }
75
87
  }
76
88
 
89
+ /** @returns {void} */
77
90
  disconnectedCallback () {
78
91
  this._isConnected = false
92
+ this._cleanup()
93
+ }
94
+
95
+ /**
96
+ * @param {Function} callback
97
+ * @return {Function} */
98
+ registerCleanup (callback) {
99
+ if (!callback || typeof callback !== 'function') return () => {}
100
+
101
+ this._cleanupCallbacks.push(callback)
102
+ return () => {
103
+ const index = this._cleanupCallbacks.indexOf(callback)
104
+ if (index === -1) return
105
+ this._cleanupCallbacks.splice(index, 1)
106
+ }
79
107
  }
80
108
 
81
- /** @return {Component} */
109
+ /** @return {this} */
82
110
  render () {
83
111
  this.classList.add(this.tagName.toLowerCase())
84
- listen(this)
112
+ if (this._needsBinding) {
113
+ listen(this)
114
+ this._needsBinding = false
115
+ }
85
116
  return this
86
117
  }
87
118
 
88
- /** @param {object} context */
89
- async load (context = {}) {}
119
+ /** @param {object} context
120
+ * @returns {void | Promise<void>} */
121
+ load (context = {}) {}
90
122
 
91
123
  /**
92
124
  * @param {string} selectors
@@ -108,26 +140,100 @@ export class Component extends globalThis.HTMLElement {
108
140
  * @param {string} type
109
141
  * @param {any} detail */
110
142
  emit (type, detail) {
111
- this.dispatchEvent(
112
- new globalThis.CustomEvent(type, {
113
- detail,
114
- bubbles: true,
115
- cancelable: true
116
- })
117
- )
143
+ this.dispatchEvent(this._createEvent(type, detail, {
144
+ bubbles: true,
145
+ cancelable: true
146
+ }))
118
147
  }
119
148
 
120
149
  /**
121
150
  * @param {string} resource
122
151
  * @return {any} */
123
152
  resolve (resource) {
124
- const event = new globalThis.CustomEvent('resolve', {
125
- detail: { resource },
153
+ const event = this._createEvent('resolve', { resource }, {
126
154
  bubbles: true,
127
155
  cancelable: true
128
156
  })
129
157
  this.dispatchEvent(event)
130
158
  return event.detail[resource]
131
159
  }
160
+
161
+ /**
162
+ * @param {any} detail
163
+ * @param {string} phase
164
+ * @return {Error} */
165
+ _enhanceError (detail, phase) {
166
+ if (!detail) return detail
167
+
168
+ const error = detail instanceof Error ? detail : new Error(
169
+ `${detail.message || detail}`
170
+ )
171
+ /** @type {Error & { phase?: string, component?: string }} */
172
+ const enhancedError = error
173
+ enhancedError.phase = phase
174
+ enhancedError.component = this.tagName
175
+ return error
176
+ }
177
+
178
+ /** @returns {void} */
179
+ _cleanup () {
180
+ const callbacks = [...this._cleanupCallbacks]
181
+ this._cleanupCallbacks = []
182
+
183
+ for (const callback of callbacks) {
184
+ try {
185
+ callback()
186
+ } catch (error) {
187
+ this.emit('error', this._enhanceError(error, 'cleanup'))
188
+ }
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Creates an event object for dispatch.
194
+ * @param {string} type
195
+ * @param {any} detail
196
+ * @param {{ bubbles?: boolean, cancelable?: boolean }} [options]
197
+ * @returns {CustomEvent}
198
+ */
199
+ _createEvent (type, detail, options = {}) {
200
+ /** @type {{ [key: string]: any }} */
201
+ const contextGlobal = this.global || {}
202
+ const contextWindow = contextGlobal.document?.defaultView || contextGlobal.window || contextGlobal
203
+ const { bubbles = true, cancelable = true } = options
204
+
205
+ if (typeof contextWindow.CustomEvent === 'function') {
206
+ return new contextWindow.CustomEvent(type, { detail, bubbles, cancelable })
207
+ }
208
+
209
+ if (typeof contextWindow.Event === 'function') {
210
+ const event = new contextWindow.Event(type, { bubbles, cancelable })
211
+ ;(/** @type {any} */ (event)).detail = detail
212
+ return /** @type {CustomEvent} */ (event)
213
+ }
214
+
215
+ if (typeof globalThis.CustomEvent === 'function') {
216
+ return new globalThis.CustomEvent(type, { detail, bubbles, cancelable })
217
+ }
218
+
219
+ if (typeof globalThis.Event === 'function') {
220
+ const event = new globalThis.Event(type, { bubbles, cancelable })
221
+ ;(/** @type {any} */ (event)).detail = detail
222
+ return /** @type {CustomEvent} */ (event)
223
+ }
224
+
225
+ return /** @type {CustomEvent} */ (/** @type {unknown} */ ({
226
+ type,
227
+ detail,
228
+ bubbles,
229
+ cancelable,
230
+ currentTarget: this,
231
+ defaultPrevented: false,
232
+ cancelBubble: false,
233
+ target: this,
234
+ stopPropagation () {},
235
+ preventDefault () {}
236
+ }))
237
+ }
132
238
  }
133
239
  Component.define(tag, Component, styles)