@webstudio-is/react-sdk 0.82.0 → 0.83.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.
- package/LICENSE +661 -21
- package/lib/cjs/components/component-meta.js +5 -0
- package/lib/cjs/components/components-utils.js +1 -0
- package/lib/cjs/css/index.js +0 -1
- package/lib/cjs/embed-template.js +30 -1
- package/lib/cjs/expression.js +47 -4
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/props.js +6 -1
- package/lib/cjs/tree/root.js +1 -0
- package/lib/cjs/tree/webstudio-component.js +24 -10
- package/lib/components/component-meta.js +5 -0
- package/lib/components/components-utils.js +1 -0
- package/lib/css/index.js +0 -1
- package/lib/embed-template.js +38 -1
- package/lib/expression.js +47 -4
- package/lib/index.js +2 -0
- package/lib/props.js +6 -1
- package/lib/tree/create-elements-tree.js +3 -1
- package/lib/tree/root.js +8 -2
- package/lib/tree/webstudio-component.js +25 -11
- package/lib/types/app/root.d.ts +1 -2
- package/lib/types/components/component-meta.d.ts +11 -8
- package/lib/types/context.d.ts +1 -1
- package/lib/types/css/index.d.ts +0 -1
- package/lib/types/css/normalize.d.ts +47 -47
- package/lib/types/embed-template.d.ts +14 -1
- package/lib/types/expression.d.ts +3 -2
- package/lib/types/index.d.ts +1 -1
- package/lib/types/props.d.ts +1 -0
- package/lib/types/tree/create-elements-tree.d.ts +5 -5
- package/lib/types/tree/root.d.ts +4 -4
- package/lib/types/tree/webstudio-component.d.ts +15 -7
- package/package.json +14 -15
- package/src/components/component-meta.ts +5 -0
- package/src/context.tsx +1 -0
- package/src/css/index.ts +0 -1
- package/src/embed-template.test.ts +77 -1
- package/src/embed-template.ts +34 -1
- package/src/expression.test.ts +74 -6
- package/src/expression.ts +55 -2
- package/src/index.ts +1 -0
- package/src/props.ts +6 -1
- package/src/tree/create-elements-tree.tsx +17 -5
- package/src/tree/root.ts +14 -3
- package/src/tree/webstudio-component.tsx +41 -14
- package/lib/cjs/css/get-browser-style.js +0 -83
- package/lib/css/get-browser-style.js +0 -65
- package/lib/types/css/get-browser-style.d.ts +0 -2
- package/src/css/get-browser-style.ts +0 -81
package/src/expression.ts
CHANGED
|
@@ -252,6 +252,7 @@ export const executeComputingExpressions = (
|
|
|
252
252
|
|
|
253
253
|
export const generateEffectfulExpression = (
|
|
254
254
|
code: string,
|
|
255
|
+
args: Set<string>,
|
|
255
256
|
allowedVariables: Set<string>
|
|
256
257
|
) => {
|
|
257
258
|
const inputVariables = new Set<string>();
|
|
@@ -259,6 +260,9 @@ export const generateEffectfulExpression = (
|
|
|
259
260
|
validateExpression(code, {
|
|
260
261
|
effectful: true,
|
|
261
262
|
transformIdentifier: (identifier, assignee) => {
|
|
263
|
+
if (args.has(identifier)) {
|
|
264
|
+
return identifier;
|
|
265
|
+
}
|
|
262
266
|
if (allowedVariables.has(identifier)) {
|
|
263
267
|
if (assignee) {
|
|
264
268
|
outputVariables.add(identifier);
|
|
@@ -274,6 +278,9 @@ export const generateEffectfulExpression = (
|
|
|
274
278
|
// generate code computing all expressions
|
|
275
279
|
let generatedCode = "";
|
|
276
280
|
|
|
281
|
+
for (const id of args) {
|
|
282
|
+
generatedCode += `let ${id} = _args.get('${id}');\n`;
|
|
283
|
+
}
|
|
277
284
|
for (const id of inputVariables) {
|
|
278
285
|
generatedCode += `let ${id} = _variables.get('${id}');\n`;
|
|
279
286
|
}
|
|
@@ -296,17 +303,63 @@ export const generateEffectfulExpression = (
|
|
|
296
303
|
|
|
297
304
|
export const executeEffectfulExpression = (
|
|
298
305
|
code: string,
|
|
306
|
+
args: Map<string, unknown>,
|
|
299
307
|
variables: Map<string, unknown>
|
|
300
308
|
) => {
|
|
301
309
|
const generatedCode = generateEffectfulExpression(
|
|
302
310
|
code,
|
|
311
|
+
new Set(args.keys()),
|
|
303
312
|
new Set(variables.keys())
|
|
304
313
|
);
|
|
305
|
-
const executeFn = new Function("_variables", generatedCode);
|
|
306
|
-
const values = executeFn(variables) as Map<string, unknown>;
|
|
314
|
+
const executeFn = new Function("_variables", "_args", generatedCode);
|
|
315
|
+
const values = executeFn(variables, args) as Map<string, unknown>;
|
|
307
316
|
return values;
|
|
308
317
|
};
|
|
309
318
|
|
|
319
|
+
const computeExpressionDependencies = (
|
|
320
|
+
expressions: Map<string, string>,
|
|
321
|
+
expressionId: string,
|
|
322
|
+
dependencies: Map<string, Set<string>>
|
|
323
|
+
) => {
|
|
324
|
+
// prevent recalculating expressions over again
|
|
325
|
+
const depsById = dependencies.get(expressionId);
|
|
326
|
+
if (depsById) {
|
|
327
|
+
return depsById;
|
|
328
|
+
}
|
|
329
|
+
const parentDeps = new Set<string>();
|
|
330
|
+
const code = expressions.get(expressionId);
|
|
331
|
+
if (code === undefined) {
|
|
332
|
+
return parentDeps;
|
|
333
|
+
}
|
|
334
|
+
// write before recursive call to avoid infinite cycle
|
|
335
|
+
dependencies.set(expressionId, parentDeps);
|
|
336
|
+
validateExpression(code, {
|
|
337
|
+
transformIdentifier: (id) => {
|
|
338
|
+
parentDeps.add(id);
|
|
339
|
+
const childDeps = computeExpressionDependencies(
|
|
340
|
+
expressions,
|
|
341
|
+
id,
|
|
342
|
+
dependencies
|
|
343
|
+
);
|
|
344
|
+
for (const depId of childDeps) {
|
|
345
|
+
parentDeps.add(depId);
|
|
346
|
+
}
|
|
347
|
+
return id;
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
return parentDeps;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export const computeExpressionsDependencies = (
|
|
354
|
+
expressions: Map<string, string>
|
|
355
|
+
) => {
|
|
356
|
+
const dependencies = new Map<string, Set<string>>();
|
|
357
|
+
for (const id of expressions.keys()) {
|
|
358
|
+
computeExpressionDependencies(expressions, id, dependencies);
|
|
359
|
+
}
|
|
360
|
+
return dependencies;
|
|
361
|
+
};
|
|
362
|
+
|
|
310
363
|
type Values = Map<string, unknown>;
|
|
311
364
|
|
|
312
365
|
const dataSourceVariablePrefix = "$ws$dataSource$";
|
package/src/index.ts
CHANGED
package/src/props.ts
CHANGED
|
@@ -55,15 +55,20 @@ export const useInstanceProps = (instanceId: Instance["id"]) => {
|
|
|
55
55
|
continue;
|
|
56
56
|
}
|
|
57
57
|
if (prop.type === "action") {
|
|
58
|
-
instancePropsObject[prop.name] = () => {
|
|
58
|
+
instancePropsObject[prop.name] = (...args: unknown[]) => {
|
|
59
59
|
// prevent all actions in canvas mode
|
|
60
60
|
if (renderer === "canvas") {
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
for (const value of prop.value) {
|
|
64
64
|
if (value.type === "execute") {
|
|
65
|
+
const argsMap = new Map<string, unknown>();
|
|
66
|
+
for (const [i, name] of value.args.entries()) {
|
|
67
|
+
argsMap.set(name, args[i]);
|
|
68
|
+
}
|
|
65
69
|
const newValues = executeEffectfulExpression(
|
|
66
70
|
value.code,
|
|
71
|
+
argsMap,
|
|
67
72
|
dataSourceValues
|
|
68
73
|
);
|
|
69
74
|
setDataSourceValues(newValues);
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Fragment,
|
|
3
|
+
type ForwardRefExoticComponent,
|
|
4
|
+
type RefAttributes,
|
|
5
|
+
} from "react";
|
|
2
6
|
import type { ReadableAtom } from "nanostores";
|
|
3
7
|
import { Scripts, ScrollRestoration } from "@remix-run/react";
|
|
4
8
|
import type { Assets } from "@webstudio-is/asset-uploader";
|
|
@@ -10,7 +14,7 @@ import {
|
|
|
10
14
|
ReactSdkContext,
|
|
11
15
|
} from "../context";
|
|
12
16
|
import type { Pages, PropsByInstanceId } from "../props";
|
|
13
|
-
import type {
|
|
17
|
+
import type { WebstudioComponentProps } from "./webstudio-component";
|
|
14
18
|
|
|
15
19
|
type InstanceSelector = Instance["id"][];
|
|
16
20
|
|
|
@@ -36,11 +40,15 @@ export const createElementsTree = ({
|
|
|
36
40
|
pagesStore: ReadableAtom<Pages>;
|
|
37
41
|
executeEffectfulExpression: (
|
|
38
42
|
expression: string,
|
|
43
|
+
args: DataSourceValues,
|
|
39
44
|
values: DataSourceValues
|
|
40
45
|
) => DataSourceValues;
|
|
41
46
|
dataSourceValuesStore: ReadableAtom<DataSourceValues>;
|
|
42
47
|
onDataSourceUpdate: (newValues: DataSourceValues) => void;
|
|
43
|
-
|
|
48
|
+
|
|
49
|
+
Component: ForwardRefExoticComponent<
|
|
50
|
+
WebstudioComponentProps & RefAttributes<HTMLElement>
|
|
51
|
+
>;
|
|
44
52
|
components: Components;
|
|
45
53
|
}) => {
|
|
46
54
|
const rootInstance = instances.get(rootInstanceId);
|
|
@@ -110,7 +118,9 @@ const createInstanceChildrenElements = ({
|
|
|
110
118
|
instances: Instances;
|
|
111
119
|
instanceSelector: InstanceSelector;
|
|
112
120
|
children: Instance["children"];
|
|
113
|
-
Component:
|
|
121
|
+
Component: ForwardRefExoticComponent<
|
|
122
|
+
WebstudioComponentProps & RefAttributes<HTMLElement>
|
|
123
|
+
>;
|
|
114
124
|
components: Components;
|
|
115
125
|
}) => {
|
|
116
126
|
const elements = [];
|
|
@@ -152,7 +162,9 @@ const createInstanceElement = ({
|
|
|
152
162
|
}: {
|
|
153
163
|
instance: Instance;
|
|
154
164
|
instanceSelector: InstanceSelector;
|
|
155
|
-
Component:
|
|
165
|
+
Component: ForwardRefExoticComponent<
|
|
166
|
+
WebstudioComponentProps & RefAttributes<HTMLElement>
|
|
167
|
+
>;
|
|
156
168
|
children?: Array<JSX.Element | string>;
|
|
157
169
|
components: Components;
|
|
158
170
|
}) => {
|
package/src/tree/root.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
type ForwardRefExoticComponent,
|
|
5
|
+
type RefAttributes,
|
|
6
|
+
} from "react";
|
|
2
7
|
import {
|
|
3
8
|
atom,
|
|
4
9
|
computed,
|
|
@@ -8,7 +13,10 @@ import {
|
|
|
8
13
|
import { type Build, type Page } from "@webstudio-is/project-build";
|
|
9
14
|
import type { Asset } from "@webstudio-is/asset-uploader";
|
|
10
15
|
import { createElementsTree } from "./create-elements-tree";
|
|
11
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
WebstudioComponent,
|
|
18
|
+
type WebstudioComponentProps,
|
|
19
|
+
} from "./webstudio-component";
|
|
12
20
|
import { getPropsByInstanceId } from "../props";
|
|
13
21
|
import type { Components } from "../components/components-utils";
|
|
14
22
|
import type { Params, DataSourceValues } from "../context";
|
|
@@ -30,9 +38,12 @@ type RootProps = {
|
|
|
30
38
|
executeComputingExpressions: (values: DataSourceValues) => DataSourceValues;
|
|
31
39
|
executeEffectfulExpression: (
|
|
32
40
|
expression: string,
|
|
41
|
+
args: DataSourceValues,
|
|
33
42
|
values: DataSourceValues
|
|
34
43
|
) => DataSourceValues;
|
|
35
|
-
Component?:
|
|
44
|
+
Component?: ForwardRefExoticComponent<
|
|
45
|
+
WebstudioComponentProps & RefAttributes<HTMLElement>
|
|
46
|
+
>;
|
|
36
47
|
components: Components;
|
|
37
48
|
};
|
|
38
49
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fragment } from "react";
|
|
1
|
+
import { Fragment, forwardRef } from "react";
|
|
2
2
|
import type { Instance } from "@webstudio-is/project-build";
|
|
3
3
|
import type { Components } from "../components/components-utils";
|
|
4
4
|
import { useInstanceProps } from "../props";
|
|
@@ -26,20 +26,18 @@ export const renderWebstudioComponentChildren = (
|
|
|
26
26
|
});
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
type WebstudioComponentProps = {
|
|
29
|
+
export type WebstudioComponentProps = {
|
|
30
30
|
instance: Instance;
|
|
31
31
|
instanceSelector: Instance["id"][];
|
|
32
32
|
children: Array<JSX.Element | string>;
|
|
33
33
|
components: Components;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
...rest
|
|
42
|
-
}: WebstudioComponentProps) => {
|
|
36
|
+
// eslint-disable-next-line react/display-name
|
|
37
|
+
export const WebstudioComponent = forwardRef<
|
|
38
|
+
HTMLElement,
|
|
39
|
+
WebstudioComponentProps
|
|
40
|
+
>(({ instance, instanceSelector, children, components, ...rest }, ref) => {
|
|
43
41
|
const { [showAttribute]: show = true, ...instanceProps } = useInstanceProps(
|
|
44
42
|
instance.id
|
|
45
43
|
);
|
|
@@ -57,13 +55,42 @@ export const WebstudioComponent = ({
|
|
|
57
55
|
return <></>;
|
|
58
56
|
}
|
|
59
57
|
return (
|
|
60
|
-
<Component {...props}>
|
|
58
|
+
<Component {...props} ref={ref}>
|
|
61
59
|
{renderWebstudioComponentChildren(children)}
|
|
62
60
|
</Component>
|
|
63
61
|
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export const idAttribute = "data-ws-id" as const;
|
|
65
|
+
export const selectorIdAttribute = "data-ws-selector" as const;
|
|
66
|
+
export const componentAttribute = "data-ws-component" as const;
|
|
67
|
+
export const showAttribute = "data-ws-show" as const;
|
|
68
|
+
export const collapsedAttribute = "data-ws-collapsed" as const;
|
|
69
|
+
|
|
70
|
+
export type WebstudioAttributes = {
|
|
71
|
+
[idAttribute]?: string | undefined;
|
|
72
|
+
[selectorIdAttribute]?: string | undefined;
|
|
73
|
+
[componentAttribute]?: string | undefined;
|
|
74
|
+
[showAttribute]?: string | undefined;
|
|
75
|
+
[collapsedAttribute]?: string | undefined;
|
|
64
76
|
};
|
|
65
77
|
|
|
66
|
-
export const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
78
|
+
export const splitPropsWithWebstudioAttributes = <
|
|
79
|
+
P extends WebstudioAttributes,
|
|
80
|
+
>({
|
|
81
|
+
[idAttribute]: idAttributeValue,
|
|
82
|
+
[componentAttribute]: componentAttributeValue,
|
|
83
|
+
[showAttribute]: showAttributeValue,
|
|
84
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
85
|
+
[selectorIdAttribute]: parentIdAttributeValue,
|
|
86
|
+
...props
|
|
87
|
+
}: P): [WebstudioAttributes, Omit<P, keyof WebstudioAttributes>] => [
|
|
88
|
+
{
|
|
89
|
+
[idAttribute]: idAttributeValue,
|
|
90
|
+
[componentAttribute]: componentAttributeValue,
|
|
91
|
+
[showAttribute]: showAttributeValue,
|
|
92
|
+
[collapsedAttribute]: collapsedAttributeValue,
|
|
93
|
+
[selectorIdAttribute]: parentIdAttributeValue,
|
|
94
|
+
},
|
|
95
|
+
props,
|
|
96
|
+
];
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var get_browser_style_exports = {};
|
|
20
|
-
__export(get_browser_style_exports, {
|
|
21
|
-
getBrowserStyle: () => getBrowserStyle
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(get_browser_style_exports);
|
|
24
|
-
var import_detect_font = require("detect-font");
|
|
25
|
-
var import_css_data = require("@webstudio-is/css-data");
|
|
26
|
-
var import_css_data2 = require("@webstudio-is/css-data");
|
|
27
|
-
const unitsList = Object.values(import_css_data2.units).flat();
|
|
28
|
-
const unitRegex = new RegExp(`${unitsList.join("|")}`);
|
|
29
|
-
const parseValue = (property, value) => {
|
|
30
|
-
const number = Number.parseFloat(value);
|
|
31
|
-
const parsedUnit = unitRegex.exec(value);
|
|
32
|
-
if (value === "rgba(0, 0, 0, 0)") {
|
|
33
|
-
value = "transparent";
|
|
34
|
-
}
|
|
35
|
-
if (Number.isNaN(number)) {
|
|
36
|
-
const values = import_css_data.keywordValues[property];
|
|
37
|
-
if (values?.includes(value)) {
|
|
38
|
-
return {
|
|
39
|
-
type: "keyword",
|
|
40
|
-
value
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return {
|
|
44
|
-
type: "unparsed",
|
|
45
|
-
value
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (number === 0 && property in import_css_data2.properties) {
|
|
49
|
-
return import_css_data2.properties[property].initial;
|
|
50
|
-
}
|
|
51
|
-
if (parsedUnit === null) {
|
|
52
|
-
return {
|
|
53
|
-
type: "unit",
|
|
54
|
-
unit: "number",
|
|
55
|
-
value: number
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
type: "unit",
|
|
60
|
-
unit: parsedUnit[0],
|
|
61
|
-
value: number
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
const getBrowserStyle = (element) => {
|
|
65
|
-
const browserStyle = {};
|
|
66
|
-
if (element === void 0) {
|
|
67
|
-
return browserStyle;
|
|
68
|
-
}
|
|
69
|
-
let knownProperty;
|
|
70
|
-
const computedStyle = getComputedStyle(element);
|
|
71
|
-
for (knownProperty in import_css_data2.properties) {
|
|
72
|
-
if (knownProperty in computedStyle === false) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
const computedValue = computedStyle[knownProperty];
|
|
76
|
-
browserStyle[knownProperty] = parseValue(knownProperty, computedValue);
|
|
77
|
-
}
|
|
78
|
-
browserStyle.fontFamily = {
|
|
79
|
-
type: "fontFamily",
|
|
80
|
-
value: [(0, import_detect_font.detectFont)(element)]
|
|
81
|
-
};
|
|
82
|
-
return browserStyle;
|
|
83
|
-
};
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { detectFont } from "detect-font";
|
|
2
|
-
import {
|
|
3
|
-
keywordValues
|
|
4
|
-
} from "@webstudio-is/css-data";
|
|
5
|
-
import { properties, units } from "@webstudio-is/css-data";
|
|
6
|
-
const unitsList = Object.values(units).flat();
|
|
7
|
-
const unitRegex = new RegExp(`${unitsList.join("|")}`);
|
|
8
|
-
const parseValue = (property, value) => {
|
|
9
|
-
const number = Number.parseFloat(value);
|
|
10
|
-
const parsedUnit = unitRegex.exec(value);
|
|
11
|
-
if (value === "rgba(0, 0, 0, 0)") {
|
|
12
|
-
value = "transparent";
|
|
13
|
-
}
|
|
14
|
-
if (Number.isNaN(number)) {
|
|
15
|
-
const values = keywordValues[property];
|
|
16
|
-
if (values?.includes(value)) {
|
|
17
|
-
return {
|
|
18
|
-
type: "keyword",
|
|
19
|
-
value
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
return {
|
|
23
|
-
type: "unparsed",
|
|
24
|
-
value
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
if (number === 0 && property in properties) {
|
|
28
|
-
return properties[property].initial;
|
|
29
|
-
}
|
|
30
|
-
if (parsedUnit === null) {
|
|
31
|
-
return {
|
|
32
|
-
type: "unit",
|
|
33
|
-
unit: "number",
|
|
34
|
-
value: number
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
type: "unit",
|
|
39
|
-
unit: parsedUnit[0],
|
|
40
|
-
value: number
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
const getBrowserStyle = (element) => {
|
|
44
|
-
const browserStyle = {};
|
|
45
|
-
if (element === void 0) {
|
|
46
|
-
return browserStyle;
|
|
47
|
-
}
|
|
48
|
-
let knownProperty;
|
|
49
|
-
const computedStyle = getComputedStyle(element);
|
|
50
|
-
for (knownProperty in properties) {
|
|
51
|
-
if (knownProperty in computedStyle === false) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
const computedValue = computedStyle[knownProperty];
|
|
55
|
-
browserStyle[knownProperty] = parseValue(knownProperty, computedValue);
|
|
56
|
-
}
|
|
57
|
-
browserStyle.fontFamily = {
|
|
58
|
-
type: "fontFamily",
|
|
59
|
-
value: [detectFont(element)]
|
|
60
|
-
};
|
|
61
|
-
return browserStyle;
|
|
62
|
-
};
|
|
63
|
-
export {
|
|
64
|
-
getBrowserStyle
|
|
65
|
-
};
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { detectFont } from "detect-font";
|
|
2
|
-
import {
|
|
3
|
-
type Style,
|
|
4
|
-
type StyleValue,
|
|
5
|
-
type Unit,
|
|
6
|
-
keywordValues,
|
|
7
|
-
} from "@webstudio-is/css-data";
|
|
8
|
-
import { properties, units } from "@webstudio-is/css-data";
|
|
9
|
-
|
|
10
|
-
const unitsList = Object.values(units).flat();
|
|
11
|
-
const unitRegex = new RegExp(`${unitsList.join("|")}`);
|
|
12
|
-
|
|
13
|
-
// @todo use a parser
|
|
14
|
-
const parseValue = (
|
|
15
|
-
property: keyof typeof properties,
|
|
16
|
-
value: string
|
|
17
|
-
): StyleValue => {
|
|
18
|
-
const number = Number.parseFloat(value);
|
|
19
|
-
const parsedUnit = unitRegex.exec(value);
|
|
20
|
-
if (value === "rgba(0, 0, 0, 0)") {
|
|
21
|
-
value = "transparent";
|
|
22
|
-
}
|
|
23
|
-
if (Number.isNaN(number)) {
|
|
24
|
-
const values = keywordValues[
|
|
25
|
-
property as keyof typeof keywordValues
|
|
26
|
-
] as ReadonlyArray<string>;
|
|
27
|
-
|
|
28
|
-
if (values?.includes(value)) {
|
|
29
|
-
return {
|
|
30
|
-
type: "keyword",
|
|
31
|
-
value: value,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
type: "unparsed",
|
|
37
|
-
value: value,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (number === 0 && property in properties) {
|
|
42
|
-
return properties[property].initial;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (parsedUnit === null) {
|
|
46
|
-
return {
|
|
47
|
-
type: "unit",
|
|
48
|
-
unit: "number",
|
|
49
|
-
value: number,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
type: "unit",
|
|
55
|
-
unit: parsedUnit[0] as Unit,
|
|
56
|
-
value: number,
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const getBrowserStyle = (element?: Element): Style => {
|
|
61
|
-
const browserStyle: Style = {};
|
|
62
|
-
if (element === undefined) {
|
|
63
|
-
return browserStyle;
|
|
64
|
-
}
|
|
65
|
-
let knownProperty: keyof typeof properties;
|
|
66
|
-
const computedStyle = getComputedStyle(element);
|
|
67
|
-
for (knownProperty in properties) {
|
|
68
|
-
if (knownProperty in computedStyle === false) {
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
// Typescript doesn't know we can access CSSStyleDeclaration properties by keys
|
|
72
|
-
const computedValue = computedStyle[knownProperty as unknown as number];
|
|
73
|
-
browserStyle[knownProperty] = parseValue(knownProperty, computedValue);
|
|
74
|
-
}
|
|
75
|
-
// We need a single font-family that is actually rendered. Computed style will return a list of potential fonts.
|
|
76
|
-
browserStyle.fontFamily = {
|
|
77
|
-
type: "fontFamily",
|
|
78
|
-
value: [detectFont(element)],
|
|
79
|
-
};
|
|
80
|
-
return browserStyle;
|
|
81
|
-
};
|