leaflet-html 0.1.7 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- package/.github/workflows/npm-publish.yml +27 -27
- package/.prettierignore +2 -0
- package/.prettierrc +1 -0
- package/README.md +63 -36
- package/dist/leaflet-html.cjs +1 -1
- package/dist/leaflet-html.cjs.map +1 -1
- package/dist/leaflet-html.esm.js +1 -1
- package/dist/leaflet-html.esm.js.map +1 -1
- package/dist/leaflet-html.js +1 -1
- package/dist/leaflet-html.js.map +1 -1
- package/dist/leaflet-html.umd.js +1 -1
- package/dist/leaflet-html.umd.js.map +1 -1
- package/docs/content/_index.md +66 -63
- package/docs/content/articles/_index.md +5 -0
- package/docs/content/articles/basic.md +105 -0
- package/docs/content/articles/icons.md +35 -0
- package/docs/content/articles/style.md +14 -0
- package/docs/public/icons/leaf-green.png +0 -0
- package/docs/public/icons/leaf-orange.png +0 -0
- package/docs/public/icons/leaf-red.png +0 -0
- package/docs/public/icons/leaf-shadow.png +0 -0
- package/docs/static/icons/leaf-green.png +0 -0
- package/docs/static/icons/leaf-orange.png +0 -0
- package/docs/static/icons/leaf-red.png +0 -0
- package/docs/static/icons/leaf-shadow.png +0 -0
- package/docs/templates/article-page.html +8 -0
- package/docs/templates/article.html +12 -0
- package/docs/templates/base.html +59 -0
- package/docs/templates/index.html +5 -52
- package/example/geojson/index.html +42 -0
- package/example/index.html +58 -50
- package/example/overlays/index.html +34 -35
- package/package.json +12 -5
- package/src/events.js +3 -0
- package/src/index.js +27 -185
- package/src/l-base-layers.js +15 -0
- package/src/l-control-layers.js +34 -0
- package/src/l-geojson.js +22 -0
- package/src/l-icon.js +124 -0
- package/src/l-image-overlay.js +43 -0
- package/src/l-lat-lng-bounds.js +20 -0
- package/src/l-layer-group.js +39 -0
- package/src/l-map.js +33 -0
- package/src/l-marker.js +94 -0
- package/src/l-overlay-layers.js +15 -0
- package/src/l-popup.js +21 -0
- package/src/l-tile-layer.js +22 -0
- package/src/l-video-overlay.js +31 -0
- package/vite.config.js +7 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LBaseLayers extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
this.addEventListener(mapAddTo, (ev) => {
|
10
|
+
ev.detail["type"] = "base";
|
11
|
+
});
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
export default LBaseLayers;
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LControlLayers extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const base = {};
|
10
|
+
const overlay = {};
|
11
|
+
const control = L.control.layers(base, overlay);
|
12
|
+
|
13
|
+
this.addEventListener(mapAddTo, (ev) => {
|
14
|
+
const { type, name, layer } = ev.detail;
|
15
|
+
if (type === "overlay") {
|
16
|
+
control.addOverlay(layer, name);
|
17
|
+
} else if (type === "base") {
|
18
|
+
control.addBaseLayer(layer, name);
|
19
|
+
}
|
20
|
+
ev.preventDefault();
|
21
|
+
});
|
22
|
+
|
23
|
+
const event = new CustomEvent(mapAddTo, {
|
24
|
+
cancelable: true,
|
25
|
+
bubbles: true,
|
26
|
+
detail: {
|
27
|
+
layer: control,
|
28
|
+
},
|
29
|
+
});
|
30
|
+
this.dispatchEvent(event);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
export default LControlLayers;
|
package/src/l-geojson.js
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LGeoJSON extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const layer = L.geoJSON(JSON.parse(this.getAttribute("geojson")));
|
10
|
+
this.dispatchEvent(
|
11
|
+
new CustomEvent(mapAddTo, {
|
12
|
+
bubbles: true,
|
13
|
+
cancelable: true,
|
14
|
+
detail: {
|
15
|
+
layer,
|
16
|
+
},
|
17
|
+
}),
|
18
|
+
);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
export default LGeoJSON;
|
package/src/l-icon.js
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
// @vitest-environment happy-dom
|
2
|
+
import * as L from "leaflet";
|
3
|
+
|
4
|
+
const camelCase = (kebab) => kebab.replace(/-./g, (x) => x[1].toUpperCase());
|
5
|
+
|
6
|
+
class LIcon extends HTMLElement {
|
7
|
+
constructor() {
|
8
|
+
super();
|
9
|
+
this.icon = null;
|
10
|
+
}
|
11
|
+
|
12
|
+
connectedCallback() {
|
13
|
+
const options = {};
|
14
|
+
|
15
|
+
// Strings
|
16
|
+
let keys = [
|
17
|
+
"icon-url",
|
18
|
+
"icon-retina-url",
|
19
|
+
"shadow-url",
|
20
|
+
"shadow-retina-url",
|
21
|
+
"class-name",
|
22
|
+
];
|
23
|
+
keys.forEach((key) => {
|
24
|
+
if (this.hasAttribute(key)) {
|
25
|
+
options[camelCase(key)] = this.getAttribute(key);
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
// Points
|
30
|
+
let points = [
|
31
|
+
"icon-anchor",
|
32
|
+
"icon-size",
|
33
|
+
"shadow-anchor",
|
34
|
+
"shadow-size",
|
35
|
+
"tooltip-anchor",
|
36
|
+
"popup-anchor",
|
37
|
+
];
|
38
|
+
points.forEach((key) => {
|
39
|
+
if (this.hasAttribute(key)) {
|
40
|
+
options[camelCase(key)] = JSON.parse(this.getAttribute(key));
|
41
|
+
}
|
42
|
+
});
|
43
|
+
|
44
|
+
if (this.hasAttribute("cross-origin")) {
|
45
|
+
options.crossOrigin = this.getAttribute("cross-origin") === "true";
|
46
|
+
}
|
47
|
+
this.icon = L.icon(options);
|
48
|
+
|
49
|
+
const event = new CustomEvent("icon:add", {
|
50
|
+
cancelable: true,
|
51
|
+
bubbles: true,
|
52
|
+
detail: {
|
53
|
+
icon: this.icon,
|
54
|
+
},
|
55
|
+
});
|
56
|
+
this.dispatchEvent(event);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
if (import.meta.vitest) {
|
61
|
+
const { it, expect, beforeAll } = import.meta.vitest;
|
62
|
+
|
63
|
+
beforeAll(() => {
|
64
|
+
customElements.define("l-icon", LIcon);
|
65
|
+
});
|
66
|
+
|
67
|
+
it("default", () => {
|
68
|
+
const el = document.createElement("l-icon");
|
69
|
+
document.body.appendChild(el);
|
70
|
+
|
71
|
+
let actual = el.icon;
|
72
|
+
let expected = L.icon();
|
73
|
+
expect(actual).toEqual(expected);
|
74
|
+
});
|
75
|
+
|
76
|
+
it("emits icon:add event", async () => {
|
77
|
+
const el = document.createElement("l-icon");
|
78
|
+
let promise = new Promise((resolve) => {
|
79
|
+
el.addEventListener("icon:add", (ev) => {
|
80
|
+
resolve(ev.detail.icon);
|
81
|
+
});
|
82
|
+
});
|
83
|
+
document.body.appendChild(el);
|
84
|
+
let actual = await promise;
|
85
|
+
let expected = L.icon();
|
86
|
+
expect(actual).toEqual(expected);
|
87
|
+
});
|
88
|
+
|
89
|
+
it("options", () => {
|
90
|
+
const el = document.createElement("l-icon");
|
91
|
+
el.setAttribute("icon-url", "url.png");
|
92
|
+
el.setAttribute("icon-retina-url", "retina.png");
|
93
|
+
el.setAttribute("icon-size", "[0, 0]");
|
94
|
+
el.setAttribute("icon-anchor", "[0, 0]");
|
95
|
+
el.setAttribute("popup-anchor", "[0, 0]");
|
96
|
+
el.setAttribute("tooltip-anchor", "[0, 0]");
|
97
|
+
el.setAttribute("shadow-url", "urlShadow.png");
|
98
|
+
el.setAttribute("shadow-retina-url", "retinaShadow.png");
|
99
|
+
el.setAttribute("shadow-size", "[0, 0]");
|
100
|
+
el.setAttribute("shadow-anchor", "[0, 0]");
|
101
|
+
el.setAttribute("class-name", "foo");
|
102
|
+
el.setAttribute("cross-origin", "true");
|
103
|
+
document.body.appendChild(el);
|
104
|
+
|
105
|
+
let actual = el.icon;
|
106
|
+
let expected = L.icon({
|
107
|
+
iconUrl: "url.png",
|
108
|
+
iconRetinaUrl: "retina.png",
|
109
|
+
iconSize: [0, 0],
|
110
|
+
iconAnchor: [0, 0],
|
111
|
+
popupAnchor: [0, 0],
|
112
|
+
tooltipAnchor: [0, 0],
|
113
|
+
shadowUrl: "urlShadow.png",
|
114
|
+
shadowRetinaUrl: "retinaShadow.png",
|
115
|
+
shadowSize: [0, 0],
|
116
|
+
shadowAnchor: [0, 0],
|
117
|
+
className: "foo",
|
118
|
+
crossOrigin: true,
|
119
|
+
});
|
120
|
+
expect(actual).toEqual(expected);
|
121
|
+
});
|
122
|
+
}
|
123
|
+
|
124
|
+
export default LIcon;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LImageOverlay extends HTMLElement {
|
4
|
+
static observedAttributes = ["url", "bounds", "opacity"];
|
5
|
+
|
6
|
+
constructor() {
|
7
|
+
super();
|
8
|
+
this.layer = null;
|
9
|
+
}
|
10
|
+
|
11
|
+
connectedCallback() {
|
12
|
+
const url = this.getAttribute("url");
|
13
|
+
const bounds = JSON.parse(this.getAttribute("bounds"));
|
14
|
+
const options = {
|
15
|
+
opacity: parseFloat(this.getAttribute("opacity") || "1.0"),
|
16
|
+
alt: this.getAttribute("alt") || "",
|
17
|
+
};
|
18
|
+
this.layer = L.imageOverlay(url, bounds, options);
|
19
|
+
this.dispatchEvent(
|
20
|
+
new CustomEvent(mapAddTo, {
|
21
|
+
cancelable: true,
|
22
|
+
bubbles: true,
|
23
|
+
detail: {
|
24
|
+
layer: this.layer,
|
25
|
+
},
|
26
|
+
}),
|
27
|
+
);
|
28
|
+
}
|
29
|
+
|
30
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
31
|
+
if (this.layer !== null) {
|
32
|
+
if (name === "url") {
|
33
|
+
this.layer.setUrl(newValue);
|
34
|
+
} else if (name === "bounds") {
|
35
|
+
this.layer.setBounds(JSON.parse(newValue));
|
36
|
+
} else if (name === "opacity") {
|
37
|
+
this.layer.setOpacity(parseFloat(newValue));
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
export default LImageOverlay;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class LLatLngBounds extends HTMLElement {
|
2
|
+
static observedAttributes = ["bounds"];
|
3
|
+
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
attributeChangedCallback(_name, _oldValue, newValue) {
|
9
|
+
const event = new CustomEvent("map:bounds", {
|
10
|
+
bubbles: true,
|
11
|
+
detail: {
|
12
|
+
bounds: JSON.parse(newValue),
|
13
|
+
method: this.getAttribute("method") || "fitBounds",
|
14
|
+
},
|
15
|
+
});
|
16
|
+
this.dispatchEvent(event);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
export default LLatLngBounds;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LLayerGroup extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const name = this.getAttribute("name");
|
10
|
+
const group = L.layerGroup();
|
11
|
+
const event = new CustomEvent(mapAddTo, {
|
12
|
+
cancelable: true,
|
13
|
+
bubbles: true,
|
14
|
+
detail: {
|
15
|
+
layer: group,
|
16
|
+
name,
|
17
|
+
},
|
18
|
+
});
|
19
|
+
this.dispatchEvent(event);
|
20
|
+
|
21
|
+
this.addEventListener(mapAddTo, (ev) => {
|
22
|
+
ev.stopPropagation();
|
23
|
+
group.addLayer(ev.detail.layer);
|
24
|
+
});
|
25
|
+
|
26
|
+
const observer = new MutationObserver(function (mutations) {
|
27
|
+
mutations.forEach((mutation) => {
|
28
|
+
mutation.removedNodes.forEach((node) => {
|
29
|
+
const leafletId = node.getAttribute("leaflet-id");
|
30
|
+
const layer = group.getLayer(leafletId);
|
31
|
+
group.removeLayer(layer);
|
32
|
+
});
|
33
|
+
});
|
34
|
+
});
|
35
|
+
observer.observe(this, { childList: true });
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
export default LLayerGroup;
|
package/src/l-map.js
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
// @ts-check
|
2
|
+
import { layerRemove, mapAddTo } from "./events.js";
|
3
|
+
|
4
|
+
class LMap extends HTMLElement {
|
5
|
+
constructor() {
|
6
|
+
super();
|
7
|
+
|
8
|
+
this.map = null;
|
9
|
+
this.addEventListener("map:bounds", (ev) => {
|
10
|
+
const { bounds, method } = ev.detail;
|
11
|
+
this.map[method](bounds);
|
12
|
+
});
|
13
|
+
}
|
14
|
+
|
15
|
+
connectedCallback() {
|
16
|
+
this.map = L.map(this);
|
17
|
+
const center = this.getAttribute("center");
|
18
|
+
const zoom = this.getAttribute("zoom");
|
19
|
+
if (center !== null && zoom !== null) {
|
20
|
+
this.map.setView(JSON.parse(center), parseInt(zoom));
|
21
|
+
}
|
22
|
+
this.addEventListener(mapAddTo, (ev) => {
|
23
|
+
const layer = ev.detail.layer;
|
24
|
+
layer.addTo(this.map);
|
25
|
+
});
|
26
|
+
|
27
|
+
this.addEventListener(layerRemove, (ev) => {
|
28
|
+
this.map.remove(ev.detail.layer);
|
29
|
+
});
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
export default LMap;
|
package/src/l-marker.js
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
// @vitest-environment happy-dom
|
2
|
+
import * as L from "leaflet";
|
3
|
+
import { mapAddTo, popupAdd } from "./events.js";
|
4
|
+
|
5
|
+
class LMarker extends HTMLElement {
|
6
|
+
static observedAttributes = ["lat-lng", "opacity", "icon"];
|
7
|
+
|
8
|
+
constructor() {
|
9
|
+
super();
|
10
|
+
this.layer = null;
|
11
|
+
this.addEventListener("icon:add", (ev) => {
|
12
|
+
ev.stopPropagation();
|
13
|
+
this.layer.setIcon(ev.detail.icon);
|
14
|
+
})
|
15
|
+
}
|
16
|
+
|
17
|
+
connectedCallback() {
|
18
|
+
const latLng = JSON.parse(this.getAttribute("lat-lng"));
|
19
|
+
const opacity = parseFloat(this.getAttribute("opacity") || "1.0");
|
20
|
+
this.layer = L.marker(latLng, { opacity });
|
21
|
+
if (this.hasAttribute("icon")) {
|
22
|
+
const icon = L.icon(JSON.parse(this.getAttribute("icon")));
|
23
|
+
this.layer.setIcon(icon);
|
24
|
+
}
|
25
|
+
|
26
|
+
this.setAttribute("leaflet-id", L.stamp(this.layer));
|
27
|
+
|
28
|
+
this.addEventListener(popupAdd, (ev) => {
|
29
|
+
const { content } = ev.detail;
|
30
|
+
this.layer.bindPopup(content);
|
31
|
+
});
|
32
|
+
|
33
|
+
const event = new CustomEvent(mapAddTo, {
|
34
|
+
cancelable: true,
|
35
|
+
bubbles: true,
|
36
|
+
detail: {
|
37
|
+
layer: this.layer,
|
38
|
+
},
|
39
|
+
});
|
40
|
+
this.dispatchEvent(event);
|
41
|
+
}
|
42
|
+
|
43
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
44
|
+
if (this.layer !== null) {
|
45
|
+
if (name === "lat-lng") {
|
46
|
+
this.layer.setLatLng(JSON.parse(newValue));
|
47
|
+
}
|
48
|
+
if (name === "opacity") {
|
49
|
+
this.layer.setOpacity(parseFloat(newValue));
|
50
|
+
}
|
51
|
+
if (name === "icon") {
|
52
|
+
this.layer.setIcon(L.icon(JSON.parse(newValue)));
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
if (import.meta.vitest) {
|
59
|
+
const { it, expect, beforeAll } = import.meta.vitest;
|
60
|
+
|
61
|
+
beforeAll(() => {
|
62
|
+
customElements.define("l-marker", LMarker);
|
63
|
+
});
|
64
|
+
|
65
|
+
it("default icon", () => {
|
66
|
+
const el = document.createElement("l-marker");
|
67
|
+
document.body.appendChild(el);
|
68
|
+
let actual = el.layer.getIcon();
|
69
|
+
let expected = new L.Icon.Default();
|
70
|
+
expect(actual).toEqual(expected);
|
71
|
+
});
|
72
|
+
|
73
|
+
it("adds an icon", () => {
|
74
|
+
const el = document.createElement("l-marker");
|
75
|
+
// Set attribute before appendChild
|
76
|
+
el.setAttribute("icon", JSON.stringify({ iconUrl: "foo.png" }));
|
77
|
+
document.body.appendChild(el);
|
78
|
+
let actual = el.layer.getIcon();
|
79
|
+
let expected = L.icon({ iconUrl: "foo.png" });
|
80
|
+
expect(actual).toEqual(expected);
|
81
|
+
});
|
82
|
+
|
83
|
+
it("changes an icon", () => {
|
84
|
+
const el = document.createElement("l-marker");
|
85
|
+
// Set attribute after appendChild
|
86
|
+
document.body.appendChild(el);
|
87
|
+
el.setAttribute("icon", JSON.stringify({ iconUrl: "bar.png" }));
|
88
|
+
let actual = el.layer.getIcon();
|
89
|
+
let expected = L.icon({ iconUrl: "bar.png" });
|
90
|
+
expect(actual).toEqual(expected);
|
91
|
+
});
|
92
|
+
}
|
93
|
+
|
94
|
+
export default LMarker;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LOverlayLayers extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
this.addEventListener(mapAddTo, (ev) => {
|
10
|
+
ev.detail["type"] = "overlay";
|
11
|
+
});
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
export default LOverlayLayers;
|
package/src/l-popup.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
import { popupAdd } from "./events.js";
|
2
|
+
|
3
|
+
class LPopup extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const content = this.getAttribute("content");
|
10
|
+
const event = new CustomEvent(popupAdd, {
|
11
|
+
cancelable: true,
|
12
|
+
bubbles: true,
|
13
|
+
detail: {
|
14
|
+
content,
|
15
|
+
},
|
16
|
+
});
|
17
|
+
this.dispatchEvent(event);
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
export default LPopup;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LTileLayer extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const name = this.getAttribute("name");
|
10
|
+
const urlTemplate = this.getAttribute("url-template");
|
11
|
+
const attribution = this.getAttribute("attribution");
|
12
|
+
const options = { attribution };
|
13
|
+
const layer = L.tileLayer(urlTemplate, options);
|
14
|
+
const event = new CustomEvent(mapAddTo, {
|
15
|
+
detail: { name, layer },
|
16
|
+
bubbles: true,
|
17
|
+
});
|
18
|
+
this.dispatchEvent(event);
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
export default LTileLayer;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { mapAddTo } from "./events.js";
|
2
|
+
|
3
|
+
class LVideoOverlay extends HTMLElement {
|
4
|
+
constructor() {
|
5
|
+
super();
|
6
|
+
}
|
7
|
+
|
8
|
+
connectedCallback() {
|
9
|
+
const url = JSON.parse(this.getAttribute("url"));
|
10
|
+
const bounds = JSON.parse(this.getAttribute("bounds"));
|
11
|
+
const options = {
|
12
|
+
opacity: parseFloat(this.getAttribute("opacity") || "1.0"),
|
13
|
+
alt: this.getAttribute("alt") || "",
|
14
|
+
autoplay: true,
|
15
|
+
muted: true,
|
16
|
+
playsInline: true,
|
17
|
+
};
|
18
|
+
const layer = L.videoOverlay(url, bounds, options);
|
19
|
+
this.dispatchEvent(
|
20
|
+
new CustomEvent(mapAddTo, {
|
21
|
+
cancelable: true,
|
22
|
+
bubbles: true,
|
23
|
+
detail: {
|
24
|
+
layer,
|
25
|
+
},
|
26
|
+
}),
|
27
|
+
);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
export default LVideoOverlay;
|