Skip to content

Commit 9501881

Browse files
kryftmaddie927
authored andcommitted
Add a module with types for SVG elements (#87)
* Add types for SVG elements Adds a new module, React.Basic.DOM.SVG, with types for SVG elements. The types are generated based on the svg-element-attribute npm package. There were a few hyphenated elements (e.g. <font-face>) that looked like they might be troublesome with React. I couldn't find any information on whether React supports these, but they turned out to be deprecated according to MDN, so in the end I omitted all the deprecated elements. * Fix the Props_svg type in React.Basic.DOM The Props_svg type was generated from react-html-attributes, but react-html-attributes intentionally lists the wrong set of attributes for the svg tag: "One more note: all SVG element attributes supported by React are under the 'svg' key to avoid too many duplicated values and unnecessary file size." (https://www.npmjs.com/package/react-html-attributes) The attributes for Props_svg are now taken from svg-element-attributes instead, so the Props_svg in React.Basic.DOM is now the same as the Props_svg in React.Basic.DOM.SVG apart from using the HTML shared props instead of the SVG ones. * Fix SharedSVGProps Add the missing row type parameter * Remove redundant import * Add 'style' to SharedSVGProps with correct type
1 parent d70820f commit 9501881

File tree

6 files changed

+4802
-178
lines changed

6 files changed

+4802
-178
lines changed

codegen/consts.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
// For now, we are using a local copy of react-html-attributes.
22
// Eventually, the relative path here should be removed, and
33
// the version number of react-html-attributes should be bumped.
4-
module.exports.props = require("./react-html-attributes");
4+
module.exports.htmlProps = require("./react-html-attributes");
5+
module.exports.svgProps = require("svg-element-attributes");
56

67
module.exports.voids = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
78
// The types for certain attributes differ according to their containing element.

codegen/index.js

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const fs = require("fs");
2-
const { props, voids, types, typesByElement, reserved } = require("./consts");
3-
const genFile = "../src/React/Basic/DOM/Generated.purs";
2+
const { htmlProps, svgProps, voids, types, typesByElement, reserved } = require("./consts");
3+
const changeCase = require('change-case')
4+
const htmlGenFile = "../src/React/Basic/DOM/Generated.purs";
5+
const svgGenFile = "../src/React/Basic/DOM/SVG.purs";
46

5-
const header = `-- | ----------------------------------------
7+
const htmlHeader = `-- | ----------------------------------------
68
-- | THIS FILE IS GENERATED -- DO NOT EDIT IT
79
-- | ----------------------------------------
810
@@ -29,25 +31,66 @@ const propType = (e, p) => {
2931
}
3032
}
3133

34+
const svgHeader = `-- | ----------------------------------------
35+
-- | THIS FILE IS GENERATED -- DO NOT EDIT IT
36+
-- | ----------------------------------------
37+
38+
module React.Basic.DOM.SVG where
39+
40+
import Prim.Row (class Union)
41+
import React.Basic (JSX, element)
42+
import React.Basic.DOM.Internal (SharedSVGProps, unsafeCreateDOMComponent)
43+
44+
`;
45+
46+
const ignoredSvgPropKeys = [
47+
'*', 'elements',
48+
// These are all deprecated according to MDN, and I'm not sure what the
49+
// React representation should be for the hyphenated ones if they are
50+
// supported all, so let's exclude them
51+
"font", "glyph", "hkern", "missing-glyph", "vkern",
52+
"font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri",
53+
"altGlyph", "altGlyphDef", "altGlyphItem", "glyphRef",
54+
"tref", "color-profile", "cursor",
55+
]
56+
57+
const camelCaseSvgProps = {}
58+
Object.keys(svgProps).forEach(elName => {
59+
if (!ignoredSvgPropKeys.includes(elName)) {
60+
const elAttrs = svgProps[elName].map(changeCase.camelCase);
61+
// style is already included in SharedSVGProps
62+
delete elAttrs['style'];
63+
camelCaseSvgProps[elName] = elAttrs;
64+
}
65+
});
66+
67+
// The attribute list for <svg> in react-html-attributes
68+
// is wrong (it contains the union of the attributes of all
69+
// svg elements)
70+
htmlProps['svg'] = camelCaseSvgProps['svg'];
71+
3272
const printRecord = (e, elProps) =>
3373
elProps.length
3474
? `
3575
( ${elProps.map(p => `${p} :: ${propType(e, p)}`).join("\n , ")}
3676
)`
3777
: "()";
3878

39-
const domTypes = props.elements.html
40-
.map(e => {
79+
const generatePropTypes = (elements, props, sharedPropType) =>
80+
elements.map(e => {
4181
const noChildren = voids.includes(e);
4282
const symbol = reserved.includes(e) ? `${e}'` : e;
83+
84+
const propType = sharedPropType ? `(${sharedPropType} Props_${e})` : `Props_${e}`
85+
4386
return `
4487
type Props_${e} =${printRecord(e,
4588
(noChildren ? [] : ["children"]).concat(props[e] || [], props["*"] || []).sort()
4689
)}
4790
4891
${symbol}
4992
:: forall attrs attrs_
50-
. Union attrs attrs_ Props_${e}
93+
. Union attrs attrs_ ${propType}
5194
=> Record attrs
5295
-> JSX
5396
${symbol} = element (unsafeCreateDOMComponent "${e}")${
@@ -59,10 +102,14 @@ const domTypes = props.elements.html
59102
${e}_ children = ${symbol} { children }`
60103
}
61104
`;
62-
})
63-
.map(x => x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n"))
105+
}).map(x => x.replace(/^\n\ {4}/, "").replace(/\n\ {4}/g, "\n"))
64106
.join("\n");
65107

66-
console.log(`Writing "${genFile}" ...`);
67-
fs.writeFileSync(genFile, header + domTypes);
108+
const htmlTagTypes = generatePropTypes(htmlProps.elements.html, htmlProps, null);
109+
const svgTagTypes = generatePropTypes(Object.keys(camelCaseSvgProps), camelCaseSvgProps, 'SharedSVGProps');
110+
111+
console.log(`Writing "${htmlGenFile}" ...`);
112+
fs.writeFileSync(htmlGenFile, htmlHeader + htmlTagTypes);
113+
console.log(`Writing "${svgGenFile}" ...`);
114+
fs.writeFileSync(svgGenFile, svgHeader + svgTagTypes);
68115
console.log("Done.");

codegen/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
"main": "index.js",
66
"author": "",
77
"dependencies": {
8-
"react-html-attributes": "^1.4.6"
8+
"react-html-attributes": "^1.4.6",
9+
"change-case": "^3.1.0",
10+
"svg-element-attributes": "^1.3.0"
911
}
1012
}

0 commit comments

Comments
 (0)