Skip to content

Commit 56f3e68

Browse files
authored
fix: improve demo controllers, do not reset state (#129)
1 parent e9f9747 commit 56f3e68

File tree

6 files changed

+120
-130
lines changed

6 files changed

+120
-130
lines changed

.changeset/gorgeous-trees-smash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@api-viewer/demo': patch
3+
---
4+
5+
Improve demo controllers, do not reset state
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { ReactiveController, ReactiveControllerHost } from 'lit';
2+
3+
export type AbstractControllerHost = HTMLElement & ReactiveControllerHost;
4+
5+
export class AbstractController<T> {
6+
host: AbstractControllerHost;
7+
8+
el: HTMLElement;
9+
10+
private _data: T[] = [];
11+
12+
get data(): T[] {
13+
return this._data;
14+
}
15+
16+
set data(data: T[]) {
17+
this._data = data;
18+
19+
this.updateData(data);
20+
}
21+
22+
updateData(_data: T[]) {
23+
if (this.host.isConnected) {
24+
this.host.requestUpdate();
25+
}
26+
}
27+
28+
constructor(host: AbstractControllerHost, component: HTMLElement) {
29+
(this.host = host).addController(this as ReactiveController);
30+
this.el = component;
31+
}
32+
33+
clear() {
34+
this.data = [];
35+
}
36+
37+
destroy() {
38+
this.host.removeController(this as ReactiveController);
39+
}
40+
}
Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,30 @@
1-
import { ReactiveController, ReactiveControllerHost } from 'lit';
21
import { Event } from '@api-viewer/common/lib/manifest.js';
2+
import {
3+
AbstractController,
4+
AbstractControllerHost
5+
} from './abstract-controller.js';
36
import { HasKnobs } from '../ui/knobs.js';
47

5-
type EventsHost = HTMLElement & ReactiveControllerHost & HasKnobs;
6-
7-
export class EventsController implements ReactiveController {
8-
host: EventsHost;
9-
10-
private _log: CustomEvent[] = [];
11-
12-
get log(): CustomEvent[] {
13-
return this._log;
14-
}
15-
16-
set log(log: CustomEvent[]) {
17-
this._log = log;
18-
19-
if (this.host.isConnected) {
20-
this.host.requestUpdate();
21-
}
22-
}
23-
8+
export class EventsController extends AbstractController<CustomEvent> {
249
constructor(
25-
host: ReactiveControllerHost,
10+
host: AbstractControllerHost & HasKnobs,
2611
component: HTMLElement,
2712
events: Event[]
2813
) {
29-
(this.host = host as EventsHost).addController(this);
14+
super(host, component);
3015

3116
events.forEach(({ name }) => {
3217
component.addEventListener(name, ((evt: CustomEvent) => {
3318
const s = '-changed';
3419
if (name.endsWith(s)) {
35-
const { knob } = this.host.getKnob(name.replace(s, ''));
20+
const { knob } = host.getKnob(name.replace(s, ''));
3621
if (knob) {
37-
this.host.syncKnob(component, knob);
22+
host.syncKnob(component, knob);
3823
}
3924
}
4025

41-
this.log = [...this.log, evt];
26+
this.data = [...this.data, evt];
4227
}) as EventListener);
4328
});
4429
}
45-
46-
clear() {
47-
this.log = [];
48-
}
49-
50-
hostDisconnected() {
51-
this.clear();
52-
}
5330
}
Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,32 @@
1-
import { ReactiveController, ReactiveControllerHost } from 'lit';
21
import { Slot, SlotValue } from '@api-viewer/common/lib/index.js';
32
import {
43
hasTemplate,
54
TemplateTypes
65
} from '@api-viewer/common/lib/templates.js';
6+
import {
7+
AbstractController,
8+
AbstractControllerHost
9+
} from './abstract-controller.js';
710

811
const capitalize = (name: string): string =>
912
name[0].toUpperCase() + name.slice(1);
1013

1114
const getSlotContent = (name: string): string =>
1215
capitalize(name === '' ? 'content' : name);
1316

14-
export class SlotsController implements ReactiveController {
15-
host: ReactiveControllerHost;
16-
17+
export class SlotsController extends AbstractController<SlotValue> {
1718
enabled: boolean;
1819

19-
el: HTMLElement;
20-
21-
private _slots: SlotValue[] = [];
22-
23-
get slots(): SlotValue[] {
24-
return this._slots;
25-
}
26-
27-
set slots(slots: SlotValue[]) {
28-
this._slots = slots;
29-
30-
// Apply slots content by re-creating nodes
31-
if (this.enabled && this.el.isConnected && slots && slots.length) {
32-
this.el.innerHTML = '';
33-
slots.forEach((slot) => {
34-
let node: Element | Text;
35-
const { name, content } = slot;
36-
if (name) {
37-
node = document.createElement('div');
38-
node.setAttribute('slot', name);
39-
node.textContent = content;
40-
} else {
41-
node = document.createTextNode(content);
42-
}
43-
this.el.appendChild(node);
44-
});
45-
}
46-
47-
// Update the demo snippet
48-
this.host.requestUpdate();
49-
}
50-
5120
constructor(
52-
host: ReactiveControllerHost,
53-
id: number,
21+
host: AbstractControllerHost,
5422
component: HTMLElement,
23+
id: number,
5524
slots: Slot[]
5625
) {
57-
(this.host = host).addController(this as ReactiveController);
58-
this.el = component;
26+
super(host, component);
27+
5928
this.enabled = !hasTemplate(id, component.localName, TemplateTypes.SLOT);
60-
this.slots = slots
29+
this.data = slots
6130
.sort((a, b) => {
6231
if (a.name === '') {
6332
return 1;
@@ -75,12 +44,8 @@ export class SlotsController implements ReactiveController {
7544
}) as SlotValue[];
7645
}
7746

78-
hostDisconnected() {
79-
this.slots = [];
80-
}
81-
8247
setValue(name: string, content: string) {
83-
this.slots = this.slots.map((slot) => {
48+
this.data = this.data.map((slot) => {
8449
return slot.name === name
8550
? {
8651
...slot,
@@ -89,4 +54,25 @@ export class SlotsController implements ReactiveController {
8954
: slot;
9055
});
9156
}
57+
58+
updateData(data: SlotValue[]) {
59+
super.updateData(data);
60+
61+
// Apply slots content by re-creating nodes
62+
if (this.enabled && this.el.isConnected && data && data.length) {
63+
this.el.innerHTML = '';
64+
data.forEach((slot) => {
65+
let node: Element | Text;
66+
const { name, content } = slot;
67+
if (name) {
68+
node = document.createElement('div');
69+
node.setAttribute('slot', name);
70+
node.textContent = content;
71+
} else {
72+
node = document.createTextNode(content);
73+
}
74+
this.el.appendChild(node);
75+
});
76+
}
77+
}
9278
}
Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,25 @@
1-
import { ReactiveController, ReactiveControllerHost } from 'lit';
21
import {
32
CssCustomProperty,
43
CssCustomPropertyValue,
54
unquote
65
} from '@api-viewer/common/lib/index.js';
6+
import {
7+
AbstractController,
8+
AbstractControllerHost
9+
} from './abstract-controller.js';
710

8-
export class StylesController implements ReactiveController {
9-
host: HTMLElement & ReactiveControllerHost;
10-
11-
el: HTMLElement;
12-
13-
private _css: CssCustomPropertyValue[] = [];
14-
15-
get css(): CssCustomPropertyValue[] {
16-
return this._css;
17-
}
18-
19-
set css(cssProps: CssCustomPropertyValue[]) {
20-
this._css = cssProps;
21-
22-
if (cssProps.length) {
23-
cssProps.forEach((prop) => {
24-
const { name, value } = prop;
25-
if (value) {
26-
if (value === prop.default) {
27-
this.el.style.removeProperty(name);
28-
} else {
29-
this.el.style.setProperty(name, value);
30-
}
31-
}
32-
});
33-
}
34-
35-
// Update the demo snippet
36-
if (this.host.isConnected) {
37-
this.host.requestUpdate();
38-
}
39-
}
40-
11+
export class StylesController extends AbstractController<CssCustomPropertyValue> {
4112
constructor(
42-
host: HTMLElement & ReactiveControllerHost,
13+
host: AbstractControllerHost,
4314
component: HTMLElement,
4415
cssProps: CssCustomProperty[]
4516
) {
46-
(this.host = host).addController(this);
47-
this.el = component;
17+
super(host, component);
4818

4919
if (cssProps.length) {
5020
const style = getComputedStyle(component);
5121

52-
this.css = cssProps.map((cssProp) => {
22+
this.data = cssProps.map((cssProp) => {
5323
let value = cssProp.default
5424
? unquote(cssProp.default)
5525
: style.getPropertyValue(cssProp.name);
@@ -66,12 +36,8 @@ export class StylesController implements ReactiveController {
6636
}
6737
}
6838

69-
hostDisconnected() {
70-
this.css = [];
71-
}
72-
7339
setValue(name: string, value: string) {
74-
this.css = this.css.map((prop) => {
40+
this.data = this.data.map((prop) => {
7541
return prop.name === name
7642
? {
7743
...prop,
@@ -80,4 +46,21 @@ export class StylesController implements ReactiveController {
8046
: prop;
8147
});
8248
}
49+
50+
updateData(data: CssCustomPropertyValue[]) {
51+
super.updateData(data);
52+
53+
if (data.length) {
54+
data.forEach((prop) => {
55+
const { name, value } = prop;
56+
if (value) {
57+
if (value === prop.default) {
58+
this.el.style.removeProperty(name);
59+
} else {
60+
this.el.style.setProperty(name, value);
61+
}
62+
}
63+
});
64+
}
65+
}
8366
}

packages/api-demo/src/layout.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ class ApiDemoLayout extends LitElement {
104104
].map((arr) => arr.length === 0);
105105

106106
const id = this.vid as number;
107-
const log = this.eventsController?.log || [];
108-
const slots = this.slotsController?.slots || [];
109-
const cssProps = this.stylesController?.css || [];
107+
const log = this.eventsController?.data || [];
108+
const slots = this.slotsController?.data || [];
109+
const cssProps = this.stylesController?.data || [];
110110
const hideSlots = noSlots || hasTemplate(id, tag, TemplateTypes.SLOT);
111111

112112
return html`
@@ -266,8 +266,7 @@ class ApiDemoLayout extends LitElement {
266266
private initEvents(component: HTMLElement) {
267267
const controller = this.eventsController;
268268
if (controller) {
269-
controller.clear();
270-
this.removeController(controller);
269+
controller.destroy();
271270
}
272271

273272
this.eventsController = new EventsController(this, component, this.events);
@@ -286,21 +285,21 @@ class ApiDemoLayout extends LitElement {
286285
private initSlots(component: HTMLElement) {
287286
const controller = this.slotsController;
288287
if (controller) {
289-
this.removeController(controller);
288+
controller.destroy();
290289
}
291290

292291
this.slotsController = new SlotsController(
293292
this,
294-
this.vid as number,
295293
component,
294+
this.vid as number,
296295
this.slots
297296
);
298297
}
299298

300299
private initStyles(component: HTMLElement) {
301300
const controller = this.stylesController;
302301
if (controller) {
303-
this.removeController(controller);
302+
controller.destroy();
304303
}
305304

306305
this.stylesController = new StylesController(

0 commit comments

Comments
 (0)