@excom/content-drawer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rush/temp/chunked-rush-logs/content-drawer.apply-exports.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-drawer.build_docs.chunks.jsonl +1 -0
- package/.rush/temp/chunked-rush-logs/content-drawer.build_package-metas.chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/all.log +1 -0
- package/.rush/temp/operation/apply-exports/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/apply-exports/state.json +3 -0
- package/.rush/temp/operation/build_docs/all.log +1 -0
- package/.rush/temp/operation/build_docs/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_docs/state.json +3 -0
- package/.rush/temp/operation/build_package-metas/all.log +1 -0
- package/.rush/temp/operation/build_package-metas/log-chunks.jsonl +1 -0
- package/.rush/temp/operation/build_package-metas/state.json +3 -0
- package/.rush/temp/shrinkwrap-deps.json +3 -0
- package/config/rig.json +5 -0
- package/content-drawer.ts +205 -0
- package/index.css +5 -0
- package/index.ts +17 -0
- package/package.json +44 -0
- package/rush-logs/content-drawer.apply-exports.cache.log +1 -0
- package/rush-logs/content-drawer.apply-exports.log +1 -0
- package/rush-logs/content-drawer.build_docs.cache.log +1 -0
- package/rush-logs/content-drawer.build_docs.log +1 -0
- package/rush-logs/content-drawer.build_package-metas.cache.log +1 -0
- package/rush-logs/content-drawer.build_package-metas.log +1 -0
- package/src/content-drawer.css +344 -0
- package/support/custom-elements.json +360 -0
- package/support/demos/disappear.html +8 -0
- package/support/demos/dismiss.html +16 -0
- package/support/demos/from-side.html +9 -0
- package/support/demos/simple.html +12 -0
- package/support/demos/singleton.html +16 -0
- package/support/demos/stages.html +18 -0
- package/support/dist-docs/content-drawer.md +252 -0
- package/support/docs/README.md +69 -0
- package/support/package-meta.json +299 -0
- package/support/tests/content-drawer.test.ts +388 -0
- package/support/tests/disappear.view.test.ts +32 -0
- package/support/tests/dismiss.view.test.ts +61 -0
- package/support/tests/from-side.view.test.ts +32 -0
- package/support/tests/simple.view.test.ts +40 -0
- package/support/tests/singleton.view.test.ts +35 -0
- package/support/tests/stages.view.test.ts +39 -0
- package/tsconfig.json +5 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
describe,
|
|
4
|
+
expect,
|
|
5
|
+
fixture,
|
|
6
|
+
it,
|
|
7
|
+
vi,
|
|
8
|
+
wait,
|
|
9
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
10
|
+
import "../../index";
|
|
11
|
+
import { propsFromSource } from "../../content-drawer";
|
|
12
|
+
import { invokeCommand } from "@excom/neutron";
|
|
13
|
+
|
|
14
|
+
/** A `<button>` invoker carrying `data-*` from `data` (camelCase keys). */
|
|
15
|
+
const sourceWith = (data: Record<string, unknown> = {}) => {
|
|
16
|
+
const button = document.createElement("button");
|
|
17
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
18
|
+
button.dataset[key] = String(value);
|
|
19
|
+
});
|
|
20
|
+
return button;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Invoke a command from a `<button>` and let the handler's microtask run. */
|
|
24
|
+
const command = async (
|
|
25
|
+
el: Element,
|
|
26
|
+
name: string,
|
|
27
|
+
data?: Record<string, unknown>,
|
|
28
|
+
) => {
|
|
29
|
+
invokeCommand(el, name, sourceWith(data));
|
|
30
|
+
await Promise.resolve();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
describe("content-drawer", () => {
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
document.body.innerHTML = "";
|
|
36
|
+
vi.restoreAllMocks();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("opens, closes and toggles from commands", async () => {
|
|
40
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
41
|
+
`<content-drawer></content-drawer>`,
|
|
42
|
+
);
|
|
43
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
44
|
+
`<content-drawer></content-drawer>`,
|
|
45
|
+
);
|
|
46
|
+
await command(contentDrawer, "--open");
|
|
47
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
48
|
+
`<content-drawer is-open></content-drawer>`,
|
|
49
|
+
);
|
|
50
|
+
await command(contentDrawer, "--close");
|
|
51
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
52
|
+
`<content-drawer></content-drawer>`,
|
|
53
|
+
);
|
|
54
|
+
await command(contentDrawer, "--toggle");
|
|
55
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
56
|
+
`<content-drawer is-open></content-drawer>`,
|
|
57
|
+
);
|
|
58
|
+
await command(contentDrawer, "--toggle");
|
|
59
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
60
|
+
`<content-drawer></content-drawer>`,
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("adds no document listeners on open (dismissal is dismiss-watcher's job)", async () => {
|
|
65
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
66
|
+
`<content-drawer></content-drawer>`,
|
|
67
|
+
);
|
|
68
|
+
const documentAddSpy = vi.spyOn(document, "addEventListener");
|
|
69
|
+
const bodyAddSpy = vi.spyOn(document.body, "addEventListener");
|
|
70
|
+
await command(contentDrawer, "--open");
|
|
71
|
+
expect(documentAddSpy).not.toHaveBeenCalled();
|
|
72
|
+
expect(bodyAddSpy).not.toHaveBeenCalled();
|
|
73
|
+
document.body.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
|
|
74
|
+
expect(contentDrawer.isOpen).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("content-drawer (propsFromSource)", () => {
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
document.body.innerHTML = "";
|
|
82
|
+
vi.restoreAllMocks();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("keeps only declared, non-private props", async () => {
|
|
86
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
87
|
+
`<content-drawer></content-drawer>`,
|
|
88
|
+
);
|
|
89
|
+
expect(
|
|
90
|
+
propsFromSource(
|
|
91
|
+
contentDrawer,
|
|
92
|
+
sourceWith({
|
|
93
|
+
openStage: 1,
|
|
94
|
+
fromSide: "top",
|
|
95
|
+
unknownKey: "x",
|
|
96
|
+
_timeoutId: 123,
|
|
97
|
+
isOpen: false,
|
|
98
|
+
}),
|
|
99
|
+
),
|
|
100
|
+
).toEqual({ openStage: "1", fromSide: "top", isOpen: "false" });
|
|
101
|
+
expect(propsFromSource(contentDrawer, undefined)).toEqual({});
|
|
102
|
+
expect(propsFromSource(contentDrawer, null)).toEqual({});
|
|
103
|
+
expect(propsFromSource(contentDrawer, sourceWith())).toEqual({});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("applies openStage from the invoker's data-* and ignores unknown / private keys", async () => {
|
|
107
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
108
|
+
`<content-drawer></content-drawer>`,
|
|
109
|
+
);
|
|
110
|
+
await command(contentDrawer, "--open", { openStage: 1, unknownKey: "x", _timeoutId: 123 });
|
|
111
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
112
|
+
`<content-drawer is-open open-stage="1"></content-drawer>`,
|
|
113
|
+
);
|
|
114
|
+
expect(contentDrawer._timeoutId).toBeFalsy();
|
|
115
|
+
expect((contentDrawer as unknown as { unknownKey?: unknown }).unknownKey).toBeUndefined();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("isOpen on the invoker cannot override the command", async () => {
|
|
119
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
120
|
+
`<content-drawer></content-drawer>`,
|
|
121
|
+
);
|
|
122
|
+
await command(contentDrawer, "--open", { isOpen: false });
|
|
123
|
+
expect(contentDrawer.isOpen).toBe(true);
|
|
124
|
+
await command(contentDrawer, "--toggle", { isOpen: true });
|
|
125
|
+
expect(contentDrawer.isOpen).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("content-drawer (open stages)", () => {
|
|
130
|
+
afterEach(() => {
|
|
131
|
+
document.body.innerHTML = "";
|
|
132
|
+
vi.restoreAllMocks();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("sets open-stage from the invoker and keeps it on close", async () => {
|
|
136
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
137
|
+
`<content-drawer></content-drawer>`,
|
|
138
|
+
);
|
|
139
|
+
await command(contentDrawer, "--open", { openStage: "1" });
|
|
140
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
141
|
+
`<content-drawer is-open open-stage="1"></content-drawer>`,
|
|
142
|
+
);
|
|
143
|
+
expect(contentDrawer.openStage).toBe(1);
|
|
144
|
+
await command(contentDrawer, "--open", { openStage: 2 });
|
|
145
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
146
|
+
`<content-drawer is-open open-stage="2"></content-drawer>`,
|
|
147
|
+
);
|
|
148
|
+
await command(contentDrawer, "--open", { openStage: 0 });
|
|
149
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
150
|
+
`<content-drawer is-open open-stage="0"></content-drawer>`,
|
|
151
|
+
);
|
|
152
|
+
await command(contentDrawer, "--close");
|
|
153
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
154
|
+
`<content-drawer open-stage="0"></content-drawer>`,
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("toggle accepts declared props from the invoker and drops the rest", async () => {
|
|
159
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
160
|
+
`<content-drawer></content-drawer>`,
|
|
161
|
+
);
|
|
162
|
+
await command(contentDrawer, "--toggle", { openStage: 2, isModal: true, fromSide: "top" });
|
|
163
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
164
|
+
`<content-drawer is-open open-stage="2" from-side="top"></content-drawer>`,
|
|
165
|
+
);
|
|
166
|
+
await command(contentDrawer, "--toggle");
|
|
167
|
+
// declared props set through the invoker persist like any attribute
|
|
168
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
169
|
+
`<content-drawer open-stage="2" from-side="top"></content-drawer>`,
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("open-stage only accepts 0, 1, or 2", async () => {
|
|
174
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
175
|
+
`<content-drawer></content-drawer>`,
|
|
176
|
+
);
|
|
177
|
+
contentDrawer.openStage = -1;
|
|
178
|
+
// attribute reflects as written, but the prop reads as invalid (null)
|
|
179
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
180
|
+
`<content-drawer open-stage="-1"></content-drawer>`,
|
|
181
|
+
);
|
|
182
|
+
expect(contentDrawer.openStage).toBe(null);
|
|
183
|
+
contentDrawer.openStage = 3;
|
|
184
|
+
expect(contentDrawer.openStage).toBe(null);
|
|
185
|
+
contentDrawer.openStage = 2;
|
|
186
|
+
expect(contentDrawer.openStage).toBe(2);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe("content-drawer (opened / closed events)", () => {
|
|
191
|
+
afterEach(() => {
|
|
192
|
+
document.body.innerHTML = "";
|
|
193
|
+
vi.restoreAllMocks();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("emits content-drawer-opened after open and -closed after close", async () => {
|
|
197
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
198
|
+
`<content-drawer></content-drawer>`,
|
|
199
|
+
);
|
|
200
|
+
const opened = vi.fn();
|
|
201
|
+
const closed = vi.fn();
|
|
202
|
+
contentDrawer.addEventListener("content-drawer-opened", opened);
|
|
203
|
+
contentDrawer.addEventListener("content-drawer-closed", closed);
|
|
204
|
+
|
|
205
|
+
await command(contentDrawer, "--open");
|
|
206
|
+
expect(opened).toHaveBeenCalledTimes(1);
|
|
207
|
+
expect(closed).not.toHaveBeenCalled();
|
|
208
|
+
expect(contentDrawer.hasAttribute("is-open")).toBe(true);
|
|
209
|
+
expect(opened.mock.calls[0][0].detail).toBe(contentDrawer);
|
|
210
|
+
|
|
211
|
+
await command(contentDrawer, "--close");
|
|
212
|
+
expect(closed).toHaveBeenCalledTimes(1);
|
|
213
|
+
expect(contentDrawer.hasAttribute("is-open")).toBe(false);
|
|
214
|
+
expect(closed.mock.calls[0][0].detail).toBe(contentDrawer);
|
|
215
|
+
expect(opened).toHaveBeenCalledTimes(1);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("emits opened without a singleton-name", async () => {
|
|
219
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
220
|
+
`<content-drawer></content-drawer>`,
|
|
221
|
+
);
|
|
222
|
+
const opened = vi.fn();
|
|
223
|
+
contentDrawer.addEventListener("content-drawer-opened", opened);
|
|
224
|
+
contentDrawer.isOpen = true;
|
|
225
|
+
expect(opened).toHaveBeenCalledTimes(1);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe("content-drawer (disappear-after)", () => {
|
|
230
|
+
afterEach(() => {
|
|
231
|
+
document.body.innerHTML = "";
|
|
232
|
+
vi.restoreAllMocks();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("disappears after a set time", async () => {
|
|
236
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
237
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
238
|
+
);
|
|
239
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
240
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
241
|
+
);
|
|
242
|
+
await command(contentDrawer, "--open");
|
|
243
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
244
|
+
`<content-drawer disappear-after="0.1" is-open></content-drawer>`,
|
|
245
|
+
);
|
|
246
|
+
// poll rather than sleeping the timer's own 100ms: an exact-length sleep
|
|
247
|
+
// loses the race whenever the machine is slow enough to start it late
|
|
248
|
+
await vi.waitFor(() => {
|
|
249
|
+
expect(contentDrawer).dom.to.equalTag(
|
|
250
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
expect(contentDrawer._timeoutId).toBeNull();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it("clears the timer when closed early", async () => {
|
|
257
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
258
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
259
|
+
);
|
|
260
|
+
const clearSpy = vi.spyOn(globalThis, "clearTimeout");
|
|
261
|
+
await command(contentDrawer, "--open");
|
|
262
|
+
const id = contentDrawer._timeoutId;
|
|
263
|
+
expect(id).not.toBeNull();
|
|
264
|
+
await command(contentDrawer, "--close");
|
|
265
|
+
expect(clearSpy).toHaveBeenCalledWith(id);
|
|
266
|
+
expect(contentDrawer._timeoutId).toBeNull();
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("clears the timer on disconnect", async () => {
|
|
270
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
271
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
272
|
+
);
|
|
273
|
+
const clearSpy = vi.spyOn(globalThis, "clearTimeout");
|
|
274
|
+
await command(contentDrawer, "--open");
|
|
275
|
+
const id = contentDrawer._timeoutId;
|
|
276
|
+
expect(id).not.toBeNull();
|
|
277
|
+
contentDrawer.remove();
|
|
278
|
+
await wait(0);
|
|
279
|
+
expect(clearSpy).toHaveBeenCalledWith(id);
|
|
280
|
+
expect(contentDrawer._timeoutId).toBeNull();
|
|
281
|
+
// the timer no longer closes it
|
|
282
|
+
await wait(110);
|
|
283
|
+
expect(contentDrawer.isOpen).toBe(true);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("keeps the timer across a DOM move", async () => {
|
|
287
|
+
const contentDrawer = fixture<HTMLContentDrawerElement>(
|
|
288
|
+
`<content-drawer disappear-after="0.1"></content-drawer>`,
|
|
289
|
+
);
|
|
290
|
+
await command(contentDrawer, "--open");
|
|
291
|
+
const id = contentDrawer._timeoutId;
|
|
292
|
+
expect(id).not.toBeNull();
|
|
293
|
+
const target = document.createElement("div");
|
|
294
|
+
document.body.append(target);
|
|
295
|
+
target.append(contentDrawer); // synchronous disconnect + connect = move
|
|
296
|
+
await wait(0);
|
|
297
|
+
expect(contentDrawer._timeoutId).toBe(id);
|
|
298
|
+
expect(contentDrawer.isOpen).toBe(true);
|
|
299
|
+
await wait(110);
|
|
300
|
+
expect(contentDrawer.isOpen).toBe(false);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
describe("content-drawer (singleton-name)", () => {
|
|
305
|
+
afterEach(() => {
|
|
306
|
+
document.body.innerHTML = "";
|
|
307
|
+
vi.restoreAllMocks();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("closes when another drawer with the same name opens", async () => {
|
|
311
|
+
const drawer1 = fixture<HTMLContentDrawerElement>(
|
|
312
|
+
`<content-drawer singleton-name="foo"></content-drawer>
|
|
313
|
+
<content-drawer singleton-name="foo"></content-drawer>
|
|
314
|
+
<content-drawer singleton-name="bar"></content-drawer>`,
|
|
315
|
+
);
|
|
316
|
+
const drawer2 = drawer1.nextElementSibling as HTMLContentDrawerElement;
|
|
317
|
+
const other = drawer2.nextElementSibling as HTMLContentDrawerElement;
|
|
318
|
+
other.isOpen = true;
|
|
319
|
+
|
|
320
|
+
await command(drawer1, "--open");
|
|
321
|
+
expect(drawer1).dom.to.equalTag(
|
|
322
|
+
`<content-drawer is-open singleton-name="foo"></content-drawer>`,
|
|
323
|
+
);
|
|
324
|
+
expect(drawer2).dom.to.equalTag(
|
|
325
|
+
`<content-drawer singleton-name="foo"></content-drawer>`,
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
await command(drawer2, "--open");
|
|
329
|
+
expect(drawer1).dom.to.equalTag(
|
|
330
|
+
`<content-drawer singleton-name="foo"></content-drawer>`,
|
|
331
|
+
);
|
|
332
|
+
expect(drawer2).dom.to.equalTag(
|
|
333
|
+
`<content-drawer is-open singleton-name="foo"></content-drawer>`,
|
|
334
|
+
);
|
|
335
|
+
// a different group is untouched
|
|
336
|
+
expect(other.isOpen).toBe(true);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("stops coordinating when singleton-name is removed", async () => {
|
|
340
|
+
const drawer1 = fixture<HTMLContentDrawerElement>(
|
|
341
|
+
`<content-drawer singleton-name="foo"></content-drawer>
|
|
342
|
+
<content-drawer singleton-name="foo"></content-drawer>`,
|
|
343
|
+
);
|
|
344
|
+
const drawer2 = drawer1.nextElementSibling as HTMLContentDrawerElement;
|
|
345
|
+
drawer1.isOpen = true;
|
|
346
|
+
drawer2.removeAttribute("singleton-name");
|
|
347
|
+
drawer2.isOpen = true;
|
|
348
|
+
expect(drawer1.isOpen).toBe(true);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("keeps coordinating after a DOM move", async () => {
|
|
352
|
+
const drawer1 = fixture<HTMLContentDrawerElement>(
|
|
353
|
+
`<content-drawer singleton-name="foo"></content-drawer>
|
|
354
|
+
<content-drawer singleton-name="foo"></content-drawer>`,
|
|
355
|
+
);
|
|
356
|
+
const drawer2 = drawer1.nextElementSibling as HTMLContentDrawerElement;
|
|
357
|
+
const target = document.createElement("div");
|
|
358
|
+
document.body.append(target);
|
|
359
|
+
target.append(drawer1); // move
|
|
360
|
+
await wait(0);
|
|
361
|
+
|
|
362
|
+
drawer1.isOpen = true;
|
|
363
|
+
await command(drawer2, "--open");
|
|
364
|
+
expect(drawer1.isOpen).toBe(false);
|
|
365
|
+
expect(drawer2.isOpen).toBe(true);
|
|
366
|
+
|
|
367
|
+
await command(drawer1, "--open");
|
|
368
|
+
expect(drawer1.isOpen).toBe(true);
|
|
369
|
+
expect(drawer2.isOpen).toBe(false);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("keeps coordinating after a disconnect and reconnect", async () => {
|
|
373
|
+
const drawer1 = fixture<HTMLContentDrawerElement>(
|
|
374
|
+
`<content-drawer singleton-name="foo"></content-drawer>
|
|
375
|
+
<content-drawer singleton-name="foo"></content-drawer>`,
|
|
376
|
+
);
|
|
377
|
+
const drawer2 = drawer1.nextElementSibling as HTMLContentDrawerElement;
|
|
378
|
+
drawer1.remove();
|
|
379
|
+
await wait(0);
|
|
380
|
+
document.body.append(drawer1);
|
|
381
|
+
await wait(0);
|
|
382
|
+
|
|
383
|
+
drawer1.isOpen = true;
|
|
384
|
+
await command(drawer2, "--open");
|
|
385
|
+
expect(drawer1.isOpen).toBe(false);
|
|
386
|
+
expect(drawer2.isOpen).toBe(true);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
wait,
|
|
9
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
10
|
+
import {
|
|
11
|
+
click,
|
|
12
|
+
flush,
|
|
13
|
+
mountView,
|
|
14
|
+
readDemo,
|
|
15
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
16
|
+
|
|
17
|
+
describe("disappear view", () => {
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
document.body.innerHTML = "";
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("opens then auto-closes after disappear-after", async () => {
|
|
23
|
+
const { root } = await mountView(readDemo(import.meta.url, "disappear"));
|
|
24
|
+
const drawer = root.querySelector("content-drawer")!;
|
|
25
|
+
expect(drawer.getAttribute("disappear-after")).toBe("2");
|
|
26
|
+
click(root.querySelector("button[command]"));
|
|
27
|
+
await flush();
|
|
28
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
29
|
+
await wait(2100);
|
|
30
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import "@excom/quark-sheet";
|
|
2
|
+
import "@excom/event-handler";
|
|
3
|
+
import "@excom/dismiss-watcher";
|
|
4
|
+
import "../../index";
|
|
5
|
+
import {
|
|
6
|
+
afterEach,
|
|
7
|
+
describe,
|
|
8
|
+
expect,
|
|
9
|
+
it,
|
|
10
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
11
|
+
import {
|
|
12
|
+
click,
|
|
13
|
+
flush,
|
|
14
|
+
mountView,
|
|
15
|
+
readDemo,
|
|
16
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
17
|
+
|
|
18
|
+
const outsideMouseup = (target: EventTarget) =>
|
|
19
|
+
target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
|
|
20
|
+
|
|
21
|
+
describe("dismiss view", () => {
|
|
22
|
+
afterEach(() => {
|
|
23
|
+
document.body.innerHTML = "";
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("dismisses the drawer on outside click and Escape through dismiss-watcher", async () => {
|
|
27
|
+
const { root } = await mountView(readDemo(import.meta.url, "dismiss"));
|
|
28
|
+
const drawer = root.querySelector("content-drawer")!;
|
|
29
|
+
const watcher = drawer.querySelector("dismiss-watcher")!;
|
|
30
|
+
expect(drawer.hasAttribute("is-modal")).toBe(false);
|
|
31
|
+
expect(watcher.hasAttribute("is-active")).toBe(false);
|
|
32
|
+
|
|
33
|
+
click(root.querySelector("button[command]"));
|
|
34
|
+
await flush();
|
|
35
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
36
|
+
expect(watcher.hasAttribute("is-active")).toBe(true);
|
|
37
|
+
|
|
38
|
+
outsideMouseup(drawer.querySelector("nav")!);
|
|
39
|
+
await flush();
|
|
40
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
41
|
+
|
|
42
|
+
outsideMouseup(document.body);
|
|
43
|
+
await flush();
|
|
44
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
45
|
+
expect(watcher.hasAttribute("is-active")).toBe(false);
|
|
46
|
+
|
|
47
|
+
click(root.querySelector("button[command]"));
|
|
48
|
+
await flush();
|
|
49
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
50
|
+
watcher._closeWatcher!.requestClose();
|
|
51
|
+
await flush();
|
|
52
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
53
|
+
|
|
54
|
+
// the overlay still closes it
|
|
55
|
+
click(root.querySelector("button[command]"));
|
|
56
|
+
await flush();
|
|
57
|
+
click(root.querySelector(".tag-backdrop"));
|
|
58
|
+
await flush();
|
|
59
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import {
|
|
10
|
+
click,
|
|
11
|
+
flush,
|
|
12
|
+
mountView,
|
|
13
|
+
readDemo,
|
|
14
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
15
|
+
|
|
16
|
+
describe("from-side view", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = "";
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("toggles a left-side drawer", async () => {
|
|
22
|
+
const { root } = await mountView(readDemo(import.meta.url, "from-side"));
|
|
23
|
+
const drawer = root.querySelector("content-drawer")!;
|
|
24
|
+
expect(drawer.getAttribute("from-side")).toBe("left");
|
|
25
|
+
click(root.querySelector("button[command]"));
|
|
26
|
+
await flush();
|
|
27
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
28
|
+
click(root.querySelector(".tag-backdrop"));
|
|
29
|
+
await flush();
|
|
30
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import {
|
|
10
|
+
click,
|
|
11
|
+
flush,
|
|
12
|
+
mountView,
|
|
13
|
+
readDemo,
|
|
14
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
15
|
+
|
|
16
|
+
describe("simple view", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = "";
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("toggles the bottom sheet and closes from the header", async () => {
|
|
22
|
+
const { root } = await mountView(readDemo(import.meta.url, "simple"));
|
|
23
|
+
const drawer = root.querySelector("content-drawer")!;
|
|
24
|
+
// bottom is the default: no from-side needed
|
|
25
|
+
expect(drawer.hasAttribute("from-side")).toBe(false);
|
|
26
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
27
|
+
click(root.querySelector("button[command]"));
|
|
28
|
+
await flush();
|
|
29
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
30
|
+
click(drawer.querySelector("[rel='prev']"));
|
|
31
|
+
await flush();
|
|
32
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
33
|
+
click(root.querySelector("button[command]"));
|
|
34
|
+
await flush();
|
|
35
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
36
|
+
click(root.querySelector(".tag-backdrop"));
|
|
37
|
+
await flush();
|
|
38
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import {
|
|
10
|
+
click,
|
|
11
|
+
flush,
|
|
12
|
+
mountView,
|
|
13
|
+
readDemo,
|
|
14
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
15
|
+
|
|
16
|
+
describe("singleton view", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = "";
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("opening B closes A", async () => {
|
|
22
|
+
const { root } = await mountView(readDemo(import.meta.url, "singleton"));
|
|
23
|
+
const a = root.querySelector("#drawer-a")!;
|
|
24
|
+
const b = root.querySelector("#drawer-b")!;
|
|
25
|
+
const [openA, openB] = root.querySelectorAll("button[command]");
|
|
26
|
+
click(openA);
|
|
27
|
+
await flush();
|
|
28
|
+
expect(a.hasAttribute("is-open")).toBe(true);
|
|
29
|
+
expect(b.hasAttribute("is-open")).toBe(false);
|
|
30
|
+
click(openB);
|
|
31
|
+
await flush();
|
|
32
|
+
expect(a.hasAttribute("is-open")).toBe(false);
|
|
33
|
+
expect(b.hasAttribute("is-open")).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import "@excom/event-handler";
|
|
2
|
+
import "../../index";
|
|
3
|
+
import {
|
|
4
|
+
afterEach,
|
|
5
|
+
describe,
|
|
6
|
+
expect,
|
|
7
|
+
it,
|
|
8
|
+
} from "@excom/heft-rig/profiles/default/config/test-utils";
|
|
9
|
+
import {
|
|
10
|
+
click,
|
|
11
|
+
flush,
|
|
12
|
+
mountView,
|
|
13
|
+
readDemo,
|
|
14
|
+
} from "@excom/quark/support/tests/view-helpers";
|
|
15
|
+
|
|
16
|
+
describe("stages view", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
document.body.innerHTML = "";
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("opens at full, half, and peek stages", async () => {
|
|
22
|
+
const { root } = await mountView(readDemo(import.meta.url, "stages"));
|
|
23
|
+
const drawer = root.querySelector("content-drawer")!;
|
|
24
|
+
const buttons = root.querySelectorAll("button[command]");
|
|
25
|
+
click(buttons[0]);
|
|
26
|
+
await flush();
|
|
27
|
+
expect(drawer.hasAttribute("is-open")).toBe(true);
|
|
28
|
+
expect(drawer.getAttribute("open-stage")).toBe("0");
|
|
29
|
+
click(buttons[1]);
|
|
30
|
+
await flush();
|
|
31
|
+
expect(drawer.getAttribute("open-stage")).toBe("1");
|
|
32
|
+
click(buttons[2]);
|
|
33
|
+
await flush();
|
|
34
|
+
expect(drawer.getAttribute("open-stage")).toBe("2");
|
|
35
|
+
click(drawer.querySelector("[rel='prev']"));
|
|
36
|
+
await flush();
|
|
37
|
+
expect(drawer.hasAttribute("is-open")).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
});
|