@walkeros/explorer 4.8.0-next-1791441510508 → 4.8.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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @walkeros/explorer
2
2
 
3
- ## 4.8.0-next-1791441510508
3
+ ## 4.8.0
4
4
 
5
5
  ### Minor Changes
6
6
 
@@ -11,9 +11,19 @@
11
11
  colour and font constants from `@walkeros/explorer/design`. A
12
12
  `walkeros-design-check` command lints consuming code. Existing exports are
13
13
  unchanged.
14
+ - aa4bb8b: Add `Playground`: a tagged component, its event, an editable mapping
15
+ and the resulting gtag call side by side, on one real flow (`startFlow`, the
16
+ browser source scoped to a shadow root, and the gtag destination with a
17
+ stubbed `gtag`). `@walkeros/web-destination-gtag` is now a runtime dependency.
14
18
 
15
19
  ### Patch Changes
16
20
 
21
+ - 7132619: `@walkeros/explorer/design/components` gains `BrowserFrame`, a
22
+ browser window on the site theme around any page: an address field with the
23
+ URL, an optional reload button, a slot for the caller's actions and an
24
+ optional bookmarks row that marks the current page. It is sized by its caller
25
+ and styled by `@walkeros/explorer/styles.css`. `Icon` gains `lock`, `reload`
26
+ and `bookmark`.
17
27
  - d5cbc9c: New `@walkeros/explorer/design/components` export with `Button`,
18
28
  `InlineCode` and `EventLegend`, styled by `@walkeros/explorer/styles.css`.
19
29
  `Button` forwards tagging attributes to its element and accepts a router link
@@ -36,11 +46,34 @@
36
46
  as CSS variables: `--type-<style>-size`, `-line-height`, `-weight`, `-family`
37
47
  and, when the style sets one, `-tracking`. Components can take sizes and
38
48
  weights from the design system instead of fixed values.
49
+ - 7132619: The `PromotionPlayground` and `LiveCode` mapping examples show events
50
+ and results again, and every failure says so in the box it concerns. `Preview`
51
+ takes a `collector` instead of `elb` and captures the page's events through
52
+ it; its document carries the design tokens, base rules and design atom styles,
53
+ so the demo product card is built from `Card`, `PhotoPlaceholder`, `Text` and
54
+ `Button`. The Playground drops its separate Code box and the `labelCode` prop:
55
+ the Preview's HTML, CSS and JS tabs edit the page. New props: `placeholder`
56
+ and `error` on `CodeBox`, `error` on `Box`, `boxWidth` on `Grid` for one row
57
+ of fixed-width boxes.
58
+ - 7132619: New `ViewSource` component: wrap a tagged element, hover it and
59
+ toggle to its live HTML with the `data-elb` attributes, edited in place. Back
60
+ in Visual the element renders your edit and walkerOS picks up the new tags; a
61
+ Reset icon restores the original. New `ToggleButton`: one button that names
62
+ the option a click switches to, at a fixed width.
63
+ - a4b03ba: The five event colours (globals, context, entity, property, action)
64
+ now have a light-theme value that reads as text on light backgrounds. Their
65
+ constants in `@walkeros/explorer/design` are now `{ dark, light }` objects,
66
+ like every other themed colour; read `.dark` where the colour sits on a dark
67
+ ground.
68
+ - Updated dependencies [7132619]
39
69
  - Updated dependencies [5593d7b]
40
- - @walkeros/core@4.8.0-next-1791441510508
41
- - @walkeros/collector@4.8.0-next-1791441510508
42
- - @walkeros/web-core@4.8.0-next-1791441510508
43
- - @walkeros/web-source-browser@4.8.0-next-1791441510508
70
+ - Updated dependencies [421233d]
71
+ - Updated dependencies [5593d7b]
72
+ - @walkeros/core@4.8.0
73
+ - @walkeros/web-destination-gtag@4.8.0
74
+ - @walkeros/collector@4.8.0
75
+ - @walkeros/web-core@4.8.0
76
+ - @walkeros/web-source-browser@4.8.0
44
77
 
45
78
  ## 4.7.2
46
79
 
