@htmlplus/element 2.10.0 → 2.12.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.
@@ -4,4 +4,5 @@ export declare const htmlplus: (...plugins: Array<TransformerPlugin>) => {
4
4
  buildStart(): Promise<void>;
5
5
  load(id: any): Promise<string | undefined>;
6
6
  buildEnd(): Promise<void>;
7
+ writeBundle(options: any, bundles: any): Promise<void>;
7
8
  };
package/bundlers/vite.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import path from 'path';
2
2
  import { transformer } from '../transformer/index.js';
3
3
  export const htmlplus = (...plugins) => {
4
- const { start, run, finish } = transformer(...plugins);
4
+ const { global, start, run, finish, write } = transformer(...plugins);
5
5
  return {
6
6
  name: 'htmlplus',
7
7
  async buildStart() {
@@ -20,6 +20,33 @@ export const htmlplus = (...plugins) => {
20
20
  },
21
21
  async buildEnd() {
22
22
  await finish();
23
+ },
24
+ async writeBundle(options, bundles) {
25
+ // TODO
26
+ try {
27
+ for (const context of global.contexts) {
28
+ for (const key in bundles) {
29
+ if (!Object.hasOwnProperty.call(bundles, key))
30
+ continue;
31
+ const bundle = bundles[key];
32
+ if (!bundle.facadeModuleId.startsWith(context.filePath))
33
+ continue;
34
+ const modules = bundle['modules'];
35
+ for (const key in modules) {
36
+ if (!Object.hasOwnProperty.call(modules, key))
37
+ continue;
38
+ const module = modules[key];
39
+ if (!key.startsWith(context.stylePath || ''))
40
+ continue;
41
+ context.styleContentTransformed = module.code;
42
+ break;
43
+ }
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ catch { }
49
+ await write();
23
50
  }
24
51
  };
25
52
  };
@@ -3,7 +3,7 @@ import { call } from './call.js';
3
3
  import { getStyles } from './getStyles.js';
4
4
  import { shadowRoot } from './shadowRoot.js';
5
5
  import { task } from './task.js';
6
- import { html, render } from './uhtml.js';
6
+ import { render } from './uhtml.js';
7
7
  /**
8
8
  * Updates the DOM with a scheduled task.
9
9
  * @param target The element instance.
@@ -31,31 +31,72 @@ export const request = (target, name, previous, callback) => {
31
31
  .map((stack) => [stack[0], stack[1].previous]));
32
32
  // Calls the lifecycle's callback before the rendering phase.
33
33
  call(target, CONSTANTS.LIFECYCLE_UPDATE, states);
34
- // Calculates the template.
35
- const template = () => {
36
- // Calculates the markup.
37
- const markup = call(target, CONSTANTS.METHOD_RENDER);
38
- // Calculates the styles.
39
- const styles = getStyles(target);
40
- // Returns the markup if styles don't exist.
41
- if (!styles)
42
- return markup;
43
- // Returns the markup and styles together.
44
- return html `<style>${styles}</style>${markup}`;
45
- };
46
34
  // Renders template to the DOM.
47
- render(shadowRoot(target), template);
35
+ render(shadowRoot(target), () => call(target, CONSTANTS.METHOD_RENDER));
48
36
  // Invokes requests' callback.
49
37
  stacks.forEach((state) => {
50
38
  state.callbacks.forEach((callback, index, callbacks) => {
51
39
  callback(callbacks.length - 1 != index);
52
40
  });
53
41
  });
42
+ // TODO
43
+ (() => {
44
+ const raw = getStyles(target);
45
+ if (!raw)
46
+ return;
47
+ const regex1 = /this-([\w-]+)(?:-([\w-]+))?/g;
48
+ const regex2 = /(\s*\w+\s*:\s*(undefined|null)\s*;?)/g;
49
+ const hasGlobal = raw.includes(':global');
50
+ const hasVariable = raw.includes('this-');
51
+ let localSheet = target[CONSTANTS.API_STYLE];
52
+ let globalSheet = target.constructor[CONSTANTS.API_STYLE];
53
+ if (!hasVariable && localSheet)
54
+ return;
55
+ const parsed = raw
56
+ .replace(regex1, (match, key) => {
57
+ let value = target;
58
+ for (const section of key.split('-')) {
59
+ value = value?.[section];
60
+ }
61
+ return value;
62
+ })
63
+ .replace(regex2, '');
64
+ if (!localSheet) {
65
+ localSheet = new CSSStyleSheet();
66
+ target[CONSTANTS.API_STYLE] = localSheet;
67
+ shadowRoot(target).adoptedStyleSheets.push(localSheet);
68
+ }
69
+ const localStyle = parsed;
70
+ localSheet.replace(localStyle);
71
+ if (!hasGlobal || globalSheet)
72
+ return;
73
+ if (!globalSheet) {
74
+ globalSheet = new CSSStyleSheet();
75
+ target.constructor[CONSTANTS.API_STYLE] = globalSheet;
76
+ document.adoptedStyleSheets.push(globalSheet);
77
+ }
78
+ const globalStyle = parsed
79
+ .split('}')
80
+ .map((rule) => {
81
+ let [selectors, properties] = rule.split('{');
82
+ selectors = selectors
83
+ .split(',')
84
+ .map((selector) => selector.trim())
85
+ .filter((selector) => selector.startsWith(':global'))
86
+ .map((selector) => selector.replace(':global', ''))
87
+ .map((selector) => selector.trim())
88
+ .join(',');
89
+ return selectors ? `${selectors}{${properties}}` : '';
90
+ })
91
+ .filter((selector) => !!selector)
92
+ .join('');
93
+ globalSheet.replace(globalStyle);
94
+ })();
54
95
  // Calls the lifecycle's callback after the rendering phase.
55
96
  call(target, CONSTANTS.LIFECYCLE_UPDATED, states);
56
97
  // Clears stacks.
57
98
  stacks.clear();
58
- // TODO: releated to the @Watch decorator.
99
+ // TODO: related to the @Watch decorator.
59
100
  target[CONSTANTS.API_RENDER_COMPLETED] = true;
60
101
  };
61
102
  // Creates/Gets a micro task function.
@@ -6,6 +6,7 @@ export declare const API_INSTANCE: unique symbol;
6
6
  export declare const API_REQUEST: unique symbol;
7
7
  export declare const API_RENDER_COMPLETED: unique symbol;
8
8
  export declare const API_STACKS: unique symbol;
9
+ export declare const API_STYLE: unique symbol;
9
10
  export declare const COMMENT_AUTO_ADDED = " THIS IS AUTO-ADDED, DO NOT EDIT MANUALY";
10
11
  export declare const DECORATOR_CSS_VARIABLE = "@Property()";
11
12
  export declare const DECORATOR_ELEMENT = "Element";
@@ -8,6 +8,7 @@ export const API_INSTANCE = Symbol();
8
8
  export const API_REQUEST = Symbol();
9
9
  export const API_RENDER_COMPLETED = Symbol();
10
10
  export const API_STACKS = Symbol();
11
+ export const API_STYLE = Symbol();
11
12
  // comments
12
13
  export const COMMENT_AUTO_ADDED = ' THIS IS AUTO-ADDED, DO NOT EDIT MANUALY';
13
14
  // CSS decorators
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlplus/element",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "author": "Masood Abdolian <m.abdolian@gmail.com>",
@@ -121,6 +121,15 @@ export const customElement = (options) => {
121
121
  for (const attribute of attributes) {
122
122
  switch (attribute.type) {
123
123
  case 'JSXAttribute':
124
+ if (attribute.name.name == 'dangerouslySetInnerHTML') {
125
+ try {
126
+ parts.push(' ', '.innerHTML');
127
+ parts.push('=');
128
+ parts.push(attribute.value.expression.properties.at(0).value);
129
+ }
130
+ catch { }
131
+ continue;
132
+ }
124
133
  parts.push(' ', attribute.name.name);
125
134
  if (!attribute.value)
126
135
  continue;
@@ -10,7 +10,7 @@ export const DOCUMENT_OPTIONS = {
10
10
  export const document = (options) => {
11
11
  const name = 'document';
12
12
  options = Object.assign({}, DOCUMENT_OPTIONS, options);
13
- const finish = (global) => {
13
+ const write = (global) => {
14
14
  const json = {
15
15
  elements: []
16
16
  };
@@ -164,7 +164,18 @@ export const document = (options) => {
164
164
  const [first, second] = section.split(/\n/);
165
165
  const description = first.replace('*/', '').trim();
166
166
  const name = second.split(':')[0].trim();
167
- const initializer = second.split(':').slice(1).join(':').replace(';', '').trim();
167
+ const initializerDefault = second.split(':').slice(1).join(':').replace(';', '').trim();
168
+ // TODO
169
+ const initializerTransformed = context.styleContentTransformed
170
+ ?.split(name)
171
+ ?.at(1)
172
+ ?.split(':')
173
+ ?.filter((section) => !!section)
174
+ ?.at(0)
175
+ ?.split(/;|}/)
176
+ ?.at(0)
177
+ ?.trim();
178
+ const initializer = initializerTransformed || initializerDefault;
168
179
  return {
169
180
  description,
170
181
  initializer,
@@ -191,5 +202,5 @@ export const document = (options) => {
191
202
  fs.ensureDirSync(dirname);
192
203
  fs.writeJSONSync(options.destination, json, { encoding: 'utf8', spaces: 2 });
193
204
  };
194
- return { name, finish };
205
+ return { name, write };
195
206
  };
@@ -1,6 +1,8 @@
1
- import { TransformerPlugin, TransformerPluginContext } from './transformer.types.js';
1
+ import { TransformerPlugin, TransformerPluginContext, TransformerPluginGlobal } from './transformer.types.js';
2
2
  export declare const transformer: (...plugins: TransformerPlugin[]) => {
3
+ global: TransformerPluginGlobal;
3
4
  start: () => Promise<void>;
4
5
  run: (filePath: string) => Promise<TransformerPluginContext>;
5
6
  finish: () => Promise<void>;
7
+ write: () => Promise<void>;
6
8
  };
@@ -67,5 +67,12 @@ export const transformer = (...plugins) => {
67
67
  log(`Plugins finished successfully.`, true);
68
68
  log(`Finished.`, true);
69
69
  };
70
- return { start, run, finish };
70
+ const write = async () => {
71
+ for (const plugin of plugins) {
72
+ if (!plugin.write)
73
+ continue;
74
+ global = (await plugin.write(global)) || global;
75
+ }
76
+ };
77
+ return { global, start, run, finish, write };
71
78
  };
@@ -30,6 +30,7 @@ export interface TransformerPluginContext {
30
30
  readmeName?: string;
31
31
  readmePath?: string;
32
32
  styleContent?: string;
33
+ styleContentTransformed?: string;
33
34
  styleExtension?: string;
34
35
  styleName?: string;
35
36
  stylePath?: string;
@@ -46,5 +47,6 @@ export interface TransformerPlugin {
46
47
  start?: (global: TransformerPluginGlobal) => Return<TransformerPluginGlobal>;
47
48
  run?: (context: TransformerPluginContext, global: TransformerPluginGlobal) => Return<TransformerPluginContext>;
48
49
  finish?: (global: TransformerPluginGlobal) => Return<TransformerPluginGlobal>;
50
+ write?: (global: TransformerPluginGlobal) => Return<TransformerPluginGlobal>;
49
51
  }
50
52
  export {};