@sitecore-feaas/clientside 0.4.0-alpha.9 → 0.4.1

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.
Files changed (62) hide show
  1. package/README.md +2 -3
  2. package/build/components/FEAASComponent.js +22 -10
  3. package/build/components/FEAASComponent.js.map +1 -1
  4. package/build/components/FEAASElement.js +3 -3
  5. package/build/components/FEAASElement.js.map +1 -1
  6. package/build/dom/html.js +3 -2
  7. package/build/dom/html.js.map +1 -1
  8. package/build/ui/react.js +24 -9
  9. package/build/ui/react.js.map +1 -1
  10. package/build/utils/settings.js +6 -0
  11. package/build/utils/settings.js.map +1 -1
  12. package/dist/browser/headless.cjs +6 -6
  13. package/dist/browser/headless.cjs.map +3 -3
  14. package/dist/browser/headless.esm.js +6 -6
  15. package/dist/browser/headless.esm.js.map +1 -1
  16. package/dist/browser/index.cjs +5 -5
  17. package/dist/browser/index.cjs.map +3 -3
  18. package/dist/browser/index.esm.js +5 -5
  19. package/dist/browser/index.esm.js.map +1 -1
  20. package/dist/browser/react.cjs +7 -7
  21. package/dist/browser/react.cjs.map +4 -4
  22. package/dist/browser/react.esm.js +7 -7
  23. package/dist/browser/react.esm.js.map +1 -1
  24. package/dist/node/headless.cjs +4 -4
  25. package/dist/node/headless.cjs.map +3 -3
  26. package/dist/node/headless.esm.js +4 -4
  27. package/dist/node/headless.esm.js.map +3 -3
  28. package/dist/node/index.cjs +4 -4
  29. package/dist/node/index.cjs.map +3 -3
  30. package/dist/node/index.esm.js +4 -4
  31. package/dist/node/index.esm.js.map +3 -3
  32. package/dist/node/react.cjs +4 -4
  33. package/dist/node/react.cjs.map +4 -4
  34. package/dist/node/react.esm.js +4 -4
  35. package/dist/node/react.esm.js.map +4 -4
  36. package/headless.cjs +4 -4
  37. package/headless.cjs.map +3 -3
  38. package/headless.js +4 -4
  39. package/headless.js.map +3 -3
  40. package/package.json +3 -3
  41. package/react.cjs +7 -7
  42. package/react.cjs.map +4 -4
  43. package/react.js +7 -7
  44. package/react.js.map +4 -4
  45. package/scripts/build.js +10 -1
  46. package/scripts/test-setup.ts +0 -1
  47. package/src/components/FEAASComponent.tsx +29 -12
  48. package/src/components/FEAASElement.tsx +1 -1
  49. package/src/dom/html.ts +2 -2
  50. package/src/ui/react.tsx +33 -12
  51. package/src/utils/settings.ts +6 -0
  52. package/test/FEAASComponent.react.test.tsx +11 -11
  53. package/test/FEAASComponent.test.tsx +165 -13
  54. package/test/FEAASContext.test.tsx +1 -1
  55. package/test/ServerComponent.test.tsx +99 -15
  56. package/types/components/FEAASComponent.d.ts +5 -5
  57. package/types/components/FEAASComponent.d.ts.map +1 -1
  58. package/types/components/FEAASElement.d.ts.map +1 -1
  59. package/types/ui/react.d.ts +9 -4
  60. package/types/ui/react.d.ts.map +1 -1
  61. package/types/utils/settings.d.ts +7 -5
  62. package/types/utils/settings.d.ts.map +1 -1
package/scripts/build.js CHANGED
@@ -17,7 +17,16 @@ function compile({ input, output, ...step }) {
17
17
  outfile: path.resolve(__dirname, '../' + output),
18
18
  bundle: true,
19
19
  write: false,
20
- external: ['node:crypto', 'node-fetch', '_MAGIC_IMPORT_COMMENTS_ESBUILD_WORKAROUND__', 'react', 'react-dom', 'vm'],
20
+ external: [
21
+ 'node:crypto',
22
+ 'node-fetch',
23
+ '_MAGIC_IMPORT_COMMENTS_ESBUILD_WORKAROUND__',
24
+ 'react',
25
+ 'react-dom',
26
+ 'vm',
27
+ '@sitecore/byoc',
28
+ '@sitecore/byoc/react'
29
+ ],
21
30
  ...step,
22
31
 
23
32
  minify: true,
@@ -1,2 +1 @@
1
- process.env.TESTING = 'true'
2
1
  export default function () {}
@@ -24,6 +24,7 @@ export function FEAASComponentsProps(element: FEAASElement) {
24
24
  }
25
25
  }
