Skip to content

Commit

Permalink
Added tailwind-merge support
Browse files Browse the repository at this point in the history
  • Loading branch information
bweis committed Nov 1, 2023
1 parent 24faf4f commit b3c581d
Show file tree
Hide file tree
Showing 156 changed files with 8,470 additions and 5,694 deletions.
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

0 comments on commit b3c581d

Please sign in to comment.