@arronqzy/react-view 1.0.3 → 1.0.7
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/styles.css +555 -15
- package/package.json +14 -7
- package/readme.md +74 -5
- package/src/core/template.tsx +12 -2
- package/src/panel/ReactViewOnlinePreview.tsx +18 -8
- package/src/panel/ReactViewPanel.tsx +403 -177
- package/src/panel/ai/AssistantChatPanel.tsx +895 -0
- package/src/panel/ai/AssistantMarkdown.tsx +256 -0
- package/src/panel/ai/applyAssistantAction.ts +652 -0
- package/src/panel/ai/revealConfigField.ts +137 -0
- package/src/panel/components/ConfigHintIcon.tsx +50 -0
- package/src/panel/components/ElementsLayer.tsx +39 -22
- package/src/panel/components/MaterialSidebar.tsx +157 -109
- package/src/panel/components/MoveableLayer.tsx +75 -61
- package/src/panel/components/PanelCanvas.tsx +81 -64
- package/src/panel/components/PanelConfigSidebar.tsx +471 -448
- package/src/panel/components/SelectLayer.tsx +1 -0
- package/src/panel/components/ViewElementScopePanel.tsx +13 -12
- package/src/panel/components/WorkspaceConfigSidebar.tsx +5 -2
- package/src/panel/components/WorkspaceProjectNav.tsx +25 -14
- package/src/panel/components/WorkspaceStageSplit.tsx +3 -1
- package/src/panel/components/scope-config/ScopeConfigContext.tsx +9 -0
- package/src/panel/components/scope-config/ScopeTemplatePreviewHost.tsx +242 -0
- package/src/panel/components/scope-config/ScopeTemplateUsageHint.tsx +12 -0
- package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.tsx +6 -3
- package/src/panel/components/table/ConditionEditor.tsx +205 -0
- package/src/panel/components/table/JsonCodeEditor.tsx +115 -0
- package/src/panel/components/table/PanelConfigTableSection.tsx +2192 -0
- package/src/panel/components/table/TableNodeContent.tsx +544 -0
- package/src/panel/constants/messages.ts +76 -34
- package/src/panel/hooks/usePanelElements.ts +64 -52
- package/src/panel/hooks/useRafThrottledScroll.ts +30 -0
- package/src/panel/hooks/useWorkspaceProjects.ts +11 -8
- package/src/panel/types.ts +6 -0
- package/src/panel/utils/chartOptionBuilder.ts +12 -1
- package/src/panel/utils/panelElementDefaults.ts +69 -39
- package/src/panel/utils/scope-field-labels.ts +51 -37
- package/src/panel/utils/scope-template-chart.ts +92 -0
- package/src/panel/utils/scope-template-preview.ts +128 -0
- package/src/panel/utils/scope-template-spread.ts +252 -0
- package/src/panel/utils/scope-template-warnings.ts +131 -11
- package/src/panel/utils/scope-template.ts +105 -3
- package/src/tailwind.css +36 -15
|
@@ -1,6 +1,22 @@
|
|
|
1
|
+
import type { TranslateFn } from "@arronqzy/i18n";
|
|
2
|
+
import { tForLocale } from "@arronqzy/i18n";
|
|
1
3
|
import type { PanelElement } from "../types";
|
|
2
4
|
import { hasScopeTemplate } from "./scope-template";
|
|
3
5
|
import { resolveScopeFieldLabel } from "./scope-field-labels";
|
|
6
|
+
import {
|
|
7
|
+
SCOPE_SPREAD_TEMPLATE_RE,
|
|
8
|
+
buildSpreadInvalidExpressionWarningMessage,
|
|
9
|
+
buildSpreadNotArrayWarningMessage,
|
|
10
|
+
formatScopePathSegments,
|
|
11
|
+
isSpreadTemplateBrace,
|
|
12
|
+
parseScopePathSegments,
|
|
13
|
+
resolveSpreadScopePath,
|
|
14
|
+
} from "./scope-template-spread";
|
|
15
|
+
|
|
16
|
+
export type ScopeTemplateWarningKind =
|
|
17
|
+
| "missing-path"
|
|
18
|
+
| "spread-not-array"
|
|
19
|
+
| "spread-invalid-expression";
|
|
4
20
|
|
|
5
21
|
export type ScopeTemplateWarning = {
|
|
6
22
|
fieldId: string;
|
|
@@ -9,6 +25,7 @@ export type ScopeTemplateWarning = {
|
|
|
9
25
|
expression: string;
|
|
10
26
|
missingPath: string;
|
|
11
27
|
message: string;
|
|
28
|
+
kind: ScopeTemplateWarningKind;
|
|
12
29
|
};
|
|
13
30
|
|
|
14
31
|
const SCOPE_PATH_RE = /scope(?:\?\.|\.)(\w+(?:\?\.\w+)*)/g;
|
|
@@ -41,19 +58,119 @@ function pathExistsInScope(scope: unknown, path: string): boolean {
|
|
|
41
58
|
return true;
|
|
42
59
|
}
|
|
43
60
|
|
|
61
|
+
function analyzeSpreadTemplateValue(
|
|
62
|
+
fieldId: string,
|
|
63
|
+
value: string,
|
|
64
|
+
scope: unknown,
|
|
65
|
+
t: TranslateFn
|
|
66
|
+
): ScopeTemplateWarning[] {
|
|
67
|
+
const warnings: ScopeTemplateWarning[] = [];
|
|
68
|
+
const fieldLabel = resolveScopeFieldLabel(fieldId, t);
|
|
69
|
+
const spreadRe = new RegExp(SCOPE_SPREAD_TEMPLATE_RE.source, "g");
|
|
70
|
+
let match: RegExpExecArray | null;
|
|
71
|
+
|
|
72
|
+
while ((match = spreadRe.exec(value)) !== null) {
|
|
73
|
+
const spreadTemplate = match[0];
|
|
74
|
+
const expression = match[1].trim();
|
|
75
|
+
const segments = parseScopePathSegments(expression);
|
|
76
|
+
|
|
77
|
+
if (segments === null || segments.length === 0) {
|
|
78
|
+
warnings.push({
|
|
79
|
+
fieldId,
|
|
80
|
+
fieldLabel,
|
|
81
|
+
template: value,
|
|
82
|
+
expression,
|
|
83
|
+
missingPath: "",
|
|
84
|
+
kind: "spread-invalid-expression",
|
|
85
|
+
message: buildSpreadInvalidExpressionWarningMessage(
|
|
86
|
+
fieldLabel,
|
|
87
|
+
spreadTemplate,
|
|
88
|
+
t
|
|
89
|
+
),
|
|
90
|
+
});
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const resolved = resolveSpreadScopePath(expression, scope);
|
|
95
|
+
if (resolved.ok) continue;
|
|
96
|
+
|
|
97
|
+
if (resolved.issue === "invalid-expression") {
|
|
98
|
+
warnings.push({
|
|
99
|
+
fieldId,
|
|
100
|
+
fieldLabel,
|
|
101
|
+
template: value,
|
|
102
|
+
expression,
|
|
103
|
+
missingPath: "",
|
|
104
|
+
kind: "spread-invalid-expression",
|
|
105
|
+
message: buildSpreadInvalidExpressionWarningMessage(
|
|
106
|
+
fieldLabel,
|
|
107
|
+
spreadTemplate,
|
|
108
|
+
t
|
|
109
|
+
),
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const arrayPath =
|
|
115
|
+
resolved.arrayPath ?? formatScopePathSegments(segments.slice(0, -1));
|
|
116
|
+
|
|
117
|
+
if (resolved.issue === "path-missing") {
|
|
118
|
+
if (!pathExistsInScope(scope, arrayPath)) {
|
|
119
|
+
warnings.push({
|
|
120
|
+
fieldId,
|
|
121
|
+
fieldLabel,
|
|
122
|
+
template: value,
|
|
123
|
+
expression,
|
|
124
|
+
missingPath: arrayPath,
|
|
125
|
+
kind: "missing-path",
|
|
126
|
+
message: t("panel.scope.warnMissingPath", {
|
|
127
|
+
fieldLabel,
|
|
128
|
+
path: arrayPath,
|
|
129
|
+
}),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (resolved.issue === "not-array") {
|
|
136
|
+
warnings.push({
|
|
137
|
+
fieldId,
|
|
138
|
+
fieldLabel,
|
|
139
|
+
template: value,
|
|
140
|
+
expression,
|
|
141
|
+
missingPath: arrayPath,
|
|
142
|
+
kind: "spread-not-array",
|
|
143
|
+
message: buildSpreadNotArrayWarningMessage(
|
|
144
|
+
fieldLabel,
|
|
145
|
+
spreadTemplate,
|
|
146
|
+
expression,
|
|
147
|
+
arrayPath,
|
|
148
|
+
t
|
|
149
|
+
),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return warnings;
|
|
155
|
+
}
|
|
156
|
+
|
|
44
157
|
function analyzeTemplateValue(
|
|
45
158
|
fieldId: string,
|
|
46
159
|
value: string,
|
|
47
|
-
scope: unknown
|
|
160
|
+
scope: unknown,
|
|
161
|
+
t: TranslateFn
|
|
48
162
|
): ScopeTemplateWarning[] {
|
|
49
163
|
if (!hasScopeTemplate(value)) return [];
|
|
50
164
|
|
|
51
|
-
const warnings: ScopeTemplateWarning[] = [
|
|
52
|
-
|
|
165
|
+
const warnings: ScopeTemplateWarning[] = [
|
|
166
|
+
...analyzeSpreadTemplateValue(fieldId, value, scope, t),
|
|
167
|
+
];
|
|
168
|
+
const fieldLabel = resolveScopeFieldLabel(fieldId, t);
|
|
53
169
|
const expressionRe = /\{([^}]+)\}/g;
|
|
54
170
|
let match: RegExpExecArray | null;
|
|
55
171
|
|
|
56
172
|
while ((match = expressionRe.exec(value)) !== null) {
|
|
173
|
+
if (isSpreadTemplateBrace(value, match.index)) continue;
|
|
57
174
|
const expression = match[1].trim();
|
|
58
175
|
const paths = extractScopePropertyPaths(expression);
|
|
59
176
|
for (const path of paths) {
|
|
@@ -64,7 +181,8 @@ function analyzeTemplateValue(
|
|
|
64
181
|
template: value,
|
|
65
182
|
expression,
|
|
66
183
|
missingPath: path,
|
|
67
|
-
|
|
184
|
+
kind: "missing-path",
|
|
185
|
+
message: t("panel.scope.warnMissingPath", { fieldLabel, path }),
|
|
68
186
|
});
|
|
69
187
|
}
|
|
70
188
|
}
|
|
@@ -80,18 +198,19 @@ function walkElementStrings(
|
|
|
80
198
|
value: unknown,
|
|
81
199
|
fieldId: string,
|
|
82
200
|
scope: unknown,
|
|
83
|
-
warnings: ScopeTemplateWarning[]
|
|
201
|
+
warnings: ScopeTemplateWarning[],
|
|
202
|
+
t: TranslateFn
|
|
84
203
|
) {
|
|
85
204
|
if (shouldSkipField(fieldId)) return;
|
|
86
205
|
|
|
87
206
|
if (typeof value === "string") {
|
|
88
|
-
warnings.push(...analyzeTemplateValue(fieldId, value, scope));
|
|
207
|
+
warnings.push(...analyzeTemplateValue(fieldId, value, scope, t));
|
|
89
208
|
return;
|
|
90
209
|
}
|
|
91
210
|
|
|
92
211
|
if (Array.isArray(value)) {
|
|
93
212
|
value.forEach((item, index) => {
|
|
94
|
-
walkElementStrings(item, `${fieldId}.${index}`, scope, warnings);
|
|
213
|
+
walkElementStrings(item, `${fieldId}.${index}`, scope, warnings, t);
|
|
95
214
|
});
|
|
96
215
|
return;
|
|
97
216
|
}
|
|
@@ -99,23 +218,24 @@ function walkElementStrings(
|
|
|
99
218
|
if (value && typeof value === "object") {
|
|
100
219
|
for (const [key, nested] of Object.entries(value)) {
|
|
101
220
|
const nextId = fieldId ? `${fieldId}.${key}` : key;
|
|
102
|
-
walkElementStrings(nested, nextId, scope, warnings);
|
|
221
|
+
walkElementStrings(nested, nextId, scope, warnings, t);
|
|
103
222
|
}
|
|
104
223
|
}
|
|
105
224
|
}
|
|
106
225
|
|
|
107
226
|
export function collectElementScopeWarnings(
|
|
108
227
|
element: PanelElement,
|
|
109
|
-
scope: unknown
|
|
228
|
+
scope: unknown,
|
|
229
|
+
t: TranslateFn = tForLocale("zh-CN")
|
|
110
230
|
): ScopeTemplateWarning[] {
|
|
111
231
|
if (scope === undefined) return [];
|
|
112
232
|
|
|
113
233
|
const warnings: ScopeTemplateWarning[] = [];
|
|
114
|
-
walkElementStrings(element, "", scope, warnings);
|
|
234
|
+
walkElementStrings(element, "", scope, warnings, t);
|
|
115
235
|
|
|
116
236
|
const seen = new Set<string>();
|
|
117
237
|
return warnings.filter((warning) => {
|
|
118
|
-
const key = `${warning.fieldId}|${warning.missingPath}|${warning.expression}`;
|
|
238
|
+
const key = `${warning.fieldId}|${warning.kind}|${warning.missingPath}|${warning.expression}`;
|
|
119
239
|
if (seen.has(key)) return false;
|
|
120
240
|
seen.add(key);
|
|
121
241
|
return true;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import type { PanelElement } from "../types";
|
|
2
|
+
import type { PanelTableConfig } from "@arronqzy/view-table";
|
|
3
|
+
import { isUsableTableRawData } from "@arronqzy/view-table";
|
|
4
|
+
import { materializeChartLabelsFromScope } from "./scope-template-chart";
|
|
5
|
+
import {
|
|
6
|
+
SCOPE_SPREAD_TEMPLATE_RE,
|
|
7
|
+
evaluateSpreadScopeExpression,
|
|
8
|
+
extractSpreadScopeExpression,
|
|
9
|
+
getValueAtScopePath,
|
|
10
|
+
isSpreadOnlyScopeTemplate,
|
|
11
|
+
resolveSpreadScopePath,
|
|
12
|
+
} from "./scope-template-spread";
|
|
2
13
|
|
|
3
|
-
const SCOPE_TEMPLATE_RE = /\{[^}]+\}/;
|
|
14
|
+
const SCOPE_TEMPLATE_RE = /\{[^}]+\}|\[\.\.\.\{[^}]+\}\]/;
|
|
4
15
|
|
|
5
16
|
export function hasScopeTemplate(value: string): boolean {
|
|
6
17
|
return SCOPE_TEMPLATE_RE.test(value);
|
|
@@ -25,7 +36,16 @@ export function evaluateScopeTemplate(
|
|
|
25
36
|
scope: unknown
|
|
26
37
|
): string {
|
|
27
38
|
if (!hasScopeTemplate(template)) return template;
|
|
28
|
-
|
|
39
|
+
|
|
40
|
+
const withSpread = template.replace(
|
|
41
|
+
SCOPE_SPREAD_TEMPLATE_RE,
|
|
42
|
+
(_: string, rawExpr: string) => {
|
|
43
|
+
const result = evaluateSpreadScopeExpression(rawExpr, scope);
|
|
44
|
+
return result.ok ? result.value : "";
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
return withSpread.replace(/\{([^}]+)\}/g, (_: string, rawExpr: string) => {
|
|
29
49
|
const value = evaluateScopeExpression(rawExpr, scope);
|
|
30
50
|
if (value === null || value === undefined) return "";
|
|
31
51
|
if (typeof value === "string") return value;
|
|
@@ -40,6 +60,65 @@ export function evaluateScopeTemplate(
|
|
|
40
60
|
});
|
|
41
61
|
}
|
|
42
62
|
|
|
63
|
+
function tryParseJson(text: string): unknown | undefined {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(text);
|
|
66
|
+
} catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function materializeTemplateValue(template: string, scope: unknown): unknown {
|
|
72
|
+
const trimmed = template.trim();
|
|
73
|
+
if (!trimmed) return undefined;
|
|
74
|
+
|
|
75
|
+
if (isSpreadOnlyScopeTemplate(trimmed)) {
|
|
76
|
+
const expression = extractSpreadScopeExpression(trimmed);
|
|
77
|
+
if (!expression) return undefined;
|
|
78
|
+
const resolved = resolveSpreadScopePath(expression, scope);
|
|
79
|
+
if (!resolved.ok) return undefined;
|
|
80
|
+
if (resolved.itemPathSegments.length === 0) {
|
|
81
|
+
return resolved.arrayValue;
|
|
82
|
+
}
|
|
83
|
+
return resolved.arrayValue.map((item) =>
|
|
84
|
+
getValueAtScopePath(item, resolved.itemPathSegments)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const singleMatch = /^\{([^}]+)\}$/.exec(trimmed);
|
|
89
|
+
if (singleMatch) {
|
|
90
|
+
return evaluateScopeExpression(singleMatch[1]!, scope);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (hasScopeTemplate(trimmed)) {
|
|
94
|
+
const text = evaluateScopeTemplate(trimmed, scope);
|
|
95
|
+
const parsed = tryParseJson(text);
|
|
96
|
+
return parsed !== undefined ? parsed : text;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return tryParseJson(trimmed);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function materializeTableSourceFromScope(
|
|
103
|
+
table: PanelTableConfig | undefined,
|
|
104
|
+
scope: unknown
|
|
105
|
+
): unknown | undefined {
|
|
106
|
+
if (!table) return undefined;
|
|
107
|
+
|
|
108
|
+
if (typeof table.source === "string" && table.source.trim()) {
|
|
109
|
+
return materializeTemplateValue(table.source, scope);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (typeof table.rowsText === "string" && table.rowsText.trim()) {
|
|
113
|
+
const trimmed = table.rowsText.trim();
|
|
114
|
+
if (hasScopeTemplate(trimmed) || isSpreadOnlyScopeTemplate(trimmed)) {
|
|
115
|
+
return materializeTemplateValue(trimmed, scope);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
43
122
|
function resolveScopedValue<T>(value: T, scope: unknown): T {
|
|
44
123
|
if (typeof value === "string" && hasScopeTemplate(value)) {
|
|
45
124
|
return evaluateScopeTemplate(value, scope) as T;
|
|
@@ -62,7 +141,30 @@ export function resolvePanelElementScope(
|
|
|
62
141
|
scope: unknown | undefined
|
|
63
142
|
): PanelElement {
|
|
64
143
|
if (scope === undefined) return element;
|
|
65
|
-
|
|
144
|
+
const resolved = resolveScopedValue(structuredClone(element), scope);
|
|
145
|
+
if (resolved.chart) {
|
|
146
|
+
const labels = materializeChartLabelsFromScope(element.chart, scope);
|
|
147
|
+
if (labels !== undefined) {
|
|
148
|
+
resolved.chart.labels = labels;
|
|
149
|
+
delete resolved.chart.labelsText;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (resolved.table) {
|
|
153
|
+
const hasDynamicSource =
|
|
154
|
+
typeof element.table?.source === "string" && element.table.source.trim().length > 0;
|
|
155
|
+
if (hasDynamicSource) {
|
|
156
|
+
const raw = materializeTableSourceFromScope(element.table, scope);
|
|
157
|
+
if (isUsableTableRawData(raw)) {
|
|
158
|
+
resolved.table = { ...resolved.table, rows: raw };
|
|
159
|
+
} else {
|
|
160
|
+
// Dynamic missing/empty → fall back to static rowsText (do not keep empty rows)
|
|
161
|
+
const next = { ...resolved.table };
|
|
162
|
+
delete next.rows;
|
|
163
|
+
resolved.table = next;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return resolved;
|
|
66
168
|
}
|
|
67
169
|
|
|
68
170
|
export function formatViewElementScope(scope: unknown): string {
|
package/src/tailwind.css
CHANGED
|
@@ -26,33 +26,54 @@
|
|
|
26
26
|
background: hsl(var(--foreground) / 0.45);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/*
|
|
29
|
+
/*
|
|
30
|
+
* Moveable 控制框:
|
|
31
|
+
* - 根节点必须高于画布元素 zIndex(节点默认 ≥1),否则多选组框线会被节点盖住,只剩锚点可见
|
|
32
|
+
* - 勿把 .moveable-group 压到 z-index:1(会覆盖根节点的 9999)
|
|
33
|
+
*/
|
|
30
34
|
.rv-moveable-layer {
|
|
31
35
|
--moveable-color: #1990ff;
|
|
36
|
+
z-index: 9999 !important;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
.rv-moveable-layer
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
margin-top: -7px !important;
|
|
38
|
-
margin-left: -7px !important;
|
|
39
|
-
border-radius: 50% !important;
|
|
40
|
-
box-sizing: border-box !important;
|
|
41
|
-
border: 2px solid hsl(var(--background)) !important;
|
|
42
|
-
background: #1990ff !important;
|
|
43
|
-
background: var(--moveable-color) !important;
|
|
39
|
+
.rv-moveable-layer.moveable-group,
|
|
40
|
+
.rv-moveable-layer.moveable-control-box {
|
|
41
|
+
z-index: 9999 !important;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
|
-
.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
margin: 0 !important;
|
|
44
|
+
/* Moveable 默认 .group { z-index: -1 },必须覆盖,避免整组掉到节点下方 */
|
|
45
|
+
.rv-moveable-layer.moveable-group {
|
|
46
|
+
z-index: 9999 !important;
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
.rv-moveable-layer .moveable-line {
|
|
53
50
|
--moveable-color: #1990ff;
|
|
51
|
+
background: var(--moveable-color) !important;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* 组选/边线:保持颜色;厚度仍由 moveable zoom 的 scaleY 补偿 */
|
|
55
|
+
.rv-moveable-layer .moveable-line.moveable-direction:not(.moveable-edge) {
|
|
56
|
+
background: var(--moveable-color) !important;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* 子 control-box 相对组内层叠,勿压低根节点 */
|
|
60
|
+
.rv-moveable-layer.moveable-group > .moveable-control-box {
|
|
61
|
+
z-index: 2 !important;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
.rv-moveable-layer .moveable-around-control {
|
|
57
65
|
background: transparent !important;
|
|
58
66
|
}
|
|
67
|
+
|
|
68
|
+
.rv-moveable-layer .moveable-control {
|
|
69
|
+
width: 14px !important;
|
|
70
|
+
height: 14px !important;
|
|
71
|
+
margin-top: -7px !important;
|
|
72
|
+
margin-left: -7px !important;
|
|
73
|
+
border-radius: 50% !important;
|
|
74
|
+
box-sizing: border-box !important;
|
|
75
|
+
border: 2px solid hsl(var(--background)) !important;
|
|
76
|
+
background: #1990ff !important;
|
|
77
|
+
background: var(--moveable-color) !important;
|
|
78
|
+
z-index: 10 !important;
|
|
79
|
+
}
|