cellery 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cells.js +85 -2
- package/lib/template.js +29 -7
- package/package.json +4 -3
package/lib/cells.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { parse, walk, generate } = require('css-tree/dist/csstree.esm')
|
|
2
|
+
|
|
1
3
|
class Cell {
|
|
2
4
|
constructor(opts = {}) {
|
|
3
5
|
this.id = opts.id
|
|
@@ -10,6 +12,7 @@ class Cell {
|
|
|
10
12
|
this.decoration = opts.decoration
|
|
11
13
|
this.size = opts.size
|
|
12
14
|
this.onclick = opts.onclick
|
|
15
|
+
this.style = opts.style
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
static Styled(styledOpts = {}) {
|
|
@@ -64,6 +67,83 @@ class Cell {
|
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
|
|
70
|
+
class Style {
|
|
71
|
+
constructor(opts = {}) {
|
|
72
|
+
this.content = parse(opts.children?.join('\n'))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
findPropertyOfCell(name, property) {
|
|
76
|
+
return this.findProperty(`[data-cellery-cell="${name}"]`, property)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
findProperty(selector, property) {
|
|
80
|
+
let value = null
|
|
81
|
+
|
|
82
|
+
walk(this.content, {
|
|
83
|
+
visit: 'Rule',
|
|
84
|
+
enter(rule) {
|
|
85
|
+
const prelude = generate(rule.prelude)
|
|
86
|
+
if (prelude !== selector) return
|
|
87
|
+
|
|
88
|
+
rule.block.children.forEach((decl) => {
|
|
89
|
+
if (decl.type === 'Declaration' && decl.property === property) {
|
|
90
|
+
value = generate(decl.value)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
return value
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
addScope(target, parent) {
|
|
100
|
+
walk(this.content, {
|
|
101
|
+
visit: 'Rule',
|
|
102
|
+
enter(rule) {
|
|
103
|
+
rule.prelude.children.forEach((selector) => {
|
|
104
|
+
const str = generate(selector)
|
|
105
|
+
if (!str.startsWith(target)) return
|
|
106
|
+
|
|
107
|
+
const items = [...selector.children]
|
|
108
|
+
let inserted = false
|
|
109
|
+
for (let i = 0; i < items.length; i++) {
|
|
110
|
+
const node = items[i]
|
|
111
|
+
if (node.type === 'PseudoClassSelector' || node.type === 'PseudoElementSelector') {
|
|
112
|
+
selector.children.insertData({ type: 'IdSelector', name: parent }, items[i])
|
|
113
|
+
inserted = true
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!inserted) {
|
|
118
|
+
selector.children.appendData({ type: 'IdSelector', name: parent })
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
class StyleHTML extends Style {
|
|
127
|
+
constructor(opts = {}) {
|
|
128
|
+
super(opts)
|
|
129
|
+
|
|
130
|
+
const cellNames = new Set(Object.keys(opts.cells))
|
|
131
|
+
|
|
132
|
+
walk(this.content, {
|
|
133
|
+
visit: 'TypeSelector',
|
|
134
|
+
enter(node) {
|
|
135
|
+
if (cellNames.has(node.name)) {
|
|
136
|
+
node.name = `[data-cellery-cell="${node.name}"]`
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
toCSS() {
|
|
143
|
+
return generate(this.content)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
67
147
|
class Container extends Cell {
|
|
68
148
|
// TODO: replace with classes
|
|
69
149
|
static ScrollAll = 'all'
|
|
@@ -89,7 +169,7 @@ class App extends Cell {
|
|
|
89
169
|
class Text extends Cell {
|
|
90
170
|
constructor(opts = {}) {
|
|
91
171
|
super(opts)
|
|
92
|
-
this.value = opts.value || ''
|
|
172
|
+
this.value = opts.value || this.children.filter((c) => typeof c === 'string').join('') || ''
|
|
93
173
|
}
|
|
94
174
|
}
|
|
95
175
|
|
|
@@ -114,5 +194,8 @@ module.exports = {
|
|
|
114
194
|
App,
|
|
115
195
|
Text,
|
|
116
196
|
Paragraph,
|
|
117
|
-
Input
|
|
197
|
+
Input,
|
|
198
|
+
|
|
199
|
+
Style,
|
|
200
|
+
StyleHTML
|
|
118
201
|
}
|
package/lib/template.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const { Cell, Container, App, Text, Paragraph, Input } = require('./cells')
|
|
1
|
+
const { Cell, Container, App, Text, Paragraph, Input, StyleHTML, Style } = require('./cells')
|
|
2
2
|
|
|
3
3
|
const SENTINEL = '\x00'
|
|
4
4
|
|
|
5
|
-
const registry = { Cell, Container, App, Text, Paragraph, Input }
|
|
5
|
+
const registry = { Cell, Container, App, Text, Paragraph, Input, 'Style.HTML': StyleHTML }
|
|
6
6
|
|
|
7
7
|
function register(cells) {
|
|
8
8
|
Object.assign(registry, cells)
|
|
@@ -44,10 +44,18 @@ function parse(input, slots) {
|
|
|
44
44
|
while (!eof() && /\s/.test(peek())) advance()
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
const SLOT_RE = new RegExp(SENTINEL + '(\\d+)' + SENTINEL, 'g')
|
|
48
|
+
const SLOT_PURE = new RegExp('^' + SENTINEL + '(\\d+)' + SENTINEL + '$')
|
|
49
|
+
|
|
47
50
|
function resolveValue(str) {
|
|
48
51
|
str = str.trim()
|
|
49
|
-
|
|
52
|
+
// Pure placeholder — preserve type
|
|
53
|
+
const m = str.match(SLOT_PURE)
|
|
50
54
|
if (m) return slots[parseInt(m[1])]
|
|
55
|
+
// Mixed content — inline replace as strings
|
|
56
|
+
if (str.includes(SENTINEL)) {
|
|
57
|
+
return str.replace(SLOT_RE, (_, id) => String(slots[parseInt(id)]))
|
|
58
|
+
}
|
|
51
59
|
if (str === 'true') return true
|
|
52
60
|
if (str === 'false') return false
|
|
53
61
|
if (str !== '' && !isNaN(str)) return Number(str)
|
|
@@ -82,7 +90,7 @@ function parse(input, slots) {
|
|
|
82
90
|
advance() // <
|
|
83
91
|
|
|
84
92
|
let name = ''
|
|
85
|
-
while (!eof() && /[a-zA-Z0-9_]/.test(peek())) name += advance()
|
|
93
|
+
while (!eof() && /[a-zA-Z0-9_.]/.test(peek())) name += advance()
|
|
86
94
|
|
|
87
95
|
const attrs = parseAttrs()
|
|
88
96
|
|
|
@@ -158,9 +166,23 @@ function build(node, slots) {
|
|
|
158
166
|
const Ctor = registry[node.tag]
|
|
159
167
|
if (!Ctor) throw new Error('Unknown cell: ' + node.tag)
|
|
160
168
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
let style = null
|
|
170
|
+
const children = node.children
|
|
171
|
+
.map((c) => build(c, slots))
|
|
172
|
+
.filter((c) => {
|
|
173
|
+
if (c instanceof Style) {
|
|
174
|
+
style = c
|
|
175
|
+
return false
|
|
176
|
+
}
|
|
177
|
+
return c !== null
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
return new Ctor({
|
|
181
|
+
...node.attrs,
|
|
182
|
+
children,
|
|
183
|
+
style,
|
|
184
|
+
cells: node.tag.startsWith('Style') ? registry : undefined
|
|
185
|
+
})
|
|
164
186
|
}
|
|
165
187
|
|
|
166
188
|
module.exports = { cellery, register }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cellery",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "cellery",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./package": "./package.json",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
26
|
"format": "prettier . --write",
|
|
27
|
-
"test": "
|
|
28
|
-
"lint": "lunte"
|
|
27
|
+
"test": "brittle-bare test/all.js",
|
|
28
|
+
"lint": "prettier . --check && lunte"
|
|
29
29
|
},
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://github.com/holepunchto/cellery",
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"css-tree": "^3.2.1",
|
|
41
42
|
"iambus": "^2.0.6"
|
|
42
43
|
}
|
|
43
44
|
}
|