From 467ae905bdeae7363c88a14dc4b9f1f2bd7dd859 Mon Sep 17 00:00:00 2001 From: isUnknown Date: Thu, 4 Dec 2025 14:03:40 +0100 Subject: [PATCH] refactor: optimize EditorPanel updates with selective debouncing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement immediate vs debounced updates based on input type to improve UX responsiveness while preventing excessive re-renders. Update strategy: - Immediate (0ms): select, buttons, checkboxes, color picker - Debounced (1s): text inputs, number inputs, range sliders Changes: - PageSettings.vue: Split watchers for margin values/units and background value/format. Extract update logic into reusable functions. - TextSettings.vue: Add comprehensive watcher system with selective debouncing for all settings (font, size, color, margins, etc.) This ensures button clicks (unit toggles, format switches) apply instantly while typed values (numbers, text) batch updates to reduce CSS re-parsing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/editor/PageSettings.vue | 309 +++++++++++++++---------- src/components/editor/TextSettings.vue | 265 ++++++++++++++++++--- 2 files changed, 417 insertions(+), 157 deletions(-) diff --git a/src/components/editor/PageSettings.vue b/src/components/editor/PageSettings.vue index 2bd7f21..9fdd04d 100644 --- a/src/components/editor/PageSettings.vue +++ b/src/components/editor/PageSettings.vue @@ -2,43 +2,37 @@

Réglage des pages

-
- - +
+
+ + +
-
- - +
+
+ + +
+ +
+ + +
-
- - -
- -
+

Marges

