@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,149 @@
1
+ <header>
2
+ <div>
3
+ <h1>Retention Cohort</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">card-ui</tag-ui> <tag-ui size="sm">table-ui</tag-ui> <tag-ui size="sm">badge-ui</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>Composition pattern: render a retention cohort "heatmap" using a regular <code>table-ui</code> with a badge-based cell renderer. Each cell is a <code>badge-ui</code> variant tinted by the retention bucket, so the table still sorts, paginates, and copies to clipboard like any other data table.</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
+ A true pixel-grid heatmap loses the numeric precision that retention analysis
15
+ needs — you want to see that W4 held at 54% AND scan the color band. A table with
16
+ badge cells gives you both: precise numbers on one axis, color-coded buckets
17
+ across the row. It also preserves accessibility (each number is a real table
18
+ cell) and lets the same component render partial cohorts (null cells where
19
+ the cohort hasn't reached that week yet).
20
+ </p>
21
+ </section>
22
+
23
+ <section data-section data-property="default-retention">
24
+ <h2 variant="section">Default retention table</h2>
25
+ <p data-note>Each week-column uses the same <code>formatPct</code> renderer, which wraps the number in a <code>badge-ui</code> whose variant is keyed to three buckets: ≥60% success, 30–60% warning, &lt;30% muted. Null values render blank so partial cohorts don't force fake zeros.</p>
26
+ <div data-artifact-container>
27
+ <div data-artifact-item data-artifact-label="retention by signup week">
28
+ <card-ui data-chunk="retention-cohort-default-retention">
29
+ <header>
30
+ <h3>Retention by signup week</h3>
31
+ <text-ui slot="description" color="subtle">% of users still active in week N</text-ui>
32
+ </header>
33
+ <section bleed>
34
+ <table-ui id="pat-retention-default"></table-ui>
35
+ </section>
36
+ </card-ui>
37
+ </div>
38
+ </div>
39
+ </section>
40
+
41
+ <section data-section data-property="with-legend">
42
+ <h2 variant="section">With a legend</h2>
43
+ <p data-note>For first-time viewers, pair the table with a tiny legend in the card footer so the buckets are decoded. The legend itself is three <code>badge-ui</code>s — same component the cells use — keeping the visual vocabulary tight.</p>
44
+ <div data-artifact-container>
45
+ <div data-artifact-item data-artifact-label="retention with legend">
46
+ <card-ui data-chunk="retention-cohort-with-legend">
47
+ <header>
48
+ <h3>Retention by signup week</h3>
49
+ <text-ui slot="description" color="subtle">Percent of the cohort still active N weeks after signup</text-ui>
50
+ </header>
51
+ <section bleed>
52
+ <table-ui id="pat-retention-legend"></table-ui>
53
+ </section>
54
+ <footer divider>
55
+ <small slot="description">Retention buckets:</small>
56
+ <span slot="action">
57
+ <row-ui gap="2" align="center">
58
+ <badge-ui text="≥ 60%" variant="success"></badge-ui>
59
+ <badge-ui text="30–60%" variant="warning"></badge-ui>
60
+ <badge-ui text="< 30%" variant="muted"></badge-ui>
61
+ </row-ui>
62
+ </span>
63
+ </footer>
64
+ </card-ui>
65
+ </div>
66
+ </div>
67
+ </section>
68
+
69
+ <section data-section data-property="stat-pair">
70
+ <h2 variant="section">With headline stats</h2>
71
+ <p data-note>When the cohort table is the only chart in a section, prepend a stat pair for the most important numbers — W4 (early signal) and W12 (sustained retention). Stops users having to scan every row to answer "is this healthy?"</p>
72
+ <div data-artifact-container>
73
+ <div data-artifact-item data-artifact-label="retention with stats">
74
+ <card-ui data-chunk="retention-cohort-stat-pair">
75
+ <header>
76
+ <h3>Retention</h3>
77
+ <text-ui slot="description" color="subtle">New signups · rolling 6-week view</text-ui>
78
+ </header>
79
+ <section>
80
+ <grid-ui columns="2" gap="3">
81
+ <card-ui>
82
+ <section>
83
+ <stat-ui label="W4 retention" value="54%" change="+4% vs last cohort" trend="up"></stat-ui>
84
+ </section>
85
+ </card-ui>
86
+ <card-ui>
87
+ <section>
88
+ <stat-ui label="W12 retention" value="32%" change="flat" trend="neutral"></stat-ui>
89
+ </section>
90
+ </card-ui>
91
+ </grid-ui>
92
+ </section>
93
+ <section bleed>
94
+ <table-ui id="pat-retention-stats"></table-ui>
95
+ </section>
96
+ </card-ui>
97
+ </div>
98
+ </div>
99
+ </section>
100
+
101
+ <section data-section data-property="the-cell-renderer">
102
+ <h2 variant="section">The cell renderer</h2>
103
+ <p data-note>All three examples use the same <code>formatPct</code> function defined in the page's <code>setup.js</code>. The column-definition object references it via <code>render: formatPct</code>:</p>
104
+ <code-ui language="javascript">const formatPct = (v) =&gt; {
105
+ if (v == null) return '';
106
+ const n = Math.round(v);
107
+ const variant = n &gt;= 60 ? 'success' : n &gt;= 30 ? 'warning' : 'muted';
108
+ return `&lt;badge-ui text='${n}%' variant='${variant}'&gt;&lt;/badge-ui&gt;`;
109
+ };
110
+
111
+ const columns = [
112
+ { key: 'week', label: 'Signup week' },
113
+ { key: 'size', label: 'Users' },
114
+ { key: 'w1', label: 'W1', render: formatPct },
115
+ { key: 'w2', label: 'W2', render: formatPct },
116
+ { key: 'w4', label: 'W4', render: formatPct },
117
+ { key: 'w8', label: 'W8', render: formatPct },
118
+ { key: 'w12', label: 'W12', render: formatPct },
119
+ ];</code-ui>
120
+ </section>
121
+
122
+ <section data-section data-property="variants-and-knobs">
123
+ <h2 variant="section">Variants &amp; knobs</h2>
124
+ <ul data-note>
125
+ <li><strong>Bucket thresholds.</strong> 60/30 works for most SaaS cohorts. For transactional products (food delivery, e-commerce), bump to 40/20 — those products have lower week-N retention by nature.</li>
126
+ <li><strong>Null cells.</strong> Return <code>''</code> for unreached weeks, never a zero or dash. An empty cell reads as "not yet known"; zero reads as "churned."</li>
127
+ <li><strong>Column set.</strong> Canonical columns: Signup week · Users · W1 · W2 · W3 · W4 · W8 · W12. Drop W3 if space is tight; don't drop W1 or W4 (baseline + first truly revealing bucket).</li>
128
+ <li><strong>Number of rows.</strong> 6–8 cohorts is the sweet spot. More becomes noise; fewer loses the trend.</li>
129
+ </ul>
130
+ </section>
131
+
132
+ <section data-section data-property="anti-patterns">
133
+ <h2 variant="section">Anti-patterns</h2>
134
+ <ul data-note>
135
+ <li><strong>Don't use a continuous color ramp.</strong> Three buckets read faster than a gradient — users can scan for "red" rows without decoding shades.</li>
136
+ <li><strong>Don't left-align the percentages.</strong> Numbers belong right-aligned (or center via the badge) so magnitudes line up vertically.</li>
137
+ <li><strong>Don't include the current (incomplete) cohort.</strong> The top row should be the most-recent cohort whose W1 is complete; otherwise its zero-ish numbers distort the visual trend.</li>
138
+ </ul>
139
+ </section>
140
+
141
+ <section data-section data-property="rules">
142
+ <h2 variant="section">Authoring rules</h2>
143
+ <ul>
144
+ <li><strong>Cohort axis (rows) = time of acquisition</strong> — typically week or month. The column axis = time since acquisition. Do not transpose this: readers expect cohorts as rows.</li>
145
+ <li><strong>Always color-code by retention rate, not absolute count.</strong> The heatmap's value is in visual comparison across cohorts; absolute numbers belong in tooltips, not cell backgrounds.</li>
146
+ <li><strong>Show at least 4 cohorts and 4 time periods</strong> for the diagonal comparison to be meaningful. A 2×2 heatmap adds no insight over a single number.</li>
147
+ <li><strong>Use <code>data-stream-src</code> for live cohort data</strong> — cohort heatmaps are expensive to compute; don't poll more frequently than the underlying aggregation window (usually daily).</li>
148
+ </ul>
149
+ </section>
@@ -0,0 +1,37 @@
1
+ /** Retention Cohort pattern — identical cell renderer used for all three tables. */
2
+
3
+ const formatPct = (v) => {
4
+ if (v == null) return '';
5
+ const n = Math.round(v);
6
+ const variant = n >= 60 ? 'success' : n >= 30 ? 'warning' : 'muted';
7
+ return `<badge-ui text="${n}%" variant="${variant}"></badge-ui>`;
8
+ };
9
+
10
+ const columns = [
11
+ { key: 'week', label: 'Signup week' },
12
+ { key: 'size', label: 'Users' },
13
+ { key: 'w1', label: 'W1', render: formatPct },
14
+ { key: 'w2', label: 'W2', render: formatPct },
15
+ { key: 'w3', label: 'W3', render: formatPct },
16
+ { key: 'w4', label: 'W4', render: formatPct },
17
+ { key: 'w8', label: 'W8', render: formatPct },
18
+ { key: 'w12', label: 'W12', render: formatPct },
19
+ ];
20
+
21
+ const data = [
22
+ { week: 'Jan 6', size: 420, w1: 100, w2: 78, w3: 62, w4: 54, w8: 41, w12: 32 },
23
+ { week: 'Jan 13', size: 480, w1: 100, w2: 82, w3: 68, w4: 58, w8: 45, w12: null },
24
+ { week: 'Jan 20', size: 510, w1: 100, w2: 80, w3: 66, w4: 57, w8: null, w12: null },
25
+ { week: 'Jan 27', size: 612, w1: 100, w2: 84, w3: 70, w4: null, w8: null, w12: null },
26
+ { week: 'Feb 3', size: 584, w1: 100, w2: 81, w3: null, w4: null, w8: null, w12: null },
27
+ { week: 'Feb 10', size: 640, w1: 100, w2: null, w3: null, w4: null, w8: null, w12: null },
28
+ ];
29
+
30
+ export default function setup(router) {
31
+ for (const id of ['pat-retention-default', 'pat-retention-legend', 'pat-retention-stats']) {
32
+ const table = router.querySelector(`#${id}`);
33
+ if (!table) continue;
34
+ table.columns = columns;
35
+ table.data = data;
36
+ }
37
+ }
@@ -0,0 +1,62 @@
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>Retention Cohort (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/badge/badge.css">
14
+ <link rel="stylesheet" href="../../components/card/card.css">
15
+ <link rel="stylesheet" href="../../components/code/code.css">
16
+ <link rel="stylesheet" href="../../components/grid/grid.css">
17
+ <link rel="stylesheet" href="../../components/row/row.css">
18
+ <link rel="stylesheet" href="../../components/stat/stat.css">
19
+ <link rel="stylesheet" href="../../components/table/table.css">
20
+ <link rel="stylesheet" href="../../components/tag/tag.css">
21
+ <link rel="stylesheet" href="../../components/text/text.css">
22
+
23
+ <!-- Component JS -->
24
+ <script type="module" src="../../components/badge/badge.js"></script>
25
+ <script type="module" src="../../components/card/card.js"></script>
26
+ <script type="module" src="../../components/code/code.js"></script>
27
+ <script type="module" src="../../components/grid/grid.js"></script>
28
+ <script type="module" src="../../components/row/row.js"></script>
29
+ <script type="module" src="../../components/stat/stat.js"></script>
30
+ <script type="module" src="../../components/table/table.js"></script>
31
+ <script type="module" src="../../components/tag/tag.js"></script>
32
+ <script type="module" src="../../components/text/text.js"></script>
33
+
34
+ <style>
35
+ :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); }
36
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
37
+ </style>
38
+ </head>
39
+ <body>
40
+
41
+ <main id="demo-root">
42
+ <p>Loading examples…</p>
43
+ </main>
44
+
45
+ <script type="module">
46
+ const root = document.getElementById('demo-root');
47
+ try {
48
+ const res = await fetch('./retention-cohort.examples.html');
49
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
50
+ root.innerHTML = await res.text();
51
+ try {
52
+ const mod = await import(/* @vite-ignore */ './retention-cohort.examples.js');
53
+ mod.default?.(root);
54
+ } catch (e) { console.error('[retention-cohort.html] setup failed:', e); }
55
+ } catch (err) {
56
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load retention-cohort.examples.html — ${err.message}</p>`;
57
+ console.error('[retention-cohort.html]', err);
58
+ }
59
+ </script>
60
+
61
+ </body>
62
+ </html>
@@ -0,0 +1,263 @@
1
+ <header>
2
+ <div>
3
+ <h1>Search &amp; Discovery</h1>
4
+ <div data-actions>
5
+ <tag-ui size="sm">card-ui</tag-ui> <tag-ui size="sm">search-ui</tag-ui> <tag-ui size="sm">tag-ui</tag-ui> <tag-ui size="sm">avatar-ui</tag-ui> <tag-ui size="sm">row-ui</tag-ui> <tag-ui size="sm">col-ui</tag-ui>
6
+ </div>
7
+ </div>
8
+ <p>The surfaces that surround a search input — what shows up below it. Result lists (flat and grouped), recent-searches menu, and saved-views list. Compose around <code>search-ui</code>; the input itself lives in its component demo.</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
+ Whenever a product surfaces a search input, three secondary
15
+ surfaces follow: results below the input, recents shown when the
16
+ input is focused but empty, and saved views (when users curate
17
+ queries). Most products use all three; smaller products skip
18
+ saved views.
19
+ </p>
20
+ </section>
21
+
22
+ <section data-section data-property="results-list">
23
+ <h2 variant="section">Result list</h2>
24
+ <p data-note>Flat ranked list. Each row carries a title, snippet, meta (author / date / type), and an optional trailing action. <code>list-ui</code> + <code>list-item-ui</code> with <code>tag-ui</code> for the type.</p>
25
+ <div data-artifact-container>
26
+ <div data-artifact-item data-artifact-label="search results list">
27
+ <card-ui data-chunk="search-results-list">
28
+ <header>
29
+ <span slot="heading" variant="section">42 results for "OKLCH tokens"</span>
30
+ <text-ui slot="description" color="subtle">Sorted by relevance · 0.18s</text-ui>
31
+ </header>
32
+ <section bleed>
33
+ <list-ui divider contained>
34
+ <list-item-ui text="Component Token Contract">
35
+ <span slot="description">"…all colors must reference --a-chrome-*, --a-data-0..9, or semantic tokens. Zero raw oklch in component CSS…"</span>
36
+ <tag-ui slot="action" size="sm">Spec</tag-ui>
37
+ </list-item-ui>
38
+ <list-item-ui text="2026-04-29 — primitive QA sweep">
39
+ <span slot="description">"…OKLCH-with-transparent red-shift bug fixed in Safari 18.0 (ADR-0007); we use oklab for color-mix instead…"</span>
40
+ <tag-ui slot="action" size="sm">Journal</tag-ui>
41
+ </list-item-ui>
42
+ <list-item-ui text="styles/tokens.css">
43
+ <span slot="description">"--a-primary-bg: oklch(64% 0.18 245); --a-primary-fg: oklch(98% 0.01 245)…"</span>
44
+ <tag-ui slot="action" size="sm">Code</tag-ui>
45
+ </list-item-ui>
46
+ <list-item-ui text="Reasoning About Color (skill)">
47
+ <span slot="description">"…OKLCH ramps that satisfy contrast, hue-stability, and perceptual-evenness…"</span>
48
+ <tag-ui slot="action" size="sm">Skill</tag-ui>
49
+ </list-item-ui>
50
+ </list-ui>
51
+ </section>
52
+ <footer divider>
53
+ <text-ui slot="description" color="subtle" size="sm">Showing 1–4 of 42</text-ui>
54
+ <button-ui slot="action" text="Load more" variant="ghost" size="sm" icon-trailing="arrow-down"></button-ui>
55
+ </footer>
56
+ </card-ui>
57
+ </div>
58
+ </div>
59
+ </section>
60
+
61
+ <section data-section data-property="results-grouped">
62
+ <h2 variant="section">Grouped results</h2>
63
+ <p data-note>Sectioned by type when the catalog is heterogeneous (Documents / People / Projects). Each group shows top 3–5; "See all in {group}" links to a filtered view.</p>
64
+ <div data-artifact-container>
65
+ <div data-artifact-item data-artifact-label="grouped search results">
66
+ <card-ui data-chunk="search-results-grouped" style="max-width: 640px;">
67
+ <header>
68
+ <span slot="heading" variant="section">"kim"</span>
69
+ <text-ui slot="description" color="subtle">Across people, documents, and projects</text-ui>
70
+ </header>
71
+ <section bleed>
72
+ <col-ui gap="0">
73
+ <row-ui align="center" gap="2" style="padding: var(--a-space-2) var(--a-space-3); background: var(--a-bg-subtle);">
74
+ <text-ui strong size="sm" color="subtle">People · 3</text-ui>
75
+ <button-ui text="See all" variant="ghost" size="sm" style="margin-inline-start: auto;"></button-ui>
76
+ </row-ui>
77
+ <list-ui divider contained>
78
+ <list-item-ui>
79
+ <row-ui gap="3" align="center">
80
+ <avatar-ui size="sm" text="Kim Granlund"></avatar-ui>
81
+ <col-ui gap="0" grow>
82
+ <text-ui strong>Kim Granlund</text-ui>
83
+ <text-ui color="subtle" size="sm">kim@example.com · Owner</text-ui>
84
+ </col-ui>
85
+ </row-ui>
86
+ </list-item-ui>
87
+ <list-item-ui>
88
+ <row-ui gap="3" align="center">
89
+ <avatar-ui size="sm" text="Kim Park"></avatar-ui>
90
+ <col-ui gap="0" grow>
91
+ <text-ui strong>Kim Park</text-ui>
92
+ <text-ui color="subtle" size="sm">kim.park@example.com · Member</text-ui>
93
+ </col-ui>
94
+ </row-ui>
95
+ </list-item-ui>
96
+ </list-ui>
97
+ <row-ui align="center" gap="2" style="padding: var(--a-space-2) var(--a-space-3); background: var(--a-bg-subtle); border-block-start: 1px solid var(--md-sys-color-neutral-outline-variant);">
98
+ <text-ui strong size="sm" color="subtle">Documents · 12</text-ui>
99
+ <button-ui text="See all" variant="ghost" size="sm" style="margin-inline-start: auto;"></button-ui>
100
+ </row-ui>
101
+ <list-ui divider contained>
102
+ <list-item-ui>
103
+ <col-ui gap="0">
104
+ <text-ui strong>Kim's onboarding plan</text-ui>
105
+ <text-ui color="subtle" size="sm">Edited 2 hours ago · by Avery</text-ui>
106
+ </col-ui>
107
+ </list-item-ui>
108
+ <list-item-ui>
109
+ <col-ui gap="0">
110
+ <text-ui strong>Kimchi recipe — team lunch</text-ui>
111
+ <text-ui color="subtle" size="sm">Edited 4 days ago · by Jordan</text-ui>
112
+ </col-ui>
113
+ </list-item-ui>
114
+ </list-ui>
115
+ <row-ui align="center" gap="2" style="padding: var(--a-space-2) var(--a-space-3); background: var(--a-bg-subtle); border-block-start: 1px solid var(--md-sys-color-neutral-outline-variant);">
116
+ <text-ui strong size="sm" color="subtle">Projects · 1</text-ui>
117
+ </row-ui>
118
+ <list-ui contained>
119
+ <list-item-ui>
120
+ <col-ui gap="0">
121
+ <text-ui strong>Kim's H2 roadmap</text-ui>
122
+ <text-ui color="subtle" size="sm">Updated yesterday · 5 active items</text-ui>
123
+ </col-ui>
124
+ </list-item-ui>
125
+ </list-ui>
126
+ </col-ui>
127
+ </section>
128
+ </card-ui>
129
+ </div>
130
+ </div>
131
+ </section>
132
+
133
+ <section data-section data-property="recents-menu">
134
+ <h2 variant="section">Recent searches menu</h2>
135
+ <p data-note>Popover that appears when the search input is focused but empty. Recent queries with most-recent-first ordering, a "Clear" action in the footer. Each row reruns the query on click; trailing icon dismisses a single entry.</p>
136
+ <div data-artifact-container>
137
+ <div data-artifact-item data-artifact-label="recent searches menu">
138
+ <card-ui data-chunk="search-recents-menu" style="max-width: 360px;">
139
+ <header>
140
+ <span slot="heading" variant="section">Recent</span>
141
+ </header>
142
+ <section bleed>
143
+ <list-ui divider contained>
144
+ <list-item-ui text="OKLCH tokens">
145
+ <icon-ui slot="icon" name="clock-counter-clockwise" size="sm"></icon-ui>
146
+ <button-ui slot="action" icon="x" variant="ghost" size="xs" aria-label="Dismiss"></button-ui>
147
+ </list-item-ui>
148
+ <list-item-ui text="primitive audit">
149
+ <icon-ui slot="icon" name="clock-counter-clockwise" size="sm"></icon-ui>
150
+ <button-ui slot="action" icon="x" variant="ghost" size="xs" aria-label="Dismiss"></button-ui>
151
+ </list-item-ui>
152
+ <list-item-ui text="drawer-ui safari fix">
153
+ <icon-ui slot="icon" name="clock-counter-clockwise" size="sm"></icon-ui>
154
+ <button-ui slot="action" icon="x" variant="ghost" size="xs" aria-label="Dismiss"></button-ui>
155
+ </list-item-ui>
156
+ <list-item-ui text="@scope hover bug">
157
+ <icon-ui slot="icon" name="clock-counter-clockwise" size="sm"></icon-ui>
158
+ <button-ui slot="action" icon="x" variant="ghost" size="xs" aria-label="Dismiss"></button-ui>
159
+ </list-item-ui>
160
+ </list-ui>
161
+ </section>
162
+ <footer divider>
163
+ <button-ui slot="action" text="Clear all recents" variant="ghost" size="sm" icon-leading="trash"></button-ui>
164
+ </footer>
165
+ </card-ui>
166
+ </div>
167
+ </div>
168
+ </section>
169
+
170
+ <section data-section data-property="saved-views">
171
+ <h2 variant="section">Saved views</h2>
172
+ <p data-note>List of curated queries the user has named and pinned. Each row shows the view name, a short description (or active filter chips), last-run time, and edit/share/delete actions. Used for "My open issues", "Q2 customer escalations", etc.</p>
173
+ <div data-artifact-container>
174
+ <div data-artifact-item data-artifact-label="saved views list">
175
+ <card-ui data-chunk="search-saved-views">
176
+ <header>
177
+ <span slot="heading" variant="section">Saved views</span>
178
+ <text-ui slot="description" color="subtle">5 views · last edited 2 days ago</text-ui>
179
+ <button-ui slot="action" text="Save current view" variant="primary" size="sm" icon-leading="bookmark-simple"></button-ui>
180
+ </header>
181
+ <section bleed>
182
+ <list-ui divider contained>
183
+ <list-item-ui>
184
+ <row-ui gap="3" align="start">
185
+ <col-ui gap="1" grow>
186
+ <text-ui strong>My open issues</text-ui>
187
+ <row-ui gap="1" wrap>
188
+ <tag-ui size="sm">assignee=me</tag-ui>
189
+ <tag-ui size="sm">status=open</tag-ui>
190
+ </row-ui>
191
+ </col-ui>
192
+ <text-ui color="subtle" size="sm">12 results · 3 min ago</text-ui>
193
+ </row-ui>
194
+ </list-item-ui>
195
+ <list-item-ui>
196
+ <row-ui gap="3" align="start">
197
+ <col-ui gap="1" grow>
198
+ <text-ui strong>Q2 customer escalations</text-ui>
199
+ <row-ui gap="1" wrap>
200
+ <tag-ui size="sm">label=customer</tag-ui>
201
+ <tag-ui size="sm">priority=p1</tag-ui>
202
+ <tag-ui size="sm">created≥2026-04-01</tag-ui>
203
+ </row-ui>
204
+ </col-ui>
205
+ <text-ui color="subtle" size="sm">7 results · today</text-ui>
206
+ </row-ui>
207
+ </list-item-ui>
208
+ <list-item-ui>
209
+ <row-ui gap="3" align="start">
210
+ <col-ui gap="1" grow>
211
+ <text-ui strong>Stale PRs</text-ui>
212
+ <row-ui gap="1" wrap>
213
+ <tag-ui size="sm">type=pr</tag-ui>
214
+ <tag-ui size="sm">updated&lt;30d</tag-ui>
215
+ <tag-ui size="sm">status=open</tag-ui>
216
+ </row-ui>
217
+ </col-ui>
218
+ <text-ui color="subtle" size="sm">23 results · 1 hour ago</text-ui>
219
+ </row-ui>
220
+ </list-item-ui>
221
+ <list-item-ui>
222
+ <row-ui gap="3" align="start">
223
+ <col-ui gap="1" grow>
224
+ <text-ui strong>Recent docs from team</text-ui>
225
+ <row-ui gap="1" wrap>
226
+ <tag-ui size="sm">type=doc</tag-ui>
227
+ <tag-ui size="sm">author∈team</tag-ui>
228
+ <tag-ui size="sm">edited≤7d</tag-ui>
229
+ </row-ui>
230
+ </col-ui>
231
+ <text-ui color="subtle" size="sm">31 results · 4 hours ago</text-ui>
232
+ </row-ui>
233
+ </list-item-ui>
234
+ </list-ui>
235
+ </section>
236
+ </card-ui>
237
+ </div>
238
+ </div>
239
+ </section>
240
+
241
+ <section data-section data-property="composition">
242
+ <h2 variant="section">Composition rules</h2>
243
+ <ul>
244
+ <li><strong>Result count + timing in the header</strong> — "42 results · 0.18s" reads as "the search worked"; bare lists feel uncertain.</li>
245
+ <li><strong>Snippets quote the source, not paraphrase</strong> — surrounding the matched term in the actual text builds trust faster than a synthesized summary.</li>
246
+ <li><strong>Group when the catalog is heterogeneous</strong> — flat is fine if all results share a type; group when "people / docs / projects" all share a query.</li>
247
+ <li><strong>Recents are queries, not results</strong> — clicking a recent re-runs the search, it doesn't open the previous result. The semantic distinction matters.</li>
248
+ <li><strong>Filter chips inside saved-view rows replace prose</strong> — "type=pr · updated&lt;30d" is faster to scan than "Pull requests updated in the last 30 days".</li>
249
+ <li><strong>Saved views are user-named</strong> — the system never auto-generates a name. "Untitled view" is the placeholder; users rename or discard.</li>
250
+ </ul>
251
+ </section>
252
+
253
+ <section data-section data-property="cross-references">
254
+ <h2 variant="section">See also</h2>
255
+ <ul>
256
+ <li><a href="/site/components/search">search-ui</a> — input primitive (debounce, default, name, placeholder, value).</li>
257
+ <li><a href="/site/components/list">list-ui</a> · <a href="/site/components/list-item">list-item-ui</a> — result-row anatomy.</li>
258
+ <li><a href="/site/components/menu">menu-ui</a> — recents menu surface.</li>
259
+ <li><a href="/site/components/command">command-ui</a> — Cmd+K palette (sibling to search).</li>
260
+ <li><a href="/site/patterns/filter-bar">filter-bar</a> — runtime filter system; saved views are persisted filter sets.</li>
261
+ <li><a href="/site/components/empty-state">empty-state-ui</a> — for "no results" surface.</li>
262
+ </ul>
263
+ </section>
@@ -0,0 +1,58 @@
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>Search &amp; Discovery (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/avatar/avatar.css">
14
+ <link rel="stylesheet" href="../../components/button/button.css">
15
+ <link rel="stylesheet" href="../../components/card/card.css">
16
+ <link rel="stylesheet" href="../../components/col/col.css">
17
+ <link rel="stylesheet" href="../../components/icon/icon.css">
18
+ <link rel="stylesheet" href="../../components/list/list.css">
19
+ <link rel="stylesheet" href="../../components/row/row.css">
20
+ <link rel="stylesheet" href="../../components/tag/tag.css">
21
+ <link rel="stylesheet" href="../../components/text/text.css">
22
+
23
+ <!-- Component JS -->
24
+ <script type="module" src="../../components/avatar/avatar.js"></script>
25
+ <script type="module" src="../../components/button/button.js"></script>
26
+ <script type="module" src="../../components/card/card.js"></script>
27
+ <script type="module" src="../../components/col/col.js"></script>
28
+ <script type="module" src="../../components/icon/icon.js"></script>
29
+ <script type="module" src="../../components/list/list.js"></script>
30
+ <script type="module" src="../../components/row/row.js"></script>
31
+ <script type="module" src="../../components/tag/tag.js"></script>
32
+ <script type="module" src="../../components/text/text.js"></script>
33
+
34
+ <style>
35
+ :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); }
36
+ main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
37
+ </style>
38
+ </head>
39
+ <body>
40
+
41
+ <main id="demo-root">
42
+ <p>Loading examples…</p>
43
+ </main>
44
+
45
+ <script type="module">
46
+ const root = document.getElementById('demo-root');
47
+ try {
48
+ const res = await fetch('./search-discovery.examples.html');
49
+ if (!res.ok) throw new Error(`fetch failed (${res.status})`);
50
+ root.innerHTML = await res.text();
51
+ } catch (err) {
52
+ root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load search-discovery.examples.html — ${err.message}</p>`;
53
+ console.error('[search-discovery.html]', err);
54
+ }
55
+ </script>
56
+
57
+ </body>
58
+ </html>