26
26
 
27
+ const fetch = element.getAttribute('fetch')
27
28
  return {
28
29
  data: (data || {}) as DataOptions,
29
30
  cdn: element.getContextAttribute('cdn') ?? cdn ?? DEFAULT_CDN_URL,
@@ -37,7 +38,12 @@ export function FEAASComponentsProps(element: FEAASElement) {
37
38
  editable: element.getAttribute('editable') != null,
38
39
  suspended: element.getAttribute('suspended') != null,
39
40
  lastModified: element.getAttribute('last-modified'),
40
- withStylesheet: element.getAttribute('with-stylesheet') != 'false'
41
+ fetch:
42
+ fetch == 'false'
43
+ ? []
44
+ : fetch == null || fetch == 'true'
45
+ ? ['data', 'template', 'stylesheet']
46
+ : fetch.split(/(\s+|\-)+/g).filter(Boolean)
41
47
  }
42
48
  }
43
49
 
@@ -92,7 +98,6 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
92
98
  cdn: DEFAULT_CDN_URL,
93
99
  revision: 'published',
94
100
  version: 'responsive',
95
- withStylesheet: true,
96
101
  editable: false,
97
102
  suspended: false,
98
103
  data: {}
@@ -124,7 +129,7 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
124
129
 
125
130
  super.attributeChangedCallback(name, oldValue, newValue)
126
131
 
127
- if (name === 'data') {
132
+ if (name === 'data' && this.props.fetch.includes('data')) {
128
133
  this.fetchData()
129
134
  }
130
135
  }
@@ -202,7 +207,7 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
202
207
 
203
208
  const advanceIfEverythingIsReady = () => {
204
209
  // html is not loaded
205
- if (!this.payload) return
210
+ if (this.payload == null) return
206
211
 
207
212
  // shared stylesheet is still being loaded
208
213
  if (stylesheetPromise) return
@@ -213,20 +218,26 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
213
218
  this.onLoad(this.payload)
214
219
  }
215
220
 