-
+
-
+
-
+
-
+
-
- -
- -
- - +
+
+ +
+ +
+ + +
-
- - +
+
+ + +
-
- - -
+
+
+ + +
-
- - +
+ + +
@@ -222,7 +210,7 @@ const pageFormats = { A5: { width: '148mm', height: '210mm' }, A3: { width: '297mm', height: '420mm' }, letter: { width: '8.5in', height: '11in' }, - legal: { width: '8.5in', height: '14in' } + legal: { width: '8.5in', height: '14in' }, }; const pageWidth = computed(() => pageFormats[pageFormat.value].width); @@ -232,12 +220,12 @@ const margins = ref({ top: { value: 20, unit: 'mm' }, bottom: { value: 20, unit: 'mm' }, left: { value: 20, unit: 'mm' }, - right: { value: 20, unit: 'mm' } + right: { value: 20, unit: 'mm' }, }); const background = ref({ value: '', - format: 'hex' + format: 'hex', }); const pattern = ref(''); @@ -249,57 +237,109 @@ const debouncedUpdate = (callback) => { updateTimer = setTimeout(callback, 1000); }; +const immediateUpdate = (callback) => { + callback(); +}; + watch(pageFormat, (newFormat) => { if (isUpdatingFromStore) return; - debouncedUpdate(() => { + immediateUpdate(() => { stylesheetStore.updateProperty('@page', 'size', newFormat, ''); }); }); -watch(margins, (newMargins) => { - if (isUpdatingFromStore) return; +const updateMargins = () => { + const marginValue = `${margins.value.top.value}${margins.value.top.unit} ${margins.value.right.value}${margins.value.right.unit} ${margins.value.bottom.value}${margins.value.bottom.unit} ${margins.value.left.value}${margins.value.left.unit}`; - debouncedUpdate(() => { - const marginValue = `${newMargins.top.value}${newMargins.top.unit} ${newMargins.right.value}${newMargins.right.unit} ${newMargins.bottom.value}${newMargins.bottom.unit} ${newMargins.left.value}${newMargins.left.unit}`; + const currentBlock = stylesheetStore.extractBlock('@page'); + const updatedBlock = currentBlock.replace( + /(margin:\s*)[^;]+/, + `$1${marginValue}` + ); - const currentBlock = stylesheetStore.extractBlock('@page'); + stylesheetStore.content = stylesheetStore.content.replace( + currentBlock, + updatedBlock + ); +}; + +// Watch margin values (number inputs) with debounce +watch( + () => [ + margins.value.top.value, + margins.value.bottom.value, + margins.value.left.value, + margins.value.right.value, + ], + () => { + if (isUpdatingFromStore) return; + debouncedUpdate(updateMargins); + } +); + +// Watch margin units (button clicks) without debounce +watch( + () => [ + margins.value.top.unit, + margins.value.bottom.unit, + margins.value.left.unit, + margins.value.right.unit, + ], + () => { + if (isUpdatingFromStore) return; + immediateUpdate(updateMargins); + } +); + +const updateBackground = () => { + if (!background.value.value) return; + + const currentBlock = stylesheetStore.extractBlock('@page'); + + if (currentBlock.includes('background:')) { const updatedBlock = currentBlock.replace( - /(margin:\s*)[^;]+/, - `$1${marginValue}` + /(background:\s*)[^;]+/, + `$1${background.value.value}` ); + stylesheetStore.content = stylesheetStore.content.replace( + currentBlock, + updatedBlock + ); + } else { + const updatedBlock = currentBlock.replace( + /(\s*})$/, + ` background: ${background.value.value};\n$1` + ); + stylesheetStore.content = stylesheetStore.content.replace( + currentBlock, + updatedBlock + ); + } +}; - stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock); - }); -}, { deep: true }); +// Watch background value (text input) with debounce +watch( + () => background.value.value, + () => { + if (isUpdatingFromStore) return; + debouncedUpdate(updateBackground); + } +); -watch(background, (newBg) => { - if (!newBg.value) return; - if (isUpdatingFromStore) return; - - debouncedUpdate(() => { - const currentBlock = stylesheetStore.extractBlock('@page'); - - if (currentBlock.includes('background:')) { - const updatedBlock = currentBlock.replace( - /(background:\s*)[^;]+/, - `$1${newBg.value}` - ); - stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock); - } else { - const updatedBlock = currentBlock.replace( - /(\s*})$/, - ` background: ${newBg.value};\n$1` - ); - stylesheetStore.content = stylesheetStore.content.replace(currentBlock, updatedBlock); - } - }); -}, { deep: true }); +// Watch background format (button clicks) without debounce +watch( + () => background.value.format, + () => { + if (isUpdatingFromStore) return; + immediateUpdate(updateBackground); + } +); watch(pattern, (newPattern) => { if (!newPattern || isUpdatingFromStore) return; - debouncedUpdate(() => { + immediateUpdate(() => { // TODO: implement pattern application }); }); @@ -307,7 +347,7 @@ watch(pattern, (newPattern) => { watch(pageNumbers, (enabled) => { if (isUpdatingFromStore) return; - debouncedUpdate(() => { + immediateUpdate(() => { // TODO: implement page numbers toggle }); }); @@ -315,7 +355,7 @@ watch(pageNumbers, (enabled) => { watch(runningTitle, (enabled) => { if (isUpdatingFromStore) return; - debouncedUpdate(() => { + immediateUpdate(() => { // TODO: implement running title toggle }); }); @@ -331,12 +371,26 @@ const syncFromStore = () => { pageFormat.value = sizeMatch[1]; } - const marginMatch = pageBlock.match(/margin:\s*([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)/i); + const marginMatch = pageBlock.match( + /margin:\s*([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)\s+([0-9.]+)([a-z]+)/i + ); if (marginMatch) { - margins.value.top = { value: parseFloat(marginMatch[1]), unit: marginMatch[2] }; - margins.value.right = { value: parseFloat(marginMatch[3]), unit: marginMatch[4] }; - margins.value.bottom = { value: parseFloat(marginMatch[5]), unit: marginMatch[6] }; - margins.value.left = { value: parseFloat(marginMatch[7]), unit: marginMatch[8] }; + margins.value.top = { + value: parseFloat(marginMatch[1]), + unit: marginMatch[2], + }; + margins.value.right = { + value: parseFloat(marginMatch[3]), + unit: marginMatch[4], + }; + margins.value.bottom = { + value: parseFloat(marginMatch[5]), + unit: marginMatch[6], + }; + margins.value.left = { + value: parseFloat(marginMatch[7]), + unit: marginMatch[8], + }; } const bgMatch = pageBlock.match(/background:\s*([^;]+)/); @@ -348,11 +402,14 @@ const syncFromStore = () => { } }; -watch(() => stylesheetStore.content, () => { - if (!isUpdatingFromStore) { - syncFromStore(); +watch( + () => stylesheetStore.content, + () => { + if (!isUpdatingFromStore) { + syncFromStore(); + } } -}); +); onMounted(() => { syncFromStore(); diff --git a/src/components/editor/TextSettings.vue b/src/components/editor/TextSettings.vue index a72a39f..451b682 100644 --- a/src/components/editor/TextSettings.vue +++ b/src/components/editor/TextSettings.vue @@ -2,8 +2,8 @@

Réglage du texte

- Ces réglages s'appliquent à l'ensemble des éléments du document. - Vous pouvez modifier ensuite les éléments indépendamment. + Ces réglages s'appliquent à l'ensemble des éléments du document. Vous + pouvez modifier ensuite les éléments indépendamment.

@@ -17,11 +17,7 @@
- +
@@ -84,7 +80,7 @@
-
+
- + -
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+