@lvce-editor/main-area-worker 5.10.0 → 5.11.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.
@@ -113,6 +113,7 @@ const IconThemeWorker = 7009;
113
113
  const RendererWorker = 1;
114
114
 
115
115
  const SetDom2 = 'Viewlet.setDom2';
116
+ const SetPatches = 'Viewlet.setPatches';
116
117
 
117
118
  const normalizeLine = line => {
118
119
  if (line.startsWith('Error: ')) {
@@ -1634,6 +1635,7 @@ const isEqual = (oldState, newState) => {
1634
1635
  };
1635
1636
 
1636
1637
  const RenderItems = 4;
1638
+ const RenderIncremental = 11;
1637
1639
 
1638
1640
  const modules = [isEqual];
1639
1641
  const numbers = [RenderItems];
@@ -2739,6 +2741,283 @@ const text = data => {
2739
2741
  };
2740
2742
  };
2741
2743
 
2744
+ const SetText = 1;
2745
+ const Replace = 2;
2746
+ const SetAttribute = 3;
2747
+ const RemoveAttribute = 4;
2748
+ const Add = 6;
2749
+ const NavigateChild = 7;
2750
+ const NavigateParent = 8;
2751
+ const RemoveChild = 9;
2752
+ const NavigateSibling = 10;
2753
+
2754
+ const isKey = key => {
2755
+ return key !== 'type' && key !== 'childCount';
2756
+ };
2757
+
2758
+ const getKeys = node => {
2759
+ const keys = Object.keys(node).filter(isKey);
2760
+ return keys;
2761
+ };
2762
+
2763
+ const arrayToTree = nodes => {
2764
+ const result = [];
2765
+ let i = 0;
2766
+ while (i < nodes.length) {
2767
+ const node = nodes[i];
2768
+ const {
2769
+ children,
2770
+ nodesConsumed
2771
+ } = getChildrenWithCount(nodes, i + 1, node.childCount || 0);
2772
+ result.push({
2773
+ node,
2774
+ children
2775
+ });
2776
+ i += 1 + nodesConsumed;
2777
+ }
2778
+ return result;
2779
+ };
2780
+ const getChildrenWithCount = (nodes, startIndex, childCount) => {
2781
+ if (childCount === 0) {
2782
+ return {
2783
+ children: [],
2784
+ nodesConsumed: 0
2785
+ };
2786
+ }
2787
+ const children = [];
2788
+ let i = startIndex;
2789
+ let remaining = childCount;
2790
+ let totalConsumed = 0;
2791
+ while (remaining > 0 && i < nodes.length) {
2792
+ const node = nodes[i];
2793
+ const nodeChildCount = node.childCount || 0;
2794
+ const {
2795
+ children: nodeChildren,
2796
+ nodesConsumed
2797
+ } = getChildrenWithCount(nodes, i + 1, nodeChildCount);
2798
+ children.push({
2799
+ node,
2800
+ children: nodeChildren
2801
+ });
2802
+ const nodeSize = 1 + nodesConsumed;
2803
+ i += nodeSize;
2804
+ totalConsumed += nodeSize;
2805
+ remaining--;
2806
+ }
2807
+ return {
2808
+ children,
2809
+ nodesConsumed: totalConsumed
2810
+ };
2811
+ };
2812
+
2813
+ const compareNodes = (oldNode, newNode) => {
2814
+ const patches = [];
2815
+ // Check if node type changed - return null to signal incompatible nodes
2816
+ // (caller should handle this with a Replace operation)
2817
+ if (oldNode.type !== newNode.type) {
2818
+ return null;
2819
+ }
2820
+ // Handle text nodes
2821
+ if (oldNode.type === Text && newNode.type === Text) {
2822
+ if (oldNode.text !== newNode.text) {
2823
+ patches.push({
2824
+ type: SetText,
2825
+ value: newNode.text
2826
+ });
2827
+ }
2828
+ return patches;
2829
+ }
2830
+ // Compare attributes
2831
+ const oldKeys = getKeys(oldNode);
2832
+ const newKeys = getKeys(newNode);
2833
+ // Check for attribute changes
2834
+ for (const key of newKeys) {
2835
+ if (oldNode[key] !== newNode[key]) {
2836
+ patches.push({
2837
+ type: SetAttribute,
2838
+ key,
2839
+ value: newNode[key]
2840
+ });
2841
+ }
2842
+ }
2843
+ // Check for removed attributes
2844
+ for (const key of oldKeys) {
2845
+ if (!(key in newNode)) {
2846
+ patches.push({
2847
+ type: RemoveAttribute,
2848
+ key
2849
+ });
2850
+ }
2851
+ }
2852
+ return patches;
2853
+ };
2854
+
2855
+ const treeToArray = node => {
2856
+ const result = [node.node];
2857
+ for (const child of node.children) {
2858
+ result.push(...treeToArray(child));
2859
+ }
2860
+ return result;
2861
+ };
2862
+
2863
+ const diffChildren = (oldChildren, newChildren, patches) => {
2864
+ const maxLength = Math.max(oldChildren.length, newChildren.length);
2865
+ // Track where we are: -1 means at parent, >= 0 means at child index
2866
+ let currentChildIndex = -1;
2867
+ // Collect indices of children to remove (we'll add these patches at the end in reverse order)
2868
+ const indicesToRemove = [];
2869
+ for (let i = 0; i < maxLength; i++) {
2870
+ const oldNode = oldChildren[i];
2871
+ const newNode = newChildren[i];
2872
+ if (!oldNode && !newNode) {
2873
+ continue;
2874
+ }
2875
+ if (!oldNode) {
2876
+ // Add new node - we should be at the parent
2877
+ if (currentChildIndex >= 0) {
2878
+ // Navigate back to parent
2879
+ patches.push({
2880
+ type: NavigateParent
2881
+ });
2882
+ currentChildIndex = -1;
2883
+ }
2884
+ // Flatten the entire subtree so renderInternal can handle it
2885
+ const flatNodes = treeToArray(newNode);
2886
+ patches.push({
2887
+ type: Add,
2888
+ nodes: flatNodes
2889
+ });
2890
+ } else if (newNode) {
2891
+ // Compare nodes to see if we need any patches
2892
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
2893
+ // If nodePatches is null, the node types are incompatible - need to replace
2894
+ if (nodePatches === null) {
2895
+ // Navigate to this child
2896
+ if (currentChildIndex === -1) {
2897
+ patches.push({
2898
+ type: NavigateChild,
2899
+ index: i
2900
+ });
2901
+ currentChildIndex = i;
2902
+ } else if (currentChildIndex !== i) {
2903
+ patches.push({
2904
+ type: NavigateSibling,
2905
+ index: i
2906
+ });
2907
+ currentChildIndex = i;
2908
+ }
2909
+ // Replace the entire subtree
2910
+ const flatNodes = treeToArray(newNode);
2911
+ patches.push({
2912
+ type: Replace,
2913
+ nodes: flatNodes
2914
+ });
2915
+ // After replace, we're at the new element (same position)
2916
+ continue;
2917
+ }
2918
+ // Check if we need to recurse into children
2919
+ const hasChildrenToCompare = oldNode.children.length > 0 || newNode.children.length > 0;
2920
+ // Only navigate to this element if we need to do something
2921
+ if (nodePatches.length > 0 || hasChildrenToCompare) {
2922
+ // Navigate to this child if not already there
2923
+ if (currentChildIndex === -1) {
2924
+ patches.push({
2925
+ type: NavigateChild,
2926
+ index: i
2927
+ });
2928
+ currentChildIndex = i;
2929
+ } else if (currentChildIndex !== i) {
2930
+ patches.push({
2931
+ type: NavigateSibling,
2932
+ index: i
2933
+ });
2934
+ currentChildIndex = i;
2935
+ }
2936
+ // Apply node patches (these apply to the current element, not children)
2937
+ if (nodePatches.length > 0) {
2938
+ patches.push(...nodePatches);
2939
+ }
2940
+ // Compare children recursively
2941
+ if (hasChildrenToCompare) {
2942
+ diffChildren(oldNode.children, newNode.children, patches);
2943
+ }
2944
+ }
2945
+ } else {
2946
+ // Remove old node - collect the index for later removal
2947
+ indicesToRemove.push(i);
2948
+ }
2949
+ }
2950
+ // Navigate back to parent if we ended at a child
2951
+ if (currentChildIndex >= 0) {
2952
+ patches.push({
2953
+ type: NavigateParent
2954
+ });
2955
+ currentChildIndex = -1;
2956
+ }
2957
+ // Add remove patches in reverse order (highest index first)
2958
+ // This ensures indices remain valid as we remove
2959
+ for (let j = indicesToRemove.length - 1; j >= 0; j--) {
2960
+ patches.push({
2961
+ type: RemoveChild,
2962
+ index: indicesToRemove[j]
2963
+ });
2964
+ }
2965
+ };
2966
+ const diffTrees = (oldTree, newTree, patches, path) => {
2967
+ // At the root level (path.length === 0), we're already AT the element
2968
+ // So we compare the root node directly, then compare its children
2969
+ if (path.length === 0 && oldTree.length === 1 && newTree.length === 1) {
2970
+ const oldNode = oldTree[0];
2971
+ const newNode = newTree[0];
2972
+ // Compare root nodes
2973
+ const nodePatches = compareNodes(oldNode.node, newNode.node);
2974
+ // If nodePatches is null, the root node types are incompatible - need to replace
2975
+ if (nodePatches === null) {
2976
+ const flatNodes = treeToArray(newNode);
2977
+ patches.push({
2978
+ type: Replace,
2979
+ nodes: flatNodes
2980
+ });
2981
+ return;
2982
+ }
2983
+ if (nodePatches.length > 0) {
2984
+ patches.push(...nodePatches);
2985
+ }
2986
+ // Compare children
2987
+ if (oldNode.children.length > 0 || newNode.children.length > 0) {
2988
+ diffChildren(oldNode.children, newNode.children, patches);
2989
+ }
2990
+ } else {
2991
+ // Non-root level or multiple root elements - use the regular comparison
2992
+ diffChildren(oldTree, newTree, patches);
2993
+ }
2994
+ };
2995
+
2996
+ const removeTrailingNavigationPatches = patches => {
2997
+ // Find the last non-navigation patch
2998
+ let lastNonNavigationIndex = -1;
2999
+ for (let i = patches.length - 1; i >= 0; i--) {
3000
+ const patch = patches[i];
3001
+ if (patch.type !== NavigateChild && patch.type !== NavigateParent && patch.type !== NavigateSibling) {
3002
+ lastNonNavigationIndex = i;
3003
+ break;
3004
+ }
3005
+ }
3006
+ // Return patches up to and including the last non-navigation patch
3007
+ return lastNonNavigationIndex === -1 ? [] : patches.slice(0, lastNonNavigationIndex + 1);
3008
+ };
3009
+
3010
+ const diffTree = (oldNodes, newNodes) => {
3011
+ // Step 1: Convert flat arrays to tree structures
3012
+ const oldTree = arrayToTree(oldNodes);
3013
+ const newTree = arrayToTree(newNodes);
3014
+ // Step 3: Compare the trees
3015
+ const patches = [];
3016
+ diffTrees(oldTree, newTree, patches, []);
3017
+ // Remove trailing navigation patches since they serve no purpose
3018
+ return removeTrailingNavigationPatches(patches);
3019
+ };
3020
+
2742
3021
  const CSS_CLASSES = {
2743
3022
  EDITOR_GROUPS_CONTAINER: 'editor-groups-container'};
2744
3023
 
@@ -2839,6 +3118,7 @@ const renderEditorGroupActions = (group, groupIndex, splitButtonEnabled) => {
2839
3118
 
2840
3119
  const renderTab = (tab, isActive, tabIndex, groupIndex) => {
2841
3120
  return [{
3121
+ 'aria-selected': isActive,
2842
3122
  childCount: 3,
2843
3123
  className: isActive ? 'MainTab MainTabSelected' : 'MainTab',
2844
3124
  'data-groupIndex': groupIndex,
@@ -2851,6 +3131,7 @@ const renderTab = (tab, isActive, tabIndex, groupIndex) => {
2851
3131
  }, {
2852
3132
  childCount: 0,
2853
3133
  className: 'TabIcon',
3134
+ role: 'none',
2854
3135
  src: tab.icon,
2855
3136
  type: Img
2856
3137
  }, {
@@ -2858,6 +3139,7 @@ const renderTab = (tab, isActive, tabIndex, groupIndex) => {
2858
3139
  className: 'TabTitle',
2859
3140
  type: Span
2860
3141
  }, text(tab.isDirty ? `*${tab.title}` : tab.title), {
3142
+ 'aria-label': 'Close',
2861
3143
  childCount: 1,
2862
3144
  className: 'EditorTabCloseButton',
2863
3145
  'data-groupIndex': groupIndex,
@@ -2921,8 +3203,17 @@ const renderItems = (oldState, newState) => {
2921
3203
  return [SetDom2, uid, dom];
2922
3204
  };
2923
3205
 
3206
+ const renderIncremental = (oldState, newState) => {
3207
+ const oldDom = renderItems(oldState, oldState)[2];
3208
+ const newDom = renderItems(newState, newState)[2];
3209
+ const patches = diffTree(oldDom, newDom);
3210
+ return [SetPatches, newState.uid, patches];
3211
+ };
3212
+
2924
3213
  const getRenderer = diffType => {
2925
3214
  switch (diffType) {
3215
+ case RenderIncremental:
3216
+ return renderIncremental;
2926
3217
  case RenderItems:
2927
3218
  return renderItems;
2928
3219
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-area-worker",
3
- "version": "5.10.0",
3
+ "version": "5.11.0",
4
4
  "description": "Main Area Worker",
5
5
  "repository": {
6
6
  "type": "git",