rizzo-css 0.0.31 → 0.0.32

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 (36) hide show
  1. package/README.md +1 -1
  2. package/bin/rizzo-css.js +6 -5
  3. package/package.json +1 -1
  4. package/scaffold/astro/Navbar.astro +12 -5
  5. package/scaffold/astro/Search.astro +36 -0
  6. package/scaffold/svelte/Navbar.svelte +19 -0
  7. package/scaffold/svelte/Search.svelte +51 -1
  8. package/scaffold/svelte/Settings.svelte +31 -4
  9. package/scaffold/vanilla/README-RIZZO.md +1 -1
  10. package/scaffold/vanilla/components/accordion.html +16 -0
  11. package/scaffold/vanilla/components/alert.html +16 -0
  12. package/scaffold/vanilla/components/avatar.html +16 -0
  13. package/scaffold/vanilla/components/badge.html +16 -0
  14. package/scaffold/vanilla/components/breadcrumb.html +16 -0
  15. package/scaffold/vanilla/components/button.html +16 -0
  16. package/scaffold/vanilla/components/cards.html +16 -0
  17. package/scaffold/vanilla/components/copy-to-clipboard.html +16 -0
  18. package/scaffold/vanilla/components/divider.html +16 -0
  19. package/scaffold/vanilla/components/dropdown.html +16 -0
  20. package/scaffold/vanilla/components/forms.html +16 -0
  21. package/scaffold/vanilla/components/icons.html +16 -0
  22. package/scaffold/vanilla/components/index.html +16 -0
  23. package/scaffold/vanilla/components/modal.html +16 -0
  24. package/scaffold/vanilla/components/navbar.html +16 -0
  25. package/scaffold/vanilla/components/pagination.html +16 -0
  26. package/scaffold/vanilla/components/progress-bar.html +16 -0
  27. package/scaffold/vanilla/components/search.html +16 -0
  28. package/scaffold/vanilla/components/settings.html +16 -0
  29. package/scaffold/vanilla/components/spinner.html +16 -0
  30. package/scaffold/vanilla/components/table.html +16 -0
  31. package/scaffold/vanilla/components/tabs.html +16 -0
  32. package/scaffold/vanilla/components/theme-switcher.html +16 -0
  33. package/scaffold/vanilla/components/toast.html +16 -0
  34. package/scaffold/vanilla/components/tooltip.html +16 -0
  35. package/scaffold/vanilla/index.html +16 -0
  36. package/scaffold/vanilla/js/main.js +40 -13
package/README.md CHANGED
@@ -61,7 +61,7 @@ import 'rizzo-css';
61
61
  **Without a bundler (plain HTML):** Use a CDN. Both unpkg and jsDelivr resolve the package root to the built CSS (via the `unpkg` / `jsdelivr` fields in this package). For reliability or to pin a version, use the explicit path:
62
62
 
