@sitecore-feaas/clientside 0.1.45 → 0.1.47
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/build/dom/html.js +287 -0
- package/build/dom/html.js.map +1 -0
- package/build/dom/rendering.js +4 -4
- package/build/dom/rendering.js.map +1 -1
- package/build/dom/scripts.js +2 -2
- package/build/dom/scripts.js.map +1 -1
- package/build/ui/FEAASContext.js +2 -2
- package/build/ui/FEAASContext.js.map +1 -1
- package/build/ui/react.js +3 -1
- package/build/ui/react.js.map +1 -1
- package/dist/browser/headless.cjs +5 -5
- package/dist/browser/headless.cjs.map +4 -4
- package/dist/browser/headless.esm.js +5 -5
- package/dist/browser/headless.esm.js.map +1 -1
- package/dist/browser/index.cjs +5 -5
- package/dist/browser/index.cjs.map +4 -4
- package/dist/browser/index.esm.js +5 -5
- package/dist/browser/index.esm.js.map +1 -1
- package/dist/browser/react.cjs +5 -5
- package/dist/browser/react.cjs.map +4 -4
- package/dist/browser/react.esm.js +5 -5
- package/dist/browser/react.esm.js.map +1 -1
- package/dist/node/headless.cjs +3 -3
- package/dist/node/headless.cjs.map +4 -4
- package/dist/node/headless.esm.js +3 -3
- package/dist/node/headless.esm.js.map +4 -4
- package/dist/node/index.cjs +3 -3
- package/dist/node/index.cjs.map +4 -4
- package/dist/node/index.esm.js +3 -3
- package/dist/node/index.esm.js.map +4 -4
- package/dist/node/react.cjs +3 -3
- package/dist/node/react.cjs.map +4 -4
- package/dist/node/react.esm.js +3 -3
- package/dist/node/react.esm.js.map +4 -4
- package/headless.cjs +3 -3
- package/headless.cjs.map +4 -4
- package/headless.js +3 -3
- package/headless.js.map +4 -4
- package/package.json +1 -4
- package/react.cjs +5 -5
- package/react.cjs.map +4 -4
- package/react.js +5 -5
- package/react.js.map +4 -4
- package/scripts/build.js +1 -9
- package/src/dom/html.ts +322 -0
- package/src/dom/rendering.ts +5 -5
- package/src/dom/scripts.ts +3 -3
- package/src/ui/FEAASContext.tsx +2 -2
- package/src/ui/react.tsx +4 -1
- package/test/FEAASComponent.react.test.tsx +109 -0
- package/test/FEAASContext.test.tsx +2 -2
- package/test/dom.test.ts +48 -25
- package/types/dom/html.d.ts +45 -0
- package/types/dom/html.d.ts.map +1 -0
- package/types/dom/rendering.d.ts +1 -1
- package/types/dom/rendering.d.ts.map +1 -1
- package/types/tsbuildinfo +1 -1
- package/types/tsbuildinfo_ui +1 -1
- package/types/ui/react.d.ts +2 -0
- package/types/ui/react.d.ts.map +1 -1
package/scripts/build.js
CHANGED
|
@@ -16,15 +16,7 @@ function compile({ input, output, ...step }) {
|
|
|
16
16
|
outfile: path.resolve(__dirname, '../' + output),
|
|
17
17
|
bundle: true,
|
|
18
18
|
write: false,
|
|
19
|
-
external: [
|
|
20
|
-
'node:crypto',
|
|
21
|
-
'node-fetch',
|
|
22
|
-
'_MAGIC_IMPORT_COMMENTS_ESBUILD_WORKAROUND__',
|
|
23
|
-
'linkedom',
|
|
24
|
-
'react',
|
|
25
|
-
'react-dom',
|
|
26
|
-
'vm'
|
|
27
|
-
],
|
|
19
|
+
external: ['node:crypto', 'node-fetch', '_MAGIC_IMPORT_COMMENTS_ESBUILD_WORKAROUND__', 'react', 'react-dom', 'vm'],
|
|
28
20
|
|
|
29
21
|
...step,
|
|
30
22
|
|
package/src/dom/html.ts
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/** Lightweight DOM parser and serializer to use in server environments */
|
|
2
|
+
|
|
3
|
+
import { Datascopes } from './data.js'
|
|
4
|
+
import { FEAASCustomizations, renderDOMElement } from './rendering.js'
|
|
5
|
+
|
|
6
|
+
type HTMLAttribute = { name: string; value: string }
|
|
7
|
+
|
|
8
|
+
class HTMLNode {
|
|
9
|
+
nodeName: string
|
|
10
|
+
nodeType: number
|
|
11
|
+
textContent?: string
|
|
12
|
+
attributes: HTMLAttribute[]
|
|
13
|
+
childNodes: HTMLNode[]
|
|
14
|
+
parentNode?: HTMLNode
|
|
15
|
+
|
|
16
|
+
constructor(nodeName: string, nodeType: number = 1, textContent?: string) {
|
|
17
|
+
this.nodeName = nodeName
|
|
18
|
+
this.nodeType = nodeType
|
|
19
|
+
this.textContent = textContent
|
|
20
|
+
this.attributes = []
|
|
21
|
+
this.childNodes = []
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setAttribute(name: string, value: string) {
|
|
25
|
+
const attr = this.attributes.find((attr) => attr.name === name)
|
|
26
|
+
if (attr) {
|
|
27
|
+
attr.value = value
|
|
28
|
+
} else {
|
|
29
|
+
this.attributes.push({ name, value })
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getAttribute(name: string): string | undefined {
|
|
34
|
+
const attr = this.attributes.find((attr) => attr.name === name)
|
|
35
|
+
return attr ? attr.value : undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
insertBefore(newNode: HTMLNode, referenceNode: HTMLNode | null) {
|
|
39
|
+
newNode.parentNode = this
|
|
40
|
+
if (referenceNode === null) {
|
|
41
|
+
this.childNodes.push(newNode)
|
|
42
|
+
} else {
|
|
43
|
+
const index = this.childNodes.indexOf(referenceNode)
|
|
44
|
+
if (index !== -1) {
|
|
45
|
+
this.childNodes.splice(index, 0, newNode)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
removeAttribute(attrName: string) {
|
|
51
|
+
const index = this.attributes.findIndex((attr) => attr.name === attrName)
|
|
52
|
+
if (index !== -1) {
|
|
53
|
+
this.attributes.splice(index, 1)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
appendChild(newNode: HTMLNode) {
|
|
58
|
+
newNode.parentNode = this
|
|
59
|
+
this.childNodes.push(newNode)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get tagName() {
|
|
63
|
+
return this.nodeName?.toUpperCase()
|
|
64
|
+
}
|
|
65
|
+
get innerHTML() {
|
|
66
|
+
return serializeHTML(this.childNodes)
|
|
67
|
+
}
|
|
68
|
+
set innerHTML(html: string) {
|
|
69
|
+
this.childNodes = parseHTML(String(html ?? ''))
|
|
70
|
+
}
|
|
71
|
+
get outerHTML() {
|
|
72
|
+
return serializeHTML([this])
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
closest(selector: string): HTMLNode | null {
|
|
76
|
+
let currentNode: HTMLNode | undefined = this
|
|
77
|
+
|
|
78
|
+
while (currentNode) {
|
|
79
|
+
if (selectorMatchesNode(selector, currentNode)) {
|
|
80
|
+
return currentNode
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
currentNode = currentNode.parentNode
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
querySelectorAll(selector: string): HTMLNode[] {
|
|
90
|
+
const selectors = selector.split(/\s*,\s*/)
|
|
91
|
+
const results: HTMLNode[] = []
|
|
92
|
+
|
|
93
|
+
const checkNode = (node: HTMLNode) => {
|
|
94
|
+
for (const sel of selectors) {
|
|
95
|
+
if (selectorMatchesNode(sel, node)) {
|
|
96
|
+
results.push(node)
|
|
97
|
+
break
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const child of node.childNodes) {
|
|
102
|
+
checkNode(child)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const child of this.childNodes) {
|
|
107
|
+
checkNode(child)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return results
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
querySelector(selector: string): HTMLNode {
|
|
114
|
+
return this.querySelectorAll(selector)[0]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private findSibling(step: -1 | 1, elementTypeOnly?: boolean): HTMLNode | null {
|
|
118
|
+
if (!this.parentNode) return null
|
|
119
|
+
const siblings = this.parentNode.childNodes
|
|
120
|
+
const index = siblings.indexOf(this)
|
|
121
|
+
if (index === -1) return null
|
|
122
|
+
|
|
123
|
+
for (let i = index + step; i >= 0 && i < siblings.length; i += step) {
|
|
124
|
+
const sibling = siblings[i]
|
|
125
|
+
if (!elementTypeOnly || sibling.nodeType === 1) {
|
|
126
|
+
return sibling
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return null
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
removeChild(child: HTMLNode): HTMLNode {
|
|
134
|
+
const index = this.childNodes.indexOf(child)
|
|
135
|
+
if (index === -1) return
|
|
136
|
+
this.childNodes.splice(index, 1)
|
|
137
|
+
child.parentNode = undefined
|
|
138
|
+
return child
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get previousSibling(): HTMLNode | null {
|
|
142
|
+
return this.findSibling(-1)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
get nextSibling(): HTMLNode | null {
|
|
146
|
+
return this.findSibling(1)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
get previousElementSibling(): HTMLNode | null {
|
|
150
|
+
return this.findSibling(-1, true)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
get nextElementSibling(): HTMLNode | null {
|
|
154
|
+
return this.findSibling(1, true)
|
|
155
|
+
}
|
|
156
|
+
cloneNode(deep: boolean = false): HTMLNode {
|
|
157
|
+
const clonedNode = new HTMLNode(this.nodeName, this.nodeType)
|
|
158
|
+
clonedNode.attributes = JSON.parse(JSON.stringify(this.attributes))
|
|
159
|
+
|
|
160
|
+
if (this.textContent) {
|
|
161
|
+
clonedNode.textContent = this.textContent
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (deep) {
|
|
165
|
+
for (const childNode of this.childNodes) {
|
|
166
|
+
const clonedChild = childNode.cloneNode(true)
|
|
167
|
+
clonedNode.appendChild(clonedChild)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return clonedNode
|
|
172
|
+
}
|
|
173
|
+
get parentElement() {
|
|
174
|
+
return this.parentNode?.nodeType == 1 ? this.parentNode : null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
ownerDocument = {
|
|
178
|
+
createElement(name: string): HTMLNode {
|
|
179
|
+
return new HTMLNode(name)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function selectorMatchesNode(selector: string, node: HTMLNode): boolean {
|
|
185
|
+
const simpleSelectors = selector.match(/([.#]?[\w-]+|\[([\w-]+)(="([^"]*)")?\])/g)
|
|
186
|
+
if (!simpleSelectors) {
|
|
187
|
+
return false
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
for (const simpleSelector of simpleSelectors) {
|
|
191
|
+
if (simpleSelector.startsWith('#')) {
|
|
192
|
+
if (node.getAttribute('id') !== simpleSelector.slice(1)) {
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
} else if (simpleSelector.startsWith('.')) {
|
|
196
|
+
const classNames = (node.getAttribute('class') || '').split(' ')
|
|
197
|
+
if (!classNames.includes(simpleSelector.slice(1))) {
|
|
198
|
+
return false
|
|
199
|
+
}
|
|
200
|
+
} else if (simpleSelector.startsWith('[')) {
|
|
201
|
+
const attrSelectorMatch = simpleSelector.match(/^\[([\w-]+)(="([^"]*)")?\]$/)
|
|
202
|
+
if (attrSelectorMatch) {
|
|
203
|
+
const attrName = attrSelectorMatch[1]
|
|
204
|
+
const attrValue = attrSelectorMatch[3]
|
|
205
|
+
const actualValue = node.getAttribute(attrName)
|
|
206
|
+
|
|
207
|
+
if (typeof attrValue === 'undefined') {
|
|
208
|
+
if (actualValue === undefined) {
|
|
209
|
+
return false
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
if (actualValue !== attrValue) {
|
|
213
|
+
return false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
return false
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
if (node.nodeName !== simpleSelector) {
|
|
221
|
+
return false
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return true
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function parseHTML(html: string): HTMLNode[] {
|
|
230
|
+
const nodes: HTMLNode[] = []
|
|
231
|
+
const stack: HTMLNode[] = []
|
|
232
|
+
|
|
233
|
+
while (html) {
|
|
234
|
+
const openTagMatch = html.match(/^<([\w-]+)(\s[^>]*)?>/)
|
|
235
|
+
const closingTagMatch = html.match(/^<\/([\w-]+)>/)
|
|
236
|
+
|
|
237
|
+
if (openTagMatch) {
|
|
238
|
+
const nodeName = openTagMatch[1]
|
|
239
|
+
const attrsStr = openTagMatch[2] || ''
|
|
240
|
+
const attrs =
|
|
241
|
+
attrsStr.match(/([\w-]+)(="([^"]*)")?/g)?.map((attr) => {
|
|
242
|
+
const [_, name, , value] = attr.match(/([\w-]+)(="([^"]*)")?/)
|
|
243
|
+
return { name, value: unescapeHTML(value || '') }
|
|
244
|
+
}) || []
|
|
245
|
+
|
|
246
|
+
const node = new HTMLNode(nodeName, 1)
|
|
247
|
+
node.attributes = attrs
|
|
248
|
+
if (stack.length > 0) {
|
|
249
|
+
const parentNode = stack[stack.length - 1]
|
|
250
|
+
parentNode.childNodes.push(node)
|
|
251
|
+
node.parentNode = parentNode
|
|
252
|
+
} else {
|
|
253
|
+
nodes.push(node)
|
|
254
|
+
}
|
|
255
|
+
stack.push(node)
|
|
256
|
+
html = html.slice(openTagMatch[0].length)
|
|
257
|
+
} else if (closingTagMatch) {
|
|
258
|
+
stack.pop()
|
|
259
|
+
html = html.slice(closingTagMatch[0].length)
|
|
260
|
+
} else {
|
|
261
|
+
const textEnd = html.indexOf('<')
|
|
262
|
+
const textContent = html.slice(0, textEnd !== -1 ? textEnd : undefined)
|
|
263
|
+
const textNode = new HTMLNode('#text', 3)
|
|
264
|
+
textNode.textContent = textContent
|
|
265
|
+
if (stack.length > 0) {
|
|
266
|
+
const parentNode = stack[stack.length - 1]
|
|
267
|
+
parentNode.childNodes.push(textNode)
|
|
268
|
+
textNode.parentNode = parentNode
|
|
269
|
+
} else {
|
|
270
|
+
nodes.push(textNode)
|
|
271
|
+
}
|
|
272
|
+
html = html.slice(textContent.length)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return nodes
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function escapeHTML(input: string): string {
|
|
280
|
+
return input
|
|
281
|
+
.replace(/&/g, '&')
|
|
282
|
+
.replace(/</g, '<')
|
|
283
|
+
.replace(/>/g, '>')
|
|
284
|
+
.replace(/"/g, '"')
|
|
285
|
+
.replace(/'/g, ''')
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function unescapeHTML(input: string): string {
|
|
289
|
+
return input
|
|
290
|
+
.replace(/&/g, '&')
|
|
291
|
+
.replace(/</g, '<')
|
|
292
|
+
.replace(/>/g, '>')
|
|
293
|
+
.replace(/"/g, '"')
|
|
294
|
+
.replace(/'/g, "'")
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function serializeHTML(nodes: HTMLNode[]): string {
|
|
298
|
+
return nodes
|
|
299
|
+
.map((node) => {
|
|
300
|
+
if (node.nodeType === 3) {
|
|
301
|
+
return node.textContent || ''
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const { nodeName, attributes } = node
|
|
305
|
+
const serializedAttributes = attributes
|
|
306
|
+
.map(({ name, value }) => ` ${name}="${escapeHTML(String(value))}"`)
|
|
307
|
+
.join('')
|
|
308
|
+
const serializedChildren = serializeHTML(node.childNodes)
|
|
309
|
+
if (['img', 'input', 'br'].includes(nodeName)) {
|
|
310
|
+
return `<${nodeName}${serializedAttributes} />`
|
|
311
|
+
} else {
|
|
312
|
+
return `<${nodeName}${serializedAttributes}>${serializedChildren}</${nodeName}>`
|
|
313
|
+
}
|
|
314
|
+
})
|
|
315
|
+
.join('')
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function renderHTMLContent(template: string, data?: Datascopes, config?: FEAASCustomizations) {
|
|
319
|
+
const newTemplate = config?.processTemplate?.(null, template, data) || template
|
|
320
|
+
const nodes = parseHTML(newTemplate)
|
|
321
|
+
return renderDOMElement(nodes[0] as unknown as HTMLElement, data, config).outerHTML
|
|
322
|
+
}
|
package/src/dom/rendering.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FEAASCDNComponentProps } from '../cdn.js'
|
|
2
2
|
import { Datascopes, normalizeCollectionScope, queryScopes, serializeCH1RichText } from './data.js'
|
|
3
|
+
import { parseHTML } from './html.js'
|
|
3
4
|
import { loadScript } from './scripts.js'
|
|
4
5
|
|
|
5
6
|
export interface FEAASCustomizations {
|
|
@@ -14,7 +15,7 @@ export interface ExplicitTemplate {
|
|
|
14
15
|
template: string
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export type FEAASComponentProps<T = Datascopes> = {
|
|
18
|
+
export type FEAASComponentProps<T = Datascopes> = Partial<ExplicitTemplate> & {
|
|
18
19
|
data?: T
|
|
19
20
|
} & (ExplicitTemplate | FEAASCDNComponentProps) &
|
|
20
21
|
FEAASCustomizations
|
|
@@ -40,7 +41,7 @@ function updateDOMClones(element: HTMLElement, targetCount: number, config?: FEA
|
|
|
40
41
|
return
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
const parentElement = element.
|
|
44
|
+
const parentElement = element.parentNode as HTMLElement
|
|
44
45
|
if (parentElement == null) {
|
|
45
46
|
return
|
|
46
47
|
}
|
|
@@ -209,9 +210,8 @@ export function renderDOMContent(root: HTMLElement, template: string, data?: Dat
|
|
|
209
210
|
export function renderHTMLContent(template: string, data?: Datascopes, config?: FEAASCustomizations, fakeDOM = false) {
|
|
210
211
|
const newTemplate = config?.processTemplate?.(null, template, data) || template
|
|
211
212
|
if (typeof document === 'undefined' || fakeDOM) {
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
return renderDOMElement(document, data, config).toString()
|
|
213
|
+
const nodes = parseHTML(newTemplate)
|
|
214
|
+
return renderDOMElement(nodes[0] as unknown as HTMLElement, data, config).outerHTML
|
|
215
215
|
} else {
|
|
216
216
|
const root = document.createElement('div')
|
|
217
217
|
root.innerHTML = newTemplate
|
package/src/dom/scripts.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function autoloadScripts(element: HTMLElement, observe = true) {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export function loadScript(element: HTMLElement, src: string) {
|
|
31
|
-
for (var p = element; p; p = p.parentElement) {
|
|
31
|
+
for (var p = element; p; p = p.parentElement as HTMLElement) {
|
|
32
32
|
if (!p.parentElement) {
|
|
33
33
|
const scripts = p.querySelectorAll('script')
|
|
34
34
|
for (var i = 0; i < scripts.length; i++) {
|
|
@@ -38,8 +38,8 @@ export function loadScript(element: HTMLElement, src: string) {
|
|
|
38
38
|
}
|
|
39
39
|
if (p.tagName == 'HTML') p = p.querySelector('head') || p
|
|
40
40
|
const script = p.ownerDocument.createElement('script')
|
|
41
|
-
script.type
|
|
42
|
-
script.src
|
|
41
|
+
script.setAttribute('type', 'module')
|
|
42
|
+
script.setAttribute('src', src)
|
|
43
43
|
p.appendChild(script)
|
|
44
44
|
break
|
|
45
45
|
}
|
package/src/ui/FEAASContext.tsx
CHANGED
|
@@ -7,8 +7,8 @@ export function FEAASContextProps(element: HTMLElement = this) {
|
|
|
7
7
|
library: element?.getAttribute('library') as string,
|
|
8
8
|
src: element?.getAttribute('src') ?? '/context.js',
|
|
9
9
|
frontend: element?.getAttribute('frontend') ?? 'https://components.sitecoreclud.io',
|
|
10
|
-
backend: element?.getAttribute('backend') ?? 'https://components
|
|
11
|
-
cdn: element?.getAttribute('cdn') ?? 'https://
|
|
10
|
+
backend: element?.getAttribute('backend') ?? 'https://components.sitecoreclud.io/api',
|
|
11
|
+
cdn: element?.getAttribute('cdn') ?? 'https://feaas.blob.core.windows.net',
|
|
12
12
|
auth: null as Partial<AuthModel>,
|
|
13
13
|
isolate: element?.getAttribute('isolate') == null || element?.getAttribute('isolate') == 'true'
|
|
14
14
|
}
|
package/src/ui/react.tsx
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './index.js'
|
|
2
|
-
import { FEAASComponentProps, parseComponentSource
|
|
2
|
+
import { FEAASComponentProps, parseComponentSource } from './index.js'
|
|
3
3
|
import React from 'react'
|
|
4
|
+
import { renderHTMLContent } from '../dom/html.js'
|
|
5
|
+
export { renderHTMLContent }
|
|
4
6
|
|
|
5
7
|
export function FEAASEmbed({ data, ...props }: FEAASComponentProps<any>) {
|
|
6
8
|
if ('template' in props) {
|
|
@@ -21,4 +23,5 @@ export function FEAASEmbed({ data, ...props }: FEAASComponentProps<any>) {
|
|
|
21
23
|
/>
|
|
22
24
|
)
|
|
23
25
|
}
|
|
26
|
+
|
|
24
27
|
export const Component = FEAASEmbed
|
|
@@ -9,6 +9,7 @@ import React from 'react'
|
|
|
9
9
|
describe('React', () => {
|
|
10
10
|
it('render react component', () => {
|
|
11
11
|
const div = document.createElement('div')
|
|
12
|
+
document.body.appendChild(div)
|
|
12
13
|
const root = ReactDOM.render(
|
|
13
14
|
<section>
|
|
14
15
|
<Component src='library/test'></Component>
|
|
@@ -18,9 +19,22 @@ describe('React', () => {
|
|
|
18
19
|
expect(div.innerHTML).toEqual(
|
|
19
20
|
'<section><feaas-component library="library" component="test" src="library/test"></feaas-component></section>'
|
|
20
21
|
)
|
|
22
|
+
const div2 = document.createElement('div')
|
|
23
|
+
document.body.appendChild(div2)
|
|
24
|
+
div2.innerHTML = div.innerHTML
|
|
25
|
+
ReactDOM.hydrate(
|
|
26
|
+
<section>
|
|
27
|
+
<Component src='library/test'></Component>
|
|
28
|
+
</section>,
|
|
29
|
+
div2
|
|
30
|
+
)
|
|
31
|
+
expect(div2.innerHTML).toEqual(
|
|
32
|
+
'<section><feaas-component library="library" component="test" src="library/test"></feaas-component></section>'
|
|
33
|
+
)
|
|
21
34
|
})
|
|
22
35
|
it('render react component with src and overrides', () => {
|
|
23
36
|
const div = document.createElement('div')
|
|
37
|
+
document.body.appendChild(div)
|
|
24
38
|
const root = ReactDOM.render(
|
|
25
39
|
<section>
|
|
26
40
|
<Component src='library/test' component='test2'></Component>
|
|
@@ -30,9 +44,22 @@ describe('React', () => {
|
|
|
30
44
|
expect(div.innerHTML).toEqual(
|
|
31
45
|
'<section><feaas-component library="library" component="test2" src="library/test"></feaas-component></section>'
|
|
32
46
|
)
|
|
47
|
+
const div2 = document.createElement('div')
|
|
48
|
+
document.body.appendChild(div2)
|
|
49
|
+
div2.innerHTML = div.innerHTML
|
|
50
|
+
ReactDOM.hydrate(
|
|
51
|
+
<section>
|
|
52
|
+
<Component src='library/test' component='test2'></Component>
|
|
53
|
+
</section>,
|
|
54
|
+
div2
|
|
55
|
+
)
|
|
56
|
+
expect(div2.innerHTML).toEqual(
|
|
57
|
+
'<section><feaas-component library="library" component="test2" src="library/test"></feaas-component></section>'
|
|
58
|
+
)
|
|
33
59
|
})
|
|
34
60
|
it('render react component with extras', () => {
|
|
35
61
|
const div = document.createElement('div')
|
|
62
|
+
document.body.appendChild(div)
|
|
36
63
|
const root = ReactDOM.render(
|
|
37
64
|
<section>
|
|
38
65
|
<Component src='library/test' version='v1'></Component>
|
|
@@ -42,9 +69,22 @@ describe('React', () => {
|
|
|
42
69
|
expect(div.innerHTML).toEqual(
|
|
43
70
|
'<section><feaas-component library="library" component="test" version="v1" src="library/test"></feaas-component></section>'
|
|
44
71
|
)
|
|
72
|
+
const div2 = document.createElement('div')
|
|
73
|
+
document.body.appendChild(div2)
|
|
74
|
+
div2.innerHTML = div.innerHTML
|
|
75
|
+
ReactDOM.hydrate(
|
|
76
|
+
<section>
|
|
77
|
+
<Component src='library/test' version='v1'></Component>
|
|
78
|
+
</section>,
|
|
79
|
+
div2
|
|
80
|
+
)
|
|
81
|
+
expect(div2.innerHTML).toEqual(
|
|
82
|
+
'<section><feaas-component library="library" component="test" version="v1" src="library/test"></feaas-component></section>'
|
|
83
|
+
)
|
|
45
84
|
})
|
|
46
85
|
it('render react template', () => {
|
|
47
86
|
const div = document.createElement('div')
|
|
87
|
+
document.body.appendChild(div)
|
|
48
88
|
const root = ReactDOM.render(
|
|
49
89
|
<section>
|
|
50
90
|
<Component src='library/test' template={'<div data-path-src="abc">'}></Component>
|
|
@@ -54,9 +94,22 @@ describe('React', () => {
|
|
|
54
94
|
expect(div.innerHTML).toEqual(
|
|
55
95
|
'<section><feaas-component library="library" component="test" src="library/test"><div data-path-src="abc"></div></feaas-component></section>'
|
|
56
96
|
)
|
|
97
|
+
const div2 = document.createElement('div')
|
|
98
|
+
document.body.appendChild(div2)
|
|
99
|
+
div2.innerHTML = div.innerHTML
|
|
100
|
+
ReactDOM.hydrate(
|
|
101
|
+
<section>
|
|
102
|
+
<Component src='library/test' template={'<div data-path-src="abc">'}></Component>
|
|
103
|
+
</section>,
|
|
104
|
+
div2
|
|
105
|
+
)
|
|
106
|
+
expect(div2.innerHTML).toEqual(
|
|
107
|
+
'<section><feaas-component library="library" component="test" src="library/test"><div data-path-src="abc"></div></feaas-component></section>'
|
|
108
|
+
)
|
|
57
109
|
})
|
|
58
110
|
it('render template with data and src', () => {
|
|
59
111
|
const div = document.createElement('div')
|
|
112
|
+
document.body.appendChild(div)
|
|
60
113
|
const root = ReactDOM.render(
|
|
61
114
|
<section>
|
|
62
115
|
<Component src='library/test' template={'<div data-path-src="abc">'} data={{ abc: 321 }}></Component>
|
|
@@ -66,9 +119,22 @@ describe('React', () => {
|
|
|
66
119
|
expect(div.innerHTML).toEqual(
|
|
67
120
|
'<section><feaas-component library="library" component="test" src="library/test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
68
121
|
)
|
|
122
|
+
const div2 = document.createElement('div')
|
|
123
|
+
document.body.appendChild(div2)
|
|
124
|
+
div2.innerHTML = div.innerHTML
|
|
125
|
+
ReactDOM.hydrate(
|
|
126
|
+
<section>
|
|
127
|
+
<Component src='library/test' template={'<div data-path-src="abc">'} data={{ abc: 321 }}></Component>
|
|
128
|
+
</section>,
|
|
129
|
+
div2
|
|
130
|
+
)
|
|
131
|
+
expect(div2.innerHTML).toEqual(
|
|
132
|
+
'<section><feaas-component library="library" component="test" src="library/test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
133
|
+
)
|
|
69
134
|
})
|
|
70
135
|
it('render template with data but without src', () => {
|
|
71
136
|
const div = document.createElement('div')
|
|
137
|
+
document.body.appendChild(div)
|
|
72
138
|
const root = ReactDOM.render(
|
|
73
139
|
<section>
|
|
74
140
|
<Component
|
|
@@ -83,9 +149,27 @@ describe('React', () => {
|
|
|
83
149
|
expect(div.innerHTML).toEqual(
|
|
84
150
|
'<section><feaas-component library="library" component="test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
85
151
|
)
|
|
152
|
+
const div2 = document.createElement('div')
|
|
153
|
+
document.body.appendChild(div2)
|
|
154
|
+
div2.innerHTML = div.innerHTML
|
|
155
|
+
ReactDOM.hydrate(
|
|
156
|
+
<section>
|
|
157
|
+
<Component
|
|
158
|
+
library='library'
|
|
159
|
+
component='test'
|
|
160
|
+
template={'<div data-path-src="abc">'}
|
|
161
|
+
data={{ abc: 321 }}
|
|
162
|
+
></Component>
|
|
163
|
+
</section>,
|
|
164
|
+
div2
|
|
165
|
+
)
|
|
166
|
+
expect(div2.innerHTML).toEqual(
|
|
167
|
+
'<section><feaas-component library="library" component="test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
168
|
+
)
|
|
86
169
|
})
|
|
87
170
|
it('render template with data with src and stringy data', () => {
|
|
88
171
|
const div = document.createElement('div')
|
|
172
|
+
document.body.appendChild(div)
|
|
89
173
|
const root = ReactDOM.render(
|
|
90
174
|
<section>
|
|
91
175
|
<Component src='library/test' template={'<div data-path-src="abc">'} data={'{"abc":321}'}></Component>
|
|
@@ -95,9 +179,22 @@ describe('React', () => {
|
|
|
95
179
|
expect(div.innerHTML).toEqual(
|
|
96
180
|
'<section><feaas-component library="library" component="test" src="library/test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
97
181
|
)
|
|
182
|
+
const div2 = document.createElement('div')
|
|
183
|
+
document.body.appendChild(div2)
|
|
184
|
+
div2.innerHTML = div.innerHTML
|
|
185
|
+
ReactDOM.hydrate(
|
|
186
|
+
<section>
|
|
187
|
+
<Component src='library/test' template={'<div data-path-src="abc">'} data={'{"abc":321}'}></Component>
|
|
188
|
+
</section>,
|
|
189
|
+
div2
|
|
190
|
+
)
|
|
191
|
+
expect(div2.innerHTML).toEqual(
|
|
192
|
+
'<section><feaas-component library="library" component="test" src="library/test" data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
193
|
+
)
|
|
98
194
|
})
|
|
99
195
|
it('render template with data and template', () => {
|
|
100
196
|
const div = document.createElement('div')
|
|
197
|
+
document.body.appendChild(div)
|
|
101
198
|
const root = ReactDOM.render(
|
|
102
199
|
<section>
|
|
103
200
|
<Component template={'<div data-path-src="abc">'} data={'{"abc":321}'}></Component>
|
|
@@ -107,5 +204,17 @@ describe('React', () => {
|
|
|
107
204
|
expect(div.innerHTML).toEqual(
|
|
108
205
|
'<section><feaas-component data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
109
206
|
)
|
|
207
|
+
const div2 = document.createElement('div')
|
|
208
|
+
document.body.appendChild(div2)
|
|
209
|
+
div2.innerHTML = div.innerHTML
|
|
210
|
+
ReactDOM.hydrate(
|
|
211
|
+
<section>
|
|
212
|
+
<Component template={'<div data-path-src="abc">'} data={'{"abc":321}'}></Component>
|
|
213
|
+
</section>,
|
|
214
|
+
div2
|
|
215
|
+
)
|
|
216
|
+
expect(div2.innerHTML).toEqual(
|
|
217
|
+
'<section><feaas-component data="{"abc":321}"><div data-path-src="abc"></div></feaas-component></section>'
|
|
218
|
+
)
|
|
110
219
|
})
|
|
111
220
|
})
|
|
@@ -37,7 +37,7 @@ describe('React', function () {
|
|
|
37
37
|
expect(spyLoad).toHaveBeenCalledTimes(1)
|
|
38
38
|
|
|
39
39
|
expect(component.outerHTML).toBe(
|
|
40
|
-
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecoreclud.io" backend="https://components
|
|
40
|
+
'<feaas-context src="test.js" library="abc" isolate="false" frontend="https://components.sitecoreclud.io" backend="https://components.sitecoreclud.io/api" cdn="https://feaas.blob.core.windows.net"><div><p>Context abc</p></div></feaas-context>'
|
|
41
41
|
)
|
|
42
42
|
})
|
|
43
43
|
})
|
|
@@ -69,7 +69,7 @@ describe('React', function () {
|
|
|
69
69
|
expect(spyLoad).toHaveBeenCalledTimes(1)
|
|
70
70
|
|
|
71
71
|
expect(component.outerHTML).toBe(
|
|
72
|
-
'<feaas-context src="test.js" library="abc" frontend="https://components.sitecoreclud.io" backend="https://components
|
|
72
|
+
'<feaas-context src="test.js" library="abc" frontend="https://components.sitecoreclud.io" backend="https://components.sitecoreclud.io/api" cdn="https://feaas.blob.core.windows.net"></feaas-context>'
|
|
73
73
|
)
|
|
74
74
|
expect(component.shadowRoot.innerHTML).toBe('<div><p>Context abc</p></div>')
|
|
75
75
|
})
|