@adia-ai/web-components 0.8.6 → 0.8.8

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 (108) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +3 -3
  3. package/dist/host.min.css +1 -1
  4. package/dist/host.sheet.js +1 -1
  5. package/dist/theme-provider.min.js +2 -2
  6. package/dist/web-components.min.css +1 -1
  7. package/dist/web-components.min.js +1 -1
  8. package/dist/web-components.sheet.js +1 -1
  9. package/package.json +2 -1
  10. package/patterns/access-requests/access-requests.examples.html +132 -0
  11. package/patterns/access-requests/access-requests.html +60 -0
  12. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +236 -0
  13. package/patterns/admin-keys-and-export/admin-keys-and-export.html +64 -0
  14. package/patterns/admin-shell/admin-shell.examples.html +327 -0
  15. package/patterns/admin-shell/admin-shell.html +44 -0
  16. package/patterns/agent-cost/agent-cost.examples.html +111 -0
  17. package/patterns/agent-cost/agent-cost.html +62 -0
  18. package/patterns/agent-memory/agent-memory.examples.html +155 -0
  19. package/patterns/agent-memory/agent-memory.html +64 -0
  20. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +181 -0
  21. package/patterns/agent-prompt-library/agent-prompt-library.html +64 -0
  22. package/patterns/agent-tool-call/agent-tool-call.examples.html +123 -0
  23. package/patterns/agent-tool-call/agent-tool-call.html +60 -0
  24. package/patterns/alert-dialog/alert-dialog.examples.html +105 -0
  25. package/patterns/alert-dialog/alert-dialog.html +57 -0
  26. package/patterns/app-nav/app-nav.examples.html +421 -0
  27. package/patterns/app-nav/app-nav.html +50 -0
  28. package/patterns/approvals/approvals.examples.html +131 -0
  29. package/patterns/approvals/approvals.html +58 -0
  30. package/patterns/audit-log/audit-log.examples.html +74 -0
  31. package/patterns/audit-log/audit-log.examples.js +60 -0
  32. package/patterns/audit-log/audit-log.html +63 -0
  33. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +89 -0
  34. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +69 -0
  35. package/patterns/bulk-action-toolbar/bulk-action-toolbar.html +62 -0
  36. package/patterns/changelog-feed/changelog-feed.examples.html +151 -0
  37. package/patterns/changelog-feed/changelog-feed.html +57 -0
  38. package/patterns/chart-in-card/chart-in-card.examples.html +193 -0
  39. package/patterns/chart-in-card/chart-in-card.examples.js +46 -0
  40. package/patterns/chart-in-card/chart-in-card.html +66 -0
  41. package/patterns/chat-shell/chat-shell.examples.html +129 -0
  42. package/patterns/chat-shell/chat-shell.html +46 -0
  43. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +241 -0
  44. package/patterns/comments-and-collaboration/comments-and-collaboration.html +66 -0
  45. package/patterns/component-tokens/component-tokens.examples.html +483 -0
  46. package/patterns/component-tokens/component-tokens.html +42 -0
  47. package/patterns/conversion-funnel/conversion-funnel.examples.html +158 -0
  48. package/patterns/conversion-funnel/conversion-funnel.examples.js +4 -0
  49. package/patterns/conversion-funnel/conversion-funnel.html +64 -0
  50. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +196 -0
  51. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.html +58 -0
  52. package/patterns/diff-review/diff-review.examples.html +147 -0
  53. package/patterns/diff-review/diff-review.html +56 -0
  54. package/patterns/editor-shell/editor-shell.examples.html +139 -0
  55. package/patterns/editor-shell/editor-shell.html +62 -0
  56. package/patterns/export-flow/export-flow.examples.html +152 -0
  57. package/patterns/export-flow/export-flow.examples.js +37 -0
  58. package/patterns/export-flow/export-flow.html +65 -0
  59. package/patterns/filter-bar/filter-bar.examples.html +116 -0
  60. package/patterns/filter-bar/filter-bar.examples.js +23 -0
  61. package/patterns/filter-bar/filter-bar.html +70 -0
  62. package/patterns/form-drawer/form-drawer.examples.html +210 -0
  63. package/patterns/form-drawer/form-drawer.html +64 -0
  64. package/patterns/form-system/form-system.examples.html +383 -0
  65. package/patterns/form-system/form-system.html +48 -0
  66. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +189 -0
  67. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.html +64 -0
  68. package/patterns/inline-dialog/inline-dialog.examples.html +143 -0
  69. package/patterns/inline-dialog/inline-dialog.html +59 -0
  70. package/patterns/kanban-board/kanban-board.examples.html +224 -0
  71. package/patterns/kanban-board/kanban-board.html +58 -0
  72. package/patterns/layout/layout.examples.html +365 -0
  73. package/patterns/layout/layout.html +54 -0
  74. package/patterns/marketing-engagement/marketing-engagement.examples.html +280 -0
  75. package/patterns/marketing-engagement/marketing-engagement.html +64 -0
  76. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +213 -0
  77. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.html +58 -0
  78. package/patterns/overview/overview.examples.html +119 -0
  79. package/patterns/overview/overview.html +42 -0
  80. package/patterns/permissions-matrix/permissions-matrix.examples.html +91 -0
  81. package/patterns/permissions-matrix/permissions-matrix.examples.js +28 -0
  82. package/patterns/permissions-matrix/permissions-matrix.html +56 -0
  83. package/patterns/permissions-role-picker/permissions-role-picker.examples.html +81 -0
  84. package/patterns/permissions-role-picker/permissions-role-picker.html +56 -0
  85. package/patterns/permissions-sharing/permissions-sharing.examples.html +175 -0
  86. package/patterns/permissions-sharing/permissions-sharing.html +66 -0
  87. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +227 -0
  88. package/patterns/profile-public-and-verification/profile-public-and-verification.html +70 -0
  89. package/patterns/record-detail-drawer/record-detail-drawer.examples.html +164 -0
  90. package/patterns/record-detail-drawer/record-detail-drawer.html +64 -0
  91. package/patterns/responsive-shell-sidebar/README.md +37 -0
  92. package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.css +39 -0
  93. package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.examples.html +208 -0
  94. package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.html +47 -0
  95. package/patterns/retention-cohort/retention-cohort.examples.html +149 -0
  96. package/patterns/retention-cohort/retention-cohort.examples.js +37 -0
  97. package/patterns/retention-cohort/retention-cohort.html +62 -0
  98. package/patterns/search-discovery/search-discovery.examples.html +263 -0
  99. package/patterns/search-discovery/search-discovery.html +58 -0
  100. package/patterns/system-banners/system-banners.examples.html +150 -0
  101. package/patterns/system-banners/system-banners.html +52 -0
  102. package/patterns/timezone-selector/timezone-selector.examples.html +82 -0
  103. package/patterns/timezone-selector/timezone-selector.examples.js +72 -0
  104. package/patterns/timezone-selector/timezone-selector.html +57 -0
  105. package/patterns/wizard-drawer/wizard-drawer.examples.html +144 -0
  106. package/patterns/wizard-drawer/wizard-drawer.examples.js +33 -0
  107. package/patterns/wizard-drawer/wizard-drawer.html +72 -0
  108. package/styles/type/roles.css +8 -8
