responsive-system 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +195 -0
- package/INSTALLATION.md +403 -0
- package/README.md +382 -0
- package/dist/components/LayoutSwitcher.d.ts +6 -0
- package/dist/components/layout/Footer.d.ts +3 -0
- package/dist/components/layout/Header.d.ts +3 -0
- package/dist/components/layout/Navigation.d.ts +3 -0
- package/dist/components/layout/Sidebar.d.ts +3 -0
- package/dist/components/layout/index.d.ts +5 -0
- package/dist/config/layout.d.ts +15 -0
- package/dist/constants/breakpoints.d.ts +19 -0
- package/dist/context/NavigationContext.d.ts +13 -0
- package/dist/context/ResponsiveLayoutContext.d.ts +22 -0
- package/dist/context/SidebarContext.d.ts +11 -0
- package/dist/context/index.d.ts +4 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/useLayout.d.ts +27 -0
- package/dist/hooks/useResponsive.d.ts +7 -0
- package/dist/hooks/useResponsiveLayout.d.ts +64 -0
- package/dist/index.d.ts +11 -0
- package/dist/layouts/DashboardLayout.d.ts +7 -0
- package/dist/layouts/DefaultLayout.d.ts +7 -0
- package/dist/layouts/MainLayout.d.ts +12 -0
- package/dist/layouts/MinimalLayout.d.ts +7 -0
- package/dist/layouts/SidebarLayout.d.ts +7 -0
- package/dist/layouts/index.d.ts +6 -0
- package/dist/providers/ResponsiveLayoutProvider.d.ts +15 -0
- package/dist/providers/ResponsiveProvider.d.ts +11 -0
- package/dist/providers/index.d.ts +3 -0
- package/dist/responsive-system.cjs +9 -0
- package/dist/responsive-system.cjs.map +1 -0
- package/dist/responsive-system.mjs +580 -0
- package/dist/responsive-system.mjs.map +1 -0
- package/dist/types/responsive.d.ts +43 -0
- package/package.json +97 -0
- package/scripts/copy-types.js +46 -0
- package/scripts/generate-types.js +163 -0
- package/scripts/postinstall.js +76 -0
- package/src/plugin/responsiveScalePlugin.d.ts +57 -0
- package/src/plugin/responsiveScalePlugin.js +296 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Scale Plugin for Tailwind CSS
|
|
3
|
+
* Auto-scales typography, spacing, line-height, letter-spacing, and shadows across all breakpoints
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const plugin = require('tailwindcss/plugin')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Default configuration
|
|
10
|
+
*/
|
|
11
|
+
const defaultConfig = {
|
|
12
|
+
// Properties to auto-scale
|
|
13
|
+
scaleProperties: {
|
|
14
|
+
typography: true, // font-size
|
|
15
|
+
spacing: true, // padding, margin, gap, space
|
|
16
|
+
lineHeight: true, // line-height (NEW)
|
|
17
|
+
letterSpacing: true, // letter-spacing (NEW)
|
|
18
|
+
shadows: true, // box-shadow (NEW)
|
|
19
|
+
borderWidth: false, // border-width (experimental)
|
|
20
|
+
sizing: false, // width, height (can break layouts)
|
|
21
|
+
borderRadius: false // rounded-* (usually should stay fixed)
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Scale factors per breakpoint
|
|
25
|
+
scales: {
|
|
26
|
+
xs: 1.0, // 0px - mobile
|
|
27
|
+
sm: 1.0, // 640px
|
|
28
|
+
md: 1.0, // 768px
|
|
29
|
+
lg: 1.0, // 1024px
|
|
30
|
+
xl: 1.0, // 1280px
|
|
31
|
+
'2xl': 1.05, // 1536px - +5%
|
|
32
|
+
'3xl': 1.15, // 1920px - +15%
|
|
33
|
+
'4xl': 1.25, // 2560px - +25%
|
|
34
|
+
'5xl': 1.35 // 3840px - +35%
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Breakpoint values (must match tailwind.config.js)
|
|
38
|
+
breakpoints: {
|
|
39
|
+
xs: '0px',
|
|
40
|
+
sm: '640px',
|
|
41
|
+
md: '768px',
|
|
42
|
+
lg: '1024px',
|
|
43
|
+
xl: '1280px',
|
|
44
|
+
'2xl': '1536px',
|
|
45
|
+
'3xl': '1920px',
|
|
46
|
+
'4xl': '2560px',
|
|
47
|
+
'5xl': '3840px'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates the responsive scale plugin
|
|
53
|
+
*/
|
|
54
|
+
function createResponsiveScalePlugin(userConfig = {}) {
|
|
55
|
+
const config = {
|
|
56
|
+
...defaultConfig,
|
|
57
|
+
...userConfig,
|
|
58
|
+
scaleProperties: {
|
|
59
|
+
...defaultConfig.scaleProperties,
|
|
60
|
+
...(userConfig.scaleProperties || {})
|
|
61
|
+
},
|
|
62
|
+
scales: {
|
|
63
|
+
...defaultConfig.scales,
|
|
64
|
+
...(userConfig.scales || {})
|
|
65
|
+
},
|
|
66
|
+
breakpoints: {
|
|
67
|
+
...defaultConfig.breakpoints,
|
|
68
|
+
...(userConfig.breakpoints || {})
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return plugin(function({ addBase, theme }) {
|
|
73
|
+
const breakpoints = config.breakpoints
|
|
74
|
+
const scales = config.scales
|
|
75
|
+
const { typography, spacing, lineHeight, letterSpacing, shadows, borderWidth } = config.scaleProperties
|
|
76
|
+
|
|
77
|
+
// Generate scaling CSS for each breakpoint
|
|
78
|
+
const scalingStyles = {}
|
|
79
|
+
|
|
80
|
+
Object.entries(breakpoints).forEach(([breakpointName, breakpointValue]) => {
|
|
81
|
+
const scale = scales[breakpointName] || 1.0
|
|
82
|
+
|
|
83
|
+
// Skip if no scaling needed
|
|
84
|
+
if (scale === 1.0) return
|
|
85
|
+
|
|
86
|
+
const mediaQuery = breakpointValue === '0px'
|
|
87
|
+
? '@media (min-width: 0px)'
|
|
88
|
+
: `@media (min-width: ${breakpointValue})`
|
|
89
|
+
|
|
90
|
+
if (!scalingStyles[mediaQuery]) {
|
|
91
|
+
scalingStyles[mediaQuery] = {}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Initialize :root for this breakpoint
|
|
95
|
+
if (!scalingStyles[mediaQuery][':root']) {
|
|
96
|
+
scalingStyles[mediaQuery][':root'] = {}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Scale typography
|
|
100
|
+
if (typography) {
|
|
101
|
+
scalingStyles[mediaQuery][':root']['--scale-text'] = scale.toString()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Scale spacing
|
|
105
|
+
if (spacing) {
|
|
106
|
+
scalingStyles[mediaQuery][':root']['--scale-spacing'] = scale.toString()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Scale line-height
|
|
110
|
+
if (lineHeight) {
|
|
111
|
+
scalingStyles[mediaQuery][':root']['--scale-line-height'] = scale.toString()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Scale letter-spacing
|
|
115
|
+
if (letterSpacing) {
|
|
116
|
+
scalingStyles[mediaQuery][':root']['--scale-letter-spacing'] = scale.toString()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Scale shadows
|
|
120
|
+
if (shadows) {
|
|
121
|
+
scalingStyles[mediaQuery][':root']['--scale-shadow'] = scale.toString()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Scale border-width
|
|
125
|
+
if (borderWidth) {
|
|
126
|
+
scalingStyles[mediaQuery][':root']['--scale-border'] = scale.toString()
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
// Apply base styles with CSS variables
|
|
131
|
+
addBase({
|
|
132
|
+
':root': {
|
|
133
|
+
'--scale-text': '1',
|
|
134
|
+
'--scale-spacing': '1',
|
|
135
|
+
'--scale-line-height': '1',
|
|
136
|
+
'--scale-letter-spacing': '1',
|
|
137
|
+
'--scale-shadow': '1',
|
|
138
|
+
'--scale-border': '1'
|
|
139
|
+
},
|
|
140
|
+
...scalingStyles
|
|
141
|
+
})
|
|
142
|
+
}, {
|
|
143
|
+
theme: {
|
|
144
|
+
extend: {
|
|
145
|
+
// Auto-grid classes for automatic column calculation
|
|
146
|
+
gridTemplateColumns: {
|
|
147
|
+
'auto-xs': 'repeat(auto-fit, minmax(150px, 1fr))', // Cards muy pequeñas
|
|
148
|
+
'auto-sm': 'repeat(auto-fit, minmax(200px, 1fr))', // Cards pequeñas
|
|
149
|
+
'auto-md': 'repeat(auto-fit, minmax(280px, 1fr))', // Cards medianas (default)
|
|
150
|
+
'auto-lg': 'repeat(auto-fit, minmax(400px, 1fr))', // Cards grandes
|
|
151
|
+
'auto-xl': 'repeat(auto-fit, minmax(500px, 1fr))', // Cards muy grandes
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
// Extend Tailwind's spacing scale to use CSS variables
|
|
155
|
+
spacing: ({ theme }) => {
|
|
156
|
+
const baseSpacing = theme('spacing')
|
|
157
|
+
const scaledSpacing = {}
|
|
158
|
+
|
|
159
|
+
Object.entries(baseSpacing).forEach(([key, value]) => {
|
|
160
|
+
// Only scale numeric values, skip 'auto', 'px', etc.
|
|
161
|
+
if (typeof value === 'string' && value.match(/^[\d.]+rem$/)) {
|
|
162
|
+
const numValue = parseFloat(value)
|
|
163
|
+
scaledSpacing[key] = `calc(${numValue}rem * var(--scale-spacing))`
|
|
164
|
+
} else {
|
|
165
|
+
scaledSpacing[key] = value
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
return scaledSpacing
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
// Extend Tailwind's fontSize scale to use CSS variables
|
|
173
|
+
fontSize: ({ theme }) => {
|
|
174
|
+
const baseFontSize = theme('fontSize')
|
|
175
|
+
const scaledFontSize = {}
|
|
176
|
+
|
|
177
|
+
Object.entries(baseFontSize).forEach(([key, value]) => {
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
// fontSize with lineHeight: ['16px', { lineHeight: '24px' }]
|
|
180
|
+
const [size, config] = value
|
|
181
|
+
if (typeof size === 'string' && size.match(/^[\d.]+rem$/)) {
|
|
182
|
+
const numValue = parseFloat(size)
|
|
183
|
+
const scaledSize = `calc(${numValue}rem * var(--scale-text))`
|
|
184
|
+
|
|
185
|
+
// Scale line-height if present
|
|
186
|
+
if (config && config.lineHeight && typeof config.lineHeight === 'string' && config.lineHeight.match(/^[\d.]+rem$/)) {
|
|
187
|
+
const lhValue = parseFloat(config.lineHeight)
|
|
188
|
+
scaledFontSize[key] = [
|
|
189
|
+
scaledSize,
|
|
190
|
+
{
|
|
191
|
+
...config,
|
|
192
|
+
lineHeight: `calc(${lhValue}rem * var(--scale-line-height))`
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
} else {
|
|
196
|
+
scaledFontSize[key] = [scaledSize, config]
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
scaledFontSize[key] = value
|
|
200
|
+
}
|
|
201
|
+
} else if (typeof value === 'string' && value.match(/^[\d.]+rem$/)) {
|
|
202
|
+
// Simple fontSize: '16px'
|
|
203
|
+
const numValue = parseFloat(value)
|
|
204
|
+
scaledFontSize[key] = `calc(${numValue}rem * var(--scale-text))`
|
|
205
|
+
} else {
|
|
206
|
+
scaledFontSize[key] = value
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
return scaledFontSize
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// Extend line-height to use CSS variables
|
|
214
|
+
lineHeight: ({ theme }) => {
|
|
215
|
+
const baseLineHeight = theme('lineHeight')
|
|
216
|
+
const scaledLineHeight = {}
|
|
217
|
+
|
|
218
|
+
Object.entries(baseLineHeight).forEach(([key, value]) => {
|
|
219
|
+
if (typeof value === 'string' && value.match(/^[\d.]+rem$/)) {
|
|
220
|
+
const numValue = parseFloat(value)
|
|
221
|
+
scaledLineHeight[key] = `calc(${numValue}rem * var(--scale-line-height))`
|
|
222
|
+
} else if (typeof value === 'string' && !isNaN(parseFloat(value)) && !value.includes('rem') && !value.includes('px')) {
|
|
223
|
+
// Unitless values (like '1.5') - scale them
|
|
224
|
+
const numValue = parseFloat(value)
|
|
225
|
+
scaledLineHeight[key] = `calc(${numValue} * var(--scale-line-height))`
|
|
226
|
+
} else {
|
|
227
|
+
scaledLineHeight[key] = value
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
return scaledLineHeight
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
// Extend letter-spacing to use CSS variables
|
|
235
|
+
letterSpacing: ({ theme }) => {
|
|
236
|
+
const baseLetterSpacing = theme('letterSpacing')
|
|
237
|
+
const scaledLetterSpacing = {}
|
|
238
|
+
|
|
239
|
+
Object.entries(baseLetterSpacing).forEach(([key, value]) => {
|
|
240
|
+
if (typeof value === 'string' && (value.match(/^[\d.]+rem$/) || value.match(/^-?[\d.]+em$/))) {
|
|
241
|
+
const numValue = parseFloat(value)
|
|
242
|
+
const unit = value.includes('rem') ? 'rem' : 'em'
|
|
243
|
+
scaledLetterSpacing[key] = `calc(${numValue}${unit} * var(--scale-letter-spacing))`
|
|
244
|
+
} else {
|
|
245
|
+
scaledLetterSpacing[key] = value
|
|
246
|
+
}
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
return scaledLetterSpacing
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// Extend box-shadow to use CSS variables
|
|
253
|
+
boxShadow: ({ theme }) => {
|
|
254
|
+
const baseBoxShadow = theme('boxShadow')
|
|
255
|
+
const scaledBoxShadow = {}
|
|
256
|
+
|
|
257
|
+
Object.entries(baseBoxShadow).forEach(([key, value]) => {
|
|
258
|
+
if (typeof value === 'string' && value !== 'none') {
|
|
259
|
+
// Scale shadow blur and spread
|
|
260
|
+
// Shadow format: "0 4px 6px -1px rgb(0 0 0 / 0.1)"
|
|
261
|
+
const scaledValue = value.replace(
|
|
262
|
+
/([\d.]+)px/g,
|
|
263
|
+
(match, num) => `calc(${num}px * var(--scale-shadow))`
|
|
264
|
+
)
|
|
265
|
+
scaledBoxShadow[key] = scaledValue
|
|
266
|
+
} else {
|
|
267
|
+
scaledBoxShadow[key] = value
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
return scaledBoxShadow
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// Extend border-width to use CSS variables (if enabled)
|
|
275
|
+
borderWidth: ({ theme }) => {
|
|
276
|
+
const baseBorderWidth = theme('borderWidth')
|
|
277
|
+
const scaledBorderWidth = {}
|
|
278
|
+
|
|
279
|
+
Object.entries(baseBorderWidth).forEach(([key, value]) => {
|
|
280
|
+
if (typeof value === 'string' && value.match(/^[\d.]+px$/)) {
|
|
281
|
+
const numValue = parseFloat(value)
|
|
282
|
+
scaledBorderWidth[key] = `calc(${numValue}px * var(--scale-border))`
|
|
283
|
+
} else {
|
|
284
|
+
scaledBorderWidth[key] = value
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
return scaledBorderWidth
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
})
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
module.exports = createResponsiveScalePlugin
|
|
296
|
+
module.exports.defaultConfig = defaultConfig
|