@sitecore-feaas/clientside 0.0.9 → 0.1.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 (57) hide show
  1. package/README.md +5 -5
  2. package/dist/browser/basic.cjs +67 -0
  3. package/dist/browser/basic.js +67 -0
  4. package/dist/browser/index.cjs +68 -79
  5. package/dist/browser/index.js +68 -79
  6. package/dist/node/{react.cjs → basic.cjs} +436 -443
  7. package/dist/node/{react.js → basic.js} +432 -439
  8. package/dist/node/index.cjs +666 -291
  9. package/dist/node/index.js +666 -295
  10. package/examples/index.html +1 -1
  11. package/package.json +17 -17
  12. package/src/basic.ts +5 -0
  13. package/src/cloud.ts +9 -5
  14. package/src/components/FEAASBase.tsx +265 -0
  15. package/src/components/FEAASComponent.ts +98 -0
  16. package/src/components/FEAASContext.tsx +105 -0
  17. package/src/components/FEAASEditor.tsx +291 -0
  18. package/src/components/FEAASLoader.ts +113 -0
  19. package/src/components/FEAASPicker.tsx +98 -0
  20. package/src/components/FEAASStylesheet.ts +43 -0
  21. package/src/components/index.tsx +7 -0
  22. package/src/index.ts +4 -11
  23. package/test/components.js +11 -0
  24. package/test/components.ts +12 -0
  25. package/test/render.js +688 -0
  26. package/tsconfig.json +11 -6
  27. package/types/basic.d.ts +5 -0
  28. package/types/cloud.d.ts +18 -0
  29. package/types/components/FEAASBase.d.ts +70 -0
  30. package/types/components/FEAASComponent.d.ts +39 -0
  31. package/types/components/FEAASContext.d.ts +43 -0
  32. package/types/components/FEAASEditor.d.ts +70 -0
  33. package/types/components/FEAASLoader.d.ts +20 -0
  34. package/types/components/FEAASPicker.d.ts +61 -0
  35. package/types/components/FEAASStylesheet.d.ts +25 -0
  36. package/types/components/index.d.ts +7 -0
  37. package/types/dom.d.ts +29 -0
  38. package/types/fetch.d.ts +1 -0
  39. package/types/index.d.ts +4 -0
  40. package/types/tsbuildinfo +1 -0
  41. package/dist/browser/index.d.ts +0 -25
  42. package/dist/browser/react.cjs +0 -83
  43. package/dist/browser/react.d.ts +0 -36
  44. package/dist/browser/react.js +0 -83
  45. package/dist/browser/webcomponent-6b45b819.d.ts +0 -120
  46. package/dist/node/index.d.ts +0 -25
  47. package/dist/node/react.d.ts +0 -36
  48. package/dist/node/webcomponent-6b45b819.d.ts +0 -120
  49. package/index.cjs +0 -83
  50. package/index.d.ts +0 -25
  51. package/index.js +0 -83
  52. package/react.cjs +0 -83
  53. package/react.d.ts +0 -36
  54. package/react.js +0 -83
  55. package/src/react.ts +0 -66
  56. package/src/webcomponent.ts +0 -393
  57. package/webcomponent-6b45b819.d.ts +0 -120
@@ -1,5 +1,5 @@
1
1
  <script type="module">
2
- import FEAAS from '../dist/browser/index.js.js'
2
+ import FEAAS from '../dist/browser/index.js'
3
3
  const renderMyComponent = (element, data) =>
