@sitecore-feaas/clientside 0.1.47 → 0.1.49

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 (54) hide show
  1. package/build/components/FEAASExternal.js +79 -0
  2. package/build/components/FEAASExternal.js.map +1 -0
  3. package/build/headless.js +1 -0
  4. package/build/headless.js.map +1 -1
  5. package/build/ui/react.js +1 -1
  6. package/build/ui/react.js.map +1 -1
  7. package/build/utils/string.js +13 -0
  8. package/build/utils/string.js.map +1 -0
  9. package/dist/browser/headless.cjs +5 -5
  10. package/dist/browser/headless.cjs.map +4 -4
  11. package/dist/browser/headless.esm.js +5 -5
  12. package/dist/browser/headless.esm.js.map +1 -1
  13. package/dist/browser/index.cjs +5 -5
  14. package/dist/browser/index.cjs.map +4 -4
  15. package/dist/browser/index.esm.js +5 -5
  16. package/dist/browser/index.esm.js.map +1 -1
  17. package/dist/browser/react.cjs +5 -5
  18. package/dist/browser/react.cjs.map +4 -4
  19. package/dist/browser/react.esm.js +5 -5
  20. package/dist/browser/react.esm.js.map +1 -1
  21. package/dist/node/headless.cjs +3 -3
  22. package/dist/node/headless.cjs.map +4 -4
  23. package/dist/node/headless.esm.js +3 -3
  24. package/dist/node/headless.esm.js.map +4 -4
  25. package/dist/node/index.cjs +3 -3
  26. package/dist/node/index.cjs.map +4 -4
  27. package/dist/node/index.esm.js +3 -3
  28. package/dist/node/index.esm.js.map +4 -4
  29. package/dist/node/react.cjs +3 -3
  30. package/dist/node/react.cjs.map +4 -4
  31. package/dist/node/react.esm.js +3 -3
  32. package/dist/node/react.esm.js.map +4 -4
  33. package/headless.cjs +3 -3
  34. package/headless.cjs.map +4 -4
  35. package/headless.js +3 -3
  36. package/headless.js.map +4 -4
  37. package/package.json +1 -1
  38. package/react.cjs +5 -5
  39. package/react.cjs.map +4 -4
  40. package/react.js +5 -5
  41. package/react.js.map +4 -4
  42. package/src/components/FEAASExternal.tsx +107 -0
  43. package/src/headless.ts +1 -0
  44. package/src/ui/react.tsx +1 -1
  45. package/src/utils/string.ts +12 -0
  46. package/test/FEAASExternal.test.tsx +49 -0
  47. package/types/components/FEAASExternal.d.ts +44 -0
  48. package/types/components/FEAASExternal.d.ts.map +1 -0
  49. package/types/headless.d.ts +1 -0
  50. package/types/headless.d.ts.map +1 -1
  51. package/types/tsbuildinfo +1 -1
  52. package/types/tsbuildinfo_ui +1 -1
  53. package/types/utils/string.d.ts +3 -0
  54. package/types/utils/string.d.ts.map +1 -0
