bruh 1.9.2-types.0 → 1.10.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/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "library",
11
11
  "modern"
12
12
  ],
13
- "version": "1.9.2-types.0",
13
+ "version": "1.10.0",
14
14
  "license": "MIT",
15
15
  "author": {
16
16
  "name": "Daniel Ethridge",
@@ -50,18 +50,10 @@
50
50
  "prepare": "npm run build"
51
51
  },
52
52
  "optionalDependencies": {
53
- "cac": "^6.7.3",
54
- "sharp": "^0.28.3"
53
+ "cac": "^6.7.11",
54
+ "sharp": "^0.29.2"
55
55
  },
56
56
  "devDependencies": {
57
- "vite": "^2.5.10"
58
- },
59
- "browserslist": [
60
- "ios_saf >= 12.4",
61
- "and_chr >= 88",
62
- "chrome >= 87",
63
- "safari >= 13.1",
64
- "edge >= 87",
65
- "firefox >= 84"
66
- ]
57
+ "vite": "^2.6.10"
58
+ }
67
59
  }
@@ -1,19 +1,12 @@
1
- /** @typedef { import("./index.browser") } */
2
-
3
1
  import { LiveFragment } from "./live-fragment.mjs"
4
- import { reactiveDo } from "../reactive/index.mjs"
5
- import { maybeDo } from "../util/index.mjs"
2
+ import { isReactive, reactiveDo } from "../reactive/index.mjs"
6
3
 
7
- const isReactive = Symbol.for("bruh reactive")
8
- const isMetaNode = Symbol.for("bruh meta node")
9
- const isMetaTextNode = Symbol.for("bruh meta text node")
10
- const isMetaElement = Symbol.for("bruh meta element")
4
+ //#region Bruh child functions e.g. bruhChildrenToNodes()
11
5
 
12
- // A basic check for if a value is allowed as a meta node's child
6
+ // A basic check for if a value is allowed as a child in bruh
13
7
  // It's responsible for quickly checking the type, not deep validation
14
- const isMetaNodeChild = x =>
15
- // meta nodes, reactives, and DOM nodes
16
- x?.[isMetaNode] ||
8
+ const isBruhChild = x =>
9
+ // Reactives and DOM nodes
17
10
  x?.[isReactive] ||
18
11
  x instanceof Node ||
19
12
  // Any array, just assume it contains valid children
@@ -24,31 +17,33 @@ const isMetaNodeChild = x =>
24
17
  !(typeof x === "function" || typeof x === "object")
25
18
  // Everything else can be a child when stringified
26
19
 
27
- const toNode = x => {
28
- if (x[isMetaNode])
29
- return x.node
30
-
31
- if (x instanceof Node)
32
- return x
33
-
34
- return document.createTextNode(x)
35
- }
20
+ // Coerces input into a DOM node, if it isn't already one
21
+ const toNode = x =>
22
+ x instanceof Node
23
+ ? x
24
+ : document.createTextNode(x)
36
25
 
37
- export const childrenToNodes = children =>
26
+ // Processes bruh children into an array of DOM nodes
27
+ // Reactive values are automatically replaced, so the output must be placed into a parent node
28
+ // before any top level (after flattening arrays) reactions run
29
+ export const bruhChildrenToNodes = (...children) =>
38
30
  children
39
31
  .flat(Infinity)
