milestone 32: task-shaped configuration, file mode as a rendering, config status api
Gates / frontend (push) Successful in 1m22s
Gates / test (push) Successful in 1m54s
Gates / test-aarch64 (push) Successful in 7m57s
Gates / package (push) Successful in 5m29s
Gates / container (push) Successful in 10s
CI / gates (push) Successful in 32m51s
Gates / frontend (push) Successful in 1m22s
Gates / test (push) Successful in 1m54s
Gates / test-aarch64 (push) Successful in 7m57s
Gates / package (push) Successful in 5m29s
Gates / container (push) Successful in 10s
CI / gates (push) Successful in 32m51s
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import type { ReactNode } from "react";
|
||||
import * as stylex from "@stylexjs/stylex";
|
||||
import { styles as shared } from "./styles";
|
||||
import { colors } from "./tokens.stylex";
|
||||
|
||||
export interface Definition {
|
||||
/** What the operator calls the value. */
|
||||
label: string;
|
||||
/**
|
||||
* The exact key in the configuration file, shown secondarily so the reader
|
||||
* can find the line to edit. Omitted for a derived value that has no key —
|
||||
* inventing one would send the reader looking for something not there.
|
||||
*/
|
||||
zonKey?: string;
|
||||
value: ReactNode;
|
||||
}
|
||||
|
||||
const styles = stylex.create({
|
||||
list: {
|
||||
display: "grid",
|
||||
gap: "0.75rem",
|
||||
gridTemplateColumns: {
|
||||
default: "repeat(1, minmax(0, 1fr))",
|
||||
"@media (min-width: 640px)": "repeat(2, minmax(0, 1fr))",
|
||||
},
|
||||
margin: 0,
|
||||
},
|
||||
term: {
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
fontWeight: 500,
|
||||
},
|
||||
key: {
|
||||
marginLeft: "0.375rem",
|
||||
fontSize: "0.75rem",
|
||||
lineHeight: "1rem",
|
||||
fontWeight: 400,
|
||||
color: colors.textMuted,
|
||||
},
|
||||
value: {
|
||||
marginTop: "0.125rem",
|
||||
marginLeft: 0,
|
||||
fontSize: "0.875rem",
|
||||
lineHeight: "1.25rem",
|
||||
color: colors.text,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Scalars as a definition list — the file-mode counterpart of a form section.
|
||||
* Nothing here is interactive: a value the process loaded from a file is read,
|
||||
* not edited.
|
||||
*/
|
||||
export default function DefinitionList({ items }: { items: readonly Definition[] }) {
|
||||
return (
|
||||
<dl {...stylex.props(styles.list)}>
|
||||
{items.map((item) => (
|
||||
<div key={item.label}>
|
||||
<dt {...stylex.props(styles.term)}>
|
||||
{item.label}
|
||||
{item.zonKey !== undefined && (
|
||||
<code {...stylex.props(shared.mono, styles.key)}>{item.zonKey}</code>
|
||||
)}
|
||||
</dt>
|
||||
<dd {...stylex.props(styles.value)}>{item.value}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
);
|
||||
}
|
||||
+28
-1
@@ -11,7 +11,16 @@
|
||||
*/
|
||||
|
||||
import * as stylex from "@stylexjs/stylex";
|
||||
import { Button, Label, ListBox, ListBoxItem, Popover, Select as AriaSelect, SelectValue } from "react-aria-components";
|
||||
import {
|
||||
Button,
|
||||
Label,
|
||||
ListBox,
|
||||
ListBoxItem,
|
||||
Popover,
|
||||
Select as AriaSelect,
|
||||
SelectValue,
|
||||
Text,
|
||||
} from "react-aria-components";
|
||||
import { colors } from "./tokens.stylex";
|
||||
import { styles as shared } from "./styles";
|
||||
|
||||
@@ -27,6 +36,12 @@ interface Props {
|
||||
/** The visible label. Omit it only when `aria-label` names the control. */
|
||||
label?: string;
|
||||
"aria-label"?: string;
|
||||
/**
|
||||
* Text under the control that qualifies it. RAC gives it an id and points the
|
||||
* trigger's `aria-describedby` at it, which a sibling rendered by the caller
|
||||
* cannot be: the trigger is this file's, so only this file can name it.
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* `field` matches a full-width form input, `compactField` the smaller one a
|
||||
* dialog uses, `inline` a control sitting in a row of other controls.
|
||||
@@ -70,6 +85,12 @@ const styles = stylex.create({
|
||||
chevron: {
|
||||
color: colors.textMuted,
|
||||
},
|
||||
description: {
|
||||
display: "block",
|
||||
fontSize: "0.75rem",
|
||||
lineHeight: "1rem",
|
||||
color: colors.textMuted,
|
||||
},
|
||||
popover: {
|
||||
width: "var(--trigger-width)",
|
||||
maxHeight: "16rem",
|
||||
@@ -116,6 +137,7 @@ export default function Select({
|
||||
onChange,
|
||||
label,
|
||||
"aria-label": ariaLabel,
|
||||
description,
|
||||
variant = "field",
|
||||
isDisabled = false,
|
||||
}: Props) {
|
||||
@@ -136,6 +158,11 @@ export default function Select({
|
||||
▾
|
||||
</span>
|
||||
</Button>
|
||||
{description !== undefined && (
|
||||
<Text slot="description" {...stylex.props(styles.description)}>
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
<Popover className={() => stylex.props(styles.popover).className ?? ""}>
|
||||
<ListBox {...stylex.props(styles.listBox)}>
|
||||
{options.map((option) => (
|
||||
|
||||
+13
-2
@@ -25,6 +25,13 @@ interface Props {
|
||||
/** The tab list's accessible name. */
|
||||
label: string;
|
||||
tabs: readonly TabSpec[];
|
||||
/**
|
||||
* The open tab, when a caller owns the selection — the configuration pages
|
||||
* keep it in the URL. Omit both of these to let RAC hold the state, which
|
||||
* is what a tab set with no linkable identity wants.
|
||||
*/
|
||||
selectedKey?: string;
|
||||
onSelectionChange?: (key: string) => void;
|
||||
}
|
||||
|
||||
const styles = stylex.create({
|
||||
@@ -73,9 +80,13 @@ const styles = stylex.create({
|
||||
},
|
||||
});
|
||||
|
||||
export default function Tabs({ label, tabs }: Props) {
|
||||
export default function Tabs({ label, tabs, selectedKey, onSelectionChange }: Props) {
|
||||
return (
|
||||
<AriaTabs className={() => stylex.props(styles.root).className ?? ""}>
|
||||
<AriaTabs
|
||||
selectedKey={selectedKey}
|
||||
onSelectionChange={onSelectionChange === undefined ? undefined : (key) => onSelectionChange(String(key))}
|
||||
className={() => stylex.props(styles.root).className ?? ""}
|
||||
>
|
||||
<TabList aria-label={label} className={() => stylex.props(styles.list).className ?? ""}>
|
||||
{tabs.map((tab) => (
|
||||
<Tab
|
||||
|
||||
Reference in New Issue
Block a user