bruh 1.13.1 → 2.0.0-beta.1
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/dist/browser/jsx-runtime.mjs +2 -0
- package/dist/browser/jsx-runtime.mjs.map +1 -0
- package/dist/browser.mjs +174 -0
- package/dist/browser.mjs.map +1 -0
- package/dist/cli/node.mjs +16 -0
- package/dist/cli/node.mjs.map +1 -0
- package/dist/components/aside-toc.mjs +162 -0
- package/dist/components/aside-toc.mjs.map +1 -0
- package/dist/components/custom-elements.mjs +52 -0
- package/dist/components/custom-elements.mjs.map +1 -0
- package/dist/components/intl/date-time.mjs +219 -0
- package/dist/components/intl/date-time.mjs.map +1 -0
- package/dist/components/intl/display-name.mjs +71 -0
- package/dist/components/intl/display-name.mjs.map +1 -0
- package/dist/components/intl/language-picker.mjs +102 -0
- package/dist/components/intl/language-picker.mjs.map +1 -0
- package/dist/components/intl/list.mjs +80 -0
- package/dist/components/intl/list.mjs.map +1 -0
- package/dist/components/intl/number.mjs +118 -0
- package/dist/components/intl/number.mjs.map +1 -0
- package/dist/components/intl/plural.mjs +82 -0
- package/dist/components/intl/plural.mjs.map +1 -0
- package/dist/components/intl/utils.mjs +197 -0
- package/dist/components/intl/utils.mjs.map +1 -0
- package/dist/components/optimized-picture/hydrate.mjs +10 -0
- package/dist/components/optimized-picture/hydrate.mjs.map +1 -0
- package/dist/components/optimized-picture/server.mjs +28 -0
- package/dist/components/optimized-picture/server.mjs.map +1 -0
- package/dist/components/utils.mjs +4 -0
- package/dist/components/utils.mjs.map +1 -0
- package/dist/media/images/node.mjs +41 -0
- package/dist/media/images/node.mjs.map +1 -0
- package/dist/polyfills/weakref.mjs +16 -0
- package/dist/polyfills/weakref.mjs.map +1 -0
- package/dist/reactive/sync/transport/websocket/browser.mjs +52 -0
- package/dist/reactive/sync/transport/websocket/browser.mjs.map +1 -0
- package/dist/reactive.mjs +160 -0
- package/dist/reactive.mjs.map +1 -0
- package/dist/server/jsx-runtime.mjs +2 -0
- package/dist/server/jsx-runtime.mjs.map +1 -0
- package/dist/server.mjs +346 -0
- package/dist/server.mjs.map +1 -0
- package/dist/types/cli/index.d.mts +2 -0
- package/dist/types/components/aside-toc/index.d.ts +45 -0
- package/dist/types/components/custom-elements.d.mts +83 -0
- package/dist/types/components/intl/date-time.d.ts +138 -0
- package/dist/types/components/intl/display-name.d.ts +45 -0
- package/dist/types/components/intl/language-picker.d.ts +35 -0
- package/dist/types/components/intl/list.d.ts +41 -0
- package/dist/types/components/intl/number.d.ts +81 -0
- package/dist/types/components/intl/plural.d.ts +60 -0
- package/dist/types/components/intl/utils.d.mts +30 -0
- package/dist/types/components/optimized-picture/hydrate.d.mts +2 -0
- package/dist/types/components/optimized-picture/server.d.ts +8 -0
- package/dist/types/components/utils.d.mts +5 -0
- package/dist/types/dom/browser/jsx-runtime.d.mts +3 -0
- package/dist/types/dom/index.browser.d.mts +127 -0
- package/dist/types/dom/index.server.d.mts +174 -0
- package/dist/types/dom/server/jsx-runtime.d.mts +3 -0
- package/dist/types/dom/types.d.mts +9 -0
- package/dist/types/media/images.node.d.mts +1 -0
- package/dist/types/polyfills/weakref.d.mts +4 -0
- package/dist/types/reactive/index.d.mts +91 -0
- package/dist/types/reactive/sync/transport/websocket/browser.d.mts +11 -0
- package/dist/types/utils/browser.d.mts +2 -0
- package/dist/types/utils/index.d.mts +122 -0
- package/dist/utils/browser.mjs +27 -0
- package/dist/utils/browser.mjs.map +1 -0
- package/dist/utils.mjs +287 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +122 -19
- package/dist/bruh.es.js +0 -226
- package/dist/bruh.es.js.map +0 -1
- package/dist/bruh.umd.js +0 -2
- package/dist/bruh.umd.js.map +0 -1
- package/src/cli/index.mjs +0 -19
- package/src/components/optimized-picture/hydrate.mjs +0 -10
- package/src/components/optimized-picture/render.mjs +0 -26
- package/src/dom/index.browser.mjs +0 -270
- package/src/dom/index.server.mjs +0 -280
- package/src/index.browser.mjs +0 -3
- package/src/media/images.node.mjs +0 -70
- package/src/reactive/index.mjs +0 -160
- package/src/util/index.mjs +0 -42
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { isReactive, reactiveDo } from "../reactive/index.mjs"
|
|
2
|
-
|
|
3
|
-
//#region Bruh child functions e.g. bruhChildrenToNodes()
|
|
4
|
-
|
|
5
|
-
// A basic check for if a value is allowed as a child in bruh
|
|
6
|
-
// It's responsible for quickly checking the type, not deep validation
|
|
7
|
-
const isBruhChild = x =>
|
|
8
|
-
// Reactives and DOM nodes
|
|
9
|
-
x?.[isReactive] ||
|
|
10
|
-
x instanceof Node ||
|
|
11
|
-
// Any array, just assume it contains valid children
|
|
12
|
-
Array.isArray(x) ||
|
|
13
|
-
// Allow nullish
|
|
14
|
-
x == null ||
|
|
15
|
-
// Disallow functions and objects
|
|
16
|
-
!(typeof x === "function" || typeof x === "object")
|
|
17
|
-
// Everything else can be a child when stringified
|
|
18
|
-
|
|
19
|
-
// Coerces input into a DOM node, if it isn't already one
|
|
20
|
-
const unreactiveChildToNode = x => {
|
|
21
|
-
// Existing DOM nodes are untouched
|
|
22
|
-
if (x instanceof Node)
|
|
23
|
-
return x
|
|
24
|
-
// booleans and nullish are ignored
|
|
25
|
-
else if (typeof x === "boolean" || x === undefined || x === null)
|
|
26
|
-
return document.createComment(x)
|
|
27
|
-
// Anything else is treated as text
|
|
28
|
-
else
|
|
29
|
-
return document.createTextNode(x)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Auto-swapping single reactive node
|
|
33
|
-
const reactiveChildToNode = child => {
|
|
34
|
-
let node = unreactiveChildToNode(child.value)
|
|
35
|
-
|
|
36
|
-
const stopReacting = child.addReaction(() => {
|
|
37
|
-
// Stop swapping if no longer possible
|
|
38
|
-
if (!node.parentNode) {
|
|
39
|
-
stopReacting()
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Normal swap
|
|
44
|
-
if (!Array.isArray(child.value)) {
|
|
45
|
-
const oldNode = node
|
|
46
|
-
node = unreactiveChildToNode(child.value)
|
|
47
|
-
oldNode.replaceWith(node)
|
|
48
|
-
}
|
|
49
|
-
// If an array now, stop swapping, then switch to reactive array swapping
|
|
50
|
-
else {
|
|
51
|
-
stopReacting()
|
|
52
|
-
node.replaceWith(...reactiveArrayChildToNodes(child))
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return node
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Auto-swapping reactive array of nodes
|
|
60
|
-
const reactiveArrayChildToNodes = child => {
|
|
61
|
-
// Markers owned by the swapper here itself, so that
|
|
62
|
-
// the values in the array can be swapped separately
|
|
63
|
-
const first = document.createComment("[")
|
|
64
|
-
const last = document.createComment("]")
|
|
65
|
-
|
|
66
|
-
const stopReacting = child.addReaction(() => {
|
|
67
|
-
// Stop swapping if there is no parent to swap within
|
|
68
|
-
if (!first.parentNode) {
|
|
69
|
-
stopReacting()
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Make a range starting after the first marker
|
|
74
|
-
const range = document.createRange()
|
|
75
|
-
range.setStartAfter(first)
|
|
76
|
-
|
|
77
|
-
// Normal swap, replacing content between the first and last markers
|
|
78
|
-
if (Array.isArray(child.value)) {
|
|
79
|
-
range.setEndBefore(last)
|
|
80
|
-
range.deleteContents()
|
|
81
|
-
first.after(...bruhChildrenToNodes(child.value))
|
|
82
|
-
}
|
|
83
|
-
// Switch to single swapping node by replacing everything
|
|
84
|
-
else {
|
|
85
|
-
stopReacting()
|
|
86
|
-
range.setEndAfter(last)
|
|
87
|
-
range.deleteContents()
|
|
88
|
-
first.replaceWith(reactiveChildToNode(child))
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
return [
|
|
93
|
-
first,
|
|
94
|
-
...bruhChildrenToNodes(child.value),
|
|
95
|
-
last
|
|
96
|
-
]
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Processes bruh children into an array of DOM nodes
|
|
100
|
-
// Reactive values are automatically replaced, so the output must be placed into a parent node
|
|
101
|
-
// before any top level (after flattening arrays) reactions run
|
|
102
|
-
export const bruhChildrenToNodes = children =>
|
|
103
|
-
children
|
|
104
|
-
.flat(Infinity)
|
|
105
|
-
.flatMap(child => {
|
|
106
|
-
// Non-reactive child
|
|
107
|
-
if (!child?.[isReactive])
|
|
108
|
-
return [unreactiveChildToNode(child)]
|
|
109
|
-
|
|
110
|
-
// Single reactive value
|
|
111
|
-
if (!Array.isArray(child.value))
|
|
112
|
-
return [reactiveChildToNode(child)]
|
|
113
|
-
|
|
114
|
-
// Reactive array
|
|
115
|
-
return reactiveArrayChildToNodes(child)
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
//#endregion
|
|
119
|
-
|
|
120
|
-
//#region Reactive-aware element helper functions e.g. applyAttributes()
|
|
121
|
-
|
|
122
|
-
// Style attribute rules from an object with
|
|
123
|
-
// potentially reactive and/or undefined values
|
|
124
|
-
export const applyStyles = (element, styles) => {
|
|
125
|
-
for (const property in styles)
|
|
126
|
-
reactiveDo(styles[property], value => {
|
|
127
|
-
if (value !== undefined)
|
|
128
|
-
element.style.setProperty (property, value)
|
|
129
|
-
else
|
|
130
|
-
element.style.removeProperty(property)
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Class list from an object mapping from
|
|
135
|
-
// class names to potentially reactive booleans
|
|
136
|
-
export const applyClasses = (element, classes) => {
|
|
137
|
-
for (const name in classes)
|
|
138
|
-
reactiveDo(classes[name], value => {
|
|
139
|
-
element.classList.toggle(name, value)
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Attributes from an object with
|
|
144
|
-
// potentially reactive and/or undefined values
|
|
145
|
-
export const applyAttributes = (element, attributes) => {
|
|
146
|
-
for (const name in attributes)
|
|
147
|
-
reactiveDo(attributes[name], value => {
|
|
148
|
-
if (value !== undefined)
|
|
149
|
-
element.setAttribute (name, value)
|
|
150
|
-
else
|
|
151
|
-
element.removeAttribute(name)
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
//#endregion
|
|
156
|
-
|
|
157
|
-
//#region t() for text nodes and e() for element nodes
|
|
158
|
-
|
|
159
|
-
// Text nodes
|
|
160
|
-
export const t = textContent => {
|
|
161
|
-
// Non-reactive values are just text nodes
|
|
162
|
-
if (!textContent[isReactive])
|
|
163
|
-
return document.createTextNode(textContent)
|
|
164
|
-
|
|
165
|
-
// Reactive values auto-update the node's text content
|
|
166
|
-
const node = document.createTextNode(textContent.value)
|
|
167
|
-
textContent.addReaction(() => {
|
|
168
|
-
node.textContent = textContent.value
|
|
169
|
-
})
|
|
170
|
-
return node
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Elements
|
|
174
|
-
export const e = name => (...variadic) => {
|
|
175
|
-
if (variadic.length === 0)
|
|
176
|
-
return document.createElement(name)
|
|
177
|
-
|
|
178
|
-
// If there are no props
|
|
179
|
-
if (isBruhChild(variadic[0])) {
|
|
180
|
-
const element = document.createElement(name)
|
|
181
|
-
element.append(...bruhChildrenToNodes(variadic))
|
|
182
|
-
return element
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// If props exist as the first variadic argument
|
|
186
|
-
const [props, ...children] = variadic
|
|
187
|
-
|
|
188
|
-
// Extract explicit options from the bruh prop
|
|
189
|
-
const { namespace } = props.bruh ?? {}
|
|
190
|
-
delete props.bruh
|
|
191
|
-
|
|
192
|
-
// Make an element with optional namespace
|
|
193
|
-
const element =
|
|
194
|
-
namespace
|
|
195
|
-
? document.createElementNS(namespace, name)
|
|
196
|
-
: document.createElement ( name)
|
|
197
|
-
|
|
198
|
-
// Apply overloaded props, if possible
|
|
199
|
-
|
|
200
|
-
// Inline style object
|
|
201
|
-
if (typeof props.style === "object" && !props.style[isReactive]) {
|
|
202
|
-
applyStyles(element, props.style)
|
|
203
|
-
delete props.style
|
|
204
|
-
}
|
|
205
|
-
// Classes object
|
|
206
|
-
if (typeof props.class === "object" && !props.class[isReactive]) {
|
|
207
|
-
applyClasses(element, props.class)
|
|
208
|
-
delete props.class
|
|
209
|
-
}
|
|
210
|
-
for (const name in props) {
|
|
211
|
-
// Event listener functions
|
|
212
|
-
if (name.startsWith("on") && typeof props[name] === "function") {
|
|
213
|
-
element.addEventListener(name.slice(2), props[name])
|
|
214
|
-
delete props[name]
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// The rest of the props are attributes
|
|
219
|
-
applyAttributes(element, props)
|
|
220
|
-
|
|
221
|
-
// Add the children to the element
|
|
222
|
-
element.append(...bruhChildrenToNodes(children))
|
|
223
|
-
return element
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
//#endregion
|
|
227
|
-
|
|
228
|
-
//#region JSX integration
|
|
229
|
-
|
|
230
|
-
// The function that jsx tags (except fragments) compile to
|
|
231
|
-
export const h = (nameOrComponent, props, ...children) => {
|
|
232
|
-
// If we are making an element, this is just a wrapper of e()
|
|
233
|
-
// This is likely when the JSX tag name begins with a lowercase character
|
|
234
|
-
if (typeof nameOrComponent === "string") {
|
|
235
|
-
const makeElement = e(nameOrComponent)
|
|
236
|
-
return props
|
|
237
|
-
? makeElement(props, ...children)
|
|
238
|
-
: makeElement(...children)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// It must be a component, then, as bruh components are just functions
|
|
242
|
-
// Due to JSX, this would mean a function with only one parameter - props
|
|
243
|
-
// This object includes the all of the normal props and a "children" key
|
|
244
|
-
return nameOrComponent({ ...props, children })
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// The JSX fragment is made into a bruh fragment (just an array)
|
|
248
|
-
export const JSXFragment = ({ children }) => children
|
|
249
|
-
|
|
250
|
-
//#endregion
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// Hydration of all bruh-textnode's from prerendered html
|
|
255
|
-
export const hydrateTextNodes = () => {
|
|
256
|
-
const tagged = {}
|
|
257
|
-
const bruhTextNodes = document.getElementsByTagName("bruh-textnode")
|
|
258
|
-
|
|
259
|
-
for (const bruhTextNode of bruhTextNodes) {
|
|
260
|
-
const textNode = document.createTextNode(bruhTextNode.textContent)
|
|
261
|
-
|
|
262
|
-
const tag = bruhTextNode.getAttribute("tag")
|
|
263
|
-
if (tag)
|
|
264
|
-
tagged[tag] = textNode
|
|
265
|
-
|
|
266
|
-
bruhTextNode.replaceWith(textNode)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return tagged
|
|
270
|
-
}
|
package/src/dom/index.server.mjs
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
const isMetaNode = Symbol.for("bruh meta node")
|
|
2
|
-
const isMetaTextNode = Symbol.for("bruh meta text node")
|
|
3
|
-
const isMetaElement = Symbol.for("bruh meta element")
|
|
4
|
-
const isMetaRawString = Symbol.for("bruh meta raw string")
|
|
5
|
-
|
|
6
|
-
//#region HTML syntax functions
|
|
7
|
-
|
|
8
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
9
|
-
const voidElements = [
|
|
10
|
-
"base",
|
|
11
|
-
"link",
|
|
12
|
-
"meta",
|
|
13
|
-
|
|
14
|
-
"hr",
|
|
15
|
-
"br",
|
|
16
|
-
"wbr",
|
|
17
|
-
|
|
18
|
-
"area",
|
|
19
|
-
"img",
|
|
20
|
-
"track",
|
|
21
|
-
|
|
22
|
-
"embed",
|
|
23
|
-
"param",
|
|
24
|
-
"source",
|
|
25
|
-
|
|
26
|
-
"col",
|
|
27
|
-
|
|
28
|
-
"input"
|
|
29
|
-
]
|
|
30
|
-
|
|
31
|
-
const isVoidElement = element =>
|
|
32
|
-
voidElements.includes(element)
|
|
33
|
-
|
|
34
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#elements-2
|
|
35
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#cdata-rcdata-restrictions
|
|
36
|
-
// Does not work for https://html.spec.whatwg.org/multipage/syntax.html#raw-text-elements (script and style)
|
|
37
|
-
const escapeForElement = x =>
|
|
38
|
-
(x + "")
|
|
39
|
-
.replace(/&/g, "&")
|
|
40
|
-
.replace(/</g, "<")
|
|
41
|
-
|
|
42
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#syntax-attribute-value
|
|
43
|
-
const escapeForDoubleQuotedAttribute = x =>
|
|
44
|
-
(x + "")
|
|
45
|
-
.replace(/&/g, "&")
|
|
46
|
-
.replace(/"/g, """)
|
|
47
|
-
|
|
48
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
49
|
-
const attributesToString = attributes =>
|
|
50
|
-
Object.entries(attributes)
|
|
51
|
-
.map(([name, value]) =>
|
|
52
|
-
value === ""
|
|
53
|
-
? ` ${name}`
|
|
54
|
-
: ` ${name}="${escapeForDoubleQuotedAttribute(value)}"`
|
|
55
|
-
).join("")
|
|
56
|
-
|
|
57
|
-
//#endregion
|
|
58
|
-
|
|
59
|
-
// A basic check for if a value is allowed as a meta node's child
|
|
60
|
-
// It's responsible for quickly checking the type, not deep validation
|
|
61
|
-
const isMetaChild = x =>
|
|
62
|
-
// meta nodes, reactives, and DOM nodes
|
|
63
|
-
x?.[isMetaNode] ||
|
|
64
|
-
x?.[isMetaRawString] ||
|
|
65
|
-
// Any array, just assume it contains valid children
|
|
66
|
-
Array.isArray(x) ||
|
|
67
|
-
// Allow nullish
|
|
68
|
-
x == null ||
|
|
69
|
-
// Disallow functions and objects
|
|
70
|
-
!(typeof x === "function" || typeof x === "object")
|
|
71
|
-
// Everything else can be a child when stringified
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//#region Meta Nodes that act like lightweight rendering-oriented DOM nodes
|
|
75
|
-
|
|
76
|
-
// Text nodes have no individual HTML representation
|
|
77
|
-
// We emulate this with a custom element <bruh-textnode> with an inline style reset
|
|
78
|
-
// These elements can be hydrated very quickly and even be marked with a tag
|
|
79
|
-
export class MetaTextNode {
|
|
80
|
-
[isMetaNode] = true;
|
|
81
|
-
[isMetaTextNode] = true
|
|
82
|
-
|
|
83
|
-
textContent
|
|
84
|
-
tag
|
|
85
|
-
|
|
86
|
-
constructor(textContent) {
|
|
87
|
-
this.textContent = textContent
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
toString() {
|
|
91
|
-
const tag = this.tag
|
|
92
|
-
? ` tag="${escapeForDoubleQuotedAttribute(this.tag)}"`
|
|
93
|
-
: ""
|
|
94
|
-
return `<bruh-textnode style="all:unset;display:inline"${tag}>${
|
|
95
|
-
escapeForElement(this.textContent)
|
|
96
|
-
}</bruh-textnode>`
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
setTag(tag) {
|
|
100
|
-
this.tag = tag
|
|
101
|
-
|
|
102
|
-
return this
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// A light model of an element
|
|
107
|
-
export class MetaElement {
|
|
108
|
-
[isMetaNode] = true;
|
|
109
|
-
[isMetaElement] = true
|
|
110
|
-
|
|
111
|
-
name
|
|
112
|
-
attributes = {}
|
|
113
|
-
children = []
|
|
114
|
-
|
|
115
|
-
constructor(name) {
|
|
116
|
-
this.name = name
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
toString() {
|
|
120
|
-
const attributes = attributesToString(this.attributes)
|
|
121
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#syntax-start-tag
|
|
122
|
-
const startTag = `<${this.name}${attributes}>`
|
|
123
|
-
if (isVoidElement(this.name))
|
|
124
|
-
return startTag
|
|
125
|
-
|
|
126
|
-
const contents = this.children
|
|
127
|
-
.flat(Infinity)
|
|
128
|
-
.filter(x => typeof x !== "boolean" && x !== undefined && x !== null)
|
|
129
|
-
.map(child =>
|
|
130
|
-
(child[isMetaNode] || child[isMetaRawString])
|
|
131
|
-
? child.toString()
|
|
132
|
-
: escapeForElement(child)
|
|
133
|
-
)
|
|
134
|
-
.join("")
|
|
135
|
-
// https://html.spec.whatwg.org/multipage/syntax.html#end-tags
|
|
136
|
-
const endTag = `</${this.name}>`
|
|
137
|
-
return startTag + contents + endTag
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Raw strings can be meta element children, where they bypass string escaping
|
|
142
|
-
// This should be avoided in general, but is needed for unsupported HTML features
|
|
143
|
-
export class MetaRawString extends String {
|
|
144
|
-
[isMetaRawString] = true
|
|
145
|
-
|
|
146
|
-
constructor(string) {
|
|
147
|
-
super(string)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
//#endregion
|
|
152
|
-
|
|
153
|
-
//#region Meta element helper functions e.g. applyAttributes()
|
|
154
|
-
|
|
155
|
-
// Merge style rules with an object
|
|
156
|
-
export const applyStyles = (element, styles) => {
|
|
157
|
-
// Doesn't support proper escaping
|
|
158
|
-
// https://www.w3.org/TR/css-syntax-3/#ref-for-parse-a-list-of-declarations%E2%91%A0
|
|
159
|
-
// https://www.w3.org/TR/css-syntax-3/#typedef-ident-token
|
|
160
|
-
const currentStyles = Object.fromEntries(
|
|
161
|
-
(element.attributes.style || "")
|
|
162
|
-
.split(";").filter(s => s.length)
|
|
163
|
-
.map(declaration => declaration.split(":").map(s => s.trim()))
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
Object.entries(styles)
|
|
167
|
-
.forEach(([property, value]) => {
|
|
168
|
-
if (value !== undefined)
|
|
169
|
-
currentStyles[property] = value
|
|
170
|
-
else
|
|
171
|
-
delete currentStyles[property]
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
element.attributes.style =
|
|
175
|
-
Object.entries(currentStyles)
|
|
176
|
-
.map(([property, value]) => `${property}:${value}`)
|
|
177
|
-
.join(";")
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Merge classes with an object mapping from class names to booleans
|
|
181
|
-
export const applyClasses = (element, classes) => {
|
|
182
|
-
// Doesn't support proper escaping
|
|
183
|
-
// https://html.spec.whatwg.org/multipage/dom.html#global-attributes:classes-2
|
|
184
|
-
const currentClasses = new Set(
|
|
185
|
-
(element.attributes.class || "")
|
|
186
|
-
.split(/\s+/).filter(s => s.length)
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
Object.entries(classes)
|
|
190
|
-
.forEach(([name, value]) => {
|
|
191
|
-
if (value)
|
|
192
|
-
currentClasses.add(name)
|
|
193
|
-
else
|
|
194
|
-
currentClasses.delete(name)
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
element.attributes.class = [...currentClasses].join(" ")
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Merge attributes with an object
|
|
201
|
-
export const applyAttributes = (element, attributes) => {
|
|
202
|
-
Object.entries(attributes)
|
|
203
|
-
.forEach(([name, value]) => {
|
|
204
|
-
if (value !== undefined)
|
|
205
|
-
element.attributes[name] = value
|
|
206
|
-
else
|
|
207
|
-
delete element.attributes[name]
|
|
208
|
-
})
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
//#endregion
|
|
212
|
-
|
|
213
|
-
//#region rawString(), t(), and e()
|
|
214
|
-
|
|
215
|
-
export const rawString = string =>
|
|
216
|
-
new MetaRawString(string)
|
|
217
|
-
|
|
218
|
-
export const t = textContent =>
|
|
219
|
-
new MetaTextNode(textContent)
|
|
220
|
-
|
|
221
|
-
export const e = name => (...variadic) => {
|
|
222
|
-
const element = new MetaElement(name)
|
|
223
|
-
|
|
224
|
-
if (variadic.length === 0)
|
|
225
|
-
return element
|
|
226
|
-
|
|
227
|
-
// If there are no props
|
|
228
|
-
if (isMetaChild(variadic[0])) {
|
|
229
|
-
element.children.push(...variadic)
|
|
230
|
-
return element
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// If props exist as the first variadic argument
|
|
234
|
-
const [props, ...children] = variadic
|
|
235
|
-
|
|
236
|
-
// The bruh prop is reserved for future use
|
|
237
|
-
delete props.bruh
|
|
238
|
-
|
|
239
|
-
// Apply overloaded props, if possible
|
|
240
|
-
if (typeof props.style === "object") {
|
|
241
|
-
applyStyles(element, props.style)
|
|
242
|
-
delete props.style
|
|
243
|
-
}
|
|
244
|
-
if (typeof props.class === "object") {
|
|
245
|
-
applyClasses(element, props.class)
|
|
246
|
-
delete props.class
|
|
247
|
-
}
|
|
248
|
-
// The rest of the props are attributes
|
|
249
|
-
applyAttributes(element, props)
|
|
250
|
-
|
|
251
|
-
// Add the children to the element
|
|
252
|
-
element.children.push(...children)
|
|
253
|
-
return element
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
//#endregion
|
|
257
|
-
|
|
258
|
-
//#region JSX integration
|
|
259
|
-
|
|
260
|
-
// The function that jsx tags (except fragments) compile to
|
|
261
|
-
export const h = (nameOrComponent, props, ...children) => {
|
|
262
|
-
// If we are making an element, this is just a wrapper of e()
|
|
263
|
-
// This is likely when the JSX tag name begins with a lowercase character
|
|
264
|
-
if (typeof nameOrComponent === "string") {
|
|
265
|
-
const makeElement = e(nameOrComponent)
|
|
266
|
-
return props
|
|
267
|
-
? makeElement(props, ...children)
|
|
268
|
-
: makeElement(...children)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// It must be a component, then, as bruh components are just functions
|
|
272
|
-
// Due to JSX, this would mean a function with only one parameter - props
|
|
273
|
-
// This object includes the all of the normal props and a "children" key
|
|
274
|
-
return nameOrComponent({ ...props, children })
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// The JSX fragment is made into a bruh fragment (just an array)
|
|
278
|
-
export const JSXFragment = ({ children }) => children
|
|
279
|
-
|
|
280
|
-
//#endregion
|
package/src/index.browser.mjs
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import sharp from "sharp"
|
|
2
|
-
import { readdir, writeFile } from "fs/promises"
|
|
3
|
-
import { extname, join } from "path"
|
|
4
|
-
|
|
5
|
-
const avif = async (filePath, sharpInstance) =>
|
|
6
|
-
sharpInstance
|
|
7
|
-
.avif({ })
|
|
8
|
-
.toFile(`${filePath}.avif`)
|
|
9
|
-
|
|
10
|
-
const webp = async (filePath, sharpInstance) =>
|
|
11
|
-
sharpInstance
|
|
12
|
-
.webp({ })
|
|
13
|
-
.toFile(`${filePath}.webp`)
|
|
14
|
-
|
|
15
|
-
// Low Quality Image Placeholder inline css for the <img> style attribute
|
|
16
|
-
const json = async (filePath, sharpInstance) => {
|
|
17
|
-
const imageManifest = {}
|
|
18
|
-
|
|
19
|
-
const metadata = await sharpInstance.metadata()
|
|
20
|
-
imageManifest.format = metadata.format
|
|
21
|
-
imageManifest.width = metadata.width
|
|
22
|
-
imageManifest.height = metadata.height
|
|
23
|
-
|
|
24
|
-
const buffer = await sharpInstance
|
|
25
|
-
.resize({ fit: "inside", width: 16, height: 16 })
|
|
26
|
-
.blur()
|
|
27
|
-
.webp({ reductionEffort: 6 })
|
|
28
|
-
.toBuffer()
|
|
29
|
-
|
|
30
|
-
imageManifest.lqip = `data:image/webp;base64,${buffer.toString("base64")}`
|
|
31
|
-
return writeFile(`${filePath}.json`, JSON.stringify(imageManifest))
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const getUnprocessedImages = async directory => {
|
|
35
|
-
const directoryEntries = await readdir(directory, { withFileTypes: true })
|
|
36
|
-
|
|
37
|
-
const promisedUnproccessedImages = directoryEntries
|
|
38
|
-
.map(async entry => {
|
|
39
|
-
const entryPath = join(directory, entry.name)
|
|
40
|
-
|
|
41
|
-
if (entry.isDirectory())
|
|
42
|
-
return await getUnprocessedImages(entryPath)
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
entry.name[0] == "." ||
|
|
46
|
-
[".avif", ".webp", ".json"]
|
|
47
|
-
.includes(extname(entry.name)) ||
|
|
48
|
-
directoryEntries.some(siblingEntry =>
|
|
49
|
-
[".avif", ".webp", ".json"]
|
|
50
|
-
.map(processedExtention => `${entry.name}${processedExtention}`)
|
|
51
|
-
.includes(siblingEntry.name)
|
|
52
|
-
)
|
|
53
|
-
)
|
|
54
|
-
return []
|
|
55
|
-
|
|
56
|
-
return [entryPath]
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
return (await Promise.all(promisedUnproccessedImages)).flat()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export const processImages = async directory => {
|
|
63
|
-
const unprocessedImages = await getUnprocessedImages(directory)
|
|
64
|
-
for (const filePath of unprocessedImages) {
|
|
65
|
-
await Promise.all(
|
|
66
|
-
[avif, webp, json]
|
|
67
|
-
.map(process => process(filePath, sharp(filePath)))
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
}
|