@imfusion/web-ui 0.11.1-dev.83.g3251cc92 → 0.11.1-dev.87.g55c5e1df

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
@@ -10,6 +10,13 @@
10
10
 
11
11
  ### Added
12
12
 
13
+ - `RichLink` takes `size="sm"` for dense lists: 6px block padding, a 32px tile, and a closer gap between glyph and text. The default `md` is unchanged.
14
+ [RichLink](src/components/rich-link/rich-link.mdx) — Nikolaus Brunner <brunner@imfusion.com>
15
+ - `Code.Inline` takes `concealable` to hide its content behind an eye button, hidden by default. `concealed` and
16
+ `onConcealedChange` control it, `defaultConcealed` sets its start, and `concealedLength` sets the placeholder width before a
17
+ value arrives. `copyConcealed` keeps copy working while hidden, `toggleLabel` names the eye button, and `size` (`sm`, `md`,
18
+ `lg`) sets the chip height.
19
+ [Code](src/components/code/code.mdx) — Nikolaus Brunner <brunner@imfusion.com>
13
20
  - `Avatar` takes `size="xs"`, 16px with smaller initials, to sit in the slot of a 16px icon or swatch in a list row.
14
21
  [Avatar](src/components/avatar/avatar.mdx) — Nikolaus Brunner <brunner@imfusion.com>
15
22
  - `Input` takes `shortcut` to show a key such as `/` or `Ctrl K` at its end and set `aria-keyshortcuts`. The key hides before the
