diff --git a/demo/smoke_color_picker_consumers.mjs b/demo/smoke_color_picker_consumers.mjs index 8cd71a58..c7fc311e 100644 --- a/demo/smoke_color_picker_consumers.mjs +++ b/demo/smoke_color_picker_consumers.mjs @@ -46,6 +46,23 @@ const result = await page.evaluate(async () => { tempCold.renderRoot.querySelector('.trigger').click(); await tempCold.updateComplete; + lightOn.renderRoot.querySelector('.trigger').click(); + await lightOn.updateComplete; + await frame(); + const pickerSurface = lightOn._surface(); + const confirmButton = pickerSurface?.querySelector('.confirm'); + let pickerSurfaceClicks = 0; + pickerSurface?.addEventListener('click', () => { pickerSurfaceClicks += 1; }); + confirmButton?.dispatchEvent(new MouseEvent('click', { + bubbles: true, composed: true, cancelable: true, + })); + await lightOn.updateComplete; + await frame(); + out.generalConfirmDoesNotClickThrough = !!pickerSurface && !!confirmButton + && lightOn.renderRoot.querySelector('.trigger') + ?.getAttribute('aria-expanded') === 'false' + && pickerSurfaceClicks === 0; + const originalGlobalBg = card._settingsDialog.bgColor; globalBg.renderRoot.querySelector('.trigger').click(); await globalBg.updateComplete; diff --git a/scripts/mutation-gate.mjs b/scripts/mutation-gate.mjs index c6fd4d54..33fe4cfa 100644 --- a/scripts/mutation-gate.mjs +++ b/scripts/mutation-gate.mjs @@ -6713,6 +6713,39 @@ const MUTANT_DEFINITIONS = [ replace: "params.getAll('hp_alpha_stage3')", }], }, + { + id: 'color-picker-invalid-confirm-latch-removed', + guard: 'node demo/smoke_color_picker.mjs', + because: 'after an invalid HEX draft is normalized for display, repeated confirmation must ' + + 'still wait for a new valid input event; only the real picker lifecycle proves that the ' + + 'normalized fallback cannot bypass the #476 validation latch', + patches: [{ + file: 'src/hp-color-opacity.ts', + find: ' if (this._hexNeedsValidInput) {\n' + + ' this._hexInvalid = true;\n' + + ' return;\n' + + ' }', + replace: ' if (false) {\n' + + ' this._hexInvalid = true;\n' + + ' return;\n' + + ' }', + }], + }, + { + id: 'color-picker-confirm-click-through', + guard: 'node demo/smoke_color_picker_consumers.mjs', + because: 'the full-width confirmation inside a general-settings dialog must consume its own ' + + 'click before it reaches the picker surface; observing that direct ancestor keeps outer ' + + 'toolbar and modal stoppers from hiding removal of the #476 picker-level defense', + patches: [{ + file: 'src/hp-color-opacity.ts', + find: ' private _confirm(event: Event): void {\n' + + ' event.preventDefault();\n' + + ' event.stopPropagation();', + replace: ' private _confirm(event: Event): void {\n' + + ' event.preventDefault();', + }], + }, ]; const mutationCardSource = readFileSync(join(repoRoot, 'src/houseplan-card.ts'), 'utf8'); diff --git a/scripts/smoke-links.mjs b/scripts/smoke-links.mjs index 91cd917c..71d5d51d 100644 --- a/scripts/smoke-links.mjs +++ b/scripts/smoke-links.mjs @@ -32,11 +32,13 @@ export const SMOKE_LINKS = [ 'DEFAULT_LABELS', '_closePicker', '_commitHex', '_confirm', '_hexInvalid', '_hexNeedsValidInput', '_surface', ], - smokes: ['smoke_color_picker.mjs', 'smoke_help_affordance.mjs'], + smokes: [ + 'smoke_color_picker.mjs', 'smoke_color_picker_consumers.mjs', 'smoke_help_affordance.mjs', + ], because: 'the #476 production-bundle scenarios prove the full-width localized confirmation, ' + 'live-event count, invalid-HEX latch, focus and click containment in both the native ' - + 'popover and the dialog portal fallback; those browser lifecycle effects are not visible ' - + 'to source or pure color conversion tests', + + 'popover and the picker surface inside a general-settings dialog; those browser ' + + 'lifecycle effects are not visible to source or pure color conversion tests', }, { symbols: ['HpDialog', '_ensureNativeModal', '_useHaDialog', '_usesHaDialog'],