Compare commits

..

No commits in common. "main" and "v0.30.0" have entirely different histories.

20 changed files with 398 additions and 1674 deletions

View File

@ -1,361 +1,3 @@
## 0.34.1
* Fix gap property break and remove redundant styles.
<br /> <br />
## 0.34.0
### Breaking
* The css-doodle element now is by default restrict the visible area to its dimension,
which means it's overflow hidden. There are two ways to change this behavior:
1. Append the <code>noclip</code> keyword to the `@grid` property:
```css
@grid: 1 / 400px noclip;
```
2. Overide the `contain` property:
```css
:doodle {
@grid: 1 / 400px;
contain: none;
}
```
### Features
* Extended `@grid` to support doodle background color, after the second `/` symbol.
```css
@grid: 1 / 400px / #000;
```
* Extended `@grid` and `@size` to support <code>aspect-ratio</code> if one of the `width` and `width` is `auto`.
```css
@grid: 1 / 400px auto 2;
@grid: 1 / 400px auto (4/3);
@size: 100px auto 1.5;
```
* Extended `@grid` to support <code>rotate</code> and <code>scale</code> to <code>:container</code>.
```css
@grid: 1 / 400px + 2; /* + means scale */
@grid: 1 / 400px * 45deg; /* * means scale */
@grid: 1 / 400px + 2 * 45deg;
```
* Extended `@grid` to change the layout to `Flex` layout.
```css
@grid: - 8x2 / 400px; /* - means using flex */
@grid: | 8x2 / 400px; /* | means using flex and vertical direction */
```
* Added support for 0 index value in `@m` function.
```css
/* 0 1 2 3 4 */
@content: @M0-4.n
```
* Added `@gap` property.
```css
@grid: 10 / 400px;
@gap: 1px;
```
* Added `@dx` and `@dy` functions.
```css
/* -2,-2 -1,-2 0,-2 1,-2 2,-2
-2,-1 -1,-1 0,-1 1,-1 2,-1
-2,0 -1,0 0,0 1,0 2,0
-2,1 -1,1 0,1 1,1 2,1
-2,2 -1,2 0,2 1,2 2,2 */
@grid: 5 / 400px;
@content: @dx, @dy;
```
Adjust offset.
```css
/* -3,-3 -2,-3 -1,-3 0,-3 1,-3
-3,-2 -2,-2 -1,-2 0,-2 1,-2
-3,-1 -2,-1 -1,-1 0,-1 1,-1
-3,0 -2,0 -1,0 0,0 1,0
-3,1 -2,1 -1,1 0,1 1,1 */
@grid: 5 / 400px;
@content: @dx(1), @dy(1);
```
### Fixes
* Fixed CSS parsing on function composition.
* Fixed seed value at pre-compose phase.
<br /> <br />
## 0.33.1
* Fixed `@Svg` function detection for transforming the `multiplication` feature.
* Fixed `@pn` index value inside `@m` function.
<br /> <br />
## 0.33.0
* Added new `@svg-pattern` function to reduce boilerplate code.
```css
background: @svg-pattern(
width, height: 10%;
viewBox: 0 0 10 10;
circle { }
);
```
* Added new `@Svg` function to return raw SVG code rather than encoded URI value.
```css
@content: @Svg(
viewBox: -1 -1 2 2;
circle {
r: 1;
}
);
```
* Added `padding` value for SVG `viewBox` property.
```css
viewBox: -1 -1 2 2 padding 1;
/* equals to */
viewBox: -2 2 4 4;
```
<br /> <br />
## 0.32.2
* Do not use `??` operator at the moment.
<br /> <br />
## 0.32.1
* Build grid without DOM object.
* Fix CSS parser for reading tail function names.
<br /> <br />
## 0.32.0
### Features
* Add `@unicode` function to insert Unicode and it can be used both in HTML and CSS.
```css
/* in HTML */
@content: @unicode(0x2500);
/* in CSS */
:after {
content: @unicode(0x2500);
}
```
A sequence of Unicode characters.
```css
@content: @pn.unicode(0x2500, 0x257f, 0x2588);
```
* Add `@mirror/@Mirror` function to transform input items, simlar to `@cycle` and `@reverse`.
```css
/* 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 */
@mirror(1, 2, 3, 4, 5);
/* 1, 2, 3, 4, 5, 4, 3, 2, 1 */
@Mirror(1, 2, 3, 4, 5);
```
* All index functions, `@i/I`, `@x/X`, `@y/Y`, and `@n/N/nx/ny` accept extra arguments to do calulations.
```css
@i5 === @calc(@i + 5)
@i(*10) === @calc(@i * 10)
@i(-10) === @calc(@i - 10)
@i(/10) === @calc(@i / 10)
@i(%10) === @calc(@i % 10)
@i(10/) === @calc(10 / @i)
@i(10-) === @calc(10 - @i)
```
### Patches
* Reduce imports of the exported svg function.
* Improve `@cycle` to support comma-separated values.
* Fix grid build for `@content`.
* Fix parsing quotes in content.
```css
/* There used to be bugs` */
content: '");';
```
<br /> <br />
## 0.31.2
* Fix svg-extended style tag generation.
<br /> <br />
## 0.31.1
* Fix bad reverse function implementation.
<br /> <br />
## 0.31.0
* Add `@content` property for text content so that they can be selectable.
* The `@` symbol can be ommited if the functions are chained together.
* Patch reverse function to support both SVG path commands and general arguments.
* Skip variable properties for SVG generation.
* Fix style tag parsing inside SVG for complex CSS selectors.
<br /> <br />
## 0.30.10
* Add `@pnr` alias for `@pr`.
<br /> <br />
## 0.30.9
* Support variables in standalone SVG export function.
* Compute index instead of reversing the whole array.
* Use single rotate for inner `@place` transformation.
* Simplify image detection.
* Use `@pn` and `@position` as aliases.
<br /> <br />
## 0.30.8
Experimenting the new added `pr` function.
<br /> <br />
## 0.30.7
Experimenting the new added `cycle()` function.
<br /> <br />
## 0.30.6
I was wrong. Only set `background-size:100%` to `pattern`, `canvas`, and `shader`.
<br /> <br />
## 0.30.5
* Always add `background-size:100%` to background properties.
<br /> <br />
## 0.30.4
* Normalize quoted SVG attribute values.
<br /> <br />
## 0.30.3
* Do not break for decodeURI.
* Fix SVG generator on cutting values.
<br /> <br />
## 0.30.2
* Fix type error.
<br /> <br />
## 0.30.1
* Fix CSS and SVG parser on quotes and parens.
* Add range support for `@m` function.
```css
::after {
/* 5 4 3 2 1 */
content: @M5-1.@n;
}
```
<br /> <br />
## 0.30.0
* Add exports.
@ -388,9 +30,6 @@ I was wrong. Only set `background-size:100%` to `pattern`, `canvas`, and `shader
`);
```
<br /> <br />
## 0.29.2

