@nordcraft/runtime 1.0.33 → 1.0.34
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/dist/components/createComponent.js +4 -0
- package/dist/components/createComponent.js.map +1 -1
- package/dist/components/createElement.js +9 -1
- package/dist/components/createElement.js.map +1 -1
- package/dist/custom-element.main.esm.js +17 -17
- package/dist/custom-element.main.esm.js.map +4 -4
- package/dist/debug/panicScreen.d.ts +6 -0
- package/dist/debug/panicScreen.js +25 -0
- package/dist/debug/panicScreen.js.map +1 -0
- package/dist/debug/sendEditorToast.d.ts +3 -0
- package/dist/debug/sendEditorToast.js +9 -0
- package/dist/debug/sendEditorToast.js.map +1 -0
- package/dist/editor-preview.main.js +65 -29
- package/dist/editor-preview.main.js.map +1 -1
- package/dist/page.main.esm.js +3 -3
- package/dist/page.main.esm.js.map +4 -4
- package/dist/styles/CustomPropertyStyleSheet.d.ts +2 -1
- package/dist/styles/CustomPropertyStyleSheet.js +14 -5
- package/dist/styles/CustomPropertyStyleSheet.js.map +1 -1
- package/dist/styles/CustomPropertyStyleSheet.test.js +7 -7
- package/dist/styles/CustomPropertyStyleSheet.test.js.map +1 -1
- package/dist/utils/subscribeCustomProperty.d.ts +4 -1
- package/dist/utils/subscribeCustomProperty.js +11 -4
- package/dist/utils/subscribeCustomProperty.js.map +1 -1
- package/package.json +3 -3
- package/src/components/createComponent.ts +4 -0
- package/src/components/createElement.ts +10 -1
- package/src/debug/panicScreen.ts +37 -0
- package/src/debug/sendEditorToast.ts +19 -0
- package/src/editor-preview.main.ts +81 -40
- package/src/styles/CustomPropertyStyleSheet.test.ts +7 -7
- package/src/styles/CustomPropertyStyleSheet.ts +22 -5
- package/src/utils/subscribeCustomProperty.ts +25 -12
|
@@ -11,7 +11,7 @@ import type { MediaQuery } from '@nordcraft/core/dist/component/component.types'
|
|
|
11
11
|
export declare class CustomPropertyStyleSheet {
|
|
12
12
|
private styleSheet;
|
|
13
13
|
private ruleMap;
|
|
14
|
-
constructor(styleSheet?: CSSStyleSheet | null);
|
|
14
|
+
constructor(root: Document | ShadowRoot, styleSheet?: CSSStyleSheet | null);
|
|
15
15
|
/**
|
|
16
16
|
* @returns A function to update the property value efficiently.
|
|
17
17
|
*/
|
|
@@ -22,6 +22,7 @@ export declare class CustomPropertyStyleSheet {
|
|
|
22
22
|
unregisterProperty(selector: string, name: string, options?: {
|
|
23
23
|
mediaQuery?: MediaQuery;
|
|
24
24
|
startingStyle?: boolean;
|
|
25
|
+
deepClean?: boolean;
|
|
25
26
|
}): void;
|
|
26
27
|
getStyleSheet(): CSSStyleSheet;
|
|
27
28
|
/**
|
|
@@ -11,13 +11,13 @@ export class CustomPropertyStyleSheet {
|
|
|
11
11
|
styleSheet;
|
|
12
12
|
// Selector to rule index mapping
|
|
13
13
|
ruleMap;
|
|
14
|
-
constructor(styleSheet) {
|
|
14
|
+
constructor(root, styleSheet) {
|
|
15
15
|
if (styleSheet) {
|
|
16
16
|
this.styleSheet = styleSheet;
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
19
|
this.styleSheet = new CSSStyleSheet();
|
|
20
|
-
|
|
20
|
+
root.adoptedStyleSheets.push(this.getStyleSheet());
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
@@ -29,7 +29,7 @@ export class CustomPropertyStyleSheet {
|
|
|
29
29
|
// Check if the selector already exists
|
|
30
30
|
let rule = this.ruleMap.get(fullSelector);
|
|
31
31
|
if (!rule) {
|
|
32
|
-
const ruleIndex = this.styleSheet.insertRule(fullSelector);
|
|
32
|
+
const ruleIndex = this.styleSheet.insertRule(fullSelector, this.styleSheet.cssRules.length);
|
|
33
33
|
let newRule = this.styleSheet.cssRules[ruleIndex];
|
|
34
34
|
// We are only interested in the dynamic style, so get the actual style rule, not media or other nested rules. Loop until we are at the bottom most rule.
|
|
35
35
|
while (newRule.cssRules &&
|
|
@@ -48,8 +48,17 @@ export class CustomPropertyStyleSheet {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
const fullSelector = CustomPropertyStyleSheet.getFullSelector(selector, options);
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
const rule = this.ruleMap.get(fullSelector);
|
|
52
|
+
if (!rule) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
rule.style.removeProperty(name);
|
|
56
|
+
// Cleaning up empty selectors is probably not necessary in production and may have performance implications.
|
|
57
|
+
// However, it is required for the editor-preview as it is a dynamic environment and things may get reordered and canvas reused.
|
|
58
|
+
if (options?.deepClean && rule.style.length === 0) {
|
|
59
|
+
this.styleSheet.deleteRule(Array.from(this.ruleMap.keys()).indexOf(fullSelector));
|
|
60
|
+
this.ruleMap.delete(fullSelector);
|
|
61
|
+
}
|
|
53
62
|
}
|
|
54
63
|
getStyleSheet() {
|
|
55
64
|
return this.styleSheet;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomPropertyStyleSheet.js","sourceRoot":"","sources":["../../src/styles/CustomPropertyStyleSheet.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,wBAAwB;IAC3B,UAAU,CAAe;IAEjC,iCAAiC;IACzB,OAAO,CAA+D;IAE9E,YAAY,UAAiC;
|
|
1
|
+
{"version":3,"file":"CustomPropertyStyleSheet.js","sourceRoot":"","sources":["../../src/styles/CustomPropertyStyleSheet.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,wBAAwB;IAC3B,UAAU,CAAe;IAEjC,iCAAiC;IACzB,OAAO,CAA+D;IAE9E,YAAY,IAA2B,EAAE,UAAiC;QACxE,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC9B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,UAAU,GAAG,IAAI,aAAa,EAAE,CAAA;YACrC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAA;QACpD,CAAC;IACH,CAAC;IAED;;OAEG;IACI,gBAAgB,CACrB,QAAgB,EAChB,IAAY,EACZ,OAGC;QAED,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,YAAY,GAAG,wBAAwB,CAAC,eAAe,CAC3D,QAAQ,EACR,OAAO,CACR,CAAA;QAED,uCAAuC;QACvC,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAC1C,YAAY,EACZ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAChC,CAAA;YACD,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;YAEjD,yJAAyJ;YACzJ,OACG,OAAe,CAAC,QAAQ;gBACxB,OAA2B,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAChD,CAAC;gBACD,OAAO,GAAI,OAA2B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACpD,CAAC;YACD,IAAI,GAAG,OAA+C,CAAA;YACtD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QACtC,CAAC;QAED,OAAO,CAAC,KAAa,EAAE,EAAE;YACvB,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACrC,CAAC,CAAA;IACH,CAAC;IAEM,kBAAkB,CACvB,QAAgB,EAChB,IAAY,EACZ,OAIC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAM;QACR,CAAC;QAED,MAAM,YAAY,GAAG,wBAAwB,CAAC,eAAe,CAC3D,QAAQ,EACR,OAAO,CACR,CAAA;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAM;QACR,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;QAE/B,6GAA6G;QAC7G,gIAAgI;QAChI,IAAI,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,UAAU,CAAC,UAAU,CACxB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CACtD,CAAA;YACD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IAEM,aAAa;QAClB,OAAO,IAAI,CAAC,UAAU,CAAA;IACxB,CAAC;IAED;;;OAGG;IACK,eAAe;QACrB,MAAM,SAAS,GAA8B,IAAI,GAAG,EAAE,CAAA;QACtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzD,IAAI,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACtC,MAAM,QAAQ,GAAG,wBAAwB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;YACnE,mFAAmF;YACnF,OACG,IAAwB,CAAC,QAAQ;gBACjC,IAAwB,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAC7C,CAAC;gBACD,IAAI,GAAI,IAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAC9C,CAAC;YAED,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAoB,CAAC,CAAA;QAC/C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAEO,MAAM,CAAC,mBAAmB,CAAC,IAAa;QAC9C,QAAQ,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;YAC9B,KAAK,cAAc;gBACjB,oFAAoF;gBACpF,OAAO,GAAI,IAAqB,CAAC,YAAY,MAAM,KAAK,CAAC,IAAI,CAC1D,IAAqB,CAAC,QAAQ,CAChC;qBACE,GAAG,CAAC,wBAAwB,CAAC,mBAAmB,CAAC;qBACjD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA;YAClB,KAAK,sBAAsB;gBACzB,OAAO,qBAAqB,KAAK,CAAC,IAAI,CACnC,IAA6B,CAAC,QAAQ,CACxC;qBACE,GAAG,CAAC,wBAAwB,CAAC,mBAAmB,CAAC;qBACjD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA;YAClB,KAAK,cAAc;gBACjB,OAAO,UAAW,IAAqB,CAAC,KAAK,CAAC,SAAS,MAAM,KAAK,CAAC,IAAI,CACpE,IAAqB,CAAC,QAAQ,CAChC;qBACE,GAAG,CAAC,wBAAwB,CAAC,mBAAmB,CAAC;qBACjD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA;YAClB,KAAK,uBAAuB;gBAC1B,OAAO,EAAE,CAAA;YACX;gBACE,sCAAsC;gBACtC,OAAO,CAAC,IAAI,CACV,8BAA8B,IAAI,CAAC,WAAW,CAAC,IAAI,6BAA6B,CACjF,CAAA;gBACD,OAAO,EAAE,CAAA;QACb,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,eAAe,CAC5B,QAAgB,EAChB,OAGC;QAED,IAAI,MAAM,GACR,QAAQ,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC1E,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC;YACxB,MAAM,GAAG,WAAW,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;iBACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC;iBACzC,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,SAAS,CAAC,OAAO,MAAM,GAAG,CAAA;QACpC,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;CACF"}
|
|
@@ -2,18 +2,18 @@ import { describe, expect, test } from 'bun:test';
|
|
|
2
2
|
import { CustomPropertyStyleSheet } from './CustomPropertyStyleSheet';
|
|
3
3
|
describe('CustomPropertyStyleSheet', () => {
|
|
4
4
|
test('it creates a new stylesheet', () => {
|
|
5
|
-
const instance = new CustomPropertyStyleSheet();
|
|
5
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
6
6
|
expect(instance).toBeInstanceOf(CustomPropertyStyleSheet);
|
|
7
7
|
expect(instance.getStyleSheet().cssRules).toHaveLength(0);
|
|
8
8
|
});
|
|
9
9
|
test('it adds a property definition', () => {
|
|
10
|
-
const instance = new CustomPropertyStyleSheet();
|
|
10
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
11
11
|
instance.registerProperty('.my-class', '--my-property');
|
|
12
12
|
expect(instance.getStyleSheet().cssRules.length).toBe(1);
|
|
13
13
|
expect(instance.getStyleSheet().cssRules[0].cssText).toBe('.my-class { }');
|
|
14
14
|
});
|
|
15
15
|
test('it puts different selectors in different rules', () => {
|
|
16
|
-
const instance = new CustomPropertyStyleSheet();
|
|
16
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
17
17
|
instance.registerProperty('.my-class', '--my-property')('256px');
|
|
18
18
|
instance.registerProperty('.my-other-class', '--my-property')('256px');
|
|
19
19
|
expect(instance.getStyleSheet().cssRules.length).toBe(2);
|
|
@@ -21,7 +21,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
21
21
|
expect(instance.getStyleSheet().cssRules[1].cssText).toBe('.my-other-class { --my-property: 256px; }');
|
|
22
22
|
});
|
|
23
23
|
test('it can update properties', () => {
|
|
24
|
-
const instance = new CustomPropertyStyleSheet();
|
|
24
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
25
25
|
const setter = instance.registerProperty('.my-class', '--my-property');
|
|
26
26
|
setter('256px');
|
|
27
27
|
expect(instance.getStyleSheet().cssRules.length).toBe(1);
|
|
@@ -30,7 +30,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
30
30
|
expect(instance.getStyleSheet().cssRules[0].cssText).toBe('.my-class { --my-property: inherit; }');
|
|
31
31
|
});
|
|
32
32
|
test('it works with media queries', () => {
|
|
33
|
-
const instance = new CustomPropertyStyleSheet();
|
|
33
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
34
34
|
instance.registerProperty('.my-class', '--my-property', {
|
|
35
35
|
mediaQuery: { 'max-width': '600px' },
|
|
36
36
|
})('256px');
|
|
@@ -38,7 +38,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
38
38
|
expect(instance.getStyleSheet().cssRules[0].cssText).toBe('@media (max-width: 600px) { .my-class { --my-property: 256px; } }');
|
|
39
39
|
});
|
|
40
40
|
test('it unregisters a property', () => {
|
|
41
|
-
const instance = new CustomPropertyStyleSheet();
|
|
41
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
42
42
|
const setter = instance.registerProperty('.my-class', '--my-property');
|
|
43
43
|
setter('256px');
|
|
44
44
|
const setter2 = instance.registerProperty('.my-class', '--my-other-property');
|
|
@@ -50,7 +50,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
50
50
|
expect(instance.getStyleSheet().cssRules[0].cssText).toBe('.my-class { }');
|
|
51
51
|
});
|
|
52
52
|
test('it unregisters a property with media queries', () => {
|
|
53
|
-
const instance = new CustomPropertyStyleSheet();
|
|
53
|
+
const instance = new CustomPropertyStyleSheet(document);
|
|
54
54
|
const setter = instance.registerProperty('.my-class-with-media', '--my-property-with-media', {
|
|
55
55
|
mediaQuery: { 'max-width': '600px' },
|
|
56
56
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomPropertyStyleSheet.test.js","sourceRoot":"","sources":["../../src/styles/CustomPropertyStyleSheet.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AACjD,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAErE,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAI,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACvC,MAAM,QAAQ,GAAG,IAAI,wBAAwB,
|
|
1
|
+
{"version":3,"file":"CustomPropertyStyleSheet.test.js","sourceRoot":"","sources":["../../src/styles/CustomPropertyStyleSheet.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { StyleVariant } from '@nordcraft/core/dist/component/component.types';
|
|
2
2
|
import type { Signal } from '../signal/signal';
|
|
3
|
-
|
|
3
|
+
import type { Runtime } from '@nordcraft/core/dist/types';
|
|
4
|
+
export declare function subscribeCustomProperty({ selector, customPropertyName, signal, variant, root, runtime, }: {
|
|
4
5
|
selector: string;
|
|
5
6
|
customPropertyName: string;
|
|
6
7
|
signal: Signal<string>;
|
|
7
8
|
variant?: StyleVariant;
|
|
9
|
+
root: Document | ShadowRoot;
|
|
10
|
+
runtime: Runtime;
|
|
8
11
|
}): void;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { CUSTOM_PROPERTIES_STYLESHEET_ID } from '@nordcraft/core/dist/styling/theme.const';
|
|
2
2
|
import { CustomPropertyStyleSheet } from '../styles/CustomPropertyStyleSheet';
|
|
3
|
-
|
|
4
|
-
export function subscribeCustomProperty({ selector, customPropertyName, signal, variant, }) {
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
let customPropertiesStylesheet;
|
|
4
|
+
export function subscribeCustomProperty({ selector, customPropertyName, signal, variant, root, runtime, }) {
|
|
5
|
+
customPropertiesStylesheet ??= new CustomPropertyStyleSheet(root, root.getElementById(CUSTOM_PROPERTIES_STYLESHEET_ID)?.sheet);
|
|
6
|
+
signal.subscribe(customPropertiesStylesheet.registerProperty(selector, customPropertyName, variant), {
|
|
7
|
+
destroy: () => {
|
|
8
|
+
customPropertiesStylesheet?.unregisterProperty(selector, customPropertyName, {
|
|
9
|
+
deepClean: runtime === 'preview',
|
|
10
|
+
mediaQuery: variant?.mediaQuery,
|
|
11
|
+
startingStyle: variant?.startingStyle,
|
|
12
|
+
});
|
|
13
|
+
},
|
|
7
14
|
});
|
|
8
15
|
}
|
|
9
16
|
//# sourceMappingURL=subscribeCustomProperty.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscribeCustomProperty.js","sourceRoot":"","sources":["../../src/utils/subscribeCustomProperty.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAA;
|
|
1
|
+
{"version":3,"file":"subscribeCustomProperty.js","sourceRoot":"","sources":["../../src/utils/subscribeCustomProperty.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,+BAA+B,EAAE,MAAM,0CAA0C,CAAA;AAE1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAA;AAE7E,IAAI,0BAAgE,CAAA;AAEpE,MAAM,UAAU,uBAAuB,CAAC,EACtC,QAAQ,EACR,kBAAkB,EAClB,MAAM,EACN,OAAO,EACP,IAAI,EACJ,OAAO,GAQR;IACC,0BAA0B,KAAK,IAAI,wBAAwB,CACzD,IAAI,EAEF,IAAI,CAAC,cAAc,CAAC,+BAA+B,CAGpD,EAAE,KAAK,CACT,CAAA;IAED,MAAM,CAAC,SAAS,CACd,0BAA0B,CAAC,gBAAgB,CACzC,QAAQ,EACR,kBAAkB,EAClB,OAAO,CACR,EACD;QACE,OAAO,EAAE,GAAG,EAAE;YACZ,0BAA0B,EAAE,kBAAkB,CAC5C,QAAQ,EACR,kBAAkB,EAClB;gBACE,SAAS,EAAE,OAAO,KAAK,SAAS;gBAChC,UAAU,EAAE,OAAO,EAAE,UAAU;gBAC/B,aAAa,EAAE,OAAO,EAAE,aAAa;aACtC,CACF,CAAA;QACH,CAAC;KACF,CACF,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://github.com/nordcraftengine/nordcraft",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@nordcraft/core": "1.0.
|
|
8
|
-
"@nordcraft/std-lib": "1.0.
|
|
7
|
+
"@nordcraft/core": "1.0.34",
|
|
8
|
+
"@nordcraft/std-lib": "1.0.34",
|
|
9
9
|
"fast-deep-equal": "3.1.3",
|
|
10
10
|
"path-to-regexp": "6.3.0"
|
|
11
11
|
},
|
|
@@ -21,5 +21,5 @@
|
|
|
21
21
|
"files": ["dist", "src"],
|
|
22
22
|
"main": "dist/page.main.js",
|
|
23
23
|
"types": "dist/page.main.d.ts",
|
|
24
|
-
"version": "1.0.
|
|
24
|
+
"version": "1.0.34"
|
|
25
25
|
}
|
|
@@ -89,6 +89,8 @@ export function createComponent({
|
|
|
89
89
|
})
|
|
90
90
|
}),
|
|
91
91
|
customPropertyName,
|
|
92
|
+
root: ctx.root,
|
|
93
|
+
runtime: ctx.env.runtime,
|
|
92
94
|
}),
|
|
93
95
|
)
|
|
94
96
|
node.variants?.forEach((variant) => {
|
|
@@ -113,6 +115,8 @@ export function createComponent({
|
|
|
113
115
|
),
|
|
114
116
|
customPropertyName,
|
|
115
117
|
variant,
|
|
118
|
+
root: ctx.root,
|
|
119
|
+
runtime: ctx.env.runtime,
|
|
116
120
|
}),
|
|
117
121
|
)
|
|
118
122
|
})
|
|
@@ -154,7 +154,12 @@ export function createElement({
|
|
|
154
154
|
([customPropertyName, { formula }]) =>
|
|
155
155
|
subscribeCustomProperty({
|
|
156
156
|
customPropertyName,
|
|
157
|
-
selector:
|
|
157
|
+
selector:
|
|
158
|
+
ctx.env.runtime === 'custom-element' &&
|
|
159
|
+
ctx.isRootComponent &&
|
|
160
|
+
path === '0'
|
|
161
|
+
? `${getNodeSelector(path)}, :host`
|
|
162
|
+
: getNodeSelector(path),
|
|
158
163
|
signal: dataSignal.map((data) =>
|
|
159
164
|
applyFormula(formula, {
|
|
160
165
|
data,
|
|
@@ -166,6 +171,8 @@ export function createElement({
|
|
|
166
171
|
env: ctx.env,
|
|
167
172
|
}),
|
|
168
173
|
),
|
|
174
|
+
root: ctx.root,
|
|
175
|
+
runtime: ctx.env.runtime,
|
|
169
176
|
}),
|
|
170
177
|
)
|
|
171
178
|
|
|
@@ -189,6 +196,8 @@ export function createElement({
|
|
|
189
196
|
env: ctx.env,
|
|
190
197
|
}),
|
|
191
198
|
),
|
|
199
|
+
root: ctx.root,
|
|
200
|
+
runtime: ctx.env.runtime,
|
|
192
201
|
})
|
|
193
202
|
},
|
|
194
203
|
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export const createPanicScreen = ({
|
|
2
|
+
name,
|
|
3
|
+
message,
|
|
4
|
+
isPage,
|
|
5
|
+
cause,
|
|
6
|
+
}: {
|
|
7
|
+
name: string
|
|
8
|
+
message: string
|
|
9
|
+
isPage?: boolean
|
|
10
|
+
cause?: unknown
|
|
11
|
+
}) => {
|
|
12
|
+
let content = getContent(name, message, isPage)
|
|
13
|
+
|
|
14
|
+
// Easter egg for RangeError
|
|
15
|
+
if (cause instanceof RangeError) {
|
|
16
|
+
for (let i = 0; i < 10; i++) {
|
|
17
|
+
content += `<div style="transform-origin: 15% 15%; scale: ${1 / (i * 0.225 + 1.225)}; font-size: ${22 / ((i * 0.6) ** 2 + 1)}px">${getContent(name, message, isPage)}</div>`
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return document.createRange().createContextualFragment(`
|
|
22
|
+
<main style="background-color: blue; color: white; font-family: 'Courier New', monospace; font-weight: 100; display: flex; justify-content: flex-start; align-items: flex-start; margin: 0px; padding: 0px;">
|
|
23
|
+
<div style="display: flex; flex-direction: column; justify-content: space-between; align-items: flex-start; height: 100vh;">
|
|
24
|
+
<div style="display: flex; flex-direction: column; gap: 20px; padding: 80px; font-size: 22px;">
|
|
25
|
+
${content}
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div style="position:fixed; pointer-events: none; width: 100vw; height: 100vh; background-image: linear-gradient(0deg, rgba(0,0,0,0) 25%, rgba(0,0,0,0.33) 25%, rgba(0,0,0,0.33) 50%, rgba(0,0,0,0) 50%, rgba(0,0,0,0) 75%, rgba(0,0,0,0.33) 75%, rgba(0,0,0,0.33) 100%); background-size: 4px 4px;"></div>
|
|
29
|
+
<div style="position:fixed; pointer-events: none; width: 100vw; height: 100vh; background-image: radial-gradient(ellipse at center, rgba(0,0,0,0) 50%, rgba(0,0,0,0.25) 100%);"></div>
|
|
30
|
+
</main>
|
|
31
|
+
`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const getContent = (name: string, message: string, isPage?: boolean) => `
|
|
35
|
+
<h1 style="display: inline; font-size: 1em; background: white; color: blue; padding: 0.4em 0.8em;">${name}</h1>
|
|
36
|
+
<p style="font-size: 0.8em;">The ${isPage ? 'page' : 'component'} could not be rendered. Fix the issue and try again. Join our <a style="color:white" href="https://discord.gg/nordcraft" target="_blank">Discord</a> for help.</p>
|
|
37
|
+
<p style="font-size: 0.81em;">Error Message: ${message}</p>`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function sendEditorToast(
|
|
2
|
+
title: string,
|
|
3
|
+
message: string,
|
|
4
|
+
{
|
|
5
|
+
type = 'neutral',
|
|
6
|
+
}: {
|
|
7
|
+
type?: 'neutral' | 'warning' | 'critical'
|
|
8
|
+
},
|
|
9
|
+
) {
|
|
10
|
+
window.parent?.postMessage(
|
|
11
|
+
{
|
|
12
|
+
type: 'emitToast',
|
|
13
|
+
toastType: type,
|
|
14
|
+
title,
|
|
15
|
+
message,
|
|
16
|
+
},
|
|
17
|
+
'*',
|
|
18
|
+
)
|
|
19
|
+
}
|
|
@@ -38,6 +38,8 @@ import { createLegacyAPI } from './api/createAPI'
|
|
|
38
38
|
import { createAPI } from './api/createAPIv2'
|
|
39
39
|
import { createNode } from './components/createNode'
|
|
40
40
|
import { isContextProvider } from './context/isContextProvider'
|
|
41
|
+
import { createPanicScreen } from './debug/panicScreen'
|
|
42
|
+
import { sendEditorToast } from './debug/sendEditorToast'
|
|
41
43
|
import { dragEnded } from './editor/drag-drop/dragEnded'
|
|
42
44
|
import { dragMove } from './editor/drag-drop/dragMove'
|
|
43
45
|
import { dragReorder } from './editor/drag-drop/dragReorder'
|
|
@@ -566,7 +568,7 @@ export const createRoot = (
|
|
|
566
568
|
}
|
|
567
569
|
const { x, y, type } = message.data
|
|
568
570
|
const elementsAtPoint = document.elementsFromPoint(x, y)
|
|
569
|
-
|
|
571
|
+
const element = elementsAtPoint.find((elem) => {
|
|
570
572
|
const id = elem.getAttribute('data-id')
|
|
571
573
|
if (
|
|
572
574
|
typeof id !== 'string' ||
|
|
@@ -583,31 +585,12 @@ export const createRoot = (
|
|
|
583
585
|
if (elem.getAttribute('data-node-type') === 'text') {
|
|
584
586
|
return (
|
|
585
587
|
// Select text nodes if the meta key is pressed or the text node is double-clicked
|
|
586
|
-
metaKey ||
|
|
587
|
-
type === 'dblclick' ||
|
|
588
|
-
// Select text nodes if the selected node is a text node. This is useful as the user is likely in a text editing mode
|
|
589
|
-
getDOMNodeFromNodeId(selectedNodeId)?.getAttribute(
|
|
590
|
-
'data-node-type',
|
|
591
|
-
) === 'text'
|
|
588
|
+
metaKey || type === 'dblclick'
|
|
592
589
|
)
|
|
593
590
|
}
|
|
594
591
|
return true
|
|
595
592
|
})
|
|
596
593
|
|
|
597
|
-
// Bubble selection to the topmost parent that has the exact same size as the element.
|
|
598
|
-
// This is important for drag and drop as you are often left with childless parents after dragging.
|
|
599
|
-
while (
|
|
600
|
-
element?.parentElement &&
|
|
601
|
-
element.getAttribute('data-node-id') !== 'root' &&
|
|
602
|
-
fastDeepEqual(
|
|
603
|
-
element.getBoundingClientRect().toJSON(),
|
|
604
|
-
element.parentElement.getBoundingClientRect().toJSON(),
|
|
605
|
-
) &&
|
|
606
|
-
element.getAttribute('data-node-type') !== 'text'
|
|
607
|
-
) {
|
|
608
|
-
element = element.parentElement
|
|
609
|
-
}
|
|
610
|
-
|
|
611
594
|
const id = element?.getAttribute('data-id') ?? null
|
|
612
595
|
if (type === 'click' && id !== selectedNodeId) {
|
|
613
596
|
if (message.data.metaKey) {
|
|
@@ -986,10 +969,30 @@ export const createRoot = (
|
|
|
986
969
|
document.head.appendChild(styleTag)
|
|
987
970
|
}
|
|
988
971
|
|
|
972
|
+
// If style variant targets a pseudo-element, apply styles to it instead
|
|
973
|
+
let pseudoElement = ''
|
|
974
|
+
if (component && styleVariantSelection) {
|
|
975
|
+
const nodeLookup = getNodeAndAncestors(
|
|
976
|
+
component,
|
|
977
|
+
component.nodes.root,
|
|
978
|
+
styleVariantSelection.nodeId,
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
if (
|
|
982
|
+
nodeLookup?.node.type === 'element' ||
|
|
983
|
+
(nodeLookup?.node.type === 'component' &&
|
|
984
|
+
nodeLookup.node.variants?.[
|
|
985
|
+
styleVariantSelection.styleVariantIndex
|
|
986
|
+
].pseudoElement)
|
|
987
|
+
) {
|
|
988
|
+
pseudoElement = `::${nodeLookup.node.variants?.[styleVariantSelection.styleVariantIndex].pseudoElement}`
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
989
992
|
const previewStyles = Object.entries(previewStyleStyles)
|
|
990
993
|
.map(([key, value]) => `${key}: ${value} !important;`)
|
|
991
994
|
.join('\n')
|
|
992
|
-
styleTag.innerHTML = `[data-id="${selectedNodeId}"], [data-id="${selectedNodeId}"] ~ [data-id^="${selectedNodeId}("] {
|
|
995
|
+
styleTag.innerHTML = `[data-id="${selectedNodeId}"]${pseudoElement}, [data-id="${selectedNodeId}"] ~ [data-id^="${selectedNodeId}("]${pseudoElement} {
|
|
993
996
|
${previewStyles}
|
|
994
997
|
transition: none !important;
|
|
995
998
|
}`
|
|
@@ -1054,9 +1057,10 @@ export const createRoot = (
|
|
|
1054
1057
|
(nodeLookup.node.type === 'element' ||
|
|
1055
1058
|
nodeLookup.node.type === 'component')
|
|
1056
1059
|
) {
|
|
1057
|
-
const selectedStyleVariant =
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
+
const selectedStyleVariant =
|
|
1061
|
+
nodeLookup.node.variants?.[
|
|
1062
|
+
styleVariantSelection.styleVariantIndex
|
|
1063
|
+
] ?? ({ style: {} } as StyleVariant)
|
|
1060
1064
|
// Add a style element specific to the selected element which
|
|
1061
1065
|
// is only applied when the preview is in design mode
|
|
1062
1066
|
const styleVariantCustomProperties = Object.entries(
|
|
@@ -1081,12 +1085,15 @@ export const createRoot = (
|
|
|
1081
1085
|
.filter(({ value }) => value !== undefined)
|
|
1082
1086
|
|
|
1083
1087
|
const styleElem = document.createElement('style')
|
|
1088
|
+
const pseudoElement = selectedStyleVariant.pseudoElement
|
|
1089
|
+
? `::${selectedStyleVariant.pseudoElement}`
|
|
1090
|
+
: ''
|
|
1084
1091
|
styleElem.setAttribute('data-hash', selectedNodeId)
|
|
1085
1092
|
styleElem.appendChild(
|
|
1086
1093
|
document.createTextNode(`
|
|
1087
|
-
body[data-mode="design"] [data-id="${selectedNodeId}"] {
|
|
1094
|
+
body[data-mode="design"] [data-id="${selectedNodeId}"]${pseudoElement} {
|
|
1088
1095
|
${styleToCss({
|
|
1089
|
-
...nodeLookup.node.style,
|
|
1096
|
+
...(!pseudoElement && nodeLookup.node.style),
|
|
1090
1097
|
...selectedStyleVariant.style,
|
|
1091
1098
|
...Object.fromEntries(
|
|
1092
1099
|
styleVariantCustomProperties.map(
|
|
@@ -1406,19 +1413,53 @@ export const createRoot = (
|
|
|
1406
1413
|
// Clear old root signal and create a new one to not keep old signals with previous root around
|
|
1407
1414
|
ctxDataSignal?.destroy()
|
|
1408
1415
|
ctxDataSignal = dataSignal.map((data) => data)
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1416
|
+
try {
|
|
1417
|
+
const rootElem = createNode({
|
|
1418
|
+
id: 'root',
|
|
1419
|
+
path: '0',
|
|
1420
|
+
dataSignal: ctxDataSignal,
|
|
1421
|
+
ctx: newCtx,
|
|
1422
|
+
parentElement: domNode,
|
|
1423
|
+
instance: { [newCtx.component.name]: 'root' },
|
|
1424
|
+
})
|
|
1425
|
+
newCtx.component.onLoad?.actions.forEach((action) => {
|
|
1426
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1427
|
+
handleAction(action, dataSignal.get(), newCtx)
|
|
1428
|
+
})
|
|
1429
|
+
rootElem.forEach((elem) => domNode.appendChild(elem))
|
|
1430
|
+
} catch (error: unknown) {
|
|
1431
|
+
const isPage = isPageComponent(newCtx.component)
|
|
1432
|
+
let name = `Unexpected error while rendering ${isPage ? 'page' : 'component'}`
|
|
1433
|
+
let message = error instanceof Error ? error.message : String(error)
|
|
1434
|
+
let panic = false
|
|
1435
|
+
if (error instanceof RangeError) {
|
|
1436
|
+
// RangeError is unrecoverable
|
|
1437
|
+
panic = true
|
|
1438
|
+
name = 'Infinite loop detected'
|
|
1439
|
+
message =
|
|
1440
|
+
'RangeError (Maximum call stack size exceeded): Remove any circular dependencies or recursive calls. This is most likely caused by components, formulas or actions using themselves without an exit case.'
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Send a toast to the editor with the error
|
|
1444
|
+
sendEditorToast(name, message, {
|
|
1445
|
+
type: 'critical',
|
|
1446
|
+
})
|
|
1447
|
+
|
|
1448
|
+
if (panic) {
|
|
1449
|
+
// Show error overlay in the editor until next update
|
|
1450
|
+
const panicScreen = createPanicScreen({
|
|
1451
|
+
name: name,
|
|
1452
|
+
message,
|
|
1453
|
+
isPage,
|
|
1454
|
+
cause: error,
|
|
1455
|
+
})
|
|
1456
|
+
|
|
1457
|
+
// Replace the inner HTML of the editor preview with the panic screen
|
|
1458
|
+
domNode.innerHTML = ''
|
|
1459
|
+
domNode.appendChild(panicScreen)
|
|
1460
|
+
}
|
|
1461
|
+
console.error(name, message, error)
|
|
1462
|
+
}
|
|
1422
1463
|
window.parent?.postMessage(
|
|
1423
1464
|
{
|
|
1424
1465
|
type: 'style',
|
|
@@ -3,20 +3,20 @@ import { CustomPropertyStyleSheet } from './CustomPropertyStyleSheet'
|
|
|
3
3
|
|
|
4
4
|
describe('CustomPropertyStyleSheet', () => {
|
|
5
5
|
test('it creates a new stylesheet', () => {
|
|
6
|
-
const instance = new CustomPropertyStyleSheet()
|
|
6
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
7
7
|
expect(instance).toBeInstanceOf(CustomPropertyStyleSheet)
|
|
8
8
|
expect(instance.getStyleSheet().cssRules).toHaveLength(0)
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
test('it adds a property definition', () => {
|
|
12
|
-
const instance = new CustomPropertyStyleSheet()
|
|
12
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
13
13
|
instance.registerProperty('.my-class', '--my-property')
|
|
14
14
|
expect(instance.getStyleSheet().cssRules.length).toBe(1)
|
|
15
15
|
expect(instance.getStyleSheet().cssRules[0].cssText).toBe('.my-class { }')
|
|
16
16
|
})
|
|
17
17
|
|
|
18
18
|
test('it puts different selectors in different rules', () => {
|
|
19
|
-
const instance = new CustomPropertyStyleSheet()
|
|
19
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
20
20
|
instance.registerProperty('.my-class', '--my-property')('256px')
|
|
21
21
|
instance.registerProperty('.my-other-class', '--my-property')('256px')
|
|
22
22
|
expect(instance.getStyleSheet().cssRules.length).toBe(2)
|
|
@@ -29,7 +29,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
test('it can update properties', () => {
|
|
32
|
-
const instance = new CustomPropertyStyleSheet()
|
|
32
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
33
33
|
const setter = instance.registerProperty('.my-class', '--my-property')
|
|
34
34
|
setter('256px')
|
|
35
35
|
expect(instance.getStyleSheet().cssRules.length).toBe(1)
|
|
@@ -44,7 +44,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
test('it works with media queries', () => {
|
|
47
|
-
const instance = new CustomPropertyStyleSheet()
|
|
47
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
48
48
|
instance.registerProperty('.my-class', '--my-property', {
|
|
49
49
|
mediaQuery: { 'max-width': '600px' },
|
|
50
50
|
})('256px')
|
|
@@ -55,7 +55,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
55
55
|
})
|
|
56
56
|
|
|
57
57
|
test('it unregisters a property', () => {
|
|
58
|
-
const instance = new CustomPropertyStyleSheet()
|
|
58
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
59
59
|
const setter = instance.registerProperty('.my-class', '--my-property')
|
|
60
60
|
setter('256px')
|
|
61
61
|
const setter2 = instance.registerProperty(
|
|
@@ -76,7 +76,7 @@ describe('CustomPropertyStyleSheet', () => {
|
|
|
76
76
|
})
|
|
77
77
|
|
|
78
78
|
test('it unregisters a property with media queries', () => {
|
|
79
|
-
const instance = new CustomPropertyStyleSheet()
|
|
79
|
+
const instance = new CustomPropertyStyleSheet(document)
|
|
80
80
|
const setter = instance.registerProperty(
|
|
81
81
|
'.my-class-with-media',
|
|
82
82
|
'--my-property-with-media',
|
|
@@ -15,12 +15,12 @@ export class CustomPropertyStyleSheet {
|
|
|
15
15
|
// Selector to rule index mapping
|
|
16
16
|
private ruleMap: Map<string, CSSStyleRule | CSSNestedDeclarations> | undefined
|
|
17
17
|
|
|
18
|
-
constructor(styleSheet?: CSSStyleSheet | null) {
|
|
18
|
+
constructor(root: Document | ShadowRoot, styleSheet?: CSSStyleSheet | null) {
|
|
19
19
|
if (styleSheet) {
|
|
20
20
|
this.styleSheet = styleSheet
|
|
21
21
|
} else {
|
|
22
22
|
this.styleSheet = new CSSStyleSheet()
|
|
23
|
-
|
|
23
|
+
root.adoptedStyleSheets.push(this.getStyleSheet())
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -44,7 +44,10 @@ export class CustomPropertyStyleSheet {
|
|
|
44
44
|
// Check if the selector already exists
|
|
45
45
|
let rule = this.ruleMap.get(fullSelector)
|
|
46
46
|
if (!rule) {
|
|
47
|
-
const ruleIndex = this.styleSheet.insertRule(
|
|
47
|
+
const ruleIndex = this.styleSheet.insertRule(
|
|
48
|
+
fullSelector,
|
|
49
|
+
this.styleSheet.cssRules.length,
|
|
50
|
+
)
|
|
48
51
|
let newRule = this.styleSheet.cssRules[ruleIndex]
|
|
49
52
|
|
|
50
53
|
// We are only interested in the dynamic style, so get the actual style rule, not media or other nested rules. Loop until we are at the bottom most rule.
|
|
@@ -69,6 +72,7 @@ export class CustomPropertyStyleSheet {
|
|
|
69
72
|
options?: {
|
|
70
73
|
mediaQuery?: MediaQuery
|
|
71
74
|
startingStyle?: boolean
|
|
75
|
+
deepClean?: boolean
|
|
72
76
|
},
|
|
73
77
|
): void {
|
|
74
78
|
if (!this.ruleMap) {
|
|
@@ -80,8 +84,21 @@ export class CustomPropertyStyleSheet {
|
|
|
80
84
|
options,
|
|
81
85
|
)
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
const rule = this.ruleMap.get(fullSelector)
|
|
88
|
+
if (!rule) {
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
rule.style.removeProperty(name)
|
|
93
|
+
|
|
94
|
+
// Cleaning up empty selectors is probably not necessary in production and may have performance implications.
|
|
95
|
+
// However, it is required for the editor-preview as it is a dynamic environment and things may get reordered and canvas reused.
|
|
96
|
+
if (options?.deepClean && rule.style.length === 0) {
|
|
97
|
+
this.styleSheet.deleteRule(
|
|
98
|
+
Array.from(this.ruleMap.keys()).indexOf(fullSelector),
|
|
99
|
+
)
|
|
100
|
+
this.ruleMap.delete(fullSelector)
|
|
101
|
+
}
|
|
85
102
|
}
|
|
86
103
|
|
|
87
104
|
public getStyleSheet(): CSSStyleSheet {
|