boxwood 2.13.0 → 2.14.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 +2 -3
- package/ui/grid/index.js +2 -5
- package/ui/index.js +2 -0
- package/ui/markdown/README.md +48 -0
- package/ui/markdown/index.js +45 -314
- package/ui/markdown/utilities/convertNodes.js +194 -0
- package/ui/markdown/utilities/format.js +15 -12
- package/ui/markdown/utilities/params.js +29 -0
- package/ui/markdown/utilities/parseBlock.js +284 -0
- package/ui/markdown/utilities/parseCustomTag.js +20 -0
- package/ui/markdown/utilities/replaceVariables.js +39 -4
- package/ui/normalize.js +1 -1
- package/ui/prose/README.md +492 -0
- package/ui/prose/index.js +153 -0
- package/ui/prose/utilities/brackets.js +21 -0
- package/ui/prose/utilities/convertNodes.js +194 -0
- package/ui/prose/utilities/format.js +184 -0
- package/ui/prose/utilities/params.js +29 -0
- package/ui/prose/utilities/parseBlock.js +284 -0
- package/ui/prose/utilities/parseCustomTag.js +218 -0
- package/ui/prose/utilities/processConditionals.js +264 -0
- package/ui/prose/utilities/processLoops.js +171 -0
- package/ui/prose/utilities/replaceVariables.js +115 -0
- package/examples/typescript-example.ts +0 -49
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a path like "images[0].src" or "user.name" from a data object
|
|
3
|
+
* @param {Object} data - The data object to resolve the path from
|
|
4
|
+
* @param {string} path - The path to resolve (e.g., "images[0].src", "user.name")
|
|
5
|
+
* @returns {*} - The resolved value or undefined
|
|
6
|
+
*/
|
|
7
|
+
function resolvePath(data, path) {
|
|
8
|
+
// Handle simple variable names (backwards compatibility)
|
|
9
|
+
if (!/[.\[]/.test(path)) {
|
|
10
|
+
return data[path]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Split the path into parts, handling both dot notation and bracket notation
|
|
14
|
+
// e.g., "images[0].src" -> ["images", "0", "src"]
|
|
15
|
+
const parts = path
|
|
16
|
+
.replace(/\[(\d+)\]/g, ".$1") // Convert [0] to .0
|
|
17
|
+
.split(".")
|
|
18
|
+
.filter(Boolean)
|
|
19
|
+
|
|
20
|
+
let current = data
|
|
21
|
+
for (const part of parts) {
|
|
22
|
+
if (current === null || current === undefined) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
current = current[part]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return current
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Replace {variableName} placeholders in text with actual values from data
|
|
33
|
+
* Supports:
|
|
34
|
+
* - Simple variables: {name}
|
|
35
|
+
* - Array indexing: {images[0]}
|
|
36
|
+
* - Property access: {user.name}
|
|
37
|
+
* - Combined: {images[0].src}
|
|
38
|
+
* @param {string} text - Text containing variable placeholders
|
|
39
|
+
* @param {Object} data - Data object with variable values
|
|
40
|
+
* @returns {string|Array} - Text with variables replaced, or array if mixed content
|
|
41
|
+
*/
|
|
42
|
+
function replaceVariables(text, data) {
|
|
43
|
+
if (!text || typeof text !== "string") {
|
|
44
|
+
return text
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!data || typeof data !== "object") {
|
|
48
|
+
return text
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if text contains any variables
|
|
52
|
+
if (!text.includes("{") || !text.includes("}")) {
|
|
53
|
+
return text
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const result = []
|
|
57
|
+
let i = 0
|
|
58
|
+
let lastIndex = 0
|
|
59
|
+
|
|
60
|
+
while (i < text.length) {
|
|
61
|
+
if (text[i] === "\\" && text[i + 1] === "{") {
|
|
62
|
+
// Escaped opening brace
|
|
63
|
+
result.push(text.substring(lastIndex, i))
|
|
64
|
+
result.push("{")
|
|
65
|
+
i += 2
|
|
66
|
+
lastIndex = i
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (text[i] === "{") {
|
|
71
|
+
const closeIndex = text.indexOf("}", i + 1)
|
|
72
|
+
|
|
73
|
+
if (closeIndex !== -1) {
|
|
74
|
+
// Found a variable placeholder
|
|
75
|
+
const variablePath = text.substring(i + 1, closeIndex).trim()
|
|
76
|
+
|
|
77
|
+
if (variablePath) {
|
|
78
|
+
// Add text before the variable
|
|
79
|
+
if (i > lastIndex) {
|
|
80
|
+
result.push(text.substring(lastIndex, i))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Resolve the variable value (supports paths like "images[0].src")
|
|
84
|
+
const value = resolvePath(data, variablePath)
|
|
85
|
+
if (value !== undefined && value !== null) {
|
|
86
|
+
result.push(String(value))
|
|
87
|
+
} else {
|
|
88
|
+
// Variable not found, keep the placeholder
|
|
89
|
+
result.push(text.substring(i, closeIndex + 1))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
i = closeIndex + 1
|
|
93
|
+
lastIndex = i
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
i++
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Add remaining text
|
|
103
|
+
if (lastIndex < text.length) {
|
|
104
|
+
result.push(text.substring(lastIndex))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// If no substitutions were made, return original text
|
|
108
|
+
if (result.length === 0) {
|
|
109
|
+
return text
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return result.join("")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = { replaceVariables, resolvePath }
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// Example of using boxwood with TypeScript
|
|
2
|
-
import { Div, H1, Button, Form, Input, component, classes } from 'boxwood';
|
|
3
|
-
|
|
4
|
-
// Define typed component props
|
|
5
|
-
interface UserCardProps {
|
|
6
|
-
name: string;
|
|
7
|
-
email: string;
|
|
8
|
-
isActive: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// Create a typed component
|
|
12
|
-
const UserCard = component<UserCardProps>(
|
|
13
|
-
({ name, email, isActive }, children) => {
|
|
14
|
-
return Div({
|
|
15
|
-
className: classes('user-card', { active: isActive })
|
|
16
|
-
}, [
|
|
17
|
-
H1({}, name),
|
|
18
|
-
Div({ className: 'email' }, email),
|
|
19
|
-
children
|
|
20
|
-
]);
|
|
21
|
-
}
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
// Use the component with type checking
|
|
25
|
-
const app = Div({ id: 'app' }, [
|
|
26
|
-
UserCard({
|
|
27
|
-
name: 'John Doe',
|
|
28
|
-
email: 'john@example.com',
|
|
29
|
-
isActive: true
|
|
30
|
-
},
|
|
31
|
-
Button({ onclick: () => alert('Hello!') }, 'Click me')
|
|
32
|
-
),
|
|
33
|
-
|
|
34
|
-
Form({ method: 'post' }, [
|
|
35
|
-
Input({
|
|
36
|
-
type: 'email',
|
|
37
|
-
name: 'email',
|
|
38
|
-
required: true,
|
|
39
|
-
placeholder: 'Enter email'
|
|
40
|
-
}),
|
|
41
|
-
Button({ type: 'submit' }, 'Submit')
|
|
42
|
-
])
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
// TypeScript will provide:
|
|
46
|
-
// - Autocomplete for all element attributes
|
|
47
|
-
// - Type checking for attribute values
|
|
48
|
-
// - Error highlighting for invalid props
|
|
49
|
-
// - IntelliSense documentation
|