@fairfox/polly 0.72.0 → 0.73.1

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.
Files changed (36) hide show
  1. package/dist/src/elysia/index.js +464 -4
  2. package/dist/src/elysia/index.js.map +6 -4
  3. package/dist/src/peer.d.ts +2 -0
  4. package/dist/src/peer.js +468 -4
  5. package/dist/src/peer.js.map +8 -5
  6. package/dist/src/polly-ui/ActionInput.d.ts +2 -1
  7. package/dist/src/polly-ui/ActionSelect.d.ts +2 -1
  8. package/dist/src/polly-ui/Button.d.ts +4 -0
  9. package/dist/src/polly-ui/Cluster.d.ts +2 -1
  10. package/dist/src/polly-ui/Code.d.ts +2 -1
  11. package/dist/src/polly-ui/Dropdown.d.ts +6 -0
  12. package/dist/src/polly-ui/Surface.d.ts +12 -1
  13. package/dist/src/polly-ui/Text.d.ts +23 -11
  14. package/dist/src/polly-ui/index.css +44 -18
  15. package/dist/src/polly-ui/index.js +118 -12
  16. package/dist/src/polly-ui/index.js.map +12 -11
  17. package/dist/src/polly-ui/internal/passthrough.d.ts +25 -0
  18. package/dist/src/polly-ui/styles.css +59 -18
  19. package/dist/src/polly-ui/theme.css +1 -0
  20. package/dist/src/shared/lib/peer-repo-server.d.ts +18 -0
  21. package/dist/src/shared/lib/sweep-sealed.d.ts +111 -0
  22. package/dist/tools/test/src/browser/run.js +42 -33
  23. package/dist/tools/test/src/browser/run.js.map +6 -5
  24. package/dist/tools/test/src/browser/runner-core.d.ts +32 -0
  25. package/dist/tools/test/src/e2e-mesh/index.js +193 -171
  26. package/dist/tools/test/src/e2e-mesh/index.js.map +4 -4
  27. package/dist/tools/test/src/visual/index.js +248 -229
  28. package/dist/tools/test/src/visual/index.js.map +5 -5
  29. package/dist/tools/verify/specs/tla/MeshSeed.cfg +27 -0
  30. package/dist/tools/verify/specs/tla/MeshSeed.tla +179 -0
  31. package/dist/tools/verify/specs/tla/README.md +11 -1
  32. package/dist/tools/verify/src/cli.js +79 -2
  33. package/dist/tools/verify/src/cli.js.map +7 -6
  34. package/dist/tools/visualize/src/cli.js +179 -3
  35. package/dist/tools/visualize/src/cli.js.map +6 -6
  36. package/package.json +3 -2
@@ -1,31 +1,43 @@
1
1
  /**
2
- * Text — typographic primitive for secondary and sized copy.
2
+ * Text — typographic primitive for secondary, sized, and status copy.
3
3
  *
4
- * Renders subtitles, captions, field labels, and empty-state copy
5
- * without the consumer reaching for a `style` attribute or a hand-rolled
6
- * `.muted` class. `tone` and `size` map to the semantic `--polly-text-*`
7
- * token family; `as` keeps the element polymorphic so the same
8
- * primitive backs a <span>, <p>, <label>, or <figcaption>. A no-prop
9
- * <Text> is an ordinary <span> at body size and default colour.
4
+ * Renders subtitles, captions, field labels, empty-state copy, and
5
+ * error/warning messages without the consumer reaching for a `style`
6
+ * attribute or a hand-rolled class. `tone` maps to the semantic
7
+ * `--polly-text-*` and `--polly-status-*` token families; `size`,
8
+ * `weight`, `italic`, and `leading` cover the remaining typographic
9
+ * axes. `as` keeps the element polymorphic so the same primitive backs a
10
+ * <span>, <p>, <label>, or <figcaption>. A no-prop <Text> is an ordinary
11
+ * <span> at body size and default colour.
12
+ *
13
+ * polly#125: arbitrary `data-*` / `aria-*` attributes are forwarded to
14
+ * the rendered element, so a Text that also needs a test hook or an
15
+ * a11y attribute stays a single element.
10
16
  */
