visualfries 0.1.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 (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/dist/DIContainer.d.ts +4 -0
  4. package/dist/DIContainer.js +145 -0
  5. package/dist/SceneBuilder.svelte.d.ts +8574 -0
  6. package/dist/SceneBuilder.svelte.js +409 -0
  7. package/dist/adapters/subtitleHelpers.d.ts +2 -0
  8. package/dist/adapters/subtitleHelpers.js +187 -0
  9. package/dist/animations/AnimationContext.d.ts +17 -0
  10. package/dist/animations/AnimationContext.js +72 -0
  11. package/dist/animations/AnimationPresetsRegister.d.ts +362 -0
  12. package/dist/animations/AnimationPresetsRegister.js +20 -0
  13. package/dist/animations/AnimationSetup.d.ts +8 -0
  14. package/dist/animations/AnimationSetup.js +30 -0
  15. package/dist/animations/SplitTextCache.d.ts +28 -0
  16. package/dist/animations/SplitTextCache.js +68 -0
  17. package/dist/animations/animationBuilder.d.ts +31 -0
  18. package/dist/animations/animationBuilder.js +255 -0
  19. package/dist/animations/animationPreset.d.ts +7 -0
  20. package/dist/animations/animationPreset.js +31 -0
  21. package/dist/animations/builders/AnimationPresetFactory.d.ts +43 -0
  22. package/dist/animations/builders/AnimationPresetFactory.js +139 -0
  23. package/dist/animations/builders/LineHighlighterAnimationBuilder.d.ts +16 -0
  24. package/dist/animations/builders/LineHighlighterAnimationBuilder.js +183 -0
  25. package/dist/animations/builders/WordHighlighterAnimationBuilder.d.ts +15 -0
  26. package/dist/animations/builders/WordHighlighterAnimationBuilder.js +180 -0
  27. package/dist/animations/engines/AnimationEngineAdaptor.d.ts +107 -0
  28. package/dist/animations/engines/AnimationEngineAdaptor.js +1 -0
  29. package/dist/animations/engines/GSAPEngineAdaptor.d.ts +21 -0
  30. package/dist/animations/engines/GSAPEngineAdaptor.js +145 -0
  31. package/dist/animations/presets/index.d.ts +2 -0
  32. package/dist/animations/presets/index.js +3 -0
  33. package/dist/animations/presets/lines.d.ts +52 -0
  34. package/dist/animations/presets/lines.js +547 -0
  35. package/dist/animations/presets/words.d.ts +31 -0
  36. package/dist/animations/presets/words.js +268 -0
  37. package/dist/animations/transformers/AnimationReferenceTransformer.d.ts +9 -0
  38. package/dist/animations/transformers/AnimationReferenceTransformer.js +114 -0
  39. package/dist/builders/PixiComponentBuilder.d.ts +63 -0
  40. package/dist/builders/PixiComponentBuilder.js +112 -0
  41. package/dist/builders/_ComponentState.svelte.d.ts +795 -0
  42. package/dist/builders/_ComponentState.svelte.js +203 -0
  43. package/dist/builders/html/HtmlBuilder.d.ts +66 -0
  44. package/dist/builders/html/HtmlBuilder.js +171 -0
  45. package/dist/builders/html/HtmlBuilderFactory.d.ts +27 -0
  46. package/dist/builders/html/HtmlBuilderFactory.js +30 -0
  47. package/dist/builders/html/StyleBuilder.d.ts +13 -0
  48. package/dist/builders/html/StyleBuilder.js +133 -0
  49. package/dist/builders/html/StyleProcessor.d.ts +9 -0
  50. package/dist/builders/html/StyleProcessor.js +1 -0
  51. package/dist/builders/html/TextComponentHtmlBuilder.d.ts +16 -0
  52. package/dist/builders/html/TextComponentHtmlBuilder.js +93 -0
  53. package/dist/builders/html/TextShadowBuilder.d.ts +60 -0
  54. package/dist/builders/html/TextShadowBuilder.js +227 -0
  55. package/dist/builders/html/processors/AppearanceStyleProcessor.d.ts +5 -0
  56. package/dist/builders/html/processors/AppearanceStyleProcessor.js +57 -0
  57. package/dist/builders/html/processors/TextAppearanceStyleProcessor.d.ts +5 -0
  58. package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +37 -0
  59. package/dist/builders/html/processors/TextEffectsStyleProcessor.d.ts +6 -0
  60. package/dist/builders/html/processors/TextEffectsStyleProcessor.js +68 -0
  61. package/dist/commands/Command.d.ts +6 -0
  62. package/dist/commands/Command.js +1 -0
  63. package/dist/commands/CommandRunner.d.ts +28 -0
  64. package/dist/commands/CommandRunner.js +81 -0
  65. package/dist/commands/CommandTypes.d.ts +11 -0
  66. package/dist/commands/CommandTypes.js +13 -0
  67. package/dist/commands/PauseCommand.d.ts +4 -0
  68. package/dist/commands/PauseCommand.js +5 -0
  69. package/dist/commands/PlayCommand.d.ts +4 -0
  70. package/dist/commands/PlayCommand.js +6 -0
  71. package/dist/commands/RenderCommand.d.ts +15 -0
  72. package/dist/commands/RenderCommand.js +18 -0
  73. package/dist/commands/RenderFrameCommand.d.ts +17 -0
  74. package/dist/commands/RenderFrameCommand.js +93 -0
  75. package/dist/commands/ReplaceSourceOnTimeCommand.d.ts +4 -0
  76. package/dist/commands/ReplaceSourceOnTimeCommand.js +22 -0
  77. package/dist/commands/SeekCommand.d.ts +15 -0
  78. package/dist/commands/SeekCommand.js +39 -0
  79. package/dist/commands/UpdateComponentCommand.d.ts +4 -0
  80. package/dist/commands/UpdateComponentCommand.js +17 -0
  81. package/dist/components/AnimatedGIF.d.ts +201 -0
  82. package/dist/components/AnimatedGIF.js +391 -0
  83. package/dist/components/Component.svelte.d.ts +33 -0
  84. package/dist/components/Component.svelte.js +152 -0
  85. package/dist/components/ComponentContext.svelte.d.ts +33 -0
  86. package/dist/components/ComponentContext.svelte.js +105 -0
  87. package/dist/components/hooks/AnimationHook.d.ts +25 -0
  88. package/dist/components/hooks/AnimationHook.js +180 -0
  89. package/dist/components/hooks/CanvasShapeHook.d.ts +12 -0
  90. package/dist/components/hooks/CanvasShapeHook.js +229 -0
  91. package/dist/components/hooks/HtmlAnimationHook.d.ts +8 -0
  92. package/dist/components/hooks/HtmlAnimationHook.js +70 -0
  93. package/dist/components/hooks/HtmlTextHook.d.ts +16 -0
  94. package/dist/components/hooks/HtmlTextHook.js +102 -0
  95. package/dist/components/hooks/HtmlToCanvasHook.d.ts +16 -0
  96. package/dist/components/hooks/HtmlToCanvasHook.js +148 -0
  97. package/dist/components/hooks/ImageHook.d.ts +10 -0
  98. package/dist/components/hooks/ImageHook.js +45 -0
  99. package/dist/components/hooks/MediaHook.d.ts +15 -0
  100. package/dist/components/hooks/MediaHook.js +252 -0
  101. package/dist/components/hooks/MediaSeekingHook.d.ts +12 -0
  102. package/dist/components/hooks/MediaSeekingHook.js +204 -0
  103. package/dist/components/hooks/PixiDisplayObjectHook.d.ts +15 -0
  104. package/dist/components/hooks/PixiDisplayObjectHook.js +77 -0
  105. package/dist/components/hooks/PixiGifHook.d.ts +15 -0
  106. package/dist/components/hooks/PixiGifHook.js +97 -0
  107. package/dist/components/hooks/PixiProgressShapeHook.d.ts +12 -0
  108. package/dist/components/hooks/PixiProgressShapeHook.js +128 -0
  109. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.d.ts +21 -0
  110. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +210 -0
  111. package/dist/components/hooks/PixiTextureHook.d.ts +7 -0
  112. package/dist/components/hooks/PixiTextureHook.js +29 -0
  113. package/dist/components/hooks/PixiVideoTextureHook.d.ts +10 -0
  114. package/dist/components/hooks/PixiVideoTextureHook.js +35 -0
  115. package/dist/components/hooks/SubtitlesHook.d.ts +88 -0
  116. package/dist/components/hooks/SubtitlesHook.js +199 -0
  117. package/dist/components/hooks/VerifyGifHook.d.ts +7 -0
  118. package/dist/components/hooks/VerifyGifHook.js +27 -0
  119. package/dist/components/hooks/VerifyImageHook.d.ts +7 -0
  120. package/dist/components/hooks/VerifyImageHook.js +27 -0
  121. package/dist/components/hooks/VerifyMediaHook.d.ts +7 -0
  122. package/dist/components/hooks/VerifyMediaHook.js +21 -0
  123. package/dist/components/hooks/shapes/progress/CustomProgressRenderer.d.ts +8 -0
  124. package/dist/components/hooks/shapes/progress/CustomProgressRenderer.js +53 -0
  125. package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.d.ts +8 -0
  126. package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.js +69 -0
  127. package/dist/components/hooks/shapes/progress/LinearProgressRenderer.d.ts +8 -0
  128. package/dist/components/hooks/shapes/progress/LinearProgressRenderer.js +60 -0
  129. package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.d.ts +9 -0
  130. package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.js +213 -0
  131. package/dist/components/hooks/shapes/progress/ProgressRenderer.d.ts +17 -0
  132. package/dist/components/hooks/shapes/progress/ProgressRenderer.js +75 -0
  133. package/dist/components/hooks/shapes/progress/RadialProgressRenderer.d.ts +8 -0
  134. package/dist/components/hooks/shapes/progress/RadialProgressRenderer.js +50 -0
  135. package/dist/components/hooks/shapes/progress/index.d.ts +6 -0
  136. package/dist/components/hooks/shapes/progress/index.js +6 -0
  137. package/dist/composers/componentComposer.d.ts +55 -0
  138. package/dist/composers/componentComposer.js +118 -0
  139. package/dist/composers/layerComposer.d.ts +46 -0
  140. package/dist/composers/layerComposer.js +79 -0
  141. package/dist/composers/sceneComposer.d.ts +48 -0
  142. package/dist/composers/sceneComposer.js +92 -0
  143. package/dist/constants.d.ts +12 -0
  144. package/dist/constants.js +14 -0
  145. package/dist/directors/ComponentDirector.d.ts +20 -0
  146. package/dist/directors/ComponentDirector.js +86 -0
  147. package/dist/factories/SceneBuilderFactory.d.ts +15 -0
  148. package/dist/factories/SceneBuilderFactory.js +51 -0
  149. package/dist/fonts/GoogleFontsProvider.d.ts +12 -0
  150. package/dist/fonts/GoogleFontsProvider.js +125 -0
  151. package/dist/fonts/fontLoader.d.ts +15 -0
  152. package/dist/fonts/fontLoader.js +41 -0
  153. package/dist/fonts/types.d.ts +1 -0
  154. package/dist/fonts/types.js +1 -0
  155. package/dist/index.d.ts +11 -0
  156. package/dist/index.js +14 -0
  157. package/dist/layers/Layer.svelte.d.ts +8492 -0
  158. package/dist/layers/Layer.svelte.js +125 -0
  159. package/dist/managers/AppManager.svelte.d.ts +23 -0
  160. package/dist/managers/AppManager.svelte.js +89 -0
  161. package/dist/managers/ComponentsManager.svelte.d.ts +49 -0
  162. package/dist/managers/ComponentsManager.svelte.js +247 -0
  163. package/dist/managers/DomManager.d.ts +18 -0
  164. package/dist/managers/DomManager.js +73 -0
  165. package/dist/managers/EventManager.d.ts +7 -0
  166. package/dist/managers/EventManager.js +22 -0
  167. package/dist/managers/LayersManager.svelte.d.ts +8499 -0
  168. package/dist/managers/LayersManager.svelte.js +176 -0
  169. package/dist/managers/MediaManager.d.ts +32 -0
  170. package/dist/managers/MediaManager.js +243 -0
  171. package/dist/managers/RenderManager.d.ts +23 -0
  172. package/dist/managers/RenderManager.js +59 -0
  173. package/dist/managers/StateManager.svelte.d.ts +8746 -0
  174. package/dist/managers/StateManager.svelte.js +272 -0
  175. package/dist/managers/SubtitlesManager.svelte.d.ts +261 -0
  176. package/dist/managers/SubtitlesManager.svelte.js +1385 -0
  177. package/dist/managers/TimeManager.svelte.d.ts +6 -0
  178. package/dist/managers/TimeManager.svelte.js +18 -0
  179. package/dist/managers/TimelineManager.svelte.d.ts +25 -0
  180. package/dist/managers/TimelineManager.svelte.js +152 -0
  181. package/dist/registers.d.ts +12 -0
  182. package/dist/registers.js +29 -0
  183. package/dist/schemas/runtime/index.d.ts +3 -0
  184. package/dist/schemas/runtime/index.js +4 -0
  185. package/dist/schemas/runtime/types.d.ts +323 -0
  186. package/dist/schemas/runtime/types.js +12 -0
  187. package/dist/schemas/scene/animations.d.ts +89738 -0
  188. package/dist/schemas/scene/animations.js +211 -0
  189. package/dist/schemas/scene/components.js +515 -0
  190. package/dist/schemas/scene/core.js +160 -0
  191. package/dist/schemas/scene/index.d.ts +22 -0
  192. package/dist/schemas/scene/index.js +10 -0
  193. package/dist/schemas/scene/properties.d.ts +914 -0
  194. package/dist/schemas/scene/properties.js +398 -0
  195. package/dist/schemas/scene/subtitles.d.ts +1141 -0
  196. package/dist/schemas/scene/subtitles.js +111 -0
  197. package/dist/schemas/scene/utils.d.ts +1 -0
  198. package/dist/schemas/scene/utils.js +5 -0
  199. package/dist/seeds/SeedFactory.d.ts +59 -0
  200. package/dist/seeds/SeedFactory.js +99 -0
  201. package/dist/seeds/index.d.ts +8 -0
  202. package/dist/seeds/index.js +8 -0
  203. package/dist/transformers/ColorTransformer.d.ts +5 -0
  204. package/dist/transformers/ColorTransformer.js +67 -0
  205. package/dist/transformers/PixiColorTransformer.d.ts +22 -0
  206. package/dist/transformers/PixiColorTransformer.js +104 -0
  207. package/dist/utils/canvas.d.ts +6 -0
  208. package/dist/utils/canvas.js +18 -0
  209. package/dist/utils/document.d.ts +2 -0
  210. package/dist/utils/document.js +36 -0
  211. package/dist/utils/emoji.d.ts +10 -0
  212. package/dist/utils/emoji.js +51 -0
  213. package/dist/utils/html.d.ts +4 -0
  214. package/dist/utils/html.js +45 -0
  215. package/dist/utils/svgGenerator.d.ts +20 -0
  216. package/dist/utils/svgGenerator.js +103 -0
  217. package/dist/utils/utils.d.ts +5 -0
  218. package/dist/utils/utils.js +125 -0
  219. package/package.json +96 -0
@@ -0,0 +1,203 @@
1
+ import { EventManager } from '../managers/EventManager.js';
2
+ import { StateManager } from '../managers/StateManager.svelte.js';
3
+ import { merge } from 'lodash-es';
4
+ import md5 from 'md5';
5
+ export class ComponentState {
6
+ #data = $state();
7
+ eventManager;
8
+ sceneState;
9
+ refreshCallback;
10
+ constructor(cradle) {
11
+ this.#data = cradle.componentData;
12
+ this.eventManager = cradle.eventManager;
13
+ this.sceneState = cradle.stateManager;
14
+ }
15
+ setRefreshCallback(callback) {
16
+ this.refreshCallback = callback;
17
+ }
18
+ async maybeAutoRefresh() {
19
+ if (this.refreshCallback) {
20
+ try {
21
+ await this.refreshCallback();
22
+ }
23
+ catch (error) {
24
+ console.warn('Auto-refresh callback failed:', error);
25
+ // Don't re-throw to avoid breaking the update operation
26
+ }
27
+ }
28
+ }
29
+ get id() {
30
+ return this.#data.id;
31
+ }
32
+ get type() {
33
+ return this.#data.type;
34
+ }
35
+ get name() {
36
+ return (this.#data.name ??
37
+ this.#data.type.charAt(0).toUpperCase() + this.#data.type.slice(1) + ' Component');
38
+ }
39
+ get start_at() {
40
+ return this.#data.timeline.startAt;
41
+ }
42
+ get end_at() {
43
+ return this.#data.timeline.endAt;
44
+ }
45
+ set start_at(time) {
46
+ this.#data.timeline.startAt = time;
47
+ }
48
+ set end_at(time) {
49
+ this.#data.timeline.endAt = time;
50
+ }
51
+ set name(name) {
52
+ this.#data.name = name;
53
+ }
54
+ get order() {
55
+ return this.#data.order || 1;
56
+ }
57
+ get visible() {
58
+ return this.#data.visible ? this.#data.visible : true;
59
+ }
60
+ get duration() {
61
+ return this.#data.timeline.endAt - this.#data.timeline.startAt;
62
+ }
63
+ get asset_id() {
64
+ // TODO
65
+ return '';
66
+ // return this.#data!.source.assetId;
67
+ }
68
+ get timeline() {
69
+ return this.#data.timeline;
70
+ }
71
+ get appearance() {
72
+ return this.#data.appearance;
73
+ }
74
+ get animations() {
75
+ return this.#data.animations ?? {};
76
+ }
77
+ get effects() {
78
+ return this.#data.effects ?? {};
79
+ }
80
+ get checksum() {
81
+ return (this.id +
82
+ '-' +
83
+ md5(JSON.stringify({
84
+ ...$state.snapshot(this.#data)
85
+ // element: {
86
+ // ...this.#data!.element,
87
+ // path: undefined
88
+ // }
89
+ })));
90
+ }
91
+ #emitChange() {
92
+ this.#data.checksum = md5(JSON.stringify(this.#data)).slice(0, 8);
93
+ this.eventManager.emit('componentchange', this.getData());
94
+ }
95
+ getData() {
96
+ return {
97
+ ...$state.snapshot(this.#data),
98
+ order: this.order,
99
+ // checksum: this.checksum,
100
+ visible: this.visible
101
+ };
102
+ }
103
+ setData(data) {
104
+ const id = this.id;
105
+ const type = this.type;
106
+ const newData = $state({ ...data, id, type });
107
+ this.#data = newData;
108
+ this.#emitChange();
109
+ }
110
+ #changeVideoStart(diff) {
111
+ if (this.type === 'VIDEO') {
112
+ let source = this.#data.source;
113
+ if (!source) {
114
+ source = {
115
+ startAt: 0
116
+ };
117
+ this.#data.source = source;
118
+ }
119
+ if (source.startAt !== undefined && source.startAt !== null) {
120
+ source.startAt += diff;
121
+ source.startAt = Math.max(0, source.startAt);
122
+ }
123
+ if (source.endAt !== undefined && source.endAt !== null) {
124
+ source.endAt += diff;
125
+ }
126
+ }
127
+ // TODO verify starting time is not beyond video duration
128
+ // const metadata = this.#data!.metadata
129
+ // ? (this.#data!.metadata as Metadata)
130
+ // : ({ starting_time: 0 } as Metadata);
131
+ // let startingTime = metadata.starting_time ? (metadata.starting_time as number) : 0;
132
+ // startingTime += diff;
133
+ // startingTime = Math.max(0, startingTime);
134
+ // this.updateMetadata({
135
+ // starting_time: startingTime
136
+ // });
137
+ }
138
+ setStart(start) {
139
+ const beforeStart = this.sceneState.transformTime(this.#data.timeline.startAt);
140
+ const newStart = this.sceneState.transformTime(start);
141
+ const diff = newStart - beforeStart;
142
+ if (diff !== 0) {
143
+ if (this.type === 'VIDEO') {
144
+ this.#changeVideoStart(diff);
145
+ }
146
+ this.#data.timeline.startAt = this.sceneState.transformTime(start);
147
+ this.#emitChange();
148
+ }
149
+ }
150
+ setEnd(end) {
151
+ this.#data.timeline.endAt = this.sceneState.transformTime(end);
152
+ this.#emitChange();
153
+ }
154
+ setStreamPath(path) {
155
+ // if (this.type === 'VIDEO' || this.type === 'AUDIO') {
156
+ // this.#data!.element.stream_path = path;
157
+ // this.#emitChange();
158
+ // }
159
+ }
160
+ async updateText(text) {
161
+ if (this.type === 'TEXT') {
162
+ this.#data.text = text;
163
+ this.#emitChange();
164
+ await this.maybeAutoRefresh();
165
+ }
166
+ }
167
+ update(data) {
168
+ console.warn('update not implemented yet', data);
169
+ // const newConfig = {
170
+ // ...this.#data!.element.config,
171
+ // ...data
172
+ // };
173
+ // const res = PlacableConfigShape.safeParse(newConfig);
174
+ // if (res.success) {
175
+ // this.#data!.element.config = newConfig;
176
+ // this.#emitChange();
177
+ // } else {
178
+ // console.error('Error updating component data', res.error);
179
+ // }
180
+ }
181
+ async updateAppearance(appearance) {
182
+ const mergedAppearance = merge({}, this.#data.appearance, appearance);
183
+ this.#data = { ...this.#data, appearance: mergedAppearance };
184
+ this.#emitChange();
185
+ await this.maybeAutoRefresh();
186
+ }
187
+ async setVisible(visible) {
188
+ if (this.#data.visible !== visible) {
189
+ this.#data.visible = visible;
190
+ this.#emitChange();
191
+ await this.maybeAutoRefresh();
192
+ }
193
+ }
194
+ async setOrder(order) {
195
+ if (this.#data.order !== order) {
196
+ this.#data.order = order;
197
+ // Note: Emitting change here might trigger frequent updates if order changes often.
198
+ // Consider if the parent manager should handle order changes and emit less frequently.
199
+ this.#emitChange();
200
+ await this.maybeAutoRefresh();
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Represents a flexible way to define HTML element styles.
3
+ * It uses Partial<CSSStyleDeclaration> for known CSS properties
4
+ * and allows any string key for custom properties or less common ones.
5
+ */
6
+ export type HtmlElementStyle = Omit<Partial<CSSStyleDeclaration>, 'length' | 'parentRule' | 'getPropertyPriority' | 'getPropertyValue' | 'item' | 'removeProperty' | 'setProperty'> & Record<string, string | number | undefined>;
7
+ /**
8
+ * Configuration for the wrapper HTML element.
9
+ */
10
+ export interface WrapperConfig {
11
+ id?: string;
12
+ style?: HtmlElementStyle;
13
+ }
14
+ /**
15
+ * Configuration for the inner HTML element.
16
+ */
17
+ export interface ElementConfig {
18
+ id?: string;
19
+ classList?: string[];
20
+ dir?: 'auto' | 'ltr' | 'rtl';
21
+ innerHTML?: string;
22
+ innerText?: string;
23
+ style?: HtmlElementStyle;
24
+ }
25
+ export declare class HtmlBuilder {
26
+ private wrapper;
27
+ private element;
28
+ private document;
29
+ constructor(document: Document);
30
+ private applyDefaultWrapperStyles;
31
+ private applyDefaultElementStyles;
32
+ /**
33
+ * Configures the wrapper element.
34
+ */
35
+ withWrapper(config: WrapperConfig): HtmlBuilder;
36
+ /**
37
+ * Configures the inner element.
38
+ */
39
+ withElement(config: ElementConfig): HtmlBuilder;
40
+ /**
41
+ * Builds and returns the wrapper and inner HTML elements.
42
+ * Ensures the inner element is a child of the wrapper.
43
+ */
44
+ build(): {
45
+ wrapper: HTMLElement;
46
+ element: HTMLElement;
47
+ };
48
+ /**
49
+ * Builds the elements and extracts inline styles to document-level CSS rules.
50
+ * Returns the elements with their inline styles converted to CSS classes.
51
+ */
52
+ buildAndExtractStyles(): {
53
+ wrapper: HTMLElement;
54
+ element: HTMLElement;
55
+ };
56
+ /**
57
+ * Extracts inline styles from an element and registers them as CSS rules in the document.
58
+ * Clears the inline styles after extraction.
59
+ * Special handling for -webkit-text-stroke properties which are registered to ::before pseudo-element.
60
+ */
61
+ private extractAndRegisterStyles;
62
+ /**
63
+ * Adds a CSS rule to the document's head or creates a style element if needed.
64
+ */
65
+ private addStyleToDocument;
66
+ }
@@ -0,0 +1,171 @@
1
+ import { sanitizeElement } from '../../utils/html.js';
2
+ export class HtmlBuilder {
3
+ wrapper;
4
+ element;
5
+ document;
6
+ constructor(document) {
7
+ this.document = document;
8
+ this.wrapper = this.document.createElement('div');
9
+ this.element = this.document.createElement('div');
10
+ this.applyDefaultWrapperStyles();
11
+ this.applyDefaultElementStyles();
12
+ }
13
+ applyDefaultWrapperStyles() {
14
+ this.wrapper.style.position = 'absolute';
15
+ this.wrapper.style.display = 'flex';
16
+ // Consider if top/left should be default 0px if not using transform for positioning
17
+ // this.wrapper.style.top = '0px';
18
+ // this.wrapper.style.left = '0px';
19
+ }
20
+ applyDefaultElementStyles() {
21
+ // The inner element is often positioned relative to the wrapper
22
+ this.element.style.position = 'relative'; // Or 'absolute' with top/left 0 if preferred
23
+ // this.element.style.display = 'flex';
24
+ this.element.dir = 'auto';
25
+ this.element.classList.add('con-el'); // Common class from your example
26
+ // this.element.style.width = '100%'; // Often inner element spans full wrapper width
27
+ // this.element.style.height = '100%'; // Often inner element spans full wrapper height
28
+ }
29
+ /**
30
+ * Configures the wrapper element.
31
+ */
32
+ withWrapper(config) {
33
+ if (config.id)
34
+ this.wrapper.id = config.id;
35
+ if (config.style) {
36
+ Object.assign(this.wrapper.style, config.style);
37
+ }
38
+ return this;
39
+ }
40
+ /**
41
+ * Configures the inner element.
42
+ */
43
+ withElement(config) {
44
+ if (config.id)
45
+ this.element.id = config.id;
46
+ if (config.classList) {
47
+ config.classList.forEach((cls) => {
48
+ if (!this.element.classList.contains(cls)) {
49
+ // Avoid duplicates if con-el is passed again
50
+ this.element.classList.add(cls);
51
+ }
52
+ });
53
+ }
54
+ if (config.dir)
55
+ this.element.dir = config.dir;
56
+ // innerHTML takes precedence over innerText if both are provided
57
+ if (config.innerHTML !== undefined) {
58
+ this.element.innerHTML = config.innerHTML;
59
+ }
60
+ else if (config.innerText !== undefined) {
61
+ this.element.innerText = config.innerText;
62
+ }
63
+ if (config.style) {
64
+ Object.assign(this.element.style, config.style);
65
+ }
66
+ return this;
67
+ }
68
+ /**
69
+ * Builds and returns the wrapper and inner HTML elements.
70
+ * Ensures the inner element is a child of the wrapper.
71
+ */
72
+ build() {
73
+ if (!this.wrapper.contains(this.element)) {
74
+ this.wrapper.appendChild(this.element);
75
+ }
76
+ return {
77
+ wrapper: sanitizeElement(this.wrapper),
78
+ element: sanitizeElement(this.element)
79
+ };
80
+ }
81
+ /**
82
+ * Builds the elements and extracts inline styles to document-level CSS rules.
83
+ * Returns the elements with their inline styles converted to CSS classes.
84
+ */
85
+ buildAndExtractStyles() {
86
+ if (!this.wrapper.contains(this.element)) {
87
+ this.wrapper.appendChild(this.element);
88
+ }
89
+ // Extract and register wrapper styles
90
+ if (this.wrapper.id) {
91
+ this.extractAndRegisterStyles(this.wrapper, this.wrapper.id);
92
+ }
93
+ // Extract and register element styles
94
+ if (this.element.id) {
95
+ this.extractAndRegisterStyles(this.element, this.element.id);
96
+ }
97
+ return { wrapper: this.wrapper, element: this.element };
98
+ }
99
+ /**
100
+ * Extracts inline styles from an element and registers them as CSS rules in the document.
101
+ * Clears the inline styles after extraction.
102
+ * Special handling for -webkit-text-stroke properties which are registered to ::before pseudo-element.
103
+ */
104
+ extractAndRegisterStyles(element, elementId) {
105
+ const inlineStyles = element.style;
106
+ const regularStyleProperties = [];
107
+ const beforeProperties = [];
108
+ // Collect all inline style properties and separate webkit-text-stroke properties
109
+ for (let i = 0; i < inlineStyles.length; i++) {
110
+ const property = inlineStyles.item(i);
111
+ const value = inlineStyles.getPropertyValue(property);
112
+ if (value) {
113
+ if (property.startsWith('-webkit-text-stroke')) {
114
+ beforeProperties.push(`${property}: ${value}`);
115
+ }
116
+ else {
117
+ regularStyleProperties.push(`${property}: ${value}`);
118
+ }
119
+ }
120
+ }
121
+ if (beforeProperties.length > 0) {
122
+ beforeProperties.push(`color: transparent`);
123
+ beforeProperties.push('content: "' + element.textContent + '"');
124
+ beforeProperties.push('position: absolute');
125
+ beforeProperties.push('top: 0');
126
+ beforeProperties.push('left: 0');
127
+ beforeProperties.push('paint-order: stroke');
128
+ }
129
+ // Register regular styles to the main element
130
+ if (regularStyleProperties.length > 0) {
131
+ const cssRule = `#${elementId} { ${regularStyleProperties.join('; ')} }`;
132
+ this.addStyleToDocument(cssRule);
133
+ }
134
+ // Register webkit-text-stroke properties to ::before pseudo-element
135
+ if (beforeProperties.length > 0) {
136
+ const pseudoRule = `#${elementId}::before { ${beforeProperties.join('; ')} }`;
137
+ this.addStyleToDocument(pseudoRule);
138
+ }
139
+ // Clear inline styles after extraction
140
+ element.style.cssText = '';
141
+ }
142
+ /**
143
+ * Adds a CSS rule to the document's head or creates a style element if needed.
144
+ */
145
+ addStyleToDocument(cssRule) {
146
+ // Try to find existing style element for this builder
147
+ let styleElement = this.document.getElementById('html-builder-styles');
148
+ if (!styleElement) {
149
+ // Create new style element if it doesn't exist
150
+ styleElement = this.document.createElement('style');
151
+ styleElement.id = 'html-builder-styles';
152
+ styleElement.type = 'text/css';
153
+ this.document.head.appendChild(styleElement);
154
+ }
155
+ // Add the CSS rule to the style element
156
+ if (styleElement.sheet) {
157
+ try {
158
+ styleElement.sheet.insertRule(cssRule, styleElement.sheet.cssRules.length);
159
+ }
160
+ catch (error) {
161
+ // Fallback: append as text content if insertRule fails
162
+ console.warn('Failed to insert CSS rule, using fallback method:', error);
163
+ styleElement.textContent += cssRule + '\n';
164
+ }
165
+ }
166
+ else {
167
+ // Fallback: append as text content
168
+ styleElement.textContent += cssRule + '\n';
169
+ }
170
+ }
171
+ }
@@ -0,0 +1,27 @@
1
+ import type { Component } from '../..';
2
+ /**
3
+ * Factory for creating the appropriate HTML builder based on component type.
4
+ *
5
+ * This factory simplifies the process of creating component-specific builders,
6
+ * allowing hooks to easily get the right builder without needing to know which
7
+ * concrete class to instantiate.
8
+ */
9
+ export declare class HtmlBuilderFactory {
10
+ /**
11
+ * Creates the appropriate builder for a given component.
12
+ *
13
+ * @param component The component to create a builder for
14
+ * @param document The document object to use for creating elements
15
+ * @returns A builder capable of creating HTML elements for the component
16
+ */
17
+ static createBuilder(component: Component, document: Document): {
18
+ build(): {
19
+ wrapper: HTMLElement;
20
+ element: HTMLElement;
21
+ };
22
+ buildAndExtractStyles(): {
23
+ wrapper: HTMLElement;
24
+ element: HTMLElement;
25
+ };
26
+ };
27
+ }
@@ -0,0 +1,30 @@
1
+ import { TextComponentHtmlBuilder } from './TextComponentHtmlBuilder.js';
2
+ /**
3
+ * Factory for creating the appropriate HTML builder based on component type.
4
+ *
5
+ * This factory simplifies the process of creating component-specific builders,
6
+ * allowing hooks to easily get the right builder without needing to know which
7
+ * concrete class to instantiate.
8
+ */
9
+ export class HtmlBuilderFactory {
10
+ /**
11
+ * Creates the appropriate builder for a given component.
12
+ *
13
+ * @param component The component to create a builder for
14
+ * @param document The document object to use for creating elements
15
+ * @returns A builder capable of creating HTML elements for the component
16
+ */
17
+ static createBuilder(component, document) {
18
+ switch (component.type) {
19
+ case 'TEXT':
20
+ return new TextComponentHtmlBuilder(component, document);
21
+ // Add cases for other component types as they're implemented
22
+ // case 'SUBTITLES':
23
+ // return new SubtitleComponentHtmlBuilder(component as SubtitleComponent, document);
24
+ // case 'SHAPE':
25
+ // return new ShapeComponentHtmlBuilder(component as ShapeComponent, document);
26
+ default:
27
+ throw new Error(`No HTML builder available for component type: ${component.type}`);
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,13 @@
1
+ import type { Component } from '../..';
2
+ export declare class StyleBuilder {
3
+ private component;
4
+ private processors;
5
+ private omitStyles;
6
+ private onlyStyles;
7
+ constructor(component: Component);
8
+ private prepareComponent;
9
+ omit(keys: string[]): void;
10
+ only(keys: string[]): void;
11
+ build(): Record<string, any>;
12
+ private _mergeStyles;
13
+ }
@@ -0,0 +1,133 @@
1
+ import { AppearanceStyleProcessor } from './processors/AppearanceStyleProcessor.js';
2
+ import { TextAppearanceStyleProcessor } from './processors/TextAppearanceStyleProcessor.js';
3
+ import { TextEffectsStyleProcessor } from './processors/TextEffectsStyleProcessor.js';
4
+ import { TextEffectPresetName } from './TextShadowBuilder.js';
5
+ export class StyleBuilder {
6
+ component;
7
+ // Using an array of a more general ProcessorEntry type or a union if strictly typed
8
+ processors;
9
+ omitStyles = [];
10
+ onlyStyles = [];
11
+ constructor(component) {
12
+ this.component = this.prepareComponent(component);
13
+ this.processors = [
14
+ {
15
+ name: 'appearance',
16
+ instance: new AppearanceStyleProcessor(),
17
+ getData: (comp) => comp.appearance ? comp.appearance : undefined
18
+ },
19
+ {
20
+ name: 'textAppearance',
21
+ instance: new TextAppearanceStyleProcessor(),
22
+ getData: (comp) => {
23
+ if (comp.type === 'TEXT' || comp.type === 'SUBTITLES') {
24
+ return comp.appearance?.text;
25
+ }
26
+ return undefined;
27
+ },
28
+ condition: (comp) => comp.type === 'TEXT' || comp.type === 'SUBTITLES'
29
+ },
30
+ {
31
+ name: 'textEffects',
32
+ instance: new TextEffectsStyleProcessor(),
33
+ getData: (comp) => {
34
+ if (comp.type === 'TEXT' || comp.type === 'SUBTITLES') {
35
+ return comp.effects?.map;
36
+ }
37
+ return undefined;
38
+ },
39
+ condition: (comp) => comp.type === 'TEXT' || comp.type === 'SUBTITLES'
40
+ }
41
+ ];
42
+ }
43
+ prepareComponent(c) {
44
+ const component = { ...c };
45
+ if (component.type === 'TEXT' || component.type === 'SUBTITLES') {
46
+ const { appearance } = component;
47
+ const textAppearance = appearance?.text;
48
+ if (textAppearance?.shadow) {
49
+ component.effects.map['textShadow'] = {
50
+ preset: TextEffectPresetName.DEFAULT,
51
+ enabled: textAppearance.shadow.enabled ? true : false,
52
+ color: typeof textAppearance.color === 'string'
53
+ ? textAppearance.color
54
+ : textAppearance.color.colors[0],
55
+ size: textAppearance.shadow.size,
56
+ blur: textAppearance.shadow.blur,
57
+ type: 'textShadow'
58
+ };
59
+ }
60
+ if (textAppearance?.outline) {
61
+ // TODO
62
+ component.effects.map['textOutline'] = {
63
+ preset: TextEffectPresetName.OUTLINE,
64
+ enabled: textAppearance.outline.enabled ? true : false,
65
+ size: textAppearance.outline.size,
66
+ color: textAppearance.outline.color
67
+ };
68
+ }
69
+ return component;
70
+ }
71
+ return component;
72
+ }
73
+ omit(keys) {
74
+ this.omitStyles = keys;
75
+ }
76
+ only(keys) {
77
+ this.onlyStyles = keys;
78
+ }
79
+ build() {
80
+ const finalStyles = {};
81
+ let processedSpecificLogic = false;
82
+ for (const processorEntry of this.processors) {
83
+ if (processorEntry.condition && !processorEntry.condition(this.component)) {
84
+ continue; // Skip processor if condition not met
85
+ }
86
+ const dataForProcessor = processorEntry.getData(this.component);
87
+ // Ensure data is not undefined if processor expects non-nullable, though current processors handle undefined.
88
+ const partialStyles = processorEntry.instance.process(dataForProcessor);
89
+ this._mergeStyles(finalStyles, partialStyles);
90
+ // Track if specific (conditional) logic was run
91
+ if (processorEntry.condition) {
92
+ processedSpecificLogic = true;
93
+ }
94
+ }
95
+ // If it's not a TEXT/SUBTITLES component and no specific logic was run (beyond base appearance)
96
+ if (!processedSpecificLogic &&
97
+ !(this.component.type === 'TEXT' || this.component.type === 'SUBTITLES')) {
98
+ // Check if only the unconditional 'appearance' processor ran
99
+ const ranProcessors = this.processors.filter((p) => !p.condition || p.condition(this.component));
100
+ if (ranProcessors.length === 1 && ranProcessors[0].name === 'appearance') {
101
+ console.warn(`StyleBuilder: Fallback styling for component type '${this.component.type}'. Only base appearance processed.`);
102
+ }
103
+ }
104
+ // Remove the omitted styles from the final styles
105
+ this.omitStyles.forEach((key) => {
106
+ delete finalStyles[key];
107
+ });
108
+ if (this.onlyStyles.length > 0) {
109
+ Object.keys(finalStyles).forEach((key) => {
110
+ if (!this.onlyStyles.includes(key)) {
111
+ delete finalStyles[key];
112
+ }
113
+ });
114
+ }
115
+ return finalStyles;
116
+ }
117
+ _mergeStyles(targetStyles, sourceStyles) {
118
+ for (const [key, value] of Object.entries(sourceStyles)) {
119
+ if (value === undefined || value === null)
120
+ continue;
121
+ if (key === 'textShadow') {
122
+ targetStyles[key] = targetStyles[key] ? `${targetStyles[key]}, ${value}` : value;
123
+ }
124
+ else if (key === 'transform') {
125
+ // Ensure space separation for multiple transform functions
126
+ targetStyles[key] = targetStyles[key] ? `${targetStyles[key]} ${value}` : value;
127
+ }
128
+ else {
129
+ targetStyles[key] = value; // Default: overwrite
130
+ }
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,9 @@
1
+ import type { Component } from '../..';
2
+ export interface StyleProcessor<K = Component> {
3
+ /**
4
+ * Processes a part of the component's data to generate styles.
5
+ * @param data The specific data part (e.g., appearance, text properties) needed by this processor.
6
+ * @returns A record of CSS style properties generated by this processor.
7
+ */
8
+ process(data: K): Record<string, any>;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { TextComponent } from '../..';
2
+ export declare class TextComponentHtmlBuilder {
3
+ private component;
4
+ private document;
5
+ constructor(component: TextComponent, document: Document);
6
+ private getWrapperConfig;
7
+ private getElementConfig;
8
+ build(): {
9
+ wrapper: HTMLElement;
10
+ element: HTMLElement;
11
+ };
12
+ buildAndExtractStyles(): {
13
+ wrapper: HTMLElement;
14
+ element: HTMLElement;
15
+ };
16
+ }