Skip to content

Commit 86b7505

Browse files
feature: Steps (#4067)
Co-authored-by: Hugo Korte <[email protected]> Co-authored-by: Hugos68 <[email protected]>
1 parent 1d59e07 commit 86b7505

File tree

55 files changed

+1528
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1528
-0
lines changed

.changeset/upset-taxes-drop.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@skeletonlabs/skeleton-common": minor
3+
"@skeletonlabs/skeleton-svelte": minor
4+
"@skeletonlabs/skeleton-react": minor
5+
---
6+
7+
feat: Added `Steps` component.
8+

packages/skeleton-common/src/classes.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,36 @@ export const slider = defineClasses({
293293
marker: 'text-xs text-surface-600-400',
294294
});
295295

296+
export const steps = defineClasses({
297+
root: ['data-[orientation=horizontal]:space-y-4', 'data-[orientation=vertical]:flex data-[orientation=vertical]:space-x-4'],
298+
list: [
299+
'flex gap-2',
300+
'data-[orientation=horizontal]:items-center',
301+
'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-start',
302+
],
303+
item: [
304+
'flex gap-2 grow last:flex-initial',
305+
'data-[orientation=horizontal]:items-center',
306+
'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-start',
307+
],
308+
trigger: 'flex items-center gap-1',
309+
indicator: [
310+
'size-8 rounded-full content-center',
311+
'not-data-complete:not-data-current:preset-outlined-surface-200-800',
312+
'data-complete:preset-filled-primary-500',
313+
'data-current:preset-outlined-primary-500',
314+
],
315+
separator: [
316+
'h-0 border-surface-200-800 grow',
317+
'data-complete:border-primary-500',
318+
'data-[orientation=horizontal]:border-t',
319+
'data-[orientation=vertical]:border-s data-[orientation=vertical]:ms-4 data-[orientation=vertical]:min-h-4',
320+
],
321+
content: '',
322+
prevTrigger: '',
323+
nextTrigger: '',
324+
});
325+
296326
const switch_ = defineClasses({
297327
root: [
298328
'cursor-pointer data-disabled:cursor-not-allowed data-disabled:opacity-50 inline-flex gap-2 items-center rounded',

packages/skeleton-react/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@zag-js/rating-group": "catalog:",
4747
"@zag-js/react": "catalog:",
4848
"@zag-js/slider": "catalog:",
49+
"@zag-js/steps": "catalog:",
4950
"@zag-js/switch": "catalog:",
5051
"@zag-js/tabs": "catalog:",
5152
"@zag-js/tags-input": "catalog:",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { RootContext } from '../modules/root-context.js';
2+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
3+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
4+
import * as classes from '@skeletonlabs/skeleton-common/classes';
5+
import { mergeProps } from '@zag-js/react';
6+
import type { ItemProps } from '@zag-js/steps';
7+
import { use } from 'react';
8+
9+
export interface StepsContentProps extends ItemProps, PropsWithElement<'div'>, HTMLAttributes<'div'> {}
10+
11+
export default function Content(props: StepsContentProps) {
12+
const steps = use(RootContext);
13+
14+
// @zag-js/steps does not currently provide a splitItemProps function, so manually destructure
15+
const { element, children, index, ...rest } = props;
16+
17+
const attributes = mergeProps(
18+
steps.getContentProps({ index }),
19+
{
20+
className: classes.steps.content,
21+
},
22+
rest,
23+
);
24+
25+
return element ? element(attributes) : <div {...attributes}>{children}</div>;
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ItemContext } from '../modules/item-context.js';
2+
import { RootContext } from '../modules/root-context.js';
3+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
4+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
5+
import * as classes from '@skeletonlabs/skeleton-common/classes';
6+
import { mergeProps } from '@zag-js/react';
7+
import { use } from 'react';
8+
9+
export interface StepsIndicatorProps extends PropsWithElement<'div'>, HTMLAttributes<'div'> {}
10+
11+
export default function Indicator(props: StepsIndicatorProps) {
12+
const steps = use(RootContext);
13+
const itemProps = use(ItemContext);
14+
15+
const { element, children, ...rest } = props;
16+
17+
const attributes = mergeProps(
18+
steps.getIndicatorProps(itemProps),
19+
{
20+
className: classes.steps.indicator,
21+
},
22+
rest,
23+
);
24+
25+
return element ? element(attributes) : <div {...attributes}>{children}</div>;
26+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { ItemContext } from '../modules/item-context.js';
2+
import { RootContext } from '../modules/root-context.js';
3+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
4+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
5+
import * as classes from '@skeletonlabs/skeleton-common/classes';
6+
import { mergeProps } from '@zag-js/react';
7+
import type { ItemProps } from '@zag-js/steps';
8+
import { use } from 'react';
9+
10+
export interface StepsItemProps extends ItemProps, PropsWithElement<'div'>, HTMLAttributes<'div'> {}
11+
12+
export default function Item(props: StepsItemProps) {
13+
const steps = use(RootContext);
14+
15+
// @zag-js/steps does not currently provide a splitItemProps function, so manually destructure
16+
const { element, children, index, ...rest } = props;
17+
const itemProps = { index };
18+
19+
const attributes = mergeProps(
20+
steps.getItemProps(itemProps),
21+
{
22+
className: classes.steps.item,
23+
},
24+
rest,
25+
);
26+
27+
return (
28+
<ItemContext.Provider value={itemProps}>{element ? element(attributes) : <div {...attributes}>{children}</div>}</ItemContext.Provider>
29+
);
30+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { RootContext } from '../modules/root-context.js';
2+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
3+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
4+
import * as classes from '@skeletonlabs/skeleton-common/classes';
5+
import { mergeProps } from '@zag-js/react';
6+
import { use } from 'react';
7+
8+
export interface StepsListProps extends PropsWithElement<'div'>, HTMLAttributes<'div'> {}
9+
10+
export default function List(props: StepsListProps) {
11+
const steps = use(RootContext);
12+
13+
const { element, children, ...rest } = props;
14+
15+
const attributes = mergeProps(
16+
steps.getListProps(),
17+
{
18+
className: classes.steps.list,
19+
},
20+
rest,
21+
);
22+
23+
return element ? element(attributes) : <div {...attributes}>{children}</div>;
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { RootContext } from '../modules/root-context.js';
2+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
3+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
4+
import * as classes from '@skeletonlabs/skeleton-common/classes';
5+
import { mergeProps } from '@zag-js/react';
6+
import { use } from 'react';
7+
8+
export interface StepsNextTriggerProps extends PropsWithElement<'button'>, HTMLAttributes<'button', 'value' | 'disabled'> {}
9+
10+
export default function NextTrigger(props: StepsNextTriggerProps) {
11+
const steps = use(RootContext);
12+
13+
const { element, children, ...rest } = props;
14+
15+
const attributes = mergeProps(
16+
steps.getNextTriggerProps(),
17+
{
18+
className: classes.steps.nextTrigger,
19+
},
20+
rest,
21+
);
22+
23+
return element ? element(attributes) : <button {...attributes}>{children}</button>;
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { RootContext } from '../modules/root-context.js';
2+
import type { HTMLAttributes } from '../../../internal/html-attributes.js';
3+
import type { PropsWithElement } from '../../../internal/props-with-element.js';
4+
import * as classes from '@skeletonlabs/skeleton-common/classes';
5+
import { mergeProps } from '@zag-js/react';
6+
import { use } from 'react';
7+
8+
export interface StepsPrevTriggerProps extends PropsWithElement<'button'>, HTMLAttributes<'button', 'value' | 'disabled'> {}
9+
10+
export default function PrevTrigger(props: StepsPrevTriggerProps) {
11+
const steps = use(RootContext);
12+
13+
const { element, children, ...rest } = props;
14+
15+
const attributes = mergeProps(
16+
steps.getPrevTriggerProps(),
17+
{
18+
className: classes.steps.prevTrigger,
19+
},
20+
rest,
21+
);
22+
23+
return element ? element(attributes) : <button {...attributes}>{children}</button>;
24+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { useSteps } from '../modules/provider.js';
2+
import { RootContext as RootContext_ } from '../modules/root-context.js';
3+
import type { ReactNode } from 'react';
4+
import { use } from 'react';
5+
6+
export interface StepsRootContextProps {
7+
children: (steps: ReturnType<typeof useSteps>) => ReactNode;
8+
}
9+
10+
export default function RootContext(props: StepsRootContextProps) {
11+
const steps = use(RootContext_);
12+
13+
const { children } = props;
14+
15+
return children(steps);
16+
}

0 commit comments

Comments
 (0)