216
- if (this.props.withStylesheet) {
221
+ if (this.props.fetch.includes('stylesheet')) {
217
222
  var stylesheetPromise = loadStylesheetAllowStale({ ...this.props }).then(() => {
218
223
  stylesheetPromise = null
219
224
  advanceIfEverythingIsReady()
220
225
  })
221
226
  }
222
227
 
223
- return Promise.all([
224
- stylesheetPromise,
225
- this.whenDataReady.then(() => advanceIfEverythingIsReady()),
226
- fetchAndRevalidateComponent(this.props, (html) => {
228
+ if (this.props.fetch.includes('template')) {
229
+ var templatePromise = fetchAndRevalidateComponent(this.props, (html) => {
227
230
  this.payload = html
228
231
  advanceIfEverythingIsReady()
229
232
  })
233
+ } else {
234
+ this.payload = this.props.template ?? this.innerHTML
235
+ }
236
+
237
+ return Promise.all([
238
+ stylesheetPromise,
239
+ this.whenDataReady.then(() => advanceIfEverythingIsReady()),
240
+ templatePromise
230
241
  ]).then(() => this.payload)
231
242
  }
232
243
 
@@ -240,7 +251,8 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
240
251
 
241
252
  update() {
242
253
  this.alreadyRendered = true
243
- if (this.getAttribute('hydrate') == 'false') return
254
+ // avoid unnecessary rendering if hydration was disabled
255
+ if (!this.props.fetch.includes('data') && !this.props.fetch.includes('template') && this.firstElementChild) return
244
256
  if (Array.from(this.children).filter((c) => c.tagName != 'BR').length > 0 && !this.needsRefresh) {
245
257
  renderDOMElement(this, this.readyData)
246
258
  } else {
@@ -254,6 +266,8 @@ export class FEAASComponent extends FEAASElement<FEAASComponentsProps, string> {
254
266
  }
255
267
  }
256
268
 
269
+ type FetchKeyword = 'data' | 'template' | 'stylesheet'
270
+
257
271
  declare global {
258
272
  namespace JSX {
259
273
  interface IntrinsicElements {
@@ -267,8 +281,11 @@ declare global {
267
281
  children?: any
268
282
  dangerouslySetInnerHTML?: { __html: string }
269
283
  'last-modified'?: string
270
- hydrate?: 'false' | 'true'
271
- 'with-stylesheet'?: 'false' | 'true' | ''
284
+ fetch?:
285
+ | `${FetchKeyword} ${FetchKeyword} ${FetchKeyword}`
286
+ | `${FetchKeyword} ${FetchKeyword}`
287
+ | `${FetchKeyword}`
288
+ | ''
272
289
  } & (
273
290
  | {
274
291
  /**
@@ -142,7 +142,6 @@ export class FEAASElement<Props = any, Payload = any> extends WebComponent {
142
142
  }
143
143
 
144
144
  log(...args: any) {
145
- if (typeof process != 'undefined' && process.env.TESTING) return
146
145
  const format = args[0]
147
146
 
148
147
  if (
@@ -412,6 +411,7 @@ export class FEAASElement<Props = any, Payload = any> extends WebComponent {
412
411
  const ErrorBoundary = this.getReactErrorBoundary()
413
412
  const Wrapper = this.getReactWrapper(target)
414
413
  return (
414
+ // @ts-ignore TS5 react types throws here
415
415
  <ErrorBoundary key={target.tagName + '-' + target.getUID()} slot={target.getAttribute('slot')}>
416
416
  <Wrapper />
417
417
  </ErrorBoundary>
package/src/dom/html.ts CHANGED
@@ -243,7 +243,7 @@ export function parseHTML(html: string): HTMLNode[] {
243
243
  const closingTagMatch = html.match(/^<\/([\w-]+)>/)
244
244
 
245
245
  if (openTagMatch) {
246
- const nodeName = openTagMatch[1]
246
+ const nodeName = openTagMatch[1].toLowerCase()
247
247
  const attrsStr = openTagMatch[2] || ''
248
248
  const attrs =
249
249
  attrsStr.match(/([\w-]+)(="([^"]*)")?/g)?.map((attr) => {
@@ -260,7 +260,7 @@ export function parseHTML(html: string): HTMLNode[] {
260
260
  } else {
261
261
  nodes.push(node)
262
262
  }
263
- stack.push(node)
263
+ if (!['img', 'input', 'br'].includes(nodeName)) stack.push(node)
264
264
  html = html.slice(openTagMatch[0].length)
265
265
  } else if (closingTagMatch) {
266
266
  stack.pop()
package/src/ui/react.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import React from 'react'
2
+ import * as BYOC from '@sitecore/byoc/react'
2
3
  import { HTMLNode, parseHTMLContent, renderHTMLContent } from '../dom/html.js'
3
4
  import { DataSettings } from '../utils/settings.js'
4
5
  import {
@@ -12,13 +13,21 @@ import {
12
13
  parseComponentSource,
13
14
  parseStylesheetSource
14
15
  } from './index.js'
15
- import * as BYOC from '@sitecore/byoc/react'
16
16
  export * from '../headless.js'
17
17
  export { External, FEAASExternalPropsObject, getComponent, linkComponents, registerComponent } from './FEAASExternal.js'
18
18
  export * from './index.js'
19
19
  export { renderHTMLContent }
20
20
 
21
+ type FEEASReactComponentFetch = string[] | string | null | undefined | boolean
22
+ export function normalizeFetchAttribute(fetch: FEEASReactComponentFetch) {
23
+ if (fetch == null || fetch === true) {
24
+ return ['template', 'stylesheet', 'data']
25
+ }
26
+ return [].concat(fetch || [])
27
+ }
28
+
21
29
  export type FEAASReactComponentProps = FEAASComponentProps & {
30
+ fetch?: FEEASReactComponentFetch
22
31
  preload?: boolean
23
32
  lastModified?: Date | string
24
33
  }
@@ -44,8 +53,9 @@ export const FEAASReactStylesheet = (props: FEAASCDNStylesheetParams | FEAASCDNS
44
53
  * @param {FEAASReactComponentProps} props - The properties for the component.
45
54
  * @returns {Promise<JSX.Element>} The JSX element representing the component.
46
55
  */
47
- export const FEAASReactServerComponent = async ({ ...props }: FEAASReactComponentProps) => {
48
- const fetchedData = await DataSettings.fetch(props?.data || {})
56
+ export const FEAASReactServerComponent = async ({ data, fetch, ...props }: FEAASReactComponentProps) => {
57
+ const fetchedData = await DataSettings.fetch(data || {})
58
+ fetch = normalizeFetchAttribute(fetch ?? ['stylesheet'])
49
59
 
50
60
  const p: FEAASReactComponentProps = { ...props }
51
61
 
@@ -54,13 +64,17 @@ export const FEAASReactServerComponent = async ({ ...props }: FEAASReactComponen
54
64
 
55
65
  p.template = response.template
56
66
  p.lastModified = response.lastModified
57
- //@ts-ignore
58
- p.hydrate = false
67
+ } else if (props?.template == null && !fetch.includes('template')) {
68
+ fetch.push('template')
59
69
  }
60
70
 
61
- return FEAASReactComponent({ ...p, data: fetchedData })
71
+ return FEAASReactComponent({
72
+ ...p,
73
+ data,
74
+ fetch,
75
+ fetchedData
76
+ })
62
77
  }
63
-
64
78
  /**
65
79
  * A wrapper over FEAAS.Component for use in React. It converts a passed template HTML into React,
66
80
  * allowing external components in the render tree. Data can be provided in JSON format.
@@ -68,12 +82,17 @@ export const FEAASReactServerComponent = async ({ ...props }: FEAASReactComponen
68
82
  * @param {FEAASReactComponentProps} props - The properties for the component.
69
83
  * @returns {JSX.Element} The JSX element representing the component.
70
84
  */
71
- export function FEAASReactComponent({ data, ...props }: FEAASReactComponentProps) {
85
+ export function FEAASReactComponent({
86
+ data,
87
+ lastModified,
88
+ fetchedData,
89
+ ...props
90
+ }: FEAASReactComponentProps & { fetchedData?: any }) {
72
91
  let preload = null
73
92
  let children: null | React.ReactNode
74
93
 
75
94
  if ('template' in props && props.template) {
76
- children = parseHTMLContent(props.template, data || {}).map((node, index) =>
95
+ children = parseHTMLContent(props.template, fetchedData || data || {}).map((node, index) =>
77
96
  HTMLNodeToReact(
78
97
  node,
79
98
  (node, attributes) => {
@@ -94,7 +113,8 @@ export function FEAASReactComponent({ data, ...props }: FEAASReactComponentProps
94
113
  if ('src' in props) {
95
114
  props = { ...parseComponentSource(props.src), ...props }
96
115
  }
97
-
116
+ const fetch = normalizeFetchAttribute(props.fetch)
117
+ const embeddedData = fetch.includes('data') ? data : fetch.includes('template') ? fetchedData : null
98
118
  return (
99
119
  <>
100
120
  {'preload' in props && preload === true && 'src' in props && (
@@ -106,10 +126,11 @@ export function FEAASReactComponent({ data, ...props }: FEAASReactComponentProps
106
126
  <feaas-component
107
127
  class='-feaas'
108
128
  {...props}
129
+ last-modified={lastModified ? String(lastModified) : null}
130
+ fetch={props.fetch == null ? props.fetch : ([].concat(props.fetch).join(' ') as any)}
109
131
  suppressHydrationWarning
110
132
  template={null}
111
- data={typeof data == 'string' ? data : data ? JSON.stringify(data) : null}
112
- hydrate={'false'}
133
+ data={typeof embeddedData == 'string' ? embeddedData : embeddedData ? JSON.stringify(embeddedData) : null}
113
134
  >
114
135
  {children}
115
136
  </feaas-component>
@@ -192,9 +192,15 @@ export async function fetchData(data: DataOptions): Promise<DataScopes> {
192
192
  )
193
193
  }
194
194
 
195
+ export async function hasDataSettings(data: DataOptions) {
196
+ if (!data) return false
197
+ return isDataSettings(data) || Object.values(data).some(isDataSettings)
198
+ }
199
+
195
200
  DataSettings.clean = clean
196
201
  DataSettings.toFetchArguments = toFetchArguments
197
202
  DataSettings.fetchOne = fetchDataSettings
198
203
  DataSettings.fetch = fetchData
199
204
  DataSettings.isDataSettings = isDataSettings
205
+ DataSettings.hasDataSettings = hasDataSettings
200
206
  DataSettings.fetchImplementation = (...args: Parameters<typeof fetch>) => fetch(...args)
@@ -53,7 +53,7 @@ describe('React', () => {
53
53
  <section>
54
54
  <Component src='library/test'></Component>
55
55
  </section>,
56
- '<section><feaas-component class="-feaas" library="library" component="test" src="library/test" hydrate="false"></feaas-component></section>'
56
+ '<section><feaas-component class="-feaas" library="library" component="test" src="library/test"></feaas-component></section>'
57
57
  )
58
58
  })
59
59
  it('render react with empty template', async () => {
@@ -61,7 +61,7 @@ describe('React', () => {
61
61
  <section>
62
62
  <Component src='library/test' template=''></Component>
63
63
  </section>,
64
- '<section><feaas-component class="-feaas" library="library" component="test" src="library/test" hydrate="false"></feaas-component></section>'
64
+ '<section><feaas-component class="-feaas" library="library" component="test" src="library/test"></feaas-component></section>'
65
65
  )
66
66
  })
67
67
  it('render react component with src and overrides', async () => {
@@ -69,7 +69,7 @@ describe('React', () => {
69
69
  <section>
70
70
  <Component src='library/test' component='test2'></Component>
71
71
  </section>,
72
- '<section><feaas-component class="-feaas" library="library" component="test2" src="library/test" hydrate="false"></feaas-component></section>'
72
+ '<section><feaas-component class="-feaas" library="library" component="test2" src="library/test"></feaas-component></section>'
73
73
  )
74
74
  })
75
75
  it('render react component with extras', async () => {
@@ -77,7 +77,7 @@ describe('React', () => {
77
77
  <section>
78
78
  <Component src='library/test' version='v1'></Component>
79
79
  </section>,
80
- '<section><feaas-component class="-feaas" library="library" component="test" version="v1" src="library/test" hydrate="false"></feaas-component></section>'
80
+ '<section><feaas-component class="-feaas" library="library" component="test" version="v1" src="library/test"></feaas-component></section>'
81
81
  )
82
82
  })
83
83
  it('render react template', async () => {
@@ -85,7 +85,7 @@ describe('React', () => {
85
85
  <section>
86
86
  <Component src='library/test' template={'<div data-path-src="abc">'}></Component>
87
87
  </section>,
88
- '<section><feaas-component class="-feaas" library="library" component="test" src="library/test" hydrate="false"><div data-path-src="abc"></div></feaas-component></section>'
88
+ '<section><feaas-component class="-feaas" library="library" component="test" src="library/test"><div data-path-src="abc"></div></feaas-component></section>'
89
89
  )
90
90
  })
91
91
  it('render template with data and src', async () => {
@@ -93,7 +93,7 @@ describe('React', () => {
93
93
  <section>
94
94
  <Component src='library/test' template={'<div data-path-src="abc">'} data={{ abc: 321 }}></Component>
95
95
  </section>,
96
- '<section><feaas-component class="-feaas" library="library" component="test" src="library/test" data="{&quot;abc&quot;:321}" hydrate="false"><div data-path-src="abc"></div></feaas-component></section>'
96
+ '<section><feaas-component class="-feaas" library="library" component="test" src="library/test" data="{&quot;abc&quot;:321}"><div data-path-src="abc"></div></feaas-component></section>'
97
97
  )
98
98
  })
99
99
  it('render template with data but without src', async () => {
@@ -106,7 +106,7 @@ describe('React', () => {
106
106
  data={{ abc: 321 }}
107
107
  ></Component>
108
108
  </section>,
109
- '<section><feaas-component class="-feaas" library="library" component="test" data="{&quot;abc&quot;:321}" hydrate="false"><div data-path-src="abc"></div></feaas-component></section>'
109
+ '<section><feaas-component class="-feaas" library="library" component="test" data="{&quot;abc&quot;:321}"><div data-path-src="abc"></div></feaas-component></section>'
110
110
  )
111
111
  })
112
112
  it('render template with style attribute', async () => {
@@ -114,7 +114,7 @@ describe('React', () => {
114
114
  <section>
115
115
  <Component template={'<div data-path-src="abc">'} data={{ abc: 321 }}></Component>
116
116
  </section>,
117
- '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}" hydrate="false"><div data-path-src="abc"></div></feaas-component></section>'
117
+ '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}"><div data-path-src="abc"></div></feaas-component></section>'
118
118
  )
119
119
  })
120
120
  it('render unwrapped external component with stringified values', async () => {
@@ -137,7 +137,7 @@ describe('React', () => {
137
137
  data={{ abc: 321 }}
138
138
  ></Component>
139
139
  </section>,
140
- '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}" hydrate="false"><feaas-external telephone="12345" first-name="Yarik" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 12345 (number). And context value is DEFAULT</div></feaas-external></feaas-component></section>'
140
+ '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}"><feaas-external telephone="12345" first-name="Yarik" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 12345 (number). And context value is DEFAULT</div></feaas-external></feaas-component></section>'
141
141
  )
142
142
  })
143
143
  it('render wrapped external component with context provider', async () => {
@@ -153,7 +153,7 @@ describe('React', () => {
153
153
  ></Component>
154
154
  </section>
155
155
  </DataContext.Provider>,
156
- '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}" hydrate="false"><feaas-external telephone="12345" first-name="Yarik" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 12345 (number). And context value is INHERITED</div></feaas-external></feaas-component></section>'
156
+ '<section><feaas-component class="-feaas" data="{&quot;abc&quot;:321}"><feaas-external telephone="12345" first-name="Yarik" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 12345 (number). And context value is INHERITED</div></feaas-external></feaas-component></section>'
157
157
  )
158
158
  })
159
159
  it('render wrapped external component with context provider and data mapping', async () => {
@@ -169,7 +169,7 @@ describe('React', () => {
169
169
  ></Component>
170
170
  </section>
171
171
  </DataContext.Provider>,
172
- '<section><feaas-component class="-feaas" data="{&quot;telephone&quot;:321}" hydrate="false"><feaas-external data-path-attributes="$" first-name="Yarik" telephone="321" data-attributes-keys="telephone" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 321 (number). And context value is INHERITED</div></feaas-external></feaas-component></section>'
172
+ '<section><feaas-component class="-feaas" data="{&quot;telephone&quot;:321}"><feaas-external data-path-attributes="$" first-name="Yarik" telephone="321" data-attributes-keys="telephone" data-external-id="MyTestComponent" hydrate="false"><div>Hello my name is Yarik (string) and my tel is 321 (number). And context value is INHERITED</div></feaas-external></feaas-component></section>'
173
173
  )
174
174
  })
175
175
  })
@@ -36,7 +36,7 @@ describe('Components', () => {
36
36
 
37
37
  // Fixme юhange to production component
38
38
  document.body.innerHTML =
39
- '<feaas-component with-stylesheet="false" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
39
+ '<feaas-component fetch="template data" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
40
40
 
41
41
  const component = document.body.firstElementChild as FEAASComponent
42
42
 
@@ -46,6 +46,164 @@ describe('Components', () => {
46
46
  expect(component.innerHTML).toContain('TODAY')
47
47
  })
48
48
 
49
+ describe('fetch control', () => {
50
+ it('should not make requests when hydration is turned off', async () => {
51
+ const spy = vi.spyOn(global, 'fetch')
52
+
53
+ // Fixme юhange to production component
54
+ document.body.innerHTML =
55
+ '<feaas-component fetch="" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
56
+
57
+ const component = document.body.firstElementChild as FEAASComponent
58
+
59
+ await expect(component.whenRendered).resolves.toEqual(component)
60
+ expect(spy).toHaveBeenCalledTimes(0)
61
+
62
+ expect(component.innerHTML).toBe('')
63
+ })
64
+
65
+ it('should not make requests when hydration is turned off, but should render template', async () => {
66
+ const spy = vi.spyOn(global, 'fetch')
67
+
68
+ // Fixme юhange to production component
69
+ document.body.innerHTML =
70
+ '<feaas-component fetch="" library="L" cdn="CDN" component="C" version="V" revision="R" template="abc"></feaas-component>'
71
+
72
+ const component = document.body.firstElementChild as FEAASComponent
73
+
74
+ await expect(component.whenRendered).resolves.toEqual(component)
75
+ expect(spy).toHaveBeenCalledTimes(0)
76
+
77
+ expect(component.innerHTML).toBe('abc')
78
+ })
79
+
80
+ it('should only make css request with fetch="stylesheet"', async () => {
81
+ const spy = vi.spyOn(global, 'fetch')
82
+ spy.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
83
+ if (url.match('.css')) {
84
+ return new Response('{}', {
85
+ headers: {
86
+ date: now.toUTCString(),
87
+ 'last-modified': earlier.toUTCString()
88
+ }
89
+ })
90
+ }
91
+ })
92
+ // Fixme юhange to production component
93
+ document.body.innerHTML =
94
+ '<feaas-component fetch="stylesheet" library="L" cdn="CDN" component="C" version="V" revision="R">abc</feaas-component>'
95
+
96
+ const component = document.body.firstElementChild as FEAASComponent
97
+
98
+ await expect(component.whenRendered).resolves.toEqual(component)
99
+ expect(spy).toHaveBeenCalledTimes(1)
100
+ expect(component.innerHTML).toBe('abc')
101
+ expect(document.head.querySelectorAll('style').length).toEqual(1)
102
+ })
103
+
104
+ it('should make html/css requests when fetch="stylesheet template"', async () => {
105
+ const spy = vi.spyOn(global, 'fetch')
106
+ spy.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
107
+ if (url.match('CDN/components/L/C/V/R')) {
108
+ return new Response('TODAY', {
109
+ headers: {
110
+ date: now.toUTCString(),
111
+ 'last-modified': earlier.toUTCString()
112
+ }
113
+ })
114
+ }
115
+ if (url.match('.css')) {
116
+ return new Response('{}', {
117
+ headers: {
118
+ date: now.toUTCString(),
119
+ 'last-modified': earlier.toUTCString()
120
+ }
121
+ })
122
+ }
123
+ })
124
+ document.body.innerHTML =
125
+ '<feaas-component fetch="stylesheet template" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
126
+
127
+ const component = document.body.firstElementChild as FEAASComponent
128
+
129
+ await expect(component.whenRendered).resolves.toEqual(component)
130
+ expect(spy).toHaveBeenCalledTimes(2)
131
+ expect(component.innerHTML).toBe('TODAY')
132
+ expect(document.head.querySelectorAll('style').length).toEqual(1)
133
+ })
134
+ it('should make data/css requests when fetch="stylesheet data"', async () => {
135
+ const spy = vi.spyOn(global, 'fetch')
136
+ spy.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
137
+ if (url.match('my.json')) {
138
+ return new Response('{"path": "value"}', {
139
+ headers: {
140
+ date: now.toUTCString(),
141
+ 'last-modified': earlier.toUTCString()
142
+ }
143
+ })
144
+ }
145
+ if (url.match('.css')) {
146
+ return new Response('{}', {
147
+ headers: {
148
+ date: now.toUTCString(),
149
+ 'last-modified': earlier.toUTCString()
150
+ }
151
+ })
152
+ }
153
+ })
154
+
155
+ document.body.innerHTML =
156
+ '<feaas-component fetch="stylesheet data" data=\'{"source": {"url": "my.json"}}\' library="L" cdn="CDN" component="C" version="V" revision="R"><var data-path="source.path"></var></feaas-component>'
157
+
158
+ const component = document.body.firstElementChild as FEAASComponent
159
+
160
+ await expect(component.whenRendered).resolves.toEqual(component)
161
+ expect(spy).toHaveBeenCalledTimes(2)
162
+ expect(component.innerHTML).toBe('<var data-path="source.path">value</var>')
163
+ expect(document.head.querySelectorAll('style').length).toEqual(1)
164
+ })
165
+
166
+ it('should make data/css/html requests when fetch="template stylesheet data"', async () => {
167
+ const spy = vi.spyOn(global, 'fetch')
168
+ spy.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
169
+ if (url.match('.html')) {
170
+ return new Response('<var data-path="source.path"></var>', {
171
+ headers: {
172
+ date: now.toUTCString(),
173
+ 'last-modified': earlier.toUTCString()
174
+ }
175
+ })
176
+ }
177
+ if (url.match('my.json')) {
178
+ return new Response('{"path": "value"}', {
179
+ headers: {
180
+ date: now.toUTCString(),
181
+ 'last-modified': earlier.toUTCString()
182
+ }
183
+ })
184
+ }
185
+ if (url.match('.css')) {
186
+ return new Response('{}', {
187
+ headers: {
188
+ date: now.toUTCString(),
189
+ 'last-modified': earlier.toUTCString()
190
+ }
191
+ })
192
+ }
193
+ })
194
+
195
+ document.body.innerHTML =
196
+ '<feaas-component fetch="template stylesheet data" data=\'{"source": {"url": "my.json"}}\' library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
197
+
198
+ const component = document.body.firstElementChild as FEAASComponent
199
+
200
+ await expect(component.whenRendered).resolves.toEqual(component)
201
+ expect(spy).toHaveBeenCalledTimes(3)
202
+ expect(component.innerHTML).toBe('<var data-path="source.path">value</var>')
203
+ expect(document.head.querySelectorAll('style').length).toEqual(1)
204
+ })
205
+ })
206
+
49
207
  it('should load component using src attribute shorthand', async () => {
50
208
  const spy = vi.spyOn(global, 'fetch')
51
209
  spy.mockImplementation(async (url: string, options: Parameters<typeof fetch>[1] = {}) => {
@@ -59,9 +217,8 @@ describe('Components', () => {
59
217
  }
60
218
  })
61
219
 
62
- // Fixme change to production component
63
220
  document.body.innerHTML =
64
- '<feaas-component with-stylesheet="false" src="http://a/components/b/c/d/1.html"></feaas-component>'
221
+ '<feaas-component fetch="template data" src="http://a/components/b/c/d/1.html"></feaas-component>'
65
222
 
66
223
  const component = document.body.firstElementChild as FEAASComponent
67
224
 
@@ -69,7 +226,7 @@ describe('Components', () => {
69
226
  expect(spy).toHaveBeenCalledTimes(1)
70
227
 
71
228
  expect(component.outerHTML).toBe(
72
- `<feaas-component with-stylesheet="false" src="http://a/components/b/c/d/1.html" cdn="http://a" library="b" component="c" version="d" revision="1" class="-feaas">TODAY</feaas-component>`
229
+ `<feaas-component fetch="template data" src="http://a/components/b/c/d/1.html" cdn="http://a" library="b" component="c" version="d" revision="1" class="-feaas">TODAY</feaas-component>`
73
230
  )
74
231
  })
75
232
 
@@ -94,7 +251,6 @@ describe('Components', () => {
94
251
  }
95
252
  })
96
253
 
97
- // Fixme change to production component
98
254
  document.body.innerHTML =
99
255
  '<feaas-component src="http://a/components/b/c/d/1.html"></feaas-component><feaas-component src="http://a/components/b/c/d/staged.html"></feaas-component>'
100
256
 
@@ -117,7 +273,6 @@ describe('Components', () => {
117
273
  }
118
274
  })
119
275
 
120
- // Fixme change to production component
121
276
  document.body.innerHTML =
122
277
  '<feaas-component src="http://a/components/b/c/d/1.html"></feaas-component><link rel="stylesheet" href="http://a/styles/b/published.css" />'
123
278
 
@@ -148,9 +303,8 @@ describe('Components', () => {
148
303
  }
149
304
  })
150
305
 
151
- // Fixme change to production component
152
306
  document.body.innerHTML =
153
- '<feaas-component with-stylesheet="false" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
307
+ '<feaas-component fetch="template data" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
154
308
 
155
309
  const component = document.body.firstElementChild as FEAASComponent
156
310
 
@@ -190,9 +344,8 @@ describe('Components', () => {
190
344
  }
191
345
  })
192
346
 
193
- // Fixme change to production component
194
347
  document.body.innerHTML =
195
- '<feaas-component with-stylesheet="false" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
348
+ '<feaas-component fetch="template data" library="L" cdn="CDN" component="C" version="V" revision="R"></feaas-component>'
196
349
 
197
350
  const component = document.body.firstElementChild as FEAASComponent
198
351
  // Renders cached version initially
@@ -226,9 +379,8 @@ describe('Components', () => {
226
379
  }
227
380
  })
228
381
 
229
- // Fixme change to production component
230
382
  document.body.innerHTML =
231
- '<feaas-component with-stylesheet="false" library="L" cdn="CDN" component="C1" version="V" revision="R"></feaas-component>'
383
+ '<feaas-component fetch="template data" library="L" cdn="CDN" component="C1" version="V" revision="R"></feaas-component>'
232
384
 
233
385
  const component = document.body.firstElementChild as FEAASComponent
234
386
  await expect(component.whenRendered).resolves.toEqual(component)
@@ -302,7 +454,7 @@ describe('Components', () => {
302
454
  }
303
455
  }
304
456
  })
305
- // Fixme change to production component
457
+
306
458
  document.body.innerHTML = '<feaas-component src="L/C"></feaas-component>'
307
459
  const component = document.body.firstElementChild as FEAASComponent
308
460
  expect(document.head.querySelector('style')).toBeNull()
@@ -154,7 +154,7 @@ describe('React', function () {
154
154
  it('should nest components into context', async () => {
155
155
  const renders = [] as FEAASElement[]
156
156
  class FEAASElementTestRenderOrder extends FEAASElement {
157
- render(props: any, payload: any): ReactNode | ReactElement<any, string | JSXElementConstructor<any>> {
157
+ render(props: any, payload: any): ReactNode {
158
158
  return null
159
159
  }
160
160
  load() {