11
17
  import { type ComponentChildren, type JSX } from "preact";
12
- export type TextTone = "default" | "muted";
18
+ import { type PassthroughAttrs } from "./internal/passthrough.ts";
19
+ export type TextTone = "default" | "muted" | "danger" | "warning" | "success";
13
20
  export type TextSize = "xs" | "sm" | "md" | "lg" | "xl";
14
21
  export type TextWeight = "normal" | "medium" | "bold";
15
- export type TextProps = {
22
+ export type TextLeading = "tight" | "base" | "loose";
23
+ export type TextProps = PassthroughAttrs & {
16
24
  children: ComponentChildren;
17
25
  /** Polymorphic element (span, p, label, figcaption, …). Defaults to 'span'. */
18
26
  as?: keyof JSX.IntrinsicElements;
19
- /** Colour role. 'muted' renders de-emphasised secondary text. Default: 'default'. */
27
+ /** Colour role. 'muted' de-emphasises; 'danger'/'warning'/'success'
28
+ * render status copy from the `--polly-status-*` tokens. Default: 'default'. */
20
29
  tone?: TextTone;
21
30
  /** Token-backed font size. Default: inherit from context. */
22
31
  size?: TextSize;
23
32
  /** Token-backed font weight. Default: inherit from context. */
24
33
  weight?: TextWeight;
34
+ /** Italic emphasis — for hints and asides — without an inline style. */
35
+ italic?: boolean;
36
+ /** Token-backed line height. 'loose' suits multi-line body copy. */
37
+ leading?: TextLeading;
25
38
  className?: string;
26
39
  id?: string;
27
40
  /** Forwarded so <Text as="label"> can point at a control. */
28
41
  htmlFor?: string;
29
- "aria-hidden"?: boolean;
30
42
  };
31
43
  export declare function Text(props: TextProps): JSX.Element;
@@ -67,10 +67,9 @@
67
67
  }
68
68
 
69
69
  .menu_HX48zA {
70
- position: absolute;
70
+ position: fixed;
71
71
  inset: unset;
72
72
  z-index: var(--polly-z-raised);
73
- margin: var(--polly-space-xs) 0 0;
74
73
  padding: var(--polly-space-xs) 0;
75
74
  border: var(--polly-border-width-default) solid var(--polly-border);
76
75
  border-radius: var(--polly-radius-md);
@@ -80,13 +79,7 @@
80
79
  overflow-y: auto;
81
80
  min-width: 160px;
82
81
  max-height: 280px;
83
- top: 100%;
84
- left: 0;
85
- }
86
-
87
- .alignRight_HX48zA {
88
- left: auto;
89
- right: 0;
82
+ margin: 0;
90
83
  }
91
84
  }
92
85
 
@@ -396,18 +389,22 @@
396
389
  --s-radius: 0;
397
390
  --s-border-color: transparent;
398
391
  --s-border-width: 0;
392
+ --s-border-style: solid;
399
393
  --s-shadow: none;
400
394
  --s-w: auto;
401
395
  --s-h: auto;
402
396
  --s-mh: auto;
397
+ --s-maxh: none;
403
398
  --s-mis: none;
399
+ --s-overflow: visible;
404
400
  --s-position: static;
405
401
  --s-inset: auto;
402
+ --s-transform: none;
406
403
  --s-z: auto;
407
404
  box-sizing: border-box;
408
405
  padding: var(--s-p);
409
406
  background: var(--s-bg);
410
- border-style: solid;
407
+ border-style: var(--s-border-style);
411
408
  border-color: var(--s-border-color);
412
409
  border-width: var(--s-border-width);
413
410
  border-radius: var(--s-radius);
@@ -415,9 +412,12 @@
415
412
  inline-size: var(--s-w);
416
413
  block-size: var(--s-h);
417
414
  min-block-size: var(--s-mh);
415
+ max-block-size: var(--s-maxh);
418
416
  max-inline-size: var(--s-mis);
