diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f451e3fb3..cfddf0d60f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange ## Unreleased +### Fixed +* [`no-unknown-property`]: add properties `onToggle`, `fill`, `as`, and pointer events ([#3385][] @sjarva) +* [`no-unknown-property`]: add `defaultChecked` property ([#3385][] @sjarva) +* [`no-unknown-property`]: add touch and media event related properties ([#3385][] @sjarva) +* [`no-unknown-property`]: `children` is always an acceptable prop; iframes have `scrolling`; ; video has `playsInline` ([#3385][] @ljharb) + +[#3385]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3385 + ## [7.31.4] - 2022.09.04 ### Fixed diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js index 2f883af8fb..a7bd0291ec 100644 --- a/lib/rules/no-unknown-property.js +++ b/lib/rules/no-unknown-property.js @@ -30,9 +30,57 @@ const ATTRIBUTE_TAGS_MAP = { checked: ['input'], // image is required for SVG support, all other tags are HTML. crossOrigin: ['script', 'img', 'video', 'audio', 'link', 'image'], - fill: ['svg'], + fill: [ // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill + // Fill color + 'altGlyph', + 'circle', + 'ellipse', + 'g', + 'path', + 'polygon', + 'polyline', + 'rect', + 'svg', + 'text', + 'textPath', + 'tref', + 'tspan', + // Animation final state + 'animate', + 'animateColor', + 'animateMotion', + 'animateTransform', + 'set', + ], property: ['meta'], viewBox: ['svg'], + as: ['link'], + // Media events allowed only on audio and video tags, see https://github.com/facebook/react/blob/256aefbea1449869620fb26f6ec695536ab453f5/CHANGELOG.md#notable-enhancements + onAbort: ['audio', 'video'], + onCanPlay: ['audio', 'video'], + onCanPlayThrough: ['audio', 'video'], + onDurationChange: ['audio', 'video'], + onEmptied: ['audio', 'video'], + onEncrypted: ['audio', 'video'], + onEnded: ['audio', 'video'], + onError: ['audio', 'video'], + onLoadedData: ['audio', 'video'], + onLoadedMetadata: ['audio', 'video'], + onLoadStart: ['audio', 'video'], + onPause: ['audio', 'video'], + onPlay: ['audio', 'video'], + onPlaying: ['audio', 'video'], + onProgress: ['audio', 'video'], + onRateChange: ['audio', 'video'], + onSeeked: ['audio', 'video'], + onSeeking: ['audio', 'video'], + onStalled: ['audio', 'video'], + onSuspend: ['audio', 'video'], + onTimeUpdate: ['audio', 'video'], + onVolumeChange: ['audio', 'video'], + onWaiting: ['audio', 'video'], + scrolling: ['iframe'], + playsInline: ['video'], }; const SVGDOM_ATTRIBUTE_NAMES = { @@ -127,7 +175,7 @@ const DOM_PROPERTY_NAMES_ONE_WORD = [ // Element specific attributes // See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes (includes global attributes too) // To be considered if these should be added also to ATTRIBUTE_TAGS_MAP - 'accept', 'action', 'allow', 'alt', 'async', 'buffered', 'capture', 'challenge', 'cite', 'code', 'cols', + 'accept', 'action', 'allow', 'alt', 'as', 'async', 'buffered', 'capture', 'challenge', 'cite', 'code', 'cols', 'content', 'coords', 'csp', 'data', 'decoding', 'default', 'defer', 'disabled', 'form', 'headers', 'height', 'high', 'href', 'icon', 'importance', 'integrity', 'kind', 'label', 'language', 'loading', 'list', 'loop', 'low', 'max', 'media', 'method', 'min', 'multiple', 'muted', @@ -149,7 +197,7 @@ const DOM_PROPERTY_NAMES_ONE_WORD = [ // OpenGraph meta tag attributes 'property', // React specific attributes - 'ref', 'key', + 'ref', 'key', 'children', ]; const DOM_PROPERTY_NAMES_TWO_WORDS = [ @@ -168,7 +216,7 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ 'onCompositionUpdate', 'onCut', 'onDoubleClick', 'onDrag', 'onDragEnd', 'onDragEnter', 'onDragExit', 'onDragLeave', 'onError', 'onFocus', 'onInput', 'onKeyDown', 'onKeyPress', 'onKeyUp', 'onLoad', 'onWheel', 'onDragOver', 'onDragStart', 'onDrop', 'onMouseDown', 'onMouseEnter', 'onMouseLeave', 'onMouseMove', 'onMouseOut', 'onMouseOver', - 'onMouseUp', 'onPaste', 'onScroll', 'onSelect', 'onSubmit', 'onTransitionEnd', 'radioGroup', 'readOnly', 'referrerPolicy', + 'onMouseUp', 'onPaste', 'onScroll', 'onSelect', 'onSubmit', 'onToggle', 'onTransitionEnd', 'radioGroup', 'readOnly', 'referrerPolicy', 'rowSpan', 'srcDoc', 'srcLang', 'srcSet', 'useMap', // SVG attributes // See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute @@ -204,7 +252,11 @@ const DOM_PROPERTY_NAMES_TWO_WORDS = [ 'autoCorrect', // https://stackoverflow.com/questions/47985384/html-autocorrect-for-text-input-is-not-working 'autoSave', // https://stackoverflow.com/questions/25456396/what-is-autosave-attribute-supposed-to-do-how-do-i-use-it // React specific attributes https://reactjs.org/docs/dom-elements.html#differences-in-attributes - 'className', 'dangerouslySetInnerHTML', 'defaultValue', 'htmlFor', 'onChange', 'suppressContentEditableWarning', 'suppressHydrationWarning', + 'className', 'dangerouslySetInnerHTML', 'defaultValue', 'defaultChecked', 'htmlFor', 'onChange', + 'onInvalid', 'onReset', 'onTouchCancel', 'onTouchEnd', 'onTouchMove', 'onTouchStart', 'suppressContentEditableWarning', 'suppressHydrationWarning', + 'onAbort', 'onCanPlay', 'onCanPlayThrough', 'onDurationChange', 'onEmptied', 'onEncrypted', 'onEnded', + 'onLoadedData', 'onLoadedMetadata', 'onLoadStart', 'onPause', 'onPlay', 'onPlaying', 'onProgress', 'onRateChange', + 'onSeeked', 'onSeeking', 'onStalled', 'onSuspend', 'onTimeUpdate', 'onVolumeChange', 'onWaiting', ]; const DOM_PROPERTIES_IGNORE_CASE = ['charset']; @@ -226,11 +278,28 @@ const ARIA_PROPERTIES = [ 'aria-posinset', 'aria-rowcount', 'aria-rowindex', 'aria-rowindextext', 'aria-rowspan', 'aria-setsize', ]; +const REACT_ON_PROPS = [ + 'onGotPointerCapture', + 'onLostPointerCapture', + 'onPointerCancel', + 'onPointerDown', + 'onPointerEnter', + 'onPointerLeave', + 'onPointerMove', + 'onPointerOut', + 'onPointerOver', + 'onPointerUp', +]; + function getDOMPropertyNames(context) { const ALL_DOM_PROPERTY_NAMES = DOM_PROPERTY_NAMES_TWO_WORDS.concat(DOM_PROPERTY_NAMES_ONE_WORD); // this was removed in React v16.1+, see https://github.com/facebook/react/pull/10823 if (!testReactVersion(context, '>= 16.1.0')) { - return ['allowTransparency'].concat(ALL_DOM_PROPERTY_NAMES); + return ALL_DOM_PROPERTY_NAMES.concat('allowTransparency'); + } + // these were added in React v16.4.0, see https://reactjs.org/blog/2018/05/23/react-v-16-4.html and https://github.com/facebook/react/pull/12507 + if (testReactVersion(context, '>= 16.4.0')) { + return ALL_DOM_PROPERTY_NAMES.concat(REACT_ON_PROPS); } return ALL_DOM_PROPERTY_NAMES; } diff --git a/tests/lib/rules/no-unknown-property.js b/tests/lib/rules/no-unknown-property.js index 7883afd23c..d03179ef75 100644 --- a/tests/lib/rules/no-unknown-property.js +++ b/tests/lib/rules/no-unknown-property.js @@ -48,11 +48,25 @@ ruleTester.run('no-unknown-property', rule, { { code: 'A cat sleeping on a keyboard' }, { code: '' }, { code: '' }, + { code: '
' }, + { code: '