mi-element 0.6.7 → 0.8.0

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/docs/element.md CHANGED
@@ -28,44 +28,32 @@ from the `static attributes` object. From there setters and getters for property
28
28
  changes using `.[name] = newValue` instead of `setAttribute(name, newValue)` are
29
29
  applied.
30
30
 
31
- Direct properties can also made observable with `static properties` as long as
32
- not yet being defined within attributes.
33
31
 
34
32
  ```js
35
33
  class extends MiElement {
36
34
  /**
37
- * Declare observable attributes and their default values with this getter.
38
- * Do not use `static attribute = { text: 'Hi' }` as components attributes
35
+ * Declare observable attributes with this getter.
36
+ * Use `true` to define boolean attributes!
37
+ * Do not use `static attribute = { text: false }` as components attributes
39
38
  * will use a shallow copy only. With the getter we always get a real "deep"
40
39
  * copy.
41
40
  *
42
- * For yet to defined numbers, boolean or strings use `Number`, `Boolean`,
43
- * `String`. Attributes are accessible via `.[name]` or `.getAttribute(name)`.
44
41
  * Avoid using attributes which are HTMLElement properties e.g. `className`.
42
+ * camelCased attributes will be made observable using its kebab-cased name.
45
43
  */
46
- static get attributes () {
44
+ static get properties () {
47
45
  return {
48
- text: 'Hi',
49
- // A yet to be defined boolean value
50
- focus: Boolean
46
+ text: {},
47
+ focus: { type: Boolean },
48
+ // define property only
49
+ numberPropOnly: { attribute: false, type: Number }
51
50
  }
52
51
  }
52
+
53
53
  /**
54
- * Declare observable properties and their default values.
55
- * Any changed value of a property, using `.[name] = nextValue` assignment,
56
- * will cause a rerender.
57
- * In case of objects or arrays consider changing the reference with the
58
- * spread operator like `{...obj}` or `[...arr]` creating a new reference.
59
- * If name is already declared in `attributes` it will be ignored.
54
+ * optionally declare "non observable" or internal properties
60
55
  */
61
- static get properties () {
62
- return { prop: 0 }
63
- }
64
- constructor() {
65
- super()
66
- // optionally declare "non observable" and internal properties
67
- this.foo = 'foo'
68
- }
56
+ foo = 'foo'
69
57
  }
70
58
  ```
71
59
 
