Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Commit f8854e6

Browse files
Merge pull request #29 from efflore/v0.8.5-docs
docs: todo-app and lazy-load examples
2 parents f7dc300 + e7b04d0 commit f8854e6

25 files changed

+554
-362
lines changed

docs/assets/css/components.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ input-button {
275275
padding: 0 var(--space-s);
276276
font-size: var(--font-size-s);
277277
line-height: var(--line-height-s);
278+
white-space: nowrap;
278279
opacity: var(--opacity-dimmed);
279280
transition: all var(--transition-shorter) var(--easing-inout);
280281

docs/assets/css/global.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
--easing-in: ease-in;
7676
--easing-out: ease-out;
7777
--easing-inout: ease-in-out;
78+
79+
--input-height: 2rem;
7880
}
7981

8082
@media screen and (min-width: 45em) and (max-width: 75em) {

docs/assets/js/main.js

Lines changed: 79 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ InputRadiogroup.define('input-radiogroup')
389389
class LazyLoad extends UIElement {
390390
static observedAttributes = ['src']
391391
static attributeMap = {
392-
src: v => v.map(src => {
392+
src: v => v.map(src => {
393393
let url = ''
394394
try {
395395
url = new URL(src, location.href) // ensure 'src' attribute is a valid URL
@@ -402,20 +402,20 @@ class LazyLoad extends UIElement {
402402
}
403403
return url.toString()
404404
})
405-
}
405+
}
406406

407407
connectedCallback() {
408408

409-
// show / hide loading message
409+
// Show / hide loading message
410410
this.first('.loading')
411411
.forEach(setProperty('ariaHidden', () => !!this.get('error')))
412412

413-
// set and show / hide error message
413+
// Set and show / hide error message
414414
this.first('.error')
415415
.map(setText('error'))
416416
.forEach(setProperty('ariaHidden', () => !this.get('error')))
417417

418-
// load content from provided URL
418+
// Load content from provided URL
419419
effect(enqueue => {
420420
const src = this.get('src')
421421
if (!src) return // silently fail if no valid URL is provided
@@ -434,7 +434,7 @@ class LazyLoad extends UIElement {
434434
})
435435
})
436436
this.set('error', '')
437-
} else {
437+
} else {
438438
this.set('error', response.status + ':'+ response.statusText)
439439
}
440440
})
@@ -525,118 +525,112 @@ class MediaContext extends UIElement {
525525
MediaContext.define('media-context')
526526

527527
class TodoApp extends UIElement {
528-
connectedCallback() {
528+
connectedCallback() {
529529
const [todoList, todoFilter] = ['todo-list', 'input-radiogroup']
530530
.map(selector => this.querySelector(selector))
531531

532532
// Event listener on own element
533-
this.self
534-
.map(on('add-todo', e => todoList?.addItem(e.detail)))
535-
536-
// Coordinate todo-count
537-
this.first('todo-count')
538-
.map(pass({ active: () => todoList?.get('count').active }))
539-
540-
// Coordinate todo-list
541-
this.first('todo-list')
542-
.map(pass({ filter: () => todoFilter?.get('value') }))
543-
544-
// Coordinate .clear-completed button
545-
this.first('.clear-completed')
546-
.map(on('click', () => todoList?.clearCompleted()))
547-
.map(pass({ disabled: () => !todoList?.get('count').completed }))
548-
}
533+
this.self.forEach(on('add-todo', e => todoList?.addItem(e.detail)))
534+
535+
// Coordinate todo-count
536+
this.first('todo-count').forEach(pass({
537+
active: () => todoList?.get('count').active
538+
}))
539+
540+
// Coordinate todo-list
541+
this.first('todo-list').forEach(pass({
542+
filter: () => todoFilter?.get('value')
543+
}))
544+
545+
// Coordinate .clear-completed button
546+
this.first('.clear-completed')
547+
.map(on('click', () => todoList?.clearCompleted()))
548+
.forEach(pass({ disabled: () => !todoList?.get('count').completed }))
549+
}
549550
}
550551
TodoApp.define('todo-app')
551552

552553
class TodoCount extends UIElement {
553554
connectedCallback() {
554-
this.set('active', 0, false)
555-
this.first('.count')
556-
.map(setText('active'))
557-
this.first('.singular')
558-
.map(setProperty('ariaHidden', () => this.get('active') > 1))
559-
this.first('.plural')
560-
.map(setProperty('ariaHidden', () => this.get('active') === 1))
561-
this.first('.remaining')
562-
.map(setProperty('ariaHidden', () => !this.get('active')))
563-
this.first('.all-done')
564-
.map(setProperty('ariaHidden', () => !!this.get('active')))
565-
}
555+
this.set('active', 0, false)
556+
this.first('.count').forEach(setText('active'))
557+
this.first('.singular').forEach(setProperty('ariaHidden', () => this.get('active') > 1))
558+
this.first('.plural').forEach(setProperty('ariaHidden', () => this.get('active') === 1))
559+
this.first('.remaining').forEach(setProperty('ariaHidden', () => !this.get('active')))
560+
this.first('.all-done').forEach(setProperty('ariaHidden', () => !!this.get('active')))
561+
}
566562
}
567563
TodoCount.define('todo-count')
568564

569565
class TodoForm extends UIElement {
570566
connectedCallback() {
571567
const inputField = this.querySelector('input-field')
572568

573-
this.first('form')
574-
.forEach(on('submit', e => {
575-
e.preventDefault()
576-
setTimeout(() => {
577-
this.dispatchEvent(new CustomEvent('add-todo', {
578-
bubbles: true,
579-
detail: inputField.get('value')
580-
}))
581-
inputField.clear()
582-
}, 0)
583-
}))
584-
585-
this.first('input-button')
586-
.forEach(pass({
587-
disabled: () => inputField.get('empty')
588-
}))
569+
this.first('form').forEach(on('submit', e => {
570+
e.preventDefault()
571+
setTimeout(() => {
572+
this.dispatchEvent(new CustomEvent('add-todo', {
573+
bubbles: true,
574+
detail: inputField.get('value')
575+
}))
576+
inputField.clear()
577+
}, 0)
578+
}))
579+
580+
this.first('input-button').forEach(pass({
581+
disabled: () => inputField.get('empty')
582+
}))
589583
}
590584
}
591585
TodoForm.define('todo-form')
592586

593587
class TodoList extends UIElement {
594-
connectedCallback() {
595-
this.set('filter', 'all') // set initial filter
588+
connectedCallback() {
589+
this.set('filter', 'all') // set initial filter
596590
this.#updateList()
597591

598592
// Event listener and attribute on own element
599-
this.self
600-
.map(on('click', e => {
601-
if (e.target.localName === 'button') this.removeItem(e.target)
602-
}))
603-
.map(setAttribute('filter'))
604-
605-
// Update count on each change
606-
this.set('count', () => {
607-
const tasks = this.get('tasks').map(el => el.signal('checked'))
608-
const completed = tasks.filter(fn => fn()).length
609-
const total = tasks.length
610-
return {
593+
this.self
594+
.map(on('click', e => {
595+
if (e.target.localName === 'button') this.removeItem(e.target)
596+
}))
597+
.forEach(setAttribute('filter'))
598+
599+
// Update count on each change
600+
this.set('count', () => {
601+
const tasks = this.get('tasks').map(el => el.signal('checked'))
602+
const completed = tasks.filter(fn => fn()).length
603+
const total = tasks.length
604+
return {
611605
active: total - completed,
612606
completed,
613607
total
614608
}
615-
})
616-
}
609+
})
610+
}
617611

618-
addItem = task => {
619-
const template = this.querySelector('template').content.cloneNode(true)
620-
template.querySelector('span').textContent = task
621-
this.querySelector('ol').appendChild(template)
622-
this.#updateList()
623-
}
612+
addItem = task => {
613+
const template = this.querySelector('template').content.cloneNode(true)
614+
template.querySelector('span').textContent = task
615+
this.querySelector('ol').appendChild(template)
616+
this.#updateList()
617+
}
624618

625-
removeItem = element => {
626-
element.closest('li').remove()
627-
this.#updateList()
628-
}
619+
removeItem = element => {
620+
element.closest('li').remove()
621+
this.#updateList()
622+
}
629623

630-
clearCompleted = () => {
631-
this.get('tasks')
632-
.filter(el => el.get('checked'))
633-
.forEach(el => el.parentElement.remove())
634-
this.#updateList()
635-
}
624+
clearCompleted = () => {
625+
this.get('tasks')
626+
.filter(el => el.get('checked'))
627+
.forEach(el => el.parentElement.remove())
628+
this.#updateList()
629+
}
636630

637631
#updateList() {
638-
this.set('tasks', Array.from(this.querySelectorAll('input-checkbox')))
639-
}
632+
this.set('tasks', Array.from(this.querySelectorAll('input-checkbox')))
633+
}
640634

641635
}
642636
TodoList.define('todo-list')