package/README.md CHANGED
@@ -32,10 +32,10 @@ import { CodeBox } from '@walkeros/explorer';
32
32
  ```
33
33
 
34
34
  In a Tailwind v4 build, import `@walkeros/explorer/design/tailwind.css` after
35
- `@import "tailwindcss"` instead of `tokens.css`: it brings the tokens and a
36
- utility for every design colour and type style.
37
- `@walkeros/explorer/design/base.css` adds optional page-wide base rules (font,
38
- colours, focus ring, selection).
35
+ `@import "tailwindcss"` instead of `tokens.css`: it brings the tokens, a utility
36
+ for every design colour and type style, `max-w-*` widths in px and `transition`
37
+ utilities on the design motion. `@walkeros/explorer/design/base.css` adds
38
+ optional page-wide base rules (font, colours, focus ring, selection).
39
39
 
40
40
  ## Themes
41
41
 
@@ -60,7 +60,7 @@ Explorer ships the walkerOS design system:
60
60
  | `@walkeros/explorer/design/tokens.css` | The design tokens as CSS custom properties |
61
61
  | `@walkeros/explorer/design/tailwind.css` | The tokens as a Tailwind v4 theme |
62
62
  | `@walkeros/explorer/design/base.css` | Optional base rules for a whole page |
63
- | `@walkeros/explorer/design` | The token values as constants, for code that cannot read CSS variables |
63
+ | `@walkeros/explorer/design` | The token values as constants (colours, fonts, type styles, motion), for code that cannot read CSS variables |
64
64
  | `@walkeros/explorer/design/components` | React building blocks of walkerOS pages (`Button`, `InlineCode`, `EventLegend` and more), with no Monaco or walkerOS runtime |
65
65
 
66
66
  The `walkeros-design-check` command checks a package's own styles against the
@@ -3,19 +3,18 @@
3
3
  * tokens.css. Explorer's own reset stays scoped to .elb-explorer.
4
4
  */
5
5
  @layer base {
6
- :root,
7
- :host,
8
- [data-theme] {
9
- --motion: 180ms;
10
- --ease: cubic-bezier(0.2, 0, 0, 1);
11
- }
12
-
13
- /* The one media query of the design system. */
6
+ /*
7
+ * tokens.css sets --motion to 0ms for reduced motion; this guard also stops
8
+ * animations, transitions with their own durations and smooth scrolling.
9
+ */
14
10
  @media (prefers-reduced-motion: reduce) {
15
- :root,
16
- :host,
17
- [data-theme] {
18
- --motion: 0ms;
11
+ *,
12
+ *::before,
13
+ *::after {
14
+ animation-duration: 0.01ms !important;
15
+ animation-iteration-count: 1 !important;
16
+ transition-duration: 0.01ms !important;
17
+ scroll-behavior: auto !important;
19
18
  }
20
19
  }
21
20
 
@@ -54,6 +54,7 @@ function globToRegExp(glob) {
54
54
  var TAILWIND_RESET_NAMESPACES = [
55
55
  "color",
56
56
  "radius",
57
+ "container",
57
58
  "font",
58
59
  "text",
59
60
  "shadow",
@@ -66,7 +67,6 @@ var TAILWIND_KEPT_NAMESPACES = [
66
67
  "aspect",
67
68
  "blur",
68
69
  "breakpoint",
69
- "container",
70
70
  "default",
71
71
  "ease",
72
72
  "font-weight",
@@ -105,11 +105,14 @@ var RULES = [
105
105
  "shadow-class",
106
106
  "z-class",
107
107
  "text-size-class",
108
+ "motion-class",
108
109
  "radius-class",
109
110
  "var-fallback",
110
111
  "undeclared-var",
111
112
  "color-scheme",
112
- "z-index"
113
+ "z-index",
114
+ "motion-literal",
115
+ "font-literal"
113
116
  ];
114
117
  var NAMED_COLORS = new Set(
115
118
  `aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown
@@ -135,6 +138,7 @@ var COLOR_UTILITY = "bg|text|border(?:-[xytrblse])?|outline|ring(?:-offset)?|div
135
138
  var START = "(?<![A-Za-z0-9_-])";
136
139
  var END = "(?![A-Za-z0-9_-])";
137
140
  var SIDE = "(?:-(?:t|r|b|l|s|e|tl|tr|br|bl|ss|se|es|ee))?";
