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

Added tailwind-merge support #5209

Closed
wants to merge 1 commit into from
Closed
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: 18 additions & 1 deletion components/doc/common/apidoc/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,13 @@
"type": "boolean",
"description": "When enabled, it removes all of components styles in the core."
},
{
"name": "useTailwind",
"optional": true,
"readonly": false,
"type": "boolean",
"description": "When enabled, all className merges will use twMerge"
},
{
"name": "setAppendTo",
"optional": true,
Expand Down Expand Up @@ -38490,6 +38497,12 @@
"optional": true,
"readonly": false,
"type": "boolean"
},
{
"name": "useTailwind",
"optional": true,
"readonly": false,
"type": "boolean"
}
],
"callbacks": []
Expand Down Expand Up @@ -52786,8 +52799,12 @@
"name": "mergeProps",
"parameters": [
{
"name": "args",
"name": "props",
"type": "object[]"
},
{
"name": "options",
"type": "object"
}
],
"returnType": "object | undefined"
Expand Down
17 changes: 12 additions & 5 deletions components/doc/passthrough/usepassthroughdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export default function UsePassThroughDemo() {
},
{
mergeSections: true,
mergeProps: false
mergeProps: false,
useTailwind: false
}
);

Expand All @@ -43,7 +44,7 @@ const CustomTailwind = usePassThrough(
header: 'my_panel_header'
}
},
{ mergeSections: true, mergeProps: false }
{ mergeSections: true, mergeProps: false, useTailwind: false }
);

// Output:
Expand All @@ -59,7 +60,7 @@ const CustomTailwind = usePassThrough(
header: 'my_panel_header'
}
},
{ mergeSections: true, mergeProps: true }
{ mergeSections: true, mergeProps: true, useTailwind: false }
);

// Output:
Expand All @@ -76,7 +77,7 @@ const CustomTailwind = usePassThrough(
header: 'my_panel_header'
}
},
{ mergeSections: false, mergeProps: true }
{ mergeSections: false, mergeProps: true, useTailwind: false }
);

// Output:
Expand All @@ -93,7 +94,7 @@ const CustomTailwind = usePassThrough(
header: 'my_panel_header'
}
},
{ mergeSections: false, mergeProps: false }
{ mergeSections: false, mergeProps: false, useTailwind: false }
);