@@ -74,10 +62,10 @@ class extends MiElement {
74
62
  Invoked when a component is being added to the document's DOM.
75
63
 
76
64
  Micro components create `this.renderRoot` (typically same as `this.shadowRoot`
77
- for open components) using `this.attachShadow(shadowRootOptions)`. Shadow root
78
- options are taken from the components `static shadowRootOptions = { mode: 'open'
65
+ for open components) using `this.attachShadow(shadowRootInit)`. Shadow root
66
+ options are taken from the components `static shadowRootInit = { mode: 'open'
79
67
  }`. In advanced cases where no shadow root is desired, set `static
80
- shadowRootOptions = null`
68
+ shadowRootInit = null`
81
69
 
82
70
  The most common use case is adding event listeners to external nodes in
83
71
  `connectedCallback()`. Typically, anything done in `connectedCallback()` should
@@ -90,7 +78,7 @@ Then the first `render()` is issued with a `requestUpdate()`
90
78
  class extends MiElement {
91
79
  // { mode: 'open' } is the default shadow root option
92
80
  // use `null` for no shadow root or { mode: 'closed' } for closed mode
93
- static shadowRootOptions = { mode: 'open' }
81
+ static shadowRootInit = { mode: 'open' }
94
82
 
95
83
  connectedCallback() {
96
84
  super.connectedCallback() // don't forget to call the super method
@@ -160,24 +148,19 @@ flowchart TD
160
148
  disconnectedCallback("disconnectedCallback()")
161
149
  render("render()")
162
150
  requestUpdate("requestUpdate()")
163
- shouldUpdate("shouldUpdate(changedAttributes)")
164
151
  update("update(changedAttributes)")
165
152
 
166
- setAttribute("setAttribute(name, newVale)")
167
- setProperty(".[name] = newValue")
153
+ setAttribute("el.setAttribute(name, newVale)")
154
+ setProperty("el.[name] = newValue")
168
155
 
169
156
  START --> constructoR
170
157
  constructoR -.->|"mount to DOM"| connectedCallback
171
158
  connectedCallback --> render
172
159
  render --> requestUpdate
173
- requestUpdate -.->|async| shouldUpdate
174
- shouldUpdate -->|true| update
175
-
176
- setAttribute -->|"attributeChangedCallback"| requestUpdate
177
- setProperty --> requestUpdate
160
+ requestUpdate -.->|async| update
178
161
 
179
- update -.->|change| setAttribute
180
- update -.->|change| setProperty
162
+ setAttribute -->|"attributeChangedCallback()"| requestUpdate
163
+ setProperty -->requestUpdate
181
164
 
182
165
  connectedCallback -.->|"unmount from DOM"| disconnectedCallback
183
166
  disconnectedCallback --> END
@@ -189,8 +172,8 @@ A micro component usually implements `render()` and `update()`:
189
172
  import { define, MiElement, refsBySelector } from 'mi-element'
190
173
 
191
174
  class Counter extends MiElement {
192
- static get attributes() {
193
- return { value: 0 }
175
+ static get properties() {
176
+ return { value: { type: Number } }
194
177
  }
195
178
 
196
179
  // define the innerHTML template for the component
@@ -226,20 +209,19 @@ class Counter extends MiElement {
226
209
  ## render()
227
210
 
228
211
  Initial rendering of the component. Try to render the component only once!
229
- If you need re-rendering by recrating the DOM do this outside of `render()`
230
212
 
231
213
  Within the `render()` method, bear in mind to:
232
214
 
233
215
  - Avoid changing the component's state.
234
216
  - Avoid producing any side effects.
235
- - Use only the component's attributes as input.
217
+ - Use only the component's properties as input.
236
218
 
237
219
  !!! WARNING XSS - Cross-Site Scripting
238
220
 
239
221
  Using [`innerHTML`][innerHTML] to create the components DOM is susceptible to
240
222
  [XSS][XSS] attacks in case that user-supplied data contains valid HTML markup.
241
223
 
242
- In all other cases you may consider the <code>esc``</code> template literal or
224
+ In all other cases you may consider the <code>html``</code> template literal or
243
225
  `escHtml()` from the "mi-element" import, which escapes user-supplied data.
244
226
 
245
227
  [innerHTML]: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
@@ -287,19 +269,19 @@ adding `id` attributes to the nodes where updates shall happen or event
287
269
  listeners must be applied.
288
270
 
289
271
  ```js
290
- import { MiElement, define, refsById } from 'mi-element'
272
+ import { MiElement, define } from 'mi-element'
291
273
 
292
274
  class Counter extends MiElement {
293
275
  static template = `
294
276
  <button id>Count</button>
295
- <p>Counter value: <span id="count">0</span></p>
277
+ <p>Counter value: <span>0</span></p>
296
278
  `
297
279
 
298
280
  render() {
299
281
  // template is already rendered on `this.renderRoot`
300
282
 
301
- // get refs though `refsById` of `refsBySelector`
302
- this.refs = refsById(this.renderRoot)
283
+ // get refs though `refsBySelector`
284
+ this.refs = this.refsBySelector({ button: 'button', count: 'p > span'})
303
285
  // this.refs == {button: <button>, count: <span>}
304
286
  }
305
287
  }
@@ -315,6 +297,11 @@ rendered elements as much as possible.
315
297
 
316
298
  ```js
317
299
  class Counter extends MiElement {
300
+ render() {
301
+ // ...
302
+ this.update()
303
+ }
304
+
318
305
  // ...
319
306
  update() {
320
307
  this.refs.count.textContent = this.value
@@ -327,18 +314,18 @@ any changed attributes are passed.
327
314
 
328
315
  To mitigate [XSS][] attacks prefer the use of `.textContent` and avoid
329
316
  ~~`.innerHTML`~~. For attribute changes use `.setAttribute(name, newValue)`.
330
- Both `.textContent` and `setAttribute()` provide escaping for you.
331
-
332
317
 
333
318
  For finer control on updates the use of signals is encouraged. With this there
334
- is no need to add logic to `shouldUpdate()` or `update()`.
319
+ is no need to add logic to `update()`.
335
320
 
336
321
  ```js
337
322
  import { MiElement, Signal } from 'mi-element'
338
323
 
339
324
  class Counter extends MiElement {
340
- static get attributes() {
341
- return { value: 0 }
325
+ static get properties() {
326
+ return {
327
+ value: { type: Number }
328
+ }
342
329
  }
343
330
 
344
331
  static template = `
@@ -346,8 +333,15 @@ class Counter extends MiElement {
346
333
  <p>Counter value: <span>0</span></p>
347
334
  `
348
335
 
336
+ constructor() {
337
+ super()
338
+ // set initial values
339
+ this.value = 0
340
+ }
341
+
342
+
349
343
  render() {
350
- const refs = refsBySelector(this.renderRoot, {
344
+ const refs = this.refsBySelector({
351
345
  button: 'button',
352
346
  count: 'span'
353
347
  })
@@ -365,13 +359,6 @@ class Counter extends MiElement {
365
359
  }
366
360
  ```
367
361
 
368
- ## shouldUpdate(changedAttributes)
369
-
370
- Convenience method in order to be able to decide on the changed attributes,
371
- whether `update()` should be called or not.
372
-
373
- Return `true` if component should be updated.
374
-
375
362
  ## on(eventName, listener, \[node\])
376
363
 
377
364
  Adds listener function for eventName. listener is removed before component
@@ -16,9 +16,9 @@ import { html, render } from 'mi-html'
16
16
  define(
17
17
  'mi-counter',
18
18
  class extends MiElement {
19
- static get attributes() {
19
+ static get properties() {
20
20
  return {
21
- count: 1 //<< this.count is already a signal
21
+ count: { type: Number } //<< this.count is already a signal
22
22
  }
23
23
  }
24
24
 
package/docs/render.md ADDED
@@ -0,0 +1,357 @@
1
+ **Table of contents**
2
+
3
+ <!-- !toc (minlevel=2) -->
4
+
5
+ - [html Tagged Template Literal](#html-tagged-template-literal)
6
+ - [Basic Usage](#basic-usage)
7
+ - [Working with Arrays](#working-with-arrays)
8
+ - [Nested Templates](#nested-templates)
9
+ - [Unsafe HTML](#unsafe-html)
10
+ - [render() Function](#render-function)
11
+ - [Signature](#signature)
12
+ - [Basic Example](#basic-example)
13
+ - [Special Attributes](#special-attributes)
14
+ - [Boolean Attributes (`?attr`)](#boolean-attributes-attr)
15
+ - [Property Binding (`.prop`)](#property-binding-prop)
16
+ - [Event Listeners (`@event`)](#event-listeners-event)
17
+ - [Element References (`ref`)](#element-references-ref)
18
+ - [Spread Properties (`...`)](#spread-properties-)
19
+ - [Complete Example](#complete-example)
20
+ - [Security](#security)
21
+ - [Best Practices](#best-practices)
22
+ - [Custom Elements](#custom-elements)
23
+
24
+ <!-- toc! -->
25
+
26
+ # HTML Templating and Rendering
27
+
28
+ MiElement offers a lightweight templating system for properly escaping HTML to
29
+ prevent XSS attacks. The `html` tagged template literal combined with the
30
+ `render()` function provides a safe and convenient way to create dynamic HTML
31
+ with event handlers, property bindings, and element references.
32
+
33
+ ## html Tagged Template Literal
34
+
35
+ The `html` function is a tagged template literal that automatically escapes all
36
+ interpolated values to prevent XSS attacks.
37
+
38
+ ### Basic Usage
39
+
40
+ ```js
41
+ import { html } from '@mi-element/mi-element'
42
+
43
+ // Simple text escaping
44
+ const userInput = '<script>alert("xss")</script>'
45
+ const safe = html`<div>${userInput}</div>`
46
+ // Result: <div>&lt;script&gt;alert("xss")&lt;/script&gt;</div>
47
+ ```
48
+
49
+ ### Working with Arrays
50
+
51
+ Arrays are automatically joined and each item is escaped:
52
+
53
+ ```js
54
+ const items = ['Apple', 'Banana', 'Cherry']
55
+ const list = html`<ul>
56
+ ${items.map((item) => html`<li>${item}</li>`)}
57
+ </ul>`
58
+ ```
59
+
60
+ ### Nested Templates
61
+
62
+ HTML templates can be nested safely without double-escaping:
63
+
64
+ ```js
65
+ const header = html`<h1>${'<Title>'}</h1>`
66
+ const page = html`
67
+ <div>
68
+ ${header}
69
+ <p>${'<content>'}</p>
70
+ </div>
71
+ `
72
+ // The header content remains escaped, not double-escaped
73
+ ```
74
+
75
+ ### Unsafe HTML
76
+
77
+ When you need to render raw HTML (use with caution):
78
+
79
+ ```js
80
+ import { unsafeHtml } from '@mi-element/mi-element'
81
+
82
+ const trustedHtml = '<strong>Bold</strong>'
83
+ const template = html`<div>${unsafeHtml(trustedHtml)}</div>`
84
+ // Result: <div><strong>Bold</strong></div>
85
+ ```
86
+
87
+ ## render() Function
88
+
89
+ The `render()` function takes an HTML template and renders it into a DOM node,
90
+ with support for special attributes for event handling, property binding, and
91
+ element references.
92
+
93
+ ### Signature
94
+
95
+ ```js
96
+ render(node, template, (handlers = {}))
97
+ ```
98
+
99
+ - `node`: Target DOM element to render into
100
+ - `template`: HTML template string (typically from `html` tagged template)
101
+ - `handlers`: Optional object containing event handler functions or HTMLElement
102
+ for method lookup
103
+ - **Returns**: Object with collected element references
104
+
105
+ ### Basic Example
106
+
107
+ ```js
108
+ import { html, render } from '@mi-element/mi-element'
109
+
110
+ const container = document.querySelector('#app')
111
+ const template = html`
112
+ <div>
113
+ <h1>Hello World</h1>
114
+ <p>Welcome to MiElement</p>
115
+ </div>
116
+ `
117
+
118
+ render(container, template)
119
+ ```
120
+
121
+ ## Special Attributes
122
+
123
+ Special attributes provide powerful features for dynamic behavior. All special
124
+ attributes are removed from the DOM after processing.
125
+
126
+ ### Boolean Attributes (`?attr`)
127
+
128
+ Use the `?` prefix for boolean attributes:
129
+
130
+ ```js
131
+ const isDisabled = true
132
+ const template = html`
133
+ <input ?disabled=${isDisabled} />
134
+ <button ?hidden=${false}>Click</button>
135
+ `
136
+
137
+ render(container, template)
138
+ // Result: <input disabled=""> <button>Click</button>
139
+ ```
140
+
141
+ ### Property Binding (`.prop`)
142
+
143
+ Use the `.` prefix to set properties directly on DOM elements (not attributes):
144
+
145
+ ```js
146
+ const inputValue = 'Hello'
147
+ const userData = { name: 'John', age: 30 }
148
+
149
+ const template = html`
150
+ <input .value=${inputValue} />
151
+ <my-component .data=${userData}></my-component>
152
+ `
153
+
154
+ render(container, template)
155
+ // The input.value property is set, but not visible as an attribute
156
+ ```
157
+
158
+ **Note**: Use kebab-case for property names - they will be automatically
159
+ converted to camelCase:
160
+
161
+ ```js
162
+ html`<div .some-property=${'value'}></div>`
163
+ // Sets element.someProperty = 'value'
164
+ ```
165
+
166
+ ### Event Listeners (`@event`)
167
+
168
+ Use the `@` prefix for event listeners:
169
+
170
+ #### Inline Functions
171
+
172
+ ```js
173
+ const template = html`
174
+ <button @click=${(e) => console.log('Clicked!', e)}>Click Me</button>
175
+ `
176
+
177
+ render(container, template)
178
+ ```
179
+
180
+ #### Named Handlers
181
+
182
+ ```js
183
+ const handlers = {
184
+ handleClick(e) {
185
+ console.log('Button clicked:', e.target)
186
+ },
187
+ handleInput(e) {
188
+ console.log('Input value:', e.target.value)
189
+ }
190
+ }
191
+
192
+ const template = html`
193
+ <button @click="handleClick">Click</button>
194
+ <input @input="handleInput" />
195
+ `
196
+
197
+ render(container, template, handlers)
198
+ ```
199
+
200
+ #### Using HTMLElement Methods
201
+
202
+ ```js
203
+ class MyComponent extends HTMLElement {
204
+ handleClick(e) {
205
+ console.log('Clicked in component')
206
+ }
207
+
208
+ connectedCallback() {
209
+ const template = html` <button @click="handleClick">Click</button> `
210
+ render(this, template, this)
211
+ }
212
+ }
213
+ ```
214
+
215
+ ### Element References (`ref`)
216
+
217
+ Collect references to rendered elements:
218
+
219
+ ```js
220
+ const template = html`
221
+ <div>
222
+ <input ref="nameInput" type="text" />
223
+ <button ref="submitBtn">Submit</button>
224
+ </div>
225
+ `
226
+
227
+ const refs = render(container, template)
228
+ // refs.nameInput -> the input element
229
+ // refs.submitBtn -> the button element
230
+
231
+ refs.nameInput.focus()
232
+ refs.submitBtn.addEventListener('click', () => {
233
+ console.log(refs.nameInput.value)
234
+ })
235
+ ```
236
+
237
+ ### Spread Properties (`...`)
238
+
239
+ Spread multiple properties from an object:
240
+
241
+ ```js
242
+ const inputProps = {
243
+ value: 'Default text',
244
+ disabled: true,
245
+ placeholder: 'Enter text'
246
+ }
247
+
248
+ const template = html`<input ...=${inputProps} />`
249
+
250
+ render(container, template)
251
+ // Sets all properties: value, disabled, and placeholder
252
+ ```
253
+
254
+ ## Complete Example
255
+
256
+ ```js
257
+ import { html, render, MiElement, define } from '@mi-element/mi-element'
258
+ import { MiElement } from '@mi-element/mi-element'
259
+
260
+ class TodoList extends MiElement {
261
+ todos = [
262
+ { id: 1, text: 'Learn MiElement', done: false },
263
+ { id: 2, text: 'Build something', done: false }
264
+ ]
265
+
266
+ toggleTodo(id) {
267
+ const todo = this.todos.find((t) => t.id === id)
268
+ if (todo) todo.done = !todo.done
269
+ this.requestUpdate()
270
+ }
271
+
272
+ // first time render
273
+ render() {
274
+ const template = html`
275
+ <div>
276
+ <h2>My Todos</h2>
277
+ <ul ref="list"></ul>
278
+ </div>
279
+ `
280
+ this.refs = render(this.renderRoot, template)
281
+ }
282
+
283
+ // any updates
284
+ update() {
285
+ const template = this.todos.map(
286
+ (todo) => html`
287
+ <li>
288
+ <input
289
+ type="checkbox"
290
+ ?checked=${todo.done}
291
+ @change=${() => this.toggleTodo(todo.id)}
292
+ />
293
+ <span>${todo.text}</span>
294
+ </li>
295
+ `
296
+ )
297
+ // clear all children first
298
+ this.refs.list.innerHTML = ''
299
+ // then rerender
300
+ render(this.refs.list, template)
301
+ }
302
+ }
303
+
304
+ define('todo-list', TodoList)
305
+ ```
306
+
307
+ ## Security
308
+
309
+ The `html` tagged template automatically escapes all values to prevent XSS
310
+ attacks:
311
+
312
+ - Strings are HTML-escaped
313
+ - Objects and functions are stored in a temporary cache and referenced by key
314
+ - Only use `unsafeHtml()` when you have trusted HTML content
315
+
316
+ ```js
317
+ // Safe - user input is escaped
318
+ const userInput = '<script>alert("xss")</script>'
319
+ html`<div>${userInput}</div>`
320
+ // Result: <div>&lt;script&gt;alert("xss")&lt;/script&gt</div>;
321
+
322
+ // Unsafe - only use with trusted content
323
+ const trustedHtml = '<strong>Safe HTML</strong>'
324
+ html`<div>${unsafeHtml(trustedHtml)}</div>`
325
+ ```
326
+
327
+ ## Best Practices
328
+
329
+ 1. **Always use `html` for dynamic content** to ensure proper escaping
330
+ 2. **Use kebab-case** for all attribute and event names
331
+ 3. **Collect refs** instead of using `querySelector` when possible
332
+ 4. **Avoid `unsafeHtml`** unless absolutely necessary with trusted content
333
+ 5. **Use property binding** (`.prop`) for complex data structures
334
+ 6. **Leverage event delegation** for dynamic lists with many items
335
+ 7. **Keep handlers object** or use class methods for better organization
336
+
337
+ ## Custom Elements
338
+
339
+ The render system automatically skips processing children of custom elements,
340
+ allowing them to manage their own content:
341
+
342
+ ```js
343
+ class MyElement extends HTMLElement {
344
+ connectedCallback() {
345
+ // This element controls its own rendering
346
+ this.innerHTML = `<input ref="inside" />`
347
+ }
348
+ }
349
+
350
+ customElements.define('my-element', MyElement)
351
+
352
+ // The render function will process my-element's attributes
353
+ // but won't process its children
354
+ const template = html`
355
+ <my-element .data=${{ test: true }} ref="custom"></my-element>
356
+ `
357
+ ```
package/docs/signal.md CHANGED
@@ -24,7 +24,7 @@ For convenience there is a `createSignal(initialValue<T>): State<T>` function to
24
24
  create a signal.
25
25
 
26
26
  ```js
27
- import { createSignal, State } from 'mi-element'
27
+ import { createSignal, State } from 'mi-signal'
28
28
 
29
29
  const signal = createSignal(1)
30
30
  // same as
@@ -58,7 +58,7 @@ signals state as well as to update on any change through
58
58
  _synchronously_!
59
59
 
60
60
  ```js
61
- import { createSignal, effect } from 'mi-element'
61
+ import { createSignal, effect } from 'mi-signal'
62
62
 
63
63
  const signal = createSignal(1)
64
64
 
@@ -157,14 +157,15 @@ MiElement attributes are backed by signals. To subscribe to reactive changes a
157
157
  `Signal.effect` callback can be used on all observed attributes.
158
158
 
159
159
  ```js
160
- import { effect, define, MiElement, refByIds } from 'mi-element'
160
+ import { effect, define, MiElement } from 'mi-element'
161
+ import { createSignal } from 'mi-signal'
161
162
 
162
163
  define(
163
164
  'mi-counter',
164
165
  class extends MiElement {
165
166
  static template = `
166
- <button id> + </button>
167
- <div id></div>
167
+ <button> + </button>
168
+ <div></div>
168
169
  `
169
170
 
170
171
  static get attributes() {
@@ -174,8 +175,14 @@ define(
174
175
  }
175
176
  }
176
177
 
178
+ // define the signal to make all properties reactive
179
+ static createSignal = createSignal
180
+
177
181
  render() {
178
- this.refs = refsById(this.renderRoot)
182
+ // define initial value
183
+ this.count = this.count ?? 0
184
+
185
+ this.refs = this.refsBySelector({ button: 'button', div: 'div' })
179
186
  this.refs.button.addEventListener('click', () => {
180
187
  // change observed and reactive attribute...
181
188
  this.count++
package/docs/store.md CHANGED
@@ -62,4 +62,5 @@ const actions = {
62
62
  (by = 1) =>
63
63
  (state) => ({ ...state, count: state.count + by })
64
64
  }
65
+ const store = new Store(actions, initialValue)
65
66
  ```
package/docs/styling.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- !toc (minlevel=2) -->
4
4
 
5
- - [classMap](#classmap)
5
+ - [classNames](#classnames)
6
6
  - [styleMap](#stylemap)
7
7
  - [addGlobalStyles](#addglobalstyles)
8
8
 
@@ -10,16 +10,16 @@
10
10
 
11
11
  # Styling
12
12
 
13
- ## classMap
13
+ ## classNames
14
14
 
15
15
  Obtain a class string from an object. Only class-names with trueish values are
16
16
  returned.
17
17
 
18
18
  ```js
19
- import { classMap } from 'mi-element'
19
+ import { classNames } from 'mi-element'
20
20
 
21
- const className = classMap({ enabled: true, hidden: '', number: 1 })
22
- //> className == 'enabled number'
21
+ const className = classNames({ enabled: true, hidden: '', number: 1 }, 'always')
22
+ //> className == 'enabled number always'
23
23
  ```
24
24
 
25
25
  ## styleMap
@@ -74,4 +74,16 @@ customElements.define(
74
74
  }
75
75
  }
76
76
  )
77
+
78
+ // with MiElement
79
+ import { define, MiElement } from 'mi-element'
80
+
81
+ define('x-with-global-styles', class extends MiElement {
82
+ static useGlobalStyles() {
83
+ return true
84
+ }
85
+
86
+ static template = '<h1>Hello World</h1>'
87
+ })
88
+
77
89
  ```