Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: #6870 Ensure steps can be programmatically styled #7101

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions components/lib/passthrough/tailwind/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2109,12 +2109,19 @@ const Tailwind = {
'focus:outline-none focus:outline-offset-0 focus:shadow-[0_0_0_0.2rem_rgba(191,219,254,1)] dark:focus:shadow-[0_0_0_0.2rem_rgba(147,197,253,0.5)]'
)
},
step: {
className: classNames('flex items-center justify-center', 'text-gray-700 dark:text-white/80 border border-gray-300 dark:border-blue-900/40 bg-white dark:bg-gray-900 w-[2rem] h-[2rem] leading-2rem text-sm z-10 rounded-full')
},
label: {
className: classNames('block', 'whitespace-nowrap overflow-hidden overflow-ellipsis max-w-full', 'mt-2 text-gray-500 dark:text-white/60')
}
step: ({ parent, context }) => ({
className: classNames('flex items-center justify-center', 'text-gray-700 dark:text-white/80 border border-gray-300 dark:border-blue-900/40 bg-white dark:bg-gray-900 w-[2rem] h-[2rem] leading-2rem text-sm z-10 rounded-full', {
'bg-white': parent.state.activeIndex !== context.index, // unselected item.
'bg-blue-500': parent.state.activeIndex === context.index // Selected item.
})
}),
label: ({ parent, context }) => ({
className: classNames('block', 'whitespace-nowrap overflow-hidden overflow-ellipsis max-w-full', 'mt-2 text-gray-500 dark:text-white/60', {
'font-normal': parent.state.activeIndex !== context.index, // unselected item.
'font-bold': parent.state.activeIndex === context.index, // Selected item.
'text-gray-500/60': context.disabled
})
})
},
tabmenu: {
root: 'overflow-x-auto',
Expand Down
44 changes: 36 additions & 8 deletions components/lib/steps/Steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,44 @@ export const Steps = React.memo(
const props = StepsBase.getProps(inProps, context);

const [idState, setIdState] = React.useState(props.id);
const [activeIndexState, setActiveIndexState] = React.useState(props.activeIndex);
const elementRef = React.useRef(null);
const listRef = React.useRef(null);
const count = React.Children.count(props.children);

const { ptm, cx, isUnstyled } = StepsBase.setMetaData({
const metaData = {
props,
state: {
id: idState
id: idState,
activeIndex: activeIndexState
}
};

const { ptm, ptmo, cx, isUnstyled } = StepsBase.setMetaData({
...metaData
});

useHandleStyle(StepsBase.css.styles, isUnstyled, { name: 'steps' });

const getStepPT = (step, key, index) => {
const stepMetaData = {
// props: step.props,
parent: metaData,
context: {
index,
count,
first: index === 0,
last: index === count - 1,
active: index === activeIndexState,
disabled: getStepProp(step, 'disabled')
}
};

return mergeProps(ptm(`step.${key}`, { step: stepMetaData }), ptm(`steps.${key}`, { steps: stepMetaData }), ptm(`steps.${key}`, stepMetaData), ptmo(getStepProp(step, 'pt'), key, stepMetaData));
};

const getStepProp = (step, name) => StepsBase.getCProp(step, name);

const itemClick = (event, item, index) => {
if (props.readOnly || item.disabled) {
event.preventDefault();
Expand All @@ -47,6 +73,8 @@ export const Steps = React.memo(
});
}

setActiveIndexState(index);

if (!item.url) {
event.preventDefault();
event.stopPropagation();
Expand Down Expand Up @@ -163,15 +191,15 @@ export const Steps = React.memo(
}

const key = item.id || idState + '_' + index;
const active = index === props.activeIndex;
const disabled = item.disabled || (index !== props.activeIndex && props.readOnly);
const active = index === activeIndexState;
const disabled = item.disabled || (index !== activeIndexState && props.readOnly);

const iconClassName = classNames('p-menuitem-icon', item.icon);
const iconProps = mergeProps(
{
className: cx('icon', { item })
},
ptm('icon')
getStepPT(item, 'icon', index)
);

const icon = IconUtils.getJSXIcon(item.icon, { ...iconProps }, { props });
Expand All @@ -180,7 +208,7 @@ export const Steps = React.memo(
{
className: cx('label')
},
ptm('label')
getStepPT(item, 'label', index)
);

const label = item.label && <span {...labelProps}>{item.label}</span>;
Expand All @@ -189,7 +217,7 @@ export const Steps = React.memo(
{
className: cx('step')
},
ptm('step')
getStepPT(item, 'step', index)
);

const actionProps = mergeProps(
Expand All @@ -202,7 +230,7 @@ export const Steps = React.memo(
onKeyDown: (event) => onItemKeyDown(event, item, index),
onClick: (event) => itemClick(event, item, index)
},
ptm('action')
getStepPT(item, 'action', index)
);

let content = (
Expand Down
5 changes: 3 additions & 2 deletions components/lib/steps/StepsBase.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ComponentBase } from '../componentbase/ComponentBase';
import { classNames } from '../utils/Utils';
import { classNames, ObjectUtils } from '../utils/Utils';

const classes = {
icon: ({ item }) => classNames('p-menuitem-icon', item.icon),
Expand Down Expand Up @@ -84,5 +84,6 @@ export const StepsBase = ComponentBase.extend({
css: {
classes,
styles
}
},
getCProp: (step, name) => ObjectUtils.getComponentProp(step, name, StepsBase.defaultProps)
});
52 changes: 48 additions & 4 deletions components/lib/steps/steps.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,50 @@ import { PassThroughOptions } from '../passthrough';
import { PassThroughType } from '../utils/utils';

export declare type StepsPassThroughType<T> = PassThroughType<T, StepsThroughMethodOptions>;
export declare type StepPassThroughType<T> = PassThroughType<T, StepPassThroughMethodOptions>;

/**
* Custom passthrough(pt) option method.
*/
export interface StepPassThroughMethodOptions {
// props: StepsProps;
parent: StepsThroughMethodOptions;
context: StepContext;
}

/**
* Defines current inline context in Steps component.
*/
export interface StepContext {
/**
* Step index.
*/
index: number;
/**
* Total number of steps
*/
count: number;
/**
* Is this the first step?
* @defaultValue false
*/
first: boolean;
/**
* Is this the last step?
* @defaultValue false
*/
last: boolean;
/**
* Is this step currently selected.
* @defaultValue false
*/
selected: boolean;
/**
* Is this step currently disabled.
* @defaultValue false
*/
disabled: boolean;
}

/**
* Custom passthrough(pt) option method.
Expand Down Expand Up @@ -42,19 +86,19 @@ export interface StepsPassThroughOptions {
/**
* Uses to pass attributes to the action's DOM element.
*/
action?: StepsPassThroughType<React.HTMLAttributes<HTMLAnchorElement>>;
action?: StepPassThroughType<React.HTMLAttributes<HTMLAnchorElement>>;
/**
* Uses to pass attributes to the step's DOM element.
*/
step?: StepsPassThroughType<React.HTMLAttributes<HTMLSpanElement>>;
step?: StepPassThroughType<React.HTMLAttributes<HTMLSpanElement>>;
/**
* Uses to pass attributes to the label's DOM element.
*/
label?: StepsPassThroughType<React.HTMLAttributes<HTMLSpanElement>>;
label?: StepPassThroughType<React.HTMLAttributes<HTMLSpanElement>>;
/**
* Uses to pass attributes to the icon's DOM element.
*/
icon?: StepsPassThroughType<React.SVGProps<SVGSVGElement> | React.HTMLAttributes<HTMLSpanElement>>;
icon?: StepPassThroughType<React.SVGProps<SVGSVGElement> | React.HTMLAttributes<HTMLSpanElement>>;
/**
* Used to manage all lifecycle hooks
* @see {@link ComponentHooks}
Expand Down
Loading