purgetss 7.3.1 → 7.5.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.
@@ -243,6 +243,28 @@ export function toggle() {
243
243
  return convertedStyles
244
244
  }
245
245
 
246
+ /**
247
+ * Snap properties for the Animation module
248
+ * @returns {string} Generated styles
249
+ */
250
+ export function snap() {
251
+ let convertedStyles = processComments({
252
+ prop: 'snap - For the Animation module',
253
+ modules: 'Animation'
254
+ })
255
+
256
+ convertedStyles += '\'.snap-back\': { animationProperties: { snap: { back: true } } }\n'
257
+ convertedStyles += '\'.snap-back-false\': { animationProperties: { snap: { back: false } } }\n'
258
+ convertedStyles += '\'.snap-center\': { animationProperties: { snap: { center: true } } }\n'
259
+ convertedStyles += '\'.snap-center-false\': { animationProperties: { snap: { center: false } } }\n'
260
+ convertedStyles += '\'.snap-magnet\': { animationProperties: { snap: { magnet: true } } }\n'
261
+ convertedStyles += '\'.snap-magnet-false\': { animationProperties: { snap: { magnet: false } } }\n'
262
+ convertedStyles += '\'.keep-z-index\': { animationProperties: { keepZIndex: true } }\n'
263
+ convertedStyles += '\'.keep-z-index-false\': { animationProperties: { keepZIndex: false } }\n'
264
+
265
+ return convertedStyles
266
+ }
267
+
246
268
  /**
247
269
  * Dragging type property
248
270
  * @returns {string} Generated styles
@@ -374,6 +374,26 @@ export function fixInvalidValues(invalidValues, currentValue) {
374
374
  return invalidValues[currentValue] || currentValue
375
375
  }
376
376
 
377
+ /**
378
+ * Recursively serialize a value for TSS output.
379
+ * Handles primitives, plain objects, and arrays of objects.
380
+ * @param {*} val - Value to serialize
381
+ * @returns {string} TSS-compatible string representation
382
+ */
383
+ function serializeValue(val) {
384
+ if (Array.isArray(val)) {
385
+ const items = val.map(item => serializeValue(item))
386
+ return `[ ${items.join(', ')} ]`
387
+ }
388
+ if (typeof val === 'object' && val !== null) {
389
+ const entries = Object.entries(val)
390
+ .map(([k, v]) => `${k}: ${serializeValue(v)}`)
391
+ .join(', ')
392
+ return `{ ${entries} }`
393
+ }
394
+ return parseValue(val)
395
+ }
396
+
377
397
  /**
378
398
  * Generate custom rules for Titanium styles
379
399
  * @param {Object} _value - Value object containing rules
@@ -399,27 +419,7 @@ export function customRules(_value, _key, changeToDash = false) {
399
419
 
400
420
  customProperties += ' {_applyProperties_},'
401
421
  } else {
402
- customProperties += ` ${theModifier}: {`
403
-
404
- let extraCustomProperties = ''
405
-
406
- _.each(theValue, (extraValue, extraModifier) => {
407
- if (typeof (extraValue) === 'object' && extraValue !== null) {
408
- customProperties += ` ${extraModifier}: {`
409
-
410
- let moreExtraCustomProperties = ''
411
-
412
- _.each(extraValue, (moreExtraValue, moreModifier) => {
413
- moreExtraCustomProperties += ` ${moreModifier}: ${parseValue(moreExtraValue)},`
414
- })
415
-
416
- customProperties += `${removeLastCharacter(moreExtraCustomProperties)} },`
417
- } else {
418
- extraCustomProperties += ` ${extraModifier}: ${parseValue(extraValue)},`
419
- }
420
- })
421
-
422
- customProperties += `${removeLastCharacter(extraCustomProperties)} },`
422
+ customProperties += ` ${theModifier}: ${serializeValue(theValue)},`
423
423
  }
424
424
  } else {
425
425
  if (theModifier === 'apply') {
@@ -470,6 +470,10 @@ export function compileApplyDirectives(twClasses) {
470
470
  const compoundClasses = []
471
471
  const classesWithOpacityValues = []
472
472
 
473
+ // Extract platform from the target class (e.g., 'Window[platform=ios]' → 'ios')
474
+ const platformMatch = className.match(/\[platform=(\w+)\]/)
475
+ const targetPlatform = platformMatch ? platformMatch[1] : null
476
+
473
477
  _.each([...values], searchClass => {
474
478
  if (searchClass.includes('ios:')) {
475
479
  searchClass = `${searchClass.replace('ios:', '')}[platform=ios]`
@@ -496,14 +500,27 @@ export function compileApplyDirectives(twClasses) {
496
500
 
497
501
  classesWithOpacityValues.push({ decimalValue, transparency, originalClass, classNameWithTransparency })
498
502
  } else {
499
- const className = `'.${searchClass}':`
500
- let foundClass = twClassesArray[findIndexOfClassName(className, twClassesArray)]
503
+ let foundClass = null
504
+
505
+ // If the target has a platform, try platform-specific class first
506
+ if (targetPlatform && !searchClass.includes('[platform=')) {
507
+ const platformClassName = `'.${searchClass}[platform=${targetPlatform}]':`
508
+ foundClass = twClassesArray[findIndexOfClassName(platformClassName, twClassesArray)]
509
+ if (!foundClass && fontsClassesArray) {
510
+ foundClass = fontsClassesArray[findIndexOfClassName(platformClassName, fontsClassesArray)]
511
+ }
512
+ }
501
513
 
502
- if (foundClass) compoundClasses.push(justProperties(foundClass))
503
- else if (fontsClassesArray) {
504
- foundClass = fontsClassesArray[findIndexOfClassName(className, fontsClassesArray)]
505
- if (foundClass) compoundClasses.push(justProperties(foundClass))
514
+ // Fall back to generic class (no platform suffix)
515
+ if (!foundClass) {
516
+ const genericClassName = `'.${searchClass}':`
517
+ foundClass = twClassesArray[findIndexOfClassName(genericClassName, twClassesArray)]
518
+ if (!foundClass && fontsClassesArray) {
519
+ foundClass = fontsClassesArray[findIndexOfClassName(genericClassName, fontsClassesArray)]
520
+ }
506
521
  }
522
+
523
+ if (foundClass) compoundClasses.push(justProperties(foundClass))
507
524
  }
508
525
  })
509
526
 
@@ -522,12 +539,54 @@ export function compileApplyDirectives(twClasses) {
522
539
  }
523
540
 
524
541
  twClassesArray[indexOfModifier] = _.replace(twClassesArray[indexOfModifier], /{_applyProperties_}/, fixDuplicateKeys(compoundClasses).join(', '))
542
+ twClassesArray[indexOfModifier] = deduplicateLineProperties(twClassesArray[indexOfModifier])
525
543
  }
526
544
  })
527
545
 
528
546
  return twClassesArray.join('\n')
529
547
  }
530
548
 
549
+ /**
550
+ * Remove duplicate property keys in a TSS line, keeping the last occurrence.
551
+ * This ensures apply directives override static defaults (e.g. backgroundColor).
552
+ */
553
+ function deduplicateLineProperties(line) {
554
+ const match = line.match(/^(.*?\{)\s*(.*)\s*(\})$/)
555
+ if (!match) return line
556
+
557
+ const prefix = match[1]
558
+ const propsStr = match[2]
559
+ const suffix = match[3]
560
+
561
+ // Split by comma respecting nested braces
562
+ const props = []
563
+ let depth = 0
564
+ let current = ''
565
+ for (const char of propsStr) {
566
+ if (char === '{') depth++
567
+ else if (char === '}') depth--
568
+ else if (char === ',' && depth === 0) {
569
+ if (current.trim()) props.push(current.trim())
570
+ current = ''
571
+ continue
572
+ }
573
+ current += char
574
+ }
575
+ if (current.trim()) props.push(current.trim())
576
+
577
+ // Keep last occurrence of each key
578
+ const seen = new Map()
579
+ props.forEach(prop => {
580
+ const colonIdx = prop.indexOf(':')
581
+ if (colonIdx > -1) {
582
+ const key = prop.substring(0, colonIdx).trim()
583
+ seen.set(key, prop)
584
+ }
585
+ })
586
+
587
+ return prefix + ' ' + [...seen.values()].join(', ') + ' ' + suffix
588
+ }
589
+
531
590
  export function justProperties(_foundClass) {
532
591
  return _foundClass.match(/{(.*)}/)[1].trim()
533
592
  }