boxwood 2.14.0 → 2.16.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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boxwood",
3
- "version": "2.14.0",
3
+ "version": "2.16.0",
4
4
  "description": "Compile HTML templates into JS",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -1,23 +1,18 @@
1
1
  const nodes = require("../..")
2
2
  const { component } = nodes
3
3
 
4
- const { extractHtmlParams } = require("./utilities/params")
4
+ const { extractHtmlParams, mergeComponents } = require("./utilities/params")
5
5
  const { parseMarkdownLines } = require("./utilities/parseBlock")
6
6
  const { convertItemsToNodes } = require("./utilities/convertNodes")
7
7
 
8
- const COMPONENTS = {
8
+ // Basic HTML components needed for markdown formatting (links, images, code, etc.)
9
+ const BASIC_HTML_COMPONENTS = {
9
10
  h1: nodes.H1,
10
11
  h2: nodes.H2,
11
12
  h3: nodes.H3,
12
13
  h4: nodes.H4,
13
14
  h5: nodes.H5,
14
15
  h6: nodes.H6,
15
- blockquote: nodes.Blockquote,
16
- hr: nodes.Hr,
17
- }
18
-
19
- // Basic HTML components needed for markdown formatting (links, images, code, etc.)
20
- const BASIC_HTML_COMPONENTS = {
21
16
  a: nodes.A,
22
17
  img: nodes.Img,
23
18
  code: nodes.Code,
@@ -45,6 +40,9 @@ function Markdown(params, children) {
45
40
 
46
41
  const htmlParams = extractHtmlParams(params)
47
42
 
43
+ // Merge basic HTML components - all components are now in one place
44
+ const allComponents = mergeComponents(BASIC_HTML_COMPONENTS, null)
45
+
48
46
  // Parse all markdown lines into structured items (no custom components, no data)
49
47
  const items = parseMarkdownLines(children, null, null)
50
48
 
@@ -54,8 +52,7 @@ function Markdown(params, children) {
54
52
  params,
55
53
  htmlParams,
56
54
  null, // no data
57
- BASIC_HTML_COMPONENTS, // basic HTML components for formatting
58
- COMPONENTS,
55
+ allComponents,
59
56
  Markdown,
60
57
  )
61
58
  }
@@ -121,7 +121,6 @@ function convertItemsToNodes(
121
121
  htmlParams,
122
122
  data,
123
123
  allComponents,
124
- components,
125
124
  markdownRenderer,
126
125
  ) {
127
126
  const result = []
@@ -174,7 +173,7 @@ function convertItemsToNodes(
174
173
  } else {
175
174
  // Regular block elements (h1-h6, p, etc.)
176
175
  const { type, content } = item
177
- const Component = components[type] || allComponents.p
176
+ const Component = allComponents[type] || allComponents.p
178
177
  const processedContent = replaceVariables(content, data)
179
178
  result.push(
180
179
  Component(htmlParams, format(processedContent, allComponents)),
package/ui/prose/index.js CHANGED
@@ -1,23 +1,18 @@
1
1
  const nodes = require("../..")
2
2
  const { component } = nodes
3
3
 
4
+ const Center = require("../center")
5
+ const Container = require("../container")
6
+ const Grid = require("../grid")
7
+ const Group = require("../group")
8
+ const Stack = require("../stack")
9
+
4
10
  const { extractHtmlParams, mergeComponents } = require("./utilities/params")
5
11
  const { parseMarkdownLines } = require("./utilities/parseBlock")
6
12
  const { convertItemsToNodes } = require("./utilities/convertNodes")
7
13
  const { processConditionals } = require("./utilities/processConditionals")
8
14
  const { processLoops } = require("./utilities/processLoops")
9
15
 
10
- const COMPONENTS = {
11
- h1: nodes.H1,
12
- h2: nodes.H2,
13
- h3: nodes.H3,
14
- h4: nodes.H4,
15
- h5: nodes.H5,
16
- h6: nodes.H6,
17
- blockquote: nodes.Blockquote,
18
- hr: nodes.Hr,
19
- }
20
-
21
16
  // Safe builtin HTML tags that can be used as custom components in markdown
22
17
  // These are always available and don't need to be explicitly passed in params.components
23
18
  const SAFE_TAG_NAMES = [
@@ -112,6 +107,18 @@ const BUILTIN_HTML_TAGS = SAFE_TAG_NAMES.reduce((acc, tagName) => {
112
107
  return acc
113
108
  }, {})
114
109
 
110
+ // Add built-in UI components
111
+ const BUILTIN_UI_COMPONENTS = {
112
+ Center,
113
+ Container,
114
+ Grid,
115
+ Group,
116
+ Stack,
117
+ }
118
+
119
+ // Merge HTML tags and UI components
120
+ const BUILTIN_COMPONENTS = { ...BUILTIN_HTML_TAGS, ...BUILTIN_UI_COMPONENTS }
121
+
115
122
  function Prose(params, children) {
116
123
  // Handle array of children recursively
117
124
  if (Array.isArray(children)) {
@@ -125,7 +132,7 @@ function Prose(params, children) {
125
132
 
126
133
  const customComponents = params && params.components
127
134
  const data = params && params.data
128
- const allComponents = mergeComponents(BUILTIN_HTML_TAGS, customComponents)
135
+ const allComponents = mergeComponents(BUILTIN_COMPONENTS, customComponents)
129
136
  const htmlParams = extractHtmlParams(params)
130
137
 
131
138
  // Process {#each}...{/each} loop blocks first
@@ -145,7 +152,6 @@ function Prose(params, children) {
145
152
  htmlParams,
146
153
  data,
147
154
  allComponents,
148
- COMPONENTS,
149
155
  Prose,
150
156
  )
151
157
  }
@@ -121,7 +121,6 @@ function convertItemsToNodes(
121
121
  htmlParams,
122
122
  data,
123
123
  allComponents,
124
- components,
125
124
  markdownRenderer,
126
125
  ) {
127
126
  const result = []
@@ -174,7 +173,7 @@ function convertItemsToNodes(
174
173
  } else {
175
174
  // Regular block elements (h1-h6, p, etc.)
176
175
  const { type, content } = item
177
- const Component = components[type] || allComponents.p
176
+ const Component = allComponents[type] || allComponents.p
178
177
  const processedContent = replaceVariables(content, data)
179
178
  result.push(
180
179
  Component(htmlParams, format(processedContent, allComponents)),
@@ -1,3 +1,5 @@
1
+ const { resolvePath } = require("./replaceVariables")
2
+
1
3
  /**
2
4
  * Parse a custom component tag from markdown
3
5
  * Supports both <Component attr="value"> and <Component attr={variable}>
@@ -157,7 +159,19 @@ function parseAttributes(attributesStr) {
157
159
  i++
158
160
  }
159
161
  }
160
- attributes[name] = value
162
+
163
+ // Check if the entire quoted value is a variable reference: "{variable}"
164
+ if (value.startsWith("{") && value.endsWith("}")) {
165
+ const variableName = value.substring(1, value.length - 1).trim()
166
+ if (variableName) {
167
+ attributes[name] = { __variable: variableName }
168
+ } else {
169
+ attributes[name] = value
170
+ }
171
+ } else {
172
+ attributes[name] = value
173
+ }
174
+
161
175
  if (i < str.length) i++ // Skip closing quote
162
176
  } else if (str[i] === "{") {
163
177
  // Variable reference
@@ -197,12 +211,10 @@ function resolveAttributes(attributes, data) {
197
211
  const resolved = {}
198
212
  for (const [key, value] of Object.entries(attributes)) {
199
213
  if (value && typeof value === "object" && value.__variable) {
200
- // Resolve variable
201
- const variableName = value.__variable
202
- resolved[key] =
203
- data && data[variableName] !== undefined
204
- ? data[variableName]
205
- : undefined
214
+ // Resolve variable using resolvePath to support complex paths
215
+ const variablePath = value.__variable
216
+ const resolvedValue = resolvePath(data, variablePath)
217
+ resolved[key] = resolvedValue
206
218
  } else {
207
219
  resolved[key] = value
208
220
  }
@@ -5,6 +5,11 @@
5
5
  * @returns {*} - The resolved value or undefined
6
6
  */
7
7
  function resolvePath(data, path) {
8
+ // Handle null or undefined data
9
+ if (data === null || data === undefined) {
10
+ return undefined
11
+ }
12
+
8
13
  // Handle simple variable names (backwards compatibility)
9
14
  if (!/[.\[]/.test(path)) {
10
15
  return data[path]