@ismail-elkorchi/ui-shell 0.1.0 → 0.1.2

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 (68) hide show
  1. package/README.md +134 -81
  2. package/dist/custom-elements.json +1333 -0
  3. package/dist/index.d.ts +8 -6
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +6 -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/light-dom-slot-controller.d.ts +22 -0
  12. package/dist/src/internal/light-dom-slot-controller.d.ts.map +1 -0
  13. package/dist/src/internal/light-dom-slot-controller.js +92 -0
  14. package/dist/src/internal/light-dom-slot-controller.js.map +1 -0
  15. package/dist/src/internal/router.d.ts +45 -0
  16. package/dist/src/internal/router.d.ts.map +1 -0
  17. package/dist/src/internal/router.js +89 -0
  18. package/dist/src/internal/router.js.map +1 -0
  19. package/dist/src/structures/uik-shell-activity-bar-contract.d.ts +10 -0
  20. package/dist/src/structures/uik-shell-activity-bar-contract.d.ts.map +1 -0
  21. package/dist/src/structures/uik-shell-activity-bar-contract.js +2 -0
  22. package/dist/src/structures/uik-shell-activity-bar-contract.js.map +1 -0
  23. package/dist/src/structures/uik-shell-activity-bar.d.ts +40 -0
  24. package/dist/src/structures/uik-shell-activity-bar.d.ts.map +1 -0
  25. package/dist/src/structures/uik-shell-activity-bar.js +148 -0
  26. package/dist/src/structures/uik-shell-activity-bar.js.map +1 -0
  27. package/dist/src/structures/uik-shell-layout.d.ts +35 -0
  28. package/dist/src/structures/uik-shell-layout.d.ts.map +1 -0
  29. package/dist/src/structures/uik-shell-layout.js +213 -0
  30. package/dist/src/structures/uik-shell-layout.js.map +1 -0
  31. package/dist/src/structures/uik-shell-secondary-sidebar.d.ts +51 -0
  32. package/dist/src/structures/uik-shell-secondary-sidebar.d.ts.map +1 -0
  33. package/dist/src/structures/uik-shell-secondary-sidebar.js +306 -0
  34. package/dist/src/structures/uik-shell-secondary-sidebar.js.map +1 -0
  35. package/dist/src/structures/uik-shell-sidebar.d.ts +44 -0
  36. package/dist/src/structures/uik-shell-sidebar.d.ts.map +1 -0
  37. package/dist/src/structures/uik-shell-sidebar.js +253 -0
  38. package/dist/src/structures/uik-shell-sidebar.js.map +1 -0
  39. package/dist/src/structures/uik-shell-status-bar.d.ts +42 -0
  40. package/dist/src/structures/uik-shell-status-bar.d.ts.map +1 -0
  41. package/dist/src/structures/uik-shell-status-bar.js +193 -0
  42. package/dist/src/structures/uik-shell-status-bar.js.map +1 -0
  43. package/package.json +40 -28
  44. package/dist/ActivityBar.d.ts +0 -25
  45. package/dist/ActivityBar.d.ts.map +0 -1
  46. package/dist/ActivityBar.js +0 -81
  47. package/dist/ActivityBar.js.map +0 -1
  48. package/dist/AppShellLayout.d.ts +0 -17
  49. package/dist/AppShellLayout.d.ts.map +0 -1
  50. package/dist/AppShellLayout.js +0 -66
  51. package/dist/AppShellLayout.js.map +0 -1
  52. package/dist/SecondarySidebar.d.ts +0 -18
  53. package/dist/SecondarySidebar.d.ts.map +0 -1
  54. package/dist/SecondarySidebar.js +0 -84
  55. package/dist/SecondarySidebar.js.map +0 -1
  56. package/dist/Sidebar.d.ts +0 -20
  57. package/dist/Sidebar.d.ts.map +0 -1
  58. package/dist/Sidebar.js +0 -105
  59. package/dist/Sidebar.js.map +0 -1
  60. package/dist/Statusbar.d.ts +0 -19
  61. package/dist/Statusbar.d.ts.map +0 -1
  62. package/dist/Statusbar.js +0 -73
  63. package/dist/Statusbar.js.map +0 -1
  64. package/dist/router.d.ts +0 -36
  65. package/dist/router.d.ts.map +0 -1
  66. package/dist/router.js +0 -72
  67. package/dist/router.js.map +0 -1
  68. package/dist/tailwind-source.css +0 -2
