@multiplatform.one/components 7.6.3 → 7.7.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/dist/cjs/Badge/index.cjs +4 -3
- package/dist/cjs/Badge/index.native.js +7 -6
- package/dist/cjs/Badge/index.native.js.map +1 -1
- package/dist/cjs/Card.cjs +1 -9
- package/dist/cjs/Card.native.js +2 -7
- package/dist/cjs/Card.native.js.map +1 -1
- package/dist/cjs/CardFooter.cjs +1 -9
- package/dist/cjs/CardFooter.native.js +2 -7
- package/dist/cjs/CardFooter.native.js.map +1 -1
- package/dist/cjs/CardHeader.cjs +1 -9
- package/dist/cjs/CardHeader.native.js +2 -7
- package/dist/cjs/CardHeader.native.js.map +1 -1
- package/dist/cjs/ProgressSteps/index.cjs +13 -6
- package/dist/cjs/ProgressSteps/index.native.js +14 -6
- package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
- package/dist/cjs/SheetModal/detents.cjs +46 -0
- package/dist/cjs/SheetModal/detents.native.js +54 -0
- package/dist/cjs/SheetModal/detents.native.js.map +1 -0
- package/dist/cjs/SheetModal/index.native.js +8 -11
- package/dist/cjs/SheetModal/index.native.js.map +1 -1
- package/dist/cjs/SortableList/index.cjs +1 -1
- package/dist/cjs/SortableList/index.native.js +1 -1
- package/dist/cjs/SortableList/index.native.js.map +1 -1
- package/dist/cjs/code/Code/index.cjs +2 -15
- package/dist/cjs/code/Code/index.native.js +3 -13
- package/dist/cjs/code/Code/index.native.js.map +1 -1
- package/dist/cjs/code/HighlightedCode/index.cjs +0 -5
- package/dist/cjs/code/HighlightedCode/index.native.js +0 -5
- package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/cjs/knobImmuneExports.cjs +8 -0
- package/dist/cjs/knobImmuneExports.native.js +8 -0
- package/dist/cjs/knobImmuneExports.native.js.map +1 -1
- package/dist/cjs/layouts/breadcrumbs.cjs +3 -1
- package/dist/cjs/layouts/breadcrumbs.native.js +3 -1
- package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/cjs/tamagui.cjs +5 -0
- package/dist/cjs/tamagui.native.js +5 -0
- package/dist/cjs/tamagui.native.js.map +1 -1
- package/dist/cjs/views/Dashboard.cjs +3 -3
- package/dist/cjs/views/Dashboard.native.js +3 -3
- package/dist/cjs/views/Dashboard.native.js.map +1 -1
- package/dist/cjs/views/List.cjs +4 -5
- package/dist/cjs/views/List.native.js +4 -5
- package/dist/cjs/views/List.native.js.map +1 -1
- package/dist/cjs/views/TreeView.cjs +4 -1
- package/dist/cjs/views/TreeView.native.js +3 -0
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/esm/Badge/index.mjs +4 -3
- package/dist/esm/Badge/index.mjs.map +1 -1
- package/dist/esm/Badge/index.native.js +7 -6
- package/dist/esm/Badge/index.native.js.map +1 -1
- package/dist/esm/Card.mjs +3 -11
- package/dist/esm/Card.mjs.map +1 -1
- package/dist/esm/Card.native.js +7 -12
- package/dist/esm/Card.native.js.map +1 -1
- package/dist/esm/CardFooter.mjs +3 -11
- package/dist/esm/CardFooter.mjs.map +1 -1
- package/dist/esm/CardFooter.native.js +6 -11
- package/dist/esm/CardFooter.native.js.map +1 -1
- package/dist/esm/CardHeader.mjs +3 -11
- package/dist/esm/CardHeader.mjs.map +1 -1
- package/dist/esm/CardHeader.native.js +6 -11
- package/dist/esm/CardHeader.native.js.map +1 -1
- package/dist/esm/ProgressSteps/index.mjs +14 -7
- package/dist/esm/ProgressSteps/index.mjs.map +1 -1
- package/dist/esm/ProgressSteps/index.native.js +15 -7
- package/dist/esm/ProgressSteps/index.native.js.map +1 -1
- package/dist/esm/SheetModal/detents.mjs +19 -0
- package/dist/esm/SheetModal/detents.mjs.map +1 -0
- package/dist/esm/SheetModal/detents.native.js +24 -0
- package/dist/esm/SheetModal/detents.native.js.map +1 -0
- package/dist/esm/SheetModal/index.mjs.map +1 -1
- package/dist/esm/SheetModal/index.native.js +7 -10
- package/dist/esm/SheetModal/index.native.js.map +1 -1
- package/dist/esm/SortableList/index.mjs +1 -1
- package/dist/esm/SortableList/index.mjs.map +1 -1
- package/dist/esm/SortableList/index.native.js +1 -1
- package/dist/esm/SortableList/index.native.js.map +1 -1
- package/dist/esm/code/Code/index.mjs +2 -15
- package/dist/esm/code/Code/index.mjs.map +1 -1
- package/dist/esm/code/Code/index.native.js +6 -16
- package/dist/esm/code/Code/index.native.js.map +1 -1
- package/dist/esm/code/HighlightedCode/index.mjs +0 -5
- package/dist/esm/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/esm/code/HighlightedCode/index.native.js +0 -5
- package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/esm/knobImmuneExports.mjs +8 -0
- package/dist/esm/knobImmuneExports.mjs.map +1 -1
- package/dist/esm/knobImmuneExports.native.js +8 -0
- package/dist/esm/knobImmuneExports.native.js.map +1 -1
- package/dist/esm/layouts/breadcrumbs.mjs +3 -1
- package/dist/esm/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/esm/layouts/breadcrumbs.native.js +3 -1
- package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/esm/tamagui.mjs +3 -2
- package/dist/esm/tamagui.mjs.map +1 -1
- package/dist/esm/tamagui.native.js +3 -2
- package/dist/esm/tamagui.native.js.map +1 -1
- package/dist/esm/views/Dashboard.mjs +3 -3
- package/dist/esm/views/Dashboard.mjs.map +1 -1
- package/dist/esm/views/Dashboard.native.js +3 -3
- package/dist/esm/views/Dashboard.native.js.map +1 -1
- package/dist/esm/views/List.mjs +4 -5
- package/dist/esm/views/List.mjs.map +1 -1
- package/dist/esm/views/List.native.js +4 -5
- package/dist/esm/views/List.native.js.map +1 -1
- package/dist/esm/views/TreeView.mjs +4 -1
- package/dist/esm/views/TreeView.mjs.map +1 -1
- package/dist/esm/views/TreeView.native.js +3 -0
- package/dist/esm/views/TreeView.native.js.map +1 -1
- package/dist/jsx/Badge/index.mjs +4 -3
- package/dist/jsx/Badge/index.mjs.map +1 -1
- package/dist/jsx/Badge/index.native.js +7 -6
- package/dist/jsx/Badge/index.native.js.map +1 -1
- package/dist/jsx/Card.mjs +3 -11
- package/dist/jsx/Card.mjs.map +1 -1
- package/dist/jsx/Card.native.js +2 -7
- package/dist/jsx/Card.native.js.map +1 -1
- package/dist/jsx/CardFooter.mjs +3 -11
- package/dist/jsx/CardFooter.mjs.map +1 -1
- package/dist/jsx/CardFooter.native.js +2 -7
- package/dist/jsx/CardFooter.native.js.map +1 -1
- package/dist/jsx/CardHeader.mjs +3 -11
- package/dist/jsx/CardHeader.mjs.map +1 -1
- package/dist/jsx/CardHeader.native.js +2 -7
- package/dist/jsx/CardHeader.native.js.map +1 -1
- package/dist/jsx/ProgressSteps/index.mjs +14 -7
- package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
- package/dist/jsx/ProgressSteps/index.native.js +14 -6
- package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
- package/dist/jsx/SheetModal/detents.mjs +19 -0
- package/dist/jsx/SheetModal/detents.mjs.map +1 -0
- package/dist/jsx/SheetModal/detents.native.js +54 -0
- package/dist/jsx/SheetModal/detents.native.js.map +1 -0
- package/dist/jsx/SheetModal/index.mjs.map +1 -1
- package/dist/jsx/SheetModal/index.native.js +8 -11
- package/dist/jsx/SheetModal/index.native.js.map +1 -1
- package/dist/jsx/SortableList/index.mjs +1 -1
- package/dist/jsx/SortableList/index.mjs.map +1 -1
- package/dist/jsx/SortableList/index.native.js +1 -1
- package/dist/jsx/SortableList/index.native.js.map +1 -1
- package/dist/jsx/code/Code/index.mjs +2 -15
- package/dist/jsx/code/Code/index.mjs.map +1 -1
- package/dist/jsx/code/Code/index.native.js +3 -13
- package/dist/jsx/code/Code/index.native.js.map +1 -1
- package/dist/jsx/code/CodeBlock/index.native.js +1 -1
- package/dist/jsx/code/HighlightedCode/index.mjs +0 -5
- package/dist/jsx/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/jsx/code/HighlightedCode/index.native.js +0 -5
- package/dist/jsx/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/jsx/code/index.native.js +1 -1
- package/dist/jsx/knobImmuneExports.mjs +8 -0
- package/dist/jsx/knobImmuneExports.mjs.map +1 -1
- package/dist/jsx/knobImmuneExports.native.js +8 -0
- package/dist/jsx/knobImmuneExports.native.js.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.mjs +3 -1
- package/dist/jsx/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.native.js +3 -1
- package/dist/jsx/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/jsx/tamagui.mjs +3 -2
- package/dist/jsx/tamagui.mjs.map +1 -1
- package/dist/jsx/tamagui.native.js +5 -0
- package/dist/jsx/tamagui.native.js.map +1 -1
- package/dist/jsx/views/Dashboard.mjs +3 -3
- package/dist/jsx/views/Dashboard.mjs.map +1 -1
- package/dist/jsx/views/Dashboard.native.js +3 -3
- package/dist/jsx/views/Dashboard.native.js.map +1 -1
- package/dist/jsx/views/List.mjs +4 -5
- package/dist/jsx/views/List.mjs.map +1 -1
- package/dist/jsx/views/List.native.js +4 -5
- package/dist/jsx/views/List.native.js.map +1 -1
- package/dist/jsx/views/TreeView.mjs +4 -1
- package/dist/jsx/views/TreeView.mjs.map +1 -1
- package/dist/jsx/views/TreeView.native.js +3 -0
- package/dist/jsx/views/TreeView.native.js.map +1 -1
- package/package.json +9 -9
- package/src/Badge/Badge.spec.tsx +10 -11
- package/src/Badge/index.tsx +7 -6
- package/src/Card.tsx +8 -3
- package/src/CardFooter.spec.tsx +1 -1
- package/src/CardFooter.tsx +6 -3
- package/src/CardHeader.spec.tsx +1 -1
- package/src/CardHeader.tsx +6 -3
- package/src/Chip/Chip.spec.tsx +1 -1
- package/src/Pagination.spec.tsx +1 -1
- package/src/ProgressSteps/ProgressSteps.spec.tsx +29 -2
- package/src/ProgressSteps/index.tsx +21 -7
- package/src/SheetModal/SheetModal.spec.tsx +88 -0
- package/src/SheetModal/detents.ts +55 -0
- package/src/SheetModal/index.native.tsx +13 -12
- package/src/SheetModal/index.tsx +5 -2
- package/src/Skeleton/Skeleton.spec.tsx +1 -1
- package/src/SortableList/SortableList.spec.tsx +41 -0
- package/src/SortableList/SortableList.stories.tsx +35 -2
- package/src/SortableList/index.tsx +1 -1
- package/src/TreeSelect/TreeSelect.stories.tsx +76 -1
- package/src/Wheel/Wheel.spec.tsx +1 -1
- package/src/code/Code/code.spec.tsx +27 -1
- package/src/code/Code/index.tsx +9 -2
- package/src/code/HighlightedCode/index.tsx +0 -1
- package/src/code/highlightedCode.spec.tsx +10 -1
- package/src/knobImmuneExports.ts +11 -0
- package/src/layouts/AsyncBoundary.spec.tsx +1 -1
- package/src/layouts/breadcrumbs.spec.tsx +17 -0
- package/src/layouts/breadcrumbs.tsx +19 -2
- package/src/layouts/tags.r7.spec.tsx +3 -1
- package/src/tamagui.ts +8 -0
- package/src/views/Dashboard.tsx +3 -3
- package/src/views/List.spec.tsx +42 -1
- package/src/views/List.tsx +6 -5
- package/src/views/TreeView.spec.tsx +26 -0
- package/src/views/TreeView.tsx +3 -0
- package/types/Badge/index.d.ts.map +1 -1
- package/types/Card.d.ts.map +1 -1
- package/types/CardFooter.d.ts.map +1 -1
- package/types/CardHeader.d.ts.map +1 -1
- package/types/ProgressSteps/index.d.ts.map +1 -1
- package/types/SheetModal/detents.d.ts +38 -0
- package/types/SheetModal/detents.d.ts.map +1 -0
- package/types/SheetModal/index.d.ts +1 -1
- package/types/SheetModal/index.d.ts.map +1 -1
- package/types/SheetModal/index.native.d.ts +1 -1
- package/types/SheetModal/index.native.d.ts.map +1 -1
- package/types/code/Code/index.d.ts.map +1 -1
- package/types/code/HighlightedCode/index.d.ts.map +1 -1
- package/types/knobImmuneExports.d.ts.map +1 -1
- package/types/layouts/breadcrumbs.d.ts +7 -1
- package/types/layouts/breadcrumbs.d.ts.map +1 -1
- package/types/tamagui.d.ts +3 -1
- package/types/tamagui.d.ts.map +1 -1
- package/types/views/List.d.ts.map +1 -1
- package/types/views/TreeView.d.ts.map +1 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { fireEvent } from "@testing-library/react";
|
|
2
2
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
3
6
|
import { useState } from "react";
|
|
4
7
|
import { describe, expect, it, vi } from "vitest";
|
|
5
8
|
import { SortableList } from "./index";
|
|
6
9
|
|
|
10
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
|
|
7
12
|
const ITEMS = [
|
|
8
13
|
{ id: "mon", label: "Monday standup" },
|
|
9
14
|
{ id: "tue", label: "Tuesday review" },
|
|
@@ -14,10 +19,14 @@ const ITEMS = [
|
|
|
14
19
|
function Harness({
|
|
15
20
|
onChange = vi.fn(),
|
|
16
21
|
readOnly,
|
|
22
|
+
disabled,
|
|
23
|
+
compact,
|
|
17
24
|
canReorder,
|
|
18
25
|
}: {
|
|
19
26
|
onChange?: (next: typeof ITEMS) => void;
|
|
20
27
|
readOnly?: boolean;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
compact?: boolean;
|
|
21
30
|
canReorder?: (item: (typeof ITEMS)[number], index: number) => boolean;
|
|
22
31
|
}) {
|
|
23
32
|
const [items, setItems] = useState(ITEMS);
|
|
@@ -28,6 +37,8 @@ function Harness({
|
|
|
28
37
|
getLabel={(item) => item.label}
|
|
29
38
|
canReorder={canReorder}
|
|
30
39
|
readOnly={readOnly}
|
|
40
|
+
disabled={disabled}
|
|
41
|
+
compact={compact}
|
|
31
42
|
onChange={(next) => {
|
|
32
43
|
setItems(next);
|
|
33
44
|
onChange(next);
|
|
@@ -119,4 +130,34 @@ describe("SortableList", () => {
|
|
|
119
130
|
const { container } = renderWithProviders(<Harness readOnly />);
|
|
120
131
|
expect(container.querySelectorAll("[data-sortable-handle]")).toHaveLength(0);
|
|
121
132
|
});
|
|
133
|
+
|
|
134
|
+
it("renders no handles when disabled (board 04)", () => {
|
|
135
|
+
const { container } = renderWithProviders(<Harness disabled />);
|
|
136
|
+
expect(container.querySelectorAll("[data-sortable-handle]")).toHaveLength(0);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("renders emptyMessage when there are no rows (board 04)", () => {
|
|
140
|
+
const { container } = renderWithProviders(
|
|
141
|
+
<SortableList
|
|
142
|
+
items={[]}
|
|
143
|
+
getId={(item: { id: string }) => item.id}
|
|
144
|
+
getLabel={(item: { label: string }) => item.label}
|
|
145
|
+
emptyMessage="No rows yet"
|
|
146
|
+
/>,
|
|
147
|
+
);
|
|
148
|
+
expect(container.textContent).toContain("No rows yet");
|
|
149
|
+
expect(container.querySelectorAll("[data-sortable-row]")).toHaveLength(0);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("compact still renders grab handles (LC-76: density does not drop controls)", () => {
|
|
153
|
+
const { container } = renderWithProviders(<Harness compact />);
|
|
154
|
+
expect(container.querySelectorAll("[data-sortable-handle]")).toHaveLength(4);
|
|
155
|
+
expect(container.querySelector('[role="list"]')).toBeTruthy();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("spreads the outer radius fragment on the list frame, not the nested alias", () => {
|
|
159
|
+
const src = readFileSync(join(here, "index.tsx"), "utf8");
|
|
160
|
+
expect(src).toContain("{...knobProps.borderRadius}");
|
|
161
|
+
expect(src).not.toContain("knobProps.borderRadiusOuter");
|
|
162
|
+
});
|
|
122
163
|
});
|
|
@@ -21,13 +21,27 @@ const meta: Meta<typeof SortableList> = {
|
|
|
21
21
|
},
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
disabled: { control: "boolean" },
|
|
26
|
+
readOnly: { control: "boolean" },
|
|
27
|
+
compact: { control: "boolean" },
|
|
28
|
+
disabledStyle: { control: "select", options: ["keepLabel", "dimWhole"] },
|
|
29
|
+
emptyMessage: { control: "text" },
|
|
30
|
+
},
|
|
24
31
|
};
|
|
25
32
|
export default meta;
|
|
26
33
|
|
|
27
34
|
type Story = StoryObj<typeof SortableList>;
|
|
28
35
|
|
|
29
|
-
function Demo(props: {
|
|
30
|
-
|
|
36
|
+
function Demo(props: {
|
|
37
|
+
readOnly?: boolean;
|
|
38
|
+
locked?: string;
|
|
39
|
+
disabled?: boolean;
|
|
40
|
+
compact?: boolean;
|
|
41
|
+
empty?: boolean;
|
|
42
|
+
disabledStyle?: "keepLabel" | "dimWhole";
|
|
43
|
+
}) {
|
|
44
|
+
const [items, setItems] = useState(props.empty ? [] : SEED);
|
|
31
45
|
return (
|
|
32
46
|
<SortableList
|
|
33
47
|
items={items}
|
|
@@ -35,6 +49,10 @@ function Demo(props: { readOnly?: boolean; locked?: string }) {
|
|
|
35
49
|
getLabel={(item) => item.label}
|
|
36
50
|
canReorder={props.locked ? (item) => item.id !== props.locked : undefined}
|
|
37
51
|
readOnly={props.readOnly}
|
|
52
|
+
disabled={props.disabled}
|
|
53
|
+
compact={props.compact}
|
|
54
|
+
disabledStyle={props.disabledStyle}
|
|
55
|
+
emptyMessage="No rows yet"
|
|
38
56
|
onChange={setItems}
|
|
39
57
|
aria-label="Sprint rituals"
|
|
40
58
|
/>
|
|
@@ -53,3 +71,18 @@ export const ReadOnly: Story = {
|
|
|
53
71
|
export const LockedRow: Story = {
|
|
54
72
|
render: () => <Demo locked="tue" />,
|
|
55
73
|
};
|
|
74
|
+
|
|
75
|
+
/** Board 04 — empty is a real state, not an error. */
|
|
76
|
+
export const Empty: Story = {
|
|
77
|
+
render: () => <Demo empty />,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Board 04 — disabled list keeps labels, drops the handles. */
|
|
81
|
+
export const Disabled: Story = {
|
|
82
|
+
render: () => <Demo disabled />,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** Board 04 — compact nested well. */
|
|
86
|
+
export const Compact: Story = {
|
|
87
|
+
render: () => <Demo compact />,
|
|
88
|
+
};
|
|
@@ -47,7 +47,7 @@ export default meta;
|
|
|
47
47
|
|
|
48
48
|
type Story = StoryObj<typeof TreeSelect>;
|
|
49
49
|
|
|
50
|
-
export const
|
|
50
|
+
export const Default: Story = {
|
|
51
51
|
render: function Render() {
|
|
52
52
|
const [value, setValue] = useState("hdfc");
|
|
53
53
|
return (
|
|
@@ -67,6 +67,31 @@ export const Account: Story = {
|
|
|
67
67
|
},
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
export const Open: Story = {
|
|
71
|
+
render: function Render() {
|
|
72
|
+
const [value, setValue] = useState("hdfc");
|
|
73
|
+
const [open, setOpen] = useState(true);
|
|
74
|
+
return (
|
|
75
|
+
<YStack width={280} padding="$4">
|
|
76
|
+
<TreeSelect
|
|
77
|
+
label="Account"
|
|
78
|
+
nodes={accounts}
|
|
79
|
+
value={value}
|
|
80
|
+
onChange={setValue}
|
|
81
|
+
open={open}
|
|
82
|
+
onOpenChange={setOpen}
|
|
83
|
+
placeholder="Select account"
|
|
84
|
+
searchPlaceholder="Filter accounts"
|
|
85
|
+
emptyMessage="No matching accounts"
|
|
86
|
+
defaultExpandedIds={["assets", "current", "bank"]}
|
|
87
|
+
/>
|
|
88
|
+
</YStack>
|
|
89
|
+
);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const Account: Story = Default;
|
|
94
|
+
|
|
70
95
|
export const Empty: Story = {
|
|
71
96
|
render: () => (
|
|
72
97
|
<YStack width={280} padding="$4">
|
|
@@ -74,3 +99,53 @@ export const Empty: Story = {
|
|
|
74
99
|
</YStack>
|
|
75
100
|
),
|
|
76
101
|
};
|
|
102
|
+
|
|
103
|
+
export const Disabled: Story = {
|
|
104
|
+
render: () => (
|
|
105
|
+
<YStack width={280} padding="$4">
|
|
106
|
+
<TreeSelect
|
|
107
|
+
label="Account"
|
|
108
|
+
nodes={accounts}
|
|
109
|
+
value="hdfc"
|
|
110
|
+
disabled
|
|
111
|
+
placeholder="Select account"
|
|
112
|
+
/>
|
|
113
|
+
</YStack>
|
|
114
|
+
),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const WithError: Story = {
|
|
118
|
+
render: () => (
|
|
119
|
+
<YStack width={280} padding="$4">
|
|
120
|
+
<TreeSelect
|
|
121
|
+
label="Account"
|
|
122
|
+
nodes={accounts}
|
|
123
|
+
required
|
|
124
|
+
error="An account is required"
|
|
125
|
+
placeholder="Select account"
|
|
126
|
+
/>
|
|
127
|
+
</YStack>
|
|
128
|
+
),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const ReadOnly: Story = {
|
|
132
|
+
render: () => (
|
|
133
|
+
<YStack width={280} padding="$4">
|
|
134
|
+
<TreeSelect
|
|
135
|
+
label="Account"
|
|
136
|
+
nodes={accounts}
|
|
137
|
+
value="hdfc"
|
|
138
|
+
readOnly
|
|
139
|
+
placeholder="Select account"
|
|
140
|
+
/>
|
|
141
|
+
</YStack>
|
|
142
|
+
),
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const Skeleton: Story = {
|
|
146
|
+
render: () => (
|
|
147
|
+
<YStack width={280} padding="$4">
|
|
148
|
+
<TreeSelect label="Account" nodes={accounts} skeleton placeholder="Select account" />
|
|
149
|
+
</YStack>
|
|
150
|
+
),
|
|
151
|
+
};
|
package/src/Wheel/Wheel.spec.tsx
CHANGED
|
@@ -272,7 +272,7 @@ describe("Wheel design-law (MPO-60)", () => {
|
|
|
272
272
|
it("exposes named exports and no default", async () => {
|
|
273
273
|
const mod = await import("./index");
|
|
274
274
|
expect(mod.Wheel).toBe(Wheel);
|
|
275
|
-
expect(mod
|
|
275
|
+
expect("default" in mod).toBe(false);
|
|
276
276
|
});
|
|
277
277
|
|
|
278
278
|
it("selected row type stays on body weight 400, never 600 (R7 / design-audit)", () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
import { Code, CodeInline } from "./index";
|
|
4
4
|
|
|
5
5
|
describe("Code", () => {
|
|
@@ -21,6 +21,15 @@ describe("Code", () => {
|
|
|
21
21
|
const codeElement = container.querySelector("code");
|
|
22
22
|
expect(codeElement).toBeDefined();
|
|
23
23
|
});
|
|
24
|
+
|
|
25
|
+
it("keeps data-code-font and does not emit a dataset attribute", () => {
|
|
26
|
+
const { container } = renderWithProviders(<Code>const test = "hello"</Code>);
|
|
27
|
+
const codeElement = container.querySelector("code");
|
|
28
|
+
expect(codeElement).toBeTruthy();
|
|
29
|
+
expect(codeElement!.getAttribute("data-code-font")).toBe("mono");
|
|
30
|
+
// React lowercases an unknown dataSet prop to dataset="[object Object]".
|
|
31
|
+
expect(codeElement!.hasAttribute("dataset")).toBe(false);
|
|
32
|
+
});
|
|
24
33
|
});
|
|
25
34
|
|
|
26
35
|
describe("CodeInline", () => {
|
|
@@ -42,4 +51,21 @@ describe("CodeInline", () => {
|
|
|
42
51
|
const codeElement = container.querySelector("code");
|
|
43
52
|
expect(codeElement).toBeDefined();
|
|
44
53
|
});
|
|
54
|
+
|
|
55
|
+
it("emits data-code-font on web without a dataSet host-prop leak", () => {
|
|
56
|
+
const leak = /does not recognize the `dataSet` prop on a DOM element/;
|
|
57
|
+
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
58
|
+
try {
|
|
59
|
+
const { container } = renderWithProviders(<CodeInline>npm install</CodeInline>);
|
|
60
|
+
const codeElement = container.querySelector("code");
|
|
61
|
+
expect(codeElement).toBeDefined();
|
|
62
|
+
expect(codeElement?.getAttribute("data-code-font")).toBe("mono");
|
|
63
|
+
const leaks = errorSpy.mock.calls
|
|
64
|
+
.map((args) => args.map(String).join(" "))
|
|
65
|
+
.filter((message) => leak.test(message));
|
|
66
|
+
expect(leaks).toEqual([]);
|
|
67
|
+
} finally {
|
|
68
|
+
errorSpy.mockRestore();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
45
71
|
});
|
package/src/code/Code/index.tsx
CHANGED
|
@@ -40,7 +40,6 @@ export const Code = CodeFrame.styleable((props, ref) => {
|
|
|
40
40
|
fontFamily="$mono"
|
|
41
41
|
letterSpacing={0}
|
|
42
42
|
data-code-font="mono"
|
|
43
|
-
{...({ dataSet: { codeFont: "mono" } } as object)}
|
|
44
43
|
/>
|
|
45
44
|
);
|
|
46
45
|
});
|
|
@@ -57,6 +56,9 @@ const CodeInlineFrame = styled(Paragraph, {
|
|
|
57
56
|
backgroundColor: componentColors.code.background,
|
|
58
57
|
cursor: "inherit",
|
|
59
58
|
borderRadius: "$3",
|
|
59
|
+
// Pin (dial: surrounding prose): 0.9× size / 0.7× leading. Size reaches
|
|
60
|
+
// the chip through context, not sizeToken. Lettered in spec § Code and
|
|
61
|
+
// CodeInline; these ratios are the house metrics already shipping.
|
|
60
62
|
fontSize: "90%" as CSSProperties["fontSize"],
|
|
61
63
|
lineHeight: "70%" as CSSProperties["lineHeight"],
|
|
62
64
|
paddingHorizontal: "0.6%",
|
|
@@ -79,7 +81,12 @@ export const CodeInline = CodeInlineFrame.styleable((props, ref) => {
|
|
|
79
81
|
fontFamily="$mono"
|
|
80
82
|
letterSpacing={0}
|
|
81
83
|
data-code-font="mono"
|
|
82
|
-
|
|
84
|
+
// react-native-web reads dataSet; React-DOM warns on the camel host
|
|
85
|
+
// prop. Keep the kebab attribute on every target; spread dataSet
|
|
86
|
+
// only when TAMAGUI_TARGET is native.
|
|
87
|
+
{...(process.env.TAMAGUI_TARGET === "native"
|
|
88
|
+
? ({ dataSet: { codeFont: "mono" } } as object)
|
|
89
|
+
: {})}
|
|
83
90
|
/>
|
|
84
91
|
);
|
|
85
92
|
});
|
|
@@ -115,9 +115,18 @@ describe("HighlightedCode", () => {
|
|
|
115
115
|
<HighlightedCode tokens={tokens} />
|
|
116
116
|
</Preset>,
|
|
117
117
|
);
|
|
118
|
-
|
|
118
|
+
// querySelector("span") used to land on renderWithProviders' Theme
|
|
119
|
+
// wrapper (`t_light _dsp_contents`), never the code line, so this guard
|
|
120
|
+
// asserted null and had been red on main. Select the line itself.
|
|
121
|
+
const line = container.querySelector("[data-code-font]") as HTMLElement | null;
|
|
119
122
|
expect(line).toBeTruthy();
|
|
120
123
|
expect(container.textContent).toContain("const");
|
|
121
124
|
expect(line!.getAttribute("data-code-font")).toBe("mono");
|
|
125
|
+
// The actual LC-07 pin: bodyFont serif / fontWeight bold must not reach
|
|
126
|
+
// code text, so the line keeps the mono family class.
|
|
127
|
+
expect(line!.className).toContain("font_mono");
|
|
128
|
+
// React does not recognise `dataSet`; leaving it on the line logged an
|
|
129
|
+
// unknown-prop error and wrote dataset="[object Object]" on every node.
|
|
130
|
+
expect(container.querySelectorAll("[dataset]")).toHaveLength(0);
|
|
122
131
|
});
|
|
123
132
|
});
|
package/src/knobImmuneExports.ts
CHANGED
|
@@ -38,6 +38,17 @@ export const knobImmuneExports: Readonly<Record<string, string>> = {
|
|
|
38
38
|
// qualifies for a row (house implementations ARE the knob story). The
|
|
39
39
|
// weight-knob question stays an ADJUDICATION-CANDIDATE on the component
|
|
40
40
|
// header (MPO-21 G10 / G0-clay R9).
|
|
41
|
+
// MPO-21 G1 — Fold's substrate. Logic shell only; Accordion (and Fold)
|
|
42
|
+
// own the painted chrome. Restored with the three below after MPO-21 R9 G8
|
|
43
|
+
// (the Adapt drop) rewrote this file from a pre-MPO-21 copy and took them
|
|
44
|
+
// out as collateral; Adapt itself stays dropped.
|
|
45
|
+
Collapsible:
|
|
46
|
+
"composition root (open/close shell); knobs land on composing surfaces (Accordion, Fold)",
|
|
47
|
+
Unspaced:
|
|
48
|
+
"spacing opt-out marker; paints nothing, tells the parent stack to skip gap on its children",
|
|
49
|
+
VisuallyHidden: "a11y hide utility; paints nothing visible, no chrome for knobs to reach",
|
|
50
|
+
LinearGradient:
|
|
51
|
+
"paint primitive (color stops are content); no opinionated chrome, consumers own the stops",
|
|
41
52
|
ListItem:
|
|
42
53
|
"raw list-row primitive consumed as lego by house list surfaces (List, sidebar, tags) which own the knob story. ADJUDICATION-CANDIDATE + BACKLOG: painted row with own padding/press states — deserves a house shadow or Tamagui* demotion once consumers migrate",
|
|
43
54
|
|
|
@@ -229,7 +229,7 @@ function SchemeWrap({
|
|
|
229
229
|
children: ReactNode;
|
|
230
230
|
}) {
|
|
231
231
|
return (
|
|
232
|
-
<TamaguiProvider config={houseConfig} defaultTheme={scheme} disableInjectCSS>
|
|
232
|
+
<TamaguiProvider config={houseConfig.tamagui} defaultTheme={scheme} disableInjectCSS>
|
|
233
233
|
<YStack backgroundColor="$background">{children}</YStack>
|
|
234
234
|
</TamaguiProvider>
|
|
235
235
|
);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
2
2
|
import { fireEvent } from "@testing-library/react";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
3
5
|
import { describe, expect, it, vi } from "vitest";
|
|
4
6
|
import { Breadcrumbs } from "./breadcrumbs";
|
|
5
7
|
|
|
@@ -28,6 +30,21 @@ describe("Breadcrumbs", () => {
|
|
|
28
30
|
expect(["400", "normal"]).toContain(String(linkWeight));
|
|
29
31
|
});
|
|
30
32
|
|
|
33
|
+
it("hides the slash separators from AT and paints them as T-HELPER ink", () => {
|
|
34
|
+
const { container } = renderWithProviders(<Breadcrumbs items={items} />);
|
|
35
|
+
const separators = [...container.querySelectorAll('[data-testid="breadcrumb-separator"]')];
|
|
36
|
+
expect(separators).toHaveLength(2);
|
|
37
|
+
for (const sep of separators) {
|
|
38
|
+
expect(sep.getAttribute("aria-hidden")).toBe("true");
|
|
39
|
+
expect(sep.textContent).toBe("/");
|
|
40
|
+
}
|
|
41
|
+
// Distinct token from MPO-40: separators ride textAccentColor (AA floor
|
|
42
|
+
// at $color11), not componentColors.text.subtle ($color8).
|
|
43
|
+
const source = readFileSync(join(import.meta.dirname, "breadcrumbs.tsx"), "utf8");
|
|
44
|
+
expect(source).toMatch(/color=\{knobProps\.textAccentColor\}/);
|
|
45
|
+
expect(source).not.toMatch(/color=\{componentColors\.text\.subtle\}/);
|
|
46
|
+
});
|
|
47
|
+
|
|
31
48
|
it("calls onNavigate from a path crumb and keeps the current page inert", () => {
|
|
32
49
|
const onNavigate = vi.fn();
|
|
33
50
|
const { container } = renderWithProviders(
|
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* Breadcrumbs — wayfinding trail (Polaris / Primer / GOV.UK).
|
|
3
3
|
*
|
|
4
4
|
* Landmark `<nav>` + ordered list; last crumb is the current page
|
|
5
|
-
* (`aria-current="page"`, not a link). Separators stay the RTL-neutral
|
|
5
|
+
* (`aria-current="page"`, not a link). Separators stay the RTL-neutral `/`,
|
|
6
|
+
* `aria-hidden` (the list already names the trail), and T-HELPER ink via
|
|
7
|
+
* `knobProps.textAccentColor` — not `componentColors.text.subtle` ($color8),
|
|
8
|
+
* which measured 1.89:1 / 2.21:1 against the 4.5 floor. Distinct from
|
|
9
|
+
* MPO-40 / !272 (outlined intent `$color11` on the warning surface).
|
|
6
10
|
* LC-71: keyboard ring on each link (and the overflow control), never the
|
|
7
11
|
* trail container. LC-03 / LC-35: tight chromeless trail.
|
|
12
|
+
* Crumb `minHeight` is a Vocabulary `pin` at 44, not a size `floor` — see
|
|
13
|
+
* `docs/design/letters/breadcrumbs-size-pin.md`.
|
|
8
14
|
*/
|
|
9
15
|
|
|
10
16
|
import {
|
|
@@ -120,12 +126,17 @@ export function Breadcrumbs({ items, onNavigate, label, maxVisible }: Breadcrumb
|
|
|
120
126
|
// Tight trail: crumbs hug the "/" separators so the path reads as one unit.
|
|
121
127
|
// The space knob still scales the gap, but from a tight base — not the
|
|
122
128
|
// panel-level knobProps.gap (which is sized for stacked layout sections).
|
|
129
|
+
// Spec: separators are T-HELPER (`textAccentColor`), never the $color8
|
|
130
|
+
// `text.subtle` ramp that fails AA on the page.
|
|
123
131
|
const spaceGap = knobProps.gap.gap;
|
|
124
132
|
const trailGap =
|
|
125
133
|
spaceGap === "$2" ? ("$1" as const) : spaceGap === "$5" ? ("$2" as const) : ("$1.5" as const);
|
|
126
134
|
// Vertical pad only (theme-propagation SP-FIXED / DG-LAY-04 / LC-03): grow
|
|
127
135
|
// the clickable box to ≥44 without horizontal padding that would re-spread
|
|
128
136
|
// the trail. No minWidth floor — the ring must hug the link, not a 44px well.
|
|
137
|
+
// Height is PINNED at MIN_PRESS_TARGET across size stops (font still remaps).
|
|
138
|
+
// That is Vocabulary `pin (forced: WCAG 2.5.5)`, not `floor`. Do not raise
|
|
139
|
+
// the box at large — lettered in docs/design/letters/breadcrumbs-size-pin.md.
|
|
129
140
|
const crumbPadY = Math.max(0, Math.ceil((MIN_PRESS_TARGET - CRUMB_LINE_PX) / 2));
|
|
130
141
|
const crumbRadius = knobProps.borderRadius.borderRadius;
|
|
131
142
|
|
|
@@ -238,7 +249,13 @@ export function Breadcrumbs({ items, onNavigate, label, maxVisible }: Breadcrumb
|
|
|
238
249
|
</Text>
|
|
239
250
|
)}
|
|
240
251
|
{!isLastSlot && (
|
|
241
|
-
<Text
|
|
252
|
+
<Text
|
|
253
|
+
aria-hidden
|
|
254
|
+
color={knobProps.textAccentColor}
|
|
255
|
+
data-testid="breadcrumb-separator"
|
|
256
|
+
fontSize={separatorSize}
|
|
257
|
+
userSelect="none"
|
|
258
|
+
>
|
|
242
259
|
/
|
|
243
260
|
</Text>
|
|
244
261
|
)}
|
|
@@ -4,7 +4,9 @@ import { Tags } from "./tags";
|
|
|
4
4
|
|
|
5
5
|
describe("Tags design law", () => {
|
|
6
6
|
it("paints the field label at weight 400 (R7 / §6.1)", () => {
|
|
7
|
-
const { container } = renderWithProviders(
|
|
7
|
+
const { container } = renderWithProviders(
|
|
8
|
+
<Tags tags={[{ id: "alpha", label: "alpha" }]} label="Topics" />,
|
|
9
|
+
);
|
|
8
10
|
const label = container.querySelector("label") as HTMLElement | null;
|
|
9
11
|
const node = label ?? (container.querySelector("*") as HTMLElement);
|
|
10
12
|
expect(container.textContent).toContain("Topics");
|
package/src/tamagui.ts
CHANGED
|
@@ -30,18 +30,26 @@
|
|
|
30
30
|
// quiet = opacity 0.5). Raw stays reachable as TamaguiSeparator below.
|
|
31
31
|
export {
|
|
32
32
|
Circle,
|
|
33
|
+
Collapsible,
|
|
33
34
|
Group,
|
|
34
35
|
ListItem,
|
|
35
36
|
ScrollView,
|
|
36
37
|
Spacer,
|
|
37
38
|
Square,
|
|
39
|
+
Unspaced,
|
|
38
40
|
View,
|
|
41
|
+
VisuallyHidden,
|
|
39
42
|
XGroup,
|
|
40
43
|
XStack,
|
|
41
44
|
YGroup,
|
|
42
45
|
YStack,
|
|
43
46
|
} from "tamagui";
|
|
44
47
|
|
|
48
|
+
// MPO-21 G2: LinearGradient is NOT on the main tamagui barrel — it lives
|
|
49
|
+
// on the `tamagui/linear-gradient` subpath.
|
|
50
|
+
export { LinearGradient } from "tamagui/linear-gradient";
|
|
51
|
+
export type { LinearGradientProps } from "tamagui/linear-gradient";
|
|
52
|
+
|
|
45
53
|
// Text primitives: NONE re-exported raw anymore (MPO-20). The former
|
|
46
54
|
// "typography substrate" registry rows were the single biggest knob hole in
|
|
47
55
|
// the catalog: FontKnobStyles rescues family/leading/tracking on WEB ONLY,
|
package/src/views/Dashboard.tsx
CHANGED
|
@@ -379,7 +379,7 @@ export function KPICard({ config, ...stackProps }: KPICardProps) {
|
|
|
379
379
|
{...stackProps}
|
|
380
380
|
>
|
|
381
381
|
<XStack justifyContent="space-between" alignItems="flex-start">
|
|
382
|
-
<Text {...knobProps.label} color={
|
|
382
|
+
<Text {...knobProps.label} color={knobProps.textAccentColor} flex={1}>
|
|
383
383
|
{config.title}
|
|
384
384
|
</Text>
|
|
385
385
|
{config.icon ? (
|
|
@@ -408,7 +408,7 @@ export function KPICard({ config, ...stackProps }: KPICardProps) {
|
|
|
408
408
|
label={knobProps.label}
|
|
409
409
|
/>
|
|
410
410
|
{config.previousValue !== undefined && (
|
|
411
|
-
<Text {...knobProps.label} color={
|
|
411
|
+
<Text {...knobProps.label} color={knobProps.textAccentColor}>
|
|
412
412
|
{t("vs {{previousValue}}", { previousValue: formatMetric(config.previousValue) })}
|
|
413
413
|
</Text>
|
|
414
414
|
)}
|
|
@@ -689,7 +689,7 @@ export function Dashboard({
|
|
|
689
689
|
</H3>
|
|
690
690
|
)}
|
|
691
691
|
{description && (
|
|
692
|
-
<Text {...knobProps.body} {...knobProps.label} color={
|
|
692
|
+
<Text {...knobProps.body} {...knobProps.label} color={knobProps.textAccentColor}>
|
|
693
693
|
{description}
|
|
694
694
|
</Text>
|
|
695
695
|
)}
|
package/src/views/List.spec.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cleanup, fireEvent, screen } from "@testing-library/react";
|
|
2
2
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
3
|
-
import { defaultKnobs, resolveKnobs } from "@multiplatform.one/theme";
|
|
3
|
+
import { defaultKnobs, Preset, resolveKnobs } from "@multiplatform.one/theme";
|
|
4
4
|
import { afterEach, describe, expect, it } from "vitest";
|
|
5
5
|
import {
|
|
6
6
|
List,
|
|
@@ -91,3 +91,44 @@ describe("List keyboard selection chrome (LC-71)", () => {
|
|
|
91
91
|
expect(focused!.textContent).toContain("Q3 Vendor Contract");
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
|
+
|
|
95
|
+
describe("ListRow ink — textAccent reaches the TEXT NODE (F11 / data-chrome honour)", () => {
|
|
96
|
+
function titleColor(title: string, accent: "high" | "low" | "medium"): string[] {
|
|
97
|
+
const { getByText } = renderWithProviders(
|
|
98
|
+
<Preset overrides={{ textAccent: accent }}>
|
|
99
|
+
<ListRow title={title} />
|
|
100
|
+
</Preset>,
|
|
101
|
+
);
|
|
102
|
+
return atoms(getByText(title), ["_col-"]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
it("changes title colour on a textAccent flip", () => {
|
|
106
|
+
const high = titleColor("ink-high", "high");
|
|
107
|
+
const low = titleColor("ink-low", "low");
|
|
108
|
+
expect(high).not.toHaveLength(0);
|
|
109
|
+
expect(low).not.toHaveLength(0);
|
|
110
|
+
expect(high).not.toEqual(low);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("low and medium share the AA legibility floor on the title", () => {
|
|
114
|
+
const low = titleColor("ink-floor-low", "low");
|
|
115
|
+
const medium = titleColor("ink-floor-medium", "medium");
|
|
116
|
+
expect(low).toEqual(medium);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("moves ListRowMeta default ink with textAccent", () => {
|
|
120
|
+
function metaColor(label: string, accent: "high" | "low"): string[] {
|
|
121
|
+
const { getByText } = renderWithProviders(
|
|
122
|
+
<Preset overrides={{ textAccent: accent }}>
|
|
123
|
+
<ListRowMeta>{label}</ListRowMeta>
|
|
124
|
+
</Preset>,
|
|
125
|
+
);
|
|
126
|
+
return atoms(getByText(label), ["_col-"]);
|
|
127
|
+
}
|
|
128
|
+
const high = metaColor("meta-high", "high");
|
|
129
|
+
const low = metaColor("meta-low", "low");
|
|
130
|
+
expect(high).not.toHaveLength(0);
|
|
131
|
+
expect(low).not.toHaveLength(0);
|
|
132
|
+
expect(high).not.toEqual(low);
|
|
133
|
+
});
|
|
134
|
+
});
|
package/src/views/List.tsx
CHANGED
|
@@ -103,7 +103,7 @@ export function ListRowMeta({
|
|
|
103
103
|
}) {
|
|
104
104
|
const { knobProps } = useResolvedKnobs();
|
|
105
105
|
const { selected, onAccent } = useListItemState();
|
|
106
|
-
const resolved = selected && onAccent ? onAccent : (color ??
|
|
106
|
+
const resolved = selected && onAccent ? onAccent : (color ?? knobProps.textAccentColor);
|
|
107
107
|
return (
|
|
108
108
|
<Text
|
|
109
109
|
{...knobProps.label}
|
|
@@ -121,8 +121,9 @@ export function ListRowMeta({
|
|
|
121
121
|
export function ListRow({ icon, title, subtitle, meta }: ListRowProps) {
|
|
122
122
|
const { knobProps } = useResolvedKnobs();
|
|
123
123
|
const { selected, onAccent } = useListItemState();
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
// data-chrome family: textAccent = honour (F11). Same channel as house Text —
|
|
125
|
+
// componentColors.text.primary/muted pin $color/$color11 and ignore the knob.
|
|
126
|
+
const ink = selected && onAccent ? onAccent : knobProps.textAccentColor;
|
|
126
127
|
const iconSize = knobProps.controlIcon.width;
|
|
127
128
|
const leading = React.isValidElement(icon)
|
|
128
129
|
? React.cloneElement(icon as React.ReactElement<{ size?: number; color?: string }>, {
|
|
@@ -139,7 +140,7 @@ export function ListRow({ icon, title, subtitle, meta }: ListRowProps) {
|
|
|
139
140
|
flexShrink={0}
|
|
140
141
|
alignItems="center"
|
|
141
142
|
justifyContent="center"
|
|
142
|
-
{...({ "data-list-slot": "icon", color:
|
|
143
|
+
{...({ "data-list-slot": "icon", color: ink } as Record<string, unknown>)}
|
|
143
144
|
>
|
|
144
145
|
{leading}
|
|
145
146
|
</View>
|
|
@@ -157,7 +158,7 @@ export function ListRow({ icon, title, subtitle, meta }: ListRowProps) {
|
|
|
157
158
|
{subtitle != null && subtitle !== false ? (
|
|
158
159
|
<RowText
|
|
159
160
|
{...knobProps.label}
|
|
160
|
-
color={
|
|
161
|
+
color={ink}
|
|
161
162
|
opacity={selected ? 0.85 : 1}
|
|
162
163
|
numberOfLines={1}
|
|
163
164
|
userSelect="none"
|