@@ -0,0 +1,185 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ import { Hu as t, Vu as n, Xo as r, ja as i, vM as a } from "./icons-CMetKl2x.js";
3
+ import { t as o } from "./meta-V_KyLeGn.js";
4
+ import { a as s, i as c, n as l, o as u, s as d } from "./scroll-area-CXQ_SxPX.js";
5
+ import { cva as f, cx as p } from "class-variance-authority";
6
+ import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
7
+ import { Children as _, isValidElement as v, useCallback as y, useEffect as b, useRef as x, useState as S } from "react";
8
+ import { Toggle as C } from "@base-ui/react/toggle";
9
+ import { useRender as w } from "@base-ui/react/use-render";
10
+ import { mergeProps as T } from "@base-ui/react/merge-props";
11
+ //#region src/hooks/use-clipboard.ts
12
+ function E({ timeout: e = 1500 } = {}) {
13
+ let [t, n] = S(!1), r = x(void 0);
14
+ return b(() => () => clearTimeout(r.current), []), {
15
+ copied: t,
16
+ copy: y((t) => {
17
+ navigator.clipboard.writeText(t).then(() => {
18
+ n(!0), clearTimeout(r.current), r.current = setTimeout(() => n(!1), e);
19
+ });
20
+ }, [e])
21
+ };
22
+ }
23
+ var D = {
24
+ block: "imf-ui-code-module-block",
25
+ copy: "imf-ui-code-module-copy",
26
+ inline: "imf-ui-code-module-inline",
27
+ inlineCopy: "imf-ui-code-module-inlineCopy",
28
+ inlineEye: "imf-ui-code-module-inlineEye",
29
+ inlineLink: "imf-ui-code-module-inlineLink",
30
+ language: "imf-ui-code-module-language",
31
+ pending: "imf-ui-code-module-pending",
32
+ placeholder: "imf-ui-code-module-placeholder",
33
+ pre: "imf-ui-code-module-pre",
34
+ pulse: "imf-ui-code-module-pulse",
35
+ separator: "imf-ui-code-module-separator",
36
+ sizeLg: "imf-ui-code-module-sizeLg",
37
+ sizeMd: "imf-ui-code-module-sizeMd"
38
+ };
39
+ //#endregion
40
+ //#region src/components/code/text-of.ts
41
+ function O(e) {
42
+ let t = "";
43
+ return _.forEach(e, (e) => {
44
+ typeof e == "string" || typeof e == "number" ? t += String(e) : v(e) && (t += O(e.props.children));
45
+ }), t;
46
+ }
47
+ //#endregion
48
+ //#region src/components/code/code.tsx
49
+ var k = /* @__PURE__ */ e({
50
+ Block: () => N,
51
+ Inline: () => j,
52
+ InlineLink: () => M
53
+ }), A = f(D.inline, { variants: { size: {
54
+ sm: null,
55
+ md: D.sizeMd,
56
+ lg: D.sizeLg
57
+ } } });
58
+ function j({ copyable: e = !1, concealable: o = !1, concealed: s, onConcealedChange: c, defaultConcealed: l = !0, concealedLength: u = 8, copyConcealed: d = !1, size: f = "sm", toggleLabel: v = "Show", children: y, render: b, ...k }) {
59
+ let [j, M] = S(l), N = o && (s ?? j), { copied: P, copy: F } = E(), I = x(null), L = P ? i : r, R = O(y), z = _.toArray(y).length === 0, B = o && (N || z), V = { "--conceal-length": R.length || u }, H = o && (z || N && !d);
60
+ function U(e) {
61
+ s === void 0 && M(e), c?.(e);
62
+ }
63
+ return w({
64
+ defaultTagName: "code",
65
+ render: b,
66
+ props: {
67
+ ...T(k, {
68
+ className: A({ size: f }),
69
+ children: /* @__PURE__ */ g(m, { children: [
70
+ o && /* @__PURE__ */ h(C, {
71
+ className: D.inlineEye,
72
+ pressed: !N,
73
+ onPressedChange: (e) => U(!e),
74
+ "aria-label": v,
75
+ children: /* @__PURE__ */ h(a, {
76
+ glyph: N ? n : t,
77
+ size: 12,
78
+ strokeWidth: 2,
79
+ "aria-hidden": !0
80
+ })
81
+ }),
82
+ o && /* @__PURE__ */ h("span", { className: D.separator }),
83
+ B ? /* @__PURE__ */ h("span", {
84
+ role: "img",
85
+ "aria-label": "Hidden",
86
+ className: p(D.placeholder, !N && D.pending),
87
+ style: V
88
+ }) : /* @__PURE__ */ h("span", {
89
+ ref: I,
90
+ children: y
91
+ }),
92
+ e && /* @__PURE__ */ h("span", { className: D.separator }),
93
+ e && /* @__PURE__ */ h("button", {
94
+ type: "button",
95
+ className: D.inlineCopy,
96
+ "data-copied": P || void 0,
97
+ "aria-label": P ? "Copied" : "Copy",
98
+ disabled: H,
99
+ onClick: () => F(I.current?.textContent ?? R),
100
+ children: /* @__PURE__ */ h(a, {
101
+ glyph: L,
102
+ size: 12,
103
+ strokeWidth: 2,
104
+ "aria-hidden": !0
105
+ })
106
+ })
107
+ ] })
108
+ }),
109
+ "data-imf-ui-component": "Code.Inline",
110
+ "data-concealed": N || void 0,
111
+ "data-size": f
112
+ }
113
+ });
114
+ }
115
+ j.displayName = "Code.Inline";
116
+ function M({ kind: e = "external", ...t }) {
117
+ let n = e === "external" ? {
118
+ target: "_blank",
119
+ rel: "noreferrer"
120
+ } : {};
121
+ return w({
122
+ defaultTagName: "a",
123
+ render: t.render,
124
+ props: {
125
+ ...T(n, t, {
126
+ className: p(D.inline, D.inlineLink, t.className),
127
+ children: t.children
128
+ }),
129
+ "data-imf-ui-component": "Code.InlineLink",
130
+ "data-kind": e
131
+ }
132
+ });
133
+ }
134
+ M.displayName = "Code.InlineLink";
135
+ function N({ className: e, language: t, hideCopy: n = !1, children: o, ...f }) {
136
+ let { copied: m, copy: _ } = E(), v = x(null), y = m ? i : r;
137
+ return /* @__PURE__ */ g("div", {
138
+ "data-imf-ui-component": "Code.Block",
139
+ className: p(D.block, e),
140
+ children: [
141
+ t != null && /* @__PURE__ */ h("span", {
142
+ className: D.language,
143
+ children: t
144
+ }),
145
+ !n && /* @__PURE__ */ h("button", {
146
+ type: "button",
147
+ className: D.copy,
148
+ "data-copied": m || void 0,
149
+ "aria-label": m ? "Copied" : "Copy",
150
+ onClick: () => _(v.current?.textContent ?? ""),
151
+ children: /* @__PURE__ */ h(a, {
152
+ glyph: y,
153
+ size: 12,
154
+ strokeWidth: 2,
155
+ "aria-hidden": !0
156
+ })
157
+ }),
158
+ /* @__PURE__ */ g(c, { children: [/* @__PURE__ */ h(d, { children: /* @__PURE__ */ h(l, { children: /* @__PURE__ */ h("pre", {
159
+ ...f,
160
+ className: D.pre,
161
+ children: /* @__PURE__ */ h("code", {
162
+ ref: v,
163
+ children: o
164
+ })
165
+ }) }) }), /* @__PURE__ */ h(s, {
166
+ orientation: "horizontal",
167
+ children: /* @__PURE__ */ h(u, {})
168
+ })] })
169
+ ]
170
+ });
171
+ }
172
+ N.displayName = "Code.Block";
173
+ //#endregion
174
+ //#region src/components/code/code.meta.ts
175
+ var P = {
176
+ name: "Code",
177
+ category: o.display,
178
+ status: "stable",
179
+ namespace: !0,
180
+ description: "Displays source code inline or in a block, with optional language labels and copying. Also called a code snippet or code block.",
181
+ origin: "native",
182
+ internalDependencies: ["ScrollArea"]
183
+ };
184
+ //#endregion
185
+ export { k as a, M as i, N as n, E as o, j as r, P as t };
@@ -1,16 +1,39 @@
1
1
  import { useRender } from '@base-ui/react/use-render';
