boxwood 2.5.0 → 2.7.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/index.d.ts +569 -420
- package/index.js +197 -70
- package/package.json +5 -5
- package/ui/center/index.js +2 -2
- package/ui/container/index.js +2 -2
- package/ui/grid/index.js +5 -2
- package/ui/group/index.js +13 -2
- package/ui/markdown/index.js +10 -8
- package/ui/stack/index.js +2 -2
package/index.js
CHANGED
|
@@ -3,6 +3,70 @@ const { readFileSync, realpathSync, lstatSync } = require("fs")
|
|
|
3
3
|
const csstree = require("css-tree")
|
|
4
4
|
const { createHash } = require("./utilities/hash")
|
|
5
5
|
|
|
6
|
+
class TranslationError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message)
|
|
9
|
+
this.name = "TranslationError"
|
|
10
|
+
Error.captureStackTrace(this, this.constructor)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class FileError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message)
|
|
17
|
+
this.name = "FileError"
|
|
18
|
+
Error.captureStackTrace(this, this.constructor)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class RawError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message)
|
|
25
|
+
this.name = "RawError"
|
|
26
|
+
Error.captureStackTrace(this, this.constructor)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class CSSError extends Error {
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message)
|
|
33
|
+
this.name = "CSSError"
|
|
34
|
+
Error.captureStackTrace(this, this.constructor)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class ImageError extends Error {
|
|
39
|
+
constructor(message) {
|
|
40
|
+
super(message)
|
|
41
|
+
this.name = "ImageError"
|
|
42
|
+
Error.captureStackTrace(this, this.constructor)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class SVGError extends Error {
|
|
47
|
+
constructor(message) {
|
|
48
|
+
super(message)
|
|
49
|
+
this.name = "SVGError"
|
|
50
|
+
Error.captureStackTrace(this, this.constructor)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class JSONError extends Error {
|
|
55
|
+
constructor(message) {
|
|
56
|
+
super(message)
|
|
57
|
+
this.name = "JSONError"
|
|
58
|
+
Error.captureStackTrace(this, this.constructor)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class ComponentError extends Error {
|
|
63
|
+
constructor(message) {
|
|
64
|
+
super(message)
|
|
65
|
+
this.name = "ComponentError"
|
|
66
|
+
Error.captureStackTrace(this, this.constructor)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
6
70
|
function compile(path) {
|
|
7
71
|
const fn = require(path)
|
|
8
72
|
return {
|
|
@@ -37,7 +101,7 @@ function compile(path) {
|
|
|
37
101
|
if (
|
|
38
102
|
attributes.src ||
|
|
39
103
|
["application/json", "application/ld+json"].includes(
|
|
40
|
-
attributes.type
|
|
104
|
+
attributes.type,
|
|
41
105
|
)
|
|
42
106
|
) {
|
|
43
107
|
node.ignore = false
|
|
@@ -179,7 +243,7 @@ function validateSymlinks(path, base) {
|
|
|
179
243
|
if (!part) continue
|
|
180
244
|
current = resolve(current, part)
|
|
181
245
|
if (lstatSync(current).isSymbolicLink()) {
|
|
182
|
-
throw new
|
|
246
|
+
throw new FileError(`symlinks are not allowed ("${current}")`)
|
|
183
247
|
}
|
|
184
248
|
}
|
|
185
249
|
}
|
|
@@ -191,33 +255,31 @@ function validateFile(path, base) {
|
|
|
191
255
|
const type = extension(normalizedPath)
|
|
192
256
|
|
|
193
257
|
if (!type) {
|
|
194
|
-
throw new
|
|
258
|
+
throw new FileError(`path "${path}" has no extension`)
|
|
195
259
|
}
|
|
196
260
|
|
|
197
261
|
if (!ALLOWED_READ_EXTENSIONS.includes(type)) {
|
|
198
|
-
throw new
|
|
199
|
-
`FileError: unsupported file type "${type}" for path "${path}"`
|
|
200
|
-
)
|
|
262
|
+
throw new FileError(`unsupported file type "${type}" for path "${path}"`)
|
|
201
263
|
}
|
|
202
264
|
|
|
203
265
|
const stats = lstatSync(normalizedPath)
|
|
204
266
|
if (!stats.isFile()) {
|
|
205
|
-
throw new
|
|
267
|
+
throw new FileError(`path "${path}" is not a file`)
|
|
206
268
|
}
|
|
207
269
|
|
|
208
270
|
if (stats.isSymbolicLink()) {
|
|
209
|
-
throw new
|
|
271
|
+
throw new FileError(`path "${path}" is a symbolic link`)
|
|
210
272
|
}
|
|
211
273
|
|
|
212
274
|
if (normalizedPath === normalizedBase) {
|
|
213
|
-
throw new
|
|
214
|
-
`
|
|
275
|
+
throw new FileError(
|
|
276
|
+
`path "${path}" is the same as the current working directory "${base}"`,
|
|
215
277
|
)
|
|
216
278
|
}
|
|
217
279
|
|
|
218
280
|
if (!normalizedPath.startsWith(normalizedBase + "/")) {
|
|
219
|
-
throw new
|
|
220
|
-
`
|
|
281
|
+
throw new FileError(
|
|
282
|
+
`real path "${normalizedPath}" is not within the current working directory "${normalizedBase}"`,
|
|
221
283
|
)
|
|
222
284
|
}
|
|
223
285
|
}
|
|
@@ -235,9 +297,7 @@ function readFile(path, encoding) {
|
|
|
235
297
|
|
|
236
298
|
return readFileSync(path, encoding)
|
|
237
299
|
} catch (exception) {
|
|
238
|
-
throw new
|
|
239
|
-
`FileError: cannot read file "${path}": ${exception.message}`
|
|
240
|
-
)
|
|
300
|
+
throw new FileError(`cannot read file "${path}": ${exception.message}`)
|
|
241
301
|
}
|
|
242
302
|
}
|
|
243
303
|
|
|
@@ -286,7 +346,7 @@ const ALIASES = {
|
|
|
286
346
|
}
|
|
287
347
|
|
|
288
348
|
// Pre-compiled regex for better performance
|
|
289
|
-
const KEY_VALIDATION_REGEX = /^[a-zA-Z0-9\-_]+$/
|
|
349
|
+
const KEY_VALIDATION_REGEX = /^[a-zA-Z0-9\-_:]+$/
|
|
290
350
|
const isKeyValid = (key) => KEY_VALIDATION_REGEX.test(key)
|
|
291
351
|
|
|
292
352
|
const attributes = (options) => {
|
|
@@ -309,7 +369,6 @@ const attributes = (options) => {
|
|
|
309
369
|
result.push(key)
|
|
310
370
|
} else {
|
|
311
371
|
const name = ALIASES[key] || key
|
|
312
|
-
const value = options[key]
|
|
313
372
|
const content = Array.isArray(value) ? classes(...value) : value
|
|
314
373
|
result.push(`${name}="${escapeHTML(content)}"`)
|
|
315
374
|
}
|
|
@@ -330,8 +389,8 @@ const attributes = (options) => {
|
|
|
330
389
|
const left = result.left || "0"
|
|
331
390
|
styles.push(
|
|
332
391
|
`${decamelize(param)}:${escapeHTML(
|
|
333
|
-
`${top} ${right} ${bottom} ${left}
|
|
334
|
-
)}
|
|
392
|
+
`${top} ${right} ${bottom} ${left}`,
|
|
393
|
+
)}`,
|
|
335
394
|
)
|
|
336
395
|
} else if (typeof result === "string" || typeof result === "number") {
|
|
337
396
|
styles.push(`${decamelize(param)}:${escapeHTML(result)}`)
|
|
@@ -377,8 +436,8 @@ const render = (input, escape = true) => {
|
|
|
377
436
|
// Second most common: arrays (~20% of nodes)
|
|
378
437
|
if (Array.isArray(input)) {
|
|
379
438
|
let result = ""
|
|
380
|
-
for (let i = 0
|
|
381
|
-
result += render(input[i])
|
|
439
|
+
for (let i = 0, ilen = input.length; i < ilen; i++) {
|
|
440
|
+
result += render(input[i], escape)
|
|
382
441
|
}
|
|
383
442
|
return result
|
|
384
443
|
}
|
|
@@ -393,11 +452,6 @@ const render = (input, escape = true) => {
|
|
|
393
452
|
return ""
|
|
394
453
|
}
|
|
395
454
|
|
|
396
|
-
// Numbers (~5% of nodes)
|
|
397
|
-
if (typeof input === "number") {
|
|
398
|
-
return input.toString()
|
|
399
|
-
}
|
|
400
|
-
|
|
401
455
|
// Objects (elements) - check ignore flag first
|
|
402
456
|
if (input.ignore) {
|
|
403
457
|
return ""
|
|
@@ -412,12 +466,24 @@ const render = (input, escape = true) => {
|
|
|
412
466
|
return attrs ? `<${input.name} ${attrs}>` : `<${input.name}>`
|
|
413
467
|
}
|
|
414
468
|
|
|
415
|
-
|
|
416
|
-
|
|
469
|
+
if (input.name) {
|
|
470
|
+
const attrs = input.attributes ? attributes(input.attributes) : ""
|
|
471
|
+
const children = render(input.children, !UNESCAPED_TAGS.has(input.name))
|
|
417
472
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
473
|
+
return attrs
|
|
474
|
+
? `<${input.name} ${attrs}>${children}</${input.name}>`
|
|
475
|
+
: `<${input.name}>${children}</${input.name}>`
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (typeof input === "number") {
|
|
479
|
+
return input.toString()
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (typeof input === "object" && input instanceof Date) {
|
|
483
|
+
return input.toString()
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return ""
|
|
421
487
|
}
|
|
422
488
|
|
|
423
489
|
const raw = (children) => {
|
|
@@ -473,9 +539,7 @@ const sanitizeHTML = (content) => {
|
|
|
473
539
|
raw.load = function (path, options = {}) {
|
|
474
540
|
const type = extension(path)
|
|
475
541
|
if (!ALLOWED_RAW_EXTENSIONS.includes(type)) {
|
|
476
|
-
throw new
|
|
477
|
-
`RawError: unsupported raw type "${type}" for path "${path}"`
|
|
478
|
-
)
|
|
542
|
+
throw new RawError(`unsupported raw type "${type}" for path "${path}"`)
|
|
479
543
|
}
|
|
480
544
|
|
|
481
545
|
let content = readFile(path, "utf8")
|
|
@@ -488,22 +552,48 @@ raw.load = function (path, options = {}) {
|
|
|
488
552
|
return raw(content)
|
|
489
553
|
}
|
|
490
554
|
|
|
491
|
-
const tag = (
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
555
|
+
const tag = (tagName, attrsOrChildren, ...restChildren) => {
|
|
556
|
+
// Check if second argument is children (not attributes)
|
|
557
|
+
const isChildrenNotAttributes =
|
|
558
|
+
typeof attrsOrChildren === "string" ||
|
|
559
|
+
typeof attrsOrChildren === "number" ||
|
|
560
|
+
Array.isArray(attrsOrChildren) ||
|
|
561
|
+
(attrsOrChildren &&
|
|
562
|
+
typeof attrsOrChildren === "object" &&
|
|
563
|
+
"name" in attrsOrChildren &&
|
|
564
|
+
"children" in attrsOrChildren)
|
|
565
|
+
|
|
566
|
+
// If we have rest arguments, they must be additional children
|
|
567
|
+
if (restChildren.length > 0) {
|
|
568
|
+
if (isChildrenNotAttributes) {
|
|
569
|
+
// tagName is name, attrsOrChildren is first child, restChildren are more children
|
|
570
|
+
return {
|
|
571
|
+
name: tagName,
|
|
572
|
+
children: [attrsOrChildren, ...restChildren],
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
// tagName is name, attrsOrChildren is attributes, restChildren are children
|
|
576
|
+
return {
|
|
577
|
+
name: tagName,
|
|
578
|
+
attributes: attrsOrChildren,
|
|
579
|
+
children: restChildren,
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// Original two-argument logic
|
|
585
|
+
if (isChildrenNotAttributes) {
|
|
495
586
|
return {
|
|
496
|
-
name,
|
|
497
|
-
children:
|
|
587
|
+
name: tagName,
|
|
588
|
+
children: attrsOrChildren,
|
|
498
589
|
}
|
|
499
590
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const children = typeof c === "number" ? c : c || []
|
|
591
|
+
|
|
592
|
+
// attrsOrChildren is attributes, no children provided
|
|
503
593
|
return {
|
|
504
|
-
name,
|
|
505
|
-
children,
|
|
506
|
-
attributes,
|
|
594
|
+
name: tagName,
|
|
595
|
+
children: [],
|
|
596
|
+
attributes: attrsOrChildren,
|
|
507
597
|
}
|
|
508
598
|
}
|
|
509
599
|
|
|
@@ -578,7 +668,7 @@ function css(inputs) {
|
|
|
578
668
|
}
|
|
579
669
|
}
|
|
580
670
|
|
|
581
|
-
function
|
|
671
|
+
function occurrences(input, string) {
|
|
582
672
|
if (string.length <= 0) {
|
|
583
673
|
return input.length + 1
|
|
584
674
|
}
|
|
@@ -599,8 +689,8 @@ function occurences(input, string) {
|
|
|
599
689
|
}
|
|
600
690
|
|
|
601
691
|
const validateCSS = (content, character1, character2) => {
|
|
602
|
-
const count1 =
|
|
603
|
-
const count2 =
|
|
692
|
+
const count1 = occurrences(content, character1)
|
|
693
|
+
const count2 = occurrences(content, character2)
|
|
604
694
|
if (count1 !== count2) {
|
|
605
695
|
return {
|
|
606
696
|
valid: false,
|
|
@@ -632,7 +722,7 @@ css.load = function (path) {
|
|
|
632
722
|
const content = readFile(file, "utf8")
|
|
633
723
|
const { valid, message } = isCSSValid(content)
|
|
634
724
|
if (!valid) {
|
|
635
|
-
throw new
|
|
725
|
+
throw new CSSError(`invalid CSS for path "${file}": ${message}`)
|
|
636
726
|
}
|
|
637
727
|
return css`
|
|
638
728
|
${content}
|
|
@@ -689,7 +779,10 @@ js.load = function (path, options = {}) {
|
|
|
689
779
|
return { js: tag("script", attributes, content) }
|
|
690
780
|
}
|
|
691
781
|
|
|
692
|
-
const node =
|
|
782
|
+
const node =
|
|
783
|
+
(name) =>
|
|
784
|
+
(options, ...children) =>
|
|
785
|
+
tag(name, options, ...children)
|
|
693
786
|
const Doctype = node("!DOCTYPE html")
|
|
694
787
|
|
|
695
788
|
const nodes = [
|
|
@@ -864,9 +957,7 @@ function base64({ content, path }) {
|
|
|
864
957
|
nodes.Img.load = function (path) {
|
|
865
958
|
const type = extension(path)
|
|
866
959
|
if (!ALLOWED_IMAGE_EXTENSIONS.includes(type)) {
|
|
867
|
-
throw new
|
|
868
|
-
`ImageError: unsupported image type "${type}" for path "${path}"`
|
|
869
|
-
)
|
|
960
|
+
throw new ImageError(`unsupported image type "${type}" for path "${path}"`)
|
|
870
961
|
}
|
|
871
962
|
const content = readFile(path, "base64")
|
|
872
963
|
return (options) => {
|
|
@@ -919,9 +1010,7 @@ const sanitizeSVG = (content) => {
|
|
|
919
1010
|
nodes.Svg.load = function (path, options = {}) {
|
|
920
1011
|
const type = extension(path)
|
|
921
1012
|
if (type !== "svg") {
|
|
922
|
-
throw new
|
|
923
|
-
`SVGError: unsupported SVG type "${type}" for path "${path}"`
|
|
924
|
-
)
|
|
1013
|
+
throw new SVGError(`unsupported SVG type "${type}" for path "${path}"`)
|
|
925
1014
|
}
|
|
926
1015
|
let content = readFile(path, "utf8")
|
|
927
1016
|
if (options.sanitize !== false) {
|
|
@@ -961,15 +1050,29 @@ const json = {
|
|
|
961
1050
|
try {
|
|
962
1051
|
return JSON.parse(content)
|
|
963
1052
|
} catch (exception) {
|
|
964
|
-
throw new
|
|
965
|
-
`JSONError: cannot parse file "${file}": ${exception.message}`
|
|
966
|
-
)
|
|
1053
|
+
throw new JSONError(`cannot parse file "${file}": ${exception.message}`)
|
|
967
1054
|
}
|
|
968
1055
|
},
|
|
969
1056
|
}
|
|
970
1057
|
|
|
971
1058
|
function i18n(translations) {
|
|
972
1059
|
return function translate(language, key) {
|
|
1060
|
+
if (key === undefined) {
|
|
1061
|
+
throw new TranslationError("key is undefined")
|
|
1062
|
+
}
|
|
1063
|
+
if (language === undefined) {
|
|
1064
|
+
throw new TranslationError("language is undefined")
|
|
1065
|
+
}
|
|
1066
|
+
if (translations[key] === undefined) {
|
|
1067
|
+
throw new TranslationError(
|
|
1068
|
+
`translation [${key}][${language}] is undefined`,
|
|
1069
|
+
)
|
|
1070
|
+
}
|
|
1071
|
+
if (translations[key][language] === undefined) {
|
|
1072
|
+
throw new TranslationError(
|
|
1073
|
+
`translation [${key}][${language}] is undefined`,
|
|
1074
|
+
)
|
|
1075
|
+
}
|
|
973
1076
|
return translations[key][language]
|
|
974
1077
|
}
|
|
975
1078
|
}
|
|
@@ -988,14 +1091,14 @@ i18n.load = function (path, options = {}) {
|
|
|
988
1091
|
|
|
989
1092
|
return function translate(language, key) {
|
|
990
1093
|
if (!language) {
|
|
991
|
-
throw new
|
|
1094
|
+
throw new TranslationError(`language is undefined`)
|
|
992
1095
|
}
|
|
993
1096
|
if (!key) {
|
|
994
|
-
throw new
|
|
1097
|
+
throw new TranslationError(`key is undefined`)
|
|
995
1098
|
}
|
|
996
1099
|
if (!data[key] || !data[key][language]) {
|
|
997
|
-
throw new
|
|
998
|
-
`
|
|
1100
|
+
throw new TranslationError(
|
|
1101
|
+
`translation [${key}][${language}] is undefined`,
|
|
999
1102
|
)
|
|
1000
1103
|
}
|
|
1001
1104
|
return data[key][language]
|
|
@@ -1009,20 +1112,20 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
1009
1112
|
}
|
|
1010
1113
|
if (i18n) {
|
|
1011
1114
|
if (!a || !a.language) {
|
|
1012
|
-
throw new
|
|
1013
|
-
`
|
|
1115
|
+
throw new TranslationError(
|
|
1116
|
+
`language is undefined for component:\n${fn.toString()}`,
|
|
1014
1117
|
)
|
|
1015
1118
|
}
|
|
1016
1119
|
const { language } = a
|
|
1017
1120
|
function translate(key) {
|
|
1018
1121
|
if (!key) {
|
|
1019
|
-
throw new
|
|
1020
|
-
`
|
|
1122
|
+
throw new TranslationError(
|
|
1123
|
+
`key is undefined for component:\n${fn.toString()}`,
|
|
1021
1124
|
)
|
|
1022
1125
|
}
|
|
1023
1126
|
if (!i18n[key] || !i18n[key][language]) {
|
|
1024
|
-
throw new
|
|
1025
|
-
`
|
|
1127
|
+
throw new TranslationError(
|
|
1128
|
+
`translation [${key}][${language}] is undefined for component:\n${fn.toString()}`,
|
|
1026
1129
|
)
|
|
1027
1130
|
}
|
|
1028
1131
|
const translation = i18n[key][language]
|
|
@@ -1038,11 +1141,27 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
1038
1141
|
|
|
1039
1142
|
if (styles) {
|
|
1040
1143
|
const data = Array.isArray(styles) ? styles : [styles]
|
|
1144
|
+
data.forEach((style, index) => {
|
|
1145
|
+
if (!style || typeof style !== "object" || !style.css) {
|
|
1146
|
+
throw new ComponentError(
|
|
1147
|
+
`Invalid style object at index ${index}: missing .css property. ` +
|
|
1148
|
+
`Styles must be created using the css\`...\` template tag or css.load() function.`,
|
|
1149
|
+
)
|
|
1150
|
+
}
|
|
1151
|
+
})
|
|
1041
1152
|
nodes = nodes.concat(data.map((style) => style.css))
|
|
1042
1153
|
}
|
|
1043
1154
|
|
|
1044
1155
|
if (scripts) {
|
|
1045
1156
|
const data = Array.isArray(scripts) ? scripts : [scripts]
|
|
1157
|
+
data.forEach((script, index) => {
|
|
1158
|
+
if (!script || typeof script !== "object" || !script.js) {
|
|
1159
|
+
throw new ComponentError(
|
|
1160
|
+
`Invalid script object at index ${index}: missing .js property. ` +
|
|
1161
|
+
`Scripts must be created using the js\`...\` template tag or js.load() function.`,
|
|
1162
|
+
)
|
|
1163
|
+
}
|
|
1164
|
+
})
|
|
1046
1165
|
nodes = nodes.concat(data.map((script) => script.js))
|
|
1047
1166
|
}
|
|
1048
1167
|
|
|
@@ -1062,5 +1181,13 @@ module.exports = {
|
|
|
1062
1181
|
json,
|
|
1063
1182
|
tag,
|
|
1064
1183
|
i18n,
|
|
1184
|
+
TranslationError,
|
|
1185
|
+
ComponentError,
|
|
1186
|
+
FileError,
|
|
1187
|
+
RawError,
|
|
1188
|
+
CSSError,
|
|
1189
|
+
ImageError,
|
|
1190
|
+
SVGError,
|
|
1191
|
+
JSONError,
|
|
1065
1192
|
...nodes,
|
|
1066
1193
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "boxwood",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Compile HTML templates into JS",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"homepage": "https://github.com/buxlabs/boxwood#readme",
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"benchmark": "2.1.4",
|
|
50
|
-
"c8": "^
|
|
50
|
+
"c8": "^11.0.0",
|
|
51
51
|
"express": "^5.2.1",
|
|
52
52
|
"handlebars": "^4.7.8",
|
|
53
|
-
"jsdom": "^
|
|
53
|
+
"jsdom": "^28.1.0",
|
|
54
54
|
"mustache": "^4.2.0",
|
|
55
|
-
"underscore": "^1.13.
|
|
55
|
+
"underscore": "^1.13.8"
|
|
56
56
|
},
|
|
57
57
|
"standard": {
|
|
58
58
|
"ignore": [
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
]
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"css-tree": "^3.1
|
|
65
|
+
"css-tree": "^3.2.1"
|
|
66
66
|
},
|
|
67
67
|
"prettier": {
|
|
68
68
|
"semi": false
|
package/ui/center/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { css, component, Div } = require("../..")
|
|
2
2
|
|
|
3
|
-
function Center({ className, style, height, width } = {}, children) {
|
|
3
|
+
function Center({ className, id, style, height, width } = {}, children) {
|
|
4
4
|
const styleObject = {
|
|
5
5
|
display: "flex",
|
|
6
6
|
"justify-content": "center",
|
|
@@ -17,7 +17,7 @@ function Center({ className, style, height, width } = {}, children) {
|
|
|
17
17
|
`
|
|
18
18
|
|
|
19
19
|
return [
|
|
20
|
-
Div({ className: [className, styles.center], style }, children),
|
|
20
|
+
Div({ className: [className, styles.center], id, style }, children),
|
|
21
21
|
styles.css,
|
|
22
22
|
]
|
|
23
23
|
}
|
package/ui/container/index.js
CHANGED
|
@@ -16,7 +16,7 @@ const normalizeValue = (value) => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function Container(
|
|
19
|
-
{ className, style, width = 1200, padding = 16 } = {},
|
|
19
|
+
{ className, style, id, width = 1200, padding = 16 } = {},
|
|
20
20
|
children
|
|
21
21
|
) {
|
|
22
22
|
width = normalizeValue(width)
|
|
@@ -39,7 +39,7 @@ function Container(
|
|
|
39
39
|
}
|
|
40
40
|
`
|
|
41
41
|
return [
|
|
42
|
-
Div({ className: [styles.container, className], style }, children),
|
|
42
|
+
Div({ className: [styles.container, className], id, style }, children),
|
|
43
43
|
styles.css,
|
|
44
44
|
]
|
|
45
45
|
}
|
package/ui/grid/index.js
CHANGED
|
@@ -8,7 +8,10 @@ const BREAKPOINTS = {
|
|
|
8
8
|
sm: "575px",
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function Grid(
|
|
11
|
+
function Grid(
|
|
12
|
+
{ className, columns = 3, gap, id, breakpoint, style },
|
|
13
|
+
children
|
|
14
|
+
) {
|
|
12
15
|
gap = normalizeGap(gap)
|
|
13
16
|
breakpoint = normalizeBreakpoint(breakpoint)
|
|
14
17
|
|
|
@@ -55,7 +58,7 @@ function Grid({ className, columns = 3, gap, breakpoint, style }, children) {
|
|
|
55
58
|
`
|
|
56
59
|
|
|
57
60
|
return [
|
|
58
|
-
Div({ className: [styles.grid, className], style }, children),
|
|
61
|
+
Div({ className: [styles.grid, className], id, style }, children),
|
|
59
62
|
styles.css,
|
|
60
63
|
]
|
|
61
64
|
}
|
package/ui/group/index.js
CHANGED
|
@@ -8,7 +8,18 @@ const {
|
|
|
8
8
|
} = require("../normalize")
|
|
9
9
|
|
|
10
10
|
function Group(
|
|
11
|
-
{
|
|
11
|
+
{
|
|
12
|
+
align,
|
|
13
|
+
className,
|
|
14
|
+
breakpoint,
|
|
15
|
+
id,
|
|
16
|
+
justify,
|
|
17
|
+
gap,
|
|
18
|
+
width,
|
|
19
|
+
margin,
|
|
20
|
+
padding,
|
|
21
|
+
style,
|
|
22
|
+
},
|
|
12
23
|
children
|
|
13
24
|
) {
|
|
14
25
|
gap = normalizeGap(gap)
|
|
@@ -43,7 +54,7 @@ function Group(
|
|
|
43
54
|
`
|
|
44
55
|
|
|
45
56
|
return [
|
|
46
|
-
Div({ className: [styles.group, className], style }, children),
|
|
57
|
+
Div({ className: [styles.group, className], id, style }, children),
|
|
47
58
|
styles.css,
|
|
48
59
|
]
|
|
49
60
|
}
|
package/ui/markdown/index.js
CHANGED
|
@@ -11,29 +11,31 @@ function Markdown(params, children) {
|
|
|
11
11
|
return lines.map((line) => {
|
|
12
12
|
if (line.startsWith("# ")) {
|
|
13
13
|
const text = line.substring(2)
|
|
14
|
-
return H1(text)
|
|
14
|
+
return H1(params, text)
|
|
15
15
|
} else if (line.startsWith("## ")) {
|
|
16
16
|
const text = line.substring(3)
|
|
17
|
-
return H2(text)
|
|
17
|
+
return H2(params, text)
|
|
18
18
|
} else if (line.startsWith("### ")) {
|
|
19
19
|
const text = line.substring(4)
|
|
20
|
-
return H3(text)
|
|
20
|
+
return H3(params, text)
|
|
21
21
|
} else if (line.startsWith("#### ")) {
|
|
22
22
|
const text = line.substring(5)
|
|
23
|
-
return H4(text)
|
|
23
|
+
return H4(params, text)
|
|
24
24
|
} else if (line.startsWith("##### ")) {
|
|
25
25
|
const text = line.substring(6)
|
|
26
|
-
return H5(text)
|
|
26
|
+
return H5(params, text)
|
|
27
27
|
} else if (line.startsWith("###### ")) {
|
|
28
28
|
const text = line.substring(7)
|
|
29
|
-
return H6(text)
|
|
29
|
+
return H6(params, text)
|
|
30
30
|
} else if (line.startsWith("> ")) {
|
|
31
31
|
const text = line.substring(2)
|
|
32
|
-
return Blockquote(text)
|
|
32
|
+
return Blockquote(params, text)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
return P(line)
|
|
35
|
+
return P(params, line)
|
|
36
36
|
})
|
|
37
|
+
} else {
|
|
38
|
+
return null
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
|
package/ui/stack/index.js
CHANGED
|
@@ -7,7 +7,7 @@ const {
|
|
|
7
7
|
} = require("../normalize")
|
|
8
8
|
|
|
9
9
|
function Stack(
|
|
10
|
-
{ align, className, justify, gap, width, margin, padding, style },
|
|
10
|
+
{ align, className, id, justify, gap, width, margin, padding, style },
|
|
11
11
|
children
|
|
12
12
|
) {
|
|
13
13
|
gap = normalizeGap(gap)
|
|
@@ -36,7 +36,7 @@ function Stack(
|
|
|
36
36
|
`
|
|
37
37
|
|
|
38
38
|
return [
|
|
39
|
-
Div({ className: [styles.stack, className], style }, children),
|
|
39
|
+
Div({ className: [styles.stack, className], id, style }, children),
|
|
40
40
|
styles.css,
|
|
41
41
|
]
|
|
42
42
|
}
|