@sentropic/design-system-angular 0.36.58 → 0.36.60

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.
package/dist/AppShell.js CHANGED
@@ -1,39 +1,651 @@
1
- import { Component, Input as NgInput } from "@angular/core";
1
+ import { Component, ElementRef, Input as NgInput, ViewChild } from "@angular/core";
2
+ import { classNames } from "./classNames.js";
3
+ import { Icon } from "./Icon.js";
2
4
  import * as i0 from "@angular/core";
5
+ // CSS custom property each resizable panel is sized by (see the
6
+ // `.st-appShell` base rule in shared styles.css) — setting it inline on the
7
+ // shell root is the intended resize mechanism, it simply out-specificities
8
+ // the token-driven default declared there. Mirrors Svelte's `PANEL_VAR`.
9
+ const PANEL_VAR = {
10
+ navigationPanel: "--st-appShell-navigation-width",
11
+ contextPanel: "--st-appShell-context-width",
12
+ utilityPanel: "--st-appShell-utility-width",
13
+ };
14
+ // Nominal px equivalent of each panel's own CSS-token default (navigation
15
+ // 20rem, context 22rem, utility 24rem, all at a 16px root) — used ONLY as a
16
+ // display/ARIA fallback (aria-valuenow, drag-start anchor) before any width
17
+ // has ever been supplied or committed. Never written back as an inline
18
+ // style, so a themed override of the underlying token is never fought until
19
+ // the consumer/user actually establishes a concrete width.
20
+ // NOTE: `primaryRail` is intentionally NOT a resizable panel — it is a
21
+ // fixed-width icon rail (à la VS Code's activity bar), not a splittable
22
+ // pane; see `AppShellPanelKey` above.
23
+ const PANEL_NOMINAL_PX = {
24
+ navigationPanel: 320,
25
+ contextPanel: 352,
26
+ utilityPanel: 384,
27
+ };
3
28
  export class AppShell {
4
29
  static stComponentName = "AppShell";
5
30
  componentName = "AppShell";
6
31
  variant = "workspace";
32
+ topChrome;
33
+ primaryRail;
34
+ navigationPanel;
35
+ contextPanel;
36
+ utilityPanel;
37
+ bottomPanel;
7
38
  mainId = "main";
8
39
  navigationLabel = "Workspace navigation";
9
40
  contextLabel = "Context panel";
10
41
  utilityLabel = "Utility panel";
11
42
  utilityMode = "reserve";
12
43
  utilitySide = "right";
44
+ panelCollapse = "stack";
45
+ primaryRailLabel = "Primary rail";
46
+ navigationPanelLabel;
47
+ contextPanelLabel;
48
+ utilityPanelLabel;
13
49
  classInput;
50
+ panelResize = false;
51
+ panelWidths;
52
+ defaultPanelWidths;
53
+ onPanelResize;
54
+ panelMinWidth = 180;
55
+ panelMaxWidth = 640;
56
+ navigationPanelRef;
57
+ contextPanelRef;
58
+ utilityPanelRef;
59
+ // Uncontrolled fallback for resizable widths, seeded on first read from
60
+ // `defaultPanelWidths` (mirrors `internalValue` on TimeRangePicker — a
61
+ // lazy, one-time seed rather than a constructor-time copy, since
62
+ // `@Input()`s aren't bound yet when the class is constructed).
63
+ internalWidths;
64
+ // Pointer-drag bookkeeping — plain fields, never read from the template,
65
+ // only from the pointer handlers below.
66
+ dragKey = null;
67
+ dragPositive = true;
68
+ dragStartX = 0;
69
+ dragStartWidth = 0;
70
+ // Uncontrolled per-panel disclosure state (v1) — each accordion panel
71
+ // starts collapsed. Desktop rendering never reads these (CSS scopes the
72
+ // collapse to `@media (max-width: 48rem)`), so they have zero effect above
73
+ // the breakpoint.
74
+ primaryRailPanelOpen = false;
75
+ navigationPanelOpen = false;
76
+ contextPanelOpen = false;
77
+ utilityPanelOpen = false;
78
+ // Static, framework-wide-matching disclosure ids (parity with the Svelte
79
+ // reference — one AppShell instance per page is the expected usage).
80
+ primaryRailTriggerId = "st-appShell-primaryRail-trigger";
81
+ primaryRailRegionId = "st-appShell-primaryRail-region";
82
+ navigationPanelTriggerId = "st-appShell-navigationPanel-trigger";
83
+ navigationPanelRegionId = "st-appShell-navigationPanel-region";
84
+ contextPanelTriggerId = "st-appShell-contextPanel-trigger";
85
+ contextPanelRegionId = "st-appShell-contextPanel-region";
86
+ utilityPanelTriggerId = "st-appShell-utilityPanel-trigger";
87
+ utilityPanelRegionId = "st-appShell-utilityPanel-region";
14
88
  get hostClass() {
15
- return ["st-appShell", `st-appShell--${this.variant}`, this.classInput].filter(Boolean).join(" ");
89
+ return classNames("st-appShell", `st-appShell--${this.variant}`, this.classInput);
90
+ }
91
+ // Resolved disclosure labels: default to the existing aria-label inputs so
92
+ // a consumer who already customized navigationLabel/contextLabel/utilityLabel
93
+ // doesn't need to duplicate the translation for the accordion trigger text.
94
+ get navigationPanelLabelResolved() {
95
+ return this.navigationPanelLabel ?? this.navigationLabel;
96
+ }
97
+ get contextPanelLabelResolved() {
98
+ return this.contextPanelLabel ?? this.contextLabel;
99
+ }
100
+ get utilityPanelLabelResolved() {
101
+ return this.utilityPanelLabel ?? this.utilityLabel;
102
+ }
103
+ get primaryRailRegionCollapsed() {
104
+ return this.panelCollapse === "accordion" && !this.primaryRailPanelOpen;
105
+ }
106
+ get navigationPanelRegionCollapsed() {
107
+ return this.panelCollapse === "accordion" && !this.navigationPanelOpen;
108
+ }
109
+ get contextPanelRegionCollapsed() {
110
+ return this.panelCollapse === "accordion" && !this.contextPanelOpen;
111
+ }
112
+ get utilityPanelRegionCollapsed() {
113
+ return this.panelCollapse === "accordion" && !this.utilityPanelOpen;
114
+ }
115
+ togglePrimaryRailPanel() {
116
+ this.primaryRailPanelOpen = !this.primaryRailPanelOpen;
117
+ }
118
+ toggleNavigationPanel() {
119
+ this.navigationPanelOpen = !this.navigationPanelOpen;
120
+ }
121
+ toggleContextPanel() {
122
+ this.contextPanelOpen = !this.contextPanelOpen;
123
+ }
124
+ toggleUtilityPanel() {
125
+ this.utilityPanelOpen = !this.utilityPanelOpen;
126
+ }
127
+ // ── Resizable panels (panelResize) ──────────────────────────────────────
128
+ // Controlled/uncontrolled mirrors the Svelte reference: `panelWidths`
129
+ // present (even as `{}`) means controlled — the component reads it but
130
+ // never writes it; otherwise widths live in `internalWidths`.
131
+ get isWidthControlled() {
132
+ return this.panelWidths !== undefined;
133
+ }
134
+ ensureInternalWidths() {
135
+ if (this.internalWidths === undefined) {
136
+ this.internalWidths = { ...this.defaultPanelWidths };
137
+ }
138
+ return this.internalWidths;
139
+ }
140
+ widthFor(key) {
141
+ const source = this.isWidthControlled ? this.panelWidths : this.ensureInternalWidths();
142
+ return source?.[key];
143
+ }
144
+ clampWidth(n) {
145
+ return Math.min(Math.max(n, this.panelMinWidth), this.panelMaxWidth);
146
+ }
147
+ // Current width for rendering/ARIA — always a concrete, clamped number so
148
+ // aria-valuenow is never NaN and is always within [aria-valuemin, aria-valuemax].
149
+ displayWidth(key) {
150
+ return this.clampWidth(this.widthFor(key) ?? PANEL_NOMINAL_PX[key]);
151
+ }
152
+ panelElFor(key) {
153
+ if (key === "navigationPanel")
154
+ return this.navigationPanelRef?.nativeElement ?? null;
155
+ if (key === "contextPanel")
156
+ return this.contextPanelRef?.nativeElement ?? null;
157
+ return this.utilityPanelRef?.nativeElement ?? null;
158
+ }
159
+ // `utilityPanel` mirrors a left panel (grow-on-drag-right) unless it sits
160
+ // on the right edge; the "bottom" side never renders a handle at all
161
+ // (guarded in the template), so its `positive` value is never read.
162
+ get utilityPositive() {
163
+ return this.utilitySide !== "right";
164
+ }
165
+ // Only the CSS vars for panels with an explicit (controlled or committed)
166
+ // width are emitted — an untouched panel keeps deferring to its token
167
+ // default (`.st-appShell` base rule), so a theme's own width override is
168
+ // never silently overridden just because `panelResize` is on.
169
+ get panelStyle() {
170
+ if (!this.panelResize)
171
+ return null;
172
+ const parts = [];
173
+ for (const key of Object.keys(PANEL_VAR)) {
174
+ const width = this.widthFor(key);
175
+ if (width !== undefined)
176
+ parts.push(`${PANEL_VAR[key]}: ${this.clampWidth(width)}px`);
177
+ }
178
+ return parts.length ? parts.join("; ") : null;
179
+ }
180
+ commitWidth(key, next) {
181
+ const clamped = this.clampWidth(next);
182
+ if (!this.isWidthControlled) {
183
+ const widths = this.ensureInternalWidths();
184
+ this.internalWidths = { ...widths, [key]: clamped };
185
+ }
186
+ this.onPanelResize?.(key, clamped);
187
+ }
188
+ onHandlePointerDown(event, key, positive) {
189
+ const handle = event.currentTarget;
190
+ handle?.setPointerCapture?.(event.pointerId);
191
+ this.dragKey = key;
192
+ this.dragPositive = positive;
193
+ this.dragStartX = event.clientX;
194
+ const measured = this.panelElFor(key)?.getBoundingClientRect().width ?? 0;
195
+ this.dragStartWidth = measured > 0 ? measured : this.displayWidth(key);
196
+ event.preventDefault();
197
+ }
198
+ onHandlePointerMove(event) {
199
+ if (this.dragKey === null)
200
+ return;
201
+ const dx = event.clientX - this.dragStartX;
202
+ const delta = this.dragPositive ? dx : -dx;
203
+ this.commitWidth(this.dragKey, this.dragStartWidth + delta);
204
+ }
205
+ onHandlePointerUp(event) {
206
+ if (this.dragKey === null)
207
+ return;
208
+ const handle = event.currentTarget;
209
+ if (handle?.hasPointerCapture?.(event.pointerId))
210
+ handle.releasePointerCapture?.(event.pointerId);
211
+ this.dragKey = null;
212
+ }
213
+ // Arrow keys move the splitter itself (WAI-ARIA window-splitter pattern):
214
+ // for a "positive" (left-edge) panel, moving the splitter right grows it;
215
+ // for a "negative" (right-edge) panel, moving the splitter right shrinks
216
+ // it. Home/End always jump to the absolute clamp bounds.
217
+ onHandleKeydown(event, key, positive) {
218
+ const current = this.displayWidth(key);
219
+ let next;
220
+ switch (event.key) {
221
+ case "ArrowLeft":
222
+ next = current + (positive ? -16 : 16);
223
+ break;
224
+ case "ArrowRight":
225
+ next = current + (positive ? 16 : -16);
226
+ break;
227
+ case "Home":
228
+ next = this.panelMinWidth;
229
+ break;
230
+ case "End":
231
+ next = this.panelMaxWidth;
232
+ break;
233
+ default:
234
+ return;
235
+ }
236
+ event.preventDefault();
237
+ this.commitWidth(key, next);
16
238
  }
17
239
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
18
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.17", type: AppShell, isStandalone: true, selector: "st-app-shell", inputs: { variant: "variant", mainId: "mainId", navigationLabel: "navigationLabel", contextLabel: "contextLabel", utilityLabel: "utilityLabel", utilityMode: "utilityMode", utilitySide: "utilitySide", classInput: ["class", "classInput"] }, ngImport: i0, template: `
19
- <div [attr.data-st-component]="componentName" [attr.data-st-app-shell-variant]="variant" [attr.data-utility-mode]="utilityMode" [attr.data-utility-side]="utilitySide" [class]="hostClass">
20
- <ng-content></ng-content>
21
- </div>
22
- `, isInline: true });
240
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppShell, isStandalone: true, selector: "st-app-shell", inputs: { variant: "variant", topChrome: "topChrome", primaryRail: "primaryRail", navigationPanel: "navigationPanel", contextPanel: "contextPanel", utilityPanel: "utilityPanel", bottomPanel: "bottomPanel", mainId: "mainId", navigationLabel: "navigationLabel", contextLabel: "contextLabel", utilityLabel: "utilityLabel", utilityMode: "utilityMode", utilitySide: "utilitySide", panelCollapse: "panelCollapse", primaryRailLabel: "primaryRailLabel", navigationPanelLabel: "navigationPanelLabel", contextPanelLabel: "contextPanelLabel", utilityPanelLabel: "utilityPanelLabel", classInput: ["class", "classInput"], panelResize: "panelResize", panelWidths: "panelWidths", defaultPanelWidths: "defaultPanelWidths", onPanelResize: "onPanelResize", panelMinWidth: "panelMinWidth", panelMaxWidth: "panelMaxWidth" }, viewQueries: [{ propertyName: "navigationPanelRef", first: true, predicate: ["navigationPanelEl"], descendants: true }, { propertyName: "contextPanelRef", first: true, predicate: ["contextPanelEl"], descendants: true }, { propertyName: "utilityPanelRef", first: true, predicate: ["utilityPanelEl"], descendants: true }], ngImport: i0, template: `
241
+ @if (variant === "site") {
242
+ <div [attr.data-st-component]="componentName" data-st-app-shell-variant="site" [class]="hostClass">
243
+ <ng-content></ng-content>
244
+ </div>
245
+ } @else {
246
+ <div
247
+ [attr.data-st-component]="componentName"
248
+ data-st-app-shell-variant="workspace"
249
+ [attr.data-utility-mode]="utilityMode"
250
+ [attr.data-utility-side]="utilitySide"
251
+ [attr.data-panel-collapse]="panelCollapse"
252
+ [class]="hostClass"
253
+ [style]="panelStyle"
254
+ >
255
+ @if (topChrome) {
256
+ <div class="st-appShell__topChrome">
257
+ <ng-content select="[slot=topChrome]"></ng-content>
258
+ </div>
259
+ }
260
+ <div class="st-appShell__body">
261
+ @if (primaryRail) {
262
+ <aside class="st-appShell__primaryRail" [attr.aria-label]="primaryRailLabel">
263
+ @if (panelCollapse === "accordion") {
264
+ <button
265
+ type="button"
266
+ class="st-appShell__panelDisclosure"
267
+ [attr.aria-expanded]="primaryRailPanelOpen"
268
+ [attr.aria-controls]="primaryRailRegionId"
269
+ [id]="primaryRailTriggerId"
270
+ (click)="togglePrimaryRailPanel()"
271
+ >
272
+ <span class="st-appShell__panelDisclosureLabel">{{ primaryRailLabel }}</span>
273
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="primaryRailPanelOpen">
274
+ <st-icon name="chevron-down" [size]="16"></st-icon>
275
+ </span>
276
+ </button>
277
+ }
278
+ <div
279
+ class="st-appShell__panelRegion"
280
+ [class.st-appShell__panelRegion--collapsed]="primaryRailRegionCollapsed"
281
+ [attr.id]="panelCollapse === 'accordion' ? primaryRailRegionId : null"
282
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
283
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? primaryRailTriggerId : null"
284
+ >
285
+ <ng-content select="[slot=primaryRail]"></ng-content>
286
+ </div>
287
+ </aside>
288
+ }
289
+ @if (navigationPanel) {
290
+ <aside class="st-appShell__navigationPanel" [attr.aria-label]="navigationLabel" #navigationPanelEl>
291
+ @if (panelCollapse === "accordion") {
292
+ <button
293
+ type="button"
294
+ class="st-appShell__panelDisclosure"
295
+ [attr.aria-expanded]="navigationPanelOpen"
296
+ [attr.aria-controls]="navigationPanelRegionId"
297
+ [id]="navigationPanelTriggerId"
298
+ (click)="toggleNavigationPanel()"
299
+ >
300
+ <span class="st-appShell__panelDisclosureLabel">{{ navigationPanelLabelResolved }}</span>
301
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="navigationPanelOpen">
302
+ <st-icon name="chevron-down" [size]="16"></st-icon>
303
+ </span>
304
+ </button>
305
+ }
306
+ <div
307
+ class="st-appShell__panelRegion"
308
+ [class.st-appShell__panelRegion--collapsed]="navigationPanelRegionCollapsed"
309
+ [attr.id]="panelCollapse === 'accordion' ? navigationPanelRegionId : null"
310
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
311
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? navigationPanelTriggerId : null"
312
+ >
313
+ <ng-content select="[slot=navigationPanel]"></ng-content>
314
+ </div>
315
+ @if (panelResize) {
316
+ <div
317
+ class="st-appShell__resizeHandle"
318
+ role="separator"
319
+ aria-orientation="vertical"
320
+ tabindex="0"
321
+ [attr.aria-valuenow]="displayWidth('navigationPanel')"
322
+ [attr.aria-valuemin]="panelMinWidth"
323
+ [attr.aria-valuemax]="panelMaxWidth"
324
+ [attr.aria-label]="'Resize ' + navigationLabel"
325
+ (pointerdown)="onHandlePointerDown($event, 'navigationPanel', true)"
326
+ (pointermove)="onHandlePointerMove($event)"
327
+ (pointerup)="onHandlePointerUp($event)"
328
+ (pointercancel)="onHandlePointerUp($event)"
329
+ (keydown)="onHandleKeydown($event, 'navigationPanel', true)"
330
+ ></div>
331
+ }
332
+ </aside>
333
+ }
334
+ <main class="st-appShell__main" [id]="mainId">
335
+ <ng-content select="[slot=main]"></ng-content>
336
+ </main>
337
+ @if (contextPanel) {
338
+ <aside class="st-appShell__contextPanel" [attr.aria-label]="contextLabel" #contextPanelEl>
339
+ @if (panelCollapse === "accordion") {
340
+ <button
341
+ type="button"
342
+ class="st-appShell__panelDisclosure"
343
+ [attr.aria-expanded]="contextPanelOpen"
344
+ [attr.aria-controls]="contextPanelRegionId"
345
+ [id]="contextPanelTriggerId"
346
+ (click)="toggleContextPanel()"
347
+ >
348
+ <span class="st-appShell__panelDisclosureLabel">{{ contextPanelLabelResolved }}</span>
349
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="contextPanelOpen">
350
+ <st-icon name="chevron-down" [size]="16"></st-icon>
351
+ </span>
352
+ </button>
353
+ }
354
+ <div
355
+ class="st-appShell__panelRegion"
356
+ [class.st-appShell__panelRegion--collapsed]="contextPanelRegionCollapsed"
357
+ [attr.id]="panelCollapse === 'accordion' ? contextPanelRegionId : null"
358
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
359
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? contextPanelTriggerId : null"
360
+ >
361
+ <ng-content select="[slot=contextPanel]"></ng-content>
362
+ </div>
363
+ @if (panelResize) {
364
+ <div
365
+ class="st-appShell__resizeHandle"
366
+ role="separator"
367
+ aria-orientation="vertical"
368
+ tabindex="0"
369
+ [attr.aria-valuenow]="displayWidth('contextPanel')"
370
+ [attr.aria-valuemin]="panelMinWidth"
371
+ [attr.aria-valuemax]="panelMaxWidth"
372
+ [attr.aria-label]="'Resize ' + contextLabel"
373
+ (pointerdown)="onHandlePointerDown($event, 'contextPanel', false)"
374
+ (pointermove)="onHandlePointerMove($event)"
375
+ (pointerup)="onHandlePointerUp($event)"
376
+ (pointercancel)="onHandlePointerUp($event)"
377
+ (keydown)="onHandleKeydown($event, 'contextPanel', false)"
378
+ ></div>
379
+ }
380
+ </aside>
381
+ }
382
+ @if (utilityPanel) {
383
+ <aside class="st-appShell__utilityPanel" [attr.aria-label]="utilityLabel" #utilityPanelEl>
384
+ @if (panelCollapse === "accordion") {
385
+ <button
386
+ type="button"
387
+ class="st-appShell__panelDisclosure"
388
+ [attr.aria-expanded]="utilityPanelOpen"
389
+ [attr.aria-controls]="utilityPanelRegionId"
390
+ [id]="utilityPanelTriggerId"
391
+ (click)="toggleUtilityPanel()"
392
+ >
393
+ <span class="st-appShell__panelDisclosureLabel">{{ utilityPanelLabelResolved }}</span>
394
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="utilityPanelOpen">
395
+ <st-icon name="chevron-down" [size]="16"></st-icon>
396
+ </span>
397
+ </button>
398
+ }
399
+ <div
400
+ class="st-appShell__panelRegion"
401
+ [class.st-appShell__panelRegion--collapsed]="utilityPanelRegionCollapsed"
402
+ [attr.id]="panelCollapse === 'accordion' ? utilityPanelRegionId : null"
403
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
404
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? utilityPanelTriggerId : null"
405
+ >
406
+ <ng-content select="[slot=utilityPanel]"></ng-content>
407
+ </div>
408
+ @if (panelResize && utilitySide !== "bottom") {
409
+ <div
410
+ class="st-appShell__resizeHandle"
411
+ role="separator"
412
+ aria-orientation="vertical"
413
+ tabindex="0"
414
+ [attr.aria-valuenow]="displayWidth('utilityPanel')"
415
+ [attr.aria-valuemin]="panelMinWidth"
416
+ [attr.aria-valuemax]="panelMaxWidth"
417
+ [attr.aria-label]="'Resize ' + utilityLabel"
418
+ (pointerdown)="onHandlePointerDown($event, 'utilityPanel', utilityPositive)"
419
+ (pointermove)="onHandlePointerMove($event)"
420
+ (pointerup)="onHandlePointerUp($event)"
421
+ (pointercancel)="onHandlePointerUp($event)"
422
+ (keydown)="onHandleKeydown($event, 'utilityPanel', utilityPositive)"
423
+ ></div>
424
+ }
425
+ </aside>
426
+ }
427
+ </div>
428
+ @if (bottomPanel) {
429
+ <section class="st-appShell__bottomPanel" aria-label="Workspace tools">
430
+ <ng-content select="[slot=bottomPanel]"></ng-content>
431
+ </section>
432
+ }
433
+ </div>
434
+ }
435
+ `, isInline: true, styles: [":host { display: contents; }"], dependencies: [{ kind: "component", type: Icon, selector: "st-icon", inputs: ["name", "size", "strokeWidth", "title", "class"] }] });
23
436
  }
24
437
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppShell, decorators: [{
25
438
  type: Component,
26
- args: [{
27
- selector: "st-app-shell",
28
- standalone: true,
29
- template: `
30
- <div [attr.data-st-component]="componentName" [attr.data-st-app-shell-variant]="variant" [attr.data-utility-mode]="utilityMode" [attr.data-utility-side]="utilitySide" [class]="hostClass">
31
- <ng-content></ng-content>
32
- </div>
33
- `,
34
- }]
439
+ args: [{ selector: "st-app-shell", standalone: true, imports: [Icon], template: `
440
+ @if (variant === "site") {
441
+ <div [attr.data-st-component]="componentName" data-st-app-shell-variant="site" [class]="hostClass">
442
+ <ng-content></ng-content>
443
+ </div>
444
+ } @else {
445
+ <div
446
+ [attr.data-st-component]="componentName"
447
+ data-st-app-shell-variant="workspace"
448
+ [attr.data-utility-mode]="utilityMode"
449
+ [attr.data-utility-side]="utilitySide"
450
+ [attr.data-panel-collapse]="panelCollapse"
451
+ [class]="hostClass"
452
+ [style]="panelStyle"
453
+ >
454
+ @if (topChrome) {
455
+ <div class="st-appShell__topChrome">
456
+ <ng-content select="[slot=topChrome]"></ng-content>
457
+ </div>
458
+ }
459
+ <div class="st-appShell__body">
460
+ @if (primaryRail) {
461
+ <aside class="st-appShell__primaryRail" [attr.aria-label]="primaryRailLabel">
462
+ @if (panelCollapse === "accordion") {
463
+ <button
464
+ type="button"
465
+ class="st-appShell__panelDisclosure"
466
+ [attr.aria-expanded]="primaryRailPanelOpen"
467
+ [attr.aria-controls]="primaryRailRegionId"
468
+ [id]="primaryRailTriggerId"
469
+ (click)="togglePrimaryRailPanel()"
470
+ >
471
+ <span class="st-appShell__panelDisclosureLabel">{{ primaryRailLabel }}</span>
472
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="primaryRailPanelOpen">
473
+ <st-icon name="chevron-down" [size]="16"></st-icon>
474
+ </span>
475
+ </button>
476
+ }
477
+ <div
478
+ class="st-appShell__panelRegion"
479
+ [class.st-appShell__panelRegion--collapsed]="primaryRailRegionCollapsed"
480
+ [attr.id]="panelCollapse === 'accordion' ? primaryRailRegionId : null"
481
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
482
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? primaryRailTriggerId : null"
483
+ >
484
+ <ng-content select="[slot=primaryRail]"></ng-content>
485
+ </div>
486
+ </aside>
487
+ }
488
+ @if (navigationPanel) {
489
+ <aside class="st-appShell__navigationPanel" [attr.aria-label]="navigationLabel" #navigationPanelEl>
490
+ @if (panelCollapse === "accordion") {
491
+ <button
492
+ type="button"
493
+ class="st-appShell__panelDisclosure"
494
+ [attr.aria-expanded]="navigationPanelOpen"
495
+ [attr.aria-controls]="navigationPanelRegionId"
496
+ [id]="navigationPanelTriggerId"
497
+ (click)="toggleNavigationPanel()"
498
+ >
499
+ <span class="st-appShell__panelDisclosureLabel">{{ navigationPanelLabelResolved }}</span>
500
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="navigationPanelOpen">
501
+ <st-icon name="chevron-down" [size]="16"></st-icon>
502
+ </span>
503
+ </button>
504
+ }
505
+ <div
506
+ class="st-appShell__panelRegion"
507
+ [class.st-appShell__panelRegion--collapsed]="navigationPanelRegionCollapsed"
508
+ [attr.id]="panelCollapse === 'accordion' ? navigationPanelRegionId : null"
509
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
510
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? navigationPanelTriggerId : null"
511
+ >
512
+ <ng-content select="[slot=navigationPanel]"></ng-content>
513
+ </div>
514
+ @if (panelResize) {
515
+ <div
516
+ class="st-appShell__resizeHandle"
517
+ role="separator"
518
+ aria-orientation="vertical"
519
+ tabindex="0"
520
+ [attr.aria-valuenow]="displayWidth('navigationPanel')"
521
+ [attr.aria-valuemin]="panelMinWidth"
522
+ [attr.aria-valuemax]="panelMaxWidth"
523
+ [attr.aria-label]="'Resize ' + navigationLabel"
524
+ (pointerdown)="onHandlePointerDown($event, 'navigationPanel', true)"
525
+ (pointermove)="onHandlePointerMove($event)"
526
+ (pointerup)="onHandlePointerUp($event)"
527
+ (pointercancel)="onHandlePointerUp($event)"
528
+ (keydown)="onHandleKeydown($event, 'navigationPanel', true)"
529
+ ></div>
530
+ }
531
+ </aside>
532
+ }
533
+ <main class="st-appShell__main" [id]="mainId">
534
+ <ng-content select="[slot=main]"></ng-content>
535
+ </main>
536
+ @if (contextPanel) {
537
+ <aside class="st-appShell__contextPanel" [attr.aria-label]="contextLabel" #contextPanelEl>
538
+ @if (panelCollapse === "accordion") {
539
+ <button
540
+ type="button"
541
+ class="st-appShell__panelDisclosure"
542
+ [attr.aria-expanded]="contextPanelOpen"
543
+ [attr.aria-controls]="contextPanelRegionId"
544
+ [id]="contextPanelTriggerId"
545
+ (click)="toggleContextPanel()"
546
+ >
547
+ <span class="st-appShell__panelDisclosureLabel">{{ contextPanelLabelResolved }}</span>
548
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="contextPanelOpen">
549
+ <st-icon name="chevron-down" [size]="16"></st-icon>
550
+ </span>
551
+ </button>
552
+ }
553
+ <div
554
+ class="st-appShell__panelRegion"
555
+ [class.st-appShell__panelRegion--collapsed]="contextPanelRegionCollapsed"
556
+ [attr.id]="panelCollapse === 'accordion' ? contextPanelRegionId : null"
557
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
558
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? contextPanelTriggerId : null"
559
+ >
560
+ <ng-content select="[slot=contextPanel]"></ng-content>
561
+ </div>
562
+ @if (panelResize) {
563
+ <div
564
+ class="st-appShell__resizeHandle"
565
+ role="separator"
566
+ aria-orientation="vertical"
567
+ tabindex="0"
568
+ [attr.aria-valuenow]="displayWidth('contextPanel')"
569
+ [attr.aria-valuemin]="panelMinWidth"
570
+ [attr.aria-valuemax]="panelMaxWidth"
571
+ [attr.aria-label]="'Resize ' + contextLabel"
572
+ (pointerdown)="onHandlePointerDown($event, 'contextPanel', false)"
573
+ (pointermove)="onHandlePointerMove($event)"
574
+ (pointerup)="onHandlePointerUp($event)"
575
+ (pointercancel)="onHandlePointerUp($event)"
576
+ (keydown)="onHandleKeydown($event, 'contextPanel', false)"
577
+ ></div>
578
+ }
579
+ </aside>
580
+ }
581
+ @if (utilityPanel) {
582
+ <aside class="st-appShell__utilityPanel" [attr.aria-label]="utilityLabel" #utilityPanelEl>
583
+ @if (panelCollapse === "accordion") {
584
+ <button
585
+ type="button"
586
+ class="st-appShell__panelDisclosure"
587
+ [attr.aria-expanded]="utilityPanelOpen"
588
+ [attr.aria-controls]="utilityPanelRegionId"
589
+ [id]="utilityPanelTriggerId"
590
+ (click)="toggleUtilityPanel()"
591
+ >
592
+ <span class="st-appShell__panelDisclosureLabel">{{ utilityPanelLabelResolved }}</span>
593
+ <span class="st-appShell__panelDisclosureIcon" [class.st-appShell__panelDisclosureIcon--expanded]="utilityPanelOpen">
594
+ <st-icon name="chevron-down" [size]="16"></st-icon>
595
+ </span>
596
+ </button>
597
+ }
598
+ <div
599
+ class="st-appShell__panelRegion"
600
+ [class.st-appShell__panelRegion--collapsed]="utilityPanelRegionCollapsed"
601
+ [attr.id]="panelCollapse === 'accordion' ? utilityPanelRegionId : null"
602
+ [attr.role]="panelCollapse === 'accordion' ? 'region' : null"
603
+ [attr.aria-labelledby]="panelCollapse === 'accordion' ? utilityPanelTriggerId : null"
604
+ >
605
+ <ng-content select="[slot=utilityPanel]"></ng-content>
606
+ </div>
607
+ @if (panelResize && utilitySide !== "bottom") {
608
+ <div
609
+ class="st-appShell__resizeHandle"
610
+ role="separator"
611
+ aria-orientation="vertical"
612
+ tabindex="0"
613
+ [attr.aria-valuenow]="displayWidth('utilityPanel')"
614
+ [attr.aria-valuemin]="panelMinWidth"
615
+ [attr.aria-valuemax]="panelMaxWidth"
616
+ [attr.aria-label]="'Resize ' + utilityLabel"
617
+ (pointerdown)="onHandlePointerDown($event, 'utilityPanel', utilityPositive)"
618
+ (pointermove)="onHandlePointerMove($event)"
619
+ (pointerup)="onHandlePointerUp($event)"
620
+ (pointercancel)="onHandlePointerUp($event)"
621
+ (keydown)="onHandleKeydown($event, 'utilityPanel', utilityPositive)"
622
+ ></div>
623
+ }
624
+ </aside>
625
+ }
626
+ </div>
627
+ @if (bottomPanel) {
628
+ <section class="st-appShell__bottomPanel" aria-label="Workspace tools">
629
+ <ng-content select="[slot=bottomPanel]"></ng-content>
630
+ </section>
631
+ }
632
+ </div>
633
+ }
634
+ `, styles: [":host { display: contents; }"] }]
35
635
  }], propDecorators: { variant: [{
36
636
  type: NgInput
637
+ }], topChrome: [{
638
+ type: NgInput
639
+ }], primaryRail: [{
640
+ type: NgInput
641
+ }], navigationPanel: [{
642
+ type: NgInput
643
+ }], contextPanel: [{
644
+ type: NgInput
645
+ }], utilityPanel: [{
646
+ type: NgInput
647
+ }], bottomPanel: [{
648
+ type: NgInput
37
649
  }], mainId: [{
38
650
  type: NgInput
39
651
  }], navigationLabel: [{
@@ -46,8 +658,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
46
658
  type: NgInput
47
659
  }], utilitySide: [{
48
660
  type: NgInput
661
+ }], panelCollapse: [{
662
+ type: NgInput
663
+ }], primaryRailLabel: [{
664
+ type: NgInput
665
+ }], navigationPanelLabel: [{
666
+ type: NgInput
667
+ }], contextPanelLabel: [{
668
+ type: NgInput
669
+ }], utilityPanelLabel: [{
670
+ type: NgInput
49
671
  }], classInput: [{
50
672
  type: NgInput,
51
673
  args: ["class"]
674
+ }], panelResize: [{
675
+ type: NgInput
676
+ }], panelWidths: [{
677
+ type: NgInput
678
+ }], defaultPanelWidths: [{
679
+ type: NgInput
680
+ }], onPanelResize: [{
681
+ type: NgInput
682
+ }], panelMinWidth: [{
683
+ type: NgInput
684
+ }], panelMaxWidth: [{
685
+ type: NgInput
686
+ }], navigationPanelRef: [{
687
+ type: ViewChild,
688
+ args: ["navigationPanelEl"]
689
+ }], contextPanelRef: [{
690
+ type: ViewChild,
691
+ args: ["contextPanelEl"]
692
+ }], utilityPanelRef: [{
693
+ type: ViewChild,
694
+ args: ["utilityPanelEl"]
52
695
  }] } });
53
696
  //# sourceMappingURL=AppShell.js.map