230 lines
6.9 KiB
JavaScript
230 lines
6.9 KiB
JavaScript
|
const pc = require('picocolors');
|
||
|
const plugin = require('tailwindcss/plugin');
|
||
|
|
||
|
const validate = require('./validate');
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* Setup tailwind-bootstrap-grid plugin
|
||
|
*
|
||
|
* @param {object} pluginOptions - plugin options
|
||
|
* @param {number} [pluginOptions.gridColumns=12] - number of columns
|
||
|
* @param {string} [pluginOptions.gridGutterWidth="1.5rem"] - spacing value
|
||
|
* @param {object} [pluginOptions.gridGutters={ 0: 0 }] - gutter spacing variable classes
|
||
|
* @param {boolean} [pluginOptions.generateContainer=true] - whether the plugin should generate .container class
|
||
|
* @param {object} [pluginOptions.containerMaxWidths={}] - the `max-width` container value for each breakpoint
|
||
|
* @param {boolean} [pluginOptions.rtl=false] - whether to enable rtl support
|
||
|
* @param {boolean} [pluginOptions.respectImportant=true] - whether to respect important config option
|
||
|
* @returns {*} - Tailwind CSS plugin
|
||
|
*/
|
||
|
module.exports = plugin.withOptions((pluginOptions) => (options) => {
|
||
|
const { addComponents, config, corePlugins } = options;
|
||
|
const screens = config('theme.screens');
|
||
|
const important = config('important');
|
||
|
|
||
|
const {
|
||
|
gridColumns,
|
||
|
gridGutterWidth,
|
||
|
gridGutters,
|
||
|
generateContainer,
|
||
|
containerMaxWidths,
|
||
|
rtl,
|
||
|
respectImportant,
|
||
|
} = validate({ screens })({
|
||
|
gridColumns: 12,
|
||
|
gridGutterWidth: '1.5rem',
|
||
|
gridGutters: { 0: 0 },
|
||
|
generateContainer: true,
|
||
|
containerMaxWidths: {},
|
||
|
rtl: false,
|
||
|
respectImportant: true,
|
||
|
...pluginOptions,
|
||
|
});
|
||
|
|
||
|
if (generateContainer && corePlugins('container')) {
|
||
|
console.warn(
|
||
|
`⚠️ The ${pc.yellow(
|
||
|
'container',
|
||
|
)} core plugin is enabled and you're also generating ${pc.green(
|
||
|
'.container',
|
||
|
)} class with the ${pc.bold(
|
||
|
'tailwind-bootstrap-grid',
|
||
|
)} plugin. This might lead to unexpected styling issues, disable either of one.`,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
const screenKeys = Object.keys(screens);
|
||
|
const columns = Array.from(Array(gridColumns), (value, index) => index + 1);
|
||
|
const rowColsSteps = columns.slice(0, Math.floor(gridColumns / 2));
|
||
|
|
||
|
const setImportant = (value) =>
|
||
|
respectImportant && important && value != null
|
||
|
? `${value} !important`
|
||
|
: value;
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Container
|
||
|
// =============================================================================================
|
||
|
if (generateContainer) {
|
||
|
addComponents(
|
||
|
[
|
||
|
{
|
||
|
'.container, .container-fluid': {
|
||
|
width: setImportant('100%'),
|
||
|
marginRight: setImportant('auto'),
|
||
|
marginLeft: setImportant('auto'),
|
||
|
paddingRight: setImportant(
|
||
|
`var(--bs-gutter-x, calc(${gridGutterWidth} / 2))`,
|
||
|
),
|
||
|
paddingLeft: setImportant(
|
||
|
`var(--bs-gutter-x, calc(${gridGutterWidth} / 2))`,
|
||
|
),
|
||
|
},
|
||
|
},
|
||
|
...screenKeys.map((name) => ({
|
||
|
[`@screen ${name}`]: {
|
||
|
'.container': {
|
||
|
maxWidth: setImportant(
|
||
|
containerMaxWidths[name] || screens[name],
|
||
|
),
|
||
|
},
|
||
|
},
|
||
|
})),
|
||
|
],
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Row
|
||
|
// =============================================================================================
|
||
|
addComponents(
|
||
|
{
|
||
|
'.row': {
|
||
|
'--bs-gutter-x': gridGutterWidth,
|
||
|
'--bs-gutter-y': 0,
|
||
|
display: 'flex',
|
||
|
flexWrap: 'wrap',
|
||
|
marginTop: 'calc(var(--bs-gutter-y) * -1)',
|
||
|
marginRight: 'calc(var(--bs-gutter-x) / -2)',
|
||
|
marginLeft: 'calc(var(--bs-gutter-x) / -2)',
|
||
|
'& > *': {
|
||
|
boxSizing: 'border-box',
|
||
|
flexShrink: 0,
|
||
|
width: '100%',
|
||
|
maxWidth: '100%',
|
||
|
paddingRight: 'calc(var(--bs-gutter-x) / 2)',
|
||
|
paddingLeft: 'calc(var(--bs-gutter-x) / 2)',
|
||
|
marginTop: 'var(--bs-gutter-y)',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Columns
|
||
|
// =============================================================================================
|
||
|
addComponents(
|
||
|
[
|
||
|
{
|
||
|
'.col': {
|
||
|
flex: '1 0 0%',
|
||
|
},
|
||
|
'.row-cols-auto': {
|
||
|
'& > *': {
|
||
|
flex: '0 0 auto',
|
||
|
width: 'auto',
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
...rowColsSteps.map((rowCol) => ({
|
||
|
[`.row-cols-${rowCol}`]: {
|
||
|
'& > *': {
|
||
|
flex: '0 0 auto',
|
||
|
width: `${100 / rowCol}%`,
|
||
|
},
|
||
|
},
|
||
|
})),
|
||
|
{
|
||
|
'.col-auto': {
|
||
|
flex: '0 0 auto',
|
||
|
width: 'auto',
|
||
|
},
|
||
|
},
|
||
|
...columns.map((size) => ({
|
||
|
[`.col-${size}`]: {
|
||
|
flex: '0 0 auto',
|
||
|
width: `${(100 / gridColumns) * size}%`,
|
||
|
},
|
||
|
})),
|
||
|
],
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Offsets
|
||
|
// =============================================================================================
|
||
|
addComponents(
|
||
|
[
|
||
|
...[0, ...columns.slice(0, -1)].map((size) => {
|
||
|
const margin = `${(100 / gridColumns) * size}%`;
|
||
|
return rtl
|
||
|
? {
|
||
|
[`[dir="ltr"] .offset-${size}`]: { marginLeft: margin },
|
||
|
[`[dir="rtl"] .offset-${size}`]: { marginRight: margin },
|
||
|
}
|
||
|
: {
|
||
|
[`.offset-${size}`]: { marginLeft: margin },
|
||
|
};
|
||
|
}),
|
||
|
],
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Gutters
|
||
|
// =============================================================================================
|
||
|
if (Object.keys(gridGutters).length) {
|
||
|
addComponents(
|
||
|
Object.entries(gridGutters).map(([key, value]) => ({
|
||
|
[`.g-${key}, .gx-${key}`]: {
|
||
|
'--bs-gutter-x': value,
|
||
|
},
|
||
|
[`.g-${key}, .gy-${key}`]: {
|
||
|
'--bs-gutter-y': value,
|
||
|
},
|
||
|
})),
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
// =============================================================================================
|
||
|
// Ordering
|
||
|
// =============================================================================================
|
||
|
addComponents(
|
||
|
[
|
||
|
{
|
||
|
'.order-first': { order: '-1' },
|
||
|
'.order-last': { order: gridColumns + 1 },
|
||
|
},
|
||
|
...[0, ...columns].map((size) => ({
|
||
|
[`.order-${size}`]: { order: `${size}` },
|
||
|
})),
|
||
|
],
|
||
|
{ respectImportant },
|
||
|
);
|
||
|
}
|
||
|
});
|