@@ -0,0 +1,107 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom'
3
+ import { FEAASBase } from './FEAASBase.js'
4
+ import { ReactJSX, ReactModules } from './FEAASElement.js'
5
+ import { kebabCase, reverseKebabCase } from '../utils/string.js'
6
+
7
+ const convertSchemaPropertiesToKebabCase = (schema: any) => {
8
+ if (!schema) return
9
+
10
+ let kebabSchemaProperties, kebabRequiredProperties
11
+ if (schema.properties) {
12
+ kebabSchemaProperties = Object.keys(schema.properties).reduce((acc: { [key: string]: string }, key) => {
13
+ acc[kebabCase(key)] = schema.properties[key]
14
+ return acc
15
+ }, {})
16
+
17
+ kebabRequiredProperties = schema.required.map((item: string) => kebabCase(item))
18
+ }
19
+ return { ...schema, properties: kebabSchemaProperties, required: kebabRequiredProperties }
20
+ }
21
+
22
+ export function FEAASExternalProps(element: FEAASBase = this) {
23
+ const attributes = element.getAttributeNames()
24
+ const props = attributes.reduce((prev, curr) => {
25
+ if (!curr.startsWith('data-attribute') && !['class', 'id', 'contenteditable'].includes(curr))
26
+ return { ...prev, [reverseKebabCase(curr)]: element.getAttribute(curr) }
27
+ else return prev
28
+ }, {})
29
+ return props
30
+ }
31
+
32
+ export type RegisteredComponents = { [id: string]: { component: React.ElementType; schema: any } }
33
+ export type FEAASExternalProps = ReturnType<typeof FEAASExternalProps> & { dataExternalId: string }
34
+
35
+ export default class FEAASExternal extends FEAASBase<FEAASExternalProps, ReactModules> {
36
+ static registered: RegisteredComponents = {}
37
+ static registrationCallback: NodeJS.Timeout
38
+ load() {
39
+ return Promise.resolve({ React, ReactDOM })
40
+ }
41
+
42
+ render(props: FEAASExternalProps, { React }: ReactModules): ReactJSX {
43
+ const { dataExternalId: id } = props
44
+ const Component = FEAASExternal.registered[id]?.component
45
+ if (!Component) console.warn('FEAASExternal: The component you requested is not registered')
46
+ return <>{Component && <Component {...props} />}</>
47
+ }
48
+
49
+ getProps() {
50
+ return FEAASExternalProps(this)
51
+ }
52
+
53
+ static registerComponent(component: React.FC, schema: any = {}, id?: string) {
54
+ FEAASExternal.registered[id || component.name] = { component, schema }
55
+ }
56
+
57
+ static setRegistrationCallback() {
58
+ // if registerCallback has not already been triggered by another component, set it
59
+ if (!FEAASExternal.registrationCallback) {
60
+ FEAASExternal.registrationCallback = setTimeout(() => {
61
+ // create components array from object
62
+ const components = Object.keys(FEAASExternal.registered).map((name) => ({
63
+ ...FEAASExternal.registered[name],
64
+ name,
65
+ schema: convertSchemaPropertiesToKebabCase(FEAASExternal.registered[name].schema),
66
+ component: FEAASExternal.registered[name].component.toString()
67
+ }))
68
+ // send components from iframe to parent window
69
+ window.parent.postMessage(
70
+ JSON.stringify({
71
+ action: 'register-components',
72
+ data: components
73
+ }),
74
+ '*'
75
+ )
76
+ }, 500)
77
+ }
78
+ }
79
+
80
+ static loadComponents() {
81
+ const components = JSON.parse(sessionStorage.getItem('feaas-external-components'))
82
+ components.forEach((c: { name: string; schema: any; component: React.FC }) => {
83
+ const name = c.name
84
+ const schema = c.schema
85
+ const component = eval('(' + c.component + ')')
86
+ FEAASExternal.registerComponent(component, schema, name)
87
+ })
88
+ }
89
+ }
90
+
91
+ declare global {
92
+ namespace JSX {
93
+ interface IntrinsicElements {
94
+ 'feaas-external': {
95
+ 'data-external-id': string
96
+ children?: any
97
+ dangerouslySetInnerHTML?: { __html: string }
98
+ [key: string]: any
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ FEAASExternal.register('feaas-external')
105
+ FEAASExternal.setRegistrationCallback()
106
+
107
+ export { FEAASExternal as External }
package/src/headless.ts CHANGED
@@ -17,6 +17,7 @@ export * from './components/FEAASElement.js'
17
17
  export * from './components/FEAASComponent.js'
18
18
  export * from './components/FEAASLoader.js'
19
19
  export * from './components/FEAASStylesheet.js'
20
+ export * from './components/FEAASExternal.js'
20
21
 
21
22
  declare global {
22
23
  interface Window {
package/src/ui/react.tsx CHANGED
@@ -5,7 +5,7 @@ import { renderHTMLContent } from '../dom/html.js'
5
5
  export { renderHTMLContent }
6
6
 
7
7
  export function FEAASEmbed({ data, ...props }: FEAASComponentProps<any>) {
8
- if ('template' in props) {
8
+ if ('template' in props && typeof props.template == 'string') {
9
9
  var html = renderHTMLContent(props.template, data || {})
10
10
  }
11
11
  if ('src' in props) {
@@ -0,0 +1,12 @@
1
+ export function kebabCase(str: string) {
2
+ const KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g
3
+ return str.replace(KEBAB_REGEX, function (match) {
4
+ return '-' + match.toLowerCase()
5
+ })
6
+ }
7
+ export function reverseKebabCase(str: string) {
8
+ const REVERSE_KEBAB_REGEX = /-[a-z\u00E0-\u00F6\u00F8-\u00FE]/g
9
+ return str.replace(REVERSE_KEBAB_REGEX, function (match) {
10
+ return match.slice(1).toUpperCase()
11
+ })
12
+ }
@@ -0,0 +1,49 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest'
2
+ import React from 'react'
3
+ import * as Clientside from '@sitecore-feaas/clientside/react'
4
+ import FEAASExternal from '../types/components/FEAASExternal.js'
5
+
6
+ describe('External', () => {
7
+ function Hello(props: { firstName: string; telephone: string }) {
8
+ return React.createElement('div', {}, `Hello my name is ${props.firstName} and my tel is ${props.telephone}`)
9
+ }
10
+ function Hello2(props: { firstName: string; address: string }) {
11
+ return React.createElement('div', {}, `Hello my name is ${props.firstName} and my address is ${props.address}`)
12
+ }
13
+ it('can register and render component', async () => {
14
+ Clientside.External.registerComponent(Hello, {}, 'MyTestComponent')
15
+ document.body.innerHTML =
16
+ '<feaas-external id="external-component" class="-component" data-attributes-keys="first-name,telephone" first-name="Chuck" telephone="45657890875643" data-attributes="{&quot;first-name&quot;:&quot;Chuck&quot;,&quot;telephone&quot;:&quot;45657890875643&quot;}" data-external-id="MyTestComponent" contenteditable="false"></feaas-external>'
17
+ const component = document.getElementById('external-component') as FEAASExternal
18
+ await expect(component.whenRendered).resolves.toEqual(component)
19
+ expect(component.innerHTML).toEqual('<div>Hello my name is Chuck and my tel is 45657890875643</div>')
20
+ })
21
+ it('can take functional component name as id', async () => {
22
+ Clientside.External.registerComponent(Hello)
23
+ document.body.innerHTML =
24
+ '<feaas-external id="external-component" class="-component" data-attributes-keys="first-name,telephone" first-name="Chuck" telephone="45657890875643" data-attributes="{&quot;first-name&quot;:&quot;Chuck&quot;,&quot;telephone&quot;:&quot;45657890875643&quot;}" data-external-id="Hello" contenteditable="false"></feaas-external>'
25
+ const component = document.getElementById('external-component') as FEAASExternal
26
+ await expect(component.whenRendered).resolves.toEqual(component)
27
+ expect(component.innerHTML).toEqual('<div>Hello my name is Chuck and my tel is 45657890875643</div>')
28
+ })
29
+ it('should return empty if component is not registered', async () => {
30
+ document.body.innerHTML =
31
+ '<feaas-external id="external-component" class="-component" data-external-id="NotRegisteredComponent" contenteditable="false"></feaas-external>'
32
+ const component = document.getElementById('external-component') as FEAASExternal
33
+ await expect(component.whenRendered).resolves.toEqual(component)
34
+ expect(component.innerHTML).toEqual('')
35
+ })
36
+ it('can register and render multiple components', async () => {
37
+ Clientside.External.registerComponent(Hello, {}, 'MyTestComponent1')
38
+ Clientside.External.registerComponent(Hello2, {}, 'MyTestComponent2')
39
+ document.body.innerHTML =
40
+ '<feaas-external id="external-component1" class="-component" data-attributes-keys="first-name,telephone" first-name="Chuck" telephone="45657890875643" data-attributes="{&quot;first-name&quot;:&quot;Chuck&quot;,&quot;telephone&quot;:&quot;45657890875643&quot;}" data-external-id="MyTestComponent1" contenteditable="false"></feaas-external>' +
41
+ '<feaas-external id="external-component2" class="-component" data-attributes-keys="first-name,address" first-name="George" address="Test street 12" data-attributes="{&quot;first-name&quot;:&quot;George&quot;,&quot;address&quot;:&quot;Test street 12&quot;}" data-external-id="MyTestComponent2" contenteditable="false"></feaas-external>'
42
+ const component1 = document.getElementById('external-component1') as FEAASExternal
43
+ await expect(component1.whenRendered).resolves.toEqual(component1)
44
+ expect(component1.innerHTML).toEqual('<div>Hello my name is Chuck and my tel is 45657890875643</div>')
45
+ const component2 = document.getElementById('external-component2') as FEAASExternal
46
+ await expect(component2.whenRendered).resolves.toEqual(component2)
47
+ expect(component2.innerHTML).toEqual('<div>Hello my name is George and my address is Test street 12</div>')
48
+ })
49
+ })
@@ -0,0 +1,44 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import React from 'react';
3
+ import ReactDOM from 'react-dom';
4
+ import { FEAASBase } from './FEAASBase.js';
5
+ import { ReactJSX, ReactModules } from './FEAASElement.js';
6
+ export declare function FEAASExternalProps(element?: FEAASBase): {};
7
+ export type RegisteredComponents = {
8
+ [id: string]: {
9
+ component: React.ElementType;
10
+ schema: any;
11
+ };
12
+ };
13
+ export type FEAASExternalProps = ReturnType<typeof FEAASExternalProps> & {
14
+ dataExternalId: string;
15
+ };
16
+ export default class FEAASExternal extends FEAASBase<FEAASExternalProps, ReactModules> {
17
+ static registered: RegisteredComponents;
18
+ static registrationCallback: NodeJS.Timeout;
19
+ load(): Promise<{
20
+ React: typeof React;
21
+ ReactDOM: typeof ReactDOM;
22
+ }>;
23
+ render(props: FEAASExternalProps, { React }: ReactModules): ReactJSX;
24
+ getProps(): {};
25
+ static registerComponent(component: React.FC, schema?: any, id?: string): void;
26
+ static setRegistrationCallback(): void;
27
+ static loadComponents(): void;
28
+ }
29
+ declare global {
30
+ namespace JSX {
31
+ interface IntrinsicElements {
32
+ 'feaas-external': {
33
+ 'data-external-id': string;
34
+ children?: any;
35
+ dangerouslySetInnerHTML?: {
36
+ __html: string;
37
+ };
38
+ [key: string]: any;
39
+ };
40
+ }
41
+ }
42
+ }
43
+ export { FEAASExternal as External };
44
+ //# sourceMappingURL=FEAASExternal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FEAASExternal.d.ts","sourceRoot":"","sources":["../../src/components/FEAASExternal.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,QAAQ,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAkB1D,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,SAAgB,MAQ3D;AAED,MAAM,MAAM,oBAAoB,GAAG;IAAE,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC;QAAC,MAAM,EAAE,GAAG,CAAA;KAAE,CAAA;CAAE,CAAA;AAClG,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnG,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,SAAS,CAAC,kBAAkB,EAAE,YAAY,CAAC;IACpF,MAAM,CAAC,UAAU,EAAE,oBAAoB,CAAK;IAC5C,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAC,OAAO,CAAA;IAC3C,IAAI;;;;IAIJ,MAAM,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,KAAK,EAAE,EAAE,YAAY,GAAG,QAAQ;IAOpE,QAAQ;IAIR,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,GAAE,GAAQ,EAAE,EAAE,CAAC,EAAE,MAAM;IAI3E,MAAM,CAAC,uBAAuB;IAuB9B,MAAM,CAAC,cAAc;CAStB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,GAAG,CAAC;QACZ,UAAU,iBAAiB;YACzB,gBAAgB,EAAE;gBAChB,kBAAkB,EAAE,MAAM,CAAA;gBAC1B,QAAQ,CAAC,EAAE,GAAG,CAAA;gBACd,uBAAuB,CAAC,EAAE;oBAAE,MAAM,EAAE,MAAM,CAAA;iBAAE,CAAA;gBAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;aACnB,CAAA;SACF;KACF;CACF;AAKD,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,CAAA"}
@@ -15,6 +15,7 @@ export * from './components/FEAASElement.js';
15
15
  export * from './components/FEAASComponent.js';
16
16
  export * from './components/FEAASLoader.js';
17
17
  export * from './components/FEAASStylesheet.js';
18
+ export * from './components/FEAASExternal.js';
18
19
  declare global {
19
20
  interface Window {
20
21
  FEAASLoading: Promise<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../src/headless.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,YAAY,MAAM,8BAA8B,CAAA;AAEvD,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,iCAAiC,CAAA;AAE/C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;QAC1B,YAAY,EAAE,OAAO,YAAY,CAAA;KAClC;CACF"}
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../src/headless.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,YAAY,MAAM,8BAA8B,CAAA;AAEvD,cAAc,oBAAoB,CAAA;AAClC,cAAc,eAAe,CAAA;AAC7B,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,+BAA+B,CAAA;AAE7C,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;QAC1B,YAAY,EAAE,OAAO,YAAY,CAAA;KAClC;CACF"}