@rokkit/core 1.0.0-next.94 → 1.0.0-next.96

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": "@rokkit/core",
3
- "version": "1.0.0-next.94",
3
+ "version": "1.0.0-next.96",
4
4
  "description": "Core components, actions and stores for svelte apps.",
5
5
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
6
  "license": "MIT",
@@ -12,21 +12,22 @@
12
12
  "access": "public"
13
13
  },
14
14
  "devDependencies": {
15
- "@sveltejs/vite-plugin-svelte": "^3.0.2",
16
- "@testing-library/svelte": "^4.1.0",
17
- "@types/ramda": "^0.29.12",
18
- "@vitest/coverage-v8": "^1.4.0",
19
- "@vitest/ui": "~1.4.0",
20
- "jsdom": "^24.0.0",
21
- "svelte": "^4.2.12",
22
- "typescript": "^5.4.4",
23
- "vite": "^5.2.8",
24
- "vitest": "~1.4.0",
25
- "shared-config": "1.0.0-next.94",
26
- "validators": "1.0.0-next.94"
15
+ "@sveltejs/vite-plugin-svelte": "^3.1.1",
16
+ "@testing-library/svelte": "^5.1.0",
17
+ "@types/ramda": "^0.30.0",
18
+ "@vitest/coverage-v8": "^1.6.0",
19
+ "@vitest/ui": "~1.6.0",
20
+ "jsdom": "^24.1.0",
21
+ "svelte": "^4.2.17",
22
+ "typescript": "^5.4.5",
23
+ "vite": "^5.2.12",
24
+ "vitest": "~1.6.0",
25
+ "shared-config": "1.0.0-next.96",
26
+ "validators": "1.0.0-next.96"
27
27
  },
28
28
  "files": [
29
29
  "src/**/*.js",
30
+ "src/**/*.json",
30
31
  "src/**/*.svelte",
31
32
  "!spec"
32
33
  ],
@@ -35,14 +36,14 @@
35
36
  "./package.json": "./package.json",
36
37
  "./constants": "./src/constants.js",
37
38
  ".": {
38
- "types": "./dist/types.d.ts",
39
+ "types": "./dist/index.d.ts",
39
40
  "import": "./src/index.js",
40
41
  "svelte": "./src/index.js"
41
42
  }
42
43
  },
43
44
  "dependencies": {
44
45
  "date-fns": "^3.6.0",
45
- "ramda": "^0.29.1"
46
+ "ramda": "^0.30.1"
46
47
  },