package/README.md CHANGED
@@ -1,113 +1,185 @@
1
1
  # @ismail-elkorchi/ui-shell
2
2
 
3
- Tailwind-friendly shell components (activity bar, sidebars, status bar, and an optional frame layout) for Light DOM layouts. They render Tailwind utility classes, depend on `@ismail-elkorchi/ui-primitives` for controls, and stay framework-agnostic.
4
-
5
- ## Build & distribution
6
-
7
- - `npm run build` emits ESM + `.d.ts` modules into `dist/` for `index/register/router`, layout, activity bar, sidebar, secondary sidebar, and status bar.
8
- - Tailwind scanning helper ships as `dist/tailwind-source.css`.
9
- - Published output contains only `dist/` plus this README; TypeScript sources stay in the workspace.
3
+ Token-driven shell components (activity bar, sidebars, status bar, and an optional frame layout) for Light DOM composition. They depend on `@ismail-elkorchi/ui-primitives` for controls, expose slots + parts, and read all visual values from `@ismail-elkorchi/ui-tokens` CSS variables.
10
4
 
11
5
  ## Layout layer
12
6
 
13
7
  - Regions: left rail (`activity-bar`), primary sidebar, main content, optional secondary sidebar, and status bar.
14
8
  - `uik-shell-layout` stitches the regions together and tags them with `data-region` attributes to keep the layout contract visible in the DOM.
15
9
  - Shell components expose only UI surface/state; business logic should live in the host app.
16
- - **Contract**: Shell components use `ui-primitives` strictly via their public API (attributes/props). They do not rely on Tailwind utility injection to style the internals of primitives (no `class="text-red-500"` on a `uik-button`).
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
+
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).
17
29
 
18
30
  ## Using the components
19
31
 
20
32
  ```ts
21
- import {html} from 'lit';
22
- import '@ismail-elkorchi/ui-primitives/register';
23
- import '@ismail-elkorchi/ui-shell/register';
24
- import type {ActivityBarItem} 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";
25
37
 
26
- const activityItems: ActivityBarItem[] = [
38
+ const activityItems: UikShellActivityBarItem[] = [
27
39
  {
28
- id: 'explorer',
29
- label: 'Explorer',
30
- 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",
31
48
  },
32
- {id: 'search', label: 'Search', icon: 'M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z'}
33
49
  ];
34
50
 
35
51
  html`
36
- <uik-shell-layout
37
- .activityBar=${html`
38
- <uik-shell-activity-bar
39
- .items=${activityItems}
40
- .activeId=${'explorer'}
41
- @activity-select=${(e: CustomEvent<{id: string}>) => console.log(e.detail.id)}>
42
- </uik-shell-activity-bar>
43
- `}
44
- .primarySidebar=${html`
45
- <uik-shell-sidebar
46
- heading="Explorer"
47
- .actions=${html`<uik-button variant="ghost" size="icon">…</uik-button>`}
48
- .body=${html`<!-- put your file tree or filters here -->`}>
49
- </uik-shell-sidebar>
50
- `}
51
- .mainContent=${html`<main class="flex-1">Your editor or tabs</main>`}
52
- .secondarySidebar=${html`
53
- <uik-shell-secondary-sidebar
54
- .open=${true}
55
- heading="AI Assistant"
56
- .body=${html`<p class="text-sm text-muted-foreground">Auxiliary tools live here.</p>`}
57
- @secondary-close=${() => console.log('close secondary')}></uik-shell-secondary-sidebar>
58
- `}
59
- .statusBar=${html`
60
- <uik-shell-statusbar message="Ready" tone="info" .meta=${'3 files selected'}></uik-shell-statusbar>
61
- `}
62
- ?showSecondary=${true}>
52
+ <uik-shell-layout ?isSecondarySidebarVisible=${true}>
53
+ <uik-shell-activity-bar
54
+ slot="activity-bar"
55
+ .items=${activityItems}
56
+ .activeId=${"explorer"}
57
+ @activity-bar-select=${(e: CustomEvent<{ id: string }>) =>
58
+ console.log(e.detail.id)}
59
+ >
60
+ </uik-shell-activity-bar>
61
+ <uik-shell-sidebar slot="primary-sidebar" heading="Explorer">
62
+ <uik-button slot="actions" variant="ghost" size="icon">…</uik-button>
63
+ <div style="font-size: var(--uik-typography-font-size-2);">
64
+ <!-- put your tree view or navigation here -->
65
+ </div>
66
+ </uik-shell-sidebar>
67
+ <main
68
+ slot="main-content"
69
+ style="flex: 1 1 auto; min-height: var(--uik-space-0);"
70
+ >
71
+ Your editor or subviews
72
+ </main>
73
+ <uik-shell-secondary-sidebar
74
+ slot="secondary-sidebar"
75
+ .isOpen=${true}
76
+ heading="AI Assistant"
77
+ @secondary-sidebar-close=${() => console.log("close secondary")}
78
+ >
79
+ <p
80
+ style="
81
+ font-size: var(--uik-typography-font-size-2);
82
+ color: oklch(var(--uik-text-muted));
83
+ "
84
+ >
85
+ Auxiliary tools live here.
86
+ </p>
87
+ </uik-shell-secondary-sidebar>
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>
63
94
  </uik-shell-layout>
