@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.
- package/build/components/FEAASExternal.js +79 -0
- package/build/components/FEAASExternal.js.map +1 -0
- package/build/headless.js +1 -0
- package/build/headless.js.map +1 -1
- package/build/ui/react.js +1 -1
- package/build/ui/react.js.map +1 -1
- package/build/utils/string.js +13 -0
- package/build/utils/string.js.map +1 -0
- 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 -1
- package/react.cjs +5 -5
- package/react.cjs.map +4 -4
- package/react.js +5 -5
- package/react.js.map +4 -4
- package/src/components/FEAASExternal.tsx +107 -0
- package/src/headless.ts +1 -0
- package/src/ui/react.tsx +1 -1
- package/src/utils/string.ts +12 -0
- package/test/FEAASExternal.test.tsx +49 -0
- package/types/components/FEAASExternal.d.ts +44 -0
- package/types/components/FEAASExternal.d.ts.map +1 -0
- package/types/headless.d.ts +1 -0
- package/types/headless.d.ts.map +1 -1
- package/types/tsbuildinfo +1 -1
- package/types/tsbuildinfo_ui +1 -1
- package/types/utils/string.d.ts +3 -0
- 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="{"first-name":"Chuck","telephone":"45657890875643"}" 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="{"first-name":"Chuck","telephone":"45657890875643"}" 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="{"first-name":"Chuck","telephone":"45657890875643"}" 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="{"first-name":"George","address":"Test street 12"}" 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"}
|
package/types/headless.d.ts
CHANGED
|
@@ -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>;
|
package/types/headless.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|