Skip to content

Commit 8c99d47

Browse files
authored
Merge pull request #1 from lume/svg-math-xml-templates
add `svg` and `mathml` template tags for supporting partial SVG and MathML templates within `html` templates
2 parents 06aa6cf + 215f27b commit 8c99d47

File tree

8 files changed

+776
-23
lines changed

8 files changed

+776
-23
lines changed

.github/copilot-instructions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Follow instructions from the repo's top-level CONTRIBUTING.md.
1+
Always, always, read the repo's top-level CONTRIBUTING.md file before doing any
2+
work, and follow its instructions.

.github/workflows/test.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
jobs:
8+
test:
9+
runs-on: ${{ matrix.os }}
10+
11+
strategy:
12+
matrix:
13+
os: [ubuntu-latest, windows-latest, macos-latest]
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
19+
- name: Setup Node.js
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: 'lts/*'
23+
cache: 'npm'
24+
25+
- name: Install dependencies
26+
run: npm clean-install
27+
28+
- name: Run tests
29+
run: npm test

.prettierrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module.exports = {
66
bracketSpacing: false,
77
printWidth: 120,
88
arrowParens: 'avoid',
9+
endOfLine: 'auto',
910

1011
overrides: [{files: '*.md', options: {useTabs: false}}],
1112
}

CONTRIBUTING.md

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,75 @@ Do not install any new dependencies.
1010
# Testing
1111

1212
Run `npm test` to test everything. This runs the build, checks code formatting,
13-
and finally runs unit tests.
13+
and finally runs unit tests. Never run any other test command than `npm test`.
1414

1515
When writing new tests, always follow the format in `html.test.js` as a
1616
reference, using `describe` and `it` functions to describe unit tests.
17+
18+
# Best Practices
19+
20+
- Don't constantly re-create RegExp objects, put them in a variable outside of
21+
functions so they are only created once (f.e. at the top level scope of the
22+
module).
23+
- Always aim for the simplest _readable, understandable_ solution.
24+
- If you're adding too much code, you might be solving the problem in a too complex way.
25+
- Put re-usable code in functions, always avoid duplication.
26+
- Don't use complex one-liners or clever bit fiddling unless it is absolutely
27+
necessary for something like solving a performance _problem_, prefer multiple
28+
simple readable lines.
29+
- Don't prematurely optimize, always prefer readable code first.
30+
- Document your code with JSDoc comments. All functions, methods, and classes
31+
should have JSDoc comments.
32+
- Avoid unnecessary braces. For example for conditional or loop blocks with a single statement, prefer:
33+
```js
34+
if (condition) doSomething()
35+
```
36+
instead of:
37+
```js
38+
if (condition) {
39+
doSomething()
40+
}
41+
```
42+
Similar with for loops, while loops, arrow functions.
43+
- Use new features such as optional chaining (`obj?.prop`), nullish coalescing
44+
(`value ?? defaultValue`), and logical assignment operators (`x ||= y`, `x &&= y`,
45+
`x ??= y`) when they make the code simpler and more readable.
46+
- Always prefer `const` for variables that don't change, and `let` only for
47+
variables that change. Never use `var` unless absolutely necessary for special
48+
hoisting reasons.
49+
- Always prefer for-of over items.forEach
50+
- Always prefer `element.remove()` instead of `element.parentNode.removeChild(element)`.
51+
- Always prefer `parentElement.append(childElement)` instead of
52+
`parentElement.appendChild(childElement)`.
53+
- Always prefer `parentElement.append(...childElements)` instead of
54+
`childElements.forEach(child => parentElement.appendChild(child))`.
55+
- Always prefer `parentElement.prepend(childElement)` instead of
56+
`parentElement.insertBefore(childElement, parentElement.firstChild)`.
57+
- Always prefer `element.replaceWith(newElement)` instead of
58+
`element.parentNode.replaceChild(newElement, element)`.
59+
60+
# AI only:
61+
62+
## Never do the following:
63+
64+
- Never create tests in files that you run with `node`. Our code is for
65+
browsers, so always run tests using `npm test` which ensures our tests run in a
66+
headless browser. The output is logged back to terminal.
67+
68+
## Responding to prompts
69+
70+
After every prompt, always provide at least three proposals for a solution, with
71+
pros and cons, and stop to allow the user to select the desired direction.
72+
73+
A conversation should be like this:
74+
75+
1. User: Let's do [thing to do].
76+
2. AI: Here are three ways we could do X:
77+
1. Do it this way because of A, B, C. Pros: ... Cons: ...
78+
2. Do it that way because of D, E, F. Pros: ... Cons: ...
79+
3. Do it another way because of G, H, I. Pros: ... Cons: ...
80+
3. User: Let's go with option 2.
81+
4. AI: Great! (AI goes and implements option 2)
82+
5. Repeat from step 1.
83+
84+
Basically, _always_ confirm with three proposals before implementing anything.