64
95
  `;
65
96
  ```
66
97
 
67
98
  ### Component notes
68
99
 
69
- - `uik-shell-activity-bar`: accepts `.items` (id/label/icon/path) and emits `activity-select`.
70
- - `uik-shell-sidebar`: header/heading with `.actions`, `.body`, and optional `.footer`; `paddedBody`/`scrollBody` toggle spacing and scroll.
71
- - `uik-shell-secondary-sidebar`: controlled via `.open`; emits `secondary-close` when the close button is clicked.
72
- - `uik-shell-statusbar`: `.message` + `.tone` colorizes the left side; `.meta` renders on the right (string becomes an outline badge).
100
+ - `uik-shell-layout`: named slots `activity-bar`, `primary-sidebar`, `main-content`, `secondary-sidebar`, `status-bar`.
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).
102
+ - `uik-shell-sidebar`: `slot="actions"` for header actions, default slot for body, optional `slot="footer"`; `isBodyPadded`/`isBodyScrollable` toggle spacing + scroll.
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`).
104
+ - `uik-shell-status-bar`: `.message` + `.tone` colorize the left side; `meta` string (outline badge) or `slot="meta"` for custom content; optional `slot="actions"`.
105
+ - Use `@ismail-elkorchi/ui-primitives/uik-nav` or `@ismail-elkorchi/ui-primitives/uik-tree-view` for sidebar navigation content.
106
+
107
+ ### Custom properties
108
+
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`.
110
+ - Sidebar: `--uik-component-shell-sidebar-bg`, `--uik-component-shell-sidebar-fg`, `--uik-component-shell-sidebar-width`.
111
+ - Secondary sidebar: `--uik-component-shell-secondary-sidebar-bg`, `--uik-component-shell-secondary-sidebar-width`.
112
+ - Status bar: `--uik-component-shell-status-bar-bg`, `--uik-component-shell-status-bar-fg`, `--uik-component-shell-status-bar-height`.
113
+ - Shared: `--uik-component-shell-divider-color`, `--uik-component-shell-scrollbar-track`, `--uik-component-shell-scrollbar-thumb`.
114
+
115
+ ## Tokens & theming
116
+
117
+ Load tokens once and set theme/density attributes on a shared container (often `:root`):
118
+
119
+ ```css
120
+ @import "@ismail-elkorchi/ui-tokens/index.css";
121
+ ```
122
+
123
+ ```html
124
+ <html data-uik-theme="light" data-uik-density="comfortable">
125
+ ...
126
+ </html>
127
+ ```
73
128
 
74
129
  ## Routing store
75
130
 
76
- 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/tabs.
131
+ 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.
77
132
 
