UNPKG

4.09 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var update = require('./update.js');
6var helpers = require('./helpers.js');
7var render = require('./render.js');
8var mergeSlots = require('./mergeSlots.js');
9
10function getDataScript(node) {
11 return node.querySelector(`script[type="application/mosaic"]`)
12}
13
14function createDataScript(node) {
15 let ds = document.createElement("script");
16 ds.setAttribute("type", "application/mosaic");
17 node.append(ds);
18 return ds
19}
20
21function serialise(node, state) {
22 let ds = getDataScript(node) || createDataScript(node);
23
24 ds.innerText = JSON.stringify(state);
25}
26
27function deserialise(node) {
28 return JSON.parse(getDataScript(node)?.innerText || "{}")
29}
30
31const define = (name, factory, template) =>
32 customElements.define(
33 name,
34 class extends HTMLElement {
35 async connectedCallback() {
36 if (!this.initialised) {
37 let config = factory(this);
38
39 if (config instanceof Promise) config = await config;
40
41 let {
42 update: update$1,
43 middleware,
44 derivations,
45 subscribe,
46 shadow,
47 initialState = {},
48 } = config;
49
50 this.connectedCallback = config.connectedCallback;
51 this.disconnectedCallback = config.disconnectedCallback;
52
53 const { dispatch, getState, onUpdate, flush } = update.configure(
54 config,
55 this
56 );
57
58 dispatch({
59 type: "MERGE",
60 payload: deserialise(this),
61 });
62
63 initialState = getState();
64
65 let observedProps = Object.keys(initialState).filter(
66 (v) => v.charAt(0) === "$"
67 );
68
69 let observedAttributes = observedProps
70 .map((v) => v.slice(1))
71 .map(helpers.pascalToKebab);
72
73 let sa = this.setAttribute;
74 this.setAttribute = (k, v) => {
75 if (observedAttributes.includes(k)) {
76 let { name, value } = helpers.attributeToProp(k, v);
77 dispatch({
78 type: "SET",
79 payload: { name: "$" + name, value },
80 });
81 }
82 sa.apply(this, [k, v]);
83 };
84
85 observedAttributes.forEach((name) => {
86 let property = helpers.attributeToProp(name).name;
87
88 let value;
89
90 if (this.hasAttribute(name)) {
91 value = this.getAttribute(name);
92 } else {
93 value = this[property] || initialState["$" + property];
94 }
95
96 Object.defineProperty(this, property, {
97 get() {
98 return getState()["$" + property]
99 },
100 set(v) {
101 dispatch({
102 type: "SET",
103 payload: { name: "$" + property, value: v },
104 });
105 if (helpers.isPrimitive(v)) {
106 helpers.applyAttribute(this, property, v);
107 }
108 },
109 });
110
111 this[property] = value;
112 });
113
114 let beforeMountCallback;
115
116 if (shadow) {
117 this.attachShadow({
118 mode: shadow,
119 });
120 } else {
121 beforeMountCallback = (frag) => mergeSlots.mergeSlots(this, frag);
122 }
123
124 onUpdate(
125 render.render(
126 this.shadowRoot || this,
127 { getState, dispatch },
128 template,
129 () => {
130 serialise(this, getState());
131
132 observedProps.forEach((k) => {
133 let v = getState()[k];
134 if (helpers.isPrimitive(v)) helpers.applyAttribute(this, k.slice(1), v);
135 });
136 subscribe?.(getState());
137 flush();
138 },
139 beforeMountCallback
140 )
141 );
142 this.initialised = true;
143 }
144 this.connectedCallback?.();
145 }
146 disconnectedCallback() {
147 this.disconnectedCallback?.();
148 }
149 }
150 );
151
152exports.define = define;