From 0f64e54ebba0ab7c09a271c72dcdb82a859330a3 Mon Sep 17 00:00:00 2001 From: Geoff Rich <4992896+geoffrich@users.noreply.github.com> Date: Fri, 17 Mar 2023 08:58:51 -0700 Subject: [PATCH 01/14] chore: update changelog (#8390) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 097cfd51ba..771adf2100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * Prevent derived store callbacks after store is unsubscribed from ([#8364](https://github.com/sveltejs/svelte/issues/8364)) * Account for `bind:group` members being spread across multiple control flow blocks ([#8372](https://github.com/sveltejs/svelte/issues/8372)) * Revert buggy reactive statement optimization ([#8374](https://github.com/sveltejs/svelte/issues/8374)) +* Support CSS units in the `fly` and `blur` transitions ([#7623](https://github.com/sveltejs/svelte/pull/7623)) ## 3.56.0 From 33065aa1e629da315942859a06f5161e3244d8f4 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Fri, 17 Mar 2023 17:55:50 +0100 Subject: [PATCH 02/14] chore: update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 771adf2100..b78413123a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Svelte changelog +## Unreleased + +* Add `bind:innerText` for `contenteditable` elements ([#3311](https://github.com/sveltejs/svelte/issues/3311)) + ## 3.57.0 * Add `` ([#3310](https://github.com/sveltejs/svelte/issues/3310)) From 7e9e78b37c0c57a02c015196984e18cc47827345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cavit=20Ertu=C4=9Frul=20S=C4=B1rt?= <100495175+ertucode@users.noreply.github.com> Date: Sun, 19 Mar 2023 09:20:20 +0300 Subject: [PATCH 03/14] docs: Tutorial body had even though was the subject (#8396) --- .../16-special-elements/06-svelte-document/app-a/App.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/tutorial/16-special-elements/06-svelte-document/app-a/App.svelte b/site/content/tutorial/16-special-elements/06-svelte-document/app-a/App.svelte index cea052ec88..09cc596e8c 100644 --- a/site/content/tutorial/16-special-elements/06-svelte-document/app-a/App.svelte +++ b/site/content/tutorial/16-special-elements/06-svelte-document/app-a/App.svelte @@ -4,7 +4,7 @@ const handleSelectionChange = (e) => selection = document.getSelection(); - +

Select this text to fire events

Selection: {selection}

From fed93ab9e1da9b54852c17ebe1dc721e52bbb27b Mon Sep 17 00:00:00 2001 From: Nguyen Tran <88808276+ngtr6788@users.noreply.github.com> Date: Mon, 20 Mar 2023 08:18:54 -0400 Subject: [PATCH 04/14] feat: add a11y `interactive-supports-focus` (#8392) #820 --- .../content/docs/06-accessibility-warnings.md | 11 + src/compiler/compile/compiler_warnings.ts | 4 + src/compiler/compile/nodes/Element.ts | 44 ++- src/compiler/compile/utils/a11y.ts | 18 ++ .../input.svelte | 32 ++ .../warnings.json | 278 ++++++++++++++++++ 6 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 test/validator/samples/a11y-interactive-supports-focus/input.svelte create mode 100644 test/validator/samples/a11y-interactive-supports-focus/warnings.json diff --git a/site/content/docs/06-accessibility-warnings.md b/site/content/docs/06-accessibility-warnings.md index bc793d80e7..0d025d797d 100644 --- a/site/content/docs/06-accessibility-warnings.md +++ b/site/content/docs/06-accessibility-warnings.md @@ -137,6 +137,17 @@ Enforce that attributes important for accessibility have a valid value. For exam --- +### `a11y-interactive-supports-focus` + +Enforce that elements with an interactive role and interactive handlers (mouse or key press) must be focusable or tabbable. + +```sv + +
{}} /> +``` + +--- + ### `a11y-label-has-associated-control` Enforce that a label tag has a text label and an associated control. diff --git a/src/compiler/compile/compiler_warnings.ts b/src/compiler/compile/compiler_warnings.ts index 710377374f..a851bc24c2 100644 --- a/src/compiler/compile/compiler_warnings.ts +++ b/src/compiler/compile/compiler_warnings.ts @@ -166,6 +166,10 @@ export default { code: 'a11y-img-redundant-alt', message: 'A11y: Screenreaders already announce elements as an image.' }, + a11y_interactive_supports_focus: (role: string) => ({ + code: 'a11y-interactive-supports-focus', + message: `A11y: Elements with the '${role}' interactive role must have a tabindex value.` + }), a11y_label_has_associated_control: { code: 'a11y-label-has-associated-control', message: 'A11y: A form label must be associated with a control.' diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 2fd91ac495..7fcb586b6a 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -25,7 +25,7 @@ import { Literal } from 'estree'; import compiler_warnings from '../compiler_warnings'; import compiler_errors from '../compiler_errors'; import { ARIARoleDefinitionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query'; -import { is_interactive_element, is_non_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element, is_abstract_role } from '../utils/a11y'; +import { is_interactive_element, is_non_interactive_element, is_non_interactive_roles, is_presentation_role, is_interactive_roles, is_hidden_from_screen_reader, is_semantic_role_element, is_abstract_role, is_static_element, has_disabled_attribute } from '../utils/a11y'; const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' '); const aria_attribute_set = new Set(aria_attributes); @@ -75,6 +75,33 @@ const a11y_labelable = new Set([ 'textarea' ]); +const a11y_interactive_handlers = new Set([ + // Keyboard events + 'keypress', + 'keydown', + 'keyup', + + // Click events + 'click', + 'contextmenu', + 'dblclick', + 'drag', + 'dragend', + 'dragenter', + 'dragexit', + 'dragleave', + 'dragover', + 'dragstart', + 'drop', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseout', + 'mouseover', + 'mouseup' +]); + const a11y_nested_implicit_semantics = new Map([ ['header', 'banner'], ['footer', 'contentinfo'] @@ -603,6 +630,21 @@ export default class Element extends Node { } } + // interactive-supports-focus + if ( + !has_disabled_attribute(attribute_map) && + !is_hidden_from_screen_reader(this.name, attribute_map) && + !is_presentation_role(current_role) && + is_interactive_roles(current_role) && + is_static_element(this.name, attribute_map) && + !attribute_map.get('tabindex') + ) { + const has_interactive_handlers = handlers.some((handler) => a11y_interactive_handlers.has(handler.name)); + if (has_interactive_handlers) { + component.warn(this, compiler_warnings.a11y_interactive_supports_focus(current_role)); + } + } + // no-interactive-element-to-noninteractive-role if (is_interactive_element(this.name, attribute_map) && (is_non_interactive_roles(current_role) || is_presentation_role(current_role))) { component.warn(this, compiler_warnings.a11y_no_interactive_element_to_noninteractive_role(current_role, this.name)); diff --git a/src/compiler/compile/utils/a11y.ts b/src/compiler/compile/utils/a11y.ts index d0564b419e..4409f80262 100644 --- a/src/compiler/compile/utils/a11y.ts +++ b/src/compiler/compile/utils/a11y.ts @@ -68,6 +68,24 @@ export function is_hidden_from_screen_reader(tag_name: string, attribute_map: Ma return aria_hidden_value === true || aria_hidden_value === 'true'; } +export function has_disabled_attribute(attribute_map: Map) { + const disabled_attr = attribute_map.get('disabled'); + const disabled_attr_value = disabled_attr && disabled_attr.get_static_value(); + if (disabled_attr_value) { + return true; + } + + const aria_disabled_attr = attribute_map.get('aria-disabled'); + if (aria_disabled_attr) { + const aria_disabled_attr_value = aria_disabled_attr.get_static_value(); + if (aria_disabled_attr_value === true) { + return true; + } + } + + return false; +} + const non_interactive_element_role_schemas: ARIARoleRelationConcept[] = []; elementRoles.entries().forEach(([schema, roles]) => { diff --git a/test/validator/samples/a11y-interactive-supports-focus/input.svelte b/test/validator/samples/a11y-interactive-supports-focus/input.svelte new file mode 100644 index 0000000000..9caa9ccfaf --- /dev/null +++ b/test/validator/samples/a11y-interactive-supports-focus/input.svelte @@ -0,0 +1,32 @@ + +
{}} /> +
{}} /> +
{}} /> +
{}} /> + + + + `, + + async test({ component, target, assert }) { + component.boxes = [{ length: 10, width: 20, height: 30 }]; + + assert.htmlEqual(target.innerHTML, + '' + ); + } +}; diff --git a/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte new file mode 100644 index 0000000000..26dc5557ed --- /dev/null +++ b/test/runtime/samples/const-tag-each-destructure-computed-in-computed/main.svelte @@ -0,0 +1,44 @@ + + +{#each boxes as { [`leng${th}`]: length, [`wid${th}`]: width, height }} + {@const { + [`two${dimension}`]: areas, + [`three${dimension}`]: { + volume + } + } = calculate(length, width, height)} + {@const { + i = 1, + [`bottom${area}`]: bottom, + [`side${area}${i++}`]: sideone, + [`side${area}${i++}`]: sidetwo + } = areas} + +{/each} From b8959ac09ec78a0c0aad3d1d846d2eda569bcbba Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:32:41 +0200 Subject: [PATCH 13/14] chore: update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e886996a80..0c375e75ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ * Relax `a11y-no-noninteractive-element-to-interactive-role` warning ([#8402](https://github.com/sveltejs/svelte/pull/8402)) * Add `a11y-interactive-supports-focus` warning ([#8392](https://github.com/sveltejs/svelte/pull/8392)) * Fix equality check when updating dynamic text ([#5931](https://github.com/sveltejs/svelte/issues/5931)) +* Make `preserveComments` effective in DOM renderer ([#7182](https://github.com/sveltejs/svelte/pull/7182)) +* Add CSS container queries support ([#6969](https://github.com/sveltejs/svelte/issues/6969)) +* Properly handle microdata attributes ([#8414](https://github.com/sveltejs/svelte/pull/8414)) +* Prevent name collision when using computed destructuring variables ([#8417](https://github.com/sveltejs/svelte/issues/8417)) +* Allow use of `document` for `target` in typings ([#7554](https://github.com/sveltejs/svelte/pull/7554)) ## 3.57.0 From 1333be0c6ad22fc49792a76478fcb231314bb765 Mon Sep 17 00:00:00 2001 From: Filip Ambrosius Date: Mon, 27 Mar 2023 11:02:12 +0200 Subject: [PATCH 14/14] fix: Regression `itemscope` as `boolean_attribute` (#8414) Microdata are a strange set of attributes which are ONLY defined in markup, and have no relationship to the underlying Document Object Model node. As such programmatically defining an element and setting a property on it with a given Microdata attribute will not work: https://codepen.io/iambrosius/full/jOvXBBG One can read more about microdata here: https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata The fix is to remove itemscope being a boolean attribute, because that opts into a transformation as a DOM property, which is wrong. --- .../render_dom/wrappers/Element/Attribute.ts | 1 - src/shared/boolean_attributes.ts | 1 - .../attribute-boolean-hidden/_config.js | 10 ++++++ .../attribute-boolean-hidden/main.svelte | 5 +++ .../attribute-boolean-itemscope/_config.js | 11 ------- .../attribute-boolean-itemscope/main.svelte | 5 --- .../samples/attribute-microdata/_config.js | 25 +++++++++++++++ .../samples/attribute-microdata/main.svelte | 31 +++++++++++++++++++ 8 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 test/runtime/samples/attribute-boolean-hidden/_config.js create mode 100644 test/runtime/samples/attribute-boolean-hidden/main.svelte delete mode 100644 test/runtime/samples/attribute-boolean-itemscope/_config.js delete mode 100644 test/runtime/samples/attribute-boolean-itemscope/main.svelte create mode 100644 test/runtime/samples/attribute-microdata/_config.js create mode 100644 test/runtime/samples/attribute-microdata/main.svelte diff --git a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts index 6cb3a00218..64178030f6 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/Attribute.ts @@ -364,7 +364,6 @@ const attribute_lookup: { [key in BooleanAttributes]: AttributeMetadata } & { [k indeterminate: { applies_to: ['input'] }, inert: {}, ismap: { property_name: 'isMap', applies_to: ['img'] }, - itemscope: {}, loop: { applies_to: ['audio', 'bgsound', 'video'] }, multiple: { applies_to: ['input', 'select'] }, muted: { applies_to: ['audio', 'video'] }, diff --git a/src/shared/boolean_attributes.ts b/src/shared/boolean_attributes.ts index 668dd97975..10513ec712 100644 --- a/src/shared/boolean_attributes.ts +++ b/src/shared/boolean_attributes.ts @@ -13,7 +13,6 @@ const _boolean_attributes = [ 'hidden', 'inert', 'ismap', - 'itemscope', 'loop', 'multiple', 'muted', diff --git a/test/runtime/samples/attribute-boolean-hidden/_config.js b/test/runtime/samples/attribute-boolean-hidden/_config.js new file mode 100644 index 0000000000..cb38feb93d --- /dev/null +++ b/test/runtime/samples/attribute-boolean-hidden/_config.js @@ -0,0 +1,10 @@ +export default { + props: { + hidden: true + }, + html: '