Skip to content

Commit b4ac2bf

Browse files
XY gesture support (#70)
Co-authored-by: Asmatzaile <gorkainventor@gmail.com>
1 parent aab2b00 commit b4ac2bf

File tree

15 files changed

+219
-49
lines changed

15 files changed

+219
-49
lines changed

apps/docs/e2e/expects.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,9 @@ export const sourceCodeLinkIsValid = async ({
112112
page: Page;
113113
filePath: string;
114114
}) => {
115-
const url = `https://github.com/satelllte/react-knob-headless/blob/main/${filePath}`;
116-
await expect(link).toHaveAttribute('href', url);
117-
await link.click();
118-
119-
const githubPage = await page.waitForEvent('popup');
120-
await expect(githubPage).toHaveURL(url);
121-
await expect(githubPage).toHaveTitle(
122-
`react-knob-headless/${filePath} at main · satelllte/react-knob-headless · GitHub`,
115+
await expect(link).toHaveAttribute(
116+
'href',
117+
`https://github.com/satelllte/react-knob-headless/blob/main/${filePath}`,
123118
);
124119
};
125120

apps/docs/e2e/index.spec.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,14 +218,14 @@ test.describe('"Horizontal orientation" example', () => {
218218
});
219219
});
220220

221-
test('has "View source" link leading to "KnobPercentageHorizontal.tsx" source code file', async ({
221+
test('has "View source" link leading to "KnobPercentageX.tsx" source code file', async ({
222222
page,
223223
}) => {
224224
const viewSourceLink = locators.exampleViewSourceLink({container});
225225
await expects.sourceCodeLinkIsValid({
226226
link: viewSourceLink,
227227
page,
228-
filePath: 'apps/docs/src/components/knobs/KnobPercentageHorizontal.tsx',
228+
filePath: 'apps/docs/src/components/knobs/KnobPercentageX.tsx',
229229
});
230230
});
231231

@@ -252,3 +252,56 @@ test.describe('"Horizontal orientation" example', () => {
252252
});
253253
});
254254
});
255+
256+
test.describe('"Vertical and horizontal orientation" example', () => {
257+
let container: Locator;
258+
259+
test.beforeEach(({page}) => {
260+
container = locators.exampleContainer({
261+
page,
262+
name: 'Vertical and horizontal orientation',
263+
});
264+
});
265+
266+
test('has "View source" link leading to "KnobPercentageXY.tsx" source code file', async ({
267+
page,
268+
}) => {
269+
const viewSourceLink = locators.exampleViewSourceLink({container});
270+
await expects.sourceCodeLinkIsValid({
271+
link: viewSourceLink,
272+
page,
273+
filePath: 'apps/docs/src/components/knobs/KnobPercentageXY.tsx',
274+
});
275+
});
276+
277+
test.describe('"XY" knob', () => {
278+
let knob: Locator;
279+
let knobOutput: Locator;
280+
281+
test.beforeEach(() => {
282+
knob = locators.exampleKnob({container, name: 'XY'});
283+
knobOutput = locators.exampleKnobOutput({container});
284+
});
285+
286+
test('has correct default value', async () => {
287+
await expects.knobValueIsEqualTo({knob, valueNow: 50});
288+
await expects.knobValueTextIs({knob, knobOutput, valueText: '50%'});
289+
});
290+
291+
test('has correct drag up behaviour', async ({page}) => {
292+
await expects.knobDragsUpCorrectly({knob, valueNow: 50, page});
293+
});
294+
295+
test('has correct drag down behaviour', async ({page}) => {
296+
await expects.knobDragsDownCorrectly({knob, valueNow: 50, page});
297+
});
298+
299+
test('has correct drag left behaviour', async ({page}) => {
300+
await expects.knobDragsLeftCorrectly({knob, valueNow: 50, page});
301+
});
302+
303+
test('has correct drag right behaviour', async ({page}) => {
304+
await expects.knobDragsRightCorrectly({knob, valueNow: 50, page});
305+
});
306+
});
307+
});

apps/docs/e2e/locators.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ const decorativeKnobSky = ({page}: {page: Page}) =>
2626
});
2727

2828
const exampleContainer = ({page, name}: {page: Page; name: string}) =>
29-
page.getByRole('heading', {name}).locator('..');
29+
page.getByRole('heading', {name, exact: true}).locator('..');
3030

3131
const exampleViewSourceLink = ({container}: {container: Locator}) =>
3232
container.getByRole('link', {name: 'View source'});
3333

3434
const exampleKnob = ({container, name}: {container: Locator; name: string}) =>
35-
container.getByRole('slider', {name});
35+
container.getByRole('slider', {name, exact: true});
3636

3737
const exampleKnobOutput = ({container}: {container: Locator}) =>
3838
container.getByRole('status');

apps/docs/src/app/page.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import {GitHubLogoIcon} from '@radix-ui/react-icons';
22
import {KnobDecorative} from '@/components/knobs/KnobDecorative';
33
import {KnobFrequency} from '@/components/knobs/KnobFrequency';
44
import {KnobPercentage} from '@/components/knobs/KnobPercentage';
5-
import {KnobPercentageHorizontal} from '@/components/knobs/KnobPercentageHorizontal';
5+
import {KnobPercentageX} from '@/components/knobs/KnobPercentageX';
6+
import {KnobPercentageXY} from '@/components/knobs/KnobPercentageXY';
67
import {ExternalLinkUnstyled} from '@/components/ui/ExternalLinkUnstyled';
78
import {TableApi} from '@/components/ui/TableApi';
89

