|
7 | 7 |
|
8 | 8 | ## Quick Reference |
9 | 9 |
|
10 | | -### All Components (50) |
| 10 | +### All Components (57) |
11 | 11 |
|
12 | 12 | | Category | Components | Common Attributes | |
13 | 13 | |----------|------------|-------------------| |
14 | 14 | | **Layout** | `au-container`, `au-stack`, `au-grid`, `au-navbar`, `au-sidebar`, `au-divider` | `gap="xs\|sm\|md\|lg"`, `direction="row\|column"` | |
15 | 15 | | **Form** | `au-button`, `au-input`, `au-textarea`, `au-checkbox`, `au-switch`, `au-radio`, `au-radio-group`, `au-dropdown`, `au-option`, `au-chip`, `au-form` | `variant`, `disabled`, `required`, `value` | |
16 | | -| **Display** | `au-card`, `au-tabs`, `au-tab`, `au-table`, `au-avatar`, `au-badge`, `au-progress`, `au-skeleton`, `au-alert`, `au-icon` | `variant="elevated\|outlined\|filled"` | |
| 16 | +| **Display** | `au-card`, `au-tabs`, `au-tab`, `au-table`, `au-avatar`, `au-badge`, `au-callout`, `au-progress`, `au-skeleton`, `au-alert`, `au-icon` | `variant="elevated\|outlined\|filled"` | |
17 | 17 | | **Feedback** | `au-modal`, `au-toast`, `au-toast-container`, `au-tooltip`, `au-spinner`, `au-confirm` | `duration`, `position` | |
18 | | -| **Performance** | `au-virtual-list`, `au-lazy`, `au-repeat` | `items`, `renderItem` | |
| 18 | +| **Structural** | `au-if`, `au-show`, `au-repeat`, `au-portal`, `au-intersection`, `au-media`, `au-transition`, `au-timer` | `condition`, `threshold`, `active` | |
| 19 | +| **Performance** | `au-virtual-list`, `au-lazy` | `items`, `renderItem` | |
19 | 20 | | **Data** | `au-fetch` | `url`, `auto`, `interval` | |
20 | 21 | | **Enterprise** | `au-error-boundary` | `fallback` | |
21 | 22 | | **Utility** | `au-theme-toggle` | - | |
@@ -1744,7 +1745,7 @@ npx serve app-dist |
1744 | 1745 | ``` |
1745 | 1746 | AgentUI/ |
1746 | 1747 | ├── src/ # Framework source |
1747 | | -│ └── components/ # 51 components |
| 1748 | +│ └── components/ # 57 components |
1748 | 1749 | │ |
1749 | 1750 | ├── dist/ # Framework build |
1750 | 1751 | │ ├── agentui.esm.js # Full bundle |
@@ -1986,6 +1987,177 @@ list.addEventListener('click', (e) => { |
1986 | 1987 | </script> |
1987 | 1988 | ``` |
1988 | 1989 |
|
| 1990 | +### au-show (Show/Hide with State Preservation) |
| 1991 | +```html |
| 1992 | +<au-show id="panel" condition> |
| 1993 | + <form> |
| 1994 | + <!-- Form values, scroll position, timers all survive toggle --> |
| 1995 | + <au-input label="Name" value="Alice"></au-input> |
| 1996 | + </form> |
| 1997 | +</au-show> |
| 1998 | + |
| 1999 | +<script type="module"> |
| 2000 | +const panel = document.getElementById('panel'); |
| 2001 | +panel.condition = false; // hidden via display:none, stays in DOM |
| 2002 | +panel.condition = true; // visible again, all state intact |
| 2003 | + |
| 2004 | +panel.addEventListener('au-show', () => console.log('Visible')); |
| 2005 | +panel.addEventListener('au-hide', () => console.log('Hidden')); |
| 2006 | +</script> |
| 2007 | +``` |
| 2008 | +
|
| 2009 | +**Key points:** |
| 2010 | +- Children hidden with `display: none` — **not removed** from DOM |
| 2011 | +- Internal state (form values, event listeners, timers) **preserved** |
| 2012 | +- Use `au-if` when you want true DOM removal; `au-show` when toggling frequently |
| 2013 | +- `display: contents` — zero layout impact |
| 2014 | +
|
| 2015 | +### au-portal (DOM Teleportation) |
| 2016 | +```html |
| 2017 | +<!-- Source: portal lives here but children render elsewhere --> |
| 2018 | +<div style="overflow: hidden;"> |
| 2019 | + <au-portal target="#modal-container"> |
| 2020 | + <au-modal open title="Escaped!"> |
| 2021 | + <p>This modal is not clipped by overflow:hidden</p> |
| 2022 | + </au-modal> |
| 2023 | + </au-portal> |
| 2024 | +</div> |
| 2025 | + |
| 2026 | +<!-- Target: teleported content appears here --> |
| 2027 | +<div id="modal-container"></div> |
| 2028 | + |
| 2029 | +<script type="module"> |
| 2030 | +const portal = document.querySelector('au-portal'); |
| 2031 | +portal.addEventListener('au-teleport', () => console.log('Moved')); |
| 2032 | +portal.addEventListener('au-return', () => console.log('Returned')); |
| 2033 | +// Children auto-return on disconnect (cleanup) |
| 2034 | +</script> |
| 2035 | +``` |
| 2036 | +
|
| 2037 | +**Key points:** |
| 2038 | +- Children are **moved** (not cloned) — DOM identity preserved |
| 2039 | +- Solves `overflow: hidden` and z-index stacking context issues |
| 2040 | +- Auto-cleanup: children return to source on disconnect |
| 2041 | +- `target` defaults to `document.body` when absent |
| 2042 | +
|
| 2043 | +### au-intersection (Viewport Observer) |
| 2044 | +```html |
| 2045 | +<!-- Lazy-load pattern --> |
| 2046 | +<au-intersection once threshold="0.1"> |
| 2047 | + <img data-src="hero.webp" alt="Hero" /> |
| 2048 | +</au-intersection> |
| 2049 | + |
| 2050 | +<script type="module"> |
| 2051 | +document.querySelectorAll('au-intersection').forEach(el => { |
| 2052 | + el.addEventListener('au-visible', (e) => { |
| 2053 | + console.log('Ratio:', e.detail.ratio); |
| 2054 | + const img = el.querySelector('img[data-src]'); |
| 2055 | + if (img) { img.src = img.dataset.src; } |
| 2056 | + }); |
| 2057 | + el.addEventListener('au-hidden', () => { |
| 2058 | + console.log('Left viewport'); |
| 2059 | + }); |
| 2060 | +}); |
| 2061 | +</script> |
| 2062 | +``` |
| 2063 | +
|
| 2064 | +**Key points:** |
| 2065 | +- Declarative `IntersectionObserver` — no manual setup/cleanup |
| 2066 | +- `once` mode disconnects after first intersection (lazy-load) |
| 2067 | +- `threshold` (0–1) controls visibility ratio trigger |
| 2068 | +- `root-margin` extends the viewport bounds (e.g. `"200px"` for preloading) |
| 2069 | +- Read `el.isVisible` for current state |
| 2070 | +
|
| 2071 | +### au-media (Responsive Rendering) |
| 2072 | +```html |
| 2073 | +<!-- Desktop-only sidebar --> |
| 2074 | +<au-media query="(min-width: 768px)"> |
| 2075 | + <aside class="sidebar"><nav>...</nav></aside> |
| 2076 | +</au-media> |
| 2077 | + |
| 2078 | +<!-- Mobile-only bottom nav --> |
| 2079 | +<au-media query="(max-width: 767px)"> |
| 2080 | + <au-bottom-nav> |
| 2081 | + <au-nav-item icon="home">Home</au-nav-item> |
| 2082 | + </au-bottom-nav> |
| 2083 | +</au-media> |
| 2084 | + |
| 2085 | +<script type="module"> |
| 2086 | +const media = document.querySelector('au-media'); |
| 2087 | +console.log(media.matches); // true/false |
| 2088 | +media.addEventListener('au-match', () => console.log('Query matches')); |
| 2089 | +media.addEventListener('au-unmatch', () => console.log('Query no longer matches')); |
| 2090 | +</script> |
| 2091 | +``` |
| 2092 | +
|
| 2093 | +**Key points:** |
| 2094 | +- Children **truly removed** from DOM when query doesn't match (like `au-if`) |
| 2095 | +- Same DOM nodes restored on match (identity preserved) |
| 2096 | +- More efficient than CSS `display: none` for heavy components |
| 2097 | +- Read `el.matches` for current state |
| 2098 | +
|
| 2099 | +### au-transition (Enter/Leave Animations) |
| 2100 | +```html |
| 2101 | +<style> |
| 2102 | + .fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; } |
| 2103 | + .fade-enter-from, .fade-leave-active { opacity: 0; } |
| 2104 | +</style> |
| 2105 | + |
| 2106 | +<au-transition name="fade" active> |
| 2107 | + <div>I animate in and out!</div> |
| 2108 | +</au-transition> |
| 2109 | + |
| 2110 | +<script type="module"> |
| 2111 | +const transition = document.querySelector('au-transition'); |
| 2112 | +transition.active = true; // applies fade-enter-from → fade-enter-active |
| 2113 | +transition.active = false; // applies fade-leave-from → fade-leave-active |
| 2114 | + |
| 2115 | +transition.addEventListener('au-enter', () => console.log('Enter started')); |
| 2116 | +transition.addEventListener('au-leave', () => console.log('Leave started')); |
| 2117 | +</script> |
| 2118 | +``` |
| 2119 | +
|
| 2120 | +**Key points:** |
| 2121 | +- Vue-inspired class naming: `{name}-enter-from`, `{name}-enter-active`, `{name}-leave-from`, `{name}-leave-active` |
| 2122 | +- Does **not** define visual CSS — you provide the transition styles |
| 2123 | +- `name` attribute sets the class prefix (default: `au`) |
| 2124 | +- `display: contents` — zero layout impact |
| 2125 | +
|
| 2126 | +### au-timer (Declarative Timer) |
| 2127 | +```html |
| 2128 | +<!-- Count-up timer --> |
| 2129 | +<au-timer id="stopwatch" interval="1000" autostart></au-timer> |
| 2130 | + |
| 2131 | +<!-- Countdown timer (30 seconds) --> |
| 2132 | +<au-timer id="countdown" interval="1000" countdown="30"></au-timer> |
| 2133 | + |
| 2134 | +<script type="module"> |
| 2135 | +const timer = document.getElementById('stopwatch'); |
| 2136 | +timer.addEventListener('au-tick', (e) => { |
| 2137 | + display.textContent = e.detail.count; // 1, 2, 3... |
| 2138 | +}); |
| 2139 | +timer.start(); |
| 2140 | +timer.stop(); |
| 2141 | +timer.reset(); |
| 2142 | + |
| 2143 | +const countdown = document.getElementById('countdown'); |
| 2144 | +countdown.addEventListener('au-tick', (e) => { |
| 2145 | + display.textContent = e.detail.count; // 30, 29, 28... |
| 2146 | +}); |
| 2147 | +countdown.addEventListener('au-complete', () => { |
| 2148 | + showToast('Time is up!', { severity: 'warning' }); |
| 2149 | +}); |
| 2150 | +countdown.start(); |
| 2151 | +</script> |
| 2152 | +``` |
| 2153 | +
|
| 2154 | +**Key points:** |
| 2155 | +- Automatic `clearInterval` on disconnect — no memory leaks |
| 2156 | +- `countdown` attribute enables count-down mode (fires `au-complete` at 0) |
| 2157 | +- `autostart` starts timer on connect |
| 2158 | +- Interval clamped to ≥100ms for safety |
| 2159 | +- Read `el.count` and `el.running` for current state |
| 2160 | +
|
1989 | 2161 | ### au-table (Data Tables with Sorting) |
1990 | 2162 | ```html |
1991 | 2163 | <au-table id="data-table"></au-table> |
@@ -2153,7 +2325,7 @@ export async function render(container) { |
2153 | 2325 |
|
2154 | 2326 | ## 📦 Component Quick Reference |
2155 | 2327 |
|
2156 | | -> **All 51 AgentUI components at a glance.** Key attributes and copy-paste examples. |
| 2328 | +> **All 57 AgentUI components at a glance.** Key attributes and copy-paste examples. |
2157 | 2329 |
|
2158 | 2330 | ### Buttons & Actions |
2159 | 2331 |
|
@@ -2238,6 +2410,12 @@ export async function render(container) { |
2238 | 2410 | | `au-fetch` | `url`, `method` | `<au-fetch url="/api/data"></au-fetch>` | |
2239 | 2411 | | `au-repeat` | `items`, `template` | `<au-repeat items="...">...</au-repeat>` | |
2240 | 2412 | | `au-if` | `condition`, `else` | `<au-if condition>Visible</au-if>` | |
| 2413 | +| `au-show` | `condition` | `<au-show condition>Hidden with display:none</au-show>` | |
| 2414 | +| `au-portal` | `target` | `<au-portal target="#container">Teleported</au-portal>` | |
| 2415 | +| `au-intersection` | `threshold`, `root-margin`, `once` | `<au-intersection once>Lazy load</au-intersection>` | |
| 2416 | +| `au-media` | `query` | `<au-media query="(min-width: 768px)">Desktop only</au-media>` | |
| 2417 | +| `au-transition` | `name`, `active` | `<au-transition name="fade" active>Animated</au-transition>` | |
| 2418 | +| `au-timer` | `interval`, `countdown`, `autostart` | `<au-timer interval="1000" autostart></au-timer>` | |
2241 | 2419 | | `au-virtual-list` | `items`, `item-height` | `<au-virtual-list items="..." item-height="50"></au-virtual-list>` | |
2242 | 2420 | | `au-error-boundary` | `fallback` | `<au-error-boundary fallback="Error">...</au-error-boundary>` | |
2243 | 2421 |
|
@@ -2277,4 +2455,4 @@ export async function render(container) { |
2277 | 2455 |
|
2278 | 2456 | --- |
2279 | 2457 |
|
2280 | | -*Last updated: v0.1.117 - 2026-02-11* |
| 2458 | +*Last updated: v0.1.150 - 2026-02-17* |
0 commit comments