@furystack/shades 6.1.5 → 7.0.0

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 (67) hide show
  1. package/dist/component-factory.spec.js +6 -6
  2. package/dist/component-factory.spec.js.map +1 -1
  3. package/dist/components/lazy-load.js +17 -14
  4. package/dist/components/lazy-load.js.map +1 -1
  5. package/dist/components/route-link.js +7 -3
  6. package/dist/components/route-link.js.map +1 -1
  7. package/dist/components/route-link.spec.js +2 -2
  8. package/dist/components/route-link.spec.js.map +1 -1
  9. package/dist/components/router.js +25 -26
  10. package/dist/components/router.js.map +1 -1
  11. package/dist/components/router.spec.js +2 -2
  12. package/dist/components/router.spec.js.map +1 -1
  13. package/dist/models/render-options.js +23 -0
  14. package/dist/models/render-options.js.map +1 -1
  15. package/dist/services/location-service.js +16 -4
  16. package/dist/services/location-service.js.map +1 -1
  17. package/dist/services/location-service.spec.js +1 -1
  18. package/dist/services/location-service.spec.js.map +1 -1
  19. package/dist/services/resource-manager.js +48 -0
  20. package/dist/services/resource-manager.js.map +1 -0
  21. package/dist/services/resource-manager.spec.js +32 -0
  22. package/dist/services/resource-manager.spec.js.map +1 -0
  23. package/dist/shade-component.js +28 -14
  24. package/dist/shade-component.js.map +1 -1
  25. package/dist/shade-resources.integration.spec.js +7 -8
  26. package/dist/shade-resources.integration.spec.js.map +1 -1
  27. package/dist/shade.js +33 -69
  28. package/dist/shade.js.map +1 -1
  29. package/dist/shades.integration.spec.js +197 -187
  30. package/dist/shades.integration.spec.js.map +1 -1
  31. package/package.json +5 -5
  32. package/src/component-factory.spec.tsx +7 -7
  33. package/src/components/lazy-load.tsx +19 -15
  34. package/src/components/route-link.spec.tsx +2 -2
  35. package/src/components/route-link.tsx +11 -10
  36. package/src/components/router.spec.tsx +2 -2
  37. package/src/components/router.tsx +32 -32
  38. package/src/jsx.ts +3 -2
  39. package/src/models/render-options.ts +37 -9
  40. package/src/services/location-service.spec.ts +1 -1
  41. package/src/services/location-service.tsx +18 -4
  42. package/src/services/resource-manager.spec.ts +33 -0
  43. package/src/services/resource-manager.ts +60 -0
  44. package/src/shade-component.ts +35 -15
  45. package/src/shade-resources.integration.spec.tsx +8 -14
  46. package/src/shade.ts +34 -107
  47. package/src/shades.integration.spec.tsx +265 -252
  48. package/types/components/lazy-load.d.ts +1 -1
  49. package/types/components/lazy-load.d.ts.map +1 -1
  50. package/types/components/route-link.d.ts +1 -1
  51. package/types/components/route-link.d.ts.map +1 -1
  52. package/types/components/router.d.ts +6 -8
  53. package/types/components/router.d.ts.map +1 -1
  54. package/types/jsx.d.ts +3 -2
  55. package/types/jsx.d.ts.map +1 -1
  56. package/types/models/render-options.d.ts +7 -7
  57. package/types/models/render-options.d.ts.map +1 -1
  58. package/types/services/location-service.d.ts +12 -1
  59. package/types/services/location-service.d.ts.map +1 -1
  60. package/types/services/resource-manager.d.ts +16 -0
  61. package/types/services/resource-manager.d.ts.map +1 -0
  62. package/types/services/resource-manager.spec.d.ts +2 -0
  63. package/types/services/resource-manager.spec.d.ts.map +1 -0
  64. package/types/shade-component.d.ts +16 -5
  65. package/types/shade-component.d.ts.map +1 -1
  66. package/types/shade.d.ts +8 -27
  67. package/types/shade.d.ts.map +1 -1
package/src/shade.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { Disposable } from '@furystack/utils'
2
2
  import { Injector } from '@furystack/inject'
3
- import type { ChildrenList, PartialElement, RenderOptions } from './models'
3
+ import type { ChildrenList, RenderOptions } from './models'
4
+ import { ResourceManager } from './services/resource-manager'
4
5
 