2
2
  type InlineProps = Omit<useRender.ComponentProps<"code">, "children"> & {
3
3
  /** Code content shown in the chip. The copy button copies its rendered text. */
4
- children: React.ReactNode;
4
+ children?: React.ReactNode;
5
5
  /** Show a small copy button on the right, behind a hairline separator. @default false */
6
6
  copyable?: boolean;
7
+ /** Show an eye button at the start that hides the content until it is pressed. @default false */
8
+ concealable?: boolean;
9
+ /** Whether the content is hidden. Needs `concealable`. Pass it with `onConcealedChange` to control the chip. */
10
+ concealed?: boolean;
11
+ /** Called with the new value when the eye button is pressed. */
12
+ onConcealedChange?: (concealed: boolean) => void;
13
+ /** Starting value of an uncontrolled chip. @default true */
14
+ defaultConcealed?: boolean;
15
+ /** Width in characters of the hidden placeholder when there is no text to measure. @default 8 */
16
+ concealedLength?: number;
17
+ /**
18
+ * Keep the copy button enabled while the content is hidden. It copies the text read from `children` without revealing it,
19
+ * so it needs text children: a component child copies nothing until revealed. @default false
20
+ */
21
+ copyConcealed?: boolean;
22
+ /** Height and type scale of the chip. @default "sm" */
23
+ size?: "sm" | "md" | "lg";
24
+ /** Accessible name of the eye button; `aria-pressed` tells whether the content is shown. @default "Show" */
25
+ toggleLabel?: string;
7
26
  };
8
27
  /**
9
28
  * Code.Inline — an inline code fragment (a `<code>` chip) for use inside running
10
29
  * text. `Typo.InlineCode` renders this under the hood so inline-code chrome is
11
30
  * defined in one place. The copy button copies the rendered text.
31
+ *
32
+ * With `concealable`, the content is replaced by a hatched placeholder until the
33
+ * eye button reveals it. A chip without content shows the placeholder with a
34
+ * pulse, so a consumer can reveal before the value has loaded.
12
35
  */
