@aquera/nile-elements 2.0.4 → 2.0.6
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/README.md +9 -0
- package/demo/nxtgen-classes.css +609 -12
- package/demo/nxtgen-dark.css +254 -35
- package/demo/nxtgen-properties.css +27 -24
- package/demo/nxtgen-utilities.css +633 -36
- package/demo/nxtgen.css +70 -12
- package/demo/utilities.css +3 -0
- package/demo/variables.css +3 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1375 -358
- package/dist/internal/glyph.cjs.js +1 -1
- package/dist/internal/glyph.cjs.js.map +1 -1
- package/dist/internal/glyph.esm.js +6 -5
- package/dist/nile-app-shell/index.cjs.js +2 -0
- package/dist/nile-app-shell/index.cjs.js.map +1 -0
- package/dist/nile-app-shell/index.esm.js +1 -0
- package/dist/nile-app-shell/nile-app-shell.cjs.js +2 -0
- package/dist/nile-app-shell/nile-app-shell.cjs.js.map +1 -0
- package/dist/nile-app-shell/nile-app-shell.css.cjs.js +2 -0
- package/dist/nile-app-shell/nile-app-shell.css.cjs.js.map +1 -0
- package/dist/nile-app-shell/nile-app-shell.css.esm.js +554 -0
- package/dist/nile-app-shell/nile-app-shell.esm.js +155 -0
- package/dist/nile-app-shell/shell-controller.cjs.js +2 -0
- package/dist/nile-app-shell/shell-controller.cjs.js.map +1 -0
- package/dist/nile-app-shell/shell-controller.esm.js +1 -0
- package/dist/nile-app-shell-main/index.cjs.js +2 -0
- package/dist/nile-app-shell-main/index.cjs.js.map +1 -0
- package/dist/nile-app-shell-main/index.esm.js +1 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.cjs.js +2 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.cjs.js.map +1 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.css.cjs.js +2 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.css.cjs.js.map +1 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.css.esm.js +18 -0
- package/dist/nile-app-shell-main/nile-app-shell-main.esm.js +1 -0
- package/dist/nile-app-shell-nav-toggle/index.cjs.js +2 -0
- package/dist/nile-app-shell-nav-toggle/index.cjs.js.map +1 -0
- package/dist/nile-app-shell-nav-toggle/index.esm.js +1 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.cjs.js +2 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.cjs.js.map +1 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.cjs.js +2 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.cjs.js.map +1 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.esm.js +29 -0
- package/dist/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.esm.js +16 -0
- package/dist/nile-app-shell-panel/index.cjs.js +2 -0
- package/dist/nile-app-shell-panel/index.cjs.js.map +1 -0
- package/dist/nile-app-shell-panel/index.esm.js +1 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.cjs.js +2 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.cjs.js.map +1 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js +2 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js.map +1 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.css.esm.js +103 -0
- package/dist/nile-app-shell-panel/nile-app-shell-panel.esm.js +33 -0
- package/dist/nile-app-shell-side-nav/index.cjs.js +2 -0
- package/dist/nile-app-shell-side-nav/index.cjs.js.map +1 -0
- package/dist/nile-app-shell-side-nav/index.esm.js +1 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.cjs.js +2 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.cjs.js.map +1 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.css.cjs.js +2 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.css.cjs.js.map +1 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.css.esm.js +55 -0
- package/dist/nile-app-shell-side-nav/nile-app-shell-side-nav.esm.js +5 -0
- package/dist/nile-combobox/nile-combobox.cjs.js +1 -1
- package/dist/nile-combobox/nile-combobox.cjs.js.map +1 -1
- package/dist/nile-combobox/nile-combobox.css.cjs.js +1 -1
- package/dist/nile-combobox/nile-combobox.css.cjs.js.map +1 -1
- package/dist/nile-combobox/nile-combobox.css.esm.js +28 -15
- package/dist/nile-combobox/nile-combobox.esm.js +11 -8
- package/dist/nile-combobox/portal-manager.cjs.js +1 -1
- package/dist/nile-combobox/portal-manager.cjs.js.map +1 -1
- package/dist/nile-combobox/portal-manager.esm.js +1 -1
- package/dist/nile-combobox/renderer.cjs.js +1 -1
- package/dist/nile-combobox/renderer.cjs.js.map +1 -1
- package/dist/nile-combobox/renderer.esm.js +31 -43
- package/dist/nile-floating-panel/nile-floating-panel.cjs.js +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.cjs.js.map +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.css.cjs.js +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.css.cjs.js.map +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.css.esm.js +46 -8
- package/dist/nile-floating-panel/nile-floating-panel.esm.js +1 -1
- package/dist/nile-popover/nile-popover.cjs.js +1 -1
- package/dist/nile-popover/nile-popover.cjs.js.map +1 -1
- package/dist/nile-popover/nile-popover.css.cjs.js +1 -1
- package/dist/nile-popover/nile-popover.css.cjs.js.map +1 -1
- package/dist/nile-popover/nile-popover.css.esm.js +32 -17
- package/dist/nile-popover/nile-popover.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/index.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/index.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-editor.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/index.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/nile-wysiwyg-toolbar/nile-wysiwyg-toolbar.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/bubble-menu.esm.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/embed-menu.esm.js +2 -2
- package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/image-menu.esm.js +4 -4
- package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-menu.cjs.js.map +1 -1
- package/dist/nile-wysiwyg-editor/ui/table-menu.esm.js +1 -1
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.js +6 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal/glyph.d.ts +6 -1
- package/dist/src/internal/glyph.js +8 -1
- package/dist/src/internal/glyph.js.map +1 -1
- package/dist/src/nile-app-shell/index.d.ts +7 -0
- package/dist/src/nile-app-shell/index.js +8 -0
- package/dist/src/nile-app-shell/index.js.map +1 -0
- package/dist/src/nile-app-shell/nile-app-shell-regions.test.d.ts +4 -0
- package/dist/src/nile-app-shell/nile-app-shell-regions.test.js +177 -0
- package/dist/src/nile-app-shell/nile-app-shell-regions.test.js.map +1 -0
- package/dist/src/nile-app-shell/nile-app-shell.css.d.ts +18 -0
- package/dist/src/nile-app-shell/nile-app-shell.css.js +572 -0
- package/dist/src/nile-app-shell/nile-app-shell.css.js.map +1 -0
- package/dist/src/nile-app-shell/nile-app-shell.d.ts +292 -0
- package/dist/src/nile-app-shell/nile-app-shell.js +796 -0
- package/dist/src/nile-app-shell/nile-app-shell.js.map +1 -0
- package/dist/src/nile-app-shell/nile-app-shell.test.d.ts +3 -0
- package/dist/src/nile-app-shell/nile-app-shell.test.js +454 -0
- package/dist/src/nile-app-shell/nile-app-shell.test.js.map +1 -0
- package/dist/src/nile-app-shell/shell-controller.d.ts +34 -0
- package/dist/src/nile-app-shell/shell-controller.js +80 -0
- package/dist/src/nile-app-shell/shell-controller.js.map +1 -0
- package/dist/src/nile-app-shell-main/index.d.ts +7 -0
- package/dist/src/nile-app-shell-main/index.js +8 -0
- package/dist/src/nile-app-shell-main/index.js.map +1 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.css.d.ts +9 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.css.js +27 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.css.js.map +1 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.d.ts +38 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.js +51 -0
- package/dist/src/nile-app-shell-main/nile-app-shell-main.js.map +1 -0
- package/dist/src/nile-app-shell-nav-toggle/index.d.ts +7 -0
- package/dist/src/nile-app-shell-nav-toggle/index.js +8 -0
- package/dist/src/nile-app-shell-nav-toggle/index.js.map +1 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.d.ts +13 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.js +42 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.js.map +1 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.d.ts +56 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.js +126 -0
- package/dist/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.js.map +1 -0
- package/dist/src/nile-app-shell-panel/index.d.ts +7 -0
- package/dist/src/nile-app-shell-panel/index.js +8 -0
- package/dist/src/nile-app-shell-panel/index.js.map +1 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.d.ts +9 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js +112 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js.map +1 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.d.ts +73 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.js +158 -0
- package/dist/src/nile-app-shell-panel/nile-app-shell-panel.js.map +1 -0
- package/dist/src/nile-app-shell-side-nav/index.d.ts +7 -0
- package/dist/src/nile-app-shell-side-nav/index.js +8 -0
- package/dist/src/nile-app-shell-side-nav/index.js.map +1 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.css.d.ts +13 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.css.js +68 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.css.js.map +1 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.d.ts +54 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.js +83 -0
- package/dist/src/nile-app-shell-side-nav/nile-app-shell-side-nav.js.map +1 -0
- package/dist/src/nile-combobox/nile-combobox.css.js +28 -15
- package/dist/src/nile-combobox/nile-combobox.css.js.map +1 -1
- package/dist/src/nile-combobox/nile-combobox.js +49 -10
- package/dist/src/nile-combobox/nile-combobox.js.map +1 -1
- package/dist/src/nile-combobox/portal-manager.js +2 -22
- package/dist/src/nile-combobox/portal-manager.js.map +1 -1
- package/dist/src/nile-combobox/renderer.d.ts +2 -3
- package/dist/src/nile-combobox/renderer.js +14 -45
- package/dist/src/nile-combobox/renderer.js.map +1 -1
- package/dist/src/nile-floating-panel/nile-floating-panel.css.js +46 -8
- package/dist/src/nile-floating-panel/nile-floating-panel.css.js.map +1 -1
- package/dist/src/nile-floating-panel/nile-floating-panel.js +13 -1
- package/dist/src/nile-floating-panel/nile-floating-panel.js.map +1 -1
- package/dist/src/nile-popover/nile-popover.css.js +30 -15
- package/dist/src/nile-popover/nile-popover.css.js.map +1 -1
- package/dist/src/nile-popover/nile-popover.js +1 -1
- package/dist/src/nile-popover/nile-popover.js.map +1 -1
- package/dist/src/nile-popover/nile-popover.test.js +1 -1
- package/dist/src/nile-popover/nile-popover.test.js.map +1 -1
- package/dist/src/version.d.ts +11 -1
- package/dist/src/version.js +56 -5
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.cjs.js +1 -1
- package/dist/version.cjs.js.map +1 -1
- package/dist/version.esm.js +1 -1
- package/package.json +8 -2
- package/scripts/replace-version.cjs +12 -10
- package/src/index.ts +16 -4
- package/src/internal/glyph.ts +12 -1
- package/src/nile-app-shell/index.ts +8 -0
- package/src/nile-app-shell/nile-app-shell-regions.test.ts +215 -0
- package/src/nile-app-shell/nile-app-shell.css.ts +574 -0
- package/src/nile-app-shell/nile-app-shell.test.ts +536 -0
- package/src/nile-app-shell/nile-app-shell.ts +838 -0
- package/src/nile-app-shell/shell-controller.ts +100 -0
- package/src/nile-app-shell-main/index.ts +8 -0
- package/src/nile-app-shell-main/nile-app-shell-main.css.ts +29 -0
- package/src/nile-app-shell-main/nile-app-shell-main.ts +52 -0
- package/src/nile-app-shell-nav-toggle/index.ts +8 -0
- package/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.css.ts +44 -0
- package/src/nile-app-shell-nav-toggle/nile-app-shell-nav-toggle.ts +138 -0
- package/src/nile-app-shell-panel/index.ts +8 -0
- package/src/nile-app-shell-panel/nile-app-shell-panel.css.ts +114 -0
- package/src/nile-app-shell-panel/nile-app-shell-panel.ts +161 -0
- package/src/nile-app-shell-side-nav/index.ts +8 -0
- package/src/nile-app-shell-side-nav/nile-app-shell-side-nav.css.ts +70 -0
- package/src/nile-app-shell-side-nav/nile-app-shell-side-nav.ts +86 -0
- package/src/nile-combobox/nile-combobox.css.ts +28 -15
- package/src/nile-combobox/nile-combobox.ts +61 -12
- package/src/nile-combobox/portal-manager.ts +4 -22
- package/src/nile-combobox/renderer.ts +26 -69
- package/src/nile-floating-panel/nile-floating-panel.css.ts +46 -8
- package/src/nile-floating-panel/nile-floating-panel.ts +19 -1
- package/src/nile-popover/nile-popover.css.ts +30 -15
- package/src/nile-popover/nile-popover.test.ts +1 -1
- package/src/nile-popover/nile-popover.ts +1 -1
- package/src/version.ts +61 -4
- package/vscode-html-custom-data.json +216 -5
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import { expect, fixture, html, oneEvent, waitUntil } from '@open-wc/testing';
|
|
2
|
+
import './nile-app-shell';
|
|
3
|
+
import '../nile-app-shell-nav-toggle/nile-app-shell-nav-toggle';
|
|
4
|
+
import '../nile-side-bar/nile-side-bar';
|
|
5
|
+
import type { NileAppShell } from './nile-app-shell';
|
|
6
|
+
import type { NileAppShellNavToggle } from '../nile-app-shell-nav-toggle/nile-app-shell-nav-toggle';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The shell derives its chrome from its own width, so most tests size the host
|
|
10
|
+
* explicitly and wait for the ResizeObserver to land.
|
|
11
|
+
*/
|
|
12
|
+
const sized = async (width: number) => {
|
|
13
|
+
const el = await fixture<NileAppShell>(html`
|
|
14
|
+
<nile-app-shell style="width: ${width}px; height: 600px;">
|
|
15
|
+
<nav slot="side-nav">nav</nav>
|
|
16
|
+
<span slot="top-bar">Title</span>
|
|
17
|
+
<p>page</p>
|
|
18
|
+
<div slot="panel">assistant</div>
|
|
19
|
+
</nile-app-shell>
|
|
20
|
+
`);
|
|
21
|
+
await waitUntil(() => el.hasAttribute('has-panel'));
|
|
22
|
+
return el;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** The same shell with an overlay drawer opted into, which is not the default. */
|
|
26
|
+
const overlaying = async (width: number) => {
|
|
27
|
+
const el = await fixture<NileAppShell>(html`
|
|
28
|
+
<nile-app-shell
|
|
29
|
+
style="width: ${width}px; height: 600px;"
|
|
30
|
+
overlay-breakpoint="1280"
|
|
31
|
+
>
|
|
32
|
+
<nav slot="side-nav">nav</nav>
|
|
33
|
+
<span slot="top-bar">Title</span>
|
|
34
|
+
<p>page</p>
|
|
35
|
+
<div slot="panel">assistant</div>
|
|
36
|
+
</nile-app-shell>
|
|
37
|
+
`);
|
|
38
|
+
await waitUntil(() => el.hasAttribute('has-panel'));
|
|
39
|
+
return el;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The side-nav track animates, so a width read straight after a state change
|
|
44
|
+
* catches the row mid-transition and sees room that is about to go away. Waits
|
|
45
|
+
* for two consecutive frames to agree before geometry is asserted.
|
|
46
|
+
*/
|
|
47
|
+
const settled = async (el: NileAppShell) => {
|
|
48
|
+
const section = el.shadowRoot!.querySelector('.content-section')!;
|
|
49
|
+
let last = -1;
|
|
50
|
+
await waitUntil(
|
|
51
|
+
() => {
|
|
52
|
+
const width = Math.round(section.getBoundingClientRect().width);
|
|
53
|
+
const same = width === last;
|
|
54
|
+
last = width;
|
|
55
|
+
return same;
|
|
56
|
+
},
|
|
57
|
+
'the shell never settled',
|
|
58
|
+
{ timeout: 3000, interval: 60 }
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const part = (el: NileAppShell, name: string) =>
|
|
63
|
+
el.shadowRoot!.querySelector(`[part~="${name}"]`) as HTMLElement | null;
|
|
64
|
+
|
|
65
|
+
describe('NileAppShell — regions', () => {
|
|
66
|
+
it('1. defaults to an expanded nav, a closed docked panel and a fluid body', async () => {
|
|
67
|
+
const el = await sized(1440);
|
|
68
|
+
expect(el.navCollapsed).to.be.false;
|
|
69
|
+
expect(el.panelOpen).to.be.false;
|
|
70
|
+
expect(el.panelMode).to.equal('docked');
|
|
71
|
+
expect(el.contentAlign).to.equal('fluid');
|
|
72
|
+
expect(el.rail).to.be.false;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('2. mounts only the regions that have slotted content', async () => {
|
|
76
|
+
const el = await sized(1440);
|
|
77
|
+
expect(el.hasAttribute('has-side-nav')).to.be.true;
|
|
78
|
+
expect(el.hasAttribute('has-top-bar')).to.be.true;
|
|
79
|
+
expect(el.hasAttribute('has-panel')).to.be.true;
|
|
80
|
+
expect(el.hasAttribute('has-banner')).to.be.false;
|
|
81
|
+
expect(el.hasAttribute('has-aside')).to.be.false;
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('3. reports no panel when the panel slot is empty', async () => {
|
|
85
|
+
const el = await fixture<NileAppShell>(
|
|
86
|
+
html`<nile-app-shell><p>page</p></nile-app-shell>`
|
|
87
|
+
);
|
|
88
|
+
expect(el.panelAvailable).to.be.false;
|
|
89
|
+
expect(el.hasAttribute('has-panel')).to.be.false;
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('4. renders the top bar inside the container by default', async () => {
|
|
93
|
+
const el = await sized(1440);
|
|
94
|
+
expect(part(el, 'container')!.contains(part(el, 'top-bar'))).to.be.true;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('5. spans the shell with the top bar when asked', async () => {
|
|
98
|
+
const el = await sized(1440);
|
|
99
|
+
el.topBarPlacement = 'shell';
|
|
100
|
+
await el.updateComplete;
|
|
101
|
+
const bar = part(el, 'top-bar')!;
|
|
102
|
+
expect(bar.classList.contains('shell-top-bar')).to.be.true;
|
|
103
|
+
expect(part(el, 'container')!.contains(bar)).to.be.false;
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
describe('NileAppShell — nav', () => {
|
|
108
|
+
it('6. collapseNav()/expandNav() drive the rail and reflect it', async () => {
|
|
109
|
+
const el = await sized(1440);
|
|
110
|
+
el.collapseNav();
|
|
111
|
+
await el.updateComplete;
|
|
112
|
+
expect(el.navCollapsed).to.be.true;
|
|
113
|
+
expect(el.hasAttribute('rail')).to.be.true;
|
|
114
|
+
|
|
115
|
+
el.expandNav();
|
|
116
|
+
await el.updateComplete;
|
|
117
|
+
expect(el.hasAttribute('rail')).to.be.false;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('7. toggleNav() flips, and accepts a forced state', async () => {
|
|
121
|
+
const el = await sized(1440);
|
|
122
|
+
el.toggleNav();
|
|
123
|
+
await el.updateComplete;
|
|
124
|
+
expect(el.navCollapsed).to.be.true;
|
|
125
|
+
el.toggleNav(true);
|
|
126
|
+
await el.updateComplete;
|
|
127
|
+
expect(el.navCollapsed).to.be.true;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('8. emits nile-nav-toggle with the collapsed state', async () => {
|
|
131
|
+
const el = await sized(1440);
|
|
132
|
+
const toggled = oneEvent(el, 'nile-nav-toggle');
|
|
133
|
+
el.collapseNav();
|
|
134
|
+
const event = await toggled;
|
|
135
|
+
expect(event.detail.collapsed).to.be.true;
|
|
136
|
+
expect(event.detail.locked).to.be.false;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('9. mirrors the effective rail onto a slotted nile-side-bar', async () => {
|
|
140
|
+
const el = await fixture<NileAppShell>(html`
|
|
141
|
+
<nile-app-shell style="width: 1440px; height: 600px;">
|
|
142
|
+
<nile-side-bar slot="side-nav"></nile-side-bar>
|
|
143
|
+
<p>page</p>
|
|
144
|
+
</nile-app-shell>
|
|
145
|
+
`);
|
|
146
|
+
const bar = el.querySelector('nile-side-bar')!;
|
|
147
|
+
el.collapseNav();
|
|
148
|
+
await el.updateComplete;
|
|
149
|
+
expect(bar.hasAttribute('collapsed')).to.be.true;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('10. the built-in toggle is disabled, not hidden, while the rail is forced', async () => {
|
|
153
|
+
const el = await sized(1000);
|
|
154
|
+
el.openPanel();
|
|
155
|
+
await waitUntil(() => el.navLocked);
|
|
156
|
+
const button = part(el, 'nav-toggle') as HTMLButtonElement;
|
|
157
|
+
expect(button).to.exist;
|
|
158
|
+
expect(button.disabled).to.be.true;
|
|
159
|
+
expect(el.hasAttribute('rail')).to.be.true;
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe('NileAppShell — Ask Aquera panel', () => {
|
|
164
|
+
it('11. openPanel()/closePanel() drive panel-open', async () => {
|
|
165
|
+
const el = await sized(1440);
|
|
166
|
+
el.openPanel();
|
|
167
|
+
await el.updateComplete;
|
|
168
|
+
expect(el.panelOpen).to.be.true;
|
|
169
|
+
expect(el.hasAttribute('panel-open')).to.be.true;
|
|
170
|
+
|
|
171
|
+
el.closePanel();
|
|
172
|
+
await el.updateComplete;
|
|
173
|
+
expect(el.panelOpen).to.be.false;
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('12. openPanel() is a no-op when the route opts out', async () => {
|
|
177
|
+
const el = await sized(1440);
|
|
178
|
+
el.noPanel = true;
|
|
179
|
+
await el.updateComplete;
|
|
180
|
+
el.openPanel();
|
|
181
|
+
await el.updateComplete;
|
|
182
|
+
expect(el.panelOpen).to.be.false;
|
|
183
|
+
expect(el.hasAttribute('has-panel')).to.be.false;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('13. emits nile-panel-toggle with the open state and mode', async () => {
|
|
187
|
+
const el = await sized(1440);
|
|
188
|
+
const toggled = oneEvent(el, 'nile-panel-toggle');
|
|
189
|
+
el.openPanel();
|
|
190
|
+
const event = await toggled;
|
|
191
|
+
expect(event.detail.open).to.be.true;
|
|
192
|
+
expect(event.detail.mode).to.equal('docked');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('14. pushes rather than overlays, however narrow the shell is', async () => {
|
|
196
|
+
for (const width of [1000, 820]) {
|
|
197
|
+
const el = await sized(width);
|
|
198
|
+
el.openPanel();
|
|
199
|
+
await el.updateComplete;
|
|
200
|
+
await settled(el);
|
|
201
|
+
expect(el.panelMode).to.equal('docked');
|
|
202
|
+
expect(el.getAttribute('panel-mode')).to.equal('docked');
|
|
203
|
+
const container = el.shadowRoot!.querySelector('.container')!;
|
|
204
|
+
const panel = el.shadowRoot!.querySelector('.panel')!;
|
|
205
|
+
// Beside the page, not over it.
|
|
206
|
+
expect(container.getBoundingClientRect().right).to.be.at.most(
|
|
207
|
+
Math.round(panel.getBoundingClientRect().left) + 1
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("14b. overlays below an author's breakpoint when one is set", async () => {
|
|
213
|
+
const el = await overlaying(1000);
|
|
214
|
+
await waitUntil(() => el.panelMode === 'overlay');
|
|
215
|
+
expect(el.getAttribute('panel-mode')).to.equal('overlay');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it('15. an open docked panel forces the rail below the docked breakpoint', async () => {
|
|
219
|
+
const el = await sized(1360);
|
|
220
|
+
await waitUntil(() => el.panelMode === 'docked');
|
|
221
|
+
expect(el.navLocked).to.be.false;
|
|
222
|
+
|
|
223
|
+
el.openPanel();
|
|
224
|
+
await waitUntil(() => el.navLocked);
|
|
225
|
+
expect(el.hasAttribute('rail')).to.be.true;
|
|
226
|
+
|
|
227
|
+
el.closePanel();
|
|
228
|
+
await waitUntil(() => !el.navLocked);
|
|
229
|
+
expect(el.hasAttribute('rail')).to.be.false;
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('16. the panel close button closes it', async () => {
|
|
233
|
+
const el = await sized(1440);
|
|
234
|
+
el.openPanel();
|
|
235
|
+
await el.updateComplete;
|
|
236
|
+
(part(el, 'panel-close') as HTMLButtonElement).click();
|
|
237
|
+
await el.updateComplete;
|
|
238
|
+
expect(el.panelOpen).to.be.false;
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('17. labels the panel and its default heading from panel-label', async () => {
|
|
242
|
+
const el = await sized(1440);
|
|
243
|
+
el.panelLabel = 'Ask Aquera';
|
|
244
|
+
await el.updateComplete;
|
|
245
|
+
expect(part(el, 'panel')!.getAttribute('aria-label')).to.equal(
|
|
246
|
+
'Ask Aquera'
|
|
247
|
+
);
|
|
248
|
+
expect(part(el, 'panel-title')!.textContent!.trim()).to.equal('Ask Aquera');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('18. Cmd/Ctrl+J toggles the panel', async () => {
|
|
252
|
+
const el = await sized(1440);
|
|
253
|
+
document.dispatchEvent(
|
|
254
|
+
new KeyboardEvent('keydown', { key: 'j', ctrlKey: true })
|
|
255
|
+
);
|
|
256
|
+
await el.updateComplete;
|
|
257
|
+
expect(el.panelOpen).to.be.true;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('19. Escape closes an overlay panel but leaves a docked one alone', async () => {
|
|
261
|
+
const docked = await sized(1440);
|
|
262
|
+
docked.openPanel();
|
|
263
|
+
await docked.updateComplete;
|
|
264
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
|
|
265
|
+
await docked.updateComplete;
|
|
266
|
+
expect(docked.panelOpen).to.be.true;
|
|
267
|
+
|
|
268
|
+
const overlay = await overlaying(1000);
|
|
269
|
+
await waitUntil(() => overlay.panelMode === 'overlay');
|
|
270
|
+
overlay.openPanel();
|
|
271
|
+
await overlay.updateComplete;
|
|
272
|
+
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }));
|
|
273
|
+
await overlay.updateComplete;
|
|
274
|
+
expect(overlay.panelOpen).to.be.false;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('20. no-panel-shortcut drops the keyboard handling', async () => {
|
|
278
|
+
const el = await sized(1440);
|
|
279
|
+
el.noPanelShortcut = true;
|
|
280
|
+
await el.updateComplete;
|
|
281
|
+
document.dispatchEvent(
|
|
282
|
+
new KeyboardEvent('keydown', { key: 'j', metaKey: true })
|
|
283
|
+
);
|
|
284
|
+
await el.updateComplete;
|
|
285
|
+
expect(el.panelOpen).to.be.false;
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('NileAppShell — content container', () => {
|
|
290
|
+
it('23. content-container makes the slotted page root a size container', async () => {
|
|
291
|
+
const el = await fixture<NileAppShell>(html`
|
|
292
|
+
<nile-app-shell style="width: 1440px; height: 600px;" content-container>
|
|
293
|
+
<div class="page">page</div>
|
|
294
|
+
</nile-app-shell>
|
|
295
|
+
`);
|
|
296
|
+
const page = el.querySelector('.page')!;
|
|
297
|
+
expect(getComputedStyle(page).containerType).to.equal('inline-size');
|
|
298
|
+
|
|
299
|
+
el.contentContainer = false;
|
|
300
|
+
await el.updateComplete;
|
|
301
|
+
expect(getComputedStyle(page).containerType).to.equal('normal');
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
describe('NileAppShellNavToggle', () => {
|
|
306
|
+
it('21. drives the nearest shell and mirrors its rail state', async () => {
|
|
307
|
+
const el = await fixture<NileAppShell>(html`
|
|
308
|
+
<nile-app-shell style="width: 1440px; height: 600px;" no-nav-toggle>
|
|
309
|
+
<nav slot="side-nav">nav</nav>
|
|
310
|
+
<nile-app-shell-nav-toggle slot="top-bar"></nile-app-shell-nav-toggle>
|
|
311
|
+
<p>page</p>
|
|
312
|
+
</nile-app-shell>
|
|
313
|
+
`);
|
|
314
|
+
const toggle = el.querySelector<NileAppShellNavToggle>(
|
|
315
|
+
'nile-app-shell-nav-toggle'
|
|
316
|
+
)!;
|
|
317
|
+
await waitUntil(() => toggle.appShell === el);
|
|
318
|
+
|
|
319
|
+
// The control is a nile-button, so the raw <button> is a shadow root
|
|
320
|
+
// deeper. The part is the contract either way.
|
|
321
|
+
const button = () =>
|
|
322
|
+
toggle.shadowRoot!.querySelector<HTMLElement & { disabled: boolean }>(
|
|
323
|
+
'[part~="button"]'
|
|
324
|
+
)!;
|
|
325
|
+
button().click();
|
|
326
|
+
await el.updateComplete;
|
|
327
|
+
expect(el.navCollapsed).to.be.true;
|
|
328
|
+
|
|
329
|
+
await toggle.updateComplete;
|
|
330
|
+
expect(button().getAttribute('aria-expanded')).to.equal('false');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('22. disables itself while the shell holds the rail', async () => {
|
|
334
|
+
const el = await fixture<NileAppShell>(html`
|
|
335
|
+
<nile-app-shell
|
|
336
|
+
style="width: 1000px; height: 600px;"
|
|
337
|
+
no-nav-toggle
|
|
338
|
+
panel-open
|
|
339
|
+
>
|
|
340
|
+
<nav slot="side-nav">nav</nav>
|
|
341
|
+
<nile-app-shell-nav-toggle slot="top-bar"></nile-app-shell-nav-toggle>
|
|
342
|
+
<div slot="panel">assistant</div>
|
|
343
|
+
<p>page</p>
|
|
344
|
+
</nile-app-shell>
|
|
345
|
+
`);
|
|
346
|
+
const toggle = el.querySelector<NileAppShellNavToggle>(
|
|
347
|
+
'nile-app-shell-nav-toggle'
|
|
348
|
+
)!;
|
|
349
|
+
await waitUntil(() => el.navLocked);
|
|
350
|
+
await toggle.updateComplete;
|
|
351
|
+
expect(
|
|
352
|
+
toggle.shadowRoot!.querySelector<HTMLElement & { disabled: boolean }>(
|
|
353
|
+
'[part~="button"]'
|
|
354
|
+
)!.disabled
|
|
355
|
+
).to.be.true;
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* The row is nav + container + aside + panel. When the sum of what a route
|
|
361
|
+
* mounts exceeds the shell, something has to give — and the one thing that may
|
|
362
|
+
* not give is the row overflowing into :host's clip, which silently cuts the
|
|
363
|
+
* panel off the right edge.
|
|
364
|
+
*/
|
|
365
|
+
describe('NileAppShell — the content row never overflows', () => {
|
|
366
|
+
const withAside = async (width: number) => {
|
|
367
|
+
const el = await fixture<NileAppShell>(html`
|
|
368
|
+
<nile-app-shell style="width: ${width}px; height: 600px;" panel-open>
|
|
369
|
+
<nav slot="side-nav">nav</nav>
|
|
370
|
+
<span slot="top-bar">Title</span>
|
|
371
|
+
<p>page</p>
|
|
372
|
+
<div slot="aside">aside</div>
|
|
373
|
+
<div slot="panel">assistant</div>
|
|
374
|
+
</nile-app-shell>
|
|
375
|
+
`);
|
|
376
|
+
await waitUntil(() => el.hasAttribute('has-aside'));
|
|
377
|
+
return el;
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/** Overflow of the flex row past the box that clips it. */
|
|
381
|
+
const overflow = (el: NileAppShell) => {
|
|
382
|
+
const section = el.shadowRoot!.querySelector('.content-section')!;
|
|
383
|
+
return (
|
|
384
|
+
section.scrollWidth - Math.round(section.getBoundingClientRect().width)
|
|
385
|
+
);
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
it('23. tightens the side columns rather than covering the page', async () => {
|
|
389
|
+
// 232px short of what the row prefers, so the panel and the aside give
|
|
390
|
+
// some width back — and the page still sits beside the panel, not under.
|
|
391
|
+
const el = await withAside(1500);
|
|
392
|
+
await waitUntil(() => el.navLocked);
|
|
393
|
+
await settled(el);
|
|
394
|
+
expect(el.panelMode).to.equal('docked');
|
|
395
|
+
const panel = el.shadowRoot!.querySelector('.panel')!;
|
|
396
|
+
const width = panel.getBoundingClientRect().width;
|
|
397
|
+
expect(width).to.be.below(480);
|
|
398
|
+
expect(width).to.be.at.least(360);
|
|
399
|
+
expect(overflow(el)).to.equal(0);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('24. rails the nav rather than clip the row', async () => {
|
|
403
|
+
// 1600 fits the docked panel over a rail, not over the expanded track.
|
|
404
|
+
const el = await withAside(1600);
|
|
405
|
+
await waitUntil(() => el.navLocked);
|
|
406
|
+
await settled(el);
|
|
407
|
+
expect(el.panelMode).to.equal('docked');
|
|
408
|
+
expect(overflow(el)).to.equal(0);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('25. holds the container floor while the row has room for it', async () => {
|
|
412
|
+
const el = await withAside(1800);
|
|
413
|
+
await waitUntil(() => el.panelMode === 'docked');
|
|
414
|
+
await settled(el);
|
|
415
|
+
const container = el.shadowRoot!.querySelector('.container')!;
|
|
416
|
+
expect(container.getBoundingClientRect().width).to.be.at.least(640);
|
|
417
|
+
expect(el.navLocked).to.be.false;
|
|
418
|
+
expect(overflow(el)).to.equal(0);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('26. asks the page for room last, and only after the floors are met', async () => {
|
|
422
|
+
const el = await withAside(820);
|
|
423
|
+
await waitUntil(() => el.navLocked);
|
|
424
|
+
await settled(el);
|
|
425
|
+
const px = (sel: string) =>
|
|
426
|
+
el.shadowRoot!.querySelector(sel)!.getBoundingClientRect().width;
|
|
427
|
+
// Both side columns sit on their floors before the page gives anything.
|
|
428
|
+
expect(Math.round(px('.panel'))).to.equal(360);
|
|
429
|
+
expect(Math.round(px('.aside'))).to.equal(240);
|
|
430
|
+
expect(px('.container')).to.be.below(640);
|
|
431
|
+
expect(overflow(el)).to.equal(0);
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('27. keeps the page above its floor at ordinary widths', async () => {
|
|
435
|
+
const el = await sized(1300);
|
|
436
|
+
el.openPanel();
|
|
437
|
+
await el.updateComplete;
|
|
438
|
+
await settled(el);
|
|
439
|
+
expect(el.panelMode).to.equal('docked');
|
|
440
|
+
const container = el.shadowRoot!.querySelector('.container')!;
|
|
441
|
+
expect(container.getBoundingClientRect().width).to.be.at.least(640);
|
|
442
|
+
expect(overflow(el)).to.equal(0);
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* An empty flex item is not a free one: it still takes the row's gap before
|
|
448
|
+
* it, which is enough to pull the bar's content short of its padding edge.
|
|
449
|
+
*/
|
|
450
|
+
describe('NileAppShell — the top bar reaches its padding edge', () => {
|
|
451
|
+
it('28. an empty actions group reserves no gap', async () => {
|
|
452
|
+
const el = await sized(1440);
|
|
453
|
+
// The Ask button lives in that group, so drop it to leave it truly empty.
|
|
454
|
+
el.noAsk = true;
|
|
455
|
+
await settled(el);
|
|
456
|
+
expect(el.hasAttribute('has-top-bar-actions')).to.be.false;
|
|
457
|
+
expect(el.hasAttribute('has-ask')).to.be.false;
|
|
458
|
+
const bar = el.shadowRoot!.querySelector('.top-bar') as HTMLElement;
|
|
459
|
+
const content = el.shadowRoot!.querySelector('.top-bar-content')!;
|
|
460
|
+
const padEnd = parseFloat(getComputedStyle(bar).paddingInlineEnd);
|
|
461
|
+
const shortfall =
|
|
462
|
+
bar.getBoundingClientRect().right - content.getBoundingClientRect().right;
|
|
463
|
+
expect(Math.round(shortfall)).to.equal(Math.round(padEnd));
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('29. slotted actions mount the group', async () => {
|
|
467
|
+
const el = await fixture<NileAppShell>(html`
|
|
468
|
+
<nile-app-shell style="width: 1440px; height: 600px;">
|
|
469
|
+
<nav slot="side-nav">nav</nav>
|
|
470
|
+
<span slot="top-bar">Title</span>
|
|
471
|
+
<button slot="top-bar-actions">Save</button>
|
|
472
|
+
<p>page</p>
|
|
473
|
+
</nile-app-shell>
|
|
474
|
+
`);
|
|
475
|
+
await waitUntil(() => el.hasAttribute('has-top-bar-actions'));
|
|
476
|
+
const actions = el.shadowRoot!.querySelector('.top-bar-actions')!;
|
|
477
|
+
expect(getComputedStyle(actions).display).to.not.equal('none');
|
|
478
|
+
expect(actions.getBoundingClientRect().width).to.be.greaterThan(0);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* The Ask door moved onto the shell when nile-app-shell-header became a slot.
|
|
484
|
+
* It is the one control in the bar that cannot be slotted markup: it turns on
|
|
485
|
+
* whether a panel is mounted for this route, and it calls openPanel().
|
|
486
|
+
*/
|
|
487
|
+
describe('NileAppShell — the built-in Ask button', () => {
|
|
488
|
+
const ask = (el: NileAppShell) => part(el, 'ask') as HTMLButtonElement | null;
|
|
489
|
+
|
|
490
|
+
it('30. opens the panel', async () => {
|
|
491
|
+
const el = await sized(1440);
|
|
492
|
+
expect(el.panelOpen).to.be.false;
|
|
493
|
+
ask(el)!.click();
|
|
494
|
+
await el.updateComplete;
|
|
495
|
+
expect(el.panelOpen).to.be.true;
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('31. is absent when the route mounts no panel', async () => {
|
|
499
|
+
const el = await fixture<NileAppShell>(html`
|
|
500
|
+
<nile-app-shell style="width: 1440px; height: 600px;">
|
|
501
|
+
<nav slot="side-nav">nav</nav>
|
|
502
|
+
<span slot="top-bar">Title</span>
|
|
503
|
+
<p>page</p>
|
|
504
|
+
</nile-app-shell>
|
|
505
|
+
`);
|
|
506
|
+
await el.updateComplete;
|
|
507
|
+
expect(el.askVisible).to.be.false;
|
|
508
|
+
expect(ask(el)).to.be.null;
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
it('32. no-ask drops it for a bar that renders its own', async () => {
|
|
512
|
+
const el = await sized(1440);
|
|
513
|
+
el.noAsk = true;
|
|
514
|
+
await el.updateComplete;
|
|
515
|
+
expect(el.askVisible).to.be.false;
|
|
516
|
+
expect(ask(el)).to.be.null;
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it('33. takes its label from ask-label', async () => {
|
|
520
|
+
const el = await sized(1440);
|
|
521
|
+
el.askLabel = 'Ask Aquera';
|
|
522
|
+
await el.updateComplete;
|
|
523
|
+
expect(ask(el)!.textContent!.trim()).to.equal('Ask Aquera');
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('34. keeps the actions group mounted on its own', async () => {
|
|
527
|
+
const el = await sized(1440);
|
|
528
|
+
await settled(el);
|
|
529
|
+
// Nothing is slotted into top-bar-actions, but the Ask button lives there.
|
|
530
|
+
expect(el.hasAttribute('has-top-bar-actions')).to.be.false;
|
|
531
|
+
expect(el.hasAttribute('has-ask')).to.be.true;
|
|
532
|
+
const actions = el.shadowRoot!.querySelector('.top-bar-actions')!;
|
|
533
|
+
expect(getComputedStyle(actions).display).to.not.equal('none');
|
|
534
|
+
expect(actions.getBoundingClientRect().width).to.be.greaterThan(0);
|
|
535
|
+
});
|
|
536
|
+
});
|