@furystack/shades 3.6.3
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/LICENSE +339 -0
- package/README.md +42 -0
- package/dist/component-factory.spec.d.ts +2 -0
- package/dist/component-factory.spec.d.ts.map +1 -0
- package/dist/component-factory.spec.js +20 -0
- package/dist/component-factory.spec.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +7 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/lazy-load.d.ts +11 -0
- package/dist/components/lazy-load.d.ts.map +1 -0
- package/dist/components/lazy-load.js +42 -0
- package/dist/components/lazy-load.js.map +1 -0
- package/dist/components/route-link.d.ts +3 -0
- package/dist/components/route-link.d.ts.map +1 -0
- package/dist/components/route-link.js +17 -0
- package/dist/components/route-link.js.map +1 -0
- package/dist/components/router.d.ts +24 -0
- package/dist/components/router.d.ts.map +1 -0
- package/dist/components/router.js +50 -0
- package/dist/components/router.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/initialize.d.ts +8 -0
- package/dist/initialize.d.ts.map +1 -0
- package/dist/initialize.js +9 -0
- package/dist/initialize.js.map +1 -0
- package/dist/is-jsx-element.spec.d.ts +2 -0
- package/dist/is-jsx-element.spec.d.ts.map +1 -0
- package/dist/is-jsx-element.spec.js +18 -0
- package/dist/is-jsx-element.spec.js.map +1 -0
- package/dist/jsx.d.ts +528 -0
- package/dist/jsx.d.ts.map +1 -0
- package/dist/jsx.js +9 -0
- package/dist/jsx.js.map +1 -0
- package/dist/models/children-list.d.ts +2 -0
- package/dist/models/children-list.d.ts.map +1 -0
- package/dist/models/children-list.js +3 -0
- package/dist/models/children-list.js.map +1 -0
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +9 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/partial-element.d.ts +6 -0
- package/dist/models/partial-element.d.ts.map +1 -0
- package/dist/models/partial-element.js +3 -0
- package/dist/models/partial-element.js.map +1 -0
- package/dist/models/render-options.d.ts +13 -0
- package/dist/models/render-options.d.ts.map +1 -0
- package/dist/models/render-options.js +3 -0
- package/dist/models/render-options.js.map +1 -0
- package/dist/models/selection-state.d.ts +10 -0
- package/dist/models/selection-state.d.ts.map +1 -0
- package/dist/models/selection-state.js +3 -0
- package/dist/models/selection-state.js.map +1 -0
- package/dist/models/shade-component.d.ts +13 -0
- package/dist/models/shade-component.d.ts.map +1 -0
- package/dist/models/shade-component.js +14 -0
- package/dist/models/shade-component.js.map +1 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/location-service.d.ts +10 -0
- package/dist/services/location-service.d.ts.map +1 -0
- package/dist/services/location-service.js +41 -0
- package/dist/services/location-service.js.map +1 -0
- package/dist/services/location-service.spec.d.ts +2 -0
- package/dist/services/location-service.spec.d.ts.map +1 -0
- package/dist/services/location-service.spec.js +18 -0
- package/dist/services/location-service.spec.js.map +1 -0
- package/dist/services/screen-service.d.ts +28 -0
- package/dist/services/screen-service.d.ts.map +1 -0
- package/dist/services/screen-service.js +52 -0
- package/dist/services/screen-service.js.map +1 -0
- package/dist/shade-component.d.ts +26 -0
- package/dist/shade-component.d.ts.map +1 -0
- package/dist/shade-component.js +72 -0
- package/dist/shade-component.js.map +1 -0
- package/dist/shade.d.ts +40 -0
- package/dist/shade.d.ts.map +1 -0
- package/dist/shade.js +138 -0
- package/dist/shade.js.map +1 -0
- package/package.json +41 -0
- package/src/component-factory.spec.tsx +22 -0
- package/src/components/index.ts +3 -0
- package/src/components/lazy-load.tsx +47 -0
- package/src/components/route-link.tsx +21 -0
- package/src/components/router.tsx +66 -0
- package/src/index.ts +7 -0
- package/src/initialize.ts +11 -0
- package/src/is-jsx-element.spec.ts +18 -0
- package/src/jsx.ts +528 -0
- package/src/models/children-list.ts +1 -0
- package/src/models/index.ts +5 -0
- package/src/models/partial-element.ts +3 -0
- package/src/models/render-options.ts +16 -0
- package/src/models/selection-state.ts +9 -0
- package/src/models/shade-component.ts +16 -0
- package/src/services/index.ts +2 -0
- package/src/services/location-service.spec.ts +16 -0
- package/src/services/location-service.tsx +40 -0
- package/src/services/screen-service.ts +59 -0
- package/src/shade-component.ts +69 -0
- package/src/shade.ts +201 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ChildrenList = Array<string | HTMLElement | JSX.Element | string[] | HTMLElement[] | JSX.Element[]>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { PartialElement } from './partial-element'
|
|
3
|
+
import { ChildrenList } from './children-list'
|
|
4
|
+
|
|
5
|
+
export type RenderOptions<TProps, TState> = {
|
|
6
|
+
readonly props: TProps
|
|
7
|
+
|
|
8
|
+
injector: Injector
|
|
9
|
+
children: ChildrenList
|
|
10
|
+
element: JSX.Element<TProps, TState>
|
|
11
|
+
} & (unknown extends TState
|
|
12
|
+
? {}
|
|
13
|
+
: {
|
|
14
|
+
getState: () => TState
|
|
15
|
+
updateState: (newState: PartialElement<TState>, skipRender?: boolean) => void
|
|
16
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ChildrenList } from './children-list'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definition for a Shade component
|
|
5
|
+
*/
|
|
6
|
+
export type ShadeComponent<TProps = {}> = (arg: TProps, children?: ChildrenList) => JSX.Element
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Type guard that checks if an object is a stateless component
|
|
10
|
+
*
|
|
11
|
+
* @param obj The object to check
|
|
12
|
+
* @returns a value that indicates if the object is a Shade component
|
|
13
|
+
*/
|
|
14
|
+
export const isShadeComponent = (obj: any): obj is ShadeComponent<any> => {
|
|
15
|
+
return typeof obj === 'function'
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { usingAsync } from '@furystack/utils'
|
|
3
|
+
import { LocationService } from './'
|
|
4
|
+
import { JSDOM } from 'jsdom'
|
|
5
|
+
|
|
6
|
+
describe('LocationService', () => {
|
|
7
|
+
it('Shuld be constructed', async () => {
|
|
8
|
+
await usingAsync(new Injector(), async (i) => {
|
|
9
|
+
const dom = new JSDOM()
|
|
10
|
+
;(global as any).window = dom.window
|
|
11
|
+
i.setExplicitInstance(dom.window, Window)
|
|
12
|
+
const s = i.getInstance(LocationService)
|
|
13
|
+
expect(s).toBeInstanceOf(LocationService)
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Disposable, ObservableValue, Trace } from '@furystack/utils'
|
|
2
|
+
import { Injectable } from '@furystack/inject'
|
|
3
|
+
@Injectable({ lifetime: 'singleton' })
|
|
4
|
+
export class LocationService implements Disposable {
|
|
5
|
+
public dispose() {
|
|
6
|
+
window.removeEventListener('popstate', this.updateState)
|
|
7
|
+
window.removeEventListener('hashchange', this.updateState)
|
|
8
|
+
this.pushStateTracer.dispose()
|
|
9
|
+
this.replaceStateTracer.dispose()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public onLocationChanged = new ObservableValue<URL>(new URL(location.href))
|
|
13
|
+
|
|
14
|
+
public updateState() {
|
|
15
|
+
const newUrl = new URL(location.href)
|
|
16
|
+
this.onLocationChanged.setValue(newUrl)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private pushStateTracer: Disposable
|
|
20
|
+
private replaceStateTracer: Disposable
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
window.addEventListener('popstate', () => this.updateState())
|
|
24
|
+
window.addEventListener('hashchange', () => this.updateState())
|
|
25
|
+
|
|
26
|
+
this.pushStateTracer = Trace.method({
|
|
27
|
+
object: history,
|
|
28
|
+
method: history.pushState,
|
|
29
|
+
isAsync: false,
|
|
30
|
+
onFinished: () => this.updateState(),
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
this.replaceStateTracer = Trace.method({
|
|
34
|
+
object: history,
|
|
35
|
+
method: history.replaceState,
|
|
36
|
+
isAsync: false,
|
|
37
|
+
onFinished: () => this.updateState(),
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Injectable } from '@furystack/inject'
|
|
2
|
+
import { Disposable, ObservableValue } from '@furystack/utils'
|
|
3
|
+
|
|
4
|
+
export const ScreenSizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
|
|
5
|
+
|
|
6
|
+
export type ScreenSize = typeof ScreenSizes[number]
|
|
7
|
+
|
|
8
|
+
export type Breakpoint = { name: ScreenSize; minSize: number; maxSize?: number }
|
|
9
|
+
|
|
10
|
+
@Injectable({ lifetime: 'singleton' })
|
|
11
|
+
export class Screen implements Disposable {
|
|
12
|
+
private getOrientation = () => (window.matchMedia('(orientation:landscape').matches ? 'landscape' : 'portrait')
|
|
13
|
+
|
|
14
|
+
public readonly breakpoints: { [K in ScreenSize]: { minSize: number } } = {
|
|
15
|
+
xl: { minSize: 1920 },
|
|
16
|
+
lg: { minSize: 1280 },
|
|
17
|
+
md: { minSize: 960 },
|
|
18
|
+
sm: { minSize: 600 },
|
|
19
|
+
xs: { minSize: 0 },
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public dispose() {
|
|
23
|
+
window.removeEventListener('resize', this.onResizeListener)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public readonly screenSize: {
|
|
27
|
+
atLeast: { [K in ScreenSize]: ObservableValue<boolean> }
|
|
28
|
+
} = {
|
|
29
|
+
atLeast: {
|
|
30
|
+
xs: new ObservableValue<boolean>(this.screenSizeAtLeast('xs')),
|
|
31
|
+
sm: new ObservableValue<boolean>(this.screenSizeAtLeast('sm')),
|
|
32
|
+
md: new ObservableValue<boolean>(this.screenSizeAtLeast('md')),
|
|
33
|
+
lg: new ObservableValue<boolean>(this.screenSizeAtLeast('lg')),
|
|
34
|
+
xl: new ObservableValue<boolean>(this.screenSizeAtLeast('xl')),
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private screenSizeAtLeast(size: ScreenSize) {
|
|
39
|
+
return window.innerWidth >= this.breakpoints[size].minSize
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public orientation = new ObservableValue<'landscape' | 'portrait'>(this.getOrientation())
|
|
43
|
+
|
|
44
|
+
private onResizeListener = () => {
|
|
45
|
+
this.refreshValues()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private refreshValues() {
|
|
49
|
+
this.orientation.setValue(this.getOrientation())
|
|
50
|
+
ScreenSizes.forEach((size) => {
|
|
51
|
+
this.screenSize.atLeast[size].setValue(this.screenSizeAtLeast(size))
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
constructor() {
|
|
56
|
+
window.addEventListener('resize', this.onResizeListener)
|
|
57
|
+
this.refreshValues()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ChildrenList, ShadeComponent, isShadeComponent } from './models'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Appends a list of items to a HTML element
|
|
5
|
+
*
|
|
6
|
+
* @param el the root element
|
|
7
|
+
* @param children array of items to append
|
|
8
|
+
*/
|
|
9
|
+
export const appendChild = (el: HTMLElement, children: ChildrenList) => {
|
|
10
|
+
for (const child of children) {
|
|
11
|
+
if (typeof child === 'string') {
|
|
12
|
+
el.appendChild(document.createTextNode(child))
|
|
13
|
+
} else {
|
|
14
|
+
if (child instanceof HTMLElement) {
|
|
15
|
+
el.appendChild(child)
|
|
16
|
+
} else if (child instanceof Array) {
|
|
17
|
+
appendChild(el, child)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const hasStyle = (props: any): props is { style: Partial<CSSStyleDeclaration> } => {
|
|
24
|
+
return props?.style !== undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param el The Target HTML Element
|
|
29
|
+
* @param props The Properties to fetch The Styles Object
|
|
30
|
+
*/
|
|
31
|
+
export const attachStyles = (el: HTMLElement, props: any) => {
|
|
32
|
+
if (hasStyle(props))
|
|
33
|
+
for (const key in props.style) {
|
|
34
|
+
if (Object.prototype.hasOwnProperty.call(props.style, key)) {
|
|
35
|
+
;(el.style as any)[key] = props.style[key]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Factory method that creates a component. This should be configured as a default JSX Factory in tsconfig.
|
|
42
|
+
*
|
|
43
|
+
* @param elementType The type of the element (component or stateless component factory method)
|
|
44
|
+
* @param props The props for the component
|
|
45
|
+
* @param children additional rest parameters will be parsed as children objects
|
|
46
|
+
* @returns the created JSX element
|
|
47
|
+
*/
|
|
48
|
+
export const createComponent = <TProps>(
|
|
49
|
+
elementType: string | ShadeComponent<TProps>,
|
|
50
|
+
props: TProps,
|
|
51
|
+
...children: ChildrenList
|
|
52
|
+
) => {
|
|
53
|
+
if (typeof elementType === 'string') {
|
|
54
|
+
const el = document.createElement(elementType)
|
|
55
|
+
Object.assign(el, props)
|
|
56
|
+
|
|
57
|
+
if (props && (props as any).style) {
|
|
58
|
+
attachStyles(el, props)
|
|
59
|
+
}
|
|
60
|
+
if (children) {
|
|
61
|
+
appendChild(el, children)
|
|
62
|
+
}
|
|
63
|
+
return el
|
|
64
|
+
} else if (isShadeComponent(elementType)) {
|
|
65
|
+
const el = (elementType as ShadeComponent<TProps>)(props, children)
|
|
66
|
+
attachStyles(el, props)
|
|
67
|
+
return el
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/shade.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { ObservableValue } from '@furystack/utils'
|
|
2
|
+
import { v4 } from 'uuid'
|
|
3
|
+
import { Injector } from '@furystack/inject'
|
|
4
|
+
import { ChildrenList, RenderOptions } from './models'
|
|
5
|
+
|
|
6
|
+
export type ShadeOptions<TProps, TState> = {
|
|
7
|
+
/**
|
|
8
|
+
* Explicit shadow dom name. Will fall back to 'shade-{guid}' if not provided
|
|
9
|
+
*/
|
|
10
|
+
shadowDomName?: string
|
|
11
|
+
/**
|
|
12
|
+
* Render hook, this method will be executed on each and every render.
|
|
13
|
+
*/
|
|
14
|
+
render: (options: RenderOptions<TProps, TState>) => JSX.Element
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Construct hook. Will be executed once when the element has been constructed and initialized
|
|
18
|
+
*/
|
|
19
|
+
constructed?: (
|
|
20
|
+
options: RenderOptions<TProps, TState>,
|
|
21
|
+
) => void | undefined | (() => void) | Promise<void | undefined | (() => void)>
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Will be executed when the element is attached to the DOM.
|
|
25
|
+
*/
|
|
26
|
+
onAttach?: (options: RenderOptions<TProps, TState>) => void
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Will be executed when the element is detached from the DOM.
|
|
30
|
+
*/
|
|
31
|
+
onDetach?: (options: RenderOptions<TProps, TState>) => void
|
|
32
|
+
} & (unknown extends TState
|
|
33
|
+
? {}
|
|
34
|
+
: {
|
|
35
|
+
/**
|
|
36
|
+
* The initial state of the component
|
|
37
|
+
*/
|
|
38
|
+
getInitialState: (options: { injector: Injector; props: TProps }) => TState
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Factory method for creating Shade components
|
|
43
|
+
*
|
|
44
|
+
* @param o for component creation
|
|
45
|
+
* @returns the JSX element
|
|
46
|
+
*/
|
|
47
|
+
export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>) => {
|
|
48
|
+
// register shadow-dom element
|
|
49
|
+
const customElementName = o.shadowDomName || `shade-${v4()}`
|
|
50
|
+
|
|
51
|
+
const existing = customElements.get(customElementName)
|
|
52
|
+
if (!existing) {
|
|
53
|
+
customElements.define(
|
|
54
|
+
customElementName,
|
|
55
|
+
class extends HTMLElement implements JSX.Element {
|
|
56
|
+
public connectedCallback() {
|
|
57
|
+
o.onAttach && o.onAttach(this.getRenderOptions())
|
|
58
|
+
this.callConstructed()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public disconnectedCallback() {
|
|
62
|
+
o.onDetach && o.onDetach(this.getRenderOptions())
|
|
63
|
+
this.props.dispose()
|
|
64
|
+
this.state.dispose()
|
|
65
|
+
this.shadeChildren.dispose()
|
|
66
|
+
this.cleanup && this.cleanup()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Will be triggered when updating the external props object
|
|
71
|
+
*/
|
|
72
|
+
public props: ObservableValue<TProps & { children?: JSX.Element[] }>
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Will be triggered on state update
|
|
76
|
+
*/
|
|
77
|
+
public state: ObservableValue<TState>
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Will be updated when on children change
|
|
81
|
+
*/
|
|
82
|
+
public shadeChildren = new ObservableValue<ChildrenList>([])
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param options Options for rendering the component
|
|
86
|
+
* @returns the JSX element
|
|
87
|
+
*/
|
|
88
|
+
public render = (options: RenderOptions<TProps, TState>) => o.render(options)
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @returns values for the current render options
|
|
92
|
+
*/
|
|
93
|
+
private getRenderOptions = () => {
|
|
94
|
+
const props = this.props.getValue() || {}
|
|
95
|
+
const getState = () => this.state.getValue()
|
|
96
|
+
return {
|
|
97
|
+
props,
|
|
98
|
+
getState,
|
|
99
|
+
injector: this.injector,
|
|
100
|
+
updateState: (newState: TState, skipRender: boolean) => {
|
|
101
|
+
this.state.setValue({ ...this.state.getValue(), ...newState })
|
|
102
|
+
!skipRender && this.updateComponent()
|
|
103
|
+
},
|
|
104
|
+
children: this.shadeChildren.getValue(),
|
|
105
|
+
element: this,
|
|
106
|
+
} as any as RenderOptions<TProps, TState>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Updates the component in the DOM.
|
|
111
|
+
*/
|
|
112
|
+
public async updateComponent() {
|
|
113
|
+
const newJsx = this.render(this.getRenderOptions())
|
|
114
|
+
|
|
115
|
+
// const selectionState = this.getSelectionState()
|
|
116
|
+
|
|
117
|
+
if (this.hasChildNodes()) {
|
|
118
|
+
this.replaceChild(newJsx, this.firstChild as Node)
|
|
119
|
+
// selectionState && this.restoreSelectionState(selectionState)
|
|
120
|
+
} else {
|
|
121
|
+
this.append(newJsx)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Finialize the component initialization after it gets the Props. Called by the framework internally
|
|
127
|
+
*/
|
|
128
|
+
public callConstructed() {
|
|
129
|
+
;(o as any).getInitialState &&
|
|
130
|
+
this.state.setValue((o as any).getInitialState({ props: this.props.getValue(), injector: this.injector }))
|
|
131
|
+
|
|
132
|
+
this.updateComponent()
|
|
133
|
+
const cleanupResult = o.constructed && o.constructed(this.getRenderOptions())
|
|
134
|
+
if (cleanupResult instanceof Promise) {
|
|
135
|
+
cleanupResult.then((cleanup) => (this.cleanup = cleanup))
|
|
136
|
+
} else {
|
|
137
|
+
// construct is not async
|
|
138
|
+
this.cleanup = cleanupResult
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private cleanup: void | (() => void) = undefined
|
|
143
|
+
|
|
144
|
+
private _injector?: Injector
|
|
145
|
+
|
|
146
|
+
private getInjectorFromParent(): Injector | void {
|
|
147
|
+
let parent = this.parentElement
|
|
148
|
+
while (parent) {
|
|
149
|
+
if ((parent as JSX.Element).injector) {
|
|
150
|
+
return (parent as JSX.Element).injector
|
|
151
|
+
}
|
|
152
|
+
parent = parent.parentElement
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public get injector(): Injector {
|
|
157
|
+
if (this._injector) {
|
|
158
|
+
return this._injector
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const fromState = (this.state.getValue() as any)?.injector
|
|
162
|
+
if (fromState && fromState instanceof Injector) {
|
|
163
|
+
return fromState
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const fromProps = (this.props.getValue() as any)?.injector
|
|
167
|
+
if (fromProps && fromProps instanceof Injector) {
|
|
168
|
+
return fromProps
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const fromParent = this.getInjectorFromParent()
|
|
172
|
+
if (fromParent) {
|
|
173
|
+
this._injector = fromParent
|
|
174
|
+
return fromParent
|
|
175
|
+
}
|
|
176
|
+
throw Error('Injector not set explicitly and not found on parents!')
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public set injector(i: Injector) {
|
|
180
|
+
this._injector = i
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
constructor(_props: TProps) {
|
|
184
|
+
super()
|
|
185
|
+
this.props = new ObservableValue()
|
|
186
|
+
this.state = new ObservableValue()
|
|
187
|
+
}
|
|
188
|
+
} as any as CustomElementConstructor,
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return (props: TProps, children: ChildrenList) => {
|
|
193
|
+
const el = document.createElement(customElementName, {
|
|
194
|
+
...props,
|
|
195
|
+
}) as JSX.Element<TProps, TState>
|
|
196
|
+
el.props.setValue(props)
|
|
197
|
+
|
|
198
|
+
el.shadeChildren.setValue(children)
|
|
199
|
+
return el as JSX.Element
|
|
200
|
+
}
|
|
201
|
+
}
|