@toptal/picasso-switch 100.0.0 → 101.0.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-package/src/Switch/Switch.d.ts +5 -0
- package/dist-package/src/Switch/Switch.d.ts.map +1 -1
- package/dist-package/src/Switch/Switch.js +7 -4
- package/dist-package/src/Switch/Switch.js.map +1 -1
- package/package.json +5 -5
- package/src/Switch/Switch.tsx +12 -4
- package/src/Switch/__snapshots__/test.tsx.snap +63 -82
- package/src/Switch/test.tsx +38 -8
|
@@ -10,6 +10,11 @@ export interface Props extends BaseProps, TextLabelProps, Omit<ButtonHTMLAttribu
|
|
|
10
10
|
label?: ReactNode;
|
|
11
11
|
/** Callback invoked when `Switch` changed its value */
|
|
12
12
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => void;
|
|
13
|
+
/** Testids of the `Switch` internal elements. The top-level `data-testid` stays on the `[role="switch"]` element */
|
|
14
|
+
testIds?: {
|
|
15
|
+
/** Testid of the visually hidden native `<input>` (rendered as a sibling of the `[role="switch"]` element) */
|
|
16
|
+
input?: string;
|
|
17
|
+
};
|
|
13
18
|
}
|
|
14
19
|
export declare const Switch: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLButtonElement>>;
|
|
15
20
|
export default Switch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../src/Switch/Switch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,KAAqB,MAAM,OAAO,CAAA;AAIzC,MAAM,WAAW,KACf,SAAQ,SAAS,EACf,cAAc,EACd,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpE,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAC1C,OAAO,EAAE,OAAO,KACb,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"Switch.d.ts","sourceRoot":"","sources":["../../../src/Switch/Switch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,KAAqB,MAAM,OAAO,CAAA;AAIzC,MAAM,WAAW,KACf,SAAQ,SAAS,EACf,cAAc,EACd,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IACpE,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAC1C,OAAO,EAAE,OAAO,KACb,IAAI,CAAA;IACT,oHAAoH;IACpH,OAAO,CAAC,EAAE;QACR,8GAA8G;QAC9G,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,eAAO,MAAM,MAAM,iFAsGjB,CAAA;AAIF,eAAe,MAAM,CAAA"}
|
|
@@ -11,22 +11,25 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { Switch as BaseUISwitch } from '@base-ui/react/switch';
|
|
13
13
|
import { useBaseUiId } from '@base-ui/react/internals/useBaseUiId';
|
|
14
|
-
import { toReactChangeEvent } from '@toptal/picasso-shared';
|
|
14
|
+
import { toReactChangeEvent, useInputTestId } from '@toptal/picasso-shared';
|
|
15
15
|
import React, { forwardRef } from 'react';
|
|
16
16
|
import { FormControlLabel } from '@toptal/picasso-form-label';
|
|
17
17
|
import { twMerge } from '@toptal/picasso-tailwind-merge';
|
|
18
18
|
export const Switch = forwardRef(function Switch(props, ref) {
|
|
19
19
|
var _a;
|
|
20
20
|
const { onChange, disabled = false, label, id, className, style, checked, titleCase, value, color: _color, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
21
|
-
|
|
21
|
+
testIds } = props, rest = __rest(props, ["onChange", "disabled", "label", "id", "className", "style", "checked", "titleCase", "value", "color", "testIds"]);
|
|
22
22
|
const handleCheckedChange = (nextChecked, { event }) => onChange === null || onChange === void 0 ? void 0 : onChange(toReactChangeEvent(event), nextChecked);
|
|
23
23
|
const rootRest = rest;
|
|
24
24
|
// Name the control via `aria-labelledby` so it is the single label-associated
|
|
25
25
|
// node (see FormControlLabel `labelId`), only when there is a label.
|
|
26
26
|
const generatedLabelId = useBaseUiId();
|
|
27
27
|
const labelId = label ? generatedLabelId : undefined;
|
|
28
|
+
// Base UI renders the hidden input beside the root and exposes it only
|
|
29
|
+
// through `inputRef`, so the testid is stamped on it imperatively
|
|
30
|
+
const inputTestIdRef = useInputTestId(testIds === null || testIds === void 0 ? void 0 : testIds.input);
|
|
28
31
|
const switchElement = (React.createElement("span", { className: 'relative inline-flex shrink-0 align-middle overflow-clip [overflow-clip-margin:6px]' },
|
|
29
|
-
React.createElement(BaseUISwitch.Root, Object.assign({}, rootRest, { ref: ref, "aria-labelledby": (_a = rootRest['aria-labelledby']) !== null && _a !== void 0 ? _a : labelId, checked: checked, className: twMerge('w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group', 'cursor-pointer outline-none data-[disabled]:cursor-default', className), style: style, disabled: disabled, id: id, value: value === undefined ? undefined : String(value), onCheckedChange: handleCheckedChange
|
|
32
|
+
React.createElement(BaseUISwitch.Root, Object.assign({}, rootRest, { ref: ref, inputRef: inputTestIdRef, "aria-labelledby": (_a = rootRest['aria-labelledby']) !== null && _a !== void 0 ? _a : labelId, checked: checked, className: twMerge('w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group', 'cursor-pointer outline-none data-[disabled]:cursor-default', className), style: style, disabled: disabled, id: id, value: value === undefined ? undefined : String(value), onCheckedChange: handleCheckedChange }),
|
|
30
33
|
React.createElement("span", { className: twMerge('w-full h-full border border-solid bg-gray-600 border-gray-600 opacity-100 rounded-[12px]', 'transition-colors duration-300 ease-out', 'group-data-[checked]:bg-blue-500 group-data-[checked]:border-blue-500', 'group-data-[disabled]:opacity-40', 'group-[[data-disabled][data-unchecked]]:bg-black') }),
|
|
31
34
|
React.createElement(BaseUISwitch.Thumb, { className: twMerge('w-[22px] h-[22px] bg-current text-white block rounded-full shadow-1 absolute z-10 p-0 top-[1px] left-[1px]', 'transition-transform duration-150 ease-out', 'group-[:hover:not([data-disabled])]:shadow-[0_0_0_4px_rgba(32,78,207,0.48)]', 'group-focus-visible:shadow-[0_0_0_4px_rgba(32,78,207,0.48)]', 'group-data-[checked]:translate-x-[16px]') }))));
|
|
32
35
|
if (!label) {
|
|
@@ -35,7 +38,7 @@ export const Switch = forwardRef(function Switch(props, ref) {
|
|
|
35
38
|
return (React.createElement(FormControlLabel, { classes: {
|
|
36
39
|
root: 'items-start text-lg',
|
|
37
40
|
label: 'ml-[0.5em] mt-[0.25em] max-w-[calc(100%-1em-0.5em+1px)]',
|
|
38
|
-
}, control: switchElement, labelId: labelId, disabled: disabled, label: label, titleCase: titleCase
|
|
41
|
+
}, control: switchElement, labelId: labelId, disabled: disabled, label: label, titleCase: titleCase }));
|
|
39
42
|
});
|
|
40
43
|
Switch.displayName = 'Switch';
|
|
41
44
|
export default Switch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../../src/Switch/Switch.tsx"],"names":[],"mappings":";;;;;;;;;;;AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAA;AAElE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../../src/Switch/Switch.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toptal/picasso-switch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "101.0.0",
|
|
4
4
|
"description": "Toptal UI components library - Switch",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"homepage": "https://github.com/toptal/picasso/tree/master/packages/picasso#readme",
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@base-ui/react": "^1.6.0",
|
|
22
|
-
"@toptal/picasso-form-label": "100.0.
|
|
23
|
-
"@toptal/picasso-shared": "100.
|
|
22
|
+
"@toptal/picasso-form-label": "100.0.1",
|
|
23
|
+
"@toptal/picasso-shared": "100.1.0"
|
|
24
24
|
},
|
|
25
25
|
"sideEffects": [
|
|
26
26
|
"**/styles.ts",
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
".": "./dist-package/src/index.js"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
+
"@toptal/picasso-tailwind-merge": "100.0.0",
|
|
39
40
|
"@toptal/picasso-provider": "100.0.0",
|
|
40
|
-
"@toptal/picasso-test-utils": "100.0.
|
|
41
|
-
"@toptal/picasso-tailwind-merge": "100.0.0"
|
|
41
|
+
"@toptal/picasso-test-utils": "100.0.1"
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
44
|
"dist-package/**",
|
package/src/Switch/Switch.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Switch as BaseUISwitch } from '@base-ui/react/switch'
|
|
2
2
|
import { useBaseUiId } from '@base-ui/react/internals/useBaseUiId'
|
|
3
3
|
import type { BaseProps, TextLabelProps } from '@toptal/picasso-shared'
|
|
4
|
-
import { toReactChangeEvent } from '@toptal/picasso-shared'
|
|
4
|
+
import { toReactChangeEvent, useInputTestId } from '@toptal/picasso-shared'
|
|
5
5
|
import type { ButtonHTMLAttributes, ReactNode } from 'react'
|
|
6
6
|
import React, { forwardRef } from 'react'
|
|
7
7
|
import { FormControlLabel } from '@toptal/picasso-form-label'
|
|
@@ -22,6 +22,11 @@ export interface Props
|
|
|
22
22
|
event: React.ChangeEvent<HTMLInputElement>,
|
|
23
23
|
checked: boolean
|
|
24
24
|
) => void
|
|
25
|
+
/** Testids of the `Switch` internal elements. The top-level `data-testid` stays on the `[role="switch"]` element */
|
|
26
|
+
testIds?: {
|
|
27
|
+
/** Testid of the visually hidden native `<input>` (rendered as a sibling of the `[role="switch"]` element) */
|
|
28
|
+
input?: string
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
export const Switch = forwardRef<HTMLButtonElement, Props>(function Switch(
|
|
@@ -39,7 +44,7 @@ export const Switch = forwardRef<HTMLButtonElement, Props>(function Switch(
|
|
|
39
44
|
titleCase,
|
|
40
45
|
value,
|
|
41
46
|
color: _color, // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
42
|
-
|
|
47
|
+
testIds,
|
|
43
48
|
...rest
|
|
44
49
|
} = props
|
|
45
50
|
|
|
@@ -64,11 +69,16 @@ export const Switch = forwardRef<HTMLButtonElement, Props>(function Switch(
|
|
|
64
69
|
const generatedLabelId = useBaseUiId()
|
|
65
70
|
const labelId = label ? generatedLabelId : undefined
|
|
66
71
|
|
|
72
|
+
// Base UI renders the hidden input beside the root and exposes it only
|
|
73
|
+
// through `inputRef`, so the testid is stamped on it imperatively
|
|
74
|
+
const inputTestIdRef = useInputTestId(testIds?.input)
|
|
75
|
+
|
|
67
76
|
const switchElement = (
|
|
68
77
|
<span className='relative inline-flex shrink-0 align-middle overflow-clip [overflow-clip-margin:6px]'>
|
|
69
78
|
<BaseUISwitch.Root
|
|
70
79
|
{...rootRest}
|
|
71
80
|
ref={ref}
|
|
81
|
+
inputRef={inputTestIdRef}
|
|
72
82
|
aria-labelledby={rootRest['aria-labelledby'] ?? labelId}
|
|
73
83
|
checked={checked}
|
|
74
84
|
className={twMerge(
|
|
@@ -81,7 +91,6 @@ export const Switch = forwardRef<HTMLButtonElement, Props>(function Switch(
|
|
|
81
91
|
id={id}
|
|
82
92
|
value={value === undefined ? undefined : String(value)}
|
|
83
93
|
onCheckedChange={handleCheckedChange}
|
|
84
|
-
data-testid={label ? undefined : dataTestId}
|
|
85
94
|
>
|
|
86
95
|
<span
|
|
87
96
|
className={twMerge(
|
|
@@ -120,7 +129,6 @@ export const Switch = forwardRef<HTMLButtonElement, Props>(function Switch(
|
|
|
120
129
|
disabled={disabled}
|
|
121
130
|
label={label}
|
|
122
131
|
titleCase={titleCase}
|
|
123
|
-
data-testid={dataTestId}
|
|
124
132
|
/>
|
|
125
133
|
)
|
|
126
134
|
})
|
|
@@ -1,49 +1,24 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`Switch behaves correctly when interacting 1`] = `
|
|
4
|
-
<
|
|
5
|
-
|
|
4
|
+
<span
|
|
5
|
+
aria-checked="true"
|
|
6
|
+
aria-labelledby="base-ui-:rk:"
|
|
7
|
+
class="w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group cursor-pointer outline-none data-[disabled]:cursor-default"
|
|
8
|
+
data-checked=""
|
|
6
9
|
data-testid="switch"
|
|
10
|
+
id="base-ui-:rl:"
|
|
11
|
+
role="switch"
|
|
12
|
+
tabindex="0"
|
|
7
13
|
>
|
|
8
14
|
<span
|
|
9
|
-
class="
|
|
10
|
-
|
|
11
|
-
<span
|
|
12
|
-
aria-checked="true"
|
|
13
|
-
aria-labelledby="base-ui-:rk:"
|
|
14
|
-
class="w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group cursor-pointer outline-none data-[disabled]:cursor-default"
|
|
15
|
-
data-checked=""
|
|
16
|
-
id="base-ui-:rl:"
|
|
17
|
-
role="switch"
|
|
18
|
-
tabindex="0"
|
|
19
|
-
>
|
|
20
|
-
<span
|
|
21
|
-
class="w-full h-full border border-solid bg-gray border-gray opacity-100 rounded-[12px] transition-colors duration-300 ease-out group-data-[checked]:bg-blue group-data-[checked]:border-blue group-data-[disabled]:opacity group-[[data-disabled][data-unchecked]]:bg-black"
|
|
22
|
-
/>
|
|
23
|
-
<span
|
|
24
|
-
class="w-[22px] h-[22px] bg-current text-white block rounded-full shadow-1 absolute z-10 p-0 top-[1px] left-[1px] transition-transform duration-150 ease-out group-[:hover:not([data-disabled])]:shadow-[0_0_0_4px_rgba(32,78,207,0.48)] group-focus-visible:shadow group-data-[checked]:translate-x"
|
|
25
|
-
data-checked=""
|
|
26
|
-
/>
|
|
27
|
-
</span>
|
|
28
|
-
<input
|
|
29
|
-
aria-hidden="true"
|
|
30
|
-
id="base-ui-:rm:"
|
|
31
|
-
style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;"
|
|
32
|
-
tabindex="-1"
|
|
33
|
-
type="checkbox"
|
|
34
|
-
/>
|
|
35
|
-
</span>
|
|
15
|
+
class="w-full h-full border border-solid bg-gray border-gray opacity-100 rounded-[12px] transition-colors duration-300 ease-out group-data-[checked]:bg-blue group-data-[checked]:border-blue group-data-[disabled]:opacity group-[[data-disabled][data-unchecked]]:bg-black"
|
|
16
|
+
/>
|
|
36
17
|
<span
|
|
37
|
-
class="
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class="align-top text-[0.8125rem]"
|
|
42
|
-
>
|
|
43
|
-
Switch
|
|
44
|
-
</span>
|
|
45
|
-
</span>
|
|
46
|
-
</div>
|
|
18
|
+
class="w-[22px] h-[22px] bg-current text-white block rounded-full shadow-1 absolute z-10 p-0 top-[1px] left-[1px] transition-transform duration-150 ease-out group-[:hover:not([data-disabled])]:shadow-[0_0_0_4px_rgba(32,78,207,0.48)] group-focus-visible:shadow group-data-[checked]:translate-x"
|
|
19
|
+
data-checked=""
|
|
20
|
+
/>
|
|
21
|
+
</span>
|
|
47
22
|
`;
|
|
48
23
|
|
|
49
24
|
exports[`Switch renders default Switch without label 1`] = `
|
|
@@ -84,52 +59,58 @@ exports[`Switch renders default Switch without label 1`] = `
|
|
|
84
59
|
`;
|
|
85
60
|
|
|
86
61
|
exports[`Switch renders disabled state 1`] = `
|
|
87
|
-
<div
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
>
|
|
91
|
-
<span
|
|
92
|
-
class="relative inline-flex shrink-0 align-middle overflow-clip [overflow-clip"
|
|
93
|
-
disabled=""
|
|
62
|
+
<div>
|
|
63
|
+
<div
|
|
64
|
+
class="flex-1 box-border [:where(&)_*]:font-sans [&_*]:[box-sizing:inherit] [&_*::before]:[box-sizing:inherit] [&_*::after]:[box-sizing:inherit]"
|
|
94
65
|
>
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
aria-disabled="true"
|
|
98
|
-
aria-labelledby="base-ui-:r8:"
|
|
99
|
-
class="w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group cursor-pointer outline-none data-[disabled]:cursor-default"
|
|
100
|
-
data-disabled=""
|
|
101
|
-
data-unchecked=""
|
|
102
|
-
id="base-ui-:r9:"
|
|
103
|
-
role="switch"
|
|
104
|
-
tabindex="-1"
|
|
66
|
+
<div
|
|
67
|
+
class="inline-flex max-w align-middle -webkit-tap-highlight-color mx-0 cursor-default items-start text-lg"
|
|
105
68
|
>
|
|
106
69
|
<span
|
|
107
|
-
class="
|
|
108
|
-
|
|
70
|
+
class="relative inline-flex shrink-0 align-middle overflow-clip [overflow-clip"
|
|
71
|
+
disabled=""
|
|
72
|
+
>
|
|
73
|
+
<span
|
|
74
|
+
aria-checked="false"
|
|
75
|
+
aria-disabled="true"
|
|
76
|
+
aria-labelledby="base-ui-:r8:"
|
|
77
|
+
class="w-[40px] h-[24px] p-0 relative inline-flex z-0 overflow-visible shrink-0 align-middle group cursor-pointer outline-none data-[disabled]:cursor-default"
|
|
78
|
+
data-disabled=""
|
|
79
|
+
data-testid="switch"
|
|
80
|
+
data-unchecked=""
|
|
81
|
+
id="base-ui-:r9:"
|
|
82
|
+
role="switch"
|
|
83
|
+
tabindex="-1"
|
|
84
|
+
>
|
|
85
|
+
<span
|
|
86
|
+
class="w-full h-full border border-solid bg-gray border-gray opacity-100 rounded-[12px] transition-colors duration-300 ease-out group-data-[checked]:bg-blue group-data-[checked]:border-blue group-data-[disabled]:opacity group-[[data-disabled][data-unchecked]]:bg-black"
|
|
87
|
+
/>
|
|
88
|
+
<span
|
|
89
|
+
class="w-[22px] h-[22px] bg-current text-white block rounded-full shadow-1 absolute z-10 p-0 top-[1px] left-[1px] transition-transform duration-150 ease-out group-[:hover:not([data-disabled])]:shadow-[0_0_0_4px_rgba(32,78,207,0.48)] group-focus-visible:shadow group-data-[checked]:translate-x"
|
|
90
|
+
data-disabled=""
|
|
91
|
+
data-unchecked=""
|
|
92
|
+
/>
|
|
93
|
+
</span>
|
|
94
|
+
<input
|
|
95
|
+
aria-hidden="true"
|
|
96
|
+
disabled=""
|
|
97
|
+
id="base-ui-:ra:"
|
|
98
|
+
style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;"
|
|
99
|
+
tabindex="-1"
|
|
100
|
+
type="checkbox"
|
|
101
|
+
/>
|
|
102
|
+
</span>
|
|
109
103
|
<span
|
|
110
|
-
class="
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
type="checkbox"
|
|
122
|
-
/>
|
|
123
|
-
</span>
|
|
124
|
-
<span
|
|
125
|
-
class="inline-block leading-[1em] mb-0 text-graphite pointer-events ml-[0.5em] mt-[0.25em] max-w-[calc(100%-1em"
|
|
126
|
-
id="base-ui-:r8:"
|
|
127
|
-
>
|
|
128
|
-
<span
|
|
129
|
-
class="align-top text-[0.8125rem]"
|
|
130
|
-
>
|
|
131
|
-
Disabled
|
|
132
|
-
</span>
|
|
133
|
-
</span>
|
|
104
|
+
class="inline-block leading-[1em] mb-0 text-graphite pointer-events ml-[0.5em] mt-[0.25em] max-w-[calc(100%-1em"
|
|
105
|
+
id="base-ui-:r8:"
|
|
106
|
+
>
|
|
107
|
+
<span
|
|
108
|
+
class="align-top text-[0.8125rem]"
|
|
109
|
+
>
|
|
110
|
+
Disabled
|
|
111
|
+
</span>
|
|
112
|
+
</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
134
115
|
</div>
|
|
135
116
|
`;
|
package/src/Switch/test.tsx
CHANGED
|
@@ -33,36 +33,36 @@ describe('Switch', () => {
|
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
it('renders default Switch with label', () => {
|
|
36
|
-
const {
|
|
36
|
+
const { getByRole } = renderSwitch({ label: 'A Switch' })
|
|
37
37
|
|
|
38
|
-
expect(
|
|
38
|
+
expect(getByRole('switch', { name: 'A Switch' })).toBeVisible()
|
|
39
39
|
})
|
|
40
40
|
|
|
41
41
|
it('renders disabled state', () => {
|
|
42
|
-
const {
|
|
42
|
+
const { container } = renderSwitch({
|
|
43
43
|
disabled: true,
|
|
44
44
|
label: 'Disabled',
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
-
expect(
|
|
47
|
+
expect(container).toMatchSnapshot()
|
|
48
48
|
})
|
|
49
49
|
|
|
50
50
|
it('transforms text to title case when Picasso titleCase property is true', () => {
|
|
51
|
-
const {
|
|
51
|
+
const { getByText } = renderSwitch(
|
|
52
52
|
{ label: 'abc ac4' },
|
|
53
53
|
{ titleCase: true }
|
|
54
54
|
)
|
|
55
55
|
|
|
56
|
-
expect(
|
|
56
|
+
expect(getByText('Abc Ac4')).toBeVisible()
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
it('transforms text to title case when Picasso titleCase property is true but the component property overrides it', () => {
|
|
60
|
-
const {
|
|
60
|
+
const { getByText } = renderSwitch(
|
|
61
61
|
{ label: 'abc dp3', titleCase: false },
|
|
62
62
|
{ titleCase: true }
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
-
expect(
|
|
65
|
+
expect(getByText('abc dp3')).toBeVisible()
|
|
66
66
|
})
|
|
67
67
|
|
|
68
68
|
it('behaves correctly when interacting', () => {
|
|
@@ -123,4 +123,34 @@ describe('Switch', () => {
|
|
|
123
123
|
})
|
|
124
124
|
})
|
|
125
125
|
})
|
|
126
|
+
|
|
127
|
+
describe('testIds', () => {
|
|
128
|
+
it('keeps the top-level data-testid on the role element, with and without label', () => {
|
|
129
|
+
const labelled = render(<Switch data-testid='switch' label='A Switch' />)
|
|
130
|
+
|
|
131
|
+
expect(labelled.getByTestId('switch')).toBe(labelled.getByRole('switch'))
|
|
132
|
+
|
|
133
|
+
labelled.unmount()
|
|
134
|
+
|
|
135
|
+
const bare = render(<Switch data-testid='switch' />)
|
|
136
|
+
|
|
137
|
+
expect(bare.getByTestId('switch')).toBe(bare.getByRole('switch'))
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('places testIds.input on the visually hidden native input', () => {
|
|
141
|
+
const { getByTestId, getByRole } = render(
|
|
142
|
+
<Switch label='A Switch' testIds={{ input: 'switch-input' }} />
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const input = getByTestId('switch-input')
|
|
146
|
+
|
|
147
|
+
expect(input).toBeInstanceOf(HTMLInputElement)
|
|
148
|
+
// the input is rendered beside the role element, not inside it
|
|
149
|
+
expect(getByRole('switch')).not.toContainElement(input)
|
|
150
|
+
|
|
151
|
+
fireEvent.click(getByRole('switch'))
|
|
152
|
+
|
|
153
|
+
expect(input).toBeChecked()
|
|
154
|
+
})
|
|
155
|
+
})
|
|
126
156
|
})
|