@charcuterie/ui 2.1.0 → 2.2.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/ColorSchemeSwitcher/ColorSchemeSwitcher.d.ts +1 -1
- package/dist/ColorSchemeSwitcher/ColorSchemeSwitcher.d.ts.map +1 -1
- package/dist/ColorSchemeSwitcher/ColorSchemeSwitcher.js.map +1 -1
- package/dist/ColorSchemeToggle/ColorSchemeToggle.d.ts +11 -2
- package/dist/ColorSchemeToggle/ColorSchemeToggle.d.ts.map +1 -1
- package/dist/ColorSchemeToggle/ColorSchemeToggle.js +2 -2
- package/dist/ColorSchemeToggle/ColorSchemeToggle.js.map +1 -1
- package/package.json +1 -1
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.mdx +6 -0
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.test.tsx +12 -0
- package/src/ColorSchemeSwitcher/ColorSchemeSwitcher.tsx +1 -0
- package/src/ColorSchemeToggle/ColorSchemeToggle.mdx +12 -0
- package/src/ColorSchemeToggle/ColorSchemeToggle.stories.tsx +39 -1
- package/src/ColorSchemeToggle/ColorSchemeToggle.test.tsx +39 -3
- package/src/ColorSchemeToggle/ColorSchemeToggle.tsx +15 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ColorSchemeApplier, ColorSchemePersistence, ColorSchemeResolver } from "@charcuterie/logic";
|
|
2
2
|
import type { ReactNode } from "react";
|
|
3
3
|
import type { ColorSchemeIcons, ColorSchemeToggleProps } from "../ColorSchemeToggle/ColorSchemeToggle.tsx";
|
|
4
|
-
export type ColorSchemeSwitcherProps = Pick<ColorSchemeToggleProps, "appearance" | "className" | "isDisabled" | "label" | "order" | "size"> & {
|
|
4
|
+
export type ColorSchemeSwitcherProps = Pick<ColorSchemeToggleProps, "appearance" | "className" | "intent" | "isDisabled" | "label" | "order" | "size"> & {
|
|
5
5
|
/** Override where the resolved scheme is written. Default `<html>`. */
|
|
6
6
|
apply?: ColorSchemeApplier;
|
|
7
7
|
icons: ColorSchemeIcons;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorSchemeSwitcher.d.ts","sourceRoot":"","sources":["../../src/ColorSchemeSwitcher/ColorSchemeSwitcher.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,oBAAoB,CAAA;AAO3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,4CAA4C,CAAA;AAGnD,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,sBAAsB,EACpB,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,CACT,GAAG;IACF,uEAAuE;IACvE,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,KAAK,EAAE,gBAAgB,CAAA;IACvB,uEAAuE;IACvE,WAAW,CAAC,EAAE,sBAAsB,CAAA;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,4EAQjC,wBAAwB,KAAG,SAsB7B,CAAA"}
|
|
1
|
+
{"version":3,"file":"ColorSchemeSwitcher.d.ts","sourceRoot":"","sources":["../../src/ColorSchemeSwitcher/ColorSchemeSwitcher.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACpB,MAAM,oBAAoB,CAAA;AAO3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,4CAA4C,CAAA;AAGnD,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,sBAAsB,EACpB,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,YAAY,GACZ,OAAO,GACP,OAAO,GACP,MAAM,CACT,GAAG;IACF,uEAAuE;IACvE,KAAK,CAAC,EAAE,kBAAkB,CAAA;IAC1B,KAAK,EAAE,gBAAgB,CAAA;IACvB,uEAAuE;IACvE,WAAW,CAAC,EAAE,sBAAsB,CAAA;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,4EAQjC,wBAAwB,KAAG,SAsB7B,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorSchemeSwitcher.js","sourceRoot":"","sources":["../../src/ColorSchemeSwitcher/ColorSchemeSwitcher.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAMhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA4C,CAAA;
|
|
1
|
+
{"version":3,"file":"ColorSchemeSwitcher.js","sourceRoot":"","sources":["../../src/ColorSchemeSwitcher/ColorSchemeSwitcher.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAMhC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA4C,CAAA;AA2B9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAClC,KAAK,EACL,KAAK,EACL,KAAK,EACL,WAAW,EACX,QAAQ,EACR,UAAU,EACV,GAAG,WAAW,EACW,EAAa,EAAE;IACxC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QAC9B,KAAK,EAAE,KAAK,IAAI,iBAAiB,EAAE;QACnC,WAAW,EACT,WAAW,IAAI,uBAAuB,CAAC,UAAU,CAAC;QACpD,QAAQ,EAAE,QAAQ,IAAI,kBAAkB,EAAE;KAC3C,CAAC,CAAC,CAAA;IAEH,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC;QACrC,GAAG,KAAK;QACR,KAAK;KACN,CAAC,CAAA;IAEF,OAAO,CACL,KAAC,iBAAiB,OACZ,WAAW,EACf,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,KAAK,EACd,KAAK,EAAE,KAAK,GACZ,CACH,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ColorSchemeMode } from "@charcuterie/logic";
|
|
2
|
-
import type { ControlSize } from "@charcuterie/tokens";
|
|
2
|
+
import type { ControlSize, IntentName } from "@charcuterie/tokens";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import type { IntentAppearance } from "../intentStyles.ts";
|
|
5
5
|
/**
|
|
@@ -14,6 +14,15 @@ export type ColorSchemeToggleProps = {
|
|
|
14
14
|
appearance?: IntentAppearance;
|
|
15
15
|
className?: string;
|
|
16
16
|
icons: ColorSchemeIcons;
|
|
17
|
+
/**
|
|
18
|
+
* The intent (tone) forwarded to the underlying `IconButton` — the
|
|
19
|
+
* same union `Button`/`IconButton` accept. **Defaults to `neutral`**,
|
|
20
|
+
* not `accent`: a scheme switcher is toolbar chrome, so its ghost
|
|
21
|
+
* hover reads as `hover:bg-intent-neutral-surface` and its icon as
|
|
22
|
+
* `text-intent-neutral-content` rather than accent-violet. Pass
|
|
23
|
+
* `intent="accent"` (or any tone) to make it an accent action.
|
|
24
|
+
*/
|
|
25
|
+
intent?: IntentName;
|
|
17
26
|
isDisabled?: boolean;
|
|
18
27
|
/**
|
|
19
28
|
* Builds the accessible name from the current and next mode.
|
|
@@ -50,5 +59,5 @@ export type ColorSchemeToggleProps = {
|
|
|
50
59
|
* shaped so a `ColorSchemePicker` could join later without changing
|
|
51
60
|
* this API.
|
|
52
61
|
*/
|
|
53
|
-
export declare const ColorSchemeToggle: ({ appearance, className, icons, isDisabled, label, mode, onCycle, order, size, }: ColorSchemeToggleProps) => ReactNode;
|
|
62
|
+
export declare const ColorSchemeToggle: ({ appearance, className, icons, intent, isDisabled, label, mode, onCycle, order, size, }: ColorSchemeToggleProps) => ReactNode;
|
|
54
63
|
//# sourceMappingURL=ColorSchemeToggle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorSchemeToggle.d.ts","sourceRoot":"","sources":["../../src/ColorSchemeToggle/ColorSchemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKzD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ColorSchemeToggle.d.ts","sourceRoot":"","sources":["../../src/ColorSchemeToggle/ColorSchemeToggle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAKzD,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACX,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CACnC,eAAe,EACf,SAAS,CACV,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,gBAAgB,CAAA;IACvB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,CACN,IAAI,EAAE,eAAe,EACrB,QAAQ,EAAE,eAAe,KACtB,MAAM,CAAA;IACX,IAAI,EAAE,eAAe,CAAA;IACrB;;;;;;;OAOG;IACH,OAAO,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAA;IAC5C,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;IAClC,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB,CAAA;AAcD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAI,0FAW/B,sBAAsB,KAAG,SAkB3B,CAAA"}
|
|
@@ -21,9 +21,9 @@ const defaultLabel = (mode, nextMode) => `Colour scheme: ${MODE_LABEL[mode]}. Ac
|
|
|
21
21
|
* shaped so a `ColorSchemePicker` could join later without changing
|
|
22
22
|
* this API.
|
|
23
23
|
*/
|
|
24
|
-
export const ColorSchemeToggle = ({ appearance = "ghost", className, icons, isDisabled = false, label = defaultLabel, mode, onCycle, order = DEFAULT_COLOR_SCHEME_ORDER, size = "md", }) => {
|
|
24
|
+
export const ColorSchemeToggle = ({ appearance = "ghost", className, icons, intent = "neutral", isDisabled = false, label = defaultLabel, mode, onCycle, order = DEFAULT_COLOR_SCHEME_ORDER, size = "md", }) => {
|
|
25
25
|
const nextMode = nextColorSchemeMode(mode, order);
|
|
26
|
-
return (_jsx(IconButton, { appearance: appearance, className: className, isDisabled: isDisabled, label: label(mode, nextMode), onClick: () => {
|
|
26
|
+
return (_jsx(IconButton, { appearance: appearance, className: className, intent: intent, isDisabled: isDisabled, label: label(mode, nextMode), onClick: () => {
|
|
27
27
|
onCycle(nextMode);
|
|
28
28
|
}, size: size, children: icons[mode] }));
|
|
29
29
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorSchemeToggle.js","sourceRoot":"","sources":["../../src/ColorSchemeToggle/ColorSchemeToggle.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"ColorSchemeToggle.js","sourceRoot":"","sources":["../../src/ColorSchemeToggle/ColorSchemeToggle.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,0BAA0B,EAC1B,mBAAmB,GACpB,MAAM,oBAAoB,CAAA;AAO3B,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA8B,CAAA;AAsDzD,MAAM,UAAU,GAAoC;IAClD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;CACjB,CAAA;AAED,MAAM,YAAY,GAAG,CACnB,IAAqB,EACrB,QAAyB,EACzB,EAAE,CACF,kBAAkB,UAAU,CAAC,IAAI,CAAC,2BAA2B,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAA;AAEtF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,EAChC,UAAU,GAAG,OAAO,EACpB,SAAS,EACT,KAAK,EACL,MAAM,GAAG,SAAS,EAClB,UAAU,GAAG,KAAK,EAClB,KAAK,GAAG,YAAY,EACpB,IAAI,EACJ,OAAO,EACP,KAAK,GAAG,0BAA0B,EAClC,IAAI,GAAG,IAAI,GACY,EAAa,EAAE;IACtC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAEjD,OAAO,CACL,KAAC,UAAU,IACT,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,EAC5B,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,CAAC,QAAQ,CAAC,CAAA;QACnB,CAAC,EACD,IAAI,EAAE,IAAI,YAET,KAAK,CAAC,IAAI,CAAC,GACD,CACd,CAAA;AACH,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -18,6 +18,12 @@ follows the OS, remembers the user's choice, and re-themes with zero React re-re
|
|
|
18
18
|
|
|
19
19
|
<Controls />
|
|
20
20
|
|
|
21
|
+
## Tone is neutral chrome
|
|
22
|
+
|
|
23
|
+
Like `ColorSchemeToggle`, this forwards `intent="neutral"` to the button by default — a
|
|
24
|
+
scheme switcher is chrome, not an accent action, so its ghost hover is the neutral surface
|
|
25
|
+
rather than accent-violet. Pass `intent` (any tone `Button` accepts) to change it.
|
|
26
|
+
|
|
21
27
|
## Every seam is overridable — that is the point
|
|
22
28
|
|
|
23
29
|
`resolver`, `persistence`, and `apply` all default to the browser implementations but can be
|
|
@@ -51,3 +51,15 @@ test("cycling to a concrete mode re-applies the scheme", async () => {
|
|
|
51
51
|
|
|
52
52
|
await expectNoAxeViolations(canvasElement)
|
|
53
53
|
})
|
|
54
|
+
|
|
55
|
+
test("the connected switcher forwards the neutral intent by default", async () => {
|
|
56
|
+
const { canvasElement } = await mountStory(Default)
|
|
57
|
+
|
|
58
|
+
const button = canvasElement.querySelector("button")
|
|
59
|
+
|
|
60
|
+
// Chrome, not an accent action — the hover is the neutral surface.
|
|
61
|
+
expect(button?.className).toContain(
|
|
62
|
+
"hover:bg-intent-neutral-surface",
|
|
63
|
+
)
|
|
64
|
+
expect(button?.className).not.toContain("intent-accent")
|
|
65
|
+
})
|
|
@@ -39,6 +39,18 @@ rather than a nameless button.
|
|
|
39
39
|
|
|
40
40
|
<Canvas of={ColorSchemeToggleStories.AllModes} />
|
|
41
41
|
|
|
42
|
+
## Intent is `neutral`, not accent
|
|
43
|
+
|
|
44
|
+
`intent` is the same tone union `Button`/`IconButton` accept, and it **defaults to
|
|
45
|
+
`neutral`** here on purpose. A scheme switcher is toolbar chrome, so its ghost hover reads
|
|
46
|
+
as `hover:bg-intent-neutral-surface` and its icon as `text-intent-neutral-content` —
|
|
47
|
+
chrome, not a violet accent action. `IconButton`'s own default is `accent`, which on real
|
|
48
|
+
app chrome made this control look like a call-to-action; forwarding `neutral` is the fix,
|
|
49
|
+
and it means a consumer no longer needs an `!important` className to tone it down. Pass
|
|
50
|
+
`intent="accent"` (or any tone) to opt back in.
|
|
51
|
+
|
|
52
|
+
<Canvas of={ColorSchemeToggleStories.Intents} />
|
|
53
|
+
|
|
42
54
|
## Cycling is the only form, for now
|
|
43
55
|
|
|
44
56
|
A segmented, all-three-visible `ColorSchemePicker` was considered and deferred (owner chose
|
|
@@ -2,7 +2,10 @@ import type { ColorSchemeMode } from "@charcuterie/logic"
|
|
|
2
2
|
import type { Meta, StoryObj } from "@storybook/react"
|
|
3
3
|
import { useState } from "react"
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
controlSizeArgType,
|
|
7
|
+
intentArgType,
|
|
8
|
+
} from "../argTypes.storyHelpers.ts"
|
|
6
9
|
import {
|
|
7
10
|
ContainerBoard,
|
|
8
11
|
StoryCell,
|
|
@@ -34,6 +37,7 @@ const meta = {
|
|
|
34
37
|
component: ColorSchemeToggle,
|
|
35
38
|
parameters: { layout: "padded" },
|
|
36
39
|
argTypes: {
|
|
40
|
+
intent: intentArgType,
|
|
37
41
|
// `mode` is `ColorSchemeMode` from @charcuterie/logic — a bare
|
|
38
42
|
// specifier docgen cannot enumerate, so it gets an explicit
|
|
39
43
|
// radio rather than falling through to the object control.
|
|
@@ -46,6 +50,7 @@ const meta = {
|
|
|
46
50
|
args: {
|
|
47
51
|
appearance: "ghost",
|
|
48
52
|
icons: ICONS,
|
|
53
|
+
intent: "neutral",
|
|
49
54
|
isDisabled: false,
|
|
50
55
|
mode: "system",
|
|
51
56
|
onCycle: () => {},
|
|
@@ -117,6 +122,39 @@ export const AllModes: Story = {
|
|
|
117
122
|
),
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* The tone is **neutral by default** — a scheme switcher is toolbar
|
|
127
|
+
* chrome, so its ghost hover is `hover:bg-intent-neutral-surface` and
|
|
128
|
+
* its icon `text-intent-neutral-content`, which read as chrome on a
|
|
129
|
+
* normal surface rather than as an accent action. A consumer that
|
|
130
|
+
* wants it to draw attention passes `intent="accent"` (or any tone).
|
|
131
|
+
*/
|
|
132
|
+
export const Intents: Story = {
|
|
133
|
+
render: (toggleProps) => (
|
|
134
|
+
<StorySection title="neutral (default) vs an explicit accent override.">
|
|
135
|
+
<StoryGrid columns={2}>
|
|
136
|
+
<StoryCell label="intent=neutral (default)">
|
|
137
|
+
<ColorSchemeToggle
|
|
138
|
+
{...toggleProps}
|
|
139
|
+
intent="neutral"
|
|
140
|
+
mode="system"
|
|
141
|
+
onCycle={() => {}}
|
|
142
|
+
/>
|
|
143
|
+
</StoryCell>
|
|
144
|
+
|
|
145
|
+
<StoryCell label="intent=accent">
|
|
146
|
+
<ColorSchemeToggle
|
|
147
|
+
{...toggleProps}
|
|
148
|
+
intent="accent"
|
|
149
|
+
mode="system"
|
|
150
|
+
onCycle={() => {}}
|
|
151
|
+
/>
|
|
152
|
+
</StoryCell>
|
|
153
|
+
</StoryGrid>
|
|
154
|
+
</StorySection>
|
|
155
|
+
),
|
|
156
|
+
}
|
|
157
|
+
|
|
120
158
|
export const Sizes: Story = {
|
|
121
159
|
render: (toggleProps) => (
|
|
122
160
|
<StorySection title="Square on the control height, so it lines up with the buttons beside it in a toolbar.">
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
composeStories,
|
|
3
|
+
composeStory,
|
|
4
|
+
} from "@storybook/react"
|
|
5
|
+
import { expect, userEvent } from "storybook/test"
|
|
3
6
|
import { test } from "vitest"
|
|
4
7
|
|
|
5
8
|
import { expectNoAxeViolations } from "../expectNoAxeViolations.testHelpers.ts"
|
|
6
9
|
import { mountStory } from "../mountStory.testHelpers.ts"
|
|
7
10
|
import { expectAgentDrivable } from "../testing/index.ts"
|
|
8
|
-
import * as stories from "./ColorSchemeToggle.stories.tsx"
|
|
11
|
+
import meta, * as stories from "./ColorSchemeToggle.stories.tsx"
|
|
9
12
|
|
|
10
13
|
const { AllModes, Default } = composeStories(stories)
|
|
11
14
|
|
|
@@ -78,3 +81,36 @@ test("each mode renders its own control", async () => {
|
|
|
78
81
|
role: "button",
|
|
79
82
|
})
|
|
80
83
|
})
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The fix: the switcher is chrome, so it forwards `neutral` to the
|
|
87
|
+
* button by default — a neutral ghost hover
|
|
88
|
+
* (`hover:bg-intent-neutral-surface`) and a neutral icon colour,
|
|
89
|
+
* rather than `IconButton`'s accent default that read as a violet
|
|
90
|
+
* action on real app chrome.
|
|
91
|
+
*/
|
|
92
|
+
test("defaults to the neutral intent, not accent", async () => {
|
|
93
|
+
const { canvasElement } = await mountStory(Default)
|
|
94
|
+
|
|
95
|
+
const button = canvasElement.querySelector("button")
|
|
96
|
+
|
|
97
|
+
expect(button?.className).toContain(
|
|
98
|
+
"hover:bg-intent-neutral-surface",
|
|
99
|
+
)
|
|
100
|
+
expect(button?.className).not.toContain("intent-accent")
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("an explicit intent overrides the default", async () => {
|
|
104
|
+
const AccentToggle = composeStory(
|
|
105
|
+
{ args: { intent: "accent" } },
|
|
106
|
+
meta,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const { canvasElement } = await mountStory(AccentToggle)
|
|
110
|
+
|
|
111
|
+
const button = canvasElement.querySelector("button")
|
|
112
|
+
|
|
113
|
+
expect(button?.className).toContain(
|
|
114
|
+
"hover:bg-intent-accent-surface",
|
|
115
|
+
)
|
|
116
|
+
})
|
|
@@ -3,7 +3,10 @@ import {
|
|
|
3
3
|
DEFAULT_COLOR_SCHEME_ORDER,
|
|
4
4
|
nextColorSchemeMode,
|
|
5
5
|
} from "@charcuterie/logic"
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ControlSize,
|
|
8
|
+
IntentName,
|
|
9
|
+
} from "@charcuterie/tokens"
|
|
7
10
|
import type { ReactNode } from "react"
|
|
8
11
|
|
|
9
12
|
import { IconButton } from "../IconButton/IconButton.tsx"
|
|
@@ -25,6 +28,15 @@ export type ColorSchemeToggleProps = {
|
|
|
25
28
|
appearance?: IntentAppearance
|
|
26
29
|
className?: string
|
|
27
30
|
icons: ColorSchemeIcons
|
|
31
|
+
/**
|
|
32
|
+
* The intent (tone) forwarded to the underlying `IconButton` — the
|
|
33
|
+
* same union `Button`/`IconButton` accept. **Defaults to `neutral`**,
|
|
34
|
+
* not `accent`: a scheme switcher is toolbar chrome, so its ghost
|
|
35
|
+
* hover reads as `hover:bg-intent-neutral-surface` and its icon as
|
|
36
|
+
* `text-intent-neutral-content` rather than accent-violet. Pass
|
|
37
|
+
* `intent="accent"` (or any tone) to make it an accent action.
|
|
38
|
+
*/
|
|
39
|
+
intent?: IntentName
|
|
28
40
|
isDisabled?: boolean
|
|
29
41
|
/**
|
|
30
42
|
* Builds the accessible name from the current and next mode.
|
|
@@ -81,6 +93,7 @@ export const ColorSchemeToggle = ({
|
|
|
81
93
|
appearance = "ghost",
|
|
82
94
|
className,
|
|
83
95
|
icons,
|
|
96
|
+
intent = "neutral",
|
|
84
97
|
isDisabled = false,
|
|
85
98
|
label = defaultLabel,
|
|
86
99
|
mode,
|
|
@@ -94,6 +107,7 @@ export const ColorSchemeToggle = ({
|
|
|
94
107
|
<IconButton
|
|
95
108
|
appearance={appearance}
|
|
96
109
|
className={className}
|
|
110
|
+
intent={intent}
|
|
97
111
|
isDisabled={isDisabled}
|
|
98
112
|
label={label(mode, nextMode)}
|
|
99
113
|
onClick={() => {
|