@@ -0,0 +1,150 @@
1
+ <header>
2
+ <div>
3
+ <h1>System &amp; App Banners</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">alert-ui</tag-ui> <tag-ui size="sm">button-ui</tag-ui> <tag-ui size="sm">text-ui</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>Persistent strip-shaped surfaces above the app shell. System banners (offline, maintenance, update available), live-update banners ("new since you opened this"), and announcement banners (beta callouts, promos). All three are <code>alert-ui</code> compositions; the variant + dismiss + CTA pattern is what differs.</p>
9
+ </header>
10
+
11
+ <section data-section data-property="when-to-use">
12
+ <h2 variant="section">When to use</h2>
13
+ <p data-note>
14
+ Three reasons a banner exists at the top of an app: the system is in
15
+ a degraded state (08j), real-time activity has out-paced the user's
16
+ view (17f), or product wants to promote something (14e). They share
17
+ a primitive but differ in tone, dismissibility, and persistence —
18
+ system banners are non-dismissible while the condition holds; live
19
+ + announcement are dismissible.
20
+ </p>
21
+ </section>
22
+
23
+ <section data-section data-property="system-offline">
24
+ <h2 variant="section">System status — offline</h2>
25
+ <p data-note><code>variant="warning"</code> with a network-slash icon. Non-dismissible while the connection is down. The banner disappears on its own when the network returns; users don't dismiss it manually.</p>
26
+ <div data-artifact-container>
27
+ <div data-artifact-item data-artifact-label="offline banner">
28
+ <alert-ui data-chunk="banner-system-offline" variant="warning" icon="wifi-slash">
29
+ <col-ui slot="content" gap="1">
30
+ <text-ui strong>You're offline.</text-ui>
31
+ <text-ui>Changes will sync when the connection returns. Some features are unavailable.</text-ui>
32
+ </col-ui>
33
+ </alert-ui>
34
+ </div>
35
+ </div>
36
+ </section>
37
+
38
+ <section data-section data-property="system-maintenance">
39
+ <h2 variant="section">System status — maintenance window</h2>
40
+ <p data-note><code>variant="info"</code> with a wrench icon. Posted ahead of a planned outage. Carries the start time and an optional "Learn more" link to a status page. Not dismissible — users need to know.</p>
41
+ <div data-artifact-container>
42
+ <div data-artifact-item data-artifact-label="maintenance banner">
43
+ <alert-ui data-chunk="banner-system-maintenance" variant="info" icon="wrench">
44
+ <col-ui slot="content" gap="1">
45
+ <text-ui strong>Scheduled maintenance — Sunday, 2:00–4:00 AM UTC.</text-ui>
46
+ <text-ui>The service will be read-only during this window.</text-ui>
47
+ <row-ui gap="2" justify="end">
48
+ <button-ui text="Status page" variant="ghost" size="sm" icon-trailing="arrow-up-right"></button-ui>
49
+ </row-ui>
50
+ </col-ui>
51
+ </alert-ui>
52
+ </div>
53
+ </div>
54
+ </section>
55
+
56
+ <section data-section data-property="system-update">
57
+ <h2 variant="section">System status — update available</h2>
58
+ <p data-note><code>variant="info"</code> with an arrow-clockwise icon and a primary "Refresh" CTA. Appears when the client detects a newer build. Dismissible (user is in the middle of something) but reappears on next session start.</p>
59
+ <div data-artifact-container>
60
+ <div data-artifact-item data-artifact-label="update available banner">
61
+ <alert-ui data-chunk="banner-system-update" variant="info" icon="arrow-clockwise" closable>
62
+ <col-ui slot="content" gap="1">
63
+ <text-ui strong>A new version is available.</text-ui>
64
+ <text-ui>Refresh to get the latest features and fixes.</text-ui>
65
+ <row-ui gap="2" justify="end">
66
+ <button-ui text="Refresh" variant="primary" size="sm"></button-ui>
67
+ </row-ui>
68
+ </col-ui>
69
+ </alert-ui>
70
+ </div>
71
+ </div>
72
+ </section>
73
+
74
+ <section data-section data-property="live-update">
75
+ <h2 variant="section">Live updates — "new since you opened this"</h2>
76
+ <p data-note><code>variant="info"</code> with a count + a "Show new" CTA. Sits above a list / feed / table to signal that the underlying data has new rows the user hasn't seen yet. Clicking the CTA scrolls the new items in and dismisses the banner. Companion to the <code>data-stream</code> trait.</p>
77
+ <div data-artifact-container>
78
+ <div data-artifact-item data-artifact-label="live update banner">
79
+ <alert-ui data-chunk="banner-live-update" variant="info" icon="arrow-up">
80
+ <col-ui slot="content" gap="1">
81
+ <row-ui gap="2" align="baseline" wrap>
82
+ <text-ui strong>12 new items</text-ui>
83
+ <text-ui color="subtle">since you opened this view 4 minutes ago.</text-ui>
84
+ </row-ui>
85
+ <row-ui gap="2" justify="end">
86
+ <button-ui text="Show new" variant="primary" size="sm" icon-trailing="arrow-up"></button-ui>
87
+ </row-ui>
88
+ </col-ui>
89
+ </alert-ui>
90
+ </div>
91
+ </div>
92
+ </section>
93
+
94
+ <section data-section data-property="announcement-beta">
95
+ <h2 variant="section">Announcement — beta callout</h2>
96
+ <p data-note><code>variant="info"</code> or <code>variant="muted"</code> with a sparkle / flask icon. Promotes a new feature to opted-in users; carries a "Try it" CTA + dismiss. Once dismissed, persists per-user — don't show twice.</p>
97
+ <div data-artifact-container>
98
+ <div data-artifact-item data-artifact-label="beta announcement banner">
99
+ <alert-ui data-chunk="banner-announcement-beta" variant="muted" icon="sparkle" closable>
100
+ <col-ui slot="content" gap="1">
101
+ <text-ui strong>New: Saved views.</text-ui>
102
+ <text-ui>Curate filter sets and reuse them across the workspace. Now in beta.</text-ui>
103
+ <row-ui gap="2" justify="end">
104
+ <button-ui text="Try it" variant="primary" size="sm"></button-ui>
105
+ </row-ui>
106
+ </col-ui>
107
+ </alert-ui>
108
+ </div>
109
+ </div>
110
+ </section>
111
+
112
+ <section data-section data-property="announcement-promo">
113
+ <h2 variant="section">Announcement — promo / event</h2>
114
+ <p data-note><code>variant="info"</code> with a megaphone or calendar icon. Time-boxed (event date, promo end). Dismiss persists for the campaign window. CTA goes to the landing page or signup flow.</p>
115
+ <div data-artifact-container>
116
+ <div data-artifact-item data-artifact-label="promo announcement banner">
117
+ <alert-ui data-chunk="banner-announcement-promo" variant="info" icon="megaphone-simple" closable>
118
+ <col-ui slot="content" gap="1">
119
+ <text-ui strong>UIConf 2026 — May 22, virtual.</text-ui>
120
+ <text-ui>Two days of sessions on generative UI, A2UI internals, and the road ahead.</text-ui>
121
+ <row-ui gap="2" justify="end">
122
+ <button-ui text="Save your seat" variant="primary" size="sm" icon-trailing="arrow-up-right"></button-ui>
123
+ </row-ui>
124
+ </col-ui>
125
+ </alert-ui>
126
+ </div>
127
+ </div>
128
+ </section>
129
+
130
+ <section data-section data-property="composition">
131
+ <h2 variant="section">Composition rules</h2>
132
+ <ul>
133
+ <li><strong>System banners are non-dismissible while the condition holds</strong> — offline, maintenance windows, and incidents disappear on their own when the situation resolves. Forcing a manual dismiss invites confusion ("did I miss something?").</li>
134
+ <li><strong>Update-available is the exception</strong> — the user is allowed to keep working through their current task; the banner reappears next session.</li>
135
+ <li><strong>Live-update banners pair with <code>data-stream</code></strong> — the banner's count comes from the same stream that's feeding the list below it. The CTA reveals queued items already in memory; the banner is a UX-layer affordance, not a re-fetch.</li>
136
+ <li><strong>Announcements respect a per-user dismiss</strong> — once a user closes a beta callout or promo, do not show it again on this device for the campaign window. Persist server-side if the campaign spans devices.</li>
137
+ <li><strong>One banner at a time</strong> — stacking three banners above the app shell pushes content down and reads as broken. Prioritize: system &gt; live &gt; announcement; suppress lower-priority banners while higher-priority ones are visible.</li>
138
+ <li><strong>Banner text leads with the noun, not the verb</strong> — "12 new items", "Scheduled maintenance", "New version available". Action verbs go on the button.</li>
139
+ </ul>
140
+ </section>
141
+
142
+ <section data-section data-property="cross-references">
143
+ <h2 variant="section">See also</h2>
144
+ <ul>
145
+ <li><a href="/site/components/alert">alert-ui</a> — the underlying primitive (variants, closable, icon, slots).</li>
146
+ <li><a href="/site/patterns/data-stream">data-stream</a> — the trait that powers live-update counts.</li>
147
+ <li><a href="/site/components/toast">toast-ui</a> — transient ephemeral notifications (sibling, not interchangeable).</li>
148
+ <li><a href="/site/patterns/auth-status-pages">auth status pages</a> — full-page status surfaces (sibling for non-banner system states).</li>
149
+ </ul>
150
+ </section>
@@ -0,0 +1,52 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" theme="auto">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>System &amp; App Banners (pattern) — AdiaUI</title>
7
+
8
+ <!-- Token base -->
9
+ <link rel="stylesheet" href="../../styles/resets.css">
10
+ <link rel="stylesheet" href="../../styles/tokens.css">
11
+
12
+ <!-- Component CSS — primitives this pattern composes -->
13
+ <link rel="stylesheet" href="../../components/alert/alert.css">
14
+ <link rel="stylesheet" href="../../components/button/button.css">
15
+ <link rel="stylesheet" href="../../components/col/col.css">
16
+ <link rel="stylesheet" href="../../components/row/row.css">
17
+ <link rel="stylesheet" href="../../components/tag/tag.css">
18
+ <link rel="stylesheet" href="../../components/text/text.css">
19
+
20
+ <!-- Component JS -->
21
+ <script type="module" src="../../components/alert/alert.js"></script>
22
+ <script type="module" src="../../components/button/button.js"></script>
23
+ <script type="module" src="../../components/col/col.js"></script>
24
+ <script type="module" src="../../components/row/row.js"></script>
25
+ <script type="module" src="../../components/tag/tag.js"></script>
26
+ <script type="module" src="../../components/text/text.js"></script>
27
+
28
+ <style>
29
+ :where(html, body) { margin: 0; min-height: 100vh; background: var(--md-sys-color-neutral-background); color: var(--md-sys-color-neutral-on-surface); font-family: var(--a-font-family); }
30
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
31
+ </style>
32
+ </head>
33
+ <body>
34
+
35
+ <main id="demo-root">
36
+ <p>Loading examples…</p>
37
+ </main>
38
+
39
+ <script type="module">
40
+ const root = document.getElementById('demo-root');
41
+ try {
42
+ const res = await fetch('./system-banners.examples.html');
43
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
44
+ root.innerHTML = await res.text();
45
+ } catch (err) {
46
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load system-banners.examples.html — ${err.message}</p>`;
47
+ console.error('[system-banners.html]', err);
48
+ }
49
+ </script>
50
+
51
+ </body>
52
+ </html>
@@ -0,0 +1,82 @@
1
+ <header>
2
+ <div>
3
+ <h1>Time-zone selector</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">select-ui</tag-ui> <tag-ui size="sm">field-ui</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>IANA timezone picker — searchable select-ui populated from <code>Intl.supportedValuesOf('timeZone')</code> (browser-native, ~400 zones, zero-deps). Each option renders as <code>America/Los_Angeles · UTC-8</code> so users can scan by offset or search by city / region.</p>
9
+ </header>
10
+
11
+ <section data-section data-property="when-to-use">
12
+ <h2 variant="section">When to use</h2>
13
+ <p data-note>User preferences / scheduling / log-display surfaces where the operator must pick a canonical IANA zone (not just a display offset). Defaults to the browser's resolved zone via <code>Intl.DateTimeFormat().resolvedOptions().timeZone</code> — overrides for users in multi-zone accounts.</p>
14
+ </section>
15
+
16
+ <section data-section data-property="basic">
17
+ <h2 variant="section">Basic — searchable picker</h2>
18
+ <p data-note>Type to filter by city, region, or offset. Default value resolved from the browser's locale; the current-tz hint sits under the input. Composes select-ui[searchable] with no new primitive.</p>
19
+ <div data-artifact-container>
20
+ <div data-artifact-item data-artifact-label="timezone picker">
21
+ <card-ui data-chunk="timezone-selector-basic" style="max-width: 480px;">
22
+ <header>
23
+ <span slot="heading" variant="section">Display time zone</span>
24
+ <text-ui slot="description" color="subtle">Used for log timestamps, scheduled reports, and meeting times</text-ui>
25
+ </header>
26
+ <section>
27
+ <col-ui gap="3">
28
+ <field-ui label="Time zone">
29
+ <select-ui id="tz-select-basic" searchable placeholder="Search by city or region…"></select-ui>
30
+ </field-ui>
31
+ <text-ui color="subtle" size="sm" id="tz-hint-basic">Detected from your browser locale.</text-ui>
32
+ </col-ui>
33
+ </section>
34
+ </card-ui>
35
+ </div>
36
+ </div>
37
+ </section>
38
+
39
+ <section data-section data-property="with-preview">
40
+ <h2 variant="section">With live preview</h2>
41
+ <p data-note>The chosen zone's current local time updates in the description as the user changes the picker. Useful for "Send at" / "Schedule report" forms where the time-in-target matters more than the offset.</p>
42
+ <div data-artifact-container>
43
+ <div data-artifact-item data-artifact-label="timezone picker with preview">
44
+ <card-ui data-chunk="timezone-selector-preview" style="max-width: 480px;">
45
+ <header>
46
+ <span slot="heading" variant="section">Schedule report</span>
47
+ </header>
48
+ <section>
49
+ <col-ui gap="3">
50
+ <field-ui label="Time zone">
51
+ <select-ui id="tz-select-preview" searchable></select-ui>
52
+ </field-ui>
53
+ <field-ui label="Send at">
54
+ <input-ui type="time" name="send-at" value="09:00"></input-ui>
55
+ </field-ui>
56
+ <text-ui id="tz-preview" color="subtle" size="sm"></text-ui>
57
+ </col-ui>
58
+ </section>
59
+ </card-ui>
60
+ </div>
61
+ </div>
62
+ </section>
63
+
64
+ <section data-section data-property="composition">
65
+ <h2 variant="section">Composition rules</h2>
66
+ <ul>
67
+ <li><strong>Data from <code>Intl.supportedValuesOf('timeZone')</code></strong> — browser-native, always current with the IANA database the browser ships. No external tz-data dependency.</li>
68
+ <li><strong>Label format: <code>region/city · UTC±N</code></strong> — gives both the canonical identifier (for storage) and the human offset (for scanning). Users sort by either.</li>
69
+ <li><strong>Default from <code>Intl.DateTimeFormat().resolvedOptions().timeZone</code></strong> — the browser's resolved zone is the right zero-friction default. Surface the value as a hint so users can confirm before saving.</li>
70
+ <li><strong>Recompute offsets per render</strong> — DST transitions move; cache the offset string at render time, not at boot. (Re-rendering on each open is cheap; the cost is the ~400-option list which we already accept.)</li>
71
+ <li><strong>For account-level multi-zone scheduling</strong> — pair with a second select-ui for the user's locale-zone vs the report-target-zone. Don't try to encode both into one picker.</li>
72
+ </ul>
73
+ </section>
74
+
75
+ <section data-section data-property="cross-references">
76
+ <h2 variant="section">Cross-references</h2>
77
+ <ul>
78
+ <li><a href="/site/components/select">select-ui</a> — base primitive ([searchable] flag is the load-bearing feature).</li>
79
+ <li><a href="/site/components/relative-time">relative-time-ui</a> — companion for showing past/future timestamps in the chosen zone.</li>
80
+ <li><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/supportedValuesOf">Intl.supportedValuesOf MDN</a> — data source.</li>
81
+ </ul>
82
+ </section>
@@ -0,0 +1,72 @@
1
+ /** Timezone-selector pattern — populate select-ui[searchable] from Intl.supportedValuesOf. */
2
+
3
+ function offsetLabel(tz, when = new Date()) {
4
+ try {
5
+ const parts = new Intl.DateTimeFormat('en-US', {
6
+ timeZone: tz,
7
+ timeZoneName: 'shortOffset',
8
+ }).formatToParts(when);
9
+ const name = parts.find(p => p.type === 'timeZoneName')?.value || '';
10
+ // shortOffset → "GMT-8" / "GMT+05:30"; normalize to "UTC-8".
11
+ return name.replace(/^GMT/, 'UTC') || '';
12
+ } catch {
13
+ return '';
14
+ }
15
+ }
16
+
17
+ function localTimeIn(tz, when = new Date()) {
18
+ try {
19
+ return new Intl.DateTimeFormat([], {
20
+ timeZone: tz,
21
+ hour: '2-digit',
22
+ minute: '2-digit',
23
+ weekday: 'short',
24
+ }).format(when);
25
+ } catch {
26
+ return '';
27
+ }
28
+ }
29
+
30
+ function timezoneOptions() {
31
+ let zones = [];
32
+ try {
33
+ zones = Intl.supportedValuesOf('timeZone');
34
+ } catch {
35
+ zones = ['UTC', 'America/Los_Angeles', 'America/New_York', 'Europe/London', 'Europe/Berlin', 'Asia/Tokyo', 'Asia/Shanghai', 'Australia/Sydney'];
36
+ }
37
+ return zones.map(tz => ({
38
+ value: tz,
39
+ label: `${tz} · ${offsetLabel(tz)}`,
40
+ }));
41
+ }
42
+
43
+ function populate(select, defaultTz) {
44
+ select.options = timezoneOptions();
45
+ if (defaultTz) select.value = defaultTz;
46
+ }
47
+
48
+ export default function setup(router) {
49
+ const root = router || document;
50
+ const defaultTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
51
+
52
+ // Basic picker
53
+ const basic = root.querySelector?.('#tz-select-basic');
54
+ if (basic) {
55
+ populate(basic, defaultTz);
56
+ const hint = root.querySelector('#tz-hint-basic');
57
+ if (hint) hint.textContent = `Detected from your browser locale: ${defaultTz} (${offsetLabel(defaultTz)}).`;
58
+ }
59
+
60
+ // With live preview
61
+ const preview = root.querySelector?.('#tz-select-preview');
62
+ const previewLine = root.querySelector?.('#tz-preview');
63
+ if (preview && previewLine) {
64
+ populate(preview, defaultTz);
65
+ const update = () => {
66
+ const tz = preview.value || defaultTz;
67
+ previewLine.textContent = `Current time in ${tz}: ${localTimeIn(tz)} (${offsetLabel(tz)}).`;
68
+ };
69
+ update();
70
+ preview.addEventListener('change', update);
71
+ }
72
+ }
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" theme="auto">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Time-zone selector (pattern) — AdiaUI</title>
7
+
8
+ <link rel="stylesheet" href="../../styles/resets.css">
9
+ <link rel="stylesheet" href="../../styles/tokens.css">
10
+
11
+ <link rel="stylesheet" href="../../components/button/button.css">
12
+ <link rel="stylesheet" href="../../components/card/card.css">
13
+ <link rel="stylesheet" href="../../components/col/col.css">
14
+ <link rel="stylesheet" href="../../components/field/field.css">
15
+ <link rel="stylesheet" href="../../components/icon/icon.css">
16
+ <link rel="stylesheet" href="../../components/input/input.css">
17
+ <link rel="stylesheet" href="../../components/row/row.css">
18
+ <link rel="stylesheet" href="../../components/select/select.css">
19
+ <link rel="stylesheet" href="../../components/tag/tag.css">
20
+ <link rel="stylesheet" href="../../components/text/text.css">
21
+
22
+ <script type="module" src="../../components/button/button.js"></script>
23
+ <script type="module" src="../../components/card/card.js"></script>
24
+ <script type="module" src="../../components/col/col.js"></script>
25
+ <script type="module" src="../../components/field/field.js"></script>
26
+ <script type="module" src="../../components/icon/icon.js"></script>
27
+ <script type="module" src="../../components/input/input.js"></script>
28
+ <script type="module" src="../../components/row/row.js"></script>
29
+ <script type="module" src="../../components/select/select.js"></script>
30
+ <script type="module" src="../../components/tag/tag.js"></script>
31
+ <script type="module" src="../../components/text/text.js"></script>
32
+
33
+ <style>
34
+ :where(html, body) { margin: 0; min-height: 100vh; background: var(--md-sys-color-neutral-background); color: var(--md-sys-color-neutral-on-surface); font-family: var(--a-font-family); }
35
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
36
+ </style>
37
+ </head>
38
+ <body>
39
+
40
+ <main id="demo-root">
41
+ <p>Loading examples…</p>
42
+ </main>
43
+
44
+ <script type="module">
45
+ const root = document.getElementById('demo-root');
46
+ try {
47
+ const res = await fetch('./timezone-selector.examples.html');
48
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
49
+ root.innerHTML = await res.text();
50
+ } catch (err) {
51
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load timezone-selector.examples.html — ${err.message}</p>`;
52
+ console.error('[timezone-selector.html]', err);
53
+ }
54
+ </script>
55
+
56
+ </body>
57
+ </html>
@@ -0,0 +1,144 @@
1
+ <header>
2
+ <div>
3
+ <h1>Wizard Drawer</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">drawer-ui</tag-ui> <tag-ui size="sm">stepper-ui</tag-ui> <tag-ui size="sm">button-ui</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>Multi-step form in a drawer. Stepper in the header tracks progress; body swaps content per step; footer pins Back / Next, with a primary finish on the last step. The canonical onboarding-inside-an-app shape.</p>
9
+ </header>
10
+
11
+ <section data-section data-property="when-to-use">
12
+ <h2 variant="section">When to use</h2>
13
+ <p data-note>
14
+ Any 3–5 step flow where each step has its own set of decisions and the user benefits
15
+ from seeing progress: invite flow, integration setup, first-run onboarding, payment
16
+ collection, multi-stage approvals. For 6+ steps, consider a dedicated page.
17
+ </p>
18
+ </section>
19
+
20
+ <section data-section data-property="three-step-wizard">
21
+ <h2 variant="section">Three-step create wizard</h2>
22
+ <p data-note>Stepper header, step body, Back/Next footer. The interactive buttons below advance the stepper and switch the body panel.</p>
23
+ <div data-artifact-container>
24
+ <div data-artifact-item data-artifact-label="wizard">
25
+ <button-ui data-chunk="wizard-drawer-three-step-wizard" text="Create workspace" icon="plus" variant="primary" onclick="this.nextElementSibling.open=true"></button-ui>
26
+ <drawer-ui id="pat-wizard" side="right" size="lg">
27
+ <header slot="header">
28
+ <col-ui gap="2" grow>
29
+ <text-ui strong>Create workspace</text-ui>
30
+ <stepper-ui id="pat-wizard-stepper" step="0">
31
+ <stepper-item-ui text="Details"></stepper-item-ui>
32
+ <stepper-item-ui text="Members"></stepper-item-ui>
33
+ <stepper-item-ui text="Review"></stepper-item-ui>
34
+ </stepper-ui>
35
+ </col-ui>
36
+ </header>
37
+ <section slot="body">
38
+ <div data-wizard-step="0">
39
+ <col-ui gap="3">
40
+ <h4>Workspace details</h4>
41
+ <field-ui label="Name">
42
+ <input-ui placeholder="Acme Team" required></input-ui>
43
+ </field-ui>
44
+ <field-ui label="Slug">
45
+ <input-ui prefix="/" placeholder="acme-team"></input-ui>
46
+ </field-ui>
47
+ <field-ui label="Description">
48
+ <textarea-ui rows="2" placeholder="What does this team work on?"></textarea-ui>
49
+ </field-ui>
50
+ </col-ui>
51
+ </div>
52
+ <div data-wizard-step="1" hidden>
53
+ <col-ui gap="3">
54
+ <h4>Invite team members</h4>
55
+ <field-ui label="Email addresses">
56
+ <textarea-ui placeholder="alex@acme.com, sarah@acme.com" rows="3"></textarea-ui>
57
+ </field-ui>
58
+ <field-ui label="Default role">
59
+ <select-ui placeholder="Select role">
60
+ <option value="admin">Admin</option>
61
+ <option value="member" selected>Member</option>
62
+ <option value="viewer">Viewer</option>
63
+ </select-ui>
64
+ </field-ui>
65
+ <field-ui label="Send welcome email" inline>
66
+ <switch-ui checked></switch-ui>
67
+ </field-ui>
68
+ </col-ui>
69
+ </div>
70
+ <div data-wizard-step="2" hidden>
71
+ <col-ui gap="3">
72
+ <h4>Review and create</h4>
73
+ <alert-ui text="Your workspace will be created and team members will be invited by email." variant="info" icon="info"></alert-ui>
74
+ <description-list-ui>
75
+ <dt>Name</dt><dd>Acme Team</dd>
76
+ <dt>Slug</dt><dd>/acme-team</dd>
77
+ <dt>Members</dt><dd>2 invited</dd>
78
+ <dt>Plan</dt><dd>Free (14-day Pro trial)</dd>
79
+ </description-list-ui>
80
+ </col-ui>
81
+ </div>
82
+ </section>
83
+ <footer slot="footer">
84
+ <span slot="action-leading">
85
+ <button-ui id="pat-wizard-back" text="Back" variant="ghost" disabled></button-ui>
86
+ </span>
87
+ <span slot="action">
88
+ <button-ui text="Cancel" variant="ghost" onclick="this.closest('drawer-ui').open=false"></button-ui>
89
+ <button-ui id="pat-wizard-next" text="Next" variant="primary"></button-ui>
90
+ </span>
91
+ </footer>
92
+ </drawer-ui>
93
+ </div>
94
+ </div>
95
+ </section>
96
+
97
+ <section data-section data-property="anatomy">
98
+ <h2 variant="section">Anatomy</h2>
99
+ <code-ui language="html">&lt;drawer-ui side="right" size="lg"&gt;
100
+
101
+ &lt;!-- stepper in header tracks progress --&gt;
102
+ &lt;header slot="header"&gt;
103
+ &lt;col-ui gap="2" grow&gt;
104
+ &lt;text-ui weight="semibold"&gt;Create workspace&lt;/text-ui&gt;
105
+ &lt;stepper-ui step="0"&gt;
106
+ &lt;stepper-item-ui text="Details"&gt;&lt;/stepper-item-ui&gt;
107
+ &lt;stepper-item-ui text="Members"&gt;&lt;/stepper-item-ui&gt;
108
+ &lt;stepper-item-ui text="Review"&gt;&lt;/stepper-item-ui&gt;
109
+ &lt;/stepper-ui&gt;
110
+ &lt;/col-ui&gt;
111
+ &lt;/header&gt;
112
+
113
+ &lt;!-- one panel per step, toggled via hidden attr --&gt;
114
+ &lt;section slot="body"&gt;
115
+ &lt;div data-wizard-step="0"&gt; ...details... &lt;/div&gt;
116
+ &lt;div data-wizard-step="1" hidden&gt; ...members... &lt;/div&gt;
117
+ &lt;div data-wizard-step="2" hidden&gt; ...review... &lt;/div&gt;
118
+ &lt;/section&gt;
119
+
120
+ &lt;!-- Back on the leading edge, Cancel/Next on the trailing edge --&gt;
121
+ &lt;footer slot="footer"&gt;
122
+ &lt;span slot="action-leading"&gt;
123
+ &lt;button-ui text="Back" variant="ghost"&gt;&lt;/button-ui&gt;
124
+ &lt;/span&gt;
125
+ &lt;span slot="action"&gt;
126
+ &lt;button-ui text="Cancel" variant="ghost"&gt;&lt;/button-ui&gt;
127
+ &lt;button-ui text="Next" variant="primary"&gt;&lt;/button-ui&gt;
128
+ &lt;/span&gt;
129
+ &lt;/footer&gt;
130
+
131
+ &lt;/drawer-ui&gt;</code-ui>
132
+ </section>
133
+
134
+ <section data-section data-property="rules">
135
+ <h2 variant="section">Rules</h2>
136
+ <ul>
137
+ <li>Stepper is in the <strong>header</strong>, not the body. The user always sees progress even when the body scrolls.</li>
138
+ <li>Use <code>stepper-ui.step</code> (numeric) as the source of truth. Toggle <code>hidden</code> on <code>[data-wizard-step="N"]</code> to swap panels.</li>
139
+ <li>The primary action label changes on the last step: "Next" → "Create" / "Finish". Back button is disabled on step 0.</li>
140
+ <li>Every step validates independently before advancing. Advance triggers <code>.next()</code> on the stepper AND unhides the next panel.</li>
141
+ <li>If steps can be revisited, make <code>stepper-item-ui</code> clickable and wire to <code>.goTo(i)</code>. Otherwise keep it display-only.</li>
142
+ <li>Consider using the <code>state-machine</code> controller on the drawer for more complex flows (branching, validation states, resumable wizards).</li>
143
+ </ul>
144
+ </section>
@@ -0,0 +1,33 @@
1
+ /** Wizard drawer pattern — wire stepper to step-panel swap */
2
+
3
+ export default function setup(router) {
4
+ const stepper = router.querySelector('#pat-wizard-stepper');
5
+ const backBtn = router.querySelector('#pat-wizard-back');
6
+ const nextBtn = router.querySelector('#pat-wizard-next');
7
+ const drawer = router.querySelector('#pat-wizard');
8
+ if (!stepper || !backBtn || !nextBtn || !drawer) return;
9
+
10
+ const total = 3;
11
+ let step = 0;
12
+
13
+ const sync = () => {
14
+ stepper.step = step;
15
+ for (let i = 0; i < total; i++) {
16
+ const panel = router.querySelector(`[data-wizard-step="${i}"]`);
17
+ if (panel) panel.hidden = i !== step;
18
+ }
19
+ backBtn.disabled = step === 0;
20
+ nextBtn.text = step === total - 1 ? 'Create' : 'Next';
21
+ };
22
+
23
+ backBtn.addEventListener('press', () => {
24
+ if (step > 0) { step--; sync(); }
25
+ });
26
+
27
+ nextBtn.addEventListener('press', () => {
28
+ if (step < total - 1) { step++; sync(); }
29
+ else { drawer.open = false; step = 0; sync(); }
30
+ });
31
+
32
+ sync();
33
+ }