postcss-enumerates-in-line 0.3.2 → 0.4.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/index.mjs CHANGED
@@ -16,8 +16,10 @@ import postcss from 'postcss'
16
16
  const pluginName = 'PostCSS Enumerates in Line'
17
17
 
18
18
  const defaultOptions = {
19
- prependDefaultColor: true,
19
+ prependDefaultColor: false,
20
20
  prependDefaultStyle: true,
21
+ appendUserColor: [],
22
+ appendShorthand: [],
21
23
  }
22
24
 
23
25
  let defaultStyle = [
@@ -49,8 +51,8 @@ let defaultStyle = [
49
51
  ]
50
52
  defaultStyle.reverse()
51
53
 
52
- const defaultColorNames = ['black', 'white', 'base', 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'magenta']
53
- const defaultColorDefines = {
54
+ let defaultColorNames = ['black', 'white', 'base', 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'magenta']
55
+ let defaultColorDefines = {
54
56
  rgb: {
55
57
  black: [[0, '#100F0F'], [999, '#000000']],
56
58
  white: [[0, '#FFFCF0'], [999, '#FFFFFF']],
@@ -92,18 +94,38 @@ const defaultColorDefines = {
92
94
  },
93
95
  }
94
96
 
97
+ let defaultShorthands = [
98
+ 'm', 'm8', 'm6', 'm2', 'm4', 'mx', 'my',
99
+ 'p', 'p8', 'p6', 'p2', 'p4', 'px', 'py',
100
+ 'o', 'o8', 'o6', 'o2', 'o4', 'ox', 'oy',
101
+ 'bw', 'bw8', 'bw6', 'bw2', 'bw4', 'bwx', 'bwy',
102
+ 'bs', 'bs8', 'bs6', 'bs2', 'bs4', 'bsx', 'bsy',
103
+ 'bc', 'bc8', 'bc6', 'bc2', 'bc4', 'bcx', 'bcy',
104
+ 'br', 'br7', 'br9', 'br3', 'br1',
105
+ 'ct', 'cb',
106
+ 'i', 'i8', 'i6', 'i2', 'i4',
107
+ 'w', 'wmin', 'wmax', 'h', 'hmin', 'hmax',
108
+ 'gx', 'g4', 'g6', 'gy', 'g8', 'g2',
109
+ 'ff', 'fs', 'fw', 'fh',
110
+ ]
111
+ let appendShorthandsIndex = []
112
+ let appendShorthandsData = {}
113
+
95
114
 
96
115
  /**
97
116
  * PostCSS plugin: PostCSS Enumerates in Line
98
117
  * @param {EnumsEnumeratesInLineOptions|object} options - Output options.
99
- * @param {boolean|string} options.prependDefaultColor - Enable to print default CSS colors which explains like a `--enums-color-red-900: #f00;`.
118
+ * @param {boolean|string} options.prependDefaultColor - Enable to print default CSS colors which explains like a `--color-black-999: #000000;`.
100
119
  * @param {boolean|string[]} options.prependDefaultStyle - Enable to print default CSS styles.
120
+ * @param {UserColor[]} options.appendUserColor - Append user color settings to default color.
101
121
  * @description This plugin extend to multiple CSSes from shrinked it which described in 1 line like `@apply` syntax of TailwindCSS.
102
122
  */
103
123
  export const enumSpreader = (options = {}) => {
104
124
  let {
105
125
  prependDefaultColor,
106
126
  prependDefaultStyle,
127
+ appendUserColor,
128
+ appendShorthand,
107
129
  } = {...defaultOptions, ...options}
108
130
 
109
131
  if(prependDefaultColor === false) {
@@ -122,6 +144,9 @@ export const enumSpreader = (options = {}) => {
122
144
  prependDefaultStyle = false
123
145
  }
124
146
 
147
+ appendUserColors(appendUserColor)
148
+ appendUserShorthands(appendShorthand)
149
+
125
150
  return {
126
151
  postcssPlugin: pluginName,
127
152
  Once: root => {
@@ -136,6 +161,7 @@ export const enumSpreader = (options = {}) => {
136
161
  isMq: '',
137
162
  isData: '',
138
163
  isAria: '',
164
+ isAttr: '',
139
165
  important: '',
140
166
  prop: '',
141
167
  value: '',
@@ -245,11 +271,11 @@ export const enumSpreader = (options = {}) => {
245
271
  if(/data\(.+?\)!/.test(param[i])) {
246
272
  setting.isData = []
247
273
  ;(!!param[i].match(/data\((.+?)\)!/)[1] ? param[i].match(/data\((.+?)\)!/)[1] : '').split(',').forEach(q => {
248
- let v1 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]?[A-Za-z\d_])?)([\~\|\^\$\*]?=)['"](.*)['"]$/)
274
+ let v1 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]*[A-Za-z\d_])?)([\~\|\^\$\*]?=)['"](.*)['"]$/)
249
275
  if(!!v1) {
250
276
  setting.isData.push(`[data-${v1[1]}${v1[2]}"${v1[3].replace('\%','%25').replace('\"','%22').replace('\'','%27').replace('\`','%60').replace('\\','%5D')}"]`)
251
277
  } else {
252
- let v2 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]?[A-Za-z\d_])?)$/)
278
+ let v2 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]*[A-Za-z\d_])?)$/)
253
279
  if(!!v2) {
254
280
  setting.isData.push(`[data-${v2[1]}]`)
255
281
  }
@@ -271,14 +297,31 @@ export const enumSpreader = (options = {}) => {
271
297
  param[i] = param[i].replace(/aria\(.+?\)!/g, '')
272
298
  }
273
299
 
274
- if(setting.isHover || setting.isDark || (setting.isMq !== '') || (setting.isData !== '') || (setting.isAria !== '')) {
300
+ if(/attr\(.+?\)!/.test(param[i])) {
301
+ setting.isAttr = []
302
+ ;(!!param[i].match(/attr\((.+?)\)!/)[1] ? param[i].match(/attr\((.+?)\)!/)[1] : '').split(',').forEach(q => {
303
+ let v1 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]*[A-Za-z\d_])?)([\~\|\^\$\*]?=)['"](.*)['"]$/)
304
+ if(!!v1) {
305
+ setting.isAttr.push(`[${v1[1]}${v1[2]}"${v1[3].replace('\%','%25').replace('\"','%22').replace('\'','%27').replace('\`','%60').replace('\\','%5D')}"]`)
306
+ } else {
307
+ let v2 = q.match(/^([A-Za-z\d_](?:[A-Za-z\d_\-]*[A-Za-z\d_])?)$/)
308
+ if(!!v2) {
309
+ setting.isAttr.push(`[${v2[1]}]`)
310
+ }
311
+ }
312
+ })
313
+ setting.isAttr = setting.isAttr.join('')
314
+ param[i] = param[i].replace(/attr\(.+?\)!/g, '')
315
+ }
316
+
317
+ if(setting.isHover || setting.isDark || (setting.isMq !== '') || (setting.isData !== '') || (setting.isAria !== '') || (setting.isAttr !== '')) {
275
318
  let regex = param[i].match(/^([\d\-a-z]+):([^!\s]+)(!)?$/)
276
319
  setting.important = (!!regex[3]) ? ' !important' : ''
277
- setting.prop = expandShortcut(regex[1])
320
+ setting.prop = expandShorthand(regex[1])
278
321
  setting.value = replaceCssPropertyValueWBracket(regex[2])
279
322
 
280
323
  for(let j = 0, m = setting.prop.length; j < m; j ++) {
281
- const css = `${setting.isMq !== '' ? '@media screen and ' + setting.isMq + ' { ' : ''}${setting.isDark ? ':root.dark ' : ''}${rule.selector}${setting.isData}${setting.isAria}${setting.isHover ? ':hover' : ''}{${setting.prop[j]}: ${setting.value}}${setting.isMq !== '' ? ' }' : ''}`
324
+ const css = `${setting.isMq !== '' ? '@media screen and ' + setting.isMq + ' { ' : ''}${setting.isDark ? ':root.dark ' : ''}${rule.selector}${setting.isData}${setting.isAria}${setting.isAttr}${setting.isHover ? ':hover' : ''}{${setting.prop[j]}: ${setting.value}}${setting.isMq !== '' ? ' }' : ''}`
282
325
  rule.after(css)
283
326
  }
284
327
  } else if(/^([\d\-a-z]+):([^!\s]+)(!)?$/.test(param[i])) {
@@ -286,7 +329,7 @@ export const enumSpreader = (options = {}) => {
286
329
  setting.important = (!!regex[3]) ? ' !important' : ''
287
330
  setting.value = replaceCssPropertyValueWBracket(regex[2])
288
331
 
289
- for(let prop = expandShortcut(regex[1]), j = 0, m = prop.length; j < m; j ++) {
332
+ for(let prop = expandShorthand(regex[1]), j = 0, m = prop.length; j < m; j ++) {
290
333
  node.after(`${prop[j]}: ${setting.value}${setting.important};`)
291
334
  }
292
335
  }
@@ -321,115 +364,234 @@ export const enumSpreader = (options = {}) => {
321
364
  }
322
365
 
323
366
 
367
+ /**
368
+ * Append user color settings
369
+ * @param {UserColor[]} auc - User color settings.
370
+ */
371
+ const appendUserColors = auc => {
372
+ for(let i = 0, l = auc.length; i < l; i ++) {
373
+ // check data
374
+ if(!auc[i].hasOwnProperty('theme')) continue
375
+ if(!auc[i].hasOwnProperty('levels')) continue
376
+ if(defaultColorNames.indexOf(auc[i].theme) >= 0) continue
377
+ let flg = false
378
+ for(let j = 0, m = auc[i].levels.length; j < m; j ++) {
379
+ if(
380
+ !auc[i].levels[j].hasOwnProperty('level')
381
+ || !auc[i].levels[j].hasOwnProperty('rgb')
382
+ || !auc[i].levels[j].hasOwnProperty('hsl')
383
+ || !auc[i].levels[j].hasOwnProperty('oklch')
384
+ ) {
385
+ flg = true
386
+ break
387
+ }
388
+ }
389
+ if(flg) continue
390
+
391
+ // push data
392
+ defaultColorNames.push(auc[i].theme)
393
+ if(!defaultColorDefines.rgb[auc[i].theme]) defaultColorDefines.rgb[auc[i].theme] = []
394
+ if(!defaultColorDefines.hsl[auc[i].theme]) defaultColorDefines.hsl[auc[i].theme] = []
395
+ if(!defaultColorDefines.oklch[auc[i].theme]) defaultColorDefines.oklch[auc[i].theme] = []
396
+ for(let j = 0, m = auc[i].levels.length; j < m; j ++) {
397
+ defaultColorDefines.rgb[auc[i].theme].push([auc[i].levels[j].level, auc[i].levels[j].rgb])
398
+ defaultColorDefines.hsl[auc[i].theme].push([auc[i].levels[j].level, auc[i].levels[j].hsl])
399
+ defaultColorDefines.oklch[auc[i].theme].push([auc[i].levels[j].level, auc[i].levels[j].oklch])
400
+ }
401
+ }
402
+
403
+ // to unique data
404
+ for(let i = 0, l = defaultColorNames.length; i < l; i ++) {
405
+ defaultColorDefines.rgb[defaultColorNames[i]] = Array.from(new Set(defaultColorDefines.rgb[defaultColorNames[i]].map(JSON.stringify)))
406
+ defaultColorDefines.hsl[defaultColorNames[i]] = Array.from(new Set(defaultColorDefines.hsl[defaultColorNames[i]].map(JSON.stringify)))
407
+ defaultColorDefines.oklch[defaultColorNames[i]] = Array.from(new Set(defaultColorDefines.oklch[defaultColorNames[i]].map(JSON.stringify)))
408
+ for(let j = 0, m = defaultColorDefines.rgb[defaultColorNames[i]].length; j < m; j ++) {
409
+ defaultColorDefines.rgb[defaultColorNames[i]][j] = JSON.parse(defaultColorDefines.rgb[defaultColorNames[i]][j])
410
+ defaultColorDefines.hsl[defaultColorNames[i]][j] = JSON.parse(defaultColorDefines.hsl[defaultColorNames[i]][j])
411
+ defaultColorDefines.oklch[defaultColorNames[i]][j] = JSON.parse(defaultColorDefines.oklch[defaultColorNames[i]][j])
412
+ }
413
+ }
414
+ }
415
+
416
+ /**
417
+ * Append user shorthand settings
418
+ * @param {Object{<string>,<string>[]}[]} aus - User shorthand settings.
419
+ */
420
+ const appendUserShorthands = aus => {
421
+ for(let i = 0, l = aus.length; i < l; i ++) {
422
+ // check data
423
+ if(typeof aus[i] !== 'object') continue
424
+ if(aus[i].length !== 2) continue
425
+ if(typeof aus[i][1] !== 'object') continue
426
+ if((defaultShorthands.indexOf(aus[i][0]) === -1) && (appendShorthandsIndex.indexOf(aus[i][0]) === -1)) {
427
+ // push data
428
+ appendShorthandsIndex.push(aus[i][0])
429
+ appendShorthandsData[aus[i][0]] = aus[i][1]
430
+ }
431
+ }
432
+ }
433
+
434
+ /**
435
+ * Replace W SQUARE BRACKET syntax to available value in CSS property value
436
+ * @param {string} value - Designated value.
437
+ * @returns {string} Available value as CSS property.
438
+ */
324
439
  const replaceCssPropertyValueWBracket = value => value.replace(/\^/g, ' ')
440
+ .replace(/color\[\[(.+?)\]\]/g,(_,expr) => {
441
+ const args = expr.split(',').reverse()
442
+ let opts = {
443
+ style: 'hsl',
444
+ color: 'base',
445
+ level: '400',
446
+ opacity: '100%',
447
+ }
448
+
449
+ for(let i = 0, l = args.length; i < l; i ++) {
450
+ if(/^[\d]+$/.test(args[i])) {
451
+ opts.level = args[i]
452
+ } else if(/^[\d]+[%]$/.test(args[i])) {
453
+ opts.opacity = args[i]
454
+ } else if(/^(rgb|hsl|oklch)$/i.test(args[i])) {
455
+ opts.style = args[i].toLowerCase()
456
+ } else if(defaultColorNames.includes(args[i])) {
457
+ opts.color = args[i]
458
+ } else {
459
+ return ''
460
+ }
461
+ }
462
+
463
+ let color = defaultColorDefines[opts.style][opts.color].filter(arr => arr[0] === parseInt(opts.level))
464
+ if(color.length !== 1) return ''
465
+ if(color[0].length !== 2) return ''
466
+ color = color[0][1]
467
+
468
+ switch(opts.style) {
469
+ case 'rgb':
470
+ color += Math.ceil(parseInt(opts.opacity)*2.55).toString(16).toUpperCase()
471
+ break;
472
+ case 'hsl':
473
+ case 'oklch':
474
+ color = color.replace(')', ` / ${opts.opacity})`)
475
+ break;
476
+ default:
477
+ break;
478
+ }
479
+
480
+ return color
481
+ })
325
482
  .replace(/\[\[([^}]+)\]\]/g,(_,expr)=>`[[${expr.replace(/([+\*/]|(?<=[0-9a-zA-Z\)])[-%](?=[0-9a-zA-Z\(]))/g,' $1 ')}]]`)
326
483
  .replace('[[', '(')
327
484
  .replace(']]', ')')
328
485
  .replace(/ +/g, ' ')
329
486
 
330
487
  /**
331
- * Expand shortcut property name.
488
+ * Expand shorthand property name.
332
489
  * @param {String} prop - Specified property name.
333
490
  * @return {Array<String>} - Regular property name that defined in CSS.
334
- * @return {Array<String>} - If this function retrieved undefined shortcut property in this plugin, returns just it.
491
+ * @return {Array<String>} - If this function retrieved undefined shorthand property in this plugin, returns just it.
335
492
  */
336
- const expandShortcut = prop => {
493
+ const expandShorthand = prop => {
337
494
  switch(prop) {
338
495
  // margin
339
- case 'm': return ['margin'];
340
- case 'm8': return ['margin-top'];
341
- case 'm6': return ['margin-right'];
342
- case 'm2': return ['margin-bottom'];
343
- case 'm4': return ['margin-left'];
344
- case 'mx': return ['margin-left', 'margin-right'];
345
- case 'my': return ['margin-top', 'margin-bottom'];
496
+ case 'm': return ['margin']
497
+ case 'm8': return ['margin-top']
498
+ case 'm6': return ['margin-right']
499
+ case 'm2': return ['margin-bottom']
500
+ case 'm4': return ['margin-left']
501
+ case 'mx': return ['margin-left', 'margin-right']
502
+ case 'my': return ['margin-top', 'margin-bottom']
346
503
 
347
504
  // padding
348
- case 'p': return ['padding'];
349
- case 'p8': return ['padding-top'];
350
- case 'p6': return ['padding-right'];
351
- case 'p2': return ['padding-bottom'];
352
- case 'p4': return ['padding-left'];
353
- case 'px': return ['padding-left', 'padding-right'];
354
- case 'py': return ['padding-top', 'padding-bottom'];
505
+ case 'p': return ['padding']
506
+ case 'p8': return ['padding-top']
507
+ case 'p6': return ['padding-right']
508
+ case 'p2': return ['padding-bottom']
509
+ case 'p4': return ['padding-left']
510
+ case 'px': return ['padding-left', 'padding-right']
511
+ case 'py': return ['padding-top', 'padding-bottom']
355
512
 
356
513
  // outline
357
- case 'o': return ['outline'];
358
- case 'o8': return ['outline-top'];
359
- case 'o6': return ['outline-right'];
360
- case 'o2': return ['outline-bottom'];
361
- case 'o4': return ['outline-left'];
362
- case 'ox': return ['outline-left', 'outline-right'];
363
- case 'oy': return ['outline-top', 'outline-bottom'];
514
+ case 'o': return ['outline']
515
+ case 'o8': return ['outline-top']
516
+ case 'o6': return ['outline-right']
517
+ case 'o2': return ['outline-bottom']
518
+ case 'o4': return ['outline-left']
519
+ case 'ox': return ['outline-left', 'outline-right']
520
+ case 'oy': return ['outline-top', 'outline-bottom']
364
521
 
365
522
  // border-width
366
- case 'bw': return ['border-width'];
367
- case 'bw8': return ['border-top-width'];
368
- case 'bw6': return ['border-right-width'];
369
- case 'bw2': return ['border-bottom-width'];
370
- case 'bw4': return ['border-left-width'];
371
- case 'bwx': return ['border-left-width', 'border-right-width'];
372
- case 'bwy': return ['border-top-width', 'border-bottom-width'];
523
+ case 'bw': return ['border-width']
524
+ case 'bw8': return ['border-top-width']
525
+ case 'bw6': return ['border-right-width']
526
+ case 'bw2': return ['border-bottom-width']
527
+ case 'bw4': return ['border-left-width']
528
+ case 'bwx': return ['border-left-width', 'border-right-width']
529
+ case 'bwy': return ['border-top-width', 'border-bottom-width']
373
530
 
374
531
  // border-style
375
- case 'bs': return ['border-style'];
376
- case 'bs8': return ['border-top-style'];
377
- case 'bs6': return ['border-right-style'];
378
- case 'bs2': return ['border-bottom-style'];
379
- case 'bs4': return ['border-left-style'];
380
- case 'bsx': return ['border-left-style', 'border-right-style'];
381
- case 'bsy': return ['border-top-style', 'border-bottom-style'];
532
+ case 'bs': return ['border-style']
533
+ case 'bs8': return ['border-top-style']
534
+ case 'bs6': return ['border-right-style']
535
+ case 'bs2': return ['border-bottom-style']
536
+ case 'bs4': return ['border-left-style']
537
+ case 'bsx': return ['border-left-style', 'border-right-style']
538
+ case 'bsy': return ['border-top-style', 'border-bottom-style']
382
539
 
383
540
  // border-color
384
- case 'bc': return ['border-color'];
385
- case 'bc8': return ['border-top-color'];
386
- case 'bc6': return ['border-right-color'];
387
- case 'bc2': return ['border-bottom-color'];
388
- case 'bc4': return ['border-left-color'];
389
- case 'bcx': return ['border-left-color', 'border-right-color'];
390
- case 'bcy': return ['border-top-color', 'border-bottom-color'];
541
+ case 'bc': return ['border-color']
542
+ case 'bc8': return ['border-top-color']
543
+ case 'bc6': return ['border-right-color']
544
+ case 'bc2': return ['border-bottom-color']
545
+ case 'bc4': return ['border-left-color']
546
+ case 'bcx': return ['border-left-color', 'border-right-color']
547
+ case 'bcy': return ['border-top-color', 'border-bottom-color']
391
548
 
392
549
  // border-radius
393
- case 'br': return ['border-radius'];
394
- case 'br7': return ['border-top-left-radius'];
395
- case 'br9': return ['border-top-right-radius'];
396
- case 'br3': return ['border-bottom-right-radius'];
397
- case 'br1': return ['border-bottom-left-radius'];
550
+ case 'br': return ['border-radius']
551
+ case 'br7': return ['border-top-left-radius']
552
+ case 'br9': return ['border-top-right-radius']
553
+ case 'br3': return ['border-bottom-right-radius']
554
+ case 'br1': return ['border-bottom-left-radius']
398
555
 
399
556
  // color
400
- case 'ct': return ['color'];
401
- case 'cb': return ['background-color'];
557
+ case 'ct': return ['color']
558
+ case 'cb': return ['background-color']
402
559
 
403
560
  // inset
404
- case 'i': return ['inset'];
405
- case 'i8': return ['top'];
406
- case 'i6': return ['right'];
407
- case 'i2': return ['bottom'];
408
- case 'i4': return ['left'];
561
+ case 'i': return ['inset']
562
+ case 'i8': return ['top']
563
+ case 'i6': return ['right']
564
+ case 'i2': return ['bottom']
565
+ case 'i4': return ['left']
409
566
 
410
567
  // sizing
411
- case 'w': return ['width'];
412
- case 'wmin': return ['min-width'];
413
- case 'wmax': return ['max-width'];
414
- case 'h': return ['height'];
415
- case 'hmin': return ['min-height'];
416
- case 'hmax': return ['max-height'];
568
+ case 'w': return ['width']
569
+ case 'wmin': return ['min-width']
570
+ case 'wmax': return ['max-width']
571
+ case 'h': return ['height']
572
+ case 'hmin': return ['min-height']
573
+ case 'hmax': return ['max-height']
417
574
 
418
575
  // grid position
419
- case 'gx': return ['grid-column'];
420
- case 'g4': return ['grid-column-start'];
421
- case 'g6': return ['grid-column-end'];
422
- case 'gy': return ['grid-row'];
423
- case 'g8': return ['grid-row-start'];
424
- case 'g2': return ['grid-row-end'];
576
+ case 'gx': return ['grid-column']
577
+ case 'g4': return ['grid-column-start']
578
+ case 'g6': return ['grid-column-end']
579
+ case 'gy': return ['grid-row']
580
+ case 'g8': return ['grid-row-start']
581
+ case 'g2': return ['grid-row-end']
425
582
 
426
583
  // font
427
- case 'ff': return ['font-family'];
428
- case 'fs': return ['font-size'];
429
- case 'fw': return ['font-weight'];
430
- case 'fh': return ['line-height'];
584
+ case 'ff': return ['font-family']
585
+ case 'fs': return ['font-size']
586
+ case 'fw': return ['font-weight']
587
+ case 'fh': return ['line-height']
431
588
 
432
589
  // default
433
- default: return [].concat(prop);
590
+ default:
591
+ if(appendShorthandsData.hasOwnProperty(prop)) {
592
+ return appendShorthandsData[prop]
593
+ } else {
594
+ return [].concat(prop)
595
+ }
434
596
  }
435
597
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "postcss-enumerates-in-line",
3
3
  "type": "module",
4
- "version": "0.3.2",
4
+ "version": "0.4.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/hadukinei/postcss-enumerates-in-line"