// Output:
Expand All @@ -114,6 +115,12 @@ const CustomTailwind = usePassThrough(
The <i>mergeSections</i> defines whether the sections from the main configuration gets added and the <i>mergeProps</i> controls whether to override or merge the defined props. Defaults are <i>true</i> for <i>mergeSections</i> and
<i>false</i> for <i>mergeProps</i>.
</p>
<p>
The <i>useTailwind</i> option should be set to <i>true</i> if using Tailwind to prevent className conflicts between the default Tailwind theme and your custom theme. If <i>useTailwind</i> is set to <i>true</i> <i>mergeProps</i>{' '}
will be overridden to <i>true</i>.
<br />
See <a href="https://www.npmjs.com/package/tailwind-merge">tailwind-merge</a> for more information.
</p>
</DocSectionText>
<DocSectionCode code={code2} hideToggleCode import hideCodeSandbox hideStackBlitz />
<DocSectionCode code={code3} hideToggleCode import hideCodeSandbox hideStackBlitz />
Expand Down
24 changes: 23 additions & 1 deletion components/doc/tailwind/unstyledmode/setupdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ return(
basic: `
import { PrimeReactProvider } from "primereact/api";

...
return(
<PrimeReactProvider value={{ unstyled: true, pt: {}, useTailwind: true }}>
<App />
</PrimeReactProvider>
)

`
};

const code4 = {
basic: `
import { PrimeReactProvider } from "primereact/api";

export default function MyApp({ Component, pageProps }) {

//My Design System with Tailwind
Expand Down Expand Up @@ -124,12 +138,20 @@ export default function MyApp({ Component, pageProps }) {
<DocSectionCode code={code2} hideToggleCode import hideCodeSandbox hideStackBlitz />
<p className="flex align-items-start gap-2">
<Badge value="3"></Badge>
<span>
<b>Optional:</b> enable <i>useTailwind</i> to resolve className conflicts via <a href="https://www.npmjs.com/package/tailwind-merge">tailwind-merge</a>. This will prevent classNames specified in the global pass through from
overriding those specified via pass through in your application.
</span>
</p>
<DocSectionCode code={code3} hideToggleCode import hideCodeSandbox hideStackBlitz />
<p className="flex align-items-start gap-2">
<Badge value="4"></Badge>
<span>
At the final step, component styles are provided via a pass through configuration that utilizes Tailwind CSS. The default preset of each component is available at the Tailwind part under theming section of each component so
you'll able to copy paste instead of starting from scratch. Example below styles, inputtext and panel components;
</span>
</p>
<DocSectionCode code={code3} hideToggleCode import hideCodeSandbox hideStackBlitz />
<DocSectionCode code={code4} hideToggleCode import hideCodeSandbox hideStackBlitz />
<p>Voilà 💙, you now have 90+ awesome React UI components styled with Tailwind that will work in harmony with the rest of your application. Time to customize it to bring in your own style with Tailwind.</p>
</DocSectionText>
</>
Expand Down
149 changes: 88 additions & 61 deletions components/lib/accordion/Accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const Accordion = React.forwardRef((inProps, ref) => {
}
};

return mergeProps(ptm(`accordiontab.${key}`, { accordiontab: tabMetaData }), ptm(`accordiontab.${key}`, tabMetaData), ptmo(tab.props, key, tabMetaData));
return mergeProps([ptm(`accordiontab.${key}`, { accordiontab: tabMetaData }), ptm(`accordiontab.${key}`, tabMetaData), ptmo(tab.props, key, tabMetaData)], { useTailwind: context.useTailwind });
};

const getTabProp = (tab, name) => AccordionTabBase.getCProp(tab, name);
Expand Down Expand Up @@ -108,44 +108,56 @@ export const Accordion = React.forwardRef((inProps, ref) => {
const ariaControls = idState + '_content_' + index;
const tabIndex = getTabProp(tab, 'disabled') ? -1 : getTabProp(tab, 'tabIndex');
const headerTitleProps = mergeProps(
{
className: cx('tab.headertitle')
},
getTabPT(tab, 'headertitle', index)
[
{
className: cx('tab.headertitle')
},
getTabPT(tab, 'headertitle', index)
],
{ useTailwind: context.useTailwind }
);
const header = getTabProp(tab, 'headerTemplate') ? ObjectUtils.getJSXElement(getTabProp(tab, 'headerTemplate'), AccordionTabBase.getCProps(tab)) : <span {...headerTitleProps}>{getTabProp(tab, 'header')}</span>;
const headerIconProps = mergeProps(
{
className: cx('tab.headericon')
},
getTabPT(tab, 'headericon', index)
[
{
className: cx('tab.headericon')
},
getTabPT(tab, 'headericon', index)
],
{ useTailwind: context.useTailwind }
);
const icon = selected ? props.collapseIcon || <ChevronDownIcon {...headerIconProps} /> : props.expandIcon || <ChevronRightIcon {...headerIconProps} />;
const toggleIcon = IconUtils.getJSXIcon(icon, { ...headerIconProps }, { props, selected });
const label = selected ? ariaLabel('collapseLabel') : ariaLabel('expandLabel');
const headerProps = mergeProps(
{
className: classNames(getTabProp(tab, 'headerClassName'), getTabProp(tab, 'className'), cx('tab.header', { selected, getTabProp, tab })),
style,
'data-p-highlight': selected,
'data-p-disabled': getTabProp(tab, 'disabled')
},
getTabPT(tab, 'header', index)
[
{
className: classNames(getTabProp(tab, 'headerClassName'), getTabProp(tab, 'className'), cx('tab.header', { selected, getTabProp, tab })),
style,
'data-p-highlight': selected,
'data-p-disabled': getTabProp(tab, 'disabled')
},
getTabPT(tab, 'header', index)
],
{ useTailwind: context.useTailwind }
);

const headerActionProps = mergeProps(
{
id: headerId,
href: '#' + ariaControls,
className: cx('tab.headeraction'),
role: 'tab',
tabIndex,
onClick: (e) => onTabHeaderClick(e, tab, index),
'aria-label': label,
'aria-controls': ariaControls,
'aria-expanded': selected
},
getTabPT(tab, 'headeraction', index)
[
{
id: headerId,
href: '#' + ariaControls,
className: cx('tab.headeraction'),
role: 'tab',
tabIndex,
onClick: (e) => onTabHeaderClick(e, tab, index),
'aria-label': label,
'aria-controls': ariaControls,
'aria-expanded': selected
},
getTabPT(tab, 'headeraction', index)
],
{ useTailwind: context.useTailwind }
);

return (
Expand All @@ -164,33 +176,42 @@ export const Accordion = React.forwardRef((inProps, ref) => {
const ariaLabelledby = idState + '_header_' + index;
const contentRef = React.createRef();
const toggleableContentProps = mergeProps(
{
id: contentId,
ref: contentRef,
className: classNames(getTabProp(tab, 'contentClassName'), getTabProp(tab, 'className'), cx('tab.toggleablecontent')),
style,
role: 'region',
'aria-labelledby': ariaLabelledby
},
getTabPT(tab, 'toggleablecontent', index)
[
{
id: contentId,
ref: contentRef,
className: classNames(getTabProp(tab, 'contentClassName'), getTabProp(tab, 'className'), cx('tab.toggleablecontent')),
style,
role: 'region',
'aria-labelledby': ariaLabelledby
},
getTabPT(tab, 'toggleablecontent', index)
],
{ useTailwind: context.useTailwind }
);

const contentProps = mergeProps(
{
className: cx('tab.content')
},
getTabPT(tab, 'content', index)
[
{
className: cx('tab.content')
},
getTabPT(tab, 'content', index)
],
{ useTailwind: context.useTailwind }
);

const transitionProps = mergeProps(
{
classNames: cx('tab.transition'),
timeout: { enter: 1000, exit: 450 },
in: selected,
unmountOnExit: true,
options: props.transitionOptions
},
getTabPT(tab, 'transition', index)
[
{
classNames: cx('tab.transition'),
timeout: { enter: 1000, exit: 450 },
in: selected,
unmountOnExit: true,
options: props.transitionOptions
},
getTabPT(tab, 'transition', index)
],
{ useTailwind: context.useTailwind }
);

return (
Expand All @@ -210,12 +231,15 @@ export const Accordion = React.forwardRef((inProps, ref) => {
const tabContent = createTabContent(tab, selected, index);

const rootProps = mergeProps(
{
key,
className: cx('tab.root', { selected })
},
AccordionTabBase.getCOtherProps(tab),
getTabPT(tab, 'root', index)
[
{
key,
className: cx('tab.root', { selected })
},
AccordionTabBase.getCOtherProps(tab),
getTabPT(tab, 'root', index)
],
{ useTailwind: context.useTailwind }
);

return (
Expand All @@ -235,12 +259,15 @@ export const Accordion = React.forwardRef((inProps, ref) => {

const tabs = createTabs();
const rootProps = mergeProps(
{
className: classNames(props.className, cx('root')),
style: props.style
},
AccordionBase.getOtherProps(props),
ptm('root')
[
{
className: classNames(props.className, cx('root')),
style: props.style
},
AccordionBase.getOtherProps(props),
ptm('root')
],
{ useTailwind: context.useTailwind }
);

return (
Expand Down
5 changes: 4 additions & 1 deletion components/lib/api/PrimeReactContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const PrimeReactProvider = (props) => {
);
const [pt, setPt] = useState(propsValue.pt || undefined);
const [unstyled, setUnstyled] = useState(propsValue.unstyled || false);
const [useTailwind, setUseTailwind] = useState(propsValue.useTailwind || false);
const [filterMatchModeOptions, setFilterMatchModeOptions] = useState(
propsValue.filterMatchModeOptions || {
text: [FilterMatchMode.STARTS_WITH, FilterMatchMode.CONTAINS, FilterMatchMode.NOT_CONTAINS, FilterMatchMode.ENDS_WITH, FilterMatchMode.EQUALS, FilterMatchMode.NOT_EQUALS],
Expand Down Expand Up @@ -87,7 +88,9 @@ export const PrimeReactProvider = (props) => {
filterMatchModeOptions,
setFilterMatchModeOptions,
unstyled,
setUnstyled
setUnstyled,
useTailwind,
setUseTailwind
};

return <PrimeReactContext.Provider value={value}>{props.children}</PrimeReactContext.Provider>;
Expand Down
5 changes: 5 additions & 0 deletions components/lib/api/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ export interface APIOptions {
* @defaultValue false
*/
unstyled?: boolean;
/**
* When enabled, all className merges will use twMerge
* @defaultValue false
*/
useTailwind?: boolean;
/**
* This method is used to change the theme dynamically.
* @param {string} theme - The name of the theme to be applied.
Expand Down
Loading
Loading