docs/best-practices-patterns.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ <h3>Scope Styles via Custom Element Name</h3>
125125
<p class="meta">
126126
<span class="language">css</span>
127127
</p>
128-
<pre><code class="language-css">my-component {
128+
<pre class="language-css"><code>my-component {
129129
padding: 1rem;
130130

131131
/* Only divs that are immediate children of my-component will be styled */
@@ -146,7 +146,7 @@ <h3>Customize via Class or CSS Custom Properties</h3>
146146
<p class="meta">
147147
<span class="language">css</span>
148148
</p>
149-
<pre><code class="language-css">parent-component {
149+
<pre class="language-css"><code>parent-component {
150150
--box-bg-color: red;
151151
--box-text-color: white;
152152
}
@@ -178,7 +178,7 @@ <h3>Passing State with pass()</h3>
178178
<p class="meta">
179179
<span class="language">js</span>
180180
</p>
181-
<pre><code class="language-js">class ParentComponent extends UIElement {
181+
<pre class="language-js"><code>class ParentComponent extends UIElement {
182182
connectedCallback() {
183183
this.set('parentColor', 'blue');
184184
this.pass('parentColor', 'child-component', 'color');
@@ -194,7 +194,7 @@ <h3>Passing State with pass()</h3>
194194
<p class="meta">
195195
<span class="language">js</span>
196196
</p>
197-
<pre><code class="language-js">class ChildComponent extends UIElement {
197+
<pre class="language-js"><code>class ChildComponent extends UIElement {
198198
connectedCallback() {
199199
this.first('.box').map(setStyle('background-color', 'color'));
200200
}
@@ -213,7 +213,7 @@ <h3>Dispatching Custom Events with <code>emit()</code></h3>
213213
<p class="meta">
214214
<span class="language">js</span>
215215
</p>
216-
<pre><code class="language-js">// In child component
216+
<pre class="language-js"><code>// In child component
217217
this.emit('change', { detail: { value: this.get('value') } });</code></pre>
218218
</code-block>
219219

@@ -223,7 +223,7 @@ <h3>Handling Custom Events in Parent Components</h3>
223223
<p class="meta">
224224
<span class="language">js</span>
225225
</p>
226-
<pre><code class="language-js">// In parent component
226+
<pre class="language-js"><code>// In parent component
227227
this.first('child-component').map(on('change', (event) => {
228228
console.log('Received change event:', event.detail.value);
229229
// Handle state changes

docs/contributing-development.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,16 @@ <h2>3. Setting Up the Development Environment</h2>
135135
<ol>
136136
<li>
137137
<strong>Clone the Repository</strong>: Clone the UIElement repository from GitHub:
138-
<pre><code class="language-bash">git clone https://github.com/efflore/ui-element.git</code></pre>
138+
<pre class="language-bash"><code>git clone https://github.com/efflore/ui-element.git</code></pre>
139139
</li>
140140
<li>
141141
<strong>Install Dependencies</strong>: Navigate to the project directory and install the necessary dependencies using npm:
142-
<pre><code class="language-bash">cd ui-element
142+
<pre class="language-bash"><code>cd ui-element
143143
npm install</code></pre>
144144
</li>
145145
<li>
146146
<strong>Run the Development Server</strong>: Start the development server to work on the code and see live updates:
147-
<pre><code class="language-bash">npm start</code></pre>
147+
<pre class="language-bash"><code>npm start</code></pre>
148148
This will run the build process and serve the project locally.
149149
</li>
150150
</ol>
@@ -155,15 +155,15 @@ <h2>4. Testing and Building</h2>
155155
<ul>
156156
<li>
157157
<strong>Linting</strong>: Run linting to maintain code quality and formatting:
158-
<pre><code class="language-bash">npm run lint</code></pre>
158+
<pre class="language-bash"><code>npm run lint</code></pre>
159159
</li>
160160
<li>
161161
<strong>Unit Testing</strong>: Execute the test suite to ensure everything works correctly:
162-
<pre><code class="language-bash">npm test</code></pre>
162+
<pre class="language-bash"><code>npm test</code></pre>
163163
</li>
164164
<li>
165165
<strong>Building for Production</strong>: When you're ready to build the project for production, run:
166-
<pre><code class="language-bash">npm run build</code></pre>
166+
<pre class="language-bash"><code>npm run build</code></pre>
167167
The production build will be created in the `dist` directory.
168168
</li>
169169
</ul>
@@ -173,7 +173,7 @@ <h2>4. Testing and Building</h2>
173173
<h2>5. Commit Message Guidelines</h2>
174174
<p>
175175
Use conventional commit messages for consistency and clarity. Examples include:
176-
<pre><code class="language-bash">
176+
<pre class="language-bash"><code>
177177
feat: add new feature to the component
178178
fix: resolve issue with context updates
179179
docs: update documentation for new API

0 commit comments

Comments
 (0)