@@ -91,9 +92,16 @@ function IndexPage() {
9192
<Example
9293
title='Horizontal orientation'
9394
description="The knob gesture can occur along horizontal (X) axis instead of vertical (Y) one, but it's not common in audio applications."
94-
source='https://github.com/satelllte/react-knob-headless/blob/main/apps/docs/src/components/knobs/KnobPercentageHorizontal.tsx'
95+
source='https://github.com/satelllte/react-knob-headless/blob/main/apps/docs/src/components/knobs/KnobPercentageX.tsx'
9596
>
96-
<KnobPercentageHorizontal label='X' theme='stone' />
97+
<KnobPercentageX label='X' theme='stone' />
98+
</Example>
99+
<Example
100+
title='Vertical and horizontal orientation'
101+
description='The knob gesture can occur along both vertical (Y) and horizontal (X) axis.'
102+
source='https://github.com/satelllte/react-knob-headless/blob/main/apps/docs/src/components/knobs/KnobPercentageXY.tsx'
103+
>
104+
<KnobPercentageXY label='XY' theme='pink' />
97105
</Example>
98106
</div>
99107
</Section>
@@ -155,9 +163,17 @@ function IndexPage() {
155163
name: 'orientation',
156164
type: 'union',
157165
defaultValue: 'vertical',
166+
deprecationNotice: 'use "axis" instead.',
158167
description:
159168
'Orientation of the knob and its gesture. Can be "vertical" or "horizontal".',
160169
},
170+
{
171+
name: 'axis',
172+
type: 'union',
173+
defaultValue: 'y',
174+
description:
175+
'Orientation of the knob and its gesture. Can be "x", "y", or "xy". Note, that "aria-orientation" attribute will not be set for the slider when it\'s "xy" to follow ARIA semantics.',
176+
},
161177
{
162178
name: 'includeIntoTabOrder',
163179
type: 'boolean',

apps/docs/src/components/knobs/KnobBase.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type KnobBaseProps = Pick<
1717
| 'valueMax'
1818
| 'valueRawRoundFn'
1919
| 'valueRawDisplayFn'
20-
| 'orientation'
20+
| 'axis'
2121
| 'mapTo01'
2222
| 'mapFrom01'
2323
> &
@@ -36,7 +36,7 @@ export function KnobBase({
3636
valueMax,
3737
valueRawRoundFn,
3838
valueRawDisplayFn,
39-
orientation,
39+
axis,
4040
stepFn,
4141
stepLargerFn,
4242
mapTo01 = mapTo01Linear,
@@ -77,7 +77,7 @@ export function KnobBase({
7777
valueRawRoundFn={valueRawRoundFn}
7878
valueRawDisplayFn={valueRawDisplayFn}
7979
dragSensitivity={dragSensitivity}
80-
orientation={orientation}
80+
axis={axis}
8181
mapTo01={mapTo01}
8282
mapFrom01={mapFrom01}
8383
onValueRawChange={setValueRaw}

apps/docs/src/components/knobs/KnobFrequency.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import {NormalisableRange} from '@/utils/math/NormalisableRange';
33
import {KnobBase} from './KnobBase';
44

55
type KnobBaseProps = React.ComponentProps<typeof KnobBase>;
6-
type KnobFrequencyProps = Pick<
7-
KnobBaseProps,
8-
'theme' | 'label' | 'orientation'
9-
>;
6+
type KnobFrequencyProps = Pick<KnobBaseProps, 'theme' | 'label' | 'axis'>;
107

118
export function KnobFrequency(props: KnobFrequencyProps) {
129
return (

apps/docs/src/components/knobs/KnobPercentage.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
import {KnobBase} from './KnobBase';
33

44
type KnobBaseProps = React.ComponentProps<typeof KnobBase>;
5-
type KnobPercentageProps = Pick<
6-
KnobBaseProps,
7-
'theme' | 'label' | 'orientation'
8-
>;
5+
type KnobPercentageProps = Pick<KnobBaseProps, 'theme' | 'label' | 'axis'>;
96

107
export function KnobPercentage(props: KnobPercentageProps) {
118
return (

apps/docs/src/components/knobs/KnobPercentageHorizontal.tsx

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use client';
2+
import {KnobPercentage} from './KnobPercentage';
3+
4+
type KnobPercentageProps = React.ComponentProps<typeof KnobPercentage>;
5+
type KnobPercentageXProps = Omit<KnobPercentageProps, 'axis'>; // eslint-disable-line @typescript-eslint/naming-convention
6+
7+
export function KnobPercentageX(props: KnobPercentageXProps) {
8+
return <KnobPercentage axis='x' {...props} />;
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use client';
2+
import {KnobPercentage} from './KnobPercentage';
3+
4+
type KnobPercentageProps = React.ComponentProps<typeof KnobPercentage>;
5+
type KnobPercentageXYProps = Omit<KnobPercentageProps, 'axis'>; // eslint-disable-line @typescript-eslint/naming-convention
6+
7+
// eslint-disable-next-line @typescript-eslint/naming-convention
8+
export function KnobPercentageXY(props: KnobPercentageXYProps) {
9+
return <KnobPercentage axis='xy' {...props} />;
10+
}

0 commit comments

Comments
 (0)