5
- export type ShadeOptions<TProps, TState> = {
6
+ export type ShadeOptions<TProps> = {
6
7
  /**
7
8
  * Explicit shadow dom name. Will fall back to 'shade-{guid}' if not provided
8
9
  */
@@ -11,48 +12,30 @@ export type ShadeOptions<TProps, TState> = {
11
12
  /**
12
13
  * Render hook, this method will be executed on each and every render.
13
14
  */
14
- render: (options: RenderOptions<TProps, TState>) => JSX.Element | string | null
15
+ render: (options: RenderOptions<TProps>) => JSX.Element | string | null
15
16
 
16
17
  /**
17
18
  * Construct hook. Will be executed once when the element has been constructed and initialized
18
19
  */
19
20
  constructed?: (
20
- options: RenderOptions<TProps, TState>,
21
+ options: RenderOptions<TProps>,
21
22
  ) => void | undefined | (() => void) | Promise<void | undefined | (() => void)>
22
23
 
23
24
  /**
24
25
  * Will be executed when the element is attached to the DOM.
25
26
  */
26
- onAttach?: (options: RenderOptions<TProps, TState>) => void
27
+ onAttach?: (options: RenderOptions<TProps>) => void
27
28
 
28
29
  /**
29
30
  * Will be executed when the element is detached from the DOM.
30
31
  */
31
- onDetach?: (options: RenderOptions<TProps, TState>) => void
32
+ onDetach?: (options: RenderOptions<TProps>) => void
32
33
 
33
34
  /**
34
35
  * A factory method that creates a list of disposable resources that will be disposed when the element is detached.
35
36
  */
36
- resources?: (options: RenderOptions<TProps, TState>) => Disposable[]
37
-
38
- /**
39
- * An optional method that checks the state for changes and returns true if the element should be rerendered. This will not be called if `skipRender` is set to true in the relevant `updateState()` call.
40
- */
41
- compareState?: (options: {
42
- oldState: TState
43
- newState: TState
44
- props: TProps
45
- element: HTMLElement
46
- injector: Injector
47
- }) => boolean
48
- } & (unknown extends TState
49
- ? {}
50
- : {
51
- /**
52
- * The initial state of the component
53
- */
54
- getInitialState: (options: { injector: Injector; props: TProps }) => TState
55
- })
37
+ resources?: (options: RenderOptions<TProps>) => Disposable[]
38
+ }
56
39
 
57
40
  /**
58
41
  * Factory method for creating Shade components
@@ -60,7 +43,7 @@ export type ShadeOptions<TProps, TState> = {
60
43
  * @param o for component creation
61
44
  * @returns the JSX element
62
45
  */
63
- export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>) => {
46
+ export const Shade = <TProps>(o: ShadeOptions<TProps>) => {
64
47
  // register shadow-dom element
65
48
  const customElementName = o.shadowDomName
66
49
 
@@ -69,11 +52,7 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
69
52
  customElements.define(
70
53
  customElementName,
71
54
  class extends HTMLElement implements JSX.Element {
72
- private compareState =
73
- o.compareState ||
74
- (({ oldState, newState }: { oldState: TState; newState: TState }) =>
75
- Object.entries(oldState as object).some(([key, value]) => value !== newState[key as keyof TState]) ||
76
- Object.entries(newState as object).some(([key, value]) => value !== oldState[key as keyof TState]))
55
+ public resourceManager = new ResourceManager()
77
56
 
78
57
  public connectedCallback() {
79
58
  o.onAttach && o.onAttach(this.getRenderOptions())
@@ -82,19 +61,14 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
82
61
 
83
62
  public disconnectedCallback() {
84
63
  o.onDetach && o.onDetach(this.getRenderOptions())
85
- Object.values(this.resources).forEach((s) => s.dispose())
64
+ this.resourceManager.dispose()
86
65
  this.cleanup && this.cleanup()
87
66
  }
88
67
 
89
68
  /**
90
69
  * Will be triggered when updating the external props object
91
70
  */
92
- public props: TProps & { children?: JSX.Element[] }
93
-
94
- /**
95
- * Will be triggered on state update
96
- */
97
- public state!: TState
71
+ public props!: TProps & { children?: JSX.Element[] }
98
72
 
99
73
  /**
100
74
  * Will be updated when on children change
@@ -105,55 +79,26 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
105
79
  * @param options Options for rendering the component
106
80
  * @returns the JSX element
107
81
  */
108
- public render = (options: RenderOptions<TProps, TState>) => o.render(options)
82
+ public render = (options: RenderOptions<TProps>) => o.render(options)
109
83
 
110
84
  /**
111
85
  * @returns values for the current render options
112
86
  */
113
- private getRenderOptions = (): RenderOptions<TProps, TState> => {
114
- const props: TProps = { ...this.props }
115
- const getState = () => ({ ...this.state })
116
- const updateState = (stateChanges: PartialElement<TState>, skipRender?: boolean) => {
117
- const oldState = { ...this.state }
118
- const newState = { ...oldState, ...stateChanges }
119
-
120
- this.state = newState
121
-
122
- if (
123
- !skipRender &&
124
- this.compareState({
125
- oldState,
126
- newState,
127
- props,
128
- element: this,
129
- injector: this.injector,
130
- })
131
- ) {
132
- this.updateComponent()
133
- }
87
+ private getRenderOptions = (): RenderOptions<TProps> => {
88
+ const renderOptions: RenderOptions<TProps> = {
89
+ props: this.props,
90
+ injector: this.injector,
91
+
92
+ children: this.shadeChildren,
93
+ element: this,
94
+ useObservable: (key, obesrvable, callback, getLast) =>
95
+ this.resourceManager.useObservable(key, obesrvable, callback || (() => this.updateComponent()), getLast),
96
+ useState: (key, initialValue) =>
97
+ this.resourceManager.useState(key, initialValue, this.updateComponent.bind(this)),
98
+ useDisposable: this.resourceManager.useDisposable.bind(this.resourceManager),
134
99
  }
135
100
 
136
- const returnValue = {
137
- ...{
138
- props,
139
- injector: this.injector,
140
-
141
- children: this.shadeChildren,
142
- element: this,
143
- },
144
- ...((o as any).getInitialState
145
- ? {
146
- getState,
147
- updateState,
148
- }
149
- : {}),
150
- } as any as RenderOptions<TProps, TState>
151
-
152
- return returnValue
153
- }
154
-
155
- private createResources() {
156
- this.resources.push(...(o.resources?.(this.getRenderOptions()) || []))
101
+ return renderOptions as RenderOptions<TProps>
157
102
  }
158
103
 
159
104
  /**
@@ -162,32 +107,27 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
162
107
  public updateComponent() {
163
108
  const renderResult = this.render(this.getRenderOptions())
164
109
 
165
- if (renderResult === null) {
110
+ if (renderResult === null || renderResult === undefined) {
166
111
  this.innerHTML = ''
167
112
  }
168
113
 
169
- if (typeof renderResult === 'string') {
114
+ if (typeof renderResult === 'string' || typeof renderResult === 'number') {
170
115
  this.innerHTML = renderResult
171
116
  }
172
117
 
173
- if (renderResult instanceof DocumentFragment) {
174
- this.replaceChildren(...renderResult.children)
175
- }
176
-
177
118
  if (renderResult instanceof HTMLElement) {
178
119
  this.replaceChildren(renderResult)
179
120
  }
121
+ if (renderResult instanceof DocumentFragment) {
122
+ this.replaceChildren(renderResult)
123
+ }
180
124
  }
181
125
 
182
126
  /**
183
127
  * Finialize the component initialization after it gets the Props. Called by the framework internally
184
128
  */
185
129
  public callConstructed() {
186
- ;(o as any).getInitialState &&
187
- (this.state = (o as any).getInitialState({ props: { ...this.props }, injector: this.injector }))
188
-
189
130
  this.updateComponent()
190
- this.createResources()
191
131
  const cleanupResult = o.constructed && o.constructed(this.getRenderOptions())
192
132
  if (cleanupResult instanceof Promise) {
193
133
  cleanupResult.then((cleanup) => (this.cleanup = cleanup))
@@ -216,11 +156,6 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
216
156
  return this._injector
217
157
  }
218
158
 
219
- const fromState = (this.state as any)?.injector
220
- if (fromState && fromState instanceof Injector) {
221
- return fromState
222
- }
223
-
224
159
  const fromProps = (this.props as any)?.injector
225
160
  if (fromProps && fromProps instanceof Injector) {
226
161
  return fromProps
@@ -238,13 +173,6 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
238
173
  public set injector(i: Injector) {
239
174
  this._injector = i
240
175
  }
241
-
242
- private resources: Disposable[] = []
243
-
244
- constructor(_props: TProps & { children?: JSX.Element[] }) {
245
- super()
246
- this.props = _props
247
- }
248
176
  },
249
177
  )
250
178
  } else {
@@ -254,9 +182,8 @@ export const Shade = <TProps, TState = unknown>(o: ShadeOptions<TProps, TState>)
254
182
  return (props: TProps, children: ChildrenList) => {
255
183
  const el = document.createElement(customElementName, {
256
184
  ...(props as TProps & ElementCreationOptions),
257
- }) as JSX.Element<TProps, TState>
258
- el.props = props
259
-
185
+ }) as JSX.Element<TProps>
186
+ el.props = props || ({} as TProps)
260
187
  el.shadeChildren = children
261
188
  return el as JSX.Element
262
189
  }