@tangle-network/ui 11.43.0 → 11.44.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,5 +1,11 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.44.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e19c28a: Add read-only `value` and optional `mono` presentation to SettingsRow while preserving children, the public props interface, and control message wiring. Value rows use the inline layout and stack in narrow cards; rows without a value keep their existing layout.
8
+
3
9
  ## 11.43.0
4
10
 
5
11
  ### Minor Changes
@@ -24,21 +24,25 @@ export interface SettingsRowProps {
24
24
  onRetry?: () => void;
25
25
  /**
26
26
  * `inline` (default): text left, control right, stacked below 34rem.
27
- * `compact`: the control keeps its own width and stays on the line (switches, single buttons).
27
+ * `compact`: the control keeps its own width and stays on the line (switches, single buttons); a row with a value uses `inline`.
28
28
  * `stacked`: the control spans the row under the text (textareas, lists).
29
29
  */
30
30
  layout?: SettingsRowLayout;
31
31
  /** Why the control is unavailable, naming who can change it. Replaces the description after a lock glyph. */
32
32
  disabledReason?: React.ReactNode;
33
+ /** A read-only value before any children; supplying even an empty value keeps its span. */
34
+ value?: React.ReactNode;
35
+ /** Use mono for the value, such as an identifier; children keep their own font. */
36
+ mono?: boolean;
33
37
  children?: React.ReactNode;
34
38
  }
35
39
  /**
36
- * One setting: its label, an optional consequence line and its control. The
40
+ * One setting: its label, an optional consequence line, read-only value and control. The
37
41
  * label carries the save status after it; an error or a lock reason replaces
38
42
  * the description. Rows inside a {@link SettingsSection} are divided by a
39
43
  * hairline and stack when the card is narrower than 34rem.
40
44
  */
41
- export declare function SettingsRow({ id, label, description, info, htmlFor, status, error, onRetry, layout, disabledReason, children }: SettingsRowProps): React.JSX.Element;
45
+ export declare function SettingsRow(props: SettingsRowProps): React.JSX.Element;
42
46
  export interface SettingsSectionProps {
43
47
  /** The section's anchor: `#id` scrolls to it. The title's id is `${id}-title`. */
44
48
  id: string;
@@ -60,18 +60,20 @@ function describeControl(children, htmlFor, messageId, invalid) {
60
60
  });
61
61
  }
62
62
  /**
63
- * One setting: its label, an optional consequence line and its control. The
63
+ * One setting: its label, an optional consequence line, read-only value and control. The
64
64
  * label carries the save status after it; an error or a lock reason replaces
65
65
  * the description. Rows inside a {@link SettingsSection} are divided by a
66
66
  * hairline and stack when the card is narrower than 34rem.
67
67
  */
