@fairfox/polly 0.74.1 → 0.75.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.
@@ -8,7 +8,9 @@
8
8
  */
9
9
  import type { ComponentChildren, JSX } from "preact";
10
10
  export type CollapsibleProps = {
11
- summary: string;
11
+ /** Disclosure header. A string for the common case, or any node —
12
+ * e.g. a muted, small <Text> — when the header needs styling. */
13
+ summary: ComponentChildren;
12
14
  children: ComponentChildren;
13
15
  defaultOpen?: boolean;
14
16
  className?: string;
@@ -28,7 +28,9 @@ export type DropdownProps = {
28
28
  * Class applied to the trigger <button> in place of Dropdown's own
29
29
  * default. Lets a composing component (Select, ActionSelect) style
30
30
  * the single interactive element directly, with no styled node
31
- * nested inside the button.
31
+ * nested inside the button. The trigger also carries a
32
+ * `data-open="true|false"` attribute mirroring `isOpen`, so the
33
+ * class can style open-state affordances (e.g. a rotating caret).
32
34
  */
33
35
  triggerClassName?: string;
34
36
  /** Disables the trigger <button>. */
@@ -0,0 +1,25 @@
1
+ /**
2
+ * FileInput — a styled trigger for the native file picker.
3
+ *
4
+ * A file is a binary object: it cannot ride a `data-action` attribute
5
+ * the way a string value does, so FileInput is the one input primitive
6
+ * that takes a callback. `onFiles` fires with the chosen FileList. The
7
+ * native <input type="file"> stays in the DOM — visually hidden inside
8
+ * the <label> — so the whole control opens the picker and remains
9
+ * keyboard-accessible (polly#135).
10
+ */
11
+ import type { JSX } from "preact";
12
+ export type FileInputProps = {
13
+ /** Fired with the chosen files whenever the selection changes. */
14
+ onFiles: (files: FileList) => void;
15
+ /** Visible trigger text. Default: 'Choose file'. */
16
+ label?: string;
17
+ /** `accept` filter forwarded to the native input (e.g. 'image/*'). */
18
+ accept?: string;
19
+ /** Allow selecting more than one file. */
20
+ multiple?: boolean;
21
+ disabled?: boolean;
22
+ className?: string;
23
+ id?: string;
24
+ };
25
+ export declare function FileInput(props: FileInputProps): JSX.Element;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Html — render trusted, already-sanitised raw markup.
3
+ *
4
+ * The deliberate escape hatch for the rare thing polly-ui cannot
5
+ * express: a locally generated, already-safe SVG (a QR code), a
6
+ * pre-rendered diagram. The caller owns safety — `html` goes straight
7
+ * into `dangerouslySetInnerHTML`, so it MUST be trusted or sanitised
8
+ * first. For untrusted markdown use `renderMarkdown`, which sanitises;
9
+ * for anything a primitive already covers, use the primitive.
10
+ */
11
+ import { type JSX } from "preact";
12
+ import { type PassthroughAttrs } from "./internal/passthrough.ts";
13
+ export type HtmlProps = PassthroughAttrs & {
14
+ /** Trusted, already-sanitised HTML. The caller owns its safety. */
15
+ html: string;
16
+ /** Polymorphic wrapper element (div, span, figure, …). Defaults to 'div'. */
17
+ as?: keyof JSX.IntrinsicElements;
18
+ className?: string;
19
+ id?: string;
20
+ };
21
+ export declare function Html(props: HtmlProps): JSX.Element;
@@ -8,7 +8,8 @@
8
8
  * any of them in media queries without touching specificity.
9
9
  */
10
10
  import { type ComponentChildren, type JSX } from "preact";
11
- export type LayoutProps = {
11
+ import { type PassthroughAttrs } from "./internal/passthrough.ts";
12
+ export type LayoutProps = PassthroughAttrs & {
12
13
  children: ComponentChildren;
13
14
  /** Polymorphic element (div, section, header, nav, …). Defaults to 'div'. */
14
15
  as?: keyof JSX.IntrinsicElements;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Link — token-styled navigational anchor.
3
+ *
4
+ * The primitive for plain hyperlinks: hub app-grid cards, a file
5
+ * download, an external reference. <Button href> is for link-shaped
6
+ * BUTTONS — a call to action wearing button chrome; <Link> is for
7
+ * inline, textual links that read as links. `external` opens a new tab
8
+ * with `rel="noopener noreferrer"`; `download` offers the target as a
9
+ * file (an empty string keeps the resource's own filename).
10
+ */
11
+ import type { ComponentChildren, JSX } from "preact";
12
+ import { type PassthroughAttrs } from "./internal/passthrough.ts";
13
+ export type LinkProps = PassthroughAttrs & {
14
+ children: ComponentChildren;
15
+ href: string;
16
+ /** Open in a new tab with rel="noopener noreferrer". */
17
+ external?: boolean;
18
+ /** Offer the href as a download; an empty string keeps its filename. */
19
+ download?: string;
20
+ /** Drop the underline until hover — for link grids and card links. */
21
+ subtle?: boolean;
22
+ className?: string;
23
+ id?: string;
24
+ };
25
+ export declare function Link(props: LinkProps): JSX.Element;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Output — read-only, multi-line diagnostic text.
3
+ *
4
+ * For program output a consumer must SHOW but not edit: a mesh-state
5
+ * snapshot, a per-peer sync table, a recovery blob. <TextInput> and
6
+ * <ActionInput> are single-line and editable; <Code> is for code
7
+ * samples and never wraps. <Output> renders a monospace <pre> that
8
+ * wraps long lines by default — a diagnostic dump should stay on
9
+ * screen — with `scroll` to switch to a horizontal scrollbar instead.
10
+ *
11
+ * It carries the polly#125 passthrough surface, so a `data-action`
12
+ * for a tap-to-select-all gesture rides straight onto the <pre>
13
+ * (polly#135).
14
+ */
15
+ import type { ComponentChildren, JSX } from "preact";
16
+ import { type PassthroughAttrs } from "./internal/passthrough.ts";
17
+ export type OutputProps = PassthroughAttrs & {
18
+ children: ComponentChildren;
19
+ /** Scroll long unbreakable lines horizontally instead of wrapping. */
20
+ scroll?: boolean;
21
+ /** Make the block focusable — pair with a `data-action` tap gesture. */
22
+ tabIndex?: number;
23
+ className?: string;
24
+ id?: string;
25
+ };
26
+ export declare function Output(props: OutputProps): JSX.Element;
@@ -21,14 +21,16 @@ type Shadow = "none" | "sm" | "md" | "lg";
21
21
  type Position = "static" | "relative" | "absolute" | "sticky" | "fixed";
22
22
  type BorderStyle = "solid" | "dashed";
23
23
  type Overflow = "visible" | "hidden" | "auto" | "scroll";
24
+ type Scheme = "dark" | "light";
24
25
  /**
25
- * Arbitrary `data-*` and `aria-*` attributes forwarded to the rendered element
26
- * so consumers (Modal, Toast, Card, etc.) can compose Surface without losing
27
- * DOM hooks or ARIA semantics.
26
+ * Arbitrary `data-*`, `aria-*`, and `title` attributes forwarded to the
27
+ * rendered element so consumers (Modal, Toast, Card, etc.) can compose
28
+ * Surface without losing DOM hooks, ARIA semantics, or a native tooltip.
28
29
  */
29
30
  export type SurfaceDataAttrs = {
30
31
  [dataAttr: `data-${string}`]: string | number | boolean | undefined;
31
32
  [ariaAttr: `aria-${string}`]: string | number | boolean | undefined;
33
+ title?: string;
32
34
  };
33
35
  export type SurfaceProps = SurfaceDataAttrs & {
34
36
  children?: ComponentChildren;
@@ -46,7 +48,22 @@ export type SurfaceProps = SurfaceDataAttrs & {
46
48
  borderSides?: BorderSides;
47
49
  /** Border line style. Default: `'solid'`. */
48
50
  borderStyle?: BorderStyle;
51
+ /** Any CSS colour, overriding the token the `border` prop would pick.
52
+ * For one-off rings (a cutout ring, a focus halo) that no semantic
53
+ * border token expresses. Implies a border width when none is set. */
54
+ borderColor?: string;
49
55
  shadow?: Shadow;
56
+ /**
57
+ * Retint the token subtree so descendant `Text`/`Button` read the
58
+ * right contrast on a dark (or forced-light) Surface — error
59
+ * banners, camera overlays, chat bubbles. Sets `data-polly-theme`,
60
+ * so every `--polly-*` colour token flips for the subtree; no inline
61
+ * `--polly-text` override needed (polly#135).
62
+ */
63
+ scheme?: Scheme;
64
+ /** `'none'` makes a decorative Surface (a scan-frame overlay) ignore
65
+ * the pointer so clicks fall through to what is behind it. */
66
+ pointerEvents?: "none" | "auto";
50
67
  /** display: inline-block — Surface flows inline with surrounding text. */
51
68
  inline?: boolean;
52
69
  width?: string;
@@ -33,6 +33,8 @@ export type TextProps = PassthroughAttrs & {
33
33
  weight?: TextWeight;
34
34
  /** Italic emphasis — for hints and asides — without an inline style. */
35
35
  italic?: boolean;
36
+ /** Line-through — for completed todo items and superseded copy. */
37
+ strikethrough?: boolean;
36
38
  /** Token-backed line height. 'loose' suits multi-line body copy. */
37
39
  leading?: TextLeading;
38
40
  className?: string;
@@ -191,16 +191,21 @@
191
191
  .caret_daofbw {
192
192
  color: var(--polly-text-muted);
193
193
  pointer-events: none;
194
+ transition: transform var(--polly-motion-fast) ease;
194
195
  flex: none;
195
196
  }
196
197
 
197
198
  .caret_daofbw:before {
198
199
  content: "▾";
199
200
  display: block;
200
- font-size: var(--polly-text-xs);
201
+ font-size: var(--polly-text-md);
201
202
  line-height: 1;
202
203
  }
203
204
 
205
+ .trigger_daofbw[data-open="true"] .caret_daofbw {
206
+ transform: rotate(180deg);
207
+ }
208
+
204
209
  .placeholder_daofbw {
205
210
  color: var(--polly-text-muted);
206
211
  }
@@ -425,6 +430,7 @@
425
430
  --s-inset: auto;
426
431
  --s-transform: none;
427
432
  --s-z: auto;
433
+ --s-pe: auto;
428
434
  box-sizing: border-box;
429
435
  padding: var(--s-p);
430
436
  background: var(--s-bg);
@@ -443,6 +449,7 @@
443
449
  inset: var(--s-inset);
444
450
  transform: var(--s-transform);
445
451
  z-index: var(--s-z);
452
+ pointer-events: var(--s-pe);
446
453
  }
447
454
 
448
455
  .inline_pQCFqA {
@@ -728,6 +735,96 @@
728
735
  }
729
736
  }
730
737
 
738
+ /* src/polly-ui/FileInput.module.css */
739
+ @layer polly-components {
740
+ .fileInput_esO1fA {
741
+ display: inline-flex;
742
+ align-items: center;
743
+ gap: var(--polly-space-sm);
744
+ min-block-size: var(--polly-control-height-md);
745
+ padding: var(--polly-space-sm) var(--polly-space-md);
746
+ border: var(--polly-border-width-default) solid var(--polly-border);
747
+ border-radius: var(--polly-radius-sm);
748
+ background-color: var(--polly-surface);
749
+ font-family: inherit;
750
+ font-size: var(--polly-text-md);
751
+ color: var(--polly-text);
752
+ cursor: pointer;
753
+ }
754
+
755
+ .fileInput_esO1fA:hover {
756
+ background-color: var(--polly-surface-sunken);
757
+ }
758
+
759
+ .fileInput_esO1fA:focus-within {
760
+ outline: var(--polly-border-width-medium) solid var(--polly-focus-ring);
761
+ outline-offset: var(--polly-border-width-medium);
762
+ }
763
+
764
+ .native_esO1fA {
765
+ position: absolute;
766
+ overflow: hidden;
767
+ clip: rect(0 0 0 0);
768
+ white-space: nowrap;
769
+ border: 0;
770
+ width: 1px;
771
+ height: 1px;
772
+ margin: -1px;
773
+ padding: 0;
774
+ }
775
+
776
+ .disabled_esO1fA {
777
+ opacity: var(--polly-opacity-disabled);
778
+ cursor: not-allowed;
779
+ }
780
+ }
781
+
782
+ /* src/polly-ui/Link.module.css */
783
+ @layer polly-components {
784
+ .link__T-0-w {
785
+ color: var(--polly-accent);
786
+ text-decoration: underline;
787
+ text-underline-offset: .15em;
788
+ border-radius: var(--polly-radius-sm);
789
+ cursor: pointer;
790
+ }
791
+
792
+ .link__T-0-w:hover {
793
+ color: var(--polly-accent-hover);
794
+ }
795
+
796
+ .subtle__T-0-w {
797
+ text-decoration: none;
798
+ }
799
+
800
+ .subtle__T-0-w:hover {
801
+ text-decoration: underline;
802
+ }
803
+ }
804
+
805
+ /* src/polly-ui/Output.module.css */
806
+ @layer polly-components {
807
+ .output_wLrUbA {
808
+ padding: var(--polly-space-md);
809
+ border: var(--polly-border-width-default) solid var(--polly-border);
810
+ border-radius: var(--polly-radius-md);
811
+ background-color: var(--polly-surface-sunken);
812
+ font-family: var(--polly-font-mono);
813
+ font-size: var(--polly-text-sm);
814
+ color: var(--polly-text);
815
+ white-space: pre-wrap;
816
+ overflow-wrap: anywhere;
817
+ max-inline-size: 100%;
818
+ margin: 0;
819
+ }
820
+
821
+ .scroll_wLrUbA {
822
+ white-space: pre;
823
+ overflow-wrap: normal;
824
+ overflow-x: auto;
825
+ }
826
+ }
827
+
731
828
  /* src/polly-ui/Skeleton.module.css */
732
829
  @layer polly-components {
733
830
  @keyframes pollyShimmer_gpBHJA {
@@ -834,6 +931,10 @@
834
931
  font-style: italic;
835
932
  }
836
933
 
934
+ .strikethrough_75HKdQ {
935
+ text-decoration: line-through;
936
+ }
937
+
837
938
  .tight_75HKdQ {
838
939
  line-height: var(--polly-line-height-tight);
839
940
  }
@@ -19,8 +19,12 @@ export { Code, type CodeProps } from "./Code.tsx";
19
19
  export { Collapsible, type CollapsibleProps } from "./Collapsible.tsx";
20
20
  export { ConfirmDialog, type ConfirmOptions, confirm } from "./ConfirmDialog.tsx";
21
21
  export { Dropdown, type DropdownProps } from "./Dropdown.tsx";
22
+ export { FileInput, type FileInputProps } from "./FileInput.tsx";
23
+ export { Html, type HtmlProps } from "./Html.tsx";
22
24
  export { Layout, type LayoutProps } from "./Layout.tsx";
25
+ export { Link, type LinkProps } from "./Link.tsx";
23
26
  export { Modal } from "./Modal.tsx";
27
+ export { Output, type OutputProps } from "./Output.tsx";
24
28
  export { getOverlayRootNode, OverlayRoot } from "./OverlayRoot.tsx";
25
29
  export { Select, type SelectOption, type SelectProps } from "./Select.tsx";
26
30
  export { Skeleton, type SkeletonProps, type SkeletonVariant } from "./Skeleton.tsx";