63
63
  ```html
64
- <!-- unpkg (pin version: replace @latest with @0.0.31 or any version) -->
64
+ <!-- unpkg (pin version: replace @latest with @0.0.32 or any version) -->
65
65
  <link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />
66
66
 
67
67
  <!-- or jsDelivr -->
package/bin/rizzo-css.js CHANGED
@@ -42,7 +42,7 @@ const VANILLA_MINIMAL_README = `# Vanilla + Rizzo CSS (minimal)
42
42
  Minimal starter: HTML + CSS + js/main.js + recommended component pages. Scaffolded with \`npx rizzo-css init --framework vanilla --template minimal\`.
43
43
 
44
44
  - Open \`index.html\` in a browser or serve the folder. Edit \`index.html\` and add your content. CSS: \`css/rizzo.min.css\`. Script: \`js/main.js\` (already linked).
45
- - \`components/\` contains HTML pages for the recommended set (Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown). Open \`components/index.html\` to browse them.
45
+ - \`components/\` contains HTML pages for the recommended set (Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown, Navbar, Search, Settings, Accordion, CopyToClipboard). Open \`components/index.html\` to browse them.
46
46
  - Set a theme: \`<html data-theme="github-dark-classic">\` (see \`npx rizzo-css theme\` for all themes).
47
47
  - For the full component showcase and icons, use template **Full** or copy from a Full scaffold.
48
48
 
@@ -109,13 +109,14 @@ const ASTRO_COMPONENTS = [
109
109
  'Navbar', 'Settings', 'Search', 'Icons',
110
110
  ];
111
111
 
112
- // Recommended subset for Full/Minimal (same for Astro, Svelte, Vanilla)
112
+ // Recommended subset for Full/Minimal (same for Astro, Svelte, Vanilla). Includes all interactive components.
113
113
  const RECOMMENDED_COMPONENTS = [
114
114
  'Button', 'Badge', 'Card', 'Modal', 'Tabs', 'ThemeSwitcher', 'FormGroup', 'Alert', 'Toast', 'Dropdown',
115
+ 'Navbar', 'Search', 'Settings', 'Accordion', 'CopyToClipboard',
115
116
  ];
116
117
 
117
- // Vanilla components that need js/main.js for interactivity (modal, dropdown, tabs, toast, search, navbar mobile, copy-to-clipboard, theme switcher).
118
- const VANILLA_JS_COMPONENTS = ['Modal', 'Dropdown', 'Tabs', 'Toast', 'ThemeSwitcher'];
118
+ // Vanilla components that need js/main.js for interactivity.
119
+ const VANILLA_JS_COMPONENTS = ['Modal', 'Dropdown', 'Tabs', 'Toast', 'ThemeSwitcher', 'Search', 'Accordion', 'CopyToClipboard', 'Navbar', 'Settings'];
119
120
 
120
121
  // Component dependencies per framework: when user selects a component, these are copied automatically so it works.
121
122
  // Manual users can run: npx rizzo-css help components
@@ -983,7 +984,7 @@ async function promptComponentChoice(componentList, framework, initialSelection)
983
984
  const choice = await selectMenu(
984
985
  [
985
986
  { value: 'none', label: 'CSS only — no components' },
986
- { value: 'recommended', label: 'Recommended set (' + recommended.length + ' components: Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown)' },
987
+ { value: 'recommended', label: 'Recommended set (' + recommended.length + ' components: Button, Badge, Card, Modal, Tabs, ThemeSwitcher, FormGroup, Alert, Toast, Dropdown, Navbar, Search, Settings, Accordion, CopyToClipboard)' },
987
988
  { value: 'all', label: 'All components (' + componentList.length + ')' },
988
989
  { value: 'pick', label: 'Pick components (choose each one)' },
989
990
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rizzo-css",
3
- "version": "0.0.31",
3
+ "version": "0.0.32",
4
4
  "scripts": {
5
5
  "prepublishOnly": "cd ../.. && pnpm run lint:css:fix && pnpm run build:css && node scripts/copy-scaffold.js && node scripts/prepare-vanilla-scaffold.js"
6
6
  },
@@ -42,11 +42,22 @@ const { siteName = 'Site', logo } = Astro.props;
42
42
  var toggle = document.getElementById('navbar-toggle');
43
43
  var menu = navbar.querySelector('.navbar__menu');
44
44
  if (!toggle || !menu) return;
45
+ var outsideClickHandler = null;
45
46
  function setMenuOpen(open) {
46
47
  menu.classList.toggle('navbar__menu--open', open);
47
48
  navbar.classList.toggle('navbar--menu-open', open);
48
49
  toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
49
50
  menu.setAttribute('aria-hidden', open ? 'false' : 'true');
51
+ if (outsideClickHandler) {
52
+ document.removeEventListener('click', outsideClickHandler);
53
+ outsideClickHandler = null;
54
+ }
55
+ if (open) {
56
+ outsideClickHandler = function (e) {
57
+ if (e.target && !navbar.contains(e.target)) setMenuOpen(false);
58
+ };
59
+ setTimeout(function () { document.addEventListener('click', outsideClickHandler); }, 0);
60
+ }
50
61
  }
51
62
  toggle.addEventListener('click', function () {
52
63
  setMenuOpen(!menu.classList.contains('navbar__menu--open'));
@@ -55,11 +66,7 @@ const { siteName = 'Site', logo } = Astro.props;
55
66
  link.addEventListener('click', function () { setMenuOpen(false); });
56
67
  });
57
68
  document.addEventListener('keydown', function (e) {
58
- if (e.key === 'Escape') {
59
- if (menu.classList.contains('navbar__menu--open')) {
60
- setMenuOpen(false);
61
- }
62
- }
69
+ if (e.key === 'Escape' && menu.classList.contains('navbar__menu--open')) setMenuOpen(false);
63
70
  });
64
71
  }
65
72
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
@@ -13,28 +13,64 @@ const { id = 'search-main' } = Astro.props;
13
13
  <div class="search__overlay" id="{id}-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
14
14
  <div class="search__panel">
15
15
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
16
+ <div class="search__results" role="listbox" aria-label="Search results">
17
+ <div class="search__empty">
18
+ <p class="search__empty-text">Start typing to search…</p>
19
+ </div>
20
+ <div class="search__results-list" role="group" aria-label="Sample results">
21
+ <a href="#" class="search__result-item" tabindex="-1" data-search-result-item><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
22
+ <a href="#" class="search__result-item" tabindex="-1" data-search-result-item><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
23
+ <a href="#" class="search__result-item" tabindex="-1" data-search-result-item><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
24
+ </div>
25
+ </div>
16
26
  </div>
17
27
  </div>
18
28
  </div>
19
29
 
20
30
  <script>
21
31
  (function initSearch() {
32
+ var focusableSel = 'button:not([disabled]),a[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
33
+ function getFocusable(container) {
34
+ return Array.prototype.slice.call(container.querySelectorAll(focusableSel));
35
+ }
22
36
  function init() {
23
37
  document.querySelectorAll('[data-search]').forEach(function (search) {
24
38
  if (search.__searchInited) return;
25
39
  search.__searchInited = true;
26
40
  var trigger = search.querySelector('.search__trigger');
27
41
  var overlay = search.querySelector('[data-search-overlay]');
42
+ var panel = search.querySelector('.search__panel');
28
43
  var input = search.querySelector('.search__input');
44
+ var resultItems = search.querySelectorAll('.search__result-item, [data-search-result-item]');
29
45
  if (!trigger || !overlay || !input) return;
30
46
  var previousActive = null;
47
+ var focusTrapHandler = null;
31
48
  function openSearch() {
32
49
  previousActive = document.activeElement;
33
50
  overlay.setAttribute('aria-hidden', 'false');
34
51
  trigger.setAttribute('aria-expanded', 'true');
52
+ for (var i = 0; i < resultItems.length; i++) resultItems[i].setAttribute('tabindex', '0');
35
53
  input.focus();
54
+ focusTrapHandler = function (e) {
55
+ if (overlay.getAttribute('aria-hidden') === 'true') return;
56
+ if (e.key === 'Escape') { e.preventDefault(); closeSearch(); return; }
57
+ if (e.key === 'Tab' && panel) {
58
+ var els = getFocusable(panel);
59
+ if (els.length === 0) return;
60
+ var first = els[0], last = els[els.length - 1], active = document.activeElement;
61
+ if (e.shiftKey) {
62
+ if (active === first || !panel.contains(active)) { e.preventDefault(); last.focus(); }
63
+ } else {
64
+ if (active === last || !panel.contains(active)) { e.preventDefault(); first.focus(); }
65
+ }
66
+ }
67
+ };
68
+ document.addEventListener('keydown', focusTrapHandler);
36
69
  }
37
70
  function closeSearch() {
71
+ document.removeEventListener('keydown', focusTrapHandler);
72
+ focusTrapHandler = null;
73
+ for (var i = 0; i < resultItems.length; i++) resultItems[i].setAttribute('tabindex', '-1');
38
74
  overlay.setAttribute('aria-hidden', 'true');
39
75
  trigger.setAttribute('aria-expanded', 'false');
40
76
  if (previousActive && previousActive.focus) previousActive.focus();
@@ -9,6 +9,25 @@
9
9
  }
10
10
  let { siteName = 'Site', logo }: Props = $props();
11
11
  let menuOpen = $state(false);
12
+
13
+ // Click outside and Escape to close mobile menu
14
+ $effect(() => {
15
+ if (!menuOpen) return;
16
+ const onEscape = (e: KeyboardEvent) => {
17
+ if (e.key === 'Escape') menuOpen = false;
18
+ };
19
+ const onClick = (e: MouseEvent) => {
20
+ const target = e.target as Node;
21
+ if (target && !(target as Element).closest?.('.navbar')) menuOpen = false;
22
+ };
23
+ document.addEventListener('keydown', onEscape);
24
+ const t = setTimeout(() => document.addEventListener('click', onClick), 0);
25
+ return () => {
26
+ document.removeEventListener('keydown', onEscape);
27
+ document.removeEventListener('click', onClick);
28
+ clearTimeout(t);
29
+ };
30
+ });
12
31
  </script>
13
32
 
14
33
  <nav class="navbar" role="navigation" aria-label="Main navigation">
@@ -5,6 +5,45 @@
5
5
  let { id = 'search-main' }: Props = $props();
6
6
  let open = $state(false);
7
7
  let query = $state('');
8
+ let panelEl = $state<HTMLElement | null>(null);
9
+
10
+ const FOCUSABLE_SEL = 'button:not([disabled]),a[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
11
+
12
+ function getFocusable(container: HTMLElement | null): HTMLElement[] {
13
+ if (!container) return [];
14
+ return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SEL));
15
+ }
16
+
17
+ $effect(() => {
18
+ if (!open) return;
19
+ const onKeydown = (e: KeyboardEvent) => {
20
+ if (e.key === 'Escape') {
21
+ e.preventDefault();
22
+ open = false;
23
+ return;
24
+ }
25
+ if (e.key === 'Tab' && panelEl) {
26
+ const els = getFocusable(panelEl);
27
+ if (els.length === 0) return;
28
+ const first = els[0];
29
+ const last = els[els.length - 1];
30
+ const active = document.activeElement as HTMLElement;
31
+ if (e.shiftKey) {
32
+ if (active === first || !panelEl.contains(active)) {
33
+ e.preventDefault();
34
+ last.focus();
35
+ }
36
+ } else {
37
+ if (active === last || !panelEl.contains(active)) {
38
+ e.preventDefault();
39
+ first.focus();
40
+ }
41
+ }
42
+ }
43
+ };
44
+ document.addEventListener('keydown', onKeydown);
45
+ return () => document.removeEventListener('keydown', onKeydown);
46
+ });
8
47
  </script>
9
48
 
10
49
  <div class="search" data-search>
@@ -27,8 +66,9 @@
27
66
  role="dialog"
28
67
  aria-modal="true"
29
68
  data-search-overlay
69
+ onclick={(e) => (e.target as HTMLElement) === (e.currentTarget as HTMLElement) && (open = false)}
30
70
  >
31
- <div class="search__panel">
71
+ <div class="search__panel" bind:this={panelEl}>
32
72
  <input
33
73
  type="search"
34
74
  class="search__input"
@@ -36,6 +76,16 @@
36
76
  aria-label="Search"
37
77
  bind:value={query}
38
78
  />
79
+ <div class="search__results" role="listbox" aria-label="Search results">
80
+ <div class="search__empty">
81
+ <p class="search__empty-text">Start typing to search…</p>
82
+ </div>
83
+ <div class="search__results-list" role="group" aria-label="Sample results">
84
+ <a href="#" class="search__result-item" tabindex={open ? 0 : -1}><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
85
+ <a href="#" class="search__result-item" tabindex={open ? 0 : -1}><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
86
+ <a href="#" class="search__result-item" tabindex={open ? 0 : -1}><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
87
+ </div>
88
+ </div>
39
89
  </div>
40
90
  </div>
41
91
  </div>
@@ -2,24 +2,51 @@
2
2
  interface Props {
3
3
  open?: boolean;
4
4
  }
5
- let { open = false }: Props = $props();
5
+ let { open: openProp }: Props = $props();
6
+ let openInternal = $state(false);
7
+ const open = $derived(openProp !== undefined ? openProp : openInternal);
8
+
9
+ $effect(() => {
10
+ (window as unknown as { openSettings?: () => void }).openSettings = () => {
11
+ openInternal = true;
12
+ };
13
+ return () => {
14
+ if ((window as unknown as { openSettings?: () => void }).openSettings) {
15
+ delete (window as unknown as { openSettings?: () => void }).openSettings;
16
+ }
17
+ };
18
+ });
19
+
20
+ $effect(() => {
21
+ if (!open) return;
22
+ const onEscape = (e: KeyboardEvent) => {
23
+ if (e.key === 'Escape') openInternal = false;
24
+ };
25
+ document.addEventListener('keydown', onEscape);
26
+ return () => document.removeEventListener('keydown', onEscape);
27
+ });
28
+
29
+ function close() {
30
+ openInternal = false;
31
+ }
6
32
  </script>
7
33
 
8
34
  <div class="settings" data-settings aria-hidden={!open}>
9
- <div class="settings__overlay" data-settings-overlay aria-hidden={!open}></div>
35
+ <div class="settings__overlay" data-settings-overlay aria-hidden={!open} onclick={close}></div>
10
36
  <div
11
37
  class="settings__panel"
12
38
  role="dialog"
13
39
  aria-modal="true"
14
40
  aria-labelledby="settings-title"
15
41
  aria-hidden={!open}
42
+ data-open={open ? 'true' : undefined}
16
43
  >
17
44
  <div class="settings__header">
18
45
  <h2 id="settings-title" class="settings__title">Settings</h2>
19
- <button type="button" class="settings__close" data-settings-close aria-label="Close">×</button>
46
+ <button type="button" class="settings__close" data-settings-close aria-label="Close settings" onclick={close}>×</button>
20
47
  </div>
21
48
  <div class="settings__content">
22
- <p>Theme, font size, and accessibility options. Wire to your state and <code>window.openSettings</code>.</p>
49
+ <p>Theme, font size, and accessibility options. Wire to your state or use <code>window.openSettings</code>.</p>
23
50
  </div>
24
51
  </div>
25
52
  </div>
@@ -13,7 +13,7 @@ If you prefer to load CSS from a CDN instead of the local file, replace the `<li
13
13
  - `<link rel="stylesheet" href="https://unpkg.com/rizzo-css@latest/dist/rizzo.min.css" />`