examples/svg-and-mathml.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>SVG Test</title>
5+
</head>
6+
<body>
7+
<script type="module" src="./svg-and-mathml.js"></script>
8+
</body>
9+
</html>

examples/svg-and-mathml.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {html, svg, mathml} from '../html.js'
2+
3+
const template = html /*html*/ `
4+
<div>
5+
<p>
6+
Showing SVG and MathML support. This example shows the <code>svg</code> and <code>mathml</code> template tags can
7+
be used to create SVG and MathML elements within HTML templates. Replacing the <code>svg</code> and
8+
<code>mathml</code> template tags with <code>html</code> will result in HTMLUnknownElement instances due to the
9+
partial templates being parsed as HTML instead of SVG or MathML.
10+
11+
<style>
12+
code {
13+
color: deeppink;
14+
font-weight: bold;
15+
}
16+
</style>
17+
</p>
18+
19+
<p>Regular HTML:</p>
20+
<div class="my-div" style="padding: 20px; border: 1px solid black;">This is a regular div</div>
21+
22+
<p>SVG Elements:</p>
23+
<svg width="200" height="200">
24+
${svg /*xml*/ `
25+
<circle cx="100" cy="100" r="50" fill="red" />
26+
<rect x="50" y="50" width="100" height="100" fill="blue" opacity="0.5" />
27+
`}
28+
</svg>
29+
30+
<p>MathML Elements:</p>
31+
<br />
32+
<math style="padding: 20px; border: 1px solid black;">
33+
${mathml /*xml*/ `
34+
<mfrac>
35+
<mi>x</mi>
36+
<mi>y</mi>
37+
</mfrac>
38+
`}
39+
</math>
40+
</div>
41+
`(Symbol())
42+
43+
document.body.append(...template)
44+
45+
// Let's inspect the elements
46+
const div = document.querySelector('.my-div')
47+
const svgEl = document.querySelector('svg')
48+
const circle = document.querySelector('circle')
49+
const rect = document.querySelector('rect')
50+
const mathEl = document.querySelector('math')
51+
const mfrac = document.querySelector('mfrac')
52+
53+
console.log('Regular div:', div, div?.constructor.name) // HTMLDivElement
54+
console.log('SVG element:', svgEl, svgEl?.constructor.name) // SVGSVGElement
55+
console.log('Circle element:', circle, circle?.constructor.name) // SVGCircleElement
56+
console.log('Rect element:', rect, rect?.constructor.name) // SVGRectElement
57+
console.log('MathML element:', mathEl, mathEl?.constructor.name) // MathMLElement
58+
console.log('mfrac element:', mfrac, mfrac?.constructor.name) // MathMLFractionElement
59+
60+
// Check if SVG elements are actually SVG elements
61+
console.log('div instanceof HTMLDivElement:', div instanceof HTMLDivElement) // true
62+
console.log('svg instanceof SVGSVGElement:', svgEl instanceof SVGSVGElement) // true
63+
console.log('circle instanceof SVGCircleElement:', circle instanceof SVGCircleElement) // true
64+
console.log('rect instanceof SVGRectElement:', rect instanceof SVGRectElement) // true
65+
console.log('math instanceof MathMLElement:', mathEl instanceof MathMLElement) // true
66+
console.log('mfrac instanceof MathMLFractionElement:', mfrac instanceof MathMLElement) // true
67+
68+
// Check if they're unknown elements
69+
console.log('circle instanceof HTMLUnknownElement:', circle instanceof HTMLUnknownElement) // false
70+
console.log('rect instanceof HTMLUnknownElement:', rect instanceof HTMLUnknownElement) // false
71+
console.log('mfrac instanceof HTMLUnknownElement:', mfrac instanceof HTMLUnknownElement) // false

0 commit comments

Comments
 (0)