13
- export declare function Inline({ copyable, children, render, ...props }: InlineProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
36
+ export declare function Inline({ copyable, concealable, concealed: concealedProp, onConcealedChange, defaultConcealed, concealedLength, copyConcealed, size, toggleLabel, children, render, ...props }: InlineProps): import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>>;
14
37
  export declare namespace Inline {
15
38
  var displayName: string;
16
39
  }
@@ -0,0 +1,3 @@
1
+ import { ReactNode } from 'react';
2
+ /** The text a node renders, read from the element tree so nothing has to be in the DOM. */
3
+ export declare function textOf(node: ReactNode): string;
@@ -8,11 +8,13 @@ type Props = React.ComponentProps<"a"> & {
8
8
  kind?: "external" | "internal";
9
9
  /** Trailing icon from `@imfusion/web-ui/icons`, replacing the arrow `kind` picks, such as `Download` for a file. */
10
10
  endGlyph?: IconComponent;
11
+ /** Row density. `"md"` is the default row; `"sm"` tightens the padding, tile, and gap for dense lists. @default "md" */
12
+ size?: "sm" | "md";
11
13
  };
12
14
  /**
13
15
  * RichLink — a link as a whole row: an optional leading icon on a tinted tile, the label with an optional description
14
16
  * line, and a trailing icon for where it leads. Draws no divider; stacked links get their spacing from the layout. Wrap it
15
17
  * with TanStack Router's `createLink` to use it as a router link.
16
18
  */
17
- export declare function RichLink({ glyph, description, kind, endGlyph, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
19
+ export declare function RichLink({ glyph, description, kind, endGlyph, size, children, ...props }: Props): import("react/jsx-runtime").JSX.Element;
18
20
  export {};
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { t as v } from "./meta-V_KyLeGn.js";
4
4
  import { a as le, i as ue, n as de, r as fe, t as pe } from "./toggle-group-CVQzM3lQ.js";
5
5
  import { a as y, i as me, n as he, o as ge, r as _e, t as ve } from "./utils-J6vbjIt1.js";
6
6
  import { a as ye, i as be, n as xe, o as Se, r as Ce, t as we } from "./row-CaeE5pqs.js";
7
- import { a as Te, o as Ee, r as De, t as Oe } from "./code-72NzL5Cp.js";
7
+ import { a as Te, o as Ee, r as De, t as Oe } from "./code-BtxeEf9P.js";
8
8
  import { A as ke, D as Ae, M as je, N as Me, O as Ne, c as Pe, j as Fe, k as Ie, l as Le, m as Re, p as ze, s as Be, u as Ve } from "./tabs-BNz_OiWn.js";
9
9
  import { n as He, t as Ue } from "./toggle-group-ghJtINie.js";
10
10
  import { a as We, c as Ge, i as Ke, n as qe, o as Je, r as Ye, s as Xe, t as Ze } from "./scroll-area-CXQ_SxPX.js";
@@ -156,16 +156,17 @@ var Lt = {
156
156
  tile: "imf-ui-rich-link-module-tile",
157
157
  tileGlyph: "imf-ui-rich-link-module-tileGlyph"
158
158
  }, zt = b(Rt.root);
159
- function Bt({ glyph: e, description: t, kind: n = "external", endGlyph: r, children: i, ...a }) {
159
+ function Bt({ glyph: e, description: t, kind: n = "external", endGlyph: r, size: i = "md", children: a, ...o }) {
160
160
  return /* @__PURE__ */ C("a", {
161
161
  ...n === "external" ? {
162
162
  target: "_blank",
163
163
  rel: "noreferrer"
164
164
  } : {},
165
- ...a,
165
+ ...o,
166
166
  "data-imf-ui-component": "RichLink",
167
167
  "data-kind": n,
168
- className: zt({ className: a.className }),
168
+ "data-size": i,
169
+ className: zt({ className: o.className }),
169
170
  children: [
170
171
  e && /* @__PURE__ */ S("span", {
171
172
  className: Rt.tile,
@@ -179,7 +180,7 @@ function Bt({ glyph: e, description: t, kind: n = "external", endGlyph: r, child
179
180
  className: Rt.text,
180
181
  children: [/* @__PURE__ */ S("span", {
181
182
  className: Rt.label,
182
- children: i
183
+ children: a
183
184
  }), t && /* @__PURE__ */ S("span", {
184
185
  className: Rt.description,
185
186
  children: t
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "../rolldown-runtime-Dy4uBu1J.js";
2
2
  import { t } from "../meta-V_KyLeGn.js";
3
- import { i as n, n as r, r as i } from "../code-72NzL5Cp.js";
3
+ import { i as n, n as r, r as i } from "../code-BtxeEf9P.js";
4
4
  import { jsx as a } from "react/jsx-runtime";
5
5
  import { cloneElement as o, useMemo as s } from "react";
6
6
  import { createHighlighter as c, defineLanguage as l, renderNodesToHtml as u, renderTokens as d } from "@tanstack/highlight/core";