14
14
  - Or jsDelivr: `https://cdn.jsdelivr.net/npm/rizzo-css@latest/dist/rizzo.min.css`
15
15
 
16
- (Replace `@latest` with a specific version, e.g. `@0.0.31`, in production.)
16
+ (Replace `@latest` with a specific version, e.g. `@0.0.32`, in production.)
17
17
 
18
18
  The CLI replaces placeholders in `index.html` (e.g. `{{DATA_THEME}}`, `{{TITLE}}`) when you run `rizzo-css init`. The theme selected during init is used on first load when you have no saved preference in the browser.
19
19
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353
 
@@ -60,6 +60,16 @@
60
60
  <div class="search__overlay" id="search-header-panel" aria-hidden="true" role="dialog" aria-modal="true" data-search-overlay>
61
61
  <div class="search__panel">
62
62
  <input type="search" class="search__input" placeholder="Search…" aria-label="Search" />
63
+ <div class="search__results" role="listbox" aria-label="Search results">
64
+ <div class="search__empty">
65
+ <p class="search__empty-text">Start typing to search…</p>
66
+ </div>
67
+ <div class="search__results-list" role="group" aria-label="Sample results">
68
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Getting started</div></a>
69
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Components</div></a>
70
+ <a href="#" class="search__result-item" tabindex="-1"><div class="search__result-category">Docs</div><div class="search__result-title">Theming</div></a>
71
+ </div>
72
+ </div>
63
73
  </div>
64
74
  </div>
65
75
  </div>
@@ -249,6 +259,9 @@
249
259
 
250
260
 
251
261
 
262
+
263
+
264
+
252
265
 
253
266
 
254
267
 
@@ -332,6 +345,9 @@
332
345
 
333
346
 
334
347
 
348
+
349
+
350
+
335
351
 
336
352
 
337
353