@ismail-elkorchi/ui-shell 0.1.1 → 0.2.0

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 (44) hide show
  1. package/README.md +117 -30
  2. package/dist/custom-elements.json +487 -120
  3. package/dist/index.d.ts +10 -8
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +7 -6
  6. package/dist/index.js.map +1 -1
  7. package/dist/register.d.ts +5 -5
  8. package/dist/register.d.ts.map +1 -1
  9. package/dist/register.js +5 -5
  10. package/dist/register.js.map +1 -1
  11. package/dist/src/internal/command-center.d.ts +32 -0
  12. package/dist/src/internal/command-center.d.ts.map +1 -0
  13. package/dist/src/internal/command-center.js +169 -0
  14. package/dist/src/internal/command-center.js.map +1 -0
  15. package/dist/src/internal/light-dom-slot-controller.d.ts.map +1 -1
  16. package/dist/src/internal/light-dom-slot-controller.js +14 -13
  17. package/dist/src/internal/light-dom-slot-controller.js.map +1 -1
  18. package/dist/src/internal/router.d.ts +9 -0
  19. package/dist/src/internal/router.d.ts.map +1 -1
  20. package/dist/src/internal/router.js +14 -4
  21. package/dist/src/internal/router.js.map +1 -1
  22. package/dist/src/structures/uik-shell-activity-bar-contract.d.ts +1 -1
  23. package/dist/src/structures/uik-shell-activity-bar-contract.d.ts.map +1 -1
  24. package/dist/src/structures/uik-shell-activity-bar.d.ts +25 -15
  25. package/dist/src/structures/uik-shell-activity-bar.d.ts.map +1 -1
  26. package/dist/src/structures/uik-shell-activity-bar.js +89 -213
  27. package/dist/src/structures/uik-shell-activity-bar.js.map +1 -1
  28. package/dist/src/structures/uik-shell-layout.d.ts +21 -2
  29. package/dist/src/structures/uik-shell-layout.d.ts.map +1 -1
  30. package/dist/src/structures/uik-shell-layout.js +144 -54
  31. package/dist/src/structures/uik-shell-layout.js.map +1 -1
  32. package/dist/src/structures/uik-shell-secondary-sidebar.d.ts +34 -4
  33. package/dist/src/structures/uik-shell-secondary-sidebar.d.ts.map +1 -1
  34. package/dist/src/structures/uik-shell-secondary-sidebar.js +207 -70
  35. package/dist/src/structures/uik-shell-secondary-sidebar.js.map +1 -1
  36. package/dist/src/structures/uik-shell-sidebar.d.ts +27 -4
  37. package/dist/src/structures/uik-shell-sidebar.d.ts.map +1 -1
  38. package/dist/src/structures/uik-shell-sidebar.js +161 -84
  39. package/dist/src/structures/uik-shell-sidebar.js.map +1 -1
  40. package/dist/src/structures/uik-shell-status-bar.d.ts +23 -4
  41. package/dist/src/structures/uik-shell-status-bar.d.ts.map +1 -1
  42. package/dist/src/structures/uik-shell-status-bar.js +105 -56
  43. package/dist/src/structures/uik-shell-status-bar.js.map +1 -1
  44. package/package.json +17 -4