47
48
  "scripts": {
48
49
  "format": "prettier --write .",
@@ -0,0 +1,42 @@
1
+ {
2
+ "one-dark": {
3
+ "dark": {
4
+ "--tab-size": "2",
5
+ "--code-fill": "var(--neutral-100)",
6
+ "--code-normal": "#e06c75",
7
+ "--code-string": "#98c379",
8
+ "--code-number": "#d19a66",
9
+ "--code-atrule": "var(--code-string)",
10
+ "--code-keyword": "#c678dd",
11
+ "--code-comment": "#5c6370",
12
+ "--code-property": "#d19a66",
13
+ "--code-selector": "var(--code-keyword)",
14
+ "--code-operator": "#56b6c2",
15
+ "--code-function": "#61afef",
16
+ "--code-gutter-marker": "black",
17
+ "--code-gutter-subtle": "#999",
18
+ "--code-cursor": "#24292e",
19
+ "--code-cursor-block": "rgba(20, 255, 20, 0.5)",
20
+ "--code-linenumbers": "rgba(27, 31, 35, 0.3)"
21
+ },
22
+ "light": {
23
+ "--tab-size": "2",
24
+ "--code-fill": "var(--neutral-100)",
25
+ "--code-normal": "#333333",
26
+ "--code-string": "#9D8248",
27
+ "--code-number": "#71A15D",
28
+ "--code-atrule": "var(--code-string)",
29
+ "--code-keyword": "#3080B5",
30
+ "--code-comment": "#969896",
31
+ "--code-property": "#63a35c",
32
+ "--code-selector": "var(--code-keyword)",
33
+ "--code-operator": "#bf5625",
34
+ "--code-function": "#a71d5d",
35
+ "--code-gutter-marker": "black",
36
+ "--code-gutter-subtle": "#999",
37
+ "--code-cursor": "#24292e",
38
+ "--code-cursor-block": "rgba(20, 255, 20, 0.5)",
39
+ "--code-linenumbers": "rgba(27, 31, 35, 0.3)"
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,289 @@
1
+ {
2
+ "amber": {
3
+ "50": "#fffbeb",
4
+ "100": "#fef3c7",
5
+ "200": "#fde68a",
6
+ "300": "#fcd34d",
7
+ "400": "#fbbf24",
8
+ "500": "#f59e0b",
9
+ "600": "#d97706",
10
+ "700": "#b45309",
11
+ "800": "#92400e",
12
+ "900": "#78350f",
13
+ "950": "#451a03"
14
+ },
15
+ "blue": {
16
+ "50": "#eff6ff",
17
+ "100": "#dbeafe",
18
+ "200": "#bfdbfe",
19
+ "300": "#93c5fd",
20
+ "400": "#60a5fa",
21
+ "500": "#3b82f6",
22
+ "600": "#2563eb",
23
+ "700": "#1d4ed8",
24
+ "800": "#1e40af",
25
+ "900": "#1e3a8a",
26
+ "950": "#172554"
27
+ },
28
+ "cyan": {
29
+ "50": "#ecfeff",
30
+ "100": "#cffafe",
31
+ "200": "#a5f3fc",
32
+ "300": "#67e8f9",
33
+ "400": "#22d3ee",
34
+ "500": "#06b6d4",
35
+ "600": "#0891b2",
36
+ "700": "#0e7490",
37
+ "800": "#155e75",
38
+ "900": "#164e63",
39
+ "950": "#083344"
40
+ },
41
+ "emerald": {
42
+ "50": "#ecfdf5",
43
+ "100": "#d1fae5",
44
+ "200": "#a7f3d0",
45
+ "300": "#6ee7b7",
46
+ "400": "#34d399",
47
+ "500": "#10b981",
48
+ "600": "#059669",
49
+ "700": "#047857",
50
+ "800": "#065f46",
51
+ "900": "#064e3b",
52
+ "950": "#022c22"
53
+ },
54
+ "fuscia": {
55
+ "50": "#fdf4ff",
56
+ "100": "#fae8ff",
57
+ "200": "#f5d0fe",
58
+ "300": "#f0abfc",
59
+ "400": "#e879f9",
60
+ "500": "#d946ef",
61
+ "600": "#c026d3",
62
+ "700": "#a21caf",
63
+ "800": "#86198f",
64
+ "900": "#701a75",
65
+ "950": "#4a044e"
66
+ },
67
+ "gray": {
68
+ "50": "#f9fafb",
69
+ "100": "#f3f4f6",
70
+ "200": "#e5e7eb",
71
+ "300": "#d1d5db",
72
+ "400": "#9ca3af",
73
+ "500": "#6b7280",
74
+ "600": "#4b5563",
75
+ "700": "#374151",
76
+ "800": "#1f2937",
77
+ "900": "#111827",
78
+ "950": "#00060c"
79
+ },
80
+ "green": {
81
+ "50": "#f0fdf4",
82
+ "100": "#dcfce7",
83
+ "200": "#bbf7d0",
84
+ "300": "#86efac",
85
+ "400": "#4ade80",
86
+ "500": "#22c55e",
87
+ "600": "#16a34a",
88
+ "700": "#15803d",
89
+ "800": "#166534",
90
+ "900": "#14532d",
91
+ "950": "#052e16"
92
+ },
93
+ "indigo": {
94
+ "50": "#eef2ff",
95
+ "100": "#e0e7ff",
96
+ "200": "#c7d2fe",
97
+ "300": "#a5b4fc",
98
+ "400": "#818cf8",
99
+ "500": "#6366f1",
100
+ "600": "#4f46e5",
101
+ "700": "#4338ca",
102
+ "800": "#3730a3",
103
+ "900": "#312e81",
104
+ "950": "#1e1b4b"
105
+ },
106
+ "lime": {
107
+ "50": "#f7fee7",
108
+ "100": "#ecfccb",
109
+ "200": "#d9f99d",
110
+ "300": "#bef264",
111
+ "400": "#a3e635",
112
+ "500": "#84cc16",
113
+ "600": "#65a30d",
114
+ "700": "#4d7c0f",
115
+ "800": "#3f6212",
116
+ "900": "#365314",
117
+ "950": "#1a2e05"
118
+ },
119
+ "orange": {
120
+ "50": "#fff7ed",
121
+ "100": "#ffedd5",
122
+ "200": "#fed7aa",
123
+ "300": "#fdba74",
124
+ "400": "#fb923c",
125
+ "500": "#f97316",
126
+ "600": "#ea580c",
127
+ "700": "#c2410c",
128
+ "800": "#9a3412",
129
+ "900": "#7c2d12",
130
+ "950": "#431407"
131
+ },
132
+ "pink": {
133
+ "50": "#fdf2f8",
134
+ "100": "#fce7f3",
135
+ "200": "#fbcfe8",
136
+ "300": "#f9a8d4",
137
+ "400": "#f472b6",
138
+ "500": "#ec4899",
139
+ "600": "#db2777",
140
+ "700": "#be185d",
141
+ "800": "#9d174d",
142
+ "900": "#831843",
143
+ "950": "#500724"
144
+ },
145
+ "purple": {
146
+ "50": "#faf5ff",
147
+ "100": "#f3e8ff",
148
+ "200": "#e9d5ff",
149
+ "300": "#d8b4fe",
150
+ "400": "#c084fc",
151
+ "500": "#a855f7",
152
+ "600": "#9333ea",
153
+ "700": "#7e22ce",
154
+ "800": "#6b21a8",
155
+ "900": "#581c87",
156
+ "950": "#3b0764"
157
+ },
158
+ "red": {
159
+ "50": "#fef2f2",
160
+ "100": "#fee2e2",
161
+ "200": "#fecaca",
162
+ "300": "#fca5a5",
163
+ "400": "#f87171",
164
+ "500": "#ef4444",
165
+ "600": "#dc2626",
166
+ "700": "#b91c1c",
167
+ "800": "#991b1b",
168
+ "900": "#7f1d1d",
169
+ "950": "#450a0a"
170
+ },
171
+ "rose": {
172
+ "50": "#fff1f2",
173
+ "100": "#ffe4e6",
174
+ "200": "#fecdd3",
175
+ "300": "#fda4af",
176
+ "400": "#fb7185",
177
+ "500": "#f43f5e",
178
+ "600": "#e11d48",
179
+ "700": "#be123c",
180
+ "800": "#9f1239",
181
+ "900": "#881337",
182
+ "950": "#4c0519"
183
+ },
184
+ "sky": {
185
+ "50": "#f0f9ff",
186
+ "100": "#e0f2fe",
187
+ "200": "#bae6fd",
188
+ "300": "#7dd3fc",
189
+ "400": "#38bdf8",
190
+ "500": "#0ea5e9",
191
+ "600": "#0284c7",
192
+ "700": "#0369a1",
193
+ "800": "#075985",
194
+ "900": "#0c4a6e",
195
+ "950": "#082f49"
196
+ },
197
+ "slate": {
198
+ "50": "#f8fafc",
199
+ "100": "#f1f5f9",
200
+ "200": "#e2e8f0",
201
+ "300": "#cbd5e0",
202
+ "400": "#94a3b8",
203
+ "500": "#64748b",
204
+ "600": "#475569",
205
+ "700": "#334155",
206
+ "800": "#1e293b",
207
+ "900": "#0f172a",
208
+ "950": "#020617"
209
+ },
210
+ "stone": {
211
+ "50": "#fafaf9",
212
+ "100": "#f5f5f4",
213
+ "200": "#e7e5e4",
214
+ "300": "#d6d3d1",
215
+ "400": "#a8a29e",
216
+ "500": "#78716c",
217
+ "600": "#57534e",
218
+ "700": "#44403c",
219
+ "800": "#292524",
220
+ "900": "#1c1917",
221
+ "950": "#0c0a09"
222
+ },
223
+ "teal": {
224
+ "50": "#f0fdfa",
225
+ "100": "#ccfbf1",
226
+ "200": "#99f6e4",
227
+ "300": "#5eead4",
228
+ "400": "#2dd4bf",
229
+ "500": "#14b8a6",
230
+ "600": "#0d9488",
231
+ "700": "#0f766e",
232
+ "800": "#115e59",
233
+ "900": "#134e4a",
234
+ "950": "#042f2e"
235
+ },
236
+ "violet": {
237
+ "50": "#f5f3ff",
238
+ "100": "#ede9fe",
239
+ "200": "#ddd6fe",
240
+ "300": "#c4b5fd",
241
+ "400": "#a78bfa",
242
+ "500": "#8b5cf6",
243
+ "600": "#7c3aed",
244
+ "700": "#6d28d9",
245
+ "800": "#5b21b6",
246
+ "900": "#4c1d95",
247
+ "950": "#2e1065"
248
+ },
249
+ "yellow": {
250
+ "50": "#fefce8",
251
+ "100": "#fef9c3",
252
+ "200": "#fef08a",
253
+ "300": "#fde047",
254
+ "400": "#facc15",
255
+ "500": "#eab308",
256
+ "600": "#ca8a04",
257
+ "700": "#a16207",
258
+ "800": "#854d0e",
259
+ "900": "#713f12",
260
+ "950": "#422006"
261
+ },
262
+ "zinc": {
263
+ "50": "#fafafa",
264
+ "100": "#f4f4f5",
265
+ "200": "#e4e4e7",
266
+ "300": "#d4d4d8",
267
+ "400": "#a1a1aa",
268
+ "500": "#71717a",
269
+ "600": "#52525b",
270
+ "700": "#3f3f46",
271
+ "800": "#27272a",
272
+ "900": "#18181b",
273
+ "950": "#000000"
274
+ },
275
+ "shark": {
276
+ "DEFAULT": "#677287",
277
+ "50": "#ffffff",
278
+ "100": "#efefef",
279
+ "200": "#E0E0E0",
280
+ "300": "#C1C6D0",
281
+ "400": "#828C9F",
282
+ "500": "#677287",
283
+ "600": "#51596A",
284
+ "700": "#3B414D",
285
+ "800": "#2E323C",
286
+ "900": "#20242A",
287
+ "950": "#1A1C22"
288
+ }
289
+ }
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import './types'
1
+ export * from './types'
2
2
  export * from './constants'
3
3
  export * from './nested'
4
4
  export * from './mapping'
@@ -2,11 +2,25 @@ import { defaultFields } from './constants'
2
2
  import { isExpanded, hasChildren, getAttribute } from './mapping'
3
3
  import { equals } from 'ramda'
4
4
 
5
+ /**
6
+ * Checks if a specifc attribute of an item matches a value.
7
+ *
8
+ * @param {Object} item - The item.
9
+ * @param {string} attr - The attribute to check.
10
+ */
5
11
  function isMatch(item, attr, value) {
6
12
  const itemValue = attr ? getAttribute(item, attr) : item
7
13
  return equals(itemValue, value)
8
14
  }
9
15
 
16
+ /**
17
+ * Traverses the tree to find an item by value.
18
+ * @param {Array} items - The items array.
19
+ * @param {Object} fields - The fields mapping.
20
+ * @param {any} value - The value to find.
21
+ * @param {Array} position - The current position in the tree.
22
+ * @returns {Object} The found item, or null if not found.
23
+ */
10
24
  function findInChildren(item, index, fields, value, attr, position) {
11
25
  if (hasChildren(item, fields)) {
12
26
  return findItemByValue(value, item[fields.children], fields.fields ?? fields, attr, [
@@ -69,7 +83,7 @@ export function findNearestItemBefore(position, items, fields) {
69
83
  if (position.length === 0) return { item: items[0], position: [0], fields }
70
84
 
71
85
  let index = position[position.length - 1]
72
- let result
86
+ let result = null
73
87
  if (index > 0) {
74
88
  index -= 1
75
89
  if (position.length === 1) {
@@ -85,6 +99,7 @@ export function findNearestItemBefore(position, items, fields) {
85
99
  }
86
100
 
87
101
  /**
102
+ * Returns the next sibling of the current item.
88
103
  *
89
104
  * @param {*} parent
90
105
  * @param {Array<integer>} position
@@ -114,8 +129,8 @@ export function findNearestItemAfter(position, items, fields) {
114
129
  if (items.length === 0) return null
115
130
  if (position.length === 0) return { item: items[0], position: [0], fields }
116
131
 
117
- let current = findItemByIndexArray(position, items, fields)
118
- let result
132
+ const current = findItemByIndexArray(position, items, fields)
133
+ let result = null
119
134
  if (isExpanded(current.item, current.fields)) {
120
135
  result = getFirstChild(current, position)
121
136
  } else if (position.length === 1) {
package/src/nested.js CHANGED
@@ -4,7 +4,7 @@ import { defaultFields } from './constants'
4
4
  export function flattenNestedList(items, fields = defaultFields, level = 0) {
5
5
  fields = { ...defaultFields, ...fields }
6
6
  let data = []
7
- items.map((item) => {
7
+ items.forEach((item) => {
8
8
  const children = item[fields.children] ?? []
9
9
  data = [
10
10
  ...data,
@@ -31,7 +31,7 @@ export function findValueFromPath(slug, data, fields) {
31
31
  let items = data
32
32
  let value = null
33
33
 
34
- keys.map((key, index) => {
34
+ keys.forEach((key, index) => {
35
35
  const match = items.find((item) => item[fields.key] === key)
36
36
  if (match) {
37
37
  if (index < keys.length - 1) {
package/src/parser.js CHANGED
@@ -19,11 +19,11 @@
19
19
  * @returns {RegExp} - The regular expression pattern to identify search filter elements.
20
20
  */
21
21
  export function getRegex() {
22
- let column = '[\\w]+'
23
- let operator = ':|>|<|>=|<=|=<|=>|=|!=|~|~\\*|!~|!~\\*'
24
- let value = '("[^"]+"|[^\\s=:<>!~*]+)'
22
+ const column = '[\\w]+'
23
+ const operator = ':|>|<|>=|<=|=<|=>|=|!=|~|~\\*|!~|!~\\*'
24
+ const value = '("[^"]+"|[^\\s=:<>!~*]+)'
25
25
 
26
- let pattern = `(?<group>((?<column>${column})\\s?(?<operator>${operator})\\s?)(?<value>${value}))`
26
+ const pattern = `(?<group>((?<column>${column})\\s?(?<operator>${operator})\\s?)(?<value>${value}))`
27
27
 
28
28
  return new RegExp(pattern, 'gm')
29
29
  }
package/src/string.js CHANGED
@@ -70,7 +70,7 @@ export function compareStrings(a, b) {
70
70
  * @returns {String} timestamp based unique id
71
71
  */
72
72
  export function uniqueId(prefix = '', separator = '-') {
73
- let pair = prefix && prefix.length > 0 ? [prefix] : []
73
+ const pair = prefix && prefix.length > 0 ? [prefix] : []
74
74
  pair.push(Date.now().toString(36))
75
75
  return pair.join(separator)
76
76
  }
package/src/theme.js CHANGED
@@ -30,7 +30,8 @@ export function shadesOf(name, modifier = 'none') {
30
30
  raised: fn(`var(--${name}-400)`),
31
31
  elevated: fn(`var(--${name}-600)`),
32
32
  floating: fn(`var(--${name}-700)`),
33
- contrast: fn(`var(--${name}-800)`)
33
+ contrast: fn(`var(--${name}-800)`),
34
+ overlay: fn(`var(--${name}-900)`)
34
35
  }
35
36
  )
36
37
  }
@@ -47,8 +48,8 @@ export function stateColors(name, modifier = 'none') {
47
48
  export function themeColors(modifier = 'none') {
48
49
  const fn = modifier in modifiers ? modifiers[modifier] : modifiers.none
49
50
 
50
- let states = ['info', 'danger', 'warning', 'success', 'error']
51
- let variants = ['neutral', 'primary', 'secondary', 'accent']
51
+ const states = ['info', 'danger', 'warning', 'success', 'error']
52
+ const variants = ['neutral', 'primary', 'secondary', 'accent']
52
53
  let colors = states.reduce(
53
54
  (acc, state) => ({ ...acc, [state]: stateColors(state, modifier) }),
54
55
  {}
@@ -70,19 +71,18 @@ export function themeColors(modifier = 'none') {
70
71
  * Creates an array of shade mapping objects for a given theme variant and mode.
71
72
  * Each object represents a CSS custom property (variable) with its value set based on a provided condition.
72
73
  *
73
- * @param {string} variant - The name of the theme variant (e.g., 'primary', 'secondary').
74
- * @param {'light' | 'dark'} mode - The theme mode for which the mappings are being created.
74
+ * @param {string} variant - The name of the theme variant (e.g., 'primary', 'secondary').
75
+ * @param {'light' | 'dark'} mode - The theme mode for which the mappings are being created.
75
76
  * @param {function(number): string} valueCondition - A function that takes a shade value and returns the color value
76
77
  * based on the condition appropriate for light or dark mode.
77
- * @returns {Array<{key: string, value: string, mode: string}>} An array of objects, where each object contains
78
- * key, value, and mode properties corresponding to
79
- * a CSS custom property definition.
78
+ * @returns {{import('./types'}.ShadeMappings>} An array of objects, where each object contains key, value, and mode
79
+ * properties corresponding to a CSS custom property definition.
80
80
  */
81
81
  function createShadeMappings(variant, mode, valueCondition) {
82
82
  return shades.map((shade) => ({
83
83
  key: `--on-${variant}-${shade}`,
84
84
  value: valueCondition(shade),
85
- mode: mode
85
+ mode
86
86
  }))
87
87
  }
88
88
 
@@ -110,7 +110,7 @@ export function contrastColors(light = '#ffffff', dark = '#000000', palette = de
110
110
  * @param {string} variant - The name of the variant to generate rules for.
111
111
  * @param {Object} colors - The object containing color definitions.
112
112
  * @param {Object} mapping - An object that maps variant names to color property names.
113
- * @returns {Array<Object>} An array containing the color rules for both light and dark modes.
113
+ * @returns {import('./types').ShadeMappings} An array containing the color rules for both light and dark modes.
114
114
  */
115
115
  function generateColorRules(variant, colors, mapping) {
116
116
  return shades.flatMap((shade, index) => [
@@ -165,9 +165,9 @@ function createThemeVariant(name, mode, colors, extraColors) {
165
165
  /**
166
166
  * Constructs and returns the light and dark theme variants based on provided color mapping and color definitions.
167
167
  *
168
- * @param {string} name - The base name for the theme, defaults to 'rokkit' if not provided.
168
+ * @param {string} name - The base name for the theme, defaults to 'rokkit' if not provided.
169
169
  * @param {Object} [mapping=defaultThemeMapping] - An object mapping variant names to color property names.
170
- * @param {Object} [colors=defaultColors] - The object containing default color definitions.
170
+ * @param {Object} [colors=defaultColors] - The object containing default color definitions.
171
171
  * @returns {Array<Array>} An array containing two arrays, one for the light theme variant and another for the dark theme.
172
172
  */
173
173
  export function themeRules(name = 'rokkit', mapping = defaultThemeMapping, colors = defaultColors) {
package/src/types.js CHANGED
@@ -85,3 +85,17 @@
85
85
  * @typedef {Object} RowStateMap
86
86
  * @property {RowState[]} rows - Flat list of hierarchy nodes.
87
87
  */
88
+
89
+ /**
90
+ * Shade mapping for color variables
91
+ *
92
+ * @typedef {Object} ShadeMapping
93
+ * @property {string} key - the variable name to be used
94
+ * @property {string} value - the value to be used
95
+ * @property {string} mode - light or dark mode
96
+ */
97
+
98
+ /**
99
+ * @typedef {Array<ShadeMapping>} ShadeMappings
100
+ */
101
+ export default {}
package/src/utils.js CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * A function that performs no operations.
3
+ */
4
+ export function noop() {
5
+ // intentionally empty to support default actions
6
+ }
7
+
1
8
  /**
2
9
  * Generates a random id
3
10
  *
@@ -60,6 +67,6 @@ export function iconShortcuts(icons, collection, variants) {
60
67
  * @returns {string|number}
61
68
  */
62
69
  export function scaledPath(size, x) {
63
- if (Array.isArray(x)) return x.map((x) => scaledPath(size, x)).join(' ')
70
+ if (Array.isArray(x)) return x.map((v) => scaledPath(size, v)).join(' ')
64
71
  return typeof x === 'number' ? x * size : x
65
72
  }