View File

@ -28,7 +28,6 @@ A web component for drawing patterns with CSS.
* [Tabbied](https://tabbied.com) -- Doodle with generated patterns
* [Shapes](https://css-doodle.com/shapes) -- Discover new CSS polygon shapes
* [SVG playground](https://css-doodle.com/svg) -- Generate SVG code with new syntax
## Resources

File diff suppressed because it is too large Load Diff

2
css-doodle.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "css-doodle",
"version": "0.34.1",
"version": "0.30.0",
"description": "A web component for drawing patterns with CSS",
"main": "css-doodle.js",
"scripts": {

View File

@ -1,24 +1,14 @@
import { generate_css } from '../../generator/css.js';
import parse_css from './../../parser/parse-css.js';
import parse_svg from './../../parser/parse-svg.js';
import parse_grid from './../../parser/parse-grid.js';
import { make_tag_function } from '../../utils/index.js';
export default function svg(rules) {
let parsedSvg = parse_svg(rules);
let inlineVariable = '';
for (let item of parsedSvg.value) {
if (item.variable) {
inlineVariable += `${item.name}: ${item.value};`;
}
}
let result = generate_css(
parse_css(`${inlineVariable} background: @svg(${rules});`),
{ x: 1, y: 1, z: 1, count: 1, ratio: 1 }
parse_css(`background: @svg(${rules});`),
parse_grid('1x1')
);
let raw = result && result.styles && result.styles.cells || '';
let cut = raw.substring(raw.indexOf('%3'), raw.lastIndexOf('");'));
try {
return decodeURIComponent(cut);
} catch (e) {
return '';
}
let cut = raw.substring(52, raw.length - 5);
return decodeURIComponent(cut);
}

View File

@ -1,7 +1,7 @@
import { create_svg_url, normalize_svg } from './utils/svg.js';
import { generate_svg } from './generator/svg.js';
import { cell_id, is_letter, is_nil, is_empty, add_alias, unique_id, lerp } from './utils/index.js';
import { cell_id, is_letter, is_nil, add_alias, unique_id, lerp } from './utils/index.js';
import { lazy, clamp, sequence, get_value } from './utils/index.js';
import { by_unit, by_charcode } from './utils/transform.js';
import { last } from './utils/list.js';
@ -26,7 +26,7 @@ function make_sequence(c) {
if (!actions || !n) return '';
let count = get_value(n());
let evaluated = count;
if (/\D/.test(count) && !/\d+[x-]\d+/.test(count)) {
if (/\D/.test(count)){
evaluated = calc(count);
if (evaluated === 0) {
evaluated = count;
@ -61,107 +61,62 @@ function map2d(value, min, max, amp = 1) {
return lerp((value - ma) / (mb - ma), min * amp, max * amp);
}
function calc_with(base) {
return v => {
if (is_empty(v) || is_empty(base)) {
return base;
}
if (/^[+*-\/%][.\d\s]/.test(v)) {
let op = v[0];
let num = Number(v.substr(1).trim()) || 0;
switch (op) {
case '+': return base + num;
case '-': return base - num;
case '*': return base * num;
case '/': return base / num;
case '%': return base % num;
}
}
else if (/[+*-\/%]$/.test(v)) {
let op = v.substr(-1);
let num = Number(v.substr(0, v.length - 1).trim()) || 0;
switch (op) {
case '+': return num + base;
case '-': return num - base;
case '*': return num * base;
case '/': return num / base;
case '%': return num % base;
}
}
return base + (Number(v) || 0);
}
}
const Expose = add_alias({
i({ count }) {
return calc_with(count);
return _ => count;
},
y({ y }) {
return calc_with(y);
return _ => y;
},
x({ x }) {
return calc_with(x);
return _ => x;
},
z({ z }) {
return calc_with(z);
return _ => z;
},
I({ grid }) {
return calc_with(grid.count);
return _ => grid.count;
},
Y({ grid }) {
return calc_with(grid.y);
return _ => grid.y;
},
X({ grid }) {
return calc_with(grid.x);
return _ => grid.x;
},
Z({ grid }) {
return calc_with(grid.z);
return _ => grid.z;
},
id({ x, y, z }) {
return _ => cell_id(x, y, z);
},
dx({ x, grid }) {
return n => {
n = Number(n) || 0;
return x - .5 - n - grid.x / 2;
}
},
dy({ y, grid }) {
return n => {
n = Number(n) || 0;
return y - .5 - n - grid.y / 2;
}
},
n({ extra }) {
let lastExtra = last(extra);
return lastExtra ? calc_with(lastExtra[0]) : '@n';
return n => lastExtra ? (lastExtra[0] + (Number(n) || 0)) : '@n';
},
nx({ extra }) {
let lastExtra = last(extra);
return lastExtra ? calc_with(lastExtra[1]) : '@nx';
return n => lastExtra ? (lastExtra[1] + (Number(n) || 0)) : '@nx';
},
ny({ extra }) {
let lastExtra = last(extra);
return lastExtra ? calc_with(lastExtra[2]) : '@ny';
return n => lastExtra ? (lastExtra[2] + (Number(n) || 0)) : '@ny';
},
N({ extra }) {
let lastExtra = last(extra);
return lastExtra ? calc_with(lastExtra[3]) : '@N';
return n => lastExtra ? (lastExtra[3] + (Number(n) || 0)) : '@N';
},
m: make_sequence(','),
@ -212,38 +167,21 @@ const Expose = add_alias({
});
},
pl({ context, extra, position }) {
pn({ context, extra, position }) {
let lastExtra = last(extra);
let sig = lastExtra ? last(lastExtra) : '';
let counter = 'pl-counter' + position + sig;
let counter = 'pn-counter' + position + sig;
return expand((...args) => {
if (!context[counter]) context[counter] = 0;
context[counter] += 1;
let max = args.length;
let idx = lastExtra && lastExtra[6];
if (is_nil(idx)) idx = context[counter];
let [idx = context[counter]] = lastExtra || [];
let pos = (idx - 1) % max;
let value = args[pos];
return push_stack(context, 'last_pick', value);
});
},
pr({ context, extra, position }) {
let lastExtra = last(extra);
let sig = lastExtra ? last(lastExtra) : '';
let counter = 'pr-counter' + position + sig;
return expand((...args) => {
if (!context[counter]) context[counter] = 0;
context[counter] += 1;
let max = args.length;
let idx = lastExtra && lastExtra[6];
if (is_nil(idx)) idx = context[counter];
let pos = (idx - 1) % max;
let value = args[max - pos - 1];
return push_stack(context, 'last_pick', value);
});
},
pd({ context, extra, position, shuffle }) {
let lastExtra = last(extra);
let sig = lastExtra ? last(lastExtra) : '';
@ -256,8 +194,7 @@ const Expose = add_alias({
context[values] = shuffle(args || []);
}
let max = args.length;
let idx = lastExtra && lastExtra[6];
if (is_nil(idx)) idx = context[counter];
let [idx = context[counter]] = lastExtra || [];
let pos = (idx - 1) % max;
let value = context[values][pos];
return push_stack(context, 'last_pick', value);
@ -384,15 +321,6 @@ const Expose = add_alias({
return create_svg_url(svg);
}),
Svg: lazy((_, ...args) => {
let value = args.map(input => get_value(input())).join(',');
if (!value.startsWith('<')) {
let parsed = parse_svg(value);
value = generate_svg(parsed);
}
return normalize_svg(value);
}),
filter: lazy((upstream, ...args) => {
let values = args.map(input => get_value(input()));
let value = values.join(',');
@ -463,20 +391,6 @@ const Expose = add_alias({
return create_svg_url(svg, id);
}),
'svg-pattern': lazy((_, ...args) => {
let value = args.map(input => get_value(input())).join(',');
let parsed = parse_svg(`
viewBox: 0 0 1 1;
preserveAspectRatio: xMidYMid slice;
rect {
width, height: 100%;
fill: defs pattern { ${ value } }
}
`);
let svg = generate_svg(parsed);
return create_svg_url(svg);
}),
var() {
return value => `var(${ get_value(value) })`;
},
@ -625,76 +539,13 @@ const Expose = add_alias({
}
},
reverse() {
return (...args) => {
let commands = args.map(get_value);
let parsed = parse_svg_path(commands.join(','));
if (parsed.valid) {
let result = [];
for (let i = parsed.commands.length - 1; i >= 0; --i) {
let { name, value } = parsed.commands[i];
result.push(name + value.join(' '));
}
return result.join(' ');
}
return commands.reverse();
}
},
cycle() {
return (...args) => {
let list = [];
let separator;
if (args.length == 1) {
separator = ' ';;
list = parse_value_group(args[0], { symbol: separator });
} else {
separator = ',';
list = parse_value_group(args.map(get_value).join(separator), { symbol: separator});
}
let size = list.length - 1;
let result = [list.join(separator)];
// Just ignore the performance
for (let i = 0; i < size; ++i) {
let item = list.shift();
list.push(item);
result.push(list.join(separator));
}
return result;
}
},
mirror() {
return (...args) => {
for (let i = args.length - 1; i >= 0; --i) {
args.push(args[i]);
}
return args;
}
},
Mirror() {
return (...args) => {
for (let i = args.length - 2; i >= 0; --i) {
args.push(args[i]);
}
return args;
}
},
unicode() {
return (...args) => {
return args.map(code => String.fromCharCode(code));
}
},
once({ context, extra, position }) {
let counter = 'once-counter' + position;
return (...args) => {
if (is_nil(context[counter])) {
context[counter] = args;
}
return context[counter];
reverse(...args) {
return commands => {
let parsed = parse_svg_path(commands);
if (!parsed.valid) return commands;
return parsed.commands.reverse().map(({ name, value }) => {
return name + value.join(' ');
}).join(' ');
}
},
@ -706,8 +557,6 @@ const Expose = add_alias({
'depth': 'z',
'rand': 'r',
'pick': 'p',
'pn': 'pl',
'pnr': 'pr',
// error prone
'stripes': 'stripe',
@ -739,8 +588,8 @@ const Expose = add_alias({
'sz': 'Z',
'size-z': 'Z',
'size-depth': 'Z',
'pick-by-turn': 'pl',
'pick-n': 'pl',
'pick-by-turn': 'pn',
'pick-n': 'pn',
'pick-d': 'pd',
'offset': 'plot',
'Offset': 'Plot',

View File

@ -2,12 +2,11 @@ import Func from '../function.js';
import Property from '../property.js';
import Selector from '../selector.js';
import parse_value_group from '../parser/parse-value-group.js';
import calc from '../calc.js';
import { uniform_time } from '../uniforms.js';
import { prefixer } from '../utils/prefixer.js';
import calc from '../calc.js';
import { seedrandom } from '../lib/seedrandom.js';
import { prefixer } from '../utils/prefixer.js';
import { maybe, cell_id, is_nil, get_value, lerp, unique_id } from '../utils/index.js';
import { join, make_array, remove_empty_values } from '../utils/list.js'
@ -23,10 +22,6 @@ function is_special_selector(s) {
return is_host_selector(s) || is_parent_selector(s);
}
function is_pseudo_selecotr(s) {
return /\:before|\:after/.test(s);
}
const MathFunc = {};
for (let name of Object.getOwnPropertyNames(Math)) {
MathFunc[name] = () => (...args) => {
@ -48,7 +43,6 @@ class Rules {
this.grid = null;
this.seed = null;
this.is_grid_defined = false;
this.is_gap_defined = false;
this.coords = [];
this.doodles = {};
this.canvas = {};
@ -57,7 +51,6 @@ class Rules {
this.reset();
this.custom_properties = {};
this.uniforms = {};
this.content = {};
}
reset() {
@ -72,7 +65,6 @@ class Rules {
this.canvas = {};
this.pattern = {};
this.shaders = {};
this.content = {};
for (let key in this.rules) {
if (key.startsWith('#c')) {
delete this.rules[key];
@ -330,29 +322,6 @@ class Rules {
}
}
add_grid_style({ fill, clip, rotate, scale, flexRow, flexColumn }) {
if (fill) {
this.add_rule(':host', `background-color: ${fill};`);
}
if (!clip) {
this.add_rule(':host', 'contain: none;');
}
if (rotate) {
this.add_rule(':container', `rotate: ${rotate};`);
}
if (scale) {
this.add_rule(':container', `scale: ${scale};`);
}
if (flexRow) {
this.add_rule(':container', `display: flex`);
this.add_rule('cell', `flex: 1`);
}
if (flexColumn) {
this.add_rule(':container', `display: flex; flex-direction: column;`);
this.add_rule('cell', `flex: 1`);
}
}
compose_rule(token, _coords, selector) {
let coords = Object.assign({}, _coords);
let prop = token.property;
@ -431,11 +400,7 @@ class Rules {
}
}
let is_image = (
/^(background|background\-image)$/.test(prop) &&
/\$\{(canvas|shader|pattern)/.test(value)
);
if (is_image) {
if (prop === 'background' && (value.includes('shader') || value.includes('canvas') || value.includes('pattern'))) {
rule += 'background-size: 100% 100%;';
}
@ -465,7 +430,6 @@ class Rules {
case 'grid': {
if (is_host_selector(selector)) {
rule = transformed.size || '';
this.add_grid_style(transformed);
} else {
rule = '';
if (!this.is_grid_defined) {
@ -475,27 +439,12 @@ class Rules {
max_grid: coords.max_grid
});
this.add_rule(':host', transformed.size || '');
this.add_grid_style(transformed);
}
}
this.grid = coords.grid;
this.is_grid_defined = true;
break;
}
case 'gap': {
rule = '';
if (!this.is_gap_defined) {
this.add_rule(':container', `gap: ${transformed};`);
this.is_gap_defined = true;
}
break;
}
case 'content': {
rule = '';
if (transformed !== undefined && !is_pseudo_selecotr(selector) && !is_parent_selector(selector)) {
this.content[this.compose_selector(coords)] = transformed;
}
}
case 'seed': {
rule = '';
break;
@ -582,9 +531,7 @@ class Rules {
}
}
});
if (is_nil(this.seed)) {
this.seed = coords.seed_value;
} else {
if (!is_nil(this.seed)) {
coords.update_random(this.seed);
}
}
@ -726,7 +673,6 @@ class Rules {
canvas: this.canvas,
pattern: this.pattern,
uniforms: this.uniforms,
content: this.content,
}
}
@ -770,7 +716,6 @@ function generate_css(tokens, grid_size, seed_value, max_grid, seed_random) {
grid: { x: 1, y: 1, z: 1, count: 1 },
random, rand, pick, shuffle,
max_grid, update_random,
seed_value,
});
let { grid, seed } = rules.output();

View File

@ -7,10 +7,7 @@ function generate(token, last) {
} else {
result += token.name + (isInline ? ' ' : '{');
}
if (token.name === 'style') {
result += token.value;
}
else if (Array.isArray(token.value) && token.value.length) {
if (Array.isArray(token.value) && token.value.length) {
let lastGroup = '';
for (let t of token.value) {
result += generate(t, lastGroup);;

View File

@ -49,12 +49,11 @@ class Tag {
}
toString() {
if (this.isTextNode()) {
return removeQuotes(this.body);
return this.body;
}
let attrs = [''];
let body = [];
for (let [name, value] of Object.entries(this.attrs)) {
value = removeQuotes(value);
attrs.push(`${name}="${value}"`);
}
for (let tag of this.body) {
@ -68,27 +67,11 @@ function composeStyleRule(name, value) {
return `${name}:${value};`
}
function removeQuotes(text) {
text = String(text);
let double = text.startsWith('"') && text.endsWith('"');
let single = text.startsWith("'") && text.endsWith("'");
if (double || single) {
return text.substring(1, text.length - 1);
}
return text;
}
function transformViewBox(token) {
let viewBox = token.detail.value;
let p = token.detail.padding || token.detail.expand;
if (!viewBox.length) {
return '';
}
let [x, y, w, h] = viewBox;
if (p) {
[x, y, w, h] = [x-p, x-p, w+p*2, h+p*2];
}
return `${x} ${y} ${w} ${h}`;
function composeStyle(block) {
const style = block.value
.map(n => (n.type === 'block') ? composeStyle(n) : composeStyleRule(n.name, n.value))
.join('');
return `${block.name}{${style}}`;
}
function generate(token, element, parent, root) {
@ -99,9 +82,17 @@ function generate(token, element, parent, root) {
if (token.type === 'block') {
// style tag
if (token.name === 'style') {
let el = new Tag('style');
el.append(token.value);
element.append(el);
if (Array.isArray(token.value)) {
let el = new Tag('style');
let styles = [];
for (let block of token.value) {
if (block.type === 'block') {
styles.push(composeStyle(block));
}
}
el.append(styles.join(''));
element.append(el);
}
}
// normal svg elements
else {
@ -132,8 +123,9 @@ function generate(token, element, parent, root) {
}
}
}
if (token.type === 'statement' && !token.variable) {
if (token.name === 'content') {
if (token.type === 'statement') {
let isTextNode = parent && /^(text|tspan|textPath|title|desc)$/i.test(parent.name);
if (isTextNode && token.name === 'content') {
let text = new Tag('text-node', token.value);
element.append(text);
}
@ -155,14 +147,7 @@ function generate(token, element, parent, root) {
value = `#${id}`;
}
}
if (/viewBox/i.test(token.name)) {
value = transformViewBox(token, value);
if (value) {
element.attr(token.name, value);
}
} else {
element.attr(token.name, value);
}
element.attr(token.name, value);
if (token.name.includes('xlink:')) {
root.attr('xmlns:xlink', NSXLink);
}

View File

@ -58,42 +58,44 @@ if (typeof customElements !== 'undefined') {
update(styles) {
this.cleanup();
// Use old rules to update
if (!styles) {
styles = un_entity(this.innerHTML);
}
if (this.innerHTML !== styles) {
this.innerHTML = styles;
}
let use = this.get_use();
if (!styles) styles = un_entity(this.innerHTML);
this.innerHTML = styles;
if (!this.grid_size) {
this.grid_size = this.get_grid();
}
const { x: gx, y: gy, z: gz } = this.grid_size;
const use = this.get_use();
let { x: gx, y: gy, z: gz } = this.grid_size;
let old_content = '';
if (this.compiled) {
old_content = this.compiled.content;
}
const compiled = this.generate(parse_css(use + styles, this.extra));
let grid = compiled.grid || this.get_grid();
let { x, y, z } = grid;
let should_rebuild = (
!this.shadowRoot.innerHTML
|| (gx !== x || gy !== y || gz !== z)
|| (JSON.stringify(old_content) !== JSON.stringify(compiled.content))
const compiled = this.generate(
parse_css(use + styles, this.extra)
);
Object.assign(this.grid_size, grid);
if (!this.shadowRoot.innerHTML) {
Object.assign(this.grid_size, compiled.grid);
return this.build_grid(compiled, compiled.grid);
}
if (should_rebuild) {
return compiled.grid
? this.build_grid(compiled, grid)
: this.build_grid(this.generate(parse_css(use + styles, this.extra)), grid);
if (compiled.grid) {
let { x, y, z } = compiled.grid;
if (gx !== x || gy !== y || gz !== z) {
Object.assign(this.grid_size, compiled.grid);
return this.build_grid(compiled, compiled.grid);
}
Object.assign(this.grid_size, compiled.grid);
}
else {
let grid = this.get_grid();
let { x, y, z } = grid;
if (gx !== x || gy !== y || gz !== z) {
Object.assign(this.grid_size, grid);
return this.build_grid(
this.generate(parse_css(use + styles, this.extra)),
grid
);
}
}
let replace = this.replace(compiled);
@ -194,7 +196,7 @@ if (typeof customElements !== 'undefined') {
const { keyframes, host, container, cells } = compiled.styles;
let replace = this.replace(compiled);
let grid_container = create_grid(grid, compiled.content);
let grid_container = create_grid(grid);
let size = (options && options.width && options.height)
? `width="${ options.width }" height="${ options.height }"`
@ -389,7 +391,7 @@ if (typeof customElements !== 'undefined') {
let style_container = get_grid_styles(grid) + host + container;
let style_cells = has_delay ? '' : cells;
const { uniforms, content } = compiled;
const { uniforms } = compiled;
let replace = this.replace(compiled);
@ -399,7 +401,7 @@ if (typeof customElements !== 'undefined') {
<style class="style-container">${ style_container }</style>
<style class="style-cells">${ style_cells }</style>
<svg id="defs" xmlns="http://www.w3.org/2000/svg" style="width:0;height:0"></svg>
${ create_grid(grid, content) }
${ create_grid(grid) }
`;
this.set_content('.style-container', replace(style_container));
@ -586,14 +588,13 @@ function get_basic_styles() {
return `
*, *::after, *::before {
box-sizing: border-box;
animation-play-state: var(--cssd-animation-play-state) !important
animation-play-state: var(--cssd-animation-play-state) !important;
}
:host, .host {
display: block;
visibility: visible;
width: auto;
height: auto;
contain: content;
--${ uniform_time.name }: 0
}
:host([hidden]), .host[hidden] {
@ -606,19 +607,20 @@ function get_basic_styles() {
display: grid;
${ inherited_grid_props }
}
cell {
cell:empty {
position: relative;
line-height: 1;
display: grid;
place-items: center
}
svg {
position: absolute;
width: 100%;
height: 100%
height: 100%;
}
:host([cssd-paused-animation]) {
--cssd-animation-play-state: paused;
animation-play-state: paused !important
animation-play-state: paused !important;
}
`;
}
@ -633,44 +635,41 @@ function get_grid_styles(grid_obj) {
`;
}
function get_content(input) {
return is_nil(input) ? '' : input;
function create_cell(x, y, z) {
let cell = document.createElement('cell');
cell.id = cell_id(x, y, z);
return cell;
}
function create_cell(x, y, z, content, child = '') {
let id = cell_id(x, y, z);
let head = get_content(content['#' + id]);
let tail = get_content(child);
return `<cell id="${id}">${head}${tail}</cell>`;
}
function create_grid(grid_obj, content) {
function create_grid(grid_obj) {
let { x, y, z } = grid_obj || {};
let result = '';
let grid = document.createElement('grid');
let root = document.createDocumentFragment();
if (z == 1) {
for (let j = 1; j <= y; ++j) {
for (let i = 1; i <= x; ++i) {
result += create_cell(i, j, 1, content);
root.appendChild(create_cell(i, j, 1));
}
}
}
else {
let child = '';
for (let i = z; i >= 1; i--) {
let cell = create_cell(1, 1, i, content, child);
child = cell;
let temp = null;
for (let i = 1; i <= z; ++i) {
let cell = create_cell(1, 1, i);
(temp || root).appendChild(cell);
temp = cell;
}
result = child;
temp = null;
}
return `<grid class="container">${result}</grid>`;
grid.className = 'container';
grid.appendChild(root);
return grid.outerHTML;
}
export default make_tag_function(rules => {
if (typeof document !== 'undefined') {
let doodle = document.createElement('css-doodle');
if (doodle.update) {
doodle.update(rules);
}
return doodle;
let doodle = document.createElement('css-doodle');
if (doodle.update) {
doodle.update(rules);
}
return doodle;
});

View File

@ -265,14 +265,9 @@ function read_arguments(it, composition, doodle) {
let raw = '';
while (!it.end()) {
c = it.curr();
let prev = it.curr(-1);
let next = it.curr(1);
let start = it.index();
if ((/[\('"`]/.test(c) && prev !== '\\')) {
if ((/[\('"`]/.test(c) && it.curr(-1) !== '\\')) {
if (stack.length) {
if ((c !== '(') && last(stack) === '(') {
stack.pop();
}
if (c != '(' && c === last(stack)) {
stack.pop();
} else {
@ -283,7 +278,7 @@ function read_arguments(it, composition, doodle) {
}
arg += c;
}
else if ((c == '@' || (prev === '.' && composition)) && !doodle) {
else if (c == '@' && !doodle) {
if (!group.length) {
arg = arg.trimLeft();
}
@ -295,7 +290,7 @@ function read_arguments(it, composition, doodle) {
}
else if (doodle && /[)]/.test(c) || (!doodle && /[,)]/.test(c))) {
if (stack.length) {
if (c == ')' && last(stack) === '(') {
if (c == ')') {
stack.pop();
}
arg += c;
@ -329,7 +324,7 @@ function read_arguments(it, composition, doodle) {
}
arg += c;
}
if (composition && ((next == ')' || next == ';') || !/[0-9a-zA-Z_\-.]/.test(it.curr())) && !stack.length) {
if (composition && (it.curr(1) == ')' || !/[0-9a-zA-Z_\-.]/.test(it.curr())) && !stack.length) {
if (group.length) {
args.push(normalize_argument(group));
}
@ -382,14 +377,14 @@ function normalize_argument(group) {
function seperate_func_name(name) {
let fname = '', extra = '';
if ((/\D$/.test(name) && !/\d+[x-]\d+/.test(name)) || Math[name.substr(1)]) {
if ((/\D$/.test(name) && !/\d+x\d+/.test(name)) || Math[name.substr(1)]) {
return { fname: name, extra }
}
for (let i = name.length - 1; i >= 0; i--) {
let c = name[i];
let prev = name[i - 1];
let next = name[i + 1];
if (/[\d.]/.test(c) || ((c == 'x' || c == '-') && /\d/.test(prev) && /\d/.test(next))) {
if (/[\d.]/.test(c) || ((c == 'x') && /\d/.test(prev) && /\d/.test(next))) {
extra = c + extra;
} else {
fname = name.substring(0, i + 1);
@ -404,28 +399,21 @@ function has_times_syntax(token) {
return str.includes('pureName') && str.includes('times');
}
function is_svg(name) {
return /^@svg$/i.test(name);
}
function read_func(it) {
let func = Tokens.func();
let name = it.curr(), c;
let name = '@', c;
let has_argument = false;
if (name === '@') {
it.next();
} else {
name = '@';
}
it.next();
while (!it.end()) {
c = it.curr();
let composition = (c == '.' && it.curr(1) == '@');
let next = it.curr(1);
let composition = (c == '.' && (next == '@' || /[a-zA-Z]/.test(next)));
if (c == '(' || composition) {
has_argument = true;
it.next();
let [args, raw_args] = read_arguments(it, composition, composible(name));
if (is_svg(name) && /\d\s*{/.test(raw_args)) {
if (name === '@svg' && /\d\s*{/.test(raw_args)) {
let parsed_svg = parse_svg(raw_args);
if (has_times_syntax(parsed_svg)) {
let svg = generate_svg_extended(parsed_svg);
@ -437,14 +425,16 @@ function read_func(it) {
}
func.arguments = args;
break;
} else if (/[0-9a-zA-Z_\-.]/.test(c)) {
} else if (!has_argument && next !== '(' && !/[0-9a-zA-Z_\-.]/.test(next)) {
name += c;
}
if (!has_argument && next !== '(' && !/[0-9a-zA-Z_\-.]/.test(next)) {
break;
}
else {
name += c;
}
it.next();
}
let { fname, extra } = seperate_func_name(name);
func.name = fname;
@ -461,9 +451,8 @@ function read_func(it) {
function read_value(it) {
let text = Tokens.text(), idx = 0, skip = true, c;
const value = [];
const value = [], stack = [];
value[idx] = [];
let stack = [], quote_stack = [];
while (!it.end()) {
c = it.curr();
@ -486,29 +475,20 @@ function read_value(it) {
value[++idx] = [];
skip = true;
}
else if (/[;}<]/.test(c) && !quote_stack.length) {
else if (/[;}<]/.test(c)) {
if (text.value.length) {
value[idx].push(text);
text = Tokens.text();
}
break;
}
else if (c == '@' && /\w/.test(it.curr(1))) {
else if (c == '@') {
if (text.value.length) {
value[idx].push(text);
text = Tokens.text();
}
value[idx].push(read_func(it));
}
else if (c === '"' || c === "'") {
let quote = last(quote_stack);
if (c === quote) {
quote_stack.pop();
} else if (!quote_stack.length) {
quote_stack.push(c);
}
text.value += c;
}
else if (!is.white_space(c) || !is.white_space(it.curr(-1))) {
if (c == '(') stack.push(c);
if (c == ')') stack.pop();
@ -516,11 +496,9 @@ function read_value(it) {
if (symbols[c] && !/[0-9]/.test(it.curr(-1))) {
c = symbols[c];
}
text.value += c;
}
if (it.curr() === ';' || it.curr() == '}') {
break;
}
it.next();
}
if (text.value.length) {

View File

@ -8,19 +8,19 @@ function readStatement(iter, token) {
let stackParen = [];
while (iter.next()) {
let { curr, next } = iter.get();
if (curr.isSymbol('(') && !stackQuote.length) {
let isStatementBreak = !stackQuote.length && !stackParen.length && (!next || curr.isSymbol(';') || next.isSymbol('}'));
if (curr.isSymbol('(')) {
stackParen.push(curr);
} else if (curr.isSymbol(')') && !stackQuote.length) {
} else if (curr.isSymbol(')')) {
stackParen.pop();
}
let isStatementBreak = !stackQuote.length && !stackParen.length && (!next || curr.isSymbol(';') || next.isSymbol('}'));
if (curr.isSymbol("'", '"')) {
if (curr.status === 'open') {
stackQuote.push(curr);
} else {
stackQuote.pop();
}
if ((next && next.isSymbol('}')) && !stackQuote.length) {
if (next.isSymbol('}') && !stackQuote.length) {
isStatementBreak = true;
}
}
@ -47,13 +47,18 @@ function readStatement(iter, token) {
}
break;
}
fragment.push(curr);
// skip quotes
let skip = (curr.status == 'open' && stackQuote.length == 1)
|| (curr.status == 'close' && !stackQuote.length);
if (!skip) {
fragment.push(curr);
}
if (isStatementBreak) {
break;
}
}
if (fragment.length && !inlineBlock) {
token._valueTokens = fragment;
token.value = joinToken(fragment);
} else if (inlineBlock) {
token.value = inlineBlock;
@ -61,26 +66,7 @@ function readStatement(iter, token) {
if (token.origin) {
token.origin.value = token.value;
}
return token;
}
function readStyle(iter) {
let stack = [];
let style = [];
while (iter.next()) {
let { curr } = iter.get();
if (curr.isSymbol('{')) {
stack.push(curr.value);
} else if (curr.isSymbol('}')) {
if (stack.length) {
stack.pop();
} else {
break;
}
}
style.push(curr.value);
}
return style.join('');
return token
}
function walk(iter, parentToken) {
@ -91,13 +77,13 @@ function walk(iter, parentToken) {
while (iter.next()) {
let { prev, curr, next } = iter.get();
let isBlockBreak = !next || curr.isSymbol('}');
if (curr.isSymbol('(')) {
stack.push(curr.value);
}
if (curr.isSymbol(')')) {
stack.pop();
}
let isBlockBreak = !next || curr.isSymbol('}');
if (isBlock(tokenType) && isBlockBreak) {
if (!next && rules.length && !curr.isSymbol('}')) {
let last = rules[rules.length - 1].value;
@ -118,29 +104,19 @@ function walk(iter, parentToken) {
}
let tokenName = selectors.pop();
let skip = isSkip(...selectors, parentToken.name, tokenName);
if (tokenName === 'style') {
rules.push({
let block = resolveId(walk(iter, splitTimes(tokenName, {
type: 'block',
name: tokenName,
value: []
})), skip);
while (tokenName = selectors.pop()) {
block = resolveId(splitTimes(tokenName, {
type: 'block',
name: tokenName,
value: readStyle(iter)
});
} else {
let block = resolveId(walk(iter, splitTimes(tokenName, {
type: 'block',
name: tokenName,
value: []
})), skip);
while (tokenName = selectors.pop()) {
block = resolveId(splitTimes(tokenName, {
type: 'block',
name: tokenName,
value: [block]
}), skip);
}
rules.push(block);
value: [block]
}), skip);
}
rules.push(block);
fragment = [];
}
else if (
@ -161,21 +137,15 @@ function walk(iter, parentToken) {
};
}
let statement = readStatement(iter, intial);
let groupdValue = parseValueGroup(statement.value);
let expand = (props.length > 1 && groupdValue.length === props.length);
props.forEach((prop, i) => {
let item = Object.assign({}, statement, { name: prop });
if (/^\-\-/.test(prop)) {
item.variable = true;
}
if (expand) {
item.value = groupdValue[i];
}
if (/viewBox/i.test(prop)) {
item.detail = parseViewBox(item.value, item._valueTokens);
}
delete item._valueTokens;
rules.push(item);
});
if (isBlock(tokenType)) {
@ -280,30 +250,6 @@ function getSelectors(tokens) {
return result;
}
function parseViewBox(value, tokens) {
const viewBox = { value: [] };
let temp;
if (!Array.isArray(tokens)) {
return viewBox;
}
for (let token of tokens) {
if (token.isSpace() || token.isSymbol(',', ';')) {
continue;
}
if (viewBox.value.length < 4 && token.isNumber()) {
viewBox.value.push(Number(token.value));
}
else if (token.isNumber() && temp) {
viewBox[temp] = Number(token.value);
temp = null;
}
else if (token.isWord()) {
temp = token.value;
}
}
return viewBox;
}
function splitTimes(name, object) {
let target = Object.assign({}, object);
if (/\*\s*[0-9]/.test(name)) {
@ -325,20 +271,12 @@ function isBlock(type) {
}
function skipHeadSVG(block) {
let headSVG, headVariables = [];
for (let item of block.value) {
if (item.name === 'svg') {
headSVG = item;
}
if (item.variable) {
headVariables.push(item);
}
let head = block && block.value && block.value[0];
if (head && head.name === 'svg' && isBlock(head.type)) {
return skipHeadSVG(head);
} else {
return block;
}
if (headSVG) {
headSVG.value.push(...headVariables);
return headSVG;
}
return block;
}
function parse(source, root) {

View File

@ -1,13 +1,12 @@
import { is_empty } from '../utils/index.js';
import { scan, iterator } from './tokenizer.js';
function parse(input, option = {symbol: ',', noSpace: false, verbose: false }) {
function parse(input, option = {symbol: ',', noSpace: false}) {
let group = [];
let skip = false;
let tokens = [];
let parenStack = [];
let quoteStack = [];
let lastGroupName = '';
if (is_empty(input)) {
return group;
@ -16,25 +15,11 @@ function parse(input, option = {symbol: ',', noSpace: false, verbose: false }) {
let iter = iterator(scan(input));
function isSeperator(token) {
let symbol = option.symbol || [','];
if (!Array.isArray(symbol)) {
symbol = [symbol];
}
let symbol = option.symbol || ',';
if (option.noSpace) {
return token.isSymbol(...symbol);
}
return token.isSymbol(...symbol) || token.isSpace();
}
function addGroup(tokens) {
let value = joinTokens(tokens);
if (option.verbose) {
if (lastGroupName.length || value.length) {
group.push({ group: lastGroupName, value });
}
} else {
group.push(value);
return token.isSymbol(symbol);
}
return token.isSymbol(symbol) || token.isSpace();
}
while (iter.next()) {
@ -58,9 +43,7 @@ function parse(input, option = {symbol: ',', noSpace: false, verbose: false }) {
if (isNextSpace || isPrevSpace) continue;
}
if (emptyStack && isSeperator(curr)) {
let groupName = lastGroupName;
addGroup(tokens);
lastGroupName = curr.value;
group.push(joinTokens(tokens));
tokens = [];
} else {
tokens.push(curr);
@ -68,7 +51,7 @@ function parse(input, option = {symbol: ',', noSpace: false, verbose: false }) {
}
if (tokens.length) {
addGroup(tokens);
group.push(joinTokens(tokens));
}
return group;

View File

@ -7,7 +7,6 @@ const symbols = [
':', ';', ',', '(', ')', '[', ']',
'{', '}', 'π', '±', '+', '-', '*',
'/', '%', '"', "'", '`', '@', '=',
'^',
];
const is = {

View File

@ -23,7 +23,7 @@ const map_top_bottom = {
export default add_alias({
size(value, { is_special_selector, grid }) {
let [w, h = w, ratio] = parse_value_group(value);
let [w, h = w] = parse_value_group(value);
if (is_preset(w)) {
[w, h] = get_preset(w, h);
}
@ -31,22 +31,11 @@ export default add_alias({
width: ${ w };
height: ${ h };
`;
if (w === 'auto' || h === 'auto') {
if (ratio) {
if (/^\(.+\)$/.test(ratio)) {
ratio = ratio.substring(1, ratio.length - 1);
} else if (!/^calc/.test(ratio)) {
ratio = `calc(${ratio})`;
}
if (!is_special_selector) {
styles += `aspect-ratio: ${ ratio };`;
}
if (is_special_selector) {
if (w === 'auto' || h === 'auto') {
styles += `aspect-ratio: ${ grid.ratio };`;
}
if (is_special_selector) {
styles += `aspect-ratio: ${ ratio || grid.ratio };`;
}
}
if (!is_special_selector) {
} else {
styles += `
--internal-cell-width: ${ w };
--internal-cell-height: ${ h };
@ -55,7 +44,7 @@ export default add_alias({
return styles;
},
place(value, { extra }) {
position(value, { extra }) {
let [left, top = '50%'] = parse_value_group(value);
left = map_left_right[left] || left;
top = map_top_bottom[top] || top;
@ -71,45 +60,16 @@ export default add_alias({
margin-top: calc(${ ch } / -2);
grid-area: unset;
--plot-angle: ${ extra || 0 };
rotate: ${ extra || 0 }deg;
transform: rotate(${ extra || 0 }deg);
`;
},
grid(value, options) {
let result = {
clip: true,
let [grid, size] = parse_value_group(value, { symbol: '/', noSpace: true });
return {
grid: parse_grid(grid, options.max_grid),
size: size ? this.size(size, options) : ''
};
if (/no\-*clip/i.test(value)) {
result.clip = false;
value = value.replace(/no\-*clip/i, '');
}
let groups = parse_value_group(value, {
symbol: ['/', '+', '*', '|', '-'],
noSpace: true,
verbose: true
});
for (let { group, value } of groups) {
if (group === '+') result.scale = value;
if (group === '*') result.rotate = value;
if (group === '/') {
if (result.size === undefined) result.size = this.size(value, options);
else result.fill = value;
}
if ((group === '|' || group == '-' || group == '') && !result.grid) {
result.grid = parse_grid(value, options.max_grid);
if (group === '|') {
result.flexColumn = true;
}
if (group === '-') {
result.flexRow = true;
}
}
}
return result;
},
gap(value) {
return value;
},
seed(value) {
@ -131,13 +91,11 @@ export default add_alias({
}
},
content(value) {
return value;
},
}, {
'place': 'position',
// legacy names.
'place-cell': 'place',
'offset': 'place',
'position': 'place',
'place-cell': 'position',
'offset': 'position',
});

View File

@ -19,7 +19,7 @@ function range(start, stop, step) {
|| (step < 0 && start > stop)) {
range.push(start);
start += step;
if (count++ >= 65535) break;
if (count++ >= 1000) break;
}
if (!range.length) range.push(old);
return range;
@ -57,43 +57,17 @@ function lazy(fn) {
}
function sequence(count, fn) {
let [x, y = 1] = String(count).split(/[x-]/);
let [cx, cy] = [Math.ceil(x), Math.ceil(y)];
if (is_invalid_number(cx)) cx = 1;
if (is_invalid_number(cy)) cy = 1;
x = clamp(cx, 0, 65536);
y = clamp(cy, 0, 65536);
let [x, y = 1] = String(count).split('x');
x = clamp(Math.ceil(x) || 1, 1, 65536);
y = clamp(Math.ceil(y) || 1, 1, 65536);
let max = x * y;
let ret = [];
let index = 1;
if (/x/.test(count)) {
for (let i = 1; i <= y; ++i) {
for (let j = 1; j <= x; ++j) {
ret.push(fn(index++, j, i, max, x, y, index));
}
for (let i = 1; i <= y; ++i) {
for (let j = 1; j <= x; ++j) {
ret.push(fn(index++, j, i, max, x, y));
}
}
else if (/-/.test(count)) {
max = Math.abs(x - y) + 1;
if (x <= y) {
for (let i = x; i <= y; ++i) {
ret.push(fn(i, i, 1, max, max, 1, index++));
}
} else {
for (let i = x; i >= y; --i) {
ret.push(fn(i, i, 1, max, max, 1, index++));
}
}
}
else {
for (let i = 1; i <= x; ++i) {
ret.push(fn(i, i, 1, x, x, 1, index++));
}
}
return ret;
}

View File

@ -130,30 +130,6 @@ test('multiple content', t => {
);
});
test('remove quotes around text', t => {
compare(t,
`text {
content: "hello";
}`,
trim(`
<svg xmlns="http://www.w3.org/2000/svg">
<text>hello</text>
</svg>
`)
);
compare(t,
`text {
content: 'hello';
}`,
trim(`
<svg xmlns="http://www.w3.org/2000/svg">
<text>hello</text>
</svg>
`)
);
});
test('style tag', t => {
compare(t,
`svg {
@ -162,8 +138,6 @@ test('style tag', t => {
circle {
fill: red;
}
circle:nth-child(1) {
}
}
}`,
trim(`
@ -171,7 +145,6 @@ test('style tag', t => {
<circle></circle>
<style>
circle{fill:red;}
circle:nth-child(1){}
</style>
</svg>
`)
@ -286,28 +259,3 @@ test('do not group elements for empty id', t => {
`)
);
});
test('Normalize quoted attribute values', t => {
compare(t,
`circle {
name: "hello";
}
`,
trim(`
<svg xmlns="http://www.w3.org/2000/svg">
<circle name="hello"></circle>
</svg>
`)
);
compare(t,
`circle {
name: 'hello';
}
`,
trim(`
<svg xmlns="http://www.w3.org/2000/svg">
<circle name="hello"></circle>
</svg>
`)
);
});

View File

@ -88,6 +88,7 @@ test('edge cases', t => {
});
test('statement', t => {
compare(t, 'viewBox: 0 0 0 10', {
@ -96,24 +97,7 @@ test('statement', t => {
value: [{
type: 'statement',
name: 'viewBox',
value: '0 0 0 10',
detail: {
value: [0, 0, 0, 10]
}
}]
});
compare(t, 'viewBox: 0 0 10 10 padding .2', {
name: 'svg',
type: 'block',
value: [{
type: 'statement',
name: 'viewBox',
value: '0 0 10 10 padding .2',
detail: {
value: [0, 0, 10, 10],
padding: .2
}
value: '0 0 0 10'
}]
});
@ -132,6 +116,7 @@ test('statement', t => {
});
test('group property', t => {
compare(t, 'cx, cy: 5', {
name: 'svg',
@ -150,8 +135,10 @@ test('group property', t => {
{ type: 'statement', origin: { name: ['cx', 'cy'], value: '5 6' }, name: 'cy', value: '6'},
]
});
});
test('semicolon separated values', t => {
compare(t, 'values: 60; 100; 180', {
name: 'svg',
@ -171,6 +158,7 @@ test('semicolon separated values', t => {
});
});
test('colon separated properties', t => {
compare(t, 'xlink:href: url(#app)', {
name: 'svg',
@ -189,6 +177,7 @@ test('colon separated properties', t => {
});
});
test('block names', t => {
compare(t, 'g circle { } ', {
name: 'svg',
@ -241,6 +230,7 @@ test('block names', t => {
}
]
});
});
test('id expand', t => {
@ -282,6 +272,7 @@ test('id expand', t => {
]
}]
});
});
test('empty id expand', t => {
@ -321,7 +312,7 @@ test('statement end on quotes', t => {
value: [{
name: 'content',
type: 'statement',
value: '\'\''
value: ''
}]
}, {
name: 'g',
@ -331,24 +322,6 @@ test('statement end on quotes', t => {
});
});
test('content values', t => {
compare(t, `
text { content: "world;}" }
`, {
type: 'block',
name: 'svg',
value: [{
type: 'block',
name: 'text',
value: [{
name: 'content',
type: 'statement',
value: '"world;}"'
}]
}]
});
});
test('times syntax', t => {
compare(t, `
circle*10 {}
@ -377,6 +350,8 @@ test('times syntax', t => {
value: []
}]
});
});
test('complex values with parens', t => {
@ -398,27 +373,3 @@ test('complex values with parens', t => {
}]
});
});
test('svg variable', t => {
compare(t, '--a: 1', {
name: 'svg',
type: 'block',
value: [{
type: 'statement',
name: '--a',
value: '1',
variable: true
}]
});
compare(t, '--a: 1; svg {}', {
name: 'svg',
type: 'block',
value: [{
type: 'statement',
name: '--a',
value: '1',
variable: true
}]
});
});

View File

@ -71,29 +71,3 @@ test('grid value', t => {
});
test('space as separator', t => {
compare.use(input => {
return parseValueGroup(input, { symbol: ' ' });
});
compare(t, '5 100%', ['5', '100%']);
compare(t, '5,100%', ['5,100%']);
compare(t, '5, 100% 5', ['5,100%', '5']);
compare(t, '5, 100% 5 8', ['5,100%', '5', '8']);
});
test('verbose option', t => {
compare.use(input => {
return parseValueGroup(input, { symbol: ['v', 'h'], noSpace: true, verbose: true });
});
compare(t, 'v 10 h -10 v 5', [
{ group: 'v', value: '10' },
{ group: 'h', value: '-10' },
{ group: 'v', value: '5' },
]);
});