@hankchen/canvas-editor 0.6.0 → 0.7.1
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/index.d.ts +115 -69
- package/dist/index.js +119 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1004,6 +1004,20 @@ function expressionFragmentAtCursor(scan, cursor) {
|
|
|
1004
1004
|
return null;
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
1007
|
+
// src/shared/resourcePath.ts
|
|
1008
|
+
function wholeTemplateDiagnostic(template, kind) {
|
|
1009
|
+
return { kind, start: 0, end: template.length, at: { start: 0, end: template.length } };
|
|
1010
|
+
}
|
|
1011
|
+
function resourcePathDiagnostics(template) {
|
|
1012
|
+
const anchored = template.endsWith("\n") ? template.slice(0, -1) : template;
|
|
1013
|
+
const matched = /^\{\{([^{}]*)\}\}$/.exec(anchored);
|
|
1014
|
+
if (matched === null) return [wholeTemplateDiagnostic(template, "resource_not_single_ref")];
|
|
1015
|
+
const path = phpTrim2(matched[1] ?? "");
|
|
1016
|
+
if (path === "") return [wholeTemplateDiagnostic(template, "empty_fragment")];
|
|
1017
|
+
if (path.includes("(")) return [wholeTemplateDiagnostic(template, "resource_function_call")];
|
|
1018
|
+
return [];
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1007
1021
|
// src/editing/alignCanvas.ts
|
|
1008
1022
|
var ALIGN_CORNER_MARGIN_PX = 40;
|
|
1009
1023
|
function alignToCanvasTarget(mode, box, canvasWidth, canvasHeight, margin) {
|
|
@@ -1226,15 +1240,14 @@ var RATIO_PRESETS = [
|
|
|
1226
1240
|
{ id: "16:9", ratio: { w: 16, h: 9 } },
|
|
1227
1241
|
{ id: "9:16", ratio: { w: 9, h: 16 } }
|
|
1228
1242
|
];
|
|
1229
|
-
function defaultNextLayerRatio() {
|
|
1230
|
-
return "free";
|
|
1231
|
-
}
|
|
1232
1243
|
function ratioValue(id) {
|
|
1233
1244
|
const entry = RATIO_PRESETS.find((candidate) => candidate.id === id);
|
|
1234
1245
|
return entry?.ratio ? { ...entry.ratio } : null;
|
|
1235
1246
|
}
|
|
1236
|
-
function
|
|
1237
|
-
return
|
|
1247
|
+
function findPresetEntry(type, presetId) {
|
|
1248
|
+
if (type === "TextLayer") return TEXT_PRESETS.find((candidate) => candidate.id === presetId);
|
|
1249
|
+
if (type === "ImageLayer") return RATIO_PRESETS.find((candidate) => candidate.id === presetId);
|
|
1250
|
+
return void 0;
|
|
1238
1251
|
}
|
|
1239
1252
|
function defaultSizeForRatio(ratio) {
|
|
1240
1253
|
return ratio.w >= ratio.h ? { width: 200, height: Math.round(200 * ratio.h / ratio.w) } : { width: Math.round(200 * ratio.w / ratio.h), height: 200 };
|
|
@@ -1742,13 +1755,14 @@ var EditorStore = class {
|
|
|
1742
1755
|
resize: null,
|
|
1743
1756
|
armedCreate: null,
|
|
1744
1757
|
armedCreateRowsPath: "",
|
|
1758
|
+
armedCreatePreset: "",
|
|
1745
1759
|
create: null,
|
|
1746
1760
|
editing: null,
|
|
1747
1761
|
renaming: null,
|
|
1748
1762
|
anchorExpanded: false,
|
|
1749
1763
|
nextTextStyle: defaultNextTextStyle(),
|
|
1750
|
-
nextLayerRatio: defaultNextLayerRatio(),
|
|
1751
1764
|
dataSourceSchema: null,
|
|
1765
|
+
dataSourceSchemaRejection: null,
|
|
1752
1766
|
guides: [],
|
|
1753
1767
|
rulersVisible: true,
|
|
1754
1768
|
snapAxes: [],
|
|
@@ -1779,7 +1793,7 @@ var EditorStore = class {
|
|
|
1779
1793
|
}
|
|
1780
1794
|
/** 打开/替换文档:ui 选择/编辑/重命名会话与双向历史一并重置(新文档不继承旧路径/旧事务);
|
|
1781
1795
|
* 参考线/锁定集合/查找会话/建层武装与画拉会话随当次会话清空(对位轴/文档内容防护/
|
|
1782
|
-
*
|
|
1796
|
+
* 查询词/待命层型不跨文档),标尺显隐/锚点折叠/新层样式作为偏好保留 */
|
|
1783
1797
|
openDocument(canvas) {
|
|
1784
1798
|
this.docValue = canvas;
|
|
1785
1799
|
this.undoSteps = [];
|
|
@@ -1792,6 +1806,7 @@ var EditorStore = class {
|
|
|
1792
1806
|
resize: null,
|
|
1793
1807
|
armedCreate: null,
|
|
1794
1808
|
armedCreateRowsPath: "",
|
|
1809
|
+
armedCreatePreset: "",
|
|
1795
1810
|
create: null,
|
|
1796
1811
|
editing: null,
|
|
1797
1812
|
renaming: null,
|
|
@@ -1891,12 +1906,20 @@ var EditorStore = class {
|
|
|
1891
1906
|
/**
|
|
1892
1907
|
* 建层武装置/解除(null,drag-create 工单 01);标量值等短路(重复武装同型
|
|
1893
1908
|
* 不通知)。rowsPath(template-table-drag-create 工单 01):模板表风味载荷
|
|
1894
|
-
*
|
|
1895
|
-
*
|
|
1909
|
+
* 与层型一体写;preset(canvas-web-preset-submenu 工单 01):预设载荷与层型
|
|
1910
|
+
* 一体写——同层型同载荷才短路(重复武装同型换载荷要更新),解除(null)
|
|
1911
|
+
* 一律清载荷(rowsPath 与 preset 双清)。
|
|
1896
1912
|
*/
|
|
1897
|
-
setArmedCreate(type, rowsPath = "") {
|
|
1898
|
-
if (this.uiValue.armedCreate === type && this.uiValue.armedCreateRowsPath === rowsPath)
|
|
1899
|
-
|
|
1913
|
+
setArmedCreate(type, rowsPath = "", preset = "") {
|
|
1914
|
+
if (this.uiValue.armedCreate === type && this.uiValue.armedCreateRowsPath === rowsPath && this.uiValue.armedCreatePreset === preset) {
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1917
|
+
this.uiValue = {
|
|
1918
|
+
...this.uiValue,
|
|
1919
|
+
armedCreate: type,
|
|
1920
|
+
armedCreateRowsPath: type === null ? "" : rowsPath,
|
|
1921
|
+
armedCreatePreset: type === null ? "" : preset
|
|
1922
|
+
};
|
|
1900
1923
|
this.notify({ scope: "ui", branch: "armedCreate" });
|
|
1901
1924
|
}
|
|
1902
1925
|
/** 画拉橡皮筋会话开始/更新/结束(null);会话对象住 ui 分支,落库在 endCreate 单事务 */
|
|
@@ -1920,8 +1943,9 @@ var EditorStore = class {
|
|
|
1920
1943
|
this.notify({ scope: "ui", branch: "anchorExpanded" });
|
|
1921
1944
|
}
|
|
1922
1945
|
/**
|
|
1923
|
-
* 新层样式槽逐字段合并(text-defaults 工单 01
|
|
1924
|
-
*
|
|
1946
|
+
* 新层样式槽逐字段合并(text-defaults 工单 01:捕获/prefs 恢复的统一写入口;
|
|
1947
|
+
* canvas-web-preset-submenu 工单 01 起预设不再写槽):patch 并入现值,五字段
|
|
1948
|
+
* 值等短路(重复写同值零通知),不进历史。
|
|
1925
1949
|
*/
|
|
1926
1950
|
setNextTextStyle(patch) {
|
|
1927
1951
|
const next = { ...this.uiValue.nextTextStyle, ...patch };
|
|
@@ -1929,23 +1953,15 @@ var EditorStore = class {
|
|
|
1929
1953
|
this.uiValue = { ...this.uiValue, nextTextStyle: next };
|
|
1930
1954
|
this.notify({ scope: "ui", branch: "nextTextStyle" });
|
|
1931
1955
|
}
|
|
1932
|
-
/**
|
|
1933
|
-
* 建层比例槽写入(image-ratio-preset 工单 01:比例预设应用 / prefs 恢复的
|
|
1934
|
-
* 统一写入口):值等短路(重复写同档零通知),仅 ui 通知、不进历史。
|
|
1935
|
-
*/
|
|
1936
|
-
setNextLayerRatio(id) {
|
|
1937
|
-
if (this.uiValue.nextLayerRatio === id) return;
|
|
1938
|
-
this.uiValue = { ...this.uiValue, nextLayerRatio: id };
|
|
1939
|
-
this.notify({ scope: "ui", branch: "nextLayerRatio" });
|
|
1940
|
-
}
|
|
1941
1956
|
/**
|
|
1942
1957
|
* 数据源 schema 声明替换(归一产物或降级 null,校验收口在注入缝不在这里):
|
|
1943
|
-
*
|
|
1958
|
+
* 声明与拒绝详情成对置换(rejection 仅被拒注入在场,2b 呈现面),同引用且
|
|
1959
|
+
* 同拒绝态短路(重复注入同一归一产物不惊动订阅方);仅 ui 通知,不参与重绘
|
|
1944
1960
|
* 脏标(onStoreChange 对该分支短路)。
|
|
1945
1961
|
*/
|
|
1946
|
-
setDataSourceSchema(schema) {
|
|
1947
|
-
if (this.uiValue.dataSourceSchema === schema) return;
|
|
1948
|
-
this.uiValue = { ...this.uiValue, dataSourceSchema: schema };
|
|
1962
|
+
setDataSourceSchema(schema, rejection = null) {
|
|
1963
|
+
if (this.uiValue.dataSourceSchema === schema && this.uiValue.dataSourceSchemaRejection === rejection) return;
|
|
1964
|
+
this.uiValue = { ...this.uiValue, dataSourceSchema: schema, dataSourceSchemaRejection: rejection };
|
|
1949
1965
|
this.notify({ scope: "ui", branch: "dataSourceSchema" });
|
|
1950
1966
|
}
|
|
1951
1967
|
/** 参考线列表替换(增删动作在会话门面收口);仅 ui 通知,不参与历史 */
|
|
@@ -2912,29 +2928,23 @@ var EditorSession = class {
|
|
|
2912
2928
|
/**
|
|
2913
2929
|
* 武装建层(面板新增项/层型快捷键的统一入口,CONTEXT「武装」词条):置 ui
|
|
2914
2930
|
* 分支待命层型,下一次画布按下即开画拉;建层提交或 Esc 即解除——一次性
|
|
2915
|
-
* 待命态,无粘性工具(spec 决策 2
|
|
2931
|
+
* 待命态,无粘性工具(spec 决策 2)。重复武装同型同载荷值等短路零通知。
|
|
2916
2932
|
*
|
|
2917
|
-
* preset(
|
|
2918
|
-
*
|
|
2919
|
-
*
|
|
2920
|
-
*
|
|
2921
|
-
* -
|
|
2922
|
-
*
|
|
2923
|
-
* -
|
|
2924
|
-
*
|
|
2933
|
+
* preset(canvas-web-preset-submenu 工单 01,ADR 0021):层型相关预设随武装
|
|
2934
|
+
* 载荷一次性携带、**不再写任何偏好槽**——命中档位把档位 id 写进
|
|
2935
|
+
* ui.armedCreatePreset(endCreate 落库一次性消费,取消路零残留);未知 id =
|
|
2936
|
+
* 不落载荷、武装照常(评审口径统一:「空转」只指载荷,武装层型本身仍合法)。
|
|
2937
|
+
* - TextLayer + 文本预设档:载荷命中 TEXT_PRESETS(endCreate 档位字号直接
|
|
2938
|
+
* 生效,不经新层样式槽——普通武装文本按槽的语义不受染指);
|
|
2939
|
+
* - ImageLayer + 比例预设档:载荷命中 RATIO_PRESETS('free' 档载荷行为等价
|
|
2940
|
+
* 自由;QR 恒方是层型硬钳、无比例语义,spec 豁免面);
|
|
2941
|
+
* - 交叉类型(文本层带比例档/图片层带文本档)各在对方清单查无此档、不落载荷。
|
|
2925
2942
|
*/
|
|
2926
2943
|
armLayerCreate(type, preset) {
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
if (entry) this.store.setNextTextStyle({ fontSize: entry.fontSize });
|
|
2930
|
-
}
|
|
2931
|
-
if (preset !== void 0 && type === "ImageLayer") {
|
|
2932
|
-
const entry = RATIO_PRESETS.find((candidate) => candidate.id === preset);
|
|
2933
|
-
if (entry) this.store.setNextLayerRatio(entry.id);
|
|
2934
|
-
}
|
|
2935
|
-
this.store.setArmedCreate(type);
|
|
2944
|
+
const entry = preset === void 0 ? void 0 : findPresetEntry(type, preset);
|
|
2945
|
+
this.store.setArmedCreate(type, "", entry !== void 0 ? entry.id : "");
|
|
2936
2946
|
}
|
|
2937
|
-
/**
|
|
2947
|
+
/** 解除建层武装(取消入口):仅清待命态(含模板表风味与预设载荷),零副作用。 */
|
|
2938
2948
|
cancelArmLayerCreate() {
|
|
2939
2949
|
this.store.setArmedCreate(null);
|
|
2940
2950
|
}
|
|
@@ -2963,9 +2973,11 @@ var EditorSession = class {
|
|
|
2963
2973
|
if (!this.store.doc) return false;
|
|
2964
2974
|
const point = { x: sceneX, y: sceneY };
|
|
2965
2975
|
const templateRowsPath = armed === "TableLayer" && this.store.ui.armedCreateRowsPath !== "" ? this.store.ui.armedCreateRowsPath : void 0;
|
|
2976
|
+
const preset = (armed === "TextLayer" || armed === "ImageLayer") && this.store.ui.armedCreatePreset !== "" ? this.store.ui.armedCreatePreset : void 0;
|
|
2966
2977
|
this.store.setCreate({
|
|
2967
2978
|
type: armed,
|
|
2968
2979
|
templateRowsPath,
|
|
2980
|
+
preset,
|
|
2969
2981
|
startScene: point,
|
|
2970
2982
|
currentScene: point,
|
|
2971
2983
|
rect: { x: sceneX, y: sceneY, width: 0, height: 0 }
|
|
@@ -2981,17 +2993,19 @@ var EditorSession = class {
|
|
|
2981
2993
|
* 全部可见根层供轴,copyMode 首移同门)。零文档事务:修正只进会话几何,
|
|
2982
2994
|
* 落库在 endCreate。
|
|
2983
2995
|
*
|
|
2984
|
-
*
|
|
2985
|
-
*
|
|
2986
|
-
*
|
|
2987
|
-
*
|
|
2996
|
+
* 建层预设档(canvas-web-preset-submenu 工单 01,ADR 0021,取代建层比例槽):
|
|
2997
|
+
* 仅 ImageLayer 按会话载荷档钳制(QR 层不传 ratio、恒方语义不动,两钳互斥;
|
|
2998
|
+
* 其余层型无比例语义);无载荷或 free 档 = 自由钳(普通武装恒自由)。
|
|
2999
|
+
* Shift 瞬时反转源 = 生效档(载荷档或自由):档具名按 Shift = 临时自由、
|
|
3000
|
+
* 生效档自由(含无载荷)按 Shift = 临时钳 1:1,按住生效松开还原(逐帧求位、
|
|
3001
|
+
* 不写载荷不改武装态,Figma 惯例的手势瞬时语义)。
|
|
2988
3002
|
*/
|
|
2989
3003
|
createTo(sceneX, sceneY, shift = false) {
|
|
2990
3004
|
const gesture = this.store.ui.create;
|
|
2991
3005
|
const doc = this.store.doc;
|
|
2992
3006
|
if (!gesture || !doc) return;
|
|
2993
|
-
const
|
|
2994
|
-
const ratio = gesture.type === "ImageLayer" ? shift ?
|
|
3007
|
+
const presetRatio = gesture.type === "ImageLayer" && gesture.preset !== void 0 ? ratioValue(gesture.preset) : null;
|
|
3008
|
+
const ratio = gesture.type === "ImageLayer" ? shift ? presetRatio === null ? { w: 1, h: 1 } : null : presetRatio : null;
|
|
2995
3009
|
const resolution = createRubberBandRect(
|
|
2996
3010
|
gesture.type,
|
|
2997
3011
|
gesture.startScene,
|
|
@@ -3013,15 +3027,20 @@ var EditorSession = class {
|
|
|
3013
3027
|
* - 死区外:单事务写入「createDefaultLayer 缺省形态 + position 左上角对准
|
|
3014
3028
|
* 橡皮筋矩形(含吸附修正)+ shape.width/height」并 insertRootLayerInDraft
|
|
3015
3029
|
* 置顶(priority min−1、push 数组尾)——尺寸取手势末态钳制结果(含 Shift
|
|
3016
|
-
*
|
|
3030
|
+
* 反转末态,钳制源 = 会话预设档,canvas-web-preset-submenu 工单 01);
|
|
3017
3031
|
* - 死区内(点击兜底,位移按 CREATE_DEAD_ZONE_SCREEN_PX 屏幕 px 随 zoom 折算,
|
|
3018
|
-
* ALT_DRAG_DEAD_ZONE_SCREEN_PX
|
|
3019
|
-
*
|
|
3020
|
-
*
|
|
3032
|
+
* ALT_DRAG_DEAD_ZONE_SCREEN_PX 同门):左上角对准点击点;尺寸按会话预设档
|
|
3033
|
+
* 派生缺省盒(ImageLayer 长边 200 定短边,自由/无载荷 = 工厂 200×150 现状;
|
|
3034
|
+
* 忽略 shift——无位移可供等比约束;其余层型保持工厂缺省)。
|
|
3021
3035
|
* 落库后自动选中新层并解除武装;返回新层路径(绑定层消费:文本层据此自动
|
|
3022
3036
|
* 进文本编辑,spec 决策 6)。无会话/无文档空转返回 null。点击兜底不产生
|
|
3023
3037
|
* 零尺寸层(缺省形态自带可见尺寸)。
|
|
3024
3038
|
*
|
|
3039
|
+
* 预设档一次性消费(canvas-web-preset-submenu 工单 01,ADR 0021):文本档
|
|
3040
|
+
* 字号直接生效(不经新层样式槽——字体/行高等槽外字段仍按槽,普通武装语义
|
|
3041
|
+
* 保留);图片档比供死区缺省盒派生。档位随会话捕获,落库后武装与载荷双清
|
|
3042
|
+
* (一次性语义,取消路零残留)。
|
|
3043
|
+
*
|
|
3025
3044
|
* 模板表风味(template-table-drag-create 工单 01):会话载荷 templateRowsPath
|
|
3026
3045
|
* 非空即分派 createTemplateTable 工厂(死区外 shape = 手势正规化矩形,死区内
|
|
3027
3046
|
* 缺省壳 400×120、左上角对准点击点);模板层不自动进文本编辑(文本层专属)。
|
|
@@ -3039,21 +3058,21 @@ var EditorSession = class {
|
|
|
3039
3058
|
const clicked = Math.hypot(dx, dy) <= deadZoneScene;
|
|
3040
3059
|
const index = { v: -1 };
|
|
3041
3060
|
const templateRowsPath = gesture.templateRowsPath;
|
|
3061
|
+
const presetTextEntry = gesture.type === "TextLayer" && gesture.preset !== void 0 ? findPresetEntry(gesture.type, gesture.preset) : void 0;
|
|
3062
|
+
const textDefaults = presetTextEntry ? { ...this.store.ui.nextTextStyle, fontSize: presetTextEntry.fontSize } : this.store.ui.nextTextStyle;
|
|
3063
|
+
const presetRatio = gesture.type === "ImageLayer" && gesture.preset !== void 0 ? ratioValue(gesture.preset) : null;
|
|
3042
3064
|
this.store.transact((draft) => {
|
|
3043
3065
|
const layer = templateRowsPath !== void 0 ? createTemplateTable(
|
|
3044
3066
|
clicked ? { rowsPath: templateRowsPath } : {
|
|
3045
3067
|
rowsPath: templateRowsPath,
|
|
3046
3068
|
shape: { width: gesture.rect.width, height: gesture.rect.height }
|
|
3047
3069
|
}
|
|
3048
|
-
) : createDefaultLayer(gesture.type,
|
|
3070
|
+
) : createDefaultLayer(gesture.type, textDefaults);
|
|
3049
3071
|
if (clicked) {
|
|
3050
|
-
if (gesture.type === "ImageLayer") {
|
|
3051
|
-
const
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
layer.shape.width = size.width;
|
|
3055
|
-
layer.shape.height = size.height;
|
|
3056
|
-
}
|
|
3072
|
+
if (gesture.type === "ImageLayer" && presetRatio) {
|
|
3073
|
+
const size = defaultSizeForRatio(presetRatio);
|
|
3074
|
+
layer.shape.width = size.width;
|
|
3075
|
+
layer.shape.height = size.height;
|
|
3057
3076
|
}
|
|
3058
3077
|
layer.position = { ...layer.position, x: gesture.startScene.x, y: gesture.startScene.y };
|
|
3059
3078
|
} else {
|
|
@@ -3069,9 +3088,9 @@ var EditorSession = class {
|
|
|
3069
3088
|
return path;
|
|
3070
3089
|
}
|
|
3071
3090
|
/**
|
|
3072
|
-
* 取消画拉(Esc
|
|
3073
|
-
*
|
|
3074
|
-
*
|
|
3091
|
+
* 取消画拉(Esc 语义):清橡皮筋会话、命中轴回显与武装态(含模板表风味与
|
|
3092
|
+
* 预设载荷)——零文档写入、零历史步(拖拽期纯视觉因此取消零回退成本,spec
|
|
3093
|
+
* 决策 4)。幂等:无会话时仅解除武装(待命态 Esc 同走此口)。
|
|
3075
3094
|
*/
|
|
3076
3095
|
cancelCreate() {
|
|
3077
3096
|
this.store.setCreate(null);
|
|
@@ -3235,30 +3254,30 @@ var EditorSession = class {
|
|
|
3235
3254
|
/**
|
|
3236
3255
|
* 只读偏好(保存 prefs 的读取口):与 store.ui 同源,给宿主一个不用下钻
|
|
3237
3256
|
* store 的口。读 = getEditorPrefs,写 = applyEditorPrefs,对称成对;帧切片
|
|
3238
|
-
* 走 restoreEditorState
|
|
3257
|
+
* 走 restoreEditorState,两不相混。建层比例(nextLayerRatio)已退役不在此
|
|
3258
|
+
* 带出(canvas-web-preset-submenu 工单 01,ADR 0021——预设随武装载荷一次性
|
|
3259
|
+
* 携带,prefs 停写)。
|
|
3239
3260
|
*/
|
|
3240
3261
|
getEditorPrefs() {
|
|
3241
3262
|
const ui = this.store.ui;
|
|
3242
3263
|
return {
|
|
3243
3264
|
rulersVisible: ui.rulersVisible,
|
|
3244
3265
|
anchorExpanded: ui.anchorExpanded,
|
|
3245
|
-
nextTextStyle: ui.nextTextStyle
|
|
3246
|
-
nextLayerRatio: ui.nextLayerRatio
|
|
3266
|
+
nextTextStyle: ui.nextTextStyle
|
|
3247
3267
|
};
|
|
3248
3268
|
}
|
|
3249
3269
|
/**
|
|
3250
3270
|
* 应用偏好(会话建立时一次性,跨会话恢复 prefs 的写入口):整体替换
|
|
3251
3271
|
* rulersVisible/anchorExpanded,不进历史;值等写入经 store 短路零通知。
|
|
3252
3272
|
* 新层样式(text-defaults 工单 01)走宽容读逐字段合并(pickNextTextStylePatch
|
|
3253
|
-
*
|
|
3254
|
-
* 工单 01
|
|
3255
|
-
*
|
|
3273
|
+
* 共享谓词——与捕获同门,缺字/类型不符保留现值)。旧快照的 nextLayerRatio
|
|
3274
|
+
* 遗留键宽容忽略(canvas-web-preset-submenu 工单 01:槽退役停读,载荷上多余
|
|
3275
|
+
* 的键无害;schemaVersion 加法演进)。
|
|
3256
3276
|
*/
|
|
3257
3277
|
applyEditorPrefs(prefs) {
|
|
3258
3278
|
this.store.setRulersVisible(prefs.rulersVisible);
|
|
3259
3279
|
this.store.setAnchorExpanded(prefs.anchorExpanded);
|
|
3260
3280
|
this.store.setNextTextStyle(pickNextTextStylePatch(prefs.nextTextStyle));
|
|
3261
|
-
this.store.setNextLayerRatio(pickNextLayerRatio(prefs.nextLayerRatio));
|
|
3262
3281
|
}
|
|
3263
3282
|
// ---- 对齐画布(layer-align-snap 工单 01):图层盒整体对齐画布几何 ----
|
|
3264
3283
|
/**
|
|
@@ -3579,8 +3598,11 @@ var EditorSession = class {
|
|
|
3579
3598
|
}
|
|
3580
3599
|
/**
|
|
3581
3600
|
* 数据字段取值方式切换(静态 ⇆ 表达式,工单 02 自面板收编内核):表达式现态
|
|
3582
|
-
* → 字面接管(updateData,值保持现镜像);静态现态 →
|
|
3583
|
-
*
|
|
3601
|
+
* → 字面接管(updateData,值保持现镜像);静态现态 → 打标,初值分内容面——
|
|
3602
|
+
* 文本层镜像原文(字面可含合法插值混排),资源层(Image/Qr)只镜像**已合法
|
|
3603
|
+
* 的单引用字面**(静态 ⇆ 表达式往返无损),违例字面(URL/拼接文案)落
|
|
3604
|
+
* 「未选择」空态不镜像——切换自身不得制造必违例初值(死端态整改条目 4;旧
|
|
3605
|
+
* 值可经撤销一步找回)。各为独立一步历史(无 mergeKey)。三内容层分派各取值
|
|
3584
3606
|
* 字段,表/行/格/悬空路径空转。
|
|
3585
3607
|
*
|
|
3586
3608
|
* 活标志防御路由(ADR 0019):路径即编辑中的层时只翻会话活标志(零文档变更
|
|
@@ -3602,16 +3624,20 @@ var EditorSession = class {
|
|
|
3602
3624
|
return;
|
|
3603
3625
|
case "ImageLayer":
|
|
3604
3626
|
if (layer.expression !== null) this.updateData(path, layer.src ?? "");
|
|
3605
|
-
else this.updateDataExpression(path, layer.src ?? "");
|
|
3627
|
+
else this.updateDataExpression(path, this.resourceToggleInitial(layer.src ?? ""));
|
|
3606
3628
|
return;
|
|
3607
3629
|
case "QrCodeLayer":
|
|
3608
3630
|
if (layer.expression !== null) this.updateData(path, layer.value);
|
|
3609
|
-
else this.updateDataExpression(path, layer.value);
|
|
3631
|
+
else this.updateDataExpression(path, this.resourceToggleInitial(layer.value));
|
|
3610
3632
|
return;
|
|
3611
3633
|
default:
|
|
3612
3634
|
return;
|
|
3613
3635
|
}
|
|
3614
3636
|
}
|
|
3637
|
+
/** 资源面切换初值:字面已是合法单引用(含空串为「未选择」)才镜像,违例落空态 */
|
|
3638
|
+
resourceToggleInitial(literal) {
|
|
3639
|
+
return resourcePathDiagnostics(literal).length === 0 ? literal : "";
|
|
3640
|
+
}
|
|
3615
3641
|
/**
|
|
3616
3642
|
* 内容写事务的统一形(会话内容独占工单 02):transact 落库 + 命中编辑层的
|
|
3617
3643
|
* 草稿接管收口——updateData/updateDataExpression/replaceOne/replaceAll 四个
|
|
@@ -3655,9 +3681,20 @@ var EditorSession = class {
|
|
|
3655
3681
|
* 换文档不重置,重注入/清除走同一入口。签名与「注入即整体替换」语义不变(D6)。
|
|
3656
3682
|
*/
|
|
3657
3683
|
setDataSourceSchema(raw) {
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3684
|
+
if (raw === null || raw === void 0) {
|
|
3685
|
+
this.store.setDataSourceSchema(null);
|
|
3686
|
+
return;
|
|
3687
|
+
}
|
|
3688
|
+
const schema = normalizeExpressionSchemaSource(raw);
|
|
3689
|
+
if (schema === null) {
|
|
3690
|
+
const parsed = parseExpressionSchema(raw);
|
|
3691
|
+
this.store.setDataSourceSchema(
|
|
3692
|
+
null,
|
|
3693
|
+
parsed.ok ? null : { reason: parsed.reason, detail: parsed.detail }
|
|
3694
|
+
);
|
|
3695
|
+
return;
|
|
3696
|
+
}
|
|
3697
|
+
this.store.setDataSourceSchema(schema);
|
|
3661
3698
|
}
|
|
3662
3699
|
// ---- 上传(工单 13):本机资源 → 可物化引用,实现经 uploadHandler 注入 ----
|
|
3663
3700
|
/** 上传可用性:未注入 uploadHandler 时为 false(宿主据此隐藏/禁用上传入口) */
|
|
@@ -4523,20 +4560,6 @@ function expressionDiagnostics(template) {
|
|
|
4523
4560
|
return found;
|
|
4524
4561
|
}
|
|
4525
4562
|
|
|
4526
|
-
// src/shared/resourcePath.ts
|
|
4527
|
-
function wholeTemplateDiagnostic(template, kind) {
|
|
4528
|
-
return { kind, start: 0, end: template.length, at: { start: 0, end: template.length } };
|
|
4529
|
-
}
|
|
4530
|
-
function resourcePathDiagnostics(template) {
|
|
4531
|
-
const anchored = template.endsWith("\n") ? template.slice(0, -1) : template;
|
|
4532
|
-
const matched = /^\{\{([^{}]*)\}\}$/.exec(anchored);
|
|
4533
|
-
if (matched === null) return [wholeTemplateDiagnostic(template, "resource_not_single_ref")];
|
|
4534
|
-
const path = phpTrim2(matched[1] ?? "");
|
|
4535
|
-
if (path === "") return [wholeTemplateDiagnostic(template, "empty_fragment")];
|
|
4536
|
-
if (path.includes("(")) return [wholeTemplateDiagnostic(template, "resource_function_call")];
|
|
4537
|
-
return [];
|
|
4538
|
-
}
|
|
4539
|
-
|
|
4540
4563
|
// src/shared/expressionFunctions.ts
|
|
4541
4564
|
var EXPRESSION_FUNCTIONS = [
|
|
4542
4565
|
{ name: "date", signature: "date(path[, format])", summary: "\u65E5\u671F\u683C\u5F0F\u5316\uFF08moment \u98CE\u683C token\uFF0C\u9884\u8BBE date/datetime\uFF09" },
|
|
@@ -4921,7 +4944,6 @@ export {
|
|
|
4921
4944
|
createDefaultLayer,
|
|
4922
4945
|
createRubberBandRect,
|
|
4923
4946
|
createTemplateTable,
|
|
4924
|
-
defaultNextLayerRatio,
|
|
4925
4947
|
defaultNextTextStyle,
|
|
4926
4948
|
defaultSizeForRatio,
|
|
4927
4949
|
deleteLayerInDraft,
|
|
@@ -4930,6 +4952,7 @@ export {
|
|
|
4930
4952
|
expressionCallSlotAtEnd,
|
|
4931
4953
|
expressionDiagnostics,
|
|
4932
4954
|
expressionFragmentAtCursor,
|
|
4955
|
+
findPresetEntry,
|
|
4933
4956
|
fitRect,
|
|
4934
4957
|
fitViewport,
|
|
4935
4958
|
growRowToCellInDraft,
|
|
@@ -4964,7 +4987,6 @@ export {
|
|
|
4964
4987
|
pathStartsWith,
|
|
4965
4988
|
pathsEqual,
|
|
4966
4989
|
phpTrim2 as phpTrim,
|
|
4967
|
-
pickNextLayerRatio,
|
|
4968
4990
|
pickNextTextStylePatch,
|
|
4969
4991
|
prepareRootPaste,
|
|
4970
4992
|
proportionalDrivingAxis,
|