78
133
  ```ts
79
- import {createAppShellRouter, APP_SHELL_NAV_EVENT, type AppShellNavigationDetail} from '@ismail-elkorchi/ui-shell/router';
134
+ import {
135
+ createUikShellRouter,
136
+ UIK_SHELL_NAVIGATION_EVENT,
137
+ type UikShellNavigationDetail,
138
+ } from "@ismail-elkorchi/ui-shell/router";
80
139
 
81
140
  const routes = [
82
- {id: 'explorer', label: 'Explorer', subviews: ['code', 'prompt', 'apply'], defaultSubview: 'code'},
83
- {id: 'search', label: 'Search'},
84
- {id: 'settings', label: 'Settings'}
141
+ {
142
+ id: "explorer",
143
+ label: "Explorer",
144
+ subviews: ["code", "prompt", "apply"],
145
+ defaultSubview: "code",
146
+ },
147
+ { id: "search", label: "Search" },
148
+ { id: "settings", label: "Settings" },
85
149
  ] as const;
86
150
 
87
- export const shellRouter = createAppShellRouter({routes, initialView: 'explorer', initialSubview: 'code'});
151
+ export const shellRouter = createUikShellRouter({
152
+ routes,
153
+ initialView: "explorer",
154
+ initialSubview: "code",
155
+ });
88
156
 
89
157
  // React to navigation anywhere in the app
90
- const unsubscribe = shellRouter.subscribe(({view, subview}) => {
91
- console.log('Current location', view, subview);
158
+ const unsubscribe = shellRouter.subscribe(({ view, subview }) => {
159
+ console.log("Current location", view, subview);
92
160
  });
93
161
 
94
162
  // Wire Lit components through events
95
163
  html`
96
164
  <uik-shell-activity-bar
97
- .items=${routes.map(r => ({id: r.id, label: r.label ?? r.id}))}
165
+ .items=${routes.map((r) => ({ id: r.id, label: r.label ?? r.id }))}
98
166
  .activeId=${shellRouter.current.view}
99
- @activity-select=${(e: CustomEvent<{id: string}>) => shellRouter.navigate(e.detail.id)}>
167
+ @activity-bar-select=${(e: CustomEvent<{ id: string }>) =>
168
+ shellRouter.navigate(e.detail.id)}
169
+ >
100
170
  </uik-shell-activity-bar>
101
171
 
102
172
  <editor-area
103
- .activeTab=${shellRouter.current.subview ?? 'code'}
104
- @tab-change=${(e: CustomEvent<{tab: string}>) => shellRouter.navigate(shellRouter.current.view, e.detail.tab)}>
173
+ .activeSubview=${shellRouter.current.subview ?? "code"}
174
+ @subview-change=${(e: CustomEvent<{ subview: string }>) =>
175
+ shellRouter.navigate(shellRouter.current.view, e.detail.subview)}
176
+ >
105
177
  </editor-area>
106
178
  `;
107
179
 
108
180
  // Listen to the low-level navigation event if you prefer EventTarget
109
- window.addEventListener(APP_SHELL_NAV_EVENT, (event: Event) => {
110
- const detail = (event as CustomEvent<AppShellNavigationDetail>).detail;
181
+ window.addEventListener(UIK_SHELL_NAVIGATION_EVENT, (event: Event) => {
182
+ const detail = (event as CustomEvent<UikShellNavigationDetail>).detail;
111
183
  console.log(detail.from, detail.to, detail.route);
112
184
  });
113
185
  ```
@@ -115,22 +187,3 @@ window.addEventListener(APP_SHELL_NAV_EVENT, (event: Event) => {
115
187
  - Routes are simple `{id, label?, subviews?, defaultSubview?}` objects.
116
188
  - `navigate(view, subview?)` resolves subviews per route (keeping the last used subview for that route).
117
189
  - `subscribe` immediately fires with the current location and returns an unsubscribe function.
118
-
119
- ## Tailwind v4 scanning
120
-
121
- The package ships Tailwind class strings in TypeScript. Add the source hint before importing Tailwind:
122
-
123
- ```css
124
- @import '@ismail-elkorchi/ui-tokens/index.css';
125
- @import '@ismail-elkorchi/ui-shell/tailwind-source.css'; /* pulls in @source "./**/*.{ts,js}" */
126
- @source "./**/*.{ts,js,html}";
127
- @import 'tailwindcss';
128
- ```
129
-
130
- Adjust the `@source` path to match the location of your entry CSS. Alternatively, add the line yourself:
131
-
132
- ```css
133
- @source "../../node_modules/@ismail-elkorchi/ui-shell/**/*.{ts,js}";
134
- ```
135
-
136
- Make sure these appear in the renderer entry CSS so Tailwind keeps the shell utilities during tree-shaking.