4
4
  FEAAS.renderComponent(
5
5
  {
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@sitecore-feaas/clientside",
3
- "version": "0.0.9",
3
+ "version": "0.1.1",
4
4
  "scripts": {
5
5
  "start": "webpack serve --open",
6
6
  "build": "rm -rf dist; npm run build:node; npm run build:browser;",
7
- "build:node": "tsup --entry.index src/index.ts --entry.react src/react.ts --target es6 --format cjs,esm -d dist/node",
8
- "build:browser": "tsup --entry.index src/index.ts --entry.react src/react.ts --target es6 --format cjs,esm -d dist/browser --minify",
9
- "watch": "tsup --entry.index src/index.ts --entry.react src/react.ts --target es6 --format esm -d dist/node --watch",
7
+ "build:node": "tsc --build; tsup --entry.index src/index.ts --entry.basic src/basic.ts --target es6 --format cjs,esm -d dist/node",
8
+ "build:browser": "tsc --build; tsup --entry.index src/index.ts --entry.basic src/basic.ts --target es6 --format cjs,esm -d dist/browser --minify",
9
+ "watch": "tsup --entry.index src/index.ts --entry.basic src/basic.ts --target es6 --format esm -d dist/node --watch",
10
10
  "test": "npx vitest --config ../frontend/vite.config.ts $FLAGS",
11
11
  "test:watch": "npx vitest --config ../frontend/vite.config.ts",
12
- "prepublishOnly": "npm run build; cp ./dist/browser/*{js,ts} .",
13
- "check": "npx tsc --noEmit",
14
- "postpublish": "rm -rf ./*{js,ts}"
12
+ "prepublishOnly": "npm run build",
13
+ "check": "npx tsc --noEmit --emitDeclarationOnly false",
14
+ "postpublish": "node ../scripts/upload-package-to-blob-storage.js clientside $npm_package_version"
15
15
  },
16
16
  "license": "ISC",
17
17
  "dependencies": {
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "tsup": {
25
25
  "platform": "browser",
26
- "dts": true,
26
+ "dts": false,
27
27
  "splitting": false,
28
28
  "external": [
29
29
  "node-fetch"
@@ -38,23 +38,23 @@
38
38
  "react-dom": ">=16.8.0"
39
39
  },
40
40
  "main": "dist/browser/index.js",
41
- "types": "dist/browser/react.d.ts",
41
+ "types": "dist/browser/index.d.ts",
42
42
  "type": "module",
43
43
  "exports": {
44
44
  ".": {
45
45
  "typescript": "./src/index.ts",
46
- "types": "./src/index.ts",
46
+ "types": "./types/index.d.ts",
47
47
  "require": "./dist/node/index.cjs",
48
48
  "browser": "./dist/browser/index.js",
49
49
  "default": "./dist/node/index.js"
50
50
  },
51
- "./react": {
52
- "typescript": "./src/react.ts",
53
- "types": "./src/react.ts",
54
- "require": "./dist/node/react.cjs",
55
- "browser": "./dist/browser/react.js",
56
- "development": "./src/react.ts",
57
- "default": "./dist/node/react.js"
51
+ "./basic": {
52
+ "typescript": "./src/basic.ts",
53
+ "types": "./src/basic.ts",
54
+ "require": "./dist/node/basic.cjs",
55
+ "browser": "./dist/browser/basic.js",
56
+ "development": "./src/basic.ts",
57
+ "default": "./dist/node/basic.js"
58
58
  }
59
59
  },
60
60
  "typedoc": {
package/src/basic.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './dom.js'
2
+ export * from './fetch.js'
3
+ export * from './components/FEAASLoader.js'
4
+ export * from './components/FEAASStylesheet.js'
5
+ export * from './components/FEAASComponent.js'
package/src/cloud.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { fetchAndRevalidate } from './fetch.js'
2
2
 
3
3
  export interface CloudTemplate {
4
+ cdn?: string
4
5
  hostname?: string
5
6
  library: string
6
7
  component: string
@@ -8,27 +9,30 @@ export interface CloudTemplate {
8
9
  revision?: string
9
10
  }
10
11
  export interface CloudStylesheet {
12
+ cdn?: string
11
13
  hostname?: string
12
14
  library: string
13
- revision?: string
15
+ revision?: 'staging' | 'published' | 'saved' | number
14
16
  }
15
17
 
16
18
  export function getComponentURL({
17
- hostname = 'https://feaascomponentsapidev.blob.core.windows.net',
19
+ cdn = 'https://feaascomponentsapidev.blob.core.windows.net',
20
+ hostname,
18
21
  library,
19
22
  component,
20
23
  version,
21
24
  revision = 'published'
22
25
  }: CloudTemplate) {
23
- return `${hostname}/components/${library}/${component}/${version}/${revision}.html`
26
+ return `${cdn || hostname}/components/${library}/${component}/${version}/${revision}.html`
24
27
  }
25
28
 
26
29
  export function getStylesheetURL({
27
- hostname = `https://feaascomponentsapidev.blob.core.windows.net`,
30
+ cdn = `https://feaascomponentsapidev.blob.core.windows.net`,
31
+ hostname,
28
32
  library,
29
33
  revision = 'published'
30
34
  }: CloudStylesheet) {
31
- return `${hostname}/styles/${library}/${revision}.css`
35
+ return `${cdn || hostname}/styles/${library}/${revision}.css`
32
36
  }
33
37
 
34
38
  export async function fetchComponent(props: CloudTemplate, callback: (html: string) => void) {
@@ -0,0 +1,265 @@
1
+ import { JSXElementConstructor, ReactElement, ReactNode } from 'react'
2
+ import type ReactDOM from 'react-dom'
3
+ import type React from 'react'
4
+
5
+ export type OptionalExcept<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>
6
+
7
+ // Shim in case it's required in node.js environment
8
+ var WebComponent = typeof HTMLElement == 'undefined' ? (class {} as unknown as typeof HTMLElement) : HTMLElement
9
+ interface ReactPayload {
10
+ React: typeof React
11
+ ReactDOM: typeof ReactDOM
12
+ }
13
+
14
+ export class FEAASBase<Props = any, Payload = any> extends HTMLElement {
15
+ static observedAttributes: string[]
16
+
17
+ /** Return attributes as parsed values */
18
+ getProps(context?: HTMLElement): any {
19
+ return {}
20
+ }
21
+
22
+ /** Properties parsed in current tick */
23
+ props: Props
24
+ overrides: Props
25
+
26
+ /** Timer until next tick */
27
+ nextRender: number
28
+
29
+ /** Is/was component in the dom? */
30
+ connected = null as Event
31
+
32
+ /** Result of lazy loading */
33
+ payload: Payload
34
+
35
+ refs: Record<string, FEAASBase> = {}
36
+ descendants: FEAASBase[] = []
37
+
38
+ /** Attaches shadow root if getShadowRootOptions any settings, or uses element itself */
39
+ getRoot(): FEAASBase | HTMLElement | ShadowRoot {
40
+ return this
41
+ }
42
+
43
+ /** Attribute changes trigger props parsing and schedules re-rendering */
44
+ attributeChangedCallback(name: string, oldValue: string, newValue: string) {
45
+ this.set()
46
+ }
47
+
48
+ /** Components parses its attributes when connected, and schedules rendeirng */
49
+ connectedCallback() {
50
+ console.log('FEAAS: Connected', this)
51
+ this.connected = new Event('feaasConnected', { bubbles: true, composed: true })
52
+ this.dispatchEvent(this.connected)
53
+ this.addEventListener('feaasConnected', this)
54
+ this.addEventListener('feaasDisconnected', this)
55
+ this.set()
56
+ }
57
+
58
+ /** Nothing special happens on disconnect, except setting a flag */
59
+ disconnectedCallback() {
60
+ console.log('FEAAS: Disconnected', this)
61
+ this.removeEventListener('feaasConnected', this)
62
+ this.removeEventListener('feaasDisconnected', this)
63
+ this.dispatchEvent(new Event('feaasDisconnected', { bubbles: true, composed: true }))
64
+ this.connected = null
65
+ }
66
+
67
+ /** Catch-all event handler that dispatches events to callback */
68
+ handleEvent(event: Event) {
69
+ switch (event.type) {
70
+ case 'feaasConnected':
71
+ this.adoptedCallback(event)
72
+ break
73
+ case 'feaasDisconnected':
74
+ this.orphanCallback(event)
75
+ break
76
+ }
77
+ }
78
+
79
+ /** Act on children element being removed */
80
+ orphanCallback(event: Event) {
81
+ const target = event.composedPath()[0] as FEAASBase
82
+ const index = this.descendants.indexOf(target)
83
+ if (index == -1) return
84
+ console.log('FEAAS: Orphaning', this, target)
85
+ this.descendants.splice(index, -1)
86
+ this.refs[target.getComponentName()] = null
87
+ if (target.refs.parent == this) target.refs.parent = null
88
+ if (target.refs.top == this) {
89
+ target.refs.top = target.refs.parent
90
+ }
91
+ }
92
+
93
+ /** Act on children element being added */
94
+ adoptedCallback(event: Event): boolean | void {
95
+ const target = event.composedPath()[0] as FEAASBase
96
+ this.descendants.push(target)
97
+ console.log('FEAAS: Adopting', this, target)
98
+ this.refs[target.getComponentName()] = target
99
+ target.refs.top = this
100
+ target.refs.parent ||= this
101
+ if (target.renderReact) {
102
+ for (var p: FEAASBase = target.refs.parent; p; p = p.refs.parent) {
103
+ if (p.renderReact) {
104
+ target.refs.parentReact ||= p
105
+ target.refs.topReact = p
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+ getComponentName() {
112
+ return this.tagName.replace('FEAAS-', '').toLowerCase()
113
+ }
114
+
115
+ /**
116
+ * Check if lazy component is ready to be loaded. For example a component may stay unloaded unless certain attributes
117
+ * are set
118
+ */
119
+ isReadyToLoad() {
120
+ return this.payload === undefined && this.getAttribute('hidden') == null
121
+ }
122
+
123
+ /** Load lazy component & render */
124
+ async reify() {
125
+ if (this.payload !== undefined) {
126
+ this.render()
127
+ } else if (this.isReadyToLoad()) {
128
+ this.payload = null
129
+ this.load().then(this.onLoad)
130
+ }
131
+ }
132
+
133
+ /** Invoke preloading logic that needs to finish before component can render */
134
+ load() {
135
+ return Promise.resolve(null)
136
+ }
137
+
138
+ /** Payload is inside onLoad callback. For web components that use react, it has to provide React & ReactDOM props */
139
+ onLoad = (payload: Payload) => {
140
+ if (payload == null) return
141
+
142
+ this.payload = payload
143
+ this.render()
144
+ }
145
+
146
+ /**
147
+ * Component-specific logic that updates the DOM. Default render implementation assume react rendering, in that case
148
+ * the component needs to provide React & ReactDOM references in its payload. Web component redefine its render to not
149
+ * use react at all
150
+ */
151
+ render(nested = false): any {
152
+ console.log('FEAAS: React', this.tagName, this.payload)
153
+ if (this.payload == null) return
154
+ const { React, ReactDOM } = (this.payload as ReactPayload) || {}
155
+ if (!React) throw new Error(`${this.tagName}: React is not present in payload`)
156
+ if (!ReactDOM) throw new Error(`${this.tagName}: ReactDOM is not present in payload`)
157
+
158
+ if (!this.refs.topReact && !this.forceUpdateReact) {
159
+ ReactDOM.render(React.createElement(this.getReactWrapper()), this.getReactRoot())
160
+ } else if (this.forceUpdateReact) {
161
+ this.forceUpdateReact?.()
162
+ } else {
163
+ this.refs.topReact.forceUpdateReact?.()
164
+ }
165
+ }
166
+
167
+ invokeReactRendering(): ReactNode {
168
+ const { React, ReactDOM } = (this.payload as ReactPayload) || {}
169
+ const children = this.descendants
170
+ .filter((r) => {
171
+ return r.refs.parentReact == this && r.payload
172
+ })
173
+ .map((child: FEAASBase<any, any>, index) => {
174
+ return React.createElement(this.getReactWrapper(child), {
175
+ key: this.tagName + '-' + index,
176
+ slot: child.getAttribute('slot')
177
+ })
178
+ })
179
+ return this.renderReact({ ...this.props, children }, this.payload)
180
+ }
181
+
182
+ reactWrapper: (props?: any) => ReactNode
183
+ getReactWrapper(target: FEAASBase = this, displayName = target.tagName) {
184
+ const Wrapper = (target.reactWrapper ||= (props?: any) => {
185
+ if (target.renderReact) {
186
+ const { React, ReactDOM } = (target.payload as ReactPayload) || {}
187
+ const [value, forceUpdateReact] = React.useReducer((r) => r + 1, 0)
188
+ target.forceUpdateReact = forceUpdateReact
189
+ return ReactDOM.createPortal(React.Fragment({ children: target.invokeReactRendering() }), target.getReactRoot())
190
+ } else {
191
+ return target.render()
192
+ }
193
+ })
194
+ Object.assign(Wrapper, {
195
+ displayName: displayName
196
+ })
197
+ return Wrapper
198
+ }
199
+
200
+ uid: string
201
+ getUID() {
202
+ return (this.uid ||= String(Math.random()))
203
+ }
204
+ forceUpdateReact: (node?: ReactNode) => void
205
+
206
+ /**
207
+ * Render method that is pretty much the same as React Functional component, but with extra second argument for
208
+ * payload (usually result of import, it is expected to have React in scope).
209
+ */
210
+ renderReact?(
211
+ props: React.PropsWithChildren<typeof this.props>,
212
+ payload: typeof this.payload
213
+ ): ReactNode | ReactElement
214
+
215
+ getReactRoot(): HTMLElement | ShadowRoot {
216
+ return this.getRoot()
217
+ }
218
+
219
+ /** Set props and return values on new next tick */
220
+ set(overrides?: Partial<Props>) {
221
+ this.overrides = {
222
+ ...this.overrides,
223
+ ...overrides
224
+ }
225
+ this.props = {
226
+ ...this.getProps(),
227
+ ...this.overrides
228
+ }
229
+ for (var property in this.props) {
230
+ const value = this.props[property as keyof typeof this.props]
231
+ if (this.props[property] == null) {
232
+ this.removeAttribute(property)
233
+ } else if (typeof value == 'string' || typeof value == 'number') {
234
+ if (this.getAttribute(property) != String(value)) this.setAttribute(property, String(value))
235
+ }
236
+ }
237
+ this.scheduleRender()
238
+ }
239
+
240
+ /** Schedule rendering on next tick, to batch multiple attribute changes */
241
+ scheduleRender() {
242
+ cancelAnimationFrame(this.nextRender)
243
+ this.nextRender = requestAnimationFrame(() => {
244
+ this.reify()
245
+ })
246
+ }
247
+
248
+ formatURL(src: string, hostname: string) {
249
+ if (typeof src == 'string' && src.match(/\/[^\/]/)) {
250
+ return hostname + src
251
+ } else {
252
+ return src
253
+ }
254
+ }
255
+
256
+ getContextAttribute(name: string, element = this) {
257
+ return element.closest(`[${name}]`)?.getAttribute(name) ?? this.getAttribute(name)
258
+ }
259
+
260
+ static register(tagName: string) {
261
+ if (!window.customElements.get(tagName)) {
262
+ window.customElements.define(tagName, this)
263
+ }
264
+ }
265
+ }
@@ -0,0 +1,98 @@
1
+ import { fetchComponent } from '../cloud.js'
2
+ import { renderDOMContent, renderDOMElement } from '../dom.js'
3
+ import { FEAASBase, OptionalExcept } from './FEAASBase.js'
4
+
5
+ export function FEAASComponentsProps(element: FEAASBase = this) {
6
+ let data: any
7
+ const dataValue = element.getAttribute('data')
8
+ if (dataValue != null) {
9
+ try {
10
+ data = typeof dataValue == 'string' ? JSON.parse(dataValue) : {}
11
+ } catch (e) {}
12
+ }
13
+ return {
14
+ data: data ?? {},
15
+ library: element.getAttribute('library'),
16
+ component: element.getAttribute('component'),
17
+ version: element.getAttribute('version'),
18
+ revision: element.getAttribute('revision'),
19
+ hostname: element.getAttribute('hostname'),
20
+ cdn: element.getContextAttribute('cdn'),
21
+ template: element.getAttribute('template')
22
+ }
23
+ }
24
+ export type FEAASComponentsProps = ReturnType<typeof FEAASComponentsProps>
25
+ export class FEAASComponent extends FEAASBase<FEAASComponentsProps, string> {
26
+ static observedAttributes = ['library', 'component', 'version', 'revision', 'hostname', 'cdn', 'template', 'data']
27
+
28
+ needsRefresh: boolean
29
+ setData(data: any) {
30
+ this.set({ data })
31
+ }
32
+
33
+ getProps() {
34
+ return FEAASComponentsProps(this)
35
+ }
36
+
37
+ attributeChangedCallback(name: string, oldValue: string, newValue: string): void {
38
+ this.payload = undefined
39
+ this.needsRefresh = true
40
+ super.attributeChangedCallback(name, oldValue, newValue)
41
+ }
42
+
43
+ /* Check if component is a repeated clone, and return the original */
44
+ getOriginal() {
45
+ const scope = this.getAttribute('data-path-scope')
46
+ if (!scope) return
47
+ for (var current = this as Element; (current = current.previousElementSibling); ) {
48
+ if (current.getAttribute('data-path-scope') == scope) {
49
+ var last = current
50
+ } else {
51
+ break
52
+ }
53
+ }
54
+ return last as FEAASComponent
55
+ }
56
+
57
+ isReadyToLoad() {
58
+ return (
59
+ super.isReadyToLoad() && this.props.library != null && this.props.component != null && this.props.version != null
60
+ )
61
+ }
62
+
63
+ async load() {
64
+ // defer loading to original element
65
+ if (this.getOriginal()) {
66
+ return
67
+ }
68
+ try {
69
+ fetchComponent(this.props, this.onLoad)
70
+ } catch {
71
+ console.error(
72
+ `FEAAS: Could not fetch component: ${this.props.component}/${this.props.version}/${this.props.revision}`
73
+ )
74
+ }
75
+ }
76
+
77
+ render() {
78
+ if (Array.from(this.children).filter((c) => c.tagName != 'BR').length > 0 && !this.needsRefresh) {
79
+ renderDOMElement(this, this.props.data)
80
+ } else {
81
+ this.needsRefresh = true
82
+ // defer rendering to original element
83
+ if (this.getOriginal()) {
84
+ return
85
+ }
86
+ renderDOMContent(this, this.payload, this.props.data)
87
+ }
88
+ }
89
+ }
90
+
91
+ declare global {
92
+ namespace JSX {
93
+ interface IntrinsicElements {
94
+ 'feaas-component': OptionalExcept<FEAASComponentsProps, 'component' | 'version' | 'revision'>
95
+ }
96
+ }
97
+ }
98
+ FEAASComponent.register('feaas-component')
@@ -0,0 +1,105 @@
1
+ import type * as FEAASContextImports from '@sitecore-feaas/frontend/src/components/providers/ContextProvider.jsx'
2
+
3
+ import { FEAASBase, OptionalExcept } from './FEAASBase.jsx'
4
+
5
+ export function FEAASContextProps(element: HTMLElement = this) {
6
+ return {
7
+ library: element?.getAttribute('library') as string,
8
+ src: element?.getAttribute('src') ?? '/assets/context.js',
9
+ frontend: element?.getAttribute('frontend') ?? 'https://components.sitecoreclud.io',
10
+ backend: element?.getAttribute('backend') ?? 'https://components-api.sitecoreclud.io',
11
+ cdn: element?.getAttribute('cdn') ?? 'https://feaascompontsapiprod.blob.core.windows.net',
12
+ getToken: null as (options: any) => Promise<string>
13
+ }
14
+ }
15
+ type FEAASContextProps = ReturnType<typeof FEAASContextProps>
16
+
17
+ /**
18
+ * Context provides shared parameters and react providers for its nested elements. It loads lazily once any of its
19
+ * nested components load. Just placing it on the page without any consumers does not impose any overhead.
20
+ */
21
+ export class FEAASContext extends FEAASBase<FEAASContextProps, typeof FEAASContextImports> {
22
+ static observedAttributes = ['library', 'component', 'version', 'revision', 'hostname', 'template']
23
+ getProps() {
24
+ return FEAASContextProps(this)
25
+ }
26
+
27
+ load() {
28
+ /* @vite-ignore */
29
+ return import(this.formatURL(this.props.src, this.props.frontend))
30
+ }
31
+
32
+ // Remove global styles
33
+ getTheme(theme: FEAASContextImports.Chakra.Theme): FEAASContextImports.Chakra.Theme {
34
+ return theme
35
+ }
36
+
37
+ getRoot(): HTMLElement | FEAASBase<any, any> | ShadowRoot {
38
+ return this.shadowRoot || this.attachShadow({ mode: 'open' })
39
+ }
40
+
41
+ reactRoot: HTMLDivElement
42
+ getReactRoot() {
43
+ if (!this.reactRoot) {
44
+ this.reactRoot = document.createElement('div')
45
+ this.getRoot().appendChild(this.reactRoot)
46
+ }
47
+ return this.reactRoot
48
+ }
49
+
50
+ /** Pull in children FEAAS react elements into the shadow DOM so they receieve the styles */
51
+ adoptedCallback(event: Event) {
52
+ super.adoptedCallback(event)
53
+
54
+ const target = event.composedPath()[0] as FEAASBase
55
+ if (target.parentNode != this.getRoot()) {
56
+ this.getRoot().appendChild(target)
57
+ }
58
+ }
59
+
60
+ renderReact(
61
+ { children, library }: React.PropsWithChildren<FEAASContextProps>,
62
+ { AppContext, Chakra: { Button, Tooltip }, React: { useRef } }: typeof this.payload
63
+ ) {
64
+ Tooltip.defaultProps = {
65
+ hasArrow: true,
66
+ placement: 'top',
67
+ portalProps: {
68
+ containerRef: { current: this.getRoot() as HTMLElement }
69
+ }
70
+ }
71
+ return (
72
+ <AppContext
73
+ libraryId={this.props.library}
74
+ container={this.getRoot()}
75
+ getTheme={this.getTheme}
76
+ modalProps={{
77
+ portalProps: {
78
+ containerRef: { current: this.getRoot() as HTMLElement }
79
+ }
80
+ }}
81
+ chakraProps={{
82
+ cssVarsRoot: ':host',
83
+ resetCSS: true,
84
+ toastOptions: {
85
+ portalProps: {
86
+ containerRef: { current: this.getRoot() as HTMLElement }
87
+ }
88
+ }
89
+ }}
90
+ >
91
+ {children}
92
+ </AppContext>
93
+ )
94
+ }
95
+ }
96
+
97
+ declare global {
98
+ namespace JSX {
99
+ interface IntrinsicElements {
100
+ 'feaas-context': OptionalExcept<FEAASContextProps, 'library'>
101
+ }
102
+ }
103
+ }
104
+
105
+ FEAASContext.register('feaas-context')