Skip to content

Commit 14dbd46

Browse files
committed
refactor(components): streamline component exports and type definitions
This commit refactors multiple component files to export components directly using `export default` and updates type definitions to use the `Component` type. This improves consistency and reduces redundant code. Additionally, the `input-field` component has been enhanced with better number handling and validation logic.
1 parent 02c0eae commit 14dbd46

File tree

20 files changed

+176
-208
lines changed

20 files changed

+176
-208
lines changed

README.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@
22

33
Version 0.12.0
44

5-
**UIElement** - transform reusable markup, styles and behavior into powerful, reactive, and maintainable Web Components.
5+
**UIElement** - the HTML-first microframework bringing reactivity to Web Components.
66

7-
`UIElement` is a base class for Web Components with reactive states and UI effects. UIElement is tiny, around 4kB gzipped JS code, of which unused functions can be tree-shaken by build tools. It uses [Cause & Effect](https://github.com/zeixcom/cause-effect) internally for state management with signals and for scheduled DOM updates.
7+
UIElement is a set of functions to build reusable, loosely coupled Web Components with reactive properties. It provides structure through components and simplifies state management and DOM synchronization using declarative signals and effects, leading to more organized and maintainable code without a steep learning curve.
8+
9+
Unlike SPA frameworks (React, Vue, Svelte, etc.) UIElement takes a HTML-first approach, progressively enhancing sever-rendered HTML rather than recreating (rendering) it using JavaScript. UIElement achieves the same result as SPA frameworks with SSR, but with a simpler, more efficient approach. It works with a backend written in any language or with any static site generator.
810

911
## Key Features
1012

11-
* **Reusable Components**: Create highly modular and reusable components to encapsulate styles and behavior.
12-
* **Declarative States**: Bring static, server-rendered content to life with dynamic interactivity and state management.
13-
* **Signal-Based Reactivity**: Employ signals for efficient state propagation, ensuring your components react instantly to changes.
14-
* **Declarative Effects**: Use granular effects to automatically synchronize UI states with minimal code.
15-
* **Context Support**: Share global states across your component tree without tightly coupling logic.
13+
* 🧱 **HTML Web Components**: Build on standard HTML and enhance it with encapsulated, reusable Web Components. No virtual DOM – UIElement works directly with the real DOM.
14+
* 🚦 **Reactive Properties**: Define reactive properties for fine-grained, efficient state management (signals). Changes automatically propagate only to the parts of the DOM that need updating, avoiding unnecessary re-renders.
15+
* 🧩 **Function Composition**: Declare component behavior by composing small, reusable functions (attribute parsers and effects). This promotes cleaner code compared to spaghetti code problems that commonly occur when writing low-level imperative code.
16+
* 🛠️ **Customizable**: UIElement is designed to be easily customizable and extensible. You can create your own custom attribute parsers and effects to suit your specific needs.
17+
* 🌐 **Context Support**: Share global states across components without prop drilling or tightly coupling logic.
18+
* 🪶 **Tiny footprint**: Minimal core (~4kB gzipped) with tree-shaking support, adding only the necessary JavaScript to enhance your HTML.
19+
* 🛡️ **Type Safety**: Get early warnings when types don't match, improving code quality and reducing bugs.
20+
21+
UIElement uses [Cause & Effect](https://github.com/zeixcom/cause-effect) internally for state management with signals and for scheduled DOM updates. But you could easily rewrite the `component()` function to use a signals library of your choice or to produce something else than Web Components.
1622

1723
## Installation
1824

docs-src/components/accordion-panel/accordion-panel.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
<accordion-panel>
2-
<details open aria-disabled="true">
3-
<summary class="visually-hidden">
2+
<details open>
3+
<summary>
44
<div class="summary">Tab 1</div>
55
</summary>
66
Content for Tab 1
77
</details>
88
</accordion-panel>
99
<accordion-panel>
10-
<details aria-disabled="true">
11-
<summary class="visually-hidden">
10+
<details>
11+
<summary>
1212
<div class="summary">Tab 2</div>
1313
</summary>
1414
Content for Tab 2
1515
</details>
1616
</accordion-panel>
1717
<accordion-panel>
18-
<details aria-disabled="true">
19-
<summary class="visually-hidden">
18+
<details>
19+
<summary>
2020
<div class="summary">Tab 3</div>
2121
</summary>
2222
Content for Tab 3

docs-src/components/accordion-panel/accordion-panel.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { asBoolean, component, first, setProperty, toggleAttribute } from '../../../'
1+
import { type Component, asBoolean, component, first, setProperty, toggleAttribute } from '../../../'
22

33
export type AccordionPanelProps = {
44
open: boolean
55
collapsible: boolean
66
}
77

8-
const AccordionPanel = component('accordion-panel', {
8+
export default component('accordion-panel', {
99
open: asBoolean,
1010
collapsible: asBoolean
1111
}, el => [
@@ -20,8 +20,6 @@ const AccordionPanel = component('accordion-panel', {
2020

2121
declare global {
2222
interface HTMLElementTagNameMap {
23-
'accordion-panel': typeof AccordionPanel
23+
'accordion-panel': Component<AccordionPanelProps>
2424
}
2525
}
26-
27-
export default AccordionPanel

docs-src/components/code-block/code-block.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { asBoolean, component, first, on, toggleAttribute } from '../../../'
1+
import { type Component, asBoolean, component, first, on, toggleAttribute } from '../../../'
22

3-
import InputButton from '../input-button/input-button'
3+
import { InputButtonProps } from '../input-button/input-button'
44

55
export type CodeBlockProps = {
66
collapsed: boolean
77
}
88

9-
const CodeBlock = component('code-block',{
9+
export default component('code-block',{
1010
collapsed: asBoolean
1111
}, el => {
1212
const code = el.querySelector('code')
1313
return [
1414
toggleAttribute('collapsed'),
1515
first('.overlay', on('click', () => { el.collapsed = false })),
1616
first('.copy', on('click', async (e: Event) => {
17-
const copyButton = e.currentTarget as typeof InputButton
17+
const copyButton = e.currentTarget as Component<InputButtonProps>
1818
const label = copyButton.textContent?.trim() ?? ''
1919
let status = 'success'
2020
try {
@@ -36,8 +36,6 @@ const CodeBlock = component('code-block',{
3636

3737
declare global {
3838
interface HTMLElementTagNameMap {
39-
'code-block': typeof CodeBlock
39+
'code-block': Component<CodeBlockProps>
4040
}
41-
}
42-
43-
export default CodeBlock
41+
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { component, first, on, RESET, setText } from '../../../'
1+
import { type Component, component, first, on, RESET, setText } from '../../../'
22

33
export type HelloWorldProps = {
44
name: string
55
}
66

7-
const HelloWorld = component('hello-world', {
7+
export default component('hello-world', {
88
name: RESET
99
}, el => [
1010
first('span', setText('name')),
@@ -15,8 +15,6 @@ const HelloWorld = component('hello-world', {
1515

1616
declare global {
1717
interface HTMLElementTagNameMap {
18-
'hello-world': typeof HelloWorld
18+
'hello-world': Component<HelloWorldProps>
1919
}
2020
}
21-
22-
export default HelloWorld
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { asBoolean, asString, component, first, RESET, setProperty, setText } from '../../../'
1+
import { type Component, asBoolean, asString, component, first, RESET, setProperty, setText } from '../../../'
22

33
export type InputButtonProps = {
44
disabled: boolean
55
label: string
66
badge: string
77
}
88

9-
const InputButton = component('input-button', {
9+
export default component('input-button', {
1010
disabled: asBoolean,
1111
label: asString(RESET),
1212
badge: asString(RESET)
@@ -18,8 +18,6 @@ const InputButton = component('input-button', {
1818

1919
declare global {
2020
interface HTMLElementTagNameMap {
21-
'input-button': typeof InputButton
21+
'input-button': Component<InputButtonProps>
2222
}
2323
}
24-
25-
export default InputButton

docs-src/components/input-checkbox/input-checkbox.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { asBoolean, asString, component, first, on, RESET, setProperty, setText, toggleAttribute } from '../../../'
1+
import { type Component, asBoolean, asString, component, first, on, RESET, setProperty, setText, toggleAttribute } from '../../../'
22

33
export type InputCheckboxProps = {
44
checked: boolean,
55
label: string
66
}
77

8-
const InputCheckbox = component('input-checkbox', {
8+
export default component('input-checkbox', {
99
checked: asBoolean,
1010
label: asString(RESET)
1111
}, el => [
@@ -21,8 +21,6 @@ const InputCheckbox = component('input-checkbox', {
2121

2222
declare global {
2323
interface HTMLElementTagNameMap {
24-
'input-checkbox': typeof InputCheckbox
24+
'input-checkbox': Component<InputCheckboxProps>
2525
}
2626
}
27-
28-
export default InputCheckbox

0 commit comments

Comments
 (0)