package/README.md CHANGED
@@ -9,21 +9,43 @@ Token-driven shell components (activity bar, sidebars, status bar, and an option
9
9
  - Shell components expose only UI surface/state; business logic should live in the host app.
10
10
  - **Contract**: Shell components use `ui-primitives` strictly via their public API (attributes/props). Visual styling comes from `--uik-*` custom properties (no framework utility classes).
11
11
 
12
+ ## Landmarks & labels (Accessibility contract)
13
+
14
+ - `uik-shell-layout` renders a `role="region"` container; override its label via `aria-label` or `aria-labelledby` on the host.
15
+ - `uik-shell-activity-bar` renders an `<aside>` landmark and forwards `aria-label`/`aria-labelledby` to the internal nav rail; default label is "Activity bar".
16
+ - `uik-shell-sidebar` and `uik-shell-secondary-sidebar` render `<aside>` landmarks; default labels come from the `heading` or fall back to "Sidebar"/"Secondary sidebar".
17
+ - `uik-shell-status-bar` uses `role="status"` with `aria-live="polite"` for status messages.
18
+ - Provide a semantic `<main>` element in the `main-content` slot and label additional landmarks as needed in host markup.
19
+
20
+ ## Focus + roving focus
21
+
22
+ - Shell navigation surfaces delegate roving focus to primitives (`uik-nav-rail`, `uik-tree-view`) and do not add competing keyboard handlers.
23
+ - Follow the Focus + Roving Focus contract in `@ismail-elkorchi/ui-primitives` when composing activity bars or navigation trees.
24
+
25
+ ## Overlay close semantics
26
+
27
+ - Overlay-like shells emit close events with `detail.reason` aligned to primitives: `escape | outside | programmatic | toggle`.
28
+ - `uik-shell-secondary-sidebar` captures the previously focused element on open and restores focus on close (unless a `focus-return-target` is provided).
29
+
12
30
  ## Using the components
13
31
 
14
32
  ```ts
15
- import {html} from 'lit';
16
- import '@ismail-elkorchi/ui-primitives/register';
17
- import '@ismail-elkorchi/ui-shell/register';
18
- import type {UikShellActivityBarItem} from '@ismail-elkorchi/ui-shell/activity-bar';
33
+ import { html } from "lit";
34
+ import "@ismail-elkorchi/ui-primitives/register";
35
+ import "@ismail-elkorchi/ui-shell/register";
36
+ import type { UikShellActivityBarItem } from "@ismail-elkorchi/ui-shell/activity-bar";
19
37
 
20
38
  const activityItems: UikShellActivityBarItem[] = [
21
39
  {
22
- id: 'explorer',
23
- label: 'Explorer',
24
- icon: 'M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z'
40
+ id: "explorer",
41
+ label: "Explorer",
42
+ icon: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",
43
+ },
44
+ {
45
+ id: "search",
46
+ label: "Search",
47
+ icon: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z",
25
48
  },
26
- {id: 'search', label: 'Search', icon: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z'}
27
49
  ];
28
50
 
29
51
  html`
@@ -31,8 +53,10 @@ html`
31
53
  <uik-shell-activity-bar
32
54
  slot="activity-bar"
33
55
  .items=${activityItems}
34
- .activeId=${'explorer'}
35
- @activity-bar-select=${(e: CustomEvent<{id: string}>) => console.log(e.detail.id)}>
56
+ .activeId=${"explorer"}
57
+ @activity-bar-select=${(e: CustomEvent<{ id: string }>) =>
58
+ console.log(e.detail.id)}
59
+ >
36
60
  </uik-shell-activity-bar>
37
61
  <uik-shell-sidebar slot="primary-sidebar" heading="Explorer">
38
62
  <uik-button slot="actions" variant="ghost" size="icon">…</uik-button>
@@ -40,23 +64,33 @@ html`
40
64
  <!-- put your tree view or navigation here -->
41
65
  </div>
42
66
  </uik-shell-sidebar>
43
- <main slot="main-content" style="flex: 1 1 auto; min-height: var(--uik-space-0);">
67
+ <main
68
+ slot="main-content"
69
+ style="flex: 1 1 auto; min-height: var(--uik-space-0);"
70
+ >
44
71
  Your editor or subviews
45
72
  </main>
46
73
  <uik-shell-secondary-sidebar
47
74
  slot="secondary-sidebar"
48
75
  .isOpen=${true}
49
76
  heading="AI Assistant"
50
- @secondary-sidebar-close=${() => console.log('close secondary')}>
77
+ @secondary-sidebar-close=${() => console.log("close secondary")}
78
+ >
51
79
  <p
52
80
  style="
53
81
  font-size: var(--uik-typography-font-size-2);
54
82
  color: oklch(var(--uik-text-muted));
55
- ">
83
+ "
84
+ >
56
85
  Auxiliary tools live here.
57
86
  </p>
58
87
  </uik-shell-secondary-sidebar>
59
- <uik-shell-status-bar slot="status-bar" message="Ready" tone="info" meta="3 files selected"></uik-shell-status-bar>
88
+ <uik-shell-status-bar
89
+ slot="status-bar"
90
+ message="Ready"
91
+ tone="info"
92
+ meta="3 files selected"
93
+ ></uik-shell-status-bar>
60
94
  </uik-shell-layout>
61
95
  `;
62
96
  ```
@@ -64,15 +98,15 @@ html`
64
98
  ### Component notes
65
99
 
66
100
  - `uik-shell-layout`: named slots `activity-bar`, `primary-sidebar`, `main-content`, `secondary-sidebar`, `status-bar`.
67
- - `uik-shell-activity-bar`: accepts `.items` (id/label/icon/path) and emits `activity-bar-select`; optional `footer` slot; roving focus with Arrow keys/Home/End and Enter/Space activation (set `aria-label` if you need a custom name).
101
+ - `uik-shell-activity-bar`: accepts `.items` (id/label/icon/path) and emits `activity-bar-select`; optional `footer` slot; delegates roving focus to `uik-nav-rail` (set `aria-label` if you need a custom name).
68
102
  - `uik-shell-sidebar`: `slot="actions"` for header actions, default slot for body, optional `slot="footer"`; `isBodyPadded`/`isBodyScrollable` toggle spacing + scroll.
69
- - `uik-shell-secondary-sidebar`: controlled via `.isOpen`; default slot for body, optional `slot="footer"`; emits `secondary-sidebar-close` on close.
103
+ - `uik-shell-secondary-sidebar`: controlled via `.isOpen`; optional `focus-return-target` (selector or element) to restore focus on close; Escape and the close button emit `secondary-sidebar-close` (`detail.reason` is `escape | toggle`).
70
104
  - `uik-shell-status-bar`: `.message` + `.tone` colorize the left side; `meta` string (outline badge) or `slot="meta"` for custom content; optional `slot="actions"`.
71
105
  - Use `@ismail-elkorchi/ui-primitives/uik-nav` or `@ismail-elkorchi/ui-primitives/uik-tree-view` for sidebar navigation content.
72
106
 
73
107
  ### Custom properties
74
108
 
75
- - Activity bar: `--uik-component-shell-activity-bar-bg`, `--uik-component-shell-activity-bar-fg`, `--uik-component-shell-activity-bar-width`.
109
+ - Activity bar: `--uik-component-shell-activity-bar-bg`, `--uik-component-shell-activity-bar-fg`, `--uik-component-shell-activity-bar-width`, `--uik-component-shell-activity-bar-item-size`, `--uik-component-shell-activity-bar-item-icon-size`, `--uik-component-shell-activity-bar-item-indicator-bg`, `--uik-component-shell-activity-bar-item-indicator-radius`, `--uik-component-shell-activity-bar-item-indicator-width`.
76
110
  - Sidebar: `--uik-component-shell-sidebar-bg`, `--uik-component-shell-sidebar-fg`, `--uik-component-shell-sidebar-width`.
77
111
  - Secondary sidebar: `--uik-component-shell-secondary-sidebar-bg`, `--uik-component-shell-secondary-sidebar-width`.
78
112
  - Status bar: `--uik-component-shell-status-bar-bg`, `--uik-component-shell-status-bar-fg`, `--uik-component-shell-status-bar-height`.
@@ -83,7 +117,7 @@ html`
83
117
  Load tokens once and set theme/density attributes on a shared container (often `:root`):
84
118
 
85
119
  ```css
86
- @import '@ismail-elkorchi/ui-tokens/index.css';
120
+ @import "@ismail-elkorchi/ui-tokens/index.css";
87
121
  ```
88
122
 
89
123
  ```html
@@ -92,38 +126,91 @@ Load tokens once and set theme/density attributes on a shared container (often `
92
126
  </html>
93
127
  ```
94
128
 
129
+ ## Command center
130
+
131
+ Wire a global command palette to app commands with `createUikCommandCenter`. It handles Ctrl/Cmd+K by default, manages open/close state, and keeps trigger ARIA attributes in sync.
132
+
133
+ ```ts
134
+ import type { UikCommandPalette } from "@ismail-elkorchi/ui-primitives";
135
+ import {
136
+ createUikCommandCenter,
137
+ type UikCommandCenterCommand,
138
+ } from "@ismail-elkorchi/ui-shell/command-center";
139
+
140
+ const palette = document.querySelector(
141
+ "uik-command-palette",
142
+ ) as UikCommandPalette;
143
+
144
+ const commands: UikCommandCenterCommand[] = [
145
+ {
146
+ id: "docs-tokens",
147
+ label: "Tokens reference",
148
+ description: "Jump to the tokens docs.",
149
+ value: "docs/tokens",
150
+ },
151
+ ];
152
+
153
+ const commandCenter = createUikCommandCenter({
154
+ palette,
155
+ commands,
156
+ onSelect: (command) => {
157
+ if (!command.value) return;
158
+ const [view, subview] = command.value.split("/");
159
+ console.log("Navigate", view, subview);
160
+ },
161
+ });
162
+
163
+ commandCenter.setOpenButton(document.querySelector("[data-command-trigger]"));
164
+ ```
165
+
95
166
  ## Routing store
96
167
 
97
168
  A tiny EventTarget-based router lives in `@ismail-elkorchi/ui-shell/router`. It is framework-light, keeps state in memory (no history), and is meant for desktop flows that only need named views and optional subviews.
98
169
 
99
170
  ```ts
100
- import {createUikShellRouter, UIK_SHELL_NAVIGATION_EVENT, type UikShellNavigationDetail} from '@ismail-elkorchi/ui-shell/router';
171
+ import {
172
+ createUikShellRouter,
173
+ UIK_SHELL_NAVIGATION_EVENT,
174
+ type UikShellNavigationDetail,
175
+ } from "@ismail-elkorchi/ui-shell/router";
101
176
 
102
177
  const routes = [
103
- {id: 'explorer', label: 'Explorer', subviews: ['code', 'prompt', 'apply'], defaultSubview: 'code'},
104
- {id: 'search', label: 'Search'},
105
- {id: 'settings', label: 'Settings'}
178
+ {
179
+ id: "explorer",
180
+ label: "Explorer",
181
+ subviews: ["code", "prompt", "apply"],
182
+ defaultSubview: "code",
183
+ },
184
+ { id: "search", label: "Search" },
185
+ { id: "settings", label: "Settings" },
106
186
  ] as const;
107
187
 
108
- export const shellRouter = createUikShellRouter({routes, initialView: 'explorer', initialSubview: 'code'});
188
+ export const shellRouter = createUikShellRouter({
189
+ routes,
190
+ initialView: "explorer",
191
+ initialSubview: "code",
192
+ });
109
193
 
110
194
  // React to navigation anywhere in the app
111
- const unsubscribe = shellRouter.subscribe(({view, subview}) => {
112
- console.log('Current location', view, subview);
195
+ const unsubscribe = shellRouter.subscribe(({ view, subview }) => {
196
+ console.log("Current location", view, subview);
113
197
  });
114
198
 
115
199
  // Wire Lit components through events
116
200
  html`
117
201
  <uik-shell-activity-bar
118
- .items=${routes.map(r => ({id: r.id, label: r.label ?? r.id}))}
202
+ .items=${routes.map((r) => ({ id: r.id, label: r.label ?? r.id }))}
119
203
  .activeId=${shellRouter.current.view}
120
- @activity-bar-select=${(e: CustomEvent<{id: string}>) => shellRouter.navigate(e.detail.id)}>
204
+ @activity-bar-select=${(e: CustomEvent<{ id: string }>) =>
205
+ shellRouter.navigate(e.detail.id)}
206
+ >
121
207
  </uik-shell-activity-bar>
122
208
 
123
209
  <editor-area
124
- .activeSubview=${shellRouter.current.subview ?? 'code'}
125
- @subview-change=${(e: CustomEvent<{subview: string}>) =>
126
- shellRouter.navigate(shellRouter.current.view, e.detail.subview)}>
210
+ .activeSubview=${shellRouter.current.subview ?? "code"}
211
+ @subview-change=${(e: CustomEvent<{ subview: string }>) =>
212
+ shellRouter.navigate(shellRouter.current.view, e.detail.subview)}
213
+ >
127
214
  </editor-area>
128
215
  `;
129
216