68
- function SettingsRow({ id, label, description, info, htmlFor, status, error, onRetry, layout = "inline", disabledReason, children }) {
68
+ function SettingsRow(props) {
69
+ const { id, label, description, info, htmlFor, status, error, onRetry, layout = "inline", disabledReason, value, mono, children } = props;
70
+ const hasValue = Object.hasOwn(props, "value");
69
71
  const messageId = htmlFor ? fieldMessageId(htmlFor) : void 0;
70
72
  const control = describeControl(children, htmlFor, error != null || disabledReason != null || description != null ? messageId : void 0, error != null);
71
73
  return /* @__PURE__ */ jsxs("div", {
72
74
  id,
73
75
  "data-layout": layout,
74
- className: cn("grid min-w-0 items-center gap-x-8 gap-y-3 px-5 py-4 @max-[34rem]/settings-section:px-4", SCROLL_OFFSET, DIVIDED, ROW_COLUMNS[layout]),
76
+ className: cn("grid min-w-0 items-center gap-x-8 gap-y-3 px-5 py-4 @max-[34rem]/settings-section:px-4", SCROLL_OFFSET, DIVIDED, ROW_COLUMNS[hasValue && layout === "compact" ? "inline" : layout]),
75
77
  children: [/* @__PURE__ */ jsxs("div", {
76
78
  className: "min-w-0",
77
79
  children: [/* @__PURE__ */ jsxs("div", {
@@ -114,9 +116,13 @@ function SettingsRow({ id, label, description, info, htmlFor, status, error, onR
114
116
  className: "mt-0.5 text-sm leading-5 text-muted-foreground [overflow-wrap:anywhere]",
115
117
  children: description
116
118
  })]
117
- }), control != null && control !== false && /* @__PURE__ */ jsx("div", {
118
- className: cn("flex min-w-0 items-center gap-2", ROW_CONTROL[layout]),
119
- children: control
119
+ }), (hasValue || control != null && control !== false) && /* @__PURE__ */ jsxs("div", {
120
+ className: cn("flex min-w-0 items-center gap-2", ROW_CONTROL[hasValue && layout === "compact" ? "inline" : layout]),
121
+ children: [hasValue && /* @__PURE__ */ jsx("span", {
122
+ "data-slot": "settings-value",
123
+ className: cn("min-w-0 text-foreground text-sm [overflow-wrap:anywhere] @min-[34rem]/settings-section:text-right", mono && "font-mono"),
124
+ children: value
125
+ }), control]
120
126
  })]
121
127
  });
122
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/ui",
3
- "version": "11.43.0",
3
+ "version": "11.44.0",
4
4
  "description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -243,6 +243,40 @@ function FieldsExample() {
243
243
  );
244
244
  }
245
245
 
246
+ /** Read-only product data beside existing controls; all values here are sample data. */
247
+ function SettingsValuesExample() {
248
+ const [details, setDetails] = useState(false);
249
+ return (
250
+ <div className="mx-auto max-w-4xl space-y-6 p-6">
251
+ <SettingsSection id="read-only-values" title="Account values">
252
+ <SettingsRow id="value-zero" label="Active sessions" value={0} layout="compact" />
253
+ <SettingsRow id="value-empty" label="Empty value" value="" layout="compact" />
254
+ <SettingsRow id="value-false" label="False value" value={false} layout="compact" />
255
+ <SettingsRow id="value-null" label="Null value" value={null} layout="compact" />
256
+ <SettingsRow id="value-undefined" label="Undefined value" value={undefined} layout="compact" />
257
+ <SettingsRow id="value-mixed" label="Projected monthly cost" value={<>$0.00 <span className="text-muted-foreground">/month</span></>} layout="compact" />
258
+ <SettingsRow id="value-long" label="Session identifier" value="session_with_a_long_unbroken_identifier_that_must_wrap_inside_its_settings_card_without_hiding_the_label_or_overflowing" mono layout="compact" />
259
+ <SettingsRow id="value-agent" label="Agent identifier" value="research-agent" mono layout="compact" />
260
+ <SettingsRow id="value-model" label="Model identifier" value="workspace-model" mono layout="compact" />
261
+ <SettingsRow id="value-provider" label="Provider identifier" value="workspace-provider" mono layout="compact" />
262
+ <SettingsRow id="value-stacked" label="Stacked summary" value="Workspace summary" layout="stacked" />
263
+ <SettingsRow id="value-action" label="Value with action" value="workspace-provider" status={details ? "Details shown" : undefined} layout="compact">
264
+ <Button type="button" variant="outline" onClick={() => setDetails((shown) => !shown)}>{details ? "Hide details" : "Show details"}</Button>
265
+ </SettingsRow>
266
+ <SettingsRow id="value-control" label="Value with input" value="UTC" htmlFor="value-timezone" description="The original input keeps its message wiring.">
267
+ <Input id="value-timezone" defaultValue="UTC" />
268
+ </SettingsRow>
269
+ </SettingsSection>
270
+ <div className="max-w-sm">
271
+ <SettingsSection id="narrow-values" title="Narrow card in any window">
272
+ <SettingsRow id="narrow-value" label="Account email" value="reader@workspace.example" layout="compact" />
273
+ <SettingsRow id="legacy-compact" label="Daily digest" htmlFor="value-digest" layout="compact"><Switch id="value-digest" defaultChecked /></SettingsRow>
274
+ </SettingsSection>
275
+ </div>
276
+ </div>
277
+ );
278
+ }
279
+
246
280
  const meta = {
247
281
  title: "Primitives/Settings",
248
282
  component: SettingsSection,
@@ -265,3 +299,6 @@ export const Bounded: Story = { render: () => <SettingsPage className="mx-auto m
265
299
 
266
300
  /** The promoted Field: hint, info tip with an aside action, a live error, and a status. */
267
301
  export const Fields: Story = { render: () => <FieldsExample /> };
302
+
303
+ /** Values preserve ReactNode content and coexist with controls; only value rows stack in a narrow compact layout. */
304
+ export const Values: Story = { render: () => <SettingsValuesExample /> };
@@ -67,12 +67,16 @@ export interface SettingsRowProps {
67
67
  onRetry?: () => void;
68
68
  /**
69
69
  * `inline` (default): text left, control right, stacked below 34rem.
70
- * `compact`: the control keeps its own width and stays on the line (switches, single buttons).
70
+ * `compact`: the control keeps its own width and stays on the line (switches, single buttons); a row with a value uses `inline`.
71
71
  * `stacked`: the control spans the row under the text (textareas, lists).
72
72
  */
73
73
  layout?: SettingsRowLayout;
74
74
  /** Why the control is unavailable, naming who can change it. Replaces the description after a lock glyph. */
75
75
  disabledReason?: React.ReactNode;
76
+ /** A read-only value before any children; supplying even an empty value keeps its span. */
77
+ value?: React.ReactNode;
78
+ /** Use mono for the value, such as an identifier; children keep their own font. */
79
+ mono?: boolean;
76
80
  children?: React.ReactNode;
77
81
  }
78
82
 
@@ -101,14 +105,16 @@ function describeControl(children: React.ReactNode, htmlFor: string | undefined,
101
105
  }
102
106
 
103
107
  /**
104
- * One setting: its label, an optional consequence line and its control. The
108
+ * One setting: its label, an optional consequence line, read-only value and control. The
105
109
  * label carries the save status after it; an error or a lock reason replaces
106
110
  * the description. Rows inside a {@link SettingsSection} are divided by a
107
111
  * hairline and stack when the card is narrower than 34rem.
108
112
  */
109
- export function SettingsRow({
110
- id, label, description, info, htmlFor, status, error, onRetry, layout = "inline", disabledReason, children,
111
- }: SettingsRowProps) {
113
+ export function SettingsRow(props: SettingsRowProps) {
114
+ const {
115
+ id, label, description, info, htmlFor, status, error, onRetry, layout = "inline", disabledReason, value, mono, children,
116
+ } = props;
117
+ const hasValue = Object.hasOwn(props, "value");
112
118
  const messageId = htmlFor ? fieldMessageId(htmlFor) : undefined;
113
119
  const hasMessage = error != null || disabledReason != null || description != null;
114
120
  const control = describeControl(children, htmlFor, hasMessage ? messageId : undefined, error != null);
@@ -120,7 +126,7 @@ export function SettingsRow({
120
126
  "grid min-w-0 items-center gap-x-8 gap-y-3 px-5 py-4 @max-[34rem]/settings-section:px-4",
121
127
  SCROLL_OFFSET,
122
128
  DIVIDED,
123
- ROW_COLUMNS[layout],
129
+ ROW_COLUMNS[hasValue && layout === "compact" ? "inline" : layout],
124
130
  )}
125
131
  >
126
132
  <div className="min-w-0">
@@ -142,8 +148,11 @@ export function SettingsRow({
142
148
  <div id={messageId} className="mt-0.5 text-sm leading-5 text-muted-foreground [overflow-wrap:anywhere]">{description}</div>
143
149
  )}
144
150
  </div>
145
- {control != null && control !== false && (
146
- <div className={cn("flex min-w-0 items-center gap-2", ROW_CONTROL[layout])}>{control}</div>
151
+ {(hasValue || (control != null && control !== false)) && (
152
+ <div className={cn("flex min-w-0 items-center gap-2", ROW_CONTROL[hasValue && layout === "compact" ? "inline" : layout])}>
153
+ {hasValue && <span data-slot="settings-value" className={cn("min-w-0 text-foreground text-sm [overflow-wrap:anywhere] @min-[34rem]/settings-section:text-right", mono && "font-mono")}>{value}</span>}
154
+ {control}
155
+ </div>
147
156
  )}
148
157
  </div>
149
158
  );