141
+ var LITERAL_ARBITRARY = "\\[(?![^\\]]*var\\()[^\\]\\s]+\\]";
138
142
  var CLASS_RULES = [
139
143
  [
140
144
  "palette-class",
@@ -161,9 +165,21 @@ var CLASS_RULES = [
161
165
  )
162
166
  ],
163
167
  ["z-class", new RegExp(`${START}-?z-(?:\\d+|\\[-?\\d+\\])${END}`, "g")],
168
+ // An arbitrary size that reads a variable (`text-[length:var(--type-x-size)]`) is not flagged.
164
169
  [
165
170
  "text-size-class",
166
- new RegExp(`${START}text-(?:xs|sm|base|lg|xl|[2-9]xl)${END}`, "g")
171
+ new RegExp(
172
+ `${START}text-(?:xs|sm|base|lg|xl|[2-9]xl|\\[(?:length:)?(?![^\\]]*var\\()(?:[\\d.]|(?:calc|clamp|min|max)\\()[^\\]\\s]*\\])${END}`,
173
+ "g"
174
+ )
175
+ ],
176
+ // Tailwind's transition utilities read --motion and --ease; a zero duration, delay-* and animate-* are not flagged.
177
+ [
178
+ "motion-class",
179
+ new RegExp(
180
+ `${START}(?:duration-(?:[1-9]\\d*|(?!\\[0m?s\\])${LITERAL_ARBITRARY})|ease-(?:in-out|in|out|linear|${LITERAL_ARBITRARY}))${END}`,
181
+ "g"
182
+ )
167
183
  ],
168
184
  // An arbitrary value that reads a design radius (`rounded-[calc(var(--radius-md)-1px)]`) is not flagged.
169
185
  [
@@ -187,8 +203,126 @@ var TAILWIND_VAR = /-\(--([A-Za-z0-9_-]+)\)/g;
187
203
  var COLOR_SCHEME = /prefers-color-scheme/g;
188
204
  var Z_INDEX_CSS = /(?<![A-Za-z0-9_-])z-index\s*:\s*-?\d+/g;
189
205
  var Z_INDEX_SCRIPT = /(?<![A-Za-z0-9_-])zIndex\s*:\s*['"]?-?\d+/g;
206
+ var CSS_STYLE = /(?<![A-Za-z0-9_-])(font-size|font-family|font|transition-duration|transition-timing-function|transition)\s*:\s*((?:\$\{[^}]*\}|[^;{}\]])+)/g;
207
+ var SCRIPT_STYLE = /(?<![A-Za-z0-9_-])(fontSize|fontFamily|transitionDuration|transitionTimingFunction|transition)\s*(?::|=\{?)\s*('(?:\\.|[^'\\\n])*'|"(?:\\.|[^"\\\n])*"|`(?:\\.|[^`\\])*`|\d*\.?\d+(?![\w.]))/g;
208
+ var NUMBER = /^\d*\.?\d+$/;
209
+ var QUOTED = /^(['"`])([\s\S]*)\1$/;
210
+ var MOTION_LITERAL = /(?<![A-Za-z0-9-])(?:cubic-bezier|steps|linear)\([^)]*\)|(?<![A-Za-z0-9.-])(?:(?:\d+(?:\.\d+)?|\.\d+)m?s|ease-in-out|ease-in|ease-out|ease|linear|step-start|step-end)(?![A-Za-z0-9-])/g;
211
+ var LENGTH = "(?:\\d+(?:\\.\\d+)?|\\.\\d+)(?:px|rem|em|pt|%|vw|vh|vmin|vmax|ch|ex|lh|rlh|cqw|cqh|cqi)";
212
+ var SIZE_LITERAL = new RegExp(
213
+ `(?<![A-Za-z0-9.-])(?:${LENGTH}|xxx-large|xx-large|x-large|xx-small|x-small|smaller|small|medium|larger|large)(?![A-Za-z0-9-])`,
214
+ "g"
215
+ );
216
+ var VARIABLE_DECLARATION = /(?<![A-Za-z0-9_-])(--[A-Za-z0-9_-]+|\$[A-Za-z_][\w-]*)['"]?\s*:\s*['"`]?([^;{}'"`\n\]]+)/g;
217
+ var VARIABLE_READ = /var\(\s*(--[A-Za-z0-9_-]+)|(?<![\w-])(\$[A-Za-z_][\w-]*)/g;
218
+ var MOTION_TOKEN = new RegExp(
219
+ `var\\(--motion\\)|${MOTION_LITERAL.source}`,
220
+ "g"
221
+ );
222
+ var FONT_KEYWORD = /(?<![\w-])(?:normal|italic|oblique|small-caps|bold|bolder|lighter|(?:ultra-|extra-|semi-)?(?:condensed|expanded))(?![\w-])/g;
223
+ var FLUID_TYPE = /clamp\((?:[^()]|\([^()]*\))*,\s*var\(--type-[a-z0-9-]+-size\)\s*\)/g;
224
+ var COMMENT = /\/\*[\s\S]*?\*\/|(?<=^|\s)\/\/[^\n]*/g;
225
+ var FONT_FACE = /@font-face\s*\{[^}]*\}/g;
226
+ var CSS_WIDE = /* @__PURE__ */ new Set([
227
+ "inherit",
228
+ "initial",
229
+ "unset",
230
+ "revert",
231
+ "revert-layer"
232
+ ]);
190
233
  var STRING_LITERAL = /'(?:\\.|[^'\\\n])*'|"(?:\\.|[^"\\\n])*"|`(?:\\.|[^`\\])*`/g;
191
234
  var APPLY = /@apply\s+[^;}]+/g;
235
+ var SCRIPT_TOKEN = new RegExp(
236
+ `${STRING_LITERAL.source}|\\/\\/[^\\n]*|\\/\\*[\\s\\S]*?\\*\\/`,
237
+ "g"
238
+ );
239
+ var within = (regions, index) => regions.some(
240
+ (region) => index >= region.offset && index < region.offset + region.text.length
241
+ );
242
+ function literalFamily(value) {
243
+ let rest = value.replace(/\$\{[^}]*\}/g, " ").replace(/!important/g, " ");
244
+ for (let previous = ""; previous !== rest; ) {
245
+ previous = rest;
246
+ rest = rest.replace(/var\([^()]*\)/g, " ");
247
+ }
248
+ return (rest.match(/[A-Za-z0-9_-]+/g) ?? []).some(
249
+ (word) => !CSS_WIDE.has(word)
250
+ );
251
+ }
252
+ function shorthandFamily(value) {
253
+ return literalFamily(
254
+ value.replace(SIZE_LITERAL, " ").replace(/(?<![\w.-])\d*\.?\d+(?![\w.])/g, " ").replace(FONT_KEYWORD, " ").replace(/(?<![\w-])(?:calc|clamp|min|max)\(/g, "(").replace(/\//g, " ")
255
+ );
256
+ }
257
+ var blank = (text) => text.replace(/[^\n]/g, " ");
258
+ function commaItems(value) {
259
+ const commas = [];
260
+ let depth = 0;
261
+ for (let i = 0; i < value.length; i++) {
262
+ if (value[i] === "(") depth++;
263
+ else if (value[i] === ")") depth--;
264
+ else if (value[i] === "," && depth === 0) commas.push(i);
265
+ }
266
+ return (index) => commas.filter((comma) => comma < index).length;
267
+ }
268
+ function localLiteralLengths(file, text) {
269
+ const code = STYLE_FILE.test(file) ? text.replace(COMMENT, blank) : text.replace(
270
+ SCRIPT_TOKEN,
271
+ (token) => token.startsWith("/") ? blank(token) : token
272
+ );
273
+ const names = /* @__PURE__ */ new Set();
274
+ forEachMatch(VARIABLE_DECLARATION, code, (match) => {
275
+ if (new RegExp(LENGTH).test(match[2]) && !/var\(|\$/.test(match[2]))
276
+ names.add(match[1]);
277
+ });
278
+ return names;
279
+ }
280
+ function styleValue(property, value, index, { add, motionValues, literalLengths }) {
281
+ const scanned = value.replace(/\$\{[^}]*\}/g, blank);
282
+ const bare = QUOTED.exec(value)?.[2] ?? value;
283
+ const asWritten = value.replace(/\s+/g, " ").trim();
284
+ if (property.startsWith("transition")) {
285
+ motionValues.push({ offset: index, text: value });
286
+ if (NUMBER.test(bare)) {
287
+ if (property === "transitionDuration")
288
+ add("motion-literal", index, value);
289
+ return;
290
+ }
291
+ const item = commaItems(value);
292
+ const timed = /* @__PURE__ */ new Set();
293
+ forEachMatch(MOTION_TOKEN, scanned, (match) => {
294
+ const time = /^[\d.]/.test(match[0]);
295
+ if (time || match[0] === "var(--motion)") {
296
+ const n = item(match.index);
297
+ if (property === "transition" && timed.has(n)) return;
298
+ timed.add(n);
299
+ if (!time || parseFloat(match[0]) === 0) return;
300
+ }
301
+ add("motion-literal", index + match.index, match[0]);
302
+ });
303
+ } else if (property === "font-family" || property === "fontFamily") {
304
+ if (literalFamily(value)) add("font-literal", index, asWritten);
305
+ } else if (NUMBER.test(bare)) {
306
+ add("font-literal", index, value);
307
+ } else {
308
+ const fluid = [];
309
+ forEachMatch(
310
+ FLUID_TYPE,
311
+ scanned,
312
+ (match) => fluid.push({ offset: match.index, text: match[0] })
313
+ );
314
+ forEachMatch(SIZE_LITERAL, scanned, (match) => {
315
+ if (!within(fluid, match.index))
316
+ add("font-literal", index + match.index, match[0]);
317
+ });
318
+ forEachMatch(VARIABLE_READ, scanned, (match) => {
319
+ if (literalLengths.has(match[1] ?? match[2]))
320
+ add("font-literal", index + match.index, match[0]);
321
+ });
322
+ if (property === "font" && shorthandFamily(value))
323
+ add("font-literal", index, asWritten);
324
+ }
325
+ }
192
326
  function classRegions(style, text) {
193
327
  const regions = [];
194
328
  forEachMatch(
@@ -248,13 +382,48 @@ function scanFile(file, text, context) {
248
382
  add("named-color", match.index, match[1]);
249
383
  });
250
384
  }
251
- for (const region of classRegions(style, text)) {
385
+ const regions = classRegions(style, text);
386
+ const fontFaces = [];
387
+ forEachMatch(
388
+ FONT_FACE,
389
+ text,
390
+ (match) => fontFaces.push({ offset: match.index, text: match[0] })
391
+ );
392
+ const scan = {
393
+ add,
394
+ motionValues: [],
395
+ literalLengths: context.literalLengths
396
+ };
397
+ const cssRegions = style ? [{ offset: 0, text }] : regions;
398
+ for (const region of cssRegions) {
399
+ const css = region.text.replace(COMMENT, blank);
400
+ forEachMatch(CSS_STYLE, css, (match) => {
401
+ const index = region.offset + match.index + match[0].length - match[2].length;
402
+ if (!within(fontFaces, index))
403
+ styleValue(match[1], match[2], index, scan);
404
+ });
405
+ }
406
+ if (!style)
407
+ forEachMatch(
408
+ SCRIPT_STYLE,
409
+ text.replace(
410
+ SCRIPT_TOKEN,
411
+ (token) => token.startsWith("/") ? blank(token) : token
412
+ ),
413
+ (match) => styleValue(
414
+ match[1],
415
+ match[2],
416
+ match.index + match[0].length - match[2].length,
417
+ scan
418
+ )
419
+ );
420
+ for (const region of regions) {
252
421
  for (const [rule, pattern] of CLASS_RULES) {
253
- forEachMatch(
254
- pattern,
255
- region.text,
256
- (match) => add(rule, region.offset + match.index, match[0])
257
- );
422
+ forEachMatch(pattern, region.text, (match) => {
423
+ const index = region.offset + match.index;
424
+ if (rule !== "motion-class" || !within(scan.motionValues, index))
425
+ add(rule, index, match[0]);
426
+ });
258
427
  }
259
428
  }
260
429
  const declared = (name) => context.declaredNames.has(name) || TAILWIND_VARIABLES.some((prefix) => name.startsWith(prefix)) || context.allowVarPrefixes.some((prefix) => name.startsWith(prefix));
@@ -419,7 +588,11 @@ function main(argv, io) {
419
588
  declaredNames: collectDeclaredNames(
420
589
  sources.map((source) => source.text).join("\n")
421
590
  ),
422
- allowVarPrefixes
591
+ allowVarPrefixes,
592
+ // A literal behind a local name: scanned files only, never a design name.
593
+ literalLengths: new Set(
594
+ scanned.flatMap((source) => [...localLiteralLengths(source.file, source.text)]).filter((name) => !designNames.has(name.replace(/^--/, "")))
595
+ )
423
596
  };
424
597
  const findings = scanned.flatMap((source) => scanFile(source.file, source.text, context)).filter((finding) => !ruleAllowed(finding));
425
598
  for (const finding of findings) {