40
32
  .flatMap(child => {
33
+ // Non-reactive values are untouched
41
34
  if (!child[isReactive])
42
35
  return [toNode(child)]
43
36
 
37
+ // Reactive arrays become live fragments with auto-swapped children
44
38
  if (Array.isArray(child.value)) {
45
39
  const liveFragment = new LiveFragment()
46
40
  child.addReaction(() => {
47
- liveFragment.replaceChildren(...childrenToNodes(child.value))
41
+ liveFragment.replaceChildren(...bruhChildrenToNodes(...child.value))
48
42
  })
49
- return [liveFragment.startMarker, ...childrenToNodes(child.value), liveFragment.endMarker]
43
+ return [liveFragment.startMarker, ...bruhChildrenToNodes(...child.value), liveFragment.endMarker]
50
44
  }
51
45
 
46
+ // Reactive values become auto-swapped DOM nodes
52
47
  let node = toNode(child.value)
53
48
  child.addReaction(() => {
54
49
  const oldNode = node
@@ -58,134 +53,129 @@ export const childrenToNodes = children =>
58
53
  return [node]
59
54
  })
60
55
 
56
+ //#endregion
61
57
 
58
+ //#region Reactive-aware element helper functions e.g. applyAttributes()
62
59
 
63
- // Meta Nodes
64
-
65
- export class MetaTextNode {
66
- [isMetaNode] = true;
67
- [isMetaTextNode] = true
68
-
69
- node
70
-
71
- constructor(textContent) {
72
- if (!textContent[isReactive]) {
73
- this.node = document.createTextNode(textContent)
74
- return
75
- }
76
-
77
- this.node = document.createTextNode(textContent.value)
78
- textContent.addReaction(() => {
79
- this.node.textContent = textContent.value
60
+ // Style attribute rules from an object with
61
+ // potentially reactive and/or undefined values
62
+ export const applyStyles = (element, styles) => {
63
+ for (const property in styles)
64
+ reactiveDo(styles[property], value => {
65
+ if (value !== undefined)
66
+ element.style.setProperty (property, value)
67
+ else
68
+ element.style.removeProperty(property)
80
69
  })
81
- }
82
-
83
- addProperties(properties = {}) {
84
- Object.assign(this.node, properties)
85
-
86
- return this
87
- }
88
70
  }
89
71
 
90
- export class MetaElement {
91
- [isMetaNode] = true;
92
- [isMetaElement] = true
93
-
94
- node
95
-
96
- constructor(name, namespace) {
97
- this.node =
98
- namespace
99
- ? document.createElementNS(namespace, name)
100
- : document.createElement ( name)
101
- }
102
-
103
- static from(element) {
104
- const result = new this("div")
105
- result.node = element
106
- return result
107
- }
72
+ // Class list from an object mapping from
73
+ // class names to potentially reactive booleans
74
+ export const applyClasses = (element, classes) => {
75
+ for (const name in classes)
76
+ reactiveDo(classes[name], value => {
77
+ element.classList.toggle(name, value)
78
+ })
79
+ }
108
80
 
109
- addProperties(properties = {}) {
110
- Object.assign(this.node, properties)
81
+ // Attributes from an object with
82
+ // potentially reactive and/or undefined values
83
+ export const applyAttributes = (element, attributes) => {
84
+ for (const name in attributes)
85
+ reactiveDo(attributes[name], value => {
86
+ if (value !== undefined)
87
+ element.setAttribute (name, value)
88
+ else
89
+ element.removeAttribute(name)
90
+ })
91
+ }
111
92
 
112
- return this
113
- }
93
+ //#endregion
114
94
 
115
- addAttributes(attributes = {}) {
116
- for (const name in attributes)
117
- reactiveDo(attributes[name],
118
- maybeDo(
119
- value => this.node.setAttribute (name, value),
120
- () => this.node.removeAttribute(name)
121
- )
122
- )
95
+ //#region t() for text nodes and e() for element nodes
123
96
 
124
- return this
125
- }
97
+ // Text nodes
98
+ export const t = textContent => {
99
+ // Non-reactive values are just text nodes
100
+ if (!textContent[isReactive])
101
+ return document.createTextNode(textContent)
126
102
 
127
- addDataAttributes(dataAttributes = {}) {
128
- for (const name in dataAttributes)
129
- reactiveDo(dataAttributes[name],
130
- maybeDo(
131
- value => this.node.dataset[name] = value,
132
- () => delete this.node.dataset[name]
133
- )
134
- )
103
+ // Reactive values auto-update the node's text content
104
+ const node = document.createTextNode(textContent.value)
105
+ textContent.addReaction(() => {
106
+ node.textContent = textContent.value
107
+ })
108
+ return node
109
+ }
135
110
 
136
- return this
111
+ // Elements
112
+ export const e = name => (...variadic) => {
113
+ // If there are no props
114
+ if (isBruhChild(variadic[0])) {
115
+ const element = document.createElement(name)
116
+ element.append(...bruhChildrenToNodes(...variadic))
117
+ return element
137
118
  }
138
119
 
139
- addStyles(styles = {}) {
140
- for (const property in styles)
141
- reactiveDo(styles[property],
142
- maybeDo(
143
- value => this.node.style.setProperty (property, value),
144
- () => this.node.style.removeProperty(property)
145
- )
146
- )
120
+ // If props exist as the first variadic argument
121
+ const [props, ...children] = variadic
147
122
 
148
- return this
149
- }
123
+ // Extract explicit options from the bruh prop
124
+ const { namespace } = props.bruh ?? {}
125
+ delete props.bruh
150
126
 
151
- toggleClasses(classes = {}) {
152
- for (const name in classes)
153
- reactiveDo(classes[name],
154
- value => this.node.classList.toggle(name, value)
155
- )
127
+ // Make an element with optional namespace
128
+ const element =
129
+ namespace
130
+ ? document.createElementNS(namespace, name)
131
+ : document.createElement ( name)
156
132
 
157
- return this
133
+ // Apply overloaded props, if possible
134
+ if (typeof props.style === "object") {
135
+ applyStyles(element, props.style)
136
+ delete props.style
158
137
  }
159
-
160
- before(...xs) {
161
- this.node.before(...childrenToNodes(xs))
138
+ if (typeof props.class === "object") {
139
+ applyClasses(element, props.class)
140
+ delete props.class
162
141
  }
142
+ // The rest of the props are attributes
143
+ applyAttributes(element, props)
163
144
 
164
- prepend(...xs) {
165
- this.node.prepend(...childrenToNodes(xs))
166
- }
145
+ // Add the children to the element
146
+ element.append(...bruhChildrenToNodes(...children))
147
+ return element
148
+ }
167
149
 
168
- append(...xs) {
169
- this.node.append(...childrenToNodes(xs))
170
- }
150
+ //#endregion
171
151
 
172
- after(...xs) {
173
- this.node.after(...childrenToNodes(xs))
174
- }
152
+ //#region JSX integration
175
153
 
176
- replaceChildren(...xs) {
177
- this.node.replaceChildren(...childrenToNodes(xs))
154
+ // The function that jsx tags (except fragments) compile to
155
+ export const h = (nameOrComponent, props, ...children) => {
156
+ // If we are making an element, this is just a wrapper of e()
157
+ // This is likely when the JSX tag name begins with a lowercase character
158
+ if (typeof nameOrComponent === "string") {
159
+ const makeElement = e(nameOrComponent)
160
+ return props
161
+ ? makeElement(props, ...children)
162
+ : makeElement(...children)
178
163
  }
179
164
 
180
- replaceWith(...xs) {
181
- this.node.replaceWith(...childrenToNodes(xs))
182
- }
165
+ // It must be a component, then, as bruh components are just functions
166
+ // Due to JSX, this would mean a function with only one parameter - props
167
+ // This object includes the all of the normal props and a "children" key
168
+ return nameOrComponent({ ...props, children })
183
169
  }
184
170
 
171
+ // The JSX fragment is made into a bruh fragment (just an array)
172
+ export const JSXFragment = ({ children }) => children
185
173
 
174
+ //#endregion
186
175
 
187
- // Convenience functions
188
176
 
177
+
178
+ // Hydration of all bruh-textnode's from prerendered html
189
179
  export const hydrateTextNodes = () => {
190
180
  const tagged = {}
191
181
  const bruhTextNodes = document.getElementsByTagName("bruh-textnode")
@@ -193,61 +183,12 @@ export const hydrateTextNodes = () => {
193
183
  for (const bruhTextNode of bruhTextNodes) {
194
184
  const textNode = document.createTextNode(bruhTextNode.textContent)
195
185
 
196
- if (bruhTextNode.dataset.tag)
197
- tagged[bruhTextNode.dataset.tag] = textNode
186
+ const tag = bruhTextNode.getAttribute("tag")
187
+ if (tag)
188
+ tagged[tag] = textNode
198
189
 
199
190
  bruhTextNode.replaceWith(textNode)
200
191
  }
201
192
 
202
193
  return tagged
203
194
  }
204
-
205
- const createMetaTextNode = textContent =>
206
- new MetaTextNode(textContent)
207
-
208
- const createMetaElement = (name, namespace) => (...variadic) => {
209
- const meta = new MetaElement(name, namespace)
210
-
211
- // Implement optional attributes as first argument
212
- if (!isMetaNodeChild(variadic[0])) {
213
- const [attributes, ...children] = variadic
214
- meta.addAttributes(attributes)
215
- meta.append(children)
216
- }
217
- else {
218
- meta.append(variadic)
219
- }
220
-
221
- return meta
222
- }
223
-
224
- // JSX integration
225
- const createMetaElementJSX = (nameOrComponent, attributesOrProps, ...children) => {
226
- // If we are making a html element
227
- // This is likely when the jsx tag name begins with a lowercase character
228
- if (typeof nameOrComponent == "string") {
229
- const meta = new MetaElement(nameOrComponent)
230
-
231
- // These are attributes then, but they might be null/undefined
232
- meta.addAttributes(attributesOrProps || {})
233
- meta.append(children)
234
-
235
- return meta
236
- }
237
-
238
- // It must be a component, then
239
- // Bruh components are just functions that return meta elements
240
- // Due to JSX, this would mean a function with only one parameter - a "props" object
241
- // This object includes the all of the attributes and a "children" key
242
- return nameOrComponent( Object.assign({}, attributesOrProps, { children }) )
243
- }
244
-
245
- // These will be called with short names
246
- export {
247
- createMetaTextNode as t,
248
- createMetaElement as e,
249
- createMetaElementJSX as h
250
- }
251
-
252
- // The JSX fragment is made into a bruh fragment (just an array)
253
- export const JSXFragment = ({ children }) => children