@operato/layout 10.29.14 → 10.29.17
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/CHANGELOG.md +28 -0
- package/coverage/lcov-report/index.html +37 -37
- package/coverage/lcov.info +818 -499
- package/dist/src/actions/entity360-name.d.ts +0 -10
- package/dist/src/actions/entity360-name.js +15 -3
- package/dist/src/actions/entity360-name.js.map +1 -1
- package/dist/src/components/ox-entity360-dock.d.ts +4 -0
- package/dist/src/components/ox-entity360-dock.js +33 -12
- package/dist/src/components/ox-entity360-dock.js.map +1 -1
- package/dist/src/components/ox-entity360-section.js +4 -3
- package/dist/src/components/ox-entity360-section.js.map +1 -1
- package/dist/test/entity360.test.js +16 -1
- package/dist/test/entity360.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/test/entity360.test.ts +17 -1
|
@@ -1,12 +1,2 @@
|
|
|
1
1
|
import { type TemplateResult } from 'lit';
|
|
2
|
-
/**
|
|
3
|
-
* An entity's name as the screen draws it: a link to its 360 when its kind is registered, the plain
|
|
4
|
-
* text otherwise (ADR-0067 decision 1 - an entity's name opens its 360; ADR-0071 - no dead links).
|
|
5
|
-
*
|
|
6
|
-
* One markup for every place a name is drawn - a grid cell, a ribbon's 「담당자」, a detail's
|
|
7
|
-
* 「올린 사람」 - so a person reads the same underline as the same promise everywhere.
|
|
8
|
-
*
|
|
9
|
-
* The link is the body colour with an underline (ADR-0071's link rule). A click does not travel on:
|
|
10
|
-
* inside a grid row it would start editing or select the row.
|
|
11
|
-
*/
|
|
12
2
|
export declare function entity360Name(value: Record<string, any> | null | undefined, text?: string): TemplateResult | string;
|
|
@@ -5,11 +5,19 @@ import { entity360KindOf, openEntity360For } from './entity360-registry.js';
|
|
|
5
5
|
* text otherwise (ADR-0067 decision 1 - an entity's name opens its 360; ADR-0071 - no dead links).
|
|
6
6
|
*
|
|
7
7
|
* One markup for every place a name is drawn - a grid cell, a ribbon's 「담당자」, a detail's
|
|
8
|
-
* 「올린 사람」 -
|
|
8
|
+
* 「올린 사람」 - with the same interaction everywhere.
|
|
9
9
|
*
|
|
10
|
-
* The link
|
|
10
|
+
* The link keeps the body colour and carries a thin, faint underline set off from the text, so a
|
|
11
|
+
* column of names stays calm; the line firms up under the pointer or keyboard focus. Keep this in
|
|
12
|
+
* the helper as it also renders inside grid and section shadow roots. A click does not travel on:
|
|
11
13
|
* inside a grid row it would start editing or select the row.
|
|
12
14
|
*/
|
|
15
|
+
const LINE_REST = 'color-mix(in srgb, currentColor 30%, transparent)';
|
|
16
|
+
const LINE_ACTIVE = 'color-mix(in srgb, currentColor 65%, transparent)';
|
|
17
|
+
function updateDecoration(event, hovered) {
|
|
18
|
+
const link = event.currentTarget;
|
|
19
|
+
link.style.textDecorationColor = hovered || link.matches(':hover, :focus-visible') ? LINE_ACTIVE : LINE_REST;
|
|
20
|
+
}
|
|
13
21
|
export function entity360Name(value, text) {
|
|
14
22
|
var _a;
|
|
15
23
|
const label = (_a = text !== null && text !== void 0 ? text : value === null || value === void 0 ? void 0 : value.name) !== null && _a !== void 0 ? _a : '';
|
|
@@ -18,7 +26,11 @@ export function entity360Name(value, text) {
|
|
|
18
26
|
return html `<a
|
|
19
27
|
href="#"
|
|
20
28
|
data-entity360
|
|
21
|
-
style="color: inherit; text-decoration: underline;
|
|
29
|
+
style="color: inherit; cursor: pointer; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: ${LINE_REST}; transition: text-decoration-color 0.12s"
|
|
30
|
+
@pointerenter=${(event) => updateDecoration(event, true)}
|
|
31
|
+
@pointerleave=${(event) => updateDecoration(event, false)}
|
|
32
|
+
@focus=${(event) => updateDecoration(event, false)}
|
|
33
|
+
@blur=${(event) => updateDecoration(event, false)}
|
|
22
34
|
@pointerdown=${(event) => event.stopPropagation()}
|
|
23
35
|
@keydown=${(event) => {
|
|
24
36
|
if (event.key === 'Enter')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity360-name.js","sourceRoot":"","sources":["../../../src/actions/entity360-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE3E
|
|
1
|
+
{"version":3,"file":"entity360-name.js","sourceRoot":"","sources":["../../../src/actions/entity360-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAE3E;;;;;;;;;;;GAWG;AACH,MAAM,SAAS,GAAG,mDAAmD,CAAA;AACrE,MAAM,WAAW,GAAG,mDAAmD,CAAA;AAEvE,SAAS,gBAAgB,CAAC,KAAY,EAAE,OAAgB;IACtD,MAAM,IAAI,GAAG,KAAK,CAAC,aAA4B,CAAA;IAC/C,IAAI,CAAC,KAAK,CAAC,mBAAmB,GAAG,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9G,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAA6C,EAAE,IAAa;;IACxF,MAAM,KAAK,GAAG,MAAA,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,mCAAI,EAAE,CAAA;IAEvC,IAAI,CAAC,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAEnD,OAAO,IAAI,CAAA;;;6JAGgJ,SAAS;oBAClJ,CAAC,KAAY,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC;oBAC/C,CAAC,KAAY,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;aACvD,CAAC,KAAY,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;YACjD,CAAC,KAAY,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC;mBACzC,CAAC,KAAY,EAAE,EAAE,CAAC,KAAK,CAAC,eAAe,EAAE;eAC7C,CAAC,KAAoB,EAAE,EAAE;QAClC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO;YAAE,KAAK,CAAC,eAAe,EAAE,CAAA;IACpD,CAAC;aACQ,CAAC,KAAY,EAAE,EAAE;QACxB,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,KAAK,CAAC,eAAe,EAAE,CAAA;QACvB,MAAM,MAAM,GAAG,KAAK,CAAC,aAA4B,CAAA;QACjD,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,MAAM,CAAC,WAAW;YAAE,MAAM,CAAC,KAAK,EAAE,CAAA,CAAC,CAAC,CAAC,CAAA;IAC3E,CAAC;OACE,KAAK;IACR,CAAA;AACJ,CAAC","sourcesContent":["import { html, type TemplateResult } from 'lit'\n\nimport { entity360KindOf, openEntity360For } from './entity360-registry.js'\n\n/**\n * An entity's name as the screen draws it: a link to its 360 when its kind is registered, the plain\n * text otherwise (ADR-0067 decision 1 - an entity's name opens its 360; ADR-0071 - no dead links).\n *\n * One markup for every place a name is drawn - a grid cell, a ribbon's 「담당자」, a detail's\n * 「올린 사람」 - with the same interaction everywhere.\n *\n * The link keeps the body colour and carries a thin, faint underline set off from the text, so a\n * column of names stays calm; the line firms up under the pointer or keyboard focus. Keep this in\n * the helper as it also renders inside grid and section shadow roots. A click does not travel on:\n * inside a grid row it would start editing or select the row.\n */\nconst LINE_REST = 'color-mix(in srgb, currentColor 30%, transparent)'\nconst LINE_ACTIVE = 'color-mix(in srgb, currentColor 65%, transparent)'\n\nfunction updateDecoration(event: Event, hovered: boolean) {\n const link = event.currentTarget as HTMLElement\n link.style.textDecorationColor = hovered || link.matches(':hover, :focus-visible') ? LINE_ACTIVE : LINE_REST\n}\n\nexport function entity360Name(value: Record<string, any> | null | undefined, text?: string): TemplateResult | string {\n const label = text ?? value?.name ?? ''\n\n if (!value || !entity360KindOf(value)) return label\n\n return html`<a\n href=\"#\"\n data-entity360\n style=\"color: inherit; cursor: pointer; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; text-decoration-color: ${LINE_REST}; transition: text-decoration-color 0.12s\"\n @pointerenter=${(event: Event) => updateDecoration(event, true)}\n @pointerleave=${(event: Event) => updateDecoration(event, false)}\n @focus=${(event: Event) => updateDecoration(event, false)}\n @blur=${(event: Event) => updateDecoration(event, false)}\n @pointerdown=${(event: Event) => event.stopPropagation()}\n @keydown=${(event: KeyboardEvent) => {\n if (event.key === 'Enter') event.stopPropagation()\n }}\n @click=${(event: Event) => {\n event.preventDefault()\n event.stopPropagation()\n const opener = event.currentTarget as HTMLElement\n openEntity360For(value, () => { if (opener.isConnected) opener.focus() })\n }}\n >${label}</a\n >`\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import '@material/web/icon/icon.js';
|
|
1
2
|
import { LitElement, type CSSResult, type TemplateResult } from 'lit';
|
|
2
3
|
/** Products supply authorized contents and words; the shared dock owns presentation only. */
|
|
3
4
|
export interface Entity360View {
|
|
@@ -13,6 +14,7 @@ export interface Entity360View {
|
|
|
13
14
|
collapse: string;
|
|
14
15
|
resize: string;
|
|
15
16
|
back: string;
|
|
17
|
+
refresh?: string;
|
|
16
18
|
};
|
|
17
19
|
onClose(): void;
|
|
18
20
|
onBack?: () => void;
|
|
@@ -20,9 +22,11 @@ export interface Entity360View {
|
|
|
20
22
|
/** Product CSS stays inside this boundary, never changes the dock's layout or controls. */
|
|
21
23
|
export declare class OxEntity360Content extends LitElement {
|
|
22
24
|
view?: Entity360View;
|
|
25
|
+
revision: number;
|
|
23
26
|
render(): TemplateResult<1>;
|
|
24
27
|
}
|
|
25
28
|
export declare class OxEntity360Dock extends LitElement {
|
|
29
|
+
private revision;
|
|
26
30
|
static styles: CSSResult[];
|
|
27
31
|
view?: Entity360View;
|
|
28
32
|
expanded: boolean;
|
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
+
import '@material/web/icon/icon.js';
|
|
2
3
|
import { LitElement, css, html } from 'lit';
|
|
3
4
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
5
|
+
import { keyed } from 'lit/directives/keyed.js';
|
|
6
|
+
import { i18next } from '@operato/i18n';
|
|
4
7
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
5
8
|
import { ScrollbarStyles } from '@operato/styles';
|
|
6
9
|
/** Product CSS stays inside this boundary, never changes the dock's layout or controls. */
|
|
7
10
|
let OxEntity360Content = class OxEntity360Content extends LitElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.revision = 0;
|
|
14
|
+
}
|
|
8
15
|
render() {
|
|
9
|
-
var _a, _b, _c;
|
|
10
|
-
return html `<style>${((_b = (_a = this.view) === null || _a === void 0 ? void 0 : _a.styles) !== null && _b !== void 0 ? _b : []).map(style => style.cssText).join('\n')}</style>${(_c = this.view) === null || _c === void 0 ? void 0 : _c.content}`;
|
|
16
|
+
var _a, _b, _c, _d;
|
|
17
|
+
return html `<style>${((_b = (_a = this.view) === null || _a === void 0 ? void 0 : _a.styles) !== null && _b !== void 0 ? _b : []).map(style => style.cssText).join('\n')}</style>${keyed(`${(_c = this.view) === null || _c === void 0 ? void 0 : _c.key}:${this.revision}`, (_d = this.view) === null || _d === void 0 ? void 0 : _d.content)}`;
|
|
11
18
|
}
|
|
12
19
|
};
|
|
13
20
|
__decorate([
|
|
14
21
|
property({ attribute: false })
|
|
15
22
|
], OxEntity360Content.prototype, "view", void 0);
|
|
23
|
+
__decorate([
|
|
24
|
+
property({ type: Number })
|
|
25
|
+
], OxEntity360Content.prototype, "revision", void 0);
|
|
16
26
|
OxEntity360Content = __decorate([
|
|
17
27
|
customElement('ox-entity360-content')
|
|
18
28
|
], OxEntity360Content);
|
|
@@ -20,6 +30,7 @@ export { OxEntity360Content };
|
|
|
20
30
|
let OxEntity360Dock = class OxEntity360Dock extends LitElement {
|
|
21
31
|
constructor() {
|
|
22
32
|
super(...arguments);
|
|
33
|
+
this.revision = 0;
|
|
23
34
|
this.expanded = false;
|
|
24
35
|
this.width = 480;
|
|
25
36
|
this.media = matchMedia('(max-width: 900px)');
|
|
@@ -70,6 +81,7 @@ let OxEntity360Dock = class OxEntity360Dock extends LitElement {
|
|
|
70
81
|
this.style.setProperty('--entity360-width', `${this.width}px`);
|
|
71
82
|
}
|
|
72
83
|
render() {
|
|
84
|
+
var _a, _b;
|
|
73
85
|
const view = this.view;
|
|
74
86
|
if (!view)
|
|
75
87
|
return html ``;
|
|
@@ -94,14 +106,16 @@ let OxEntity360Dock = class OxEntity360Dock extends LitElement {
|
|
|
94
106
|
@pointerup=${() => { this.dragStart = undefined; }} @pointercancel=${() => { this.dragStart = undefined; }}
|
|
95
107
|
></div>
|
|
96
108
|
<header>
|
|
97
|
-
${view.onBack ? html `<button data-action="back" aria-label=${view.labels.back} title=${view.labels.back} @click=${view.onBack}
|
|
109
|
+
${view.onBack ? html `<button data-action="back" aria-label=${view.labels.back} title=${view.labels.back} @click=${view.onBack}><md-icon aria-hidden="true">arrow_back</md-icon></button>` : ''}
|
|
98
110
|
<div class="heading" aria-live="polite"><h2 id="entity360-title" tabindex="-1">${view.title}</h2><p>${view.context}</p></div>
|
|
111
|
+
<button data-action="refresh" aria-label=${(_a = view.labels.refresh) !== null && _a !== void 0 ? _a : i18next.t('button.refresh')}
|
|
112
|
+
title=${(_b = view.labels.refresh) !== null && _b !== void 0 ? _b : i18next.t('button.refresh')} @click=${() => { this.revision++; }}><md-icon aria-hidden="true">refresh</md-icon></button>
|
|
99
113
|
<button class="expand" data-action="expand" aria-label=${this.expanded ? view.labels.collapse : view.labels.expand}
|
|
100
114
|
title=${this.expanded ? view.labels.collapse : view.labels.expand} aria-pressed=${this.expanded}
|
|
101
|
-
@click=${() => { this.expanded = !this.expanded; }}>${this.expanded ? '
|
|
102
|
-
<button data-action="close" aria-label=${view.labels.close} title=${view.labels.close} @click=${view.onClose}
|
|
115
|
+
@click=${() => { this.expanded = !this.expanded; }}><md-icon aria-hidden="true">${this.expanded ? 'fullscreen_exit' : 'fullscreen'}</md-icon></button>
|
|
116
|
+
<button data-action="close" aria-label=${view.labels.close} title=${view.labels.close} @click=${view.onClose}><md-icon aria-hidden="true">close</md-icon></button>
|
|
103
117
|
</header>
|
|
104
|
-
<div class="body"><ox-entity360-content .view=${view}></ox-entity360-content></div>
|
|
118
|
+
<div class="body"><ox-entity360-content .view=${view} .revision=${this.revision}></ox-entity360-content></div>
|
|
105
119
|
</aside>`;
|
|
106
120
|
}
|
|
107
121
|
};
|
|
@@ -111,14 +125,18 @@ OxEntity360Dock.styles = [ScrollbarStyles, css `
|
|
|
111
125
|
border-left: 1px solid var(--ui-line, #ccc); box-sizing: border-box; position: relative; }
|
|
112
126
|
:host([expanded]) { position: fixed; inset: 0; width: 100vw; max-width: none; height: 100dvh; z-index: 901; }
|
|
113
127
|
aside { height: 100%; display: flex; flex-direction: column; min-height: 0; }
|
|
114
|
-
header { display: flex; align-items: flex-start; gap:
|
|
128
|
+
header { display: flex; align-items: flex-start; gap: 6px; padding: 12px 14px;
|
|
115
129
|
border-bottom: 1px solid var(--ui-line, #ccc); flex: none; }
|
|
116
130
|
.heading { flex: 1; min-width: 0; }
|
|
117
|
-
h2 { font: 600
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
131
|
+
h2 { font: 600 15px/1.4 var(--ui-font-family, sans-serif); margin: 0; overflow-wrap: anywhere; }
|
|
132
|
+
h2:focus { outline: none; }
|
|
133
|
+
p { font: 12px/1.4 var(--ui-font-family, sans-serif); margin: 4px 0 0; overflow-wrap: anywhere; color: var(--md-sys-color-on-surface-variant, #555); }
|
|
134
|
+
button { font: 14px/1 sans-serif; width: 28px; height: 28px; padding: 0; display: grid; place-items: center;
|
|
135
|
+
flex: none; cursor: pointer; border: none;
|
|
136
|
+
border-radius: 6px; background: transparent; color: inherit; }
|
|
137
|
+
p:empty { display: none; }
|
|
138
|
+
button md-icon { --md-icon-size: 20px; }
|
|
139
|
+
button:hover { background: var(--md-sys-color-surface-container-high, #eee); }
|
|
122
140
|
button:focus-visible, [role=separator]:focus-visible { outline: 2px solid var(--md-sys-color-primary, #2865ad); outline-offset: -2px; }
|
|
123
141
|
.body { overflow: auto; scrollbar-gutter: stable; min-height: 0; flex: 1; overscroll-behavior: contain; }
|
|
124
142
|
.resize { position: absolute; left: -3px; top: 0; bottom: 0; width: 7px; cursor: col-resize; touch-action: none; z-index: 1; }
|
|
@@ -129,6 +147,9 @@ OxEntity360Dock.styles = [ScrollbarStyles, css `
|
|
|
129
147
|
}
|
|
130
148
|
@media (pointer: coarse) { button { width: 40px; height: 40px; } }
|
|
131
149
|
`];
|
|
150
|
+
__decorate([
|
|
151
|
+
state()
|
|
152
|
+
], OxEntity360Dock.prototype, "revision", void 0);
|
|
132
153
|
__decorate([
|
|
133
154
|
property({ attribute: false })
|
|
134
155
|
], OxEntity360Dock.prototype, "view", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ox-entity360-dock.js","sourceRoot":"","sources":["../../../src/components/ox-entity360-dock.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, type CSSResult, type TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\n/** Products supply authorized contents and words; the shared dock owns presentation only. */\nexport interface Entity360View {\n /** Canonical subject + read scope, not a display name. Different revisions must have different keys. */\n key: string\n title: string\n context: string\n content: TemplateResult\n styles?: CSSResult[]\n labels: { close: string; expand: string; collapse: string; resize: string; back: string }\n onClose(): void\n onBack?: () => void\n}\n\n/** Product CSS stays inside this boundary, never changes the dock's layout or controls. */\n@customElement('ox-entity360-content')\nexport class OxEntity360Content extends LitElement {\n @property({ attribute: false }) view?: Entity360View\n render() {\n return html`<style>${(this.view?.styles ?? []).map(style => style.cssText).join('\\n')}</style>${this.view?.content}`\n }\n}\n\n@customElement('ox-entity360-dock')\nexport class OxEntity360Dock extends LitElement {\n static styles = [ScrollbarStyles, css`\n :host { display: block; width: var(--entity360-width, 480px); max-width: 65vw; height: 100%; min-height: 0;\n color: var(--md-sys-color-on-surface, #222); background: var(--md-sys-color-surface, white);\n border-left: 1px solid var(--ui-line, #ccc); box-sizing: border-box; position: relative; }\n :host([expanded]) { position: fixed; inset: 0; width: 100vw; max-width: none; height: 100dvh; z-index: 901; }\n aside { height: 100%; display: flex; flex-direction: column; min-height: 0; }\n header { display: flex; align-items: flex-start; gap: 8px; padding: 14px 16px;\n border-bottom: 1px solid var(--ui-line, #ccc); flex: none; }\n .heading { flex: 1; min-width: 0; }\n h2 { font: 600 18px/1.4 sans-serif; margin: 0; overflow-wrap: anywhere; }\n p { font: 13px/1.5 sans-serif; margin: 6px 0 0; overflow-wrap: anywhere; color: var(--md-sys-color-on-surface-variant, #555); }\n button { font: 14px/1 sans-serif; width: 26px; height: 26px; padding: 0; display: grid; place-items: center;\n flex: none; cursor: pointer; border: 1px solid var(--ui-line, #ccc);\n border-radius: 4px; background: transparent; color: inherit; }\n button:focus-visible, [role=separator]:focus-visible { outline: 2px solid var(--md-sys-color-primary, #2865ad); outline-offset: -2px; }\n .body { overflow: auto; scrollbar-gutter: stable; min-height: 0; flex: 1; overscroll-behavior: contain; }\n .resize { position: absolute; left: -3px; top: 0; bottom: 0; width: 7px; cursor: col-resize; touch-action: none; z-index: 1; }\n :host([expanded]) .resize { display: none; }\n @media (max-width: 900px) {\n :host { position: fixed; inset: 0; width: 100vw; max-width: none; height: 100dvh; z-index: 901; }\n .resize, .expand { display: none; }\n }\n @media (pointer: coarse) { button { width: 40px; height: 40px; } }\n `]\n @property({ attribute: false }) view?: Entity360View\n @property({ type: Boolean, reflect: true }) expanded = false\n @state() private width = 480\n private media = matchMedia('(max-width: 900px)')\n @state() private compact = this.media.matches\n private onMedia = () => { this.compact = this.media.matches }\n private dragStart?: { x: number; width: number }\n private onEscape = (event: KeyboardEvent) => {\n // A modal opened above the nonmodal dock owns Escape until it closes.\n if (event.defaultPrevented || history.state?.overlay) return\n if (event.key === 'Escape') this.view?.onClose()\n if (event.key === 'Tab' && (this.expanded || this.compact)) {\n const walk = (root: ParentNode): HTMLElement[] => Array.from(root.querySelectorAll<HTMLElement>('*'))\n .flatMap(el => [el, ...(el.shadowRoot ? walk(el.shadowRoot) : [])])\n const controls = walk(this.renderRoot).filter(el => el.matches('button,a[href],input,select,textarea,summary,[tabindex]') &&\n el.getAttribute('tabindex') !== '-1' && !el.hasAttribute('disabled') && el.getClientRects().length && getComputedStyle(el).visibility !== 'hidden')\n const first = controls[0], last = controls[controls.length - 1]\n const target = event.composedPath()[0]\n if (!controls.includes(target as HTMLElement) || (event.shiftKey ? target === first : target === last)) {\n event.preventDefault()\n ;(event.shiftKey ? last : first)?.focus()\n }\n }\n }\n connectedCallback() {\n super.connectedCallback()\n document.addEventListener('keydown', this.onEscape)\n this.media.addEventListener('change', this.onMedia)\n }\n disconnectedCallback() {\n document.removeEventListener('keydown', this.onEscape)\n this.media.removeEventListener('change', this.onMedia)\n super.disconnectedCallback()\n }\n firstUpdated() { this.focusHeading() }\n updated(changes: Map<PropertyKey, unknown>) {\n const previous = changes.get('view') as Entity360View | undefined\n if (changes.has('view') && previous?.key !== this.view?.key) {\n this.renderRoot.querySelector('.body')?.scrollTo(0, 0)\n }\n }\n focusHeading() { this.renderRoot.querySelector<HTMLElement>('h2')?.focus({ preventScroll: true }) }\n private resize(width: number) {\n this.width = Math.max(320, Math.min(width, innerWidth * .65, 960))\n this.style.setProperty('--entity360-width', `${this.width}px`)\n }\n render() {\n const view = this.view\n if (!view) return html``\n const fullscreen = this.expanded || this.compact\n return html`<aside role=${fullscreen ? 'dialog' : 'complementary'} aria-modal=${ifDefined(fullscreen ? 'true' : undefined)} aria-labelledby=\"entity360-title\">\n <div class=\"resize\" role=\"separator\" tabindex=\"0\" aria-orientation=\"vertical\"\n aria-label=${view.labels.resize} aria-valuemin=\"320\" aria-valuemax=${Math.min(innerWidth * .65, 960)} aria-valuenow=${this.width}\n @keydown=${(event: KeyboardEvent) => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return\n event.preventDefault()\n this.resize(event.key === 'Home' ? 320 : event.key === 'End' ? 960 : this.width + (event.key === 'ArrowLeft' ? 32 : -32))\n }}\n @pointerdown=${(event: PointerEvent) => {\n if (event.button !== 0) return\n this.dragStart = { x: event.clientX, width: this.getBoundingClientRect().width }\n ;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)\n }}\n @pointermove=${(event: PointerEvent) => { if (this.dragStart) this.resize(this.dragStart.width + this.dragStart.x - event.clientX) }}\n @pointerup=${() => { this.dragStart = undefined }} @pointercancel=${() => { this.dragStart = undefined }}\n ></div>\n <header>\n ${view.onBack ? html`<button data-action=\"back\" aria-label=${view.labels.back} title=${view.labels.back} @click=${view.onBack}>‹</button>` : ''}\n <div class=\"heading\" aria-live=\"polite\"><h2 id=\"entity360-title\" tabindex=\"-1\">${view.title}</h2><p>${view.context}</p></div>\n <button class=\"expand\" data-action=\"expand\" aria-label=${this.expanded ? view.labels.collapse : view.labels.expand}\n title=${this.expanded ? view.labels.collapse : view.labels.expand} aria-pressed=${this.expanded}\n @click=${() => { this.expanded = !this.expanded }}>${this.expanded ? '↙' : '↗'}</button>\n <button data-action=\"close\" aria-label=${view.labels.close} title=${view.labels.close} @click=${view.onClose}>✕</button>\n </header>\n <div class=\"body\"><ox-entity360-content .view=${view}></ox-entity360-content></div>\n </aside>`\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ox-entity360-dock.js","sourceRoot":"","sources":["../../../src/components/ox-entity360-dock.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport { LitElement, css, html, type CSSResult, type TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { keyed } from 'lit/directives/keyed.js'\nimport { i18next } from '@operato/i18n'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { ScrollbarStyles } from '@operato/styles'\n\n/** Products supply authorized contents and words; the shared dock owns presentation only. */\nexport interface Entity360View {\n /** Canonical subject + read scope, not a display name. Different revisions must have different keys. */\n key: string\n title: string\n context: string\n content: TemplateResult\n styles?: CSSResult[]\n labels: { close: string; expand: string; collapse: string; resize: string; back: string; refresh?: string }\n onClose(): void\n onBack?: () => void\n}\n\n/** Product CSS stays inside this boundary, never changes the dock's layout or controls. */\n@customElement('ox-entity360-content')\nexport class OxEntity360Content extends LitElement {\n @property({ attribute: false }) view?: Entity360View\n @property({ type: Number }) revision = 0\n render() {\n return html`<style>${(this.view?.styles ?? []).map(style => style.cssText).join('\\n')}</style>${keyed(`${this.view?.key}:${this.revision}`, this.view?.content)}`\n }\n}\n\n@customElement('ox-entity360-dock')\nexport class OxEntity360Dock extends LitElement {\n @state() private revision = 0\n static styles = [ScrollbarStyles, css`\n :host { display: block; width: var(--entity360-width, 480px); max-width: 65vw; height: 100%; min-height: 0;\n color: var(--md-sys-color-on-surface, #222); background: var(--md-sys-color-surface, white);\n border-left: 1px solid var(--ui-line, #ccc); box-sizing: border-box; position: relative; }\n :host([expanded]) { position: fixed; inset: 0; width: 100vw; max-width: none; height: 100dvh; z-index: 901; }\n aside { height: 100%; display: flex; flex-direction: column; min-height: 0; }\n header { display: flex; align-items: flex-start; gap: 6px; padding: 12px 14px;\n border-bottom: 1px solid var(--ui-line, #ccc); flex: none; }\n .heading { flex: 1; min-width: 0; }\n h2 { font: 600 15px/1.4 var(--ui-font-family, sans-serif); margin: 0; overflow-wrap: anywhere; }\n h2:focus { outline: none; }\n p { font: 12px/1.4 var(--ui-font-family, sans-serif); margin: 4px 0 0; overflow-wrap: anywhere; color: var(--md-sys-color-on-surface-variant, #555); }\n button { font: 14px/1 sans-serif; width: 28px; height: 28px; padding: 0; display: grid; place-items: center;\n flex: none; cursor: pointer; border: none;\n border-radius: 6px; background: transparent; color: inherit; }\n p:empty { display: none; }\n button md-icon { --md-icon-size: 20px; }\n button:hover { background: var(--md-sys-color-surface-container-high, #eee); }\n button:focus-visible, [role=separator]:focus-visible { outline: 2px solid var(--md-sys-color-primary, #2865ad); outline-offset: -2px; }\n .body { overflow: auto; scrollbar-gutter: stable; min-height: 0; flex: 1; overscroll-behavior: contain; }\n .resize { position: absolute; left: -3px; top: 0; bottom: 0; width: 7px; cursor: col-resize; touch-action: none; z-index: 1; }\n :host([expanded]) .resize { display: none; }\n @media (max-width: 900px) {\n :host { position: fixed; inset: 0; width: 100vw; max-width: none; height: 100dvh; z-index: 901; }\n .resize, .expand { display: none; }\n }\n @media (pointer: coarse) { button { width: 40px; height: 40px; } }\n `]\n @property({ attribute: false }) view?: Entity360View\n @property({ type: Boolean, reflect: true }) expanded = false\n @state() private width = 480\n private media = matchMedia('(max-width: 900px)')\n @state() private compact = this.media.matches\n private onMedia = () => { this.compact = this.media.matches }\n private dragStart?: { x: number; width: number }\n private onEscape = (event: KeyboardEvent) => {\n // A modal opened above the nonmodal dock owns Escape until it closes.\n if (event.defaultPrevented || history.state?.overlay) return\n if (event.key === 'Escape') this.view?.onClose()\n if (event.key === 'Tab' && (this.expanded || this.compact)) {\n const walk = (root: ParentNode): HTMLElement[] => Array.from(root.querySelectorAll<HTMLElement>('*'))\n .flatMap(el => [el, ...(el.shadowRoot ? walk(el.shadowRoot) : [])])\n const controls = walk(this.renderRoot).filter(el => el.matches('button,a[href],input,select,textarea,summary,[tabindex]') &&\n el.getAttribute('tabindex') !== '-1' && !el.hasAttribute('disabled') && el.getClientRects().length && getComputedStyle(el).visibility !== 'hidden')\n const first = controls[0], last = controls[controls.length - 1]\n const target = event.composedPath()[0]\n if (!controls.includes(target as HTMLElement) || (event.shiftKey ? target === first : target === last)) {\n event.preventDefault()\n ;(event.shiftKey ? last : first)?.focus()\n }\n }\n }\n connectedCallback() {\n super.connectedCallback()\n document.addEventListener('keydown', this.onEscape)\n this.media.addEventListener('change', this.onMedia)\n }\n disconnectedCallback() {\n document.removeEventListener('keydown', this.onEscape)\n this.media.removeEventListener('change', this.onMedia)\n super.disconnectedCallback()\n }\n firstUpdated() { this.focusHeading() }\n updated(changes: Map<PropertyKey, unknown>) {\n const previous = changes.get('view') as Entity360View | undefined\n if (changes.has('view') && previous?.key !== this.view?.key) {\n this.renderRoot.querySelector('.body')?.scrollTo(0, 0)\n }\n }\n focusHeading() { this.renderRoot.querySelector<HTMLElement>('h2')?.focus({ preventScroll: true }) }\n private resize(width: number) {\n this.width = Math.max(320, Math.min(width, innerWidth * .65, 960))\n this.style.setProperty('--entity360-width', `${this.width}px`)\n }\n render() {\n const view = this.view\n if (!view) return html``\n const fullscreen = this.expanded || this.compact\n return html`<aside role=${fullscreen ? 'dialog' : 'complementary'} aria-modal=${ifDefined(fullscreen ? 'true' : undefined)} aria-labelledby=\"entity360-title\">\n <div class=\"resize\" role=\"separator\" tabindex=\"0\" aria-orientation=\"vertical\"\n aria-label=${view.labels.resize} aria-valuemin=\"320\" aria-valuemax=${Math.min(innerWidth * .65, 960)} aria-valuenow=${this.width}\n @keydown=${(event: KeyboardEvent) => {\n if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return\n event.preventDefault()\n this.resize(event.key === 'Home' ? 320 : event.key === 'End' ? 960 : this.width + (event.key === 'ArrowLeft' ? 32 : -32))\n }}\n @pointerdown=${(event: PointerEvent) => {\n if (event.button !== 0) return\n this.dragStart = { x: event.clientX, width: this.getBoundingClientRect().width }\n ;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)\n }}\n @pointermove=${(event: PointerEvent) => { if (this.dragStart) this.resize(this.dragStart.width + this.dragStart.x - event.clientX) }}\n @pointerup=${() => { this.dragStart = undefined }} @pointercancel=${() => { this.dragStart = undefined }}\n ></div>\n <header>\n ${view.onBack ? html`<button data-action=\"back\" aria-label=${view.labels.back} title=${view.labels.back} @click=${view.onBack}><md-icon aria-hidden=\"true\">arrow_back</md-icon></button>` : ''}\n <div class=\"heading\" aria-live=\"polite\"><h2 id=\"entity360-title\" tabindex=\"-1\">${view.title}</h2><p>${view.context}</p></div>\n <button data-action=\"refresh\" aria-label=${view.labels.refresh ?? i18next.t('button.refresh')}\n title=${view.labels.refresh ?? i18next.t('button.refresh')} @click=${() => { this.revision++; }}><md-icon aria-hidden=\"true\">refresh</md-icon></button>\n <button class=\"expand\" data-action=\"expand\" aria-label=${this.expanded ? view.labels.collapse : view.labels.expand}\n title=${this.expanded ? view.labels.collapse : view.labels.expand} aria-pressed=${this.expanded}\n @click=${() => { this.expanded = !this.expanded }}><md-icon aria-hidden=\"true\">${this.expanded ? 'fullscreen_exit' : 'fullscreen'}</md-icon></button>\n <button data-action=\"close\" aria-label=${view.labels.close} title=${view.labels.close} @click=${view.onClose}><md-icon aria-hidden=\"true\">close</md-icon></button>\n </header>\n <div class=\"body\"><ox-entity360-content .view=${view} .revision=${this.revision}></ox-entity360-content></div>\n </aside>`\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { css, html, LitElement } from 'lit';
|
|
2
|
+
import { css, html, LitElement, nothing } from 'lit';
|
|
3
3
|
import { customElement, property } from 'lit/decorators.js';
|
|
4
4
|
import { i18next } from '@operato/i18n';
|
|
5
5
|
/**
|
|
@@ -18,7 +18,7 @@ let OxEntity360Section = class OxEntity360Section extends LitElement {
|
|
|
18
18
|
this.message = '';
|
|
19
19
|
}
|
|
20
20
|
render() {
|
|
21
|
-
return html `<h3>${this.heading}</h3>${this.body()}`;
|
|
21
|
+
return html `<header><h3>${this.heading}</h3>${this.state === 'ready' ? html `<slot name="actions"></slot>` : nothing}</header>${this.body()}`;
|
|
22
22
|
}
|
|
23
23
|
body() {
|
|
24
24
|
switch (this.state) {
|
|
@@ -46,8 +46,9 @@ OxEntity360Section.styles = css `
|
|
|
46
46
|
padding: 12px 16px;
|
|
47
47
|
border-top: 1px solid var(--md-sys-color-outline-variant);
|
|
48
48
|
}
|
|
49
|
+
header { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
|
|
49
50
|
h3 {
|
|
50
|
-
margin: 0
|
|
51
|
+
margin: 0;
|
|
51
52
|
font: var(--md-sys-typescale-title-small-weight, 500) var(--md-sys-typescale-title-small-size, 14px) / 1.4 sans-serif;
|
|
52
53
|
color: var(--md-sys-color-on-surface);
|
|
53
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ox-entity360-section.js","sourceRoot":"","sources":["../../../src/components/ox-entity360-section.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"ox-entity360-section.js","sourceRoot":"","sources":["../../../src/components/ox-entity360-section.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAIvC;;;;;;GAMG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,UAAU;IAA3C;;QAqBO,YAAO,GAAG,EAAE,CAAA;QACZ,UAAK,GAAuB,SAAS,CAAA;QACjD,sDAAsD;QAC1C,YAAO,GAAG,EAAE,CAAA;IAyB1B,CAAC;IAvBC,MAAM;QACJ,OAAO,IAAI,CAAA,eAAe,IAAI,CAAC,OAAO,QAAQ,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,8BAA8B,CAAC,CAAC,CAAC,OAAO,YAAY,IAAI,CAAC,IAAI,EAAE,EAAE,CAAA;IAC9I,CAAC;IAEO,IAAI;QACV,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,OAAO;gBACV,OAAO,IAAI,CAAA,eAAe,CAAA;YAC5B,KAAK,MAAM;gBACT,OAAO,IAAI,CAAA,wBAAwB,OAAO,CAAC,CAAC,CAAC,qBAAqB,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,MAAM,CAAA;YACrG,KAAK,WAAW;gBACd,OAAO,IAAI,CAAA;YACP,OAAO,CAAC,CAAC,CAAC,0BAA0B,EAAE,EAAE,YAAY,EAAE,sBAAsB,EAAE,CAAC;aAC9E,CAAA;YACP,KAAK,QAAQ;gBACX,8GAA8G;gBAC9G,OAAO,IAAI,CAAA;YACP,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,uBAAuB,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;aACxF,CAAA;YACP;gBACE,OAAO,IAAI,CAAA,2BAA2B,OAAO,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,MAAM,CAAA;QACvG,CAAC;IACH,CAAC;;AA/CM,yBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;GAkBlB,AAlBY,CAkBZ;AAEW;IAAX,QAAQ,EAAE;mDAAa;AACZ;IAAX,QAAQ,EAAE;iDAAsC;AAErC;IAAX,QAAQ,EAAE;mDAAa;AAxBb,kBAAkB;IAD9B,aAAa,CAAC,sBAAsB,CAAC;GACzB,kBAAkB,CAiD9B","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { i18next } from '@operato/i18n'\n\nimport type { Entity360DoorState } from '../actions/entity360-door.js'\n\n/**\n * One section of a 360: a heading and what its read door answered.\n *\n * Every module's section says loading, none, may-not-see and failed the same way, so the dock reads as\n * one thing even though three modules filled it. What the section has to show goes in the default slot\n * and is drawn only when `state` is `ready`.\n */\n@customElement('ox-entity360-section')\nexport class OxEntity360Section extends LitElement {\n static styles = css`\n :host {\n display: block;\n padding: 12px 16px;\n border-top: 1px solid var(--md-sys-color-outline-variant);\n }\n header { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }\n h3 {\n margin: 0;\n font: var(--md-sys-typescale-title-small-weight, 500) var(--md-sys-typescale-title-small-size, 14px) / 1.4 sans-serif;\n color: var(--md-sys-color-on-surface);\n }\n p {\n margin: 0;\n font: 13px/1.5 sans-serif;\n color: var(--md-sys-color-on-surface-variant);\n overflow-wrap: anywhere;\n }\n `\n\n @property() heading = ''\n @property() state: Entity360DoorState = 'loading'\n /** The server's sentence when `state` is `failed`. */\n @property() message = ''\n\n render() {\n return html`<header><h3>${this.heading}</h3>${this.state === 'ready' ? html`<slot name=\"actions\"></slot>` : nothing}</header>${this.body()}`\n }\n\n private body() {\n switch (this.state) {\n case 'ready':\n return html`<slot></slot>`\n case 'none':\n return html`<p data-state=\"none\">${i18next.t('text.entity360-none', { defaultValue: 'none' })}</p>`\n case 'forbidden':\n return html`<p data-state=\"forbidden\">\n ${i18next.t('text.entity360-forbidden', { defaultValue: 'you may not see this' })}\n </p>`\n case 'failed':\n /* The server's sentence when there is one; otherwise only that it could not be read - no cause is made up. */\n return html`<p data-state=\"failed\">\n ${this.message || i18next.t('text.entity360-failed', { defaultValue: 'could not be read' })}\n </p>`\n default:\n return html`<p data-state=\"loading\">${i18next.t('text.loading', { defaultValue: 'loading…' })}</p>`\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ox-entity360-section': OxEntity360Section\n }\n}\n"]}
|
|
@@ -33,13 +33,28 @@ describe('shared nonmodal entity 360 dock', () => {
|
|
|
33
33
|
expect(original.view.context).to.equal('Approval after · Revision 2');
|
|
34
34
|
expect(original.shadowRoot.textContent).to.contain('Approval after · Revision 2');
|
|
35
35
|
});
|
|
36
|
+
it('refreshes all content while keeping the dock and its read context', async () => {
|
|
37
|
+
showEntity360(owner, view());
|
|
38
|
+
await settle();
|
|
39
|
+
const original = dock();
|
|
40
|
+
original.expanded = true;
|
|
41
|
+
const content = original.shadowRoot.querySelector('ox-entity360-content');
|
|
42
|
+
const input = content.shadowRoot.querySelector('input');
|
|
43
|
+
original.shadowRoot.querySelector('[data-action="refresh"]').click();
|
|
44
|
+
await settle();
|
|
45
|
+
expect(dock()).to.equal(original);
|
|
46
|
+
expect(original.expanded).to.equal(true);
|
|
47
|
+
expect(original.view.key).to.equal('Revision 1');
|
|
48
|
+
expect(content.shadowRoot.querySelector('input')).not.to.equal(input);
|
|
49
|
+
expect(content.shadowRoot.querySelector('input').value).to.equal('Revision 1');
|
|
50
|
+
});
|
|
36
51
|
it('uses compact header controls and the shared scrollbar theme without local overrides', async () => {
|
|
37
52
|
bar.style.setProperty('--scrollbar-thumb-color', 'rgb(57, 78, 100)');
|
|
38
53
|
showEntity360(owner, { ...view(), content: html `<div style="height:3000px">Long detail</div>` });
|
|
39
54
|
await settle();
|
|
40
55
|
const el = dock();
|
|
41
56
|
const close = el.shadowRoot.querySelector('[data-action="close"]');
|
|
42
|
-
expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 :
|
|
57
|
+
expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 : 28);
|
|
43
58
|
const body = el.shadowRoot.querySelector('.body');
|
|
44
59
|
expect(getComputedStyle(body).scrollbarGutter).to.equal('stable');
|
|
45
60
|
expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('5px');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity360.test.js","sourceRoot":"","sources":["../../test/entity360.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, elementUpdated } from '@open-wc/testing'\nimport { html } from 'lit'\nimport '../src/index.js'\nimport { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360, type OxEntity360Dock, type Entity360View } from '../src/index.js'\n\nconst owner = {}\nconst labels = { close: 'Close', expand: 'Expand', collapse: 'Collapse', resize: 'Resize', back: 'Back' }\nconst settle = () => new Promise(resolve => setTimeout(resolve, 50))\nlet bar: HTMLElement\nconst dock = () => bar.shadowRoot!.querySelector('ox-entity360-dock') as OxEntity360Dock\nfunction view(name = 'Revision 1'): Entity360View {\n return { key: name, title: 'Test specification', context: name, labels, content: html`<input value=${name}>`, onClose: () => hideEntity360(owner) }\n}\n\ndescribe('shared nonmodal entity 360 dock', () => {\n beforeEach(async () => { bar = await fixture(html`<ox-aside-bar></ox-aside-bar>`) })\n afterEach(() => hideEntity360(owner))\n\n it('uses the aside layout without a modal backdrop or duplicate close action', async () => {\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n expect(bar.shadowRoot!.querySelector('ox-floating-overlay')).to.equal(null)\n expect(!!dock().shadowRoot!.querySelector('[aria-modal]')).to.equal(matchMedia('(max-width: 900px)').matches)\n expect(dock().shadowRoot!.querySelectorAll('[data-action=\"close\"]').length).to.equal(1)\n })\n\n it('switches the contents in one dock and retains expanded state', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n showEntity360(owner, view('Approval after · Revision 2'))\n await elementUpdated(original)\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.context).to.equal('Approval after · Revision 2')\n expect(original.shadowRoot!.textContent).to.contain('Approval after · Revision 2')\n })\n\n it('uses compact header controls and the shared scrollbar theme without local overrides', async () => {\n bar.style.setProperty('--scrollbar-thumb-color', 'rgb(57, 78, 100)')\n showEntity360(owner, { ...view(), content: html`<div style=\"height:3000px\">Long detail</div>` })\n await settle()\n const el = dock()\n const close = el.shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement\n expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 : 26)\n const body = el.shadowRoot!.querySelector('.body') as HTMLElement\n expect(getComputedStyle(body).scrollbarGutter).to.equal('stable')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('5px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-track').backgroundColor).to.equal('rgba(0, 0, 0, 0)')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').backgroundColor).to.equal('rgb(57, 78, 100)')\n bar.style.setProperty('--scrollbar-width', '7px')\n bar.style.setProperty('--scrollbar-thumb-border-radius', '2px')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('7px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').borderRadius).to.equal('2px')\n })\n\n it('closes through the common button and restores the invoking control', async () => {\n let restored = false\n showEntity360(owner, view(), () => { restored = true })\n await settle()\n ;(dock().shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(null)\n expect(restored).to.equal(true)\n })\n\n it('Escape does not close the dock underneath a modal', async () => {\n showEntity360(owner, view())\n await settle()\n const state = history.state\n history.replaceState({ ...state, overlay: { name: 'confirmation' } }, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n expect(dock()).to.exist\n history.replaceState(state, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n await settle()\n expect(dock()).to.equal(null)\n })\n\n it('resizes using the keyboard without changing the read context', async () => {\n showEntity360(owner, view())\n await settle()\n const el = dock()\n el.shadowRoot!.querySelector('[role=\"separator\"]')!.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))\n await elementUpdated(el)\n expect(el.style.getPropertyValue('--entity360-width')).to.equal('448px')\n expect(el.view!.context).to.equal('Revision 1')\n })\n\n it('also mounts in fullbleed layouts', async () => {\n bar.setAttribute('fullbleed', '')\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n })\n\n it('records distinct targets and preserves unrelated address state', () => {\n const initial = location.href\n history.replaceState({ userState: 42 }, '', initial)\n const first = new URL(initial)\n first.searchParams.set('f', 'testSpecifications:one')\n first.searchParams.set('revision', 'r1')\n navigateEntity360(first.href)\n expect(canGoBackEntity360()).to.equal(false)\n const second = new URL(first)\n second.searchParams.set('revision', 'r2')\n navigateEntity360(second.href)\n expect(canGoBackEntity360()).to.equal(true)\n expect(history.state.userState).to.equal(42)\n expect(history.state.entity360Previous).to.equal(first.href)\n history.replaceState({}, '', initial)\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"entity360.test.js","sourceRoot":"","sources":["../../test/entity360.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAA4C,MAAM,iBAAiB,CAAA;AAE/I,MAAM,KAAK,GAAG,EAAE,CAAA;AAChB,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzG,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AACpE,IAAI,GAAgB,CAAA;AACpB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,UAAW,CAAC,aAAa,CAAC,mBAAmB,CAAoB,CAAA;AACxF,SAAS,IAAI,CAAC,IAAI,GAAG,YAAY;IAC/B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAA,gBAAgB,IAAI,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAA;AACrJ,CAAC;AAED,QAAQ,CAAC,iCAAiC,EAAE,GAAG,EAAE;IAC/C,UAAU,CAAC,KAAK,IAAI,EAAE,GAAG,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAA,+BAA+B,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;IACpF,SAAS,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAA;IAErC,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;QACvB,MAAM,CAAC,GAAG,CAAC,UAAW,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3E,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAA;QAC7G,MAAM,CAAC,IAAI,EAAE,CAAC,UAAW,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAA;QACvB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAA;QACxB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAA;QACzD,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAA;QAC9B,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;QACtE,MAAM,CAAC,QAAQ,CAAC,UAAW,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAA;IACpF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAA;QACvB,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAA;QACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAW,CAAC,aAAa,CAAC,sBAAsB,CAAgB,CAAA;QACzF,MAAM,KAAK,GAAG,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAE,CACxD;QAAC,QAAQ,CAAC,UAAW,CAAC,aAAa,CAAC,yBAAyB,CAAiB,CAAC,KAAK,EAAE,CAAA;QACvF,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,CAAC,QAAQ,CAAC,IAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QACjD,MAAM,CAAC,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACtE,MAAM,CAAC,OAAO,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACnG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,yBAAyB,EAAE,kBAAkB,CAAC,CAAA;QACpE,aAAa,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAA,8CAA8C,EAAE,CAAC,CAAA;QAChG,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,EAAE,GAAG,IAAI,EAAE,CAAA;QACjB,MAAM,KAAK,GAAG,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,uBAAuB,CAAgB,CAAA;QAClF,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACvG,MAAM,IAAI,GAAG,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,OAAO,CAAgB,CAAA;QACjE,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QACjE,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC3E,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACxG,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACxG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAA;QACjD,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAA;QAC/D,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC3E,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,2BAA2B,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1F,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,GAAG,QAAQ,GAAG,IAAI,CAAA,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,MAAM,EAAE,CACb;QAAC,IAAI,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,uBAAuB,CAAiB,CAAC,KAAK,EAAE,CAAA;QACnF,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC3B,OAAO,CAAC,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACzE,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QACvE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;QACvB,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;QAC/B,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAA;QACvE,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,EAAE,GAAG,IAAI,EAAE,CAAA;QACjB,EAAE,CAAC,UAAW,CAAC,aAAa,CAAC,oBAAoB,CAAE,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC,CAAA;QACtH,MAAM,cAAc,CAAC,EAAE,CAAC,CAAA;QACxB,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QACxE,MAAM,CAAC,EAAE,CAAC,IAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QACjC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,MAAM,EAAE,CAAA;QACd,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAA;QAC7B,OAAO,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;QACpD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;QAC9B,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;QACrD,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACxC,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7B,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC5C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;QACzC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC9B,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC5C,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5D,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACvC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect, fixture, elementUpdated } from '@open-wc/testing'\nimport { html } from 'lit'\nimport '../src/index.js'\nimport { showEntity360, hideEntity360, navigateEntity360, canGoBackEntity360, type OxEntity360Dock, type Entity360View } from '../src/index.js'\n\nconst owner = {}\nconst labels = { close: 'Close', expand: 'Expand', collapse: 'Collapse', resize: 'Resize', back: 'Back' }\nconst settle = () => new Promise(resolve => setTimeout(resolve, 50))\nlet bar: HTMLElement\nconst dock = () => bar.shadowRoot!.querySelector('ox-entity360-dock') as OxEntity360Dock\nfunction view(name = 'Revision 1'): Entity360View {\n return { key: name, title: 'Test specification', context: name, labels, content: html`<input value=${name}>`, onClose: () => hideEntity360(owner) }\n}\n\ndescribe('shared nonmodal entity 360 dock', () => {\n beforeEach(async () => { bar = await fixture(html`<ox-aside-bar></ox-aside-bar>`) })\n afterEach(() => hideEntity360(owner))\n\n it('uses the aside layout without a modal backdrop or duplicate close action', async () => {\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n expect(bar.shadowRoot!.querySelector('ox-floating-overlay')).to.equal(null)\n expect(!!dock().shadowRoot!.querySelector('[aria-modal]')).to.equal(matchMedia('(max-width: 900px)').matches)\n expect(dock().shadowRoot!.querySelectorAll('[data-action=\"close\"]').length).to.equal(1)\n })\n\n it('switches the contents in one dock and retains expanded state', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n showEntity360(owner, view('Approval after · Revision 2'))\n await elementUpdated(original)\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.context).to.equal('Approval after · Revision 2')\n expect(original.shadowRoot!.textContent).to.contain('Approval after · Revision 2')\n })\n\n it('refreshes all content while keeping the dock and its read context', async () => {\n showEntity360(owner, view())\n await settle()\n const original = dock()\n original.expanded = true\n const content = original.shadowRoot!.querySelector('ox-entity360-content') as HTMLElement\n const input = content.shadowRoot!.querySelector('input')!\n ;(original.shadowRoot!.querySelector('[data-action=\"refresh\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(original)\n expect(original.expanded).to.equal(true)\n expect(original.view!.key).to.equal('Revision 1')\n expect(content.shadowRoot!.querySelector('input')).not.to.equal(input)\n expect(content.shadowRoot!.querySelector('input')!.value).to.equal('Revision 1')\n })\n\n it('uses compact header controls and the shared scrollbar theme without local overrides', async () => {\n bar.style.setProperty('--scrollbar-thumb-color', 'rgb(57, 78, 100)')\n showEntity360(owner, { ...view(), content: html`<div style=\"height:3000px\">Long detail</div>` })\n await settle()\n const el = dock()\n const close = el.shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement\n expect(close.getBoundingClientRect().width).to.equal(matchMedia('(pointer: coarse)').matches ? 40 : 28)\n const body = el.shadowRoot!.querySelector('.body') as HTMLElement\n expect(getComputedStyle(body).scrollbarGutter).to.equal('stable')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('5px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-track').backgroundColor).to.equal('rgba(0, 0, 0, 0)')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').backgroundColor).to.equal('rgb(57, 78, 100)')\n bar.style.setProperty('--scrollbar-width', '7px')\n bar.style.setProperty('--scrollbar-thumb-border-radius', '2px')\n expect(getComputedStyle(body, '::-webkit-scrollbar').width).to.equal('7px')\n expect(getComputedStyle(body, '::-webkit-scrollbar-thumb').borderRadius).to.equal('2px')\n })\n\n it('closes through the common button and restores the invoking control', async () => {\n let restored = false\n showEntity360(owner, view(), () => { restored = true })\n await settle()\n ;(dock().shadowRoot!.querySelector('[data-action=\"close\"]') as HTMLElement).click()\n await settle()\n expect(dock()).to.equal(null)\n expect(restored).to.equal(true)\n })\n\n it('Escape does not close the dock underneath a modal', async () => {\n showEntity360(owner, view())\n await settle()\n const state = history.state\n history.replaceState({ ...state, overlay: { name: 'confirmation' } }, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n expect(dock()).to.exist\n history.replaceState(state, '')\n document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))\n await settle()\n expect(dock()).to.equal(null)\n })\n\n it('resizes using the keyboard without changing the read context', async () => {\n showEntity360(owner, view())\n await settle()\n const el = dock()\n el.shadowRoot!.querySelector('[role=\"separator\"]')!.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))\n await elementUpdated(el)\n expect(el.style.getPropertyValue('--entity360-width')).to.equal('448px')\n expect(el.view!.context).to.equal('Revision 1')\n })\n\n it('also mounts in fullbleed layouts', async () => {\n bar.setAttribute('fullbleed', '')\n showEntity360(owner, view())\n await settle()\n expect(dock()).to.exist\n })\n\n it('records distinct targets and preserves unrelated address state', () => {\n const initial = location.href\n history.replaceState({ userState: 42 }, '', initial)\n const first = new URL(initial)\n first.searchParams.set('f', 'testSpecifications:one')\n first.searchParams.set('revision', 'r1')\n navigateEntity360(first.href)\n expect(canGoBackEntity360()).to.equal(false)\n const second = new URL(first)\n second.searchParams.set('revision', 'r2')\n navigateEntity360(second.href)\n expect(canGoBackEntity360()).to.equal(true)\n expect(history.state.userState).to.equal(42)\n expect(history.state.entity360Previous).to.equal(first.href)\n history.replaceState({}, '', initial)\n })\n})\n"]}
|