diff --git a/docs/docs/ref-04-tags-and-attributes.md b/docs/docs/ref-04-tags-and-attributes.md index 8481c75b1c430..6cb7207239a2d 100644 --- a/docs/docs/ref-04-tags-and-attributes.md +++ b/docs/docs/ref-04-tags-and-attributes.md @@ -86,6 +86,13 @@ There is also the React-specific attribute `dangerouslySetInnerHTML` ([more here ### SVG Attributes -Any attributes passed to SVG tags are passed through without changes. - -React used to support special camelCase aliases for certain SVG attributes, such as `clipPath`. If you use them now you'll see a deprecation warning. These aliases will be removed in the next version in favor of their real names from the SVG specification, such as `clip-path`. Attributes that have a camelCase name in the spec, such as `gradientTransform`, will keep their names. +``` +clipPath cx cy d dx dy fill fillOpacity fontFamily +fontSize fx fy gradientTransform gradientUnits markerEnd +markerMid markerStart offset opacity patternContentUnits +patternUnits points preserveAspectRatio r rx ry spreadMethod +stopColor stopOpacity stroke strokeDasharray strokeLinecap +strokeOpacity strokeWidth textAnchor transform version +viewBox x1 x2 x xlinkActuate xlinkArcrole xlinkHref xlinkRole +xlinkShow xlinkTitle xlinkType xmlBase xmlLang xmlSpace y1 y2 y +``` diff --git a/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js b/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js index ed24ad4acaec5..84fb2711f42ab 100644 --- a/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js +++ b/src/renderers/dom/client/__tests__/ReactDOMSVG-test.js @@ -21,45 +21,6 @@ describe('ReactDOMSVG', function() { ReactDOMServer = require('ReactDOMServer'); }); - it('creates initial markup for known hyphenated attributes', function() { - var markup = ReactDOMServer.renderToString( - - ); - expect(markup).toContain('clip-path="url(#starlet)"'); - }); - - it('creates initial markup for camel case attributes', function() { - var markup = ReactDOMServer.renderToString( - - ); - expect(markup).toContain('viewBox="0 0 100 100"'); - }); - - it('deprecates camel casing of hyphenated attributes', function() { - spyOn(console, 'error'); - var markup = ReactDOMServer.renderToString( - - ); - expect(markup).toContain('clip-path="url(#starlet)"'); - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toContain('clipPath'); - expect(console.error.argsForCall[0][0]).toContain('clip-path'); - }); - - it('creates initial markup for unknown hyphenated attributes', function() { - var markup = ReactDOMServer.renderToString( - - ); - expect(markup).toContain('the-word="the-bird"'); - }); - - it('creates initial markup for unknown camel case attributes', function() { - var markup = ReactDOMServer.renderToString( - - ); - expect(markup).toContain('theWord="theBird"'); - }); - it('creates initial namespaced markup', function() { var markup = ReactDOMServer.renderToString( diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js index dc0c3fb7f9eee..1ce9e29b753fb 100644 --- a/src/renderers/dom/shared/DOMPropertyOperations.js +++ b/src/renderers/dom/shared/DOMPropertyOperations.js @@ -126,31 +126,6 @@ var DOMPropertyOperations = { return name + '=' + quoteAttributeValueForBrowser(value); }, - /** - * Creates markup for an SVG property. - * - * @param {string} name - * @param {*} value - * @return {string} Markup string, or empty string if the property was invalid. - */ - createMarkupForSVGAttribute: function(name, value) { - if (__DEV__) { - ReactDOMInstrumentation.debugTool.onCreateMarkupForSVGAttribute(name, value); - } - if (!isAttributeNameSafe(name) || value == null) { - return ''; - } - var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? - DOMProperty.properties[name] : null; - if (propertyInfo) { - // Migration path for deprecated camelCase aliases for SVG attributes - var { attributeName } = propertyInfo; - return attributeName + '=' + quoteAttributeValueForBrowser(value); - } else { - return name + '=' + quoteAttributeValueForBrowser(value); - } - }, - /** * Sets the value for a property on a node. * @@ -210,18 +185,6 @@ var DOMPropertyOperations = { } }, - setValueForSVGAttribute: function(node, name, value) { - if (__DEV__) { - ReactDOMInstrumentation.debugTool.onSetValueForSVGAttribute(node, name, value); - } - if (DOMProperty.properties.hasOwnProperty(name)) { - // Migration path for deprecated camelCase aliases for SVG attributes - DOMPropertyOperations.setValueForProperty(node, name, value); - } else { - DOMPropertyOperations.setValueForAttribute(node, name, value); - } - }, - /** * Deletes the value for a property on a node. * @@ -257,16 +220,6 @@ var DOMPropertyOperations = { } }, - deleteValueForSVGAttribute: function(node, name) { - var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? - DOMProperty.properties[name] : null; - if (propertyInfo) { - DOMPropertyOperations.deleteValueForProperty(node, name); - } else { - node.removeAttribute(name); - } - }, - }; ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', { diff --git a/src/renderers/dom/shared/HTMLDOMPropertyConfig.js b/src/renderers/dom/shared/HTMLDOMPropertyConfig.js index b71aafc78a337..ce5e93cea6e1a 100644 --- a/src/renderers/dom/shared/HTMLDOMPropertyConfig.js +++ b/src/renderers/dom/shared/HTMLDOMPropertyConfig.js @@ -30,176 +30,176 @@ var HTMLDOMPropertyConfig = { /** * Standard Properties */ - accept: null, - acceptCharset: null, - accessKey: null, - action: null, + accept: 0, + acceptCharset: 0, + accessKey: 0, + action: 0, allowFullScreen: HAS_BOOLEAN_VALUE, - allowTransparency: null, - alt: null, + allowTransparency: 0, + alt: 0, async: HAS_BOOLEAN_VALUE, - autoComplete: null, + autoComplete: 0, // autoFocus is polyfilled/normalized by AutoFocusUtils // autoFocus: HAS_BOOLEAN_VALUE, autoPlay: HAS_BOOLEAN_VALUE, capture: HAS_BOOLEAN_VALUE, - cellPadding: null, - cellSpacing: null, - charSet: null, - challenge: null, + cellPadding: 0, + cellSpacing: 0, + charSet: 0, + challenge: 0, checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - cite: null, - classID: null, - className: null, + cite: 0, + classID: 0, + className: 0, cols: HAS_POSITIVE_NUMERIC_VALUE, - colSpan: null, - content: null, - contentEditable: null, - contextMenu: null, + colSpan: 0, + content: 0, + contentEditable: 0, + contextMenu: 0, controls: HAS_BOOLEAN_VALUE, - coords: null, - crossOrigin: null, - data: null, // For `` acts as `src`. - dateTime: null, + coords: 0, + crossOrigin: 0, + data: 0, // For `` acts as `src`. + dateTime: 0, default: HAS_BOOLEAN_VALUE, defer: HAS_BOOLEAN_VALUE, - dir: null, + dir: 0, disabled: HAS_BOOLEAN_VALUE, download: HAS_OVERLOADED_BOOLEAN_VALUE, - draggable: null, - encType: null, - form: null, - formAction: null, - formEncType: null, - formMethod: null, + draggable: 0, + encType: 0, + form: 0, + formAction: 0, + formEncType: 0, + formMethod: 0, formNoValidate: HAS_BOOLEAN_VALUE, - formTarget: null, - frameBorder: null, - headers: null, - height: null, + formTarget: 0, + frameBorder: 0, + headers: 0, + height: 0, hidden: HAS_BOOLEAN_VALUE, - high: null, - href: null, - hrefLang: null, - htmlFor: null, - httpEquiv: null, - icon: null, - id: null, - inputMode: null, - integrity: null, - is: null, - keyParams: null, - keyType: null, - kind: null, - label: null, - lang: null, - list: null, + high: 0, + href: 0, + hrefLang: 0, + htmlFor: 0, + httpEquiv: 0, + icon: 0, + id: 0, + inputMode: 0, + integrity: 0, + is: 0, + keyParams: 0, + keyType: 0, + kind: 0, + label: 0, + lang: 0, + list: 0, loop: HAS_BOOLEAN_VALUE, - low: null, - manifest: null, - marginHeight: null, - marginWidth: null, - max: null, - maxLength: null, - media: null, - mediaGroup: null, - method: null, - min: null, - minLength: null, + low: 0, + manifest: 0, + marginHeight: 0, + marginWidth: 0, + max: 0, + maxLength: 0, + media: 0, + mediaGroup: 0, + method: 0, + min: 0, + minLength: 0, // Caution; `option.selected` is not updated if `select.multiple` is // disabled with `removeAttribute`. multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - name: null, - nonce: null, + name: 0, + nonce: 0, noValidate: HAS_BOOLEAN_VALUE, open: HAS_BOOLEAN_VALUE, - optimum: null, - pattern: null, - placeholder: null, - poster: null, - preload: null, - profile: null, - radioGroup: null, + optimum: 0, + pattern: 0, + placeholder: 0, + poster: 0, + preload: 0, + profile: 0, + radioGroup: 0, readOnly: HAS_BOOLEAN_VALUE, - rel: null, + rel: 0, required: HAS_BOOLEAN_VALUE, reversed: HAS_BOOLEAN_VALUE, - role: null, + role: 0, rows: HAS_POSITIVE_NUMERIC_VALUE, rowSpan: HAS_NUMERIC_VALUE, - sandbox: null, - scope: null, + sandbox: 0, + scope: 0, scoped: HAS_BOOLEAN_VALUE, - scrolling: null, + scrolling: 0, seamless: HAS_BOOLEAN_VALUE, selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, - shape: null, + shape: 0, size: HAS_POSITIVE_NUMERIC_VALUE, - sizes: null, + sizes: 0, span: HAS_POSITIVE_NUMERIC_VALUE, - spellCheck: null, - src: null, - srcDoc: null, - srcLang: null, - srcSet: null, + spellCheck: 0, + src: 0, + srcDoc: 0, + srcLang: 0, + srcSet: 0, start: HAS_NUMERIC_VALUE, - step: null, - style: null, - summary: null, - tabIndex: null, - target: null, - title: null, + step: 0, + style: 0, + summary: 0, + tabIndex: 0, + target: 0, + title: 0, // Setting .type throws on non-
, container); @@ -487,132 +328,6 @@ describe('ReactDOMComponent', function() { expect(container.childNodes[0].getAttribute('myattr')).toBe('myval'); }); - it('should update known hyphenated attributes for SVG tags', function() { - var container = document.createElement('div'); - - var beforeUpdate = ; - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ; - ReactDOM.render(afterUpdate, container); - - expect(container.childNodes[0].getAttribute('clip-path')).toBe( - 'url(#starlet)' - ); - }); - - it('should update camel case attributes for SVG tags', function() { - var container = document.createElement('div'); - - var beforeUpdate = ; - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ; - ReactDOM.render(afterUpdate, container); - - expect(container.childNodes[0].getAttribute('viewBox')).toBe( - '0 0 100 100' - ); - }); - - it('should warn camel casing hyphenated attributes for SVG tags', function() { - spyOn(console, 'error'); - var container = document.createElement('div'); - - var beforeUpdate = ; - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ; - ReactDOM.render(afterUpdate, container); - - expect(container.childNodes[0].getAttribute('clip-path')).toBe( - 'url(#starlet)' - ); - expect(console.error.argsForCall.length).toBe(1); - expect(console.error.argsForCall[0][0]).toContain('clipPath'); - expect(console.error.argsForCall[0][0]).toContain('clip-path'); - }); - - it('should only warn once about deprecated SVG attributes', function() { - spyOn(console, 'error'); - var container = document.createElement('div'); - ReactDOM.render( - - - - , - container - ); - expect(console.error.argsForCall.length).toBe(2); - expect(console.error.argsForCall[0][0]).toContain('clipPath'); - expect(console.error.argsForCall[0][0]).toContain('clip-path'); - expect(console.error.argsForCall[1][0]).toContain('strokeWidth'); - expect(console.error.argsForCall[1][0]).toContain('stroke-width'); - - ReactDOM.render( - - - - - , - container - ); - expect(console.error.argsForCall.length).toBe(3); - expect(console.error.argsForCall[0][0]).toContain('clipPath'); - expect(console.error.argsForCall[0][0]).toContain('clip-path'); - expect(console.error.argsForCall[1][0]).toContain('strokeWidth'); - expect(console.error.argsForCall[1][0]).toContain('stroke-width'); - expect(console.error.argsForCall[2][0]).toContain('strokeOpacity'); - expect(console.error.argsForCall[2][0]).toContain('stroke-opacity'); - }); - - it('should update arbitrary hyphenated attributes for SVG tags', function() { - var container = document.createElement('div'); - - var beforeUpdate = ; - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ; - ReactDOM.render(afterUpdate, container); - - expect(container.childNodes[0].getAttribute('the-word')).toBe('the-bird'); - }); - - it('should update arbitrary camel case attributes for SVG tags', function() { - var container = document.createElement('div'); - - var beforeUpdate = ; - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ; - ReactDOM.render(afterUpdate, container); - - expect(container.childNodes[0].getAttribute('theWord')).toBe('theBird'); - }); - - it('should update namespaced SVG attributes', function() { - var container = document.createElement('div'); - - var beforeUpdate = ( - - - - ); - ReactDOM.render(beforeUpdate, container); - - var afterUpdate = ( - - - - ); - ReactDOM.render(afterUpdate, container); - - expect(container.firstChild.firstChild.getAttributeNS( - 'http://www.w3.org/1999/xlink', - 'href' - )).toBe('http://i.imgur.com/JvqCM2p.png'); - }); - it('should clear all the styles when removing `style`', function() { var styles = {display: 'none', color: 'red'}; var container = document.createElement('div'); diff --git a/src/renderers/dom/shared/devtools/ReactDOMSVGDeprecatedAttributeDevtool.js b/src/renderers/dom/shared/devtools/ReactDOMSVGDeprecatedAttributeDevtool.js deleted file mode 100644 index 164340c7a7022..0000000000000 --- a/src/renderers/dom/shared/devtools/ReactDOMSVGDeprecatedAttributeDevtool.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * @providesModule ReactDOMSVGDeprecatedAttributeDevtool - */ - -'use strict'; - -var DOMProperty = require('DOMProperty'); - -var warning = require('warning'); - -if (__DEV__) { - var reactProps = { - children: true, - dangerouslySetInnerHTML: true, - key: true, - ref: true, - }; - var warnedSVGAttributes = {}; - - var warnDeprecatedSVGAttribute = function(name) { - if (reactProps.hasOwnProperty(name) && reactProps[name]) { - return; - } - - if (!DOMProperty.properties.hasOwnProperty(name)) { - return; - } - var { attributeName, attributeNamespace } = DOMProperty.properties[name]; - if (attributeNamespace || name === attributeName) { - return; - } - - if (warnedSVGAttributes.hasOwnProperty(name) && warnedSVGAttributes[name]) { - return; - } - warnedSVGAttributes[name] = true; - - warning( - false, - 'SVG property %s is deprecated. Use the original attribute name ' + - '%s for SVG tags instead.', - name, - attributeName - ); - }; -} - -var ReactDOMSVGDeprecatedAttributeDevtool = { - onCreateMarkupForSVGAttribute(name, value) { - warnDeprecatedSVGAttribute(name); - }, - onSetValueForSVGAttribute(node, name, value) { - warnDeprecatedSVGAttribute(name); - }, -}; - -module.exports = ReactDOMSVGDeprecatedAttributeDevtool;