417
+ overflow: var(--s-overflow);
419
418
  position: var(--s-position);
420
419
  inset: var(--s-inset);
420
+ transform: var(--s-transform);
421
421
  z-index: var(--s-z);
422
422
  }
423
423
 
@@ -428,34 +428,32 @@
428
428
 
429
429
  .sides-block-start_pQCFqA {
430
430
  border-style: none;
431
- border-block-start-style: solid;
431
+ border-block-start-style: var(--s-border-style);
432
432
  }
433
433
 
434
434
  .sides-block-end_pQCFqA {
435
435
  border-style: none;
436
- border-block-end-style: solid;
436
+ border-block-end-style: var(--s-border-style);
437
437
  }
438
438
 
439
439
  .sides-inline-start_pQCFqA {
440
440
  border-style: none;
441
- border-inline-start-style: solid;
441
+ border-inline-start-style: var(--s-border-style);
442
442
  }
443
443
 
444
444
  .sides-inline-end_pQCFqA {
445
445
  border-style: none;
446
- border-inline-end-style: solid;
446
+ border-inline-end-style: var(--s-border-style);
447
447
  }
448
448
 
449
449
  .sides-block_pQCFqA {
450
450
  border-style: none;
451
- border-block-start-style: solid;
452
- border-block-end-style: solid;
451
+ border-block-style: var(--s-border-style);
453
452
  }
454
453
 
455
454
  .sides-inline_pQCFqA {
456
455
  border-style: none;
457
- border-left-style: solid;
458
- border-right-style: solid;
456
+ border-inline-style: var(--s-border-style);
459
457
  }
460
458
  }
461
459
 
@@ -796,6 +794,34 @@
796
794
  color: var(--polly-text-muted);
797
795
  }
798
796
 
797
+ .danger_75HKdQ {
798
+ color: var(--polly-status-danger-text);
799
+ }
800
+
801
+ .warning_75HKdQ {
802
+ color: var(--polly-status-warning-text);
803
+ }
804
+
805
+ .success_75HKdQ {
806
+ color: var(--polly-status-success-text);
807
+ }
808
+
809
+ .italic_75HKdQ {
810
+ font-style: italic;
811
+ }
812
+
813
+ .tight_75HKdQ {
814
+ line-height: var(--polly-line-height-tight);
815
+ }
816
+
817
+ .base_75HKdQ {
818
+ line-height: var(--polly-line-height-base);
819
+ }
820
+
821
+ .loose_75HKdQ {
822
+ line-height: var(--polly-line-height-loose);
823
+ }
824
+
799
825
  .xs_75HKdQ {
800
826
  font-size: var(--polly-text-xs);
801
827
  }
@@ -123,6 +123,20 @@ function dispatchAction(action, data) {
123
123
  }
124
124
  }
125
125
 
126
+ // src/polly-ui/internal/passthrough.ts
127
+ function collectPassthrough(props) {
128
+ const out = {};
129
+ for (const key of Object.keys(props)) {
130
+ if (!key.startsWith("data-") && !key.startsWith("aria-"))
131
+ continue;
132
+ const value = props[key];
133
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
134
+ out[key] = value;
135
+ }
136
+ }
137
+ return out;
138
+ }
139
+
126
140
  // src/polly-ui/ActionInput.tsx
127
141
  import { jsxDEV as jsxDEV2 } from "preact/jsx-dev-runtime";
128
142
  function ActionInput(props) {
@@ -180,10 +194,12 @@ function ActionInput(props) {
180
194
  }
181
195
  };
182
196
  const className = props.className ? `${ActionInput_module_default["root"]} ${props.className}` : ActionInput_module_default["root"];
197
+ const passthrough = collectPassthrough(props);
183
198
  if (mode === "view") {
184
199
  const rendered = props.renderView ? props.renderView(props.value) : props.value;
185
200
  const isEmpty = props.value.length === 0;
186
201
  return /* @__PURE__ */ jsxDEV2("div", {
202
+ ...passthrough,
187
203
  class: `${className} ${ActionInput_module_default["view"]}`,
188
204
  "data-polly-ui": true,
189
205
  "data-polly-action-input": true,
@@ -208,6 +224,7 @@ function ActionInput(props) {
208
224
  }, undefined, false, undefined, this);
209
225
  }
210
226
  const common = {
227
+ ...passthrough,
211
228
  class: `${ActionInput_module_default["edit"]} ${ActionInput_module_default["root"]}`,
212
229
  "data-polly-ui": true,
213
230
  "data-polly-action-input": true,
@@ -258,8 +275,7 @@ import { useEffect as useEffect2, useRef as useRef2 } from "preact/hooks";
258
275
  var Dropdown_module_default = {
259
276
  dropdown: "dropdown_HX48zA",
260
277
  trigger: "trigger_HX48zA",
261
- menu: "menu_HX48zA",
262
- alignRight: "alignRight_HX48zA"
278
+ menu: "menu_HX48zA"
263
279
  };
264
280
 
265
281
  // src/polly-ui/Layout.tsx
@@ -375,6 +391,8 @@ function Layout(props) {
375
391
  // src/polly-ui/Dropdown.tsx
376
392
  import { jsxDEV as jsxDEV3 } from "preact/jsx-dev-runtime";
377
393
  var dropdownCounter = 0;
394
+ var MENU_GAP = 4;
395
+ var VIEWPORT_PADDING = 8;
378
396
  function Dropdown(props) {
379
397
  const { isOpen, trigger, children, align = "left", multiSelect = false, className, id } = props;
380
398
  const menuRef = useRef2(null);
@@ -398,6 +416,60 @@ function Dropdown(props) {
398
416
  menu.removeEventListener("overlay:close", onOverlayClose);
399
417
  };
400
418
  }, [popoverId, isOpen]);
419
+ useEffect2(() => {
420
+ const menu = menuRef.current;
421
+ const trigger2 = triggerRef.current;
422
+ if (!menu || !trigger2)
423
+ return;
424
+ const positionMenu = () => {
425
+ const t = trigger2.getBoundingClientRect();
426
+ const prevDisplay = menu.style.display;
427
+ menu.style.maxHeight = "";
428
+ menu.style.display = "block";
429
+ const menuWidth = menu.offsetWidth;
430
+ const menuHeight = menu.offsetHeight;
431
+ menu.style.display = prevDisplay;
432
+ const viewportWidth = document.documentElement.clientWidth;
433
+ const viewportHeight = document.documentElement.clientHeight;
434
+ let left = align === "right" ? t.right - menuWidth : t.left;
435
+ const maxLeft = Math.max(VIEWPORT_PADDING, viewportWidth - menuWidth - VIEWPORT_PADDING);
436
+ left = Math.min(Math.max(left, VIEWPORT_PADDING), maxLeft);
437
+ const spaceBelow = viewportHeight - t.bottom - MENU_GAP - VIEWPORT_PADDING;
438
+ const spaceAbove = t.top - MENU_GAP - VIEWPORT_PADDING;
439
+ let top;
440
+ if (menuHeight <= spaceBelow || spaceBelow >= spaceAbove) {
441
+ top = t.bottom + MENU_GAP;
442
+ if (menuHeight > spaceBelow) {
443
+ menu.style.maxHeight = `${Math.max(spaceBelow, 0)}px`;
444
+ }
445
+ } else {
446
+ const available = Math.max(spaceAbove, 0);
447
+ menu.style.maxHeight = `${available}px`;
448
+ top = t.top - MENU_GAP - Math.min(menuHeight, available);
449
+ }
450
+ menu.style.position = "fixed";
451
+ menu.style.margin = "0";
452
+ menu.style.left = `${left}px`;
453
+ menu.style.top = `${top}px`;
454
+ };
455
+ const onBeforeToggle = (e) => {
456
+ if (e.newState === "open") {
457
+ positionMenu();
458
+ }
459
+ };
460
+ const onReposition = () => {
461
+ if (menu.matches(":popover-open"))
462
+ positionMenu();
463
+ };
464
+ menu.addEventListener("beforetoggle", onBeforeToggle);
465
+ window.addEventListener("scroll", onReposition, true);
466
+ window.addEventListener("resize", onReposition);
467
+ return () => {
468
+ menu.removeEventListener("beforetoggle", onBeforeToggle);
469
+ window.removeEventListener("scroll", onReposition, true);
470
+ window.removeEventListener("resize", onReposition);
471
+ };
472
+ }, [align]);
401
473
  useSignalEffect(() => {
402
474
  const menu = menuRef.current;
403
475
  if (!menu)
@@ -426,9 +498,6 @@ function Dropdown(props) {
426
498
  const parts = [Dropdown_module_default["dropdown"] ?? ""];
427
499
  if (className)
428
500
  parts.push(className);
429
- const menuParts = [Dropdown_module_default["menu"] ?? ""];
430
- if (align === "right")
431
- menuParts.push(Dropdown_module_default["alignRight"] ?? "");
432
501
  return /* @__PURE__ */ jsxDEV3("div", {
433
502
  id,
434
503
  class: parts.filter(Boolean).join(" "),
@@ -445,7 +514,8 @@ function Dropdown(props) {
445
514
  ref: menuRef,
446
515
  id: popoverId,
447
516
  role: "listbox",
448
- class: menuParts.filter(Boolean).join(" "),
517
+ class: Dropdown_module_default["menu"] ?? "",
518
+ "data-align": align,
449
519
  popover: "auto",
450
520
  "data-overlay-id": popoverId,
451
521
  onToggle: handleToggle,
@@ -510,6 +580,7 @@ function ActionSelect(props) {
510
580
  if (className)
511
581
  parts.push(className);
512
582
  return /* @__PURE__ */ jsxDEV4("div", {
583
+ ...collectPassthrough(props),
513
584
  id,
514
585
  class: parts.filter(Boolean).join(" "),
515
586
  "data-polly-ui": true,
@@ -691,6 +762,7 @@ function Button(props) {
691
762
  href: disabled ? undefined : props.href,
692
763
  target: "target" in props ? props.target : undefined,
693
764
  rel: "rel" in props ? props.rel : undefined,
765
+ download: "download" in props ? props.download : undefined,
694
766
  "aria-disabled": disabled,
695
767
  "aria-label": ariaLabel,
696
768
  "data-polly-ui": true,
@@ -841,6 +913,7 @@ function Surface(props) {
841
913
  const position = props.position ?? v.position;
842
914
  const inset = props.inset ?? v.inset;
843
915
  const zIndex = props.zIndex ?? v.zIndex;
916
+ const { maxHeight, overflow, borderStyle, transform } = props;
844
917
  const borderWidth = props.borderWidth ?? v.borderWidth ?? (border && border !== "none" ? "default" : undefined);
845
918
  const style = {};
846
919
  if (padding)
@@ -855,18 +928,26 @@ function Surface(props) {
855
928
  style["--s-border-width"] = borderWidthValue(borderWidth);
856
929
  if (shadow)
857
930
  style["--s-shadow"] = shadowValue(shadow);
931
+ if (borderStyle)
932
+ style["--s-border-style"] = borderStyle;
858
933
  if (width)
859
934
  style["--s-w"] = width;
860
935
  if (height)
861
936
  style["--s-h"] = height;
862
937
  if (minHeight)
863
938
  style["--s-mh"] = minHeight;
939
+ if (maxHeight)
940
+ style["--s-maxh"] = maxHeight;
864
941
  if (maxInlineSize)
865
942
  style["--s-mis"] = maxInlineSize;
943
+ if (overflow)
944
+ style["--s-overflow"] = overflow;
866
945
  if (position)
867
946
  style["--s-position"] = position;
868
947
  if (inset)
869
948
  style["--s-inset"] = inset;
949
+ if (transform)
950
+ style["--s-transform"] = transform;
870
951
  if (zIndex !== undefined)
871
952
  style["--s-z"] = String(zIndex);
872
953
  if (props.style) {
@@ -1041,6 +1122,7 @@ function Cluster(props) {
1041
1122
  if (className)
1042
1123
  parts.push(className);
1043
1124
  return createElement3(as, {
1125
+ ...collectPassthrough(props),
1044
1126
  id,
1045
1127
  class: parts.filter(Boolean).join(" "),
1046
1128
  style,
@@ -1060,11 +1142,13 @@ var Code_module_default = {
1060
1142
  import { jsxDEV as jsxDEV9 } from "preact/jsx-dev-runtime";
1061
1143
  function Code(props) {
1062
1144
  const { children, block, className, id } = props;
1145
+ const passthrough = collectPassthrough(props);
1063
1146
  if (block) {
1064
1147
  const parts2 = [Code_module_default["block"]];
1065
1148
  if (className)
1066
1149
  parts2.push(className);
1067
1150
  return /* @__PURE__ */ jsxDEV9("pre", {
1151
+ ...passthrough,
1068
1152
  id,
1069
1153
  class: parts2.filter(Boolean).join(" "),
1070
1154
  "data-polly-ui": true,
@@ -1078,6 +1162,7 @@ function Code(props) {
1078
1162
  if (className)
1079
1163
  parts.push(className);
1080
1164
  return /* @__PURE__ */ jsxDEV9("code", {
1165
+ ...passthrough,
1081
1166
  id,
1082
1167
  class: parts.filter(Boolean).join(" "),
1083
1168
  "data-polly-ui": true,
@@ -1755,6 +1840,13 @@ import { createElement as createElement4 } from "preact";
1755
1840
  var Text_module_default = {
1756
1841
  text: "text_75HKdQ",
1757
1842
  muted: "muted_75HKdQ",
1843
+ danger: "danger_75HKdQ",
1844
+ warning: "warning_75HKdQ",
1845
+ success: "success_75HKdQ",
1846
+ italic: "italic_75HKdQ",
1847
+ tight: "tight_75HKdQ",
1848
+ base: "base_75HKdQ",
1849
+ loose: "loose_75HKdQ",
1758
1850
  xs: "xs_75HKdQ",
1759
1851
  sm: "sm_75HKdQ",
1760
1852
  md: "md_75HKdQ",
@@ -1767,23 +1859,37 @@ var Text_module_default = {
1767
1859
 
1768
1860
  // src/polly-ui/Text.tsx
1769
1861
  function Text(props) {
1770
- const { children, as = "span", tone = "default", size, weight, className, id } = props;
1862
+ const {
1863
+ children,
1864
+ as = "span",
1865
+ tone = "default",
1866
+ size,
1867
+ weight,
1868
+ italic,
1869
+ leading,
1870
+ className,
1871
+ id
1872
+ } = props;
1771
1873
  const parts = [Text_module_default["text"]];
1772
- if (tone === "muted")
1773
- parts.push(Text_module_default["muted"]);
1874
+ if (tone !== "default")
1875
+ parts.push(Text_module_default[tone]);
1774
1876
  if (size)
1775
1877
  parts.push(Text_module_default[size]);
1776
1878
  if (weight)
1777
1879
  parts.push(Text_module_default[weight]);
1880
+ if (italic)
1881
+ parts.push(Text_module_default["italic"]);
1882
+ if (leading)
1883
+ parts.push(Text_module_default[leading]);
1778
1884
  if (className)
1779
1885
  parts.push(className);
1780
1886
  return createElement4(as, {
1887
+ ...collectPassthrough(props),
1781
1888
  id,
1782
1889
  class: parts.filter(Boolean).join(" "),
1783
1890
  for: props.htmlFor,
1784
1891
  "data-polly-ui": true,
1785
- "data-polly-text": tone,
1786
- "aria-hidden": props["aria-hidden"]
1892
+ "data-polly-text": tone
1787
1893
  }, children);
1788
1894
  }
1789
1895
  // src/polly-ui/internal/input-base.ts
@@ -2047,4 +2153,4 @@ export {
2047
2153
  ActionForm
2048
2154
  };
2049
2155
 
2050
- //# debugId=05E49C730A24E5F464756E2164756E21
2156
+ //# debugId=1CBD05449C07223E64756E2164756E21