purgetss 7.7.1 → 7.9.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.
@@ -1,39 +1,10 @@
1
1
  /**
2
2
  * PurgeTSS v7.1.0 - Core Builder: Tailwind Helpers
3
- * Helper functions for building Tailwind CSS
4
- *
5
- * COPIED from src/index.js during refactorization - NO CHANGES to logic.
6
3
  *
7
4
  * @since 7.1.0
8
5
  * @author César Estrada
9
6
  */
10
7
 
11
- import _ from 'lodash'
12
- import defaultColors from 'tailwindcss/colors.js'
13
-
14
- // Import functions from their new modular locations
15
- import { getConfigFile } from '../../shared/config-manager.js'
16
- import { removeDeprecatedColors, fixPercentages } from '../../shared/helpers.js'
17
-
18
- // Get config once for this module
19
- const configFile = getConfigFile()
20
-
21
- /**
22
- * Remove fit, max, min values from width, height and spacing objects
23
- * @param {Object} theObject - Object with width, height, spacing properties
24
- */
25
- export function removeFitMaxMin(theObject) {
26
- delete theObject.width.fit
27
- delete theObject.width.max
28
- delete theObject.width.min
29
- delete theObject.height.fit
30
- delete theObject.height.max
31
- delete theObject.height.min
32
- delete theObject.spacing.fit
33
- delete theObject.spacing.max
34
- delete theObject.spacing.min
35
- }
36
-
37
8
  /**
38
9
  * Combine keys from theme and extend, with fallback to base values
39
10
  * @param {Object} values - Theme values object
@@ -44,418 +15,3 @@ export function removeFitMaxMin(theObject) {
44
15
  export function combineKeys(values, base, key) {
45
16
  return (values[key]) ? { ...values[key], ...values.extend[key] } : { ...base, ...values.extend[key] }
46
17
  }
47
-
48
- /**
49
- * Get base values for Tailwind building
50
- * This function prepares all the base theme values needed for building
51
- * @param {Object} defaultTheme - Default Tailwind theme
52
- * @returns {Object} Base values object
53
- */
54
- export function getBaseValues(defaultTheme) {
55
- const defaultThemeWidth = defaultTheme.width({ theme: () => (defaultTheme.spacing) })
56
- const defaultThemeHeight = defaultTheme.height({ theme: () => (defaultTheme.spacing) })
57
-
58
- removeDeprecatedColors(defaultColors)
59
-
60
- // !Prepare values
61
- const tiResets = { full: '100%' }
62
- const allWidthsCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeWidth }
63
- const allHeightsCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeHeight }
64
- const allSpacingCombined = (configFile.theme.spacing) ? { ...configFile.theme.spacing, ...tiResets } : { ...defaultThemeWidth, ...defaultThemeHeight }
65
-
66
- const themeOrDefaultValues = {
67
- width: configFile.theme.width ?? allWidthsCombined,
68
- height: configFile.theme.height ?? allHeightsCombined,
69
- spacing: configFile.theme.spacing ?? allSpacingCombined,
70
- fontSize: configFile.theme.spacing ?? defaultTheme.fontSize,
71
- colors: configFile.theme.colors ?? { transparent: 'transparent', ...defaultColors }
72
- }
73
-
74
- // ! Remove unnecessary values
75
- removeFitMaxMin(themeOrDefaultValues)
76
-
77
- // ! Merge with extend values
78
- const base = {
79
- width: { ...themeOrDefaultValues.spacing, ...configFile.theme.extend.spacing, ...themeOrDefaultValues.width, ...configFile.theme.extend.width },
80
- height: { ...themeOrDefaultValues.spacing, ...configFile.theme.extend.spacing, ...themeOrDefaultValues.height, ...configFile.theme.extend.height },
81
- colors: { ...themeOrDefaultValues.colors, ...configFile.theme.extend.colors },
82
- spacing: { ...themeOrDefaultValues.spacing, ...configFile.theme.extend.spacing },
83
- fontSize: { ...themeOrDefaultValues.fontSize, ...configFile.theme.extend.spacing, ...configFile.theme.extend.fontSize },
84
- columns: { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 },
85
- delay: { 0: '0ms', 25: '25ms', 50: '50ms', 250: '250ms', 350: '350ms', 400: '400ms', 450: '450ms', 600: '600ms', 800: '800ms', 900: '900ms', 2000: '2000ms', 3000: '3000ms', 4000: '4000ms', 5000: '5000ms' }
86
- }
87
-
88
- fixPercentages(base.width)
89
- fixPercentages(base.height)
90
- fixPercentages(base.spacing)
91
-
92
- return base
93
- }
94
-
95
- /**
96
- * Combine all values for Tailwind building - MASSIVE function with all Titanium properties
97
- * This function builds the complete values object used in legacy Tailwind building
98
- * @param {Object} base - Base values from getBaseValues()
99
- * @param {Object} defaultTheme - Default Tailwind theme
100
- * @returns {Object} Complete values object for building
101
- */
102
- export function combineAllValues(base, defaultTheme) {
103
- const allValues = {}
104
-
105
- // ! Custom Window, View and ImageView
106
- // Merge extend values into theme (same as colors, spacing, etc.)
107
- _.each(['Window', 'View', 'ImageView'], comp => {
108
- if (configFile.theme.extend[comp]) {
109
- configFile.theme[comp] = _.merge({}, configFile.theme[comp], configFile.theme.extend[comp])
110
- delete configFile.theme.extend[comp]
111
- }
112
- // Normalize shorthand: { apply: '...' } → { default: { apply: '...' } }
113
- if (configFile.theme[comp] && configFile.theme[comp].apply && !configFile.theme[comp].default) {
114
- configFile.theme[comp] = { default: configFile.theme[comp] }
115
- }
116
- })
117
-
118
- // Merge user config WITH defaults, then write back to configFile.theme
119
- // so that downstream functions pick up the full merged object
120
- configFile.theme.Window = _.merge({ default: { backgroundColor: '#FFFFFF' } }, configFile.theme.Window)
121
- configFile.theme.ImageView = _.merge({ ios: { hires: true } }, configFile.theme.ImageView)
122
- configFile.theme.View = _.merge({ default: { width: 'Ti.UI.SIZE', height: 'Ti.UI.SIZE' } }, configFile.theme.View)
123
-
124
- allValues.Window = configFile.theme.Window
125
- allValues.ImageView = configFile.theme.ImageView
126
- allValues.View = configFile.theme.View
127
-
128
- // ! Width, height and margin properties
129
- // INFO: sizingProperties: For glossary generator only... Do not move from this position.
130
- allValues.sizingProperties = {}
131
-
132
- allValues.height = base.height
133
- allValues.width = base.width
134
- allValues.margin = combineKeys(configFile.theme, base.spacing, 'margin')
135
- allValues.marginAlternate = combineKeys(configFile.theme, base.spacing, 'margin')
136
-
137
- // ! Properties with constant values
138
- // INFO: constantProperties: For glossary generator only... Do not move from this position.
139
- allValues.constantProperties = {}
140
-
141
- // allValues.audioStreamType = {};
142
- // allValues.category = {};
143
- allValues.accessibilityHidden = {}
144
- allValues.accessoryType = {}
145
- allValues.activeIconIsMask = {}
146
- allValues.activityEnterTransition = {}
147
- allValues.activityExitTransition = {}
148
- allValues.activityIndicatorStyle = {}
149
- allValues.activityReenterTransition = {}
150
- allValues.activityReturnTransition = {}
151
- allValues.activitySharedElementEnterTransition = {}
152
- allValues.activitySharedElementExitTransition = {}
153
- allValues.activitySharedElementReenterTransition = {}
154
- allValues.activitySharedElementReturnTransition = {}
155
- allValues.alertDialogStyle = {}
156
- allValues.allowsBackForwardNavigationGestures = {}
157
- allValues.allowsLinkPreview = {}
158
- allValues.allowsMultipleSelectionDuringEditing = {}
159
- allValues.allowsMultipleSelectionInteraction = {}
160
- allValues.allowsSelection = {}
161
- allValues.allowsSelectionDuringEditing = {}
162
- allValues.allowUserCustomization = {}
163
- allValues.anchorPoint = {}
164
- allValues.autoAdjustScrollViewInsets = {}
165
- allValues.autocapitalization = {}
166
- allValues.autocorrect = {}
167
- allValues.autofillType = {}
168
- allValues.autoLink = {}
169
- allValues.autoreverse = {}
170
- allValues.autorotate = {}
171
- allValues.backgroundBlendMode = {}
172
- allValues.backgroundLinearGradient = {}
173
- allValues.backgroundRadialGradient = {}
174
- allValues.backgroundRepeat = {}
175
- allValues.borderStyle = {}
176
- allValues.bubbleParent = {}
177
- allValues.buttonStyle = {}
178
- allValues.cacheMode = {}
179
- allValues.cachePolicy = {}
180
- allValues.calendarViewShown = {}
181
- allValues.canCancelEvents = {}
182
- allValues.cancelable = {}
183
- allValues.canceledOnTouchOutside = {}
184
- allValues.canDelete = {}
185
- allValues.canEdit = {}
186
- allValues.canInsert = {}
187
- allValues.canMove = {}
188
- allValues.canScroll = {}
189
- allValues.caseInsensitiveSearch = {}
190
- allValues.checkable = {}
191
- allValues.clearButtonMode = {}
192
- allValues.clearOnEdit = {}
193
- allValues.clipMode = {}
194
- allValues.constraint = {}
195
- allValues.contentHeightAndWidth = {}
196
- allValues.curve = {}
197
- allValues.datePickerStyle = {}
198
- allValues.defaultItemTemplate = {}
199
- allValues.dimBackgroundForSearch = {}
200
- allValues.disableBounce = {}
201
- allValues.disableContextMenu = {}
202
- allValues.displayCaps = {}
203
- allValues.displayHomeAsUp = {}
204
- allValues.draggingType = {}
205
- allValues.drawerIndicatorEnabled = {}
206
- allValues.drawerLockMode = {}
207
- allValues.dropShadow = {}
208
- allValues.duration = {}
209
- allValues.editable = {}
210
- allValues.editing = {}
211
- allValues.ellipsize = {}
212
- allValues.enableCopy = {}
213
- allValues.enabled = {}
214
- allValues.enableJavascriptInterface = {}
215
- allValues.enableReturnKey = {}
216
- allValues.enableZoomControls = {}
217
- allValues.exitOnClose = {}
218
- allValues.extendBackground = {}
219
- allValues.extendEdges = {}
220
- allValues.extendSafeArea = {}
221
- allValues.fastScroll = {}
222
- allValues.filterAnchored = {}
223
- allValues.filterAttribute = {}
224
- allValues.filterCaseInsensitive = {}
225
- allValues.filterTouchesWhenObscured = {}
226
- allValues.flags = {}
227
- allValues.flagSecure = {}
228
- allValues.flip = {}
229
- allValues.focusable = {}
230
- allValues.fontStyle = {}
231
- allValues.footerDividersEnabled = {}
232
- allValues.format24 = {}
233
- allValues.fullscreen = {}
234
- allValues.gravity = {}
235
- allValues.gridColumnsRowsStartEnd = {}
236
- allValues.gridFlow = {}
237
- allValues.gridSystem = {}
238
- allValues.hasCheck = {}
239
- allValues.hasChild = {}
240
- allValues.hasDetail = {}
241
- allValues.headerDividersEnabled = {}
242
- allValues.hiddenBehavior = {}
243
- allValues.hideLoadIndicator = {}
244
- allValues.hidesBackButton = {}
245
- allValues.hidesBarsOnSwipe = {}
246
- allValues.hidesBarsOnTap = {}
247
- allValues.hidesBarsWhenKeyboardAppears = {}
248
- allValues.hideSearchOnSelection = {}
249
- allValues.hideShadow = {}
250
- allValues.hidesSearchBarWhenScrolling = {}
251
- allValues.hintType = {}
252
- allValues.hires = {}
253
- allValues.homeButtonEnabled = {}
254
- allValues.homeIndicatorAutoHidden = {}
255
- allValues.horizontalWrap = {}
256
- allValues.html = {}
257
- allValues.icon = {}
258
- allValues.iconified = {}
259
- allValues.iconifiedByDefault = {}
260
- allValues.iconIsMask = {}
261
- allValues.ignoreSslError = {}
262
- allValues.imageTouchFeedback = {}
263
- allValues.includeFontPadding = {}
264
- allValues.includeOpaqueBars = {}
265
- allValues.keepScreenOn = {}
266
- allValues.keepSectionsInSearch = {}
267
- allValues.keyboardAppearance = {}
268
- allValues.keyboardDismissMode = {}
269
- allValues.keyboardDisplayRequiresUserAction = {}
270
- allValues.keyboardType = {}
271
- allValues.largeTitleDisplayMode = {}
272
- allValues.largeTitleEnabled = {}
273
- allValues.layout = {}
274
- allValues.lazyLoadingEnabled = {}
275
- allValues.leftButtonMode = {}
276
- allValues.leftDrawerLockMode = {}
277
- allValues.lightTouchEnabled = {}
278
- allValues.listViewStyle = {}
279
- allValues.loginKeyboardType = {}
280
- allValues.loginReturnKeyType = {}
281
- allValues.mixedContentMode = {}
282
- allValues.modal = {}
283
- allValues.moveable = {}
284
- allValues.moving = {}
285
- allValues.nativeSpinner = {}
286
- allValues.navBarHidden = {}
287
- allValues.navigationMode = {}
288
- allValues.orientationModes = {}
289
- allValues.overlayEnabled = {}
290
- allValues.overrideCurrentAnimation = {}
291
- allValues.overScrollMode = {}
292
- allValues.showPagingControl = {}
293
- allValues.pagingControlOnTop = {}
294
- allValues.passwordKeyboardType = {}
295
- allValues.passwordMask = {}
296
- allValues.pickerType = {}
297
- allValues.placement = {}
298
- allValues.pluginState = {}
299
- allValues.preventCornerOverlap = {}
300
- allValues.preventDefaultImage = {}
301
- allValues.previewActionStyle = {}
302
- allValues.progressBarStyle = {}
303
- allValues.progressIndicatorType = {}
304
- allValues.pruneSectionsOnEdit = {}
305
- allValues.requestedOrientation = {}
306
- allValues.resultsSeparatorStyle = {}
307
- allValues.returnKeyType = {}
308
- allValues.reverse = {}
309
- allValues.rightButtonMode = {}
310
- allValues.rightDrawerLockMode = {}
311
- allValues.scalesPageToFit = {}
312
- allValues.scrollable = {}
313
- allValues.scrollIndicators = {}
314
- allValues.scrollIndicatorStyle = {}
315
- allValues.scrollingEnabled = {}
316
- allValues.scrollsToTop = {}
317
- allValues.scrollType = {}
318
- allValues.searchAsChild = {}
319
- allValues.searchBarStyle = {}
320
- allValues.searchHidden = {}
321
- allValues.selectionGranularity = {}
322
- allValues.selectionOpens = {}
323
- allValues.selectionStyle = {}
324
- allValues.separatorStyle = {}
325
- allValues.shiftMode = {}
326
- allValues.showAsAction = {}
327
- allValues.showBookmark = {}
328
- allValues.showCancel = {}
329
- allValues.showHorizontalScrollIndicator = {}
330
- allValues.showSearchBarInNavBar = {}
331
- allValues.showSelectionCheck = {}
332
- allValues.showUndoRedoActions = {}
333
- allValues.showVerticalScrollIndicator = {}
334
- allValues.smoothScrollOnTabClick = {}
335
- allValues.statusBarStyle = {}
336
- allValues.submitEnabled = {}
337
- allValues.suppressReturn = {}
338
- allValues.sustainedPerformanceMode = {}
339
- allValues.swipeToClose = {}
340
- allValues.switchStyle = {}
341
- allValues.systemButton = {}
342
- allValues.tabBarHidden = {}
343
- allValues.tabbedBarStyle = {}
344
- allValues.tabGroupStyle = {}
345
- allValues.tableViewStyle = {}
346
- allValues.tabsTranslucent = {}
347
- allValues.textAlign = {}
348
- allValues.theme = {}
349
- allValues.titleAttributesShadow = {}
350
- allValues.toolbarEnabled = {}
351
- allValues.touchEnabled = {}
352
- allValues.touchFeedback = {}
353
- allValues.translucent = {}
354
- allValues.useCompatPadding = {}
355
- allValues.useSpinner = {}
356
- allValues.verticalAlign = {}
357
- allValues.verticalBounce = {}
358
- allValues.viewShadow = {}
359
- allValues.visible = {}
360
- allValues.willHandleTouches = {}
361
- allValues.willScrollOnStatusTap = {}
362
- allValues.windowPixelFormat = {}
363
- allValues.windowSoftInputMode = {}
364
- allValues.wobble = {}
365
-
366
- // ! Configurable properties
367
- // INFO: configurableProperties: For glossary generator only... Do not move from this position.
368
- allValues.configurableProperties = {}
369
-
370
- allValues.activeTab = combineKeys(configFile.theme, base.spacing, 'activeTab')
371
- allValues.backgroundLeftCap = combineKeys(configFile.theme, base.spacing, 'backgroundLeftCap')
372
- allValues.backgroundPaddingBottom = combineKeys(configFile.theme, base.spacing, 'backgroundPaddingBottom')
373
- allValues.backgroundPaddingLeft = combineKeys(configFile.theme, base.spacing, 'backgroundPaddingLeft')
374
- allValues.backgroundPaddingRight = combineKeys(configFile.theme, base.spacing, 'backgroundPaddingRight')
375
- allValues.backgroundPaddingTop = combineKeys(configFile.theme, base.spacing, 'backgroundPaddingTop')
376
- allValues.backgroundTopCap = combineKeys(configFile.theme, base.spacing, 'backgroundTopCap')
377
- allValues.borderRadius = combineKeys(configFile.theme, base.spacing, 'borderRadius')
378
- allValues.borderWidth = combineKeys(configFile.theme, base.spacing, 'borderWidth')
379
- allValues.bottomNavigation = combineKeys(configFile.theme, base.spacing, 'bottomNavigation')
380
- allValues.cacheSize = combineKeys(configFile.theme, base.spacing, 'cacheSize')
381
- allValues.columnCount = combineKeys(configFile.theme, { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12 }, 'columnCount')
382
- allValues.contentHeight = combineKeys(configFile.theme, base.height, 'contentHeight')
383
- allValues.contentWidth = combineKeys(configFile.theme, base.width, 'contentWidth')
384
- allValues.countDownDuration = combineKeys(configFile.theme, base.spacing, 'countDownDuration')
385
- allValues.elevation = combineKeys(configFile.theme, base.spacing, 'elevation')
386
- allValues.fontFamily = combineKeys(configFile.theme, {}, 'fontFamily')
387
- allValues.fontSize = combineKeys(configFile.theme, base.fontSize, 'fontSize')
388
- allValues.fontWeight = combineKeys(configFile.theme, defaultTheme.fontWeight, 'fontWeight')
389
- allValues.gap = combineKeys(configFile.theme, base.spacing, 'gap')
390
- allValues.indentionLevel = combineKeys(configFile.theme, base.spacing, 'indentionLevel')
391
- allValues.keyboardToolbarHeight = combineKeys(configFile.theme, base.spacing, 'keyboardToolbarHeight')
392
- allValues.leftButtonPadding = combineKeys(configFile.theme, base.spacing, 'leftButtonPadding')
393
- allValues.leftWidth = combineKeys(configFile.theme, base.width, 'leftWidth')
394
- allValues.lines = combineKeys(configFile.theme, { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10 }, 'lines')
395
- allValues.maxElevation = combineKeys(configFile.theme, base.spacing, 'maxElevation')
396
- allValues.maxLines = combineKeys(configFile.theme, { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10 }, 'maxLines')
397
- allValues.maxRowHeight = combineKeys(configFile.theme, base.height, 'maxRowHeight')
398
- allValues.maxZoomScale = combineKeys(configFile.theme, { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5 }, 'maxZoomScale')
399
- allValues.minimumFontSize = combineKeys(configFile.theme, base.fontSize, 'minimumFontSize')
400
- allValues.minRowHeight = combineKeys(configFile.theme, base.height, 'minRowHeight')
401
- allValues.minZoomScale = combineKeys(configFile.theme, { 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5 }, 'minZoomScale')
402
- allValues.offsets = combineKeys(configFile.theme, base.spacing, 'offsets')
403
- allValues.opacity = combineKeys(configFile.theme, defaultTheme.opacity, 'opacity')
404
- allValues.padding = combineKeys(configFile.theme, base.spacing, 'padding')
405
- allValues.pagingControlAlpha = combineKeys(configFile.theme, defaultTheme.opacity, 'pagingControlAlpha')
406
- allValues.pagingControlHeight = combineKeys(configFile.theme, base.height, 'pagingControlHeight')
407
- allValues.pagingControlTimeout = combineKeys(configFile.theme, base.delay, 'pagingControlTimeout')
408
- allValues.repeat = combineKeys(configFile.theme, { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, infinite: -1 }, 'repeat')
409
- allValues.repeatCount = combineKeys(configFile.theme, { 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, infinite: -1 }, 'repeatCount')
410
- allValues.rightButtonPadding = combineKeys(configFile.theme, base.spacing, 'rightButtonPadding')
411
- allValues.rightWidth = combineKeys(configFile.theme, base.width, 'rightWidth')
412
- allValues.rotate = combineKeys(configFile.theme, defaultTheme.rotate, 'rotate')
413
-
414
- // ! Custom Color properties
415
- // INFO: colorProperties: For glossary generator only... Do not move from this position.
416
- allValues.colorProperties = {}
417
-
418
- allValues.activeTintColor = combineKeys(configFile.theme, base.colors, 'activeTintColor')
419
- allValues.activeTitleColor = combineKeys(configFile.theme, base.colors, 'activeTitleColor')
420
- allValues.backgroundColor = combineKeys(configFile.theme, base.colors, 'backgroundColor')
421
- allValues.backgroundDisabledColor = combineKeys(configFile.theme, base.colors, 'backgroundDisabledColor')
422
- allValues.backgroundFocusedColor = combineKeys(configFile.theme, base.colors, 'backgroundFocusedColor')
423
- allValues.backgroundGradient = combineKeys(configFile.theme, base.colors, 'backgroundGradient')
424
- allValues.backgroundSelectedColor = combineKeys(configFile.theme, base.colors, 'backgroundSelectedColor')
425
- allValues.backgroundSelectedGradient = combineKeys(configFile.theme, base.colors, 'backgroundSelectedGradient')
426
- allValues.badgeColor = combineKeys(configFile.theme, base.colors, 'badgeColor')
427
- allValues.barColor = combineKeys(configFile.theme, base.colors, 'barColor')
428
- allValues.borderColor = combineKeys(configFile.theme, base.colors, 'borderColor')
429
- allValues.currentPageIndicatorColor = combineKeys(configFile.theme, base.colors, 'currentPageIndicatorColor')
430
- allValues.dateTimeColor = combineKeys(configFile.theme, base.colors, 'dateTimeColor')
431
- allValues.disabledColor = combineKeys(configFile.theme, base.colors, 'disabledColor')
432
- allValues.highlightedColor = combineKeys(configFile.theme, base.colors, 'highlightedColor')
433
- allValues.hintTextColor = combineKeys(configFile.theme, base.colors, 'hintTextColor')
434
- allValues.imageTouchFeedbackColor = combineKeys(configFile.theme, base.colors, 'imageTouchFeedbackColor')
435
- allValues.pageIndicatorColor = combineKeys(configFile.theme, base.colors, 'pageIndicatorColor')
436
- allValues.pagingControlColor = combineKeys(configFile.theme, base.colors, 'pagingControlColor')
437
- allValues.pullBackgroundColor = combineKeys(configFile.theme, base.colors, 'pullBackgroundColor')
438
- allValues.resultsBackgroundColor = combineKeys(configFile.theme, base.colors, 'resultsBackgroundColor')
439
- allValues.resultsSeparatorColor = combineKeys(configFile.theme, base.colors, 'resultsSeparatorColor')
440
- allValues.selectedBackgroundColor = combineKeys(configFile.theme, base.colors, 'selectedBackgroundColor')
441
- allValues.selectedBackgroundGradient = combineKeys(configFile.theme, base.colors, 'selectedBackgroundGradient')
442
- allValues.selectedColor = combineKeys(configFile.theme, base.colors, 'selectedColor')
443
- allValues.separatorColor = combineKeys(configFile.theme, base.colors, 'separatorColor')
444
- allValues.shadowColor = combineKeys(configFile.theme, base.colors, 'shadowColor')
445
- allValues.tabsBackgroundColor = combineKeys(configFile.theme, base.colors, 'tabsBackgroundColor')
446
- allValues.tabsBackgroundDisabledColor = combineKeys(configFile.theme, base.colors, 'tabsBackgroundDisabledColor')
447
- allValues.tabsBackgroundFocusedColor = combineKeys(configFile.theme, base.colors, 'tabsBackgroundFocusedColor')
448
- allValues.tabsBackgroundSelectedColor = combineKeys(configFile.theme, base.colors, 'tabsBackgroundSelectedColor')
449
- allValues.textColor = combineKeys(configFile.theme, base.colors, 'textColor')
450
- allValues.tintColor = combineKeys(configFile.theme, base.colors, 'tintColor')
451
- allValues.titleColor = combineKeys(configFile.theme, base.colors, 'titleColor')
452
- allValues.titleDisabledColor = combineKeys(configFile.theme, base.colors, 'titleDisabledColor')
453
- allValues.titleFocusedColor = combineKeys(configFile.theme, base.colors, 'titleFocusedColor')
454
- allValues.titleHighlightedColor = combineKeys(configFile.theme, base.colors, 'titleHighlightedColor')
455
- allValues.titleSelectedColor = combineKeys(configFile.theme, base.colors, 'titleSelectedColor')
456
- allValues.touchFeedbackColor = combineKeys(configFile.theme, base.colors, 'touchFeedbackColor')
457
- allValues.viewShadowColor = combineKeys(configFile.theme, base.colors, 'viewShadowColor')
458
- allValues.navTintColor = combineKeys(configFile.theme, base.colors, 'navTintColor')
459
-
460
- return allValues
461
- }
@@ -73,6 +73,26 @@ export const IPHONE_SCALES = Object.freeze([
73
73
  { suffix: '@3x', factor: 3 / 4 }
74
74
  ])
75
75
 
76
+ // Resolve target dimensions for a single scale.
77
+ // `factor * 4` recovers the integer multiplier (1, 1.5, 2, 3, 4 for Android;
78
+ // 1, 2, 3 for iPhone) only because every entry in *_SCALES is normalized to
79
+ // n/4 with the largest scale (xxxhdpi/@4x) at 4/4. If a future density is
80
+ // added beyond xxxhdpi, this conversion factor needs to be revisited.
81
+ function computeScaleTarget(srcMeta, factor, baseWidth) {
82
+ if (baseWidth == null) {
83
+ return {
84
+ targetWidth: Math.max(1, Math.round(srcMeta.width * factor)),
85
+ targetHeight: Math.max(1, Math.round(srcMeta.height * factor))
86
+ }
87
+ }
88
+ const multiplier = factor * 4
89
+ const aspect = srcMeta.width > 0 ? (srcMeta.height / srcMeta.width) : 1
90
+ return {
91
+ targetWidth: Math.max(1, Math.round(baseWidth * multiplier)),
92
+ targetHeight: Math.max(1, Math.round(baseWidth * multiplier * aspect))
93
+ }
94
+ }
95
+
76
96
  /**
77
97
  * Scale a source image into all Android density variants.
78
98
  *
@@ -85,13 +105,12 @@ export const IPHONE_SCALES = Object.freeze([
85
105
  * @returns {Promise<string[]>} Paths written
86
106
  */
87
107
  export async function genAndroidScales(sourceFile, relPath, androidBaseDir, opts = {}) {
88
- const { format = null, quality = 85 } = opts
108
+ const { format = null, quality = 85, baseWidth = null } = opts
89
109
  const src = await readSource(sourceFile)
90
110
  const written = []
91
111
 
92
112
  for (const { name, factor } of ANDROID_SCALES) {
93
- const targetWidth = Math.max(1, Math.round(src.meta.width * factor))
94
- const targetHeight = Math.max(1, Math.round(src.meta.height * factor))
113
+ const { targetWidth, targetHeight } = computeScaleTarget(src.meta, factor, baseWidth)
95
114
 
96
115
  const outDir = path.join(androidBaseDir, name, path.dirname(relPath))
97
116
  fs.mkdirSync(outDir, { recursive: true })
@@ -113,7 +132,7 @@ export async function genAndroidScales(sourceFile, relPath, androidBaseDir, opts
113
132
  * @returns {Promise<string[]>} Paths written
114
133
  */
115
134
  export async function genIphoneScales(sourceFile, relPath, iphoneBaseDir, opts = {}) {
116
- const { format = null, quality = 85 } = opts
135
+ const { format = null, quality = 85, baseWidth = null } = opts
117
136
  const src = await readSource(sourceFile)
118
137
  const written = []
119
138
 
@@ -122,8 +141,7 @@ export async function genIphoneScales(sourceFile, relPath, iphoneBaseDir, opts =
122
141
  fs.mkdirSync(outDir, { recursive: true })
123
142
 
124
143
  for (const { suffix, factor } of IPHONE_SCALES) {
125
- const targetWidth = Math.max(1, Math.round(src.meta.width * factor))
126
- const targetHeight = Math.max(1, Math.round(src.meta.height * factor))
144
+ const { targetWidth, targetHeight } = computeScaleTarget(src.meta, factor, baseWidth)
127
145
 
128
146
  // SVG sources can't be written as SVG by Sharp — fall back to PNG if the
129
147
  // user didn't specify an explicit output format.
@@ -35,6 +35,7 @@ export async function runImages(opts) {
35
35
  iphoneOnly = false,
36
36
  format = null,
37
37
  quality = 85,
38
+ baseWidth = null,
38
39
  dryRun = false,
39
40
  yes = false,
40
41
  confirmOverwrites = true
@@ -49,6 +50,11 @@ export async function runImages(opts) {
49
50
 
50
51
  const files = collectImageFiles(source)
51
52
 
53
+ if (baseWidth == null && files.some(f => path.extname(f).toLowerCase() === '.svg')) {
54
+ logger.warning('⚠ SVG source detected without --width. Output sizes will be derived from each SVG\'s viewBox (treated as a 4× master).')
55
+ logger.warning(' For SVGs from vector editors with disproportionate viewBoxes, pass --width <n> (e.g. --width 256) to pin the @1x/mdpi width.')
56
+ }
57
+
52
58
  console.log()
53
59
  mainLogger.info('Generating multi-density image variants...')
54
60
  console.log()
@@ -60,6 +66,7 @@ export async function runImages(opts) {
60
66
  if (!androidOnly) platforms.push('iPhone (@1x, @2x, @3x)')
61
67
  logger.property('Platforms: ', platforms.join(' + '))
62
68
  if (format) logger.property('Format: ', `convert all to ${format}`)
69
+ if (baseWidth != null) logger.property('Width: ', `${baseWidth} px @1x/mdpi`)
63
70
  if (dryRun) logger.warning('DRY RUN — no files will be written')
64
71
 
65
72
  if (files.length === 0) {
@@ -115,11 +122,11 @@ export async function runImages(opts) {
115
122
  if (dryRun) continue
116
123
 
117
124
  if (!iphoneOnly) {
118
- const androidFiles = await genAndroidScales(file, relPath, androidBaseDir, { format, quality })
125
+ const androidFiles = await genAndroidScales(file, relPath, androidBaseDir, { format, quality, baseWidth })
119
126
  written.push(...androidFiles)
120
127
  }
121
128
  if (!androidOnly) {
122
- const iphoneFiles = await genIphoneScales(file, relPath, iphoneBaseDir, { format, quality })
129
+ const iphoneFiles = await genIphoneScales(file, relPath, iphoneBaseDir, { format, quality, baseWidth })
123
130
  written.push(...iphoneFiles)
124
131
  }
125
132
  }
@@ -14,6 +14,7 @@ import _ from 'lodash'
14
14
  import chalk from 'chalk'
15
15
  import * as helpers from '../../shared/helpers.js'
16
16
  import { logger } from '../../shared/logger.js'
17
+ import { deriveAlphaKey } from '../../shared/semantic-helpers.js'
17
18
  import {
18
19
  // eslint-disable-next-line camelcase
19
20
  projectsTailwind_TSS,
@@ -191,10 +192,20 @@ export function purgeTailwind(uniqueClasses, debug = false) {
191
192
  const opacityIndex = _.findIndex(tailwindClasses, line => line.startsWith(`'.${opacityValue.className}'`))
192
193
 
193
194
  const classProperties = tailwindClasses[opacityIndex]
194
- if (opacityIndex > -1 && classProperties.includes('#')) {
195
- // ! TODO: Check if color value is a hex value!! (if not, they are using rbg, rgba or semantic colors)
196
- // ! In other words, we need to validate the color value, before we can alter its opacity.
197
- const defaultHexValue = (classProperties.includes('from')) ? classProperties.match(/#[0-9a-f]{6}/g)[1] : classProperties.match(/#[0-9a-f]{6}/i)[0]
195
+ if (opacityIndex > -1 && classProperties && !classProperties.includes('#')) {
196
+ const derivedLine = tryDeriveSemanticOpacityLine(classProperties, opacityValue)
197
+ if (derivedLine) {
198
+ purgedClasses += switchPlatform(helpers.checkPlatformAndDevice(derivedLine, opacityValue.classNameWithTransparency))
199
+ } else {
200
+ console.warn('')
201
+ console.warn(chalk.yellow(` Skipping ".${opacityValue.className}/${opacityValue.decimalValue}" — semantic color, no hex to blend.`))
202
+ console.warn(chalk.yellow(` Use a PurgeTSS built-in color, bg-(#AARRGGBB), or "purgetss semantic --single ... --alpha ${opacityValue.decimalValue}".`))
203
+ console.warn('')
204
+ }
205
+ }
206
+ if (opacityIndex > -1 && classProperties && classProperties.includes('#')) {
207
+ const hexMatches = classProperties.match(/#[0-9a-f]{6}/gi)
208
+ const defaultHexValue = (classProperties.includes('from')) ? hexMatches[1] : hexMatches[0]
198
209
  let classWithoutDecimalOpacity = `${classProperties.replace(new RegExp(defaultHexValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), `#${opacityValue.transparency}${defaultHexValue.substring(1)}`)}`
199
210
  // Special case: #000000
200
211
  if (classProperties.includes('from') && defaultHexValue === '#000000') classWithoutDecimalOpacity = classWithoutDecimalOpacity.replace('00000000', '000000')
@@ -216,6 +227,31 @@ export function purgeTailwind(uniqueClasses, debug = false) {
216
227
  return purgedClasses
217
228
  }
218
229
 
230
+ // Auto-derive a semantic key with applied alpha and emit a TSS line for the
231
+ // `class/N` form. Returns the rewritten line (with selector renamed to include
232
+ // `/N` and the semantic value swapped for the derived key), or `null` when no
233
+ // candidate matches an entry in semantic.colors.json. Conflict errors from
234
+ // `deriveAlphaKey` propagate naturally.
235
+ function tryDeriveSemanticOpacityLine(classProperties, opacityValue) {
236
+ const bodyMatch = classProperties.match(/\{([^}]*)\}/)
237
+ if (!bodyMatch) return null
238
+ const candidates = (bodyMatch[1].match(/'([^']+)'/g) || [])
239
+ .map(m => m.slice(1, -1))
240
+ .filter(v => !v.startsWith('#'))
241
+ for (const candidate of candidates) {
242
+ const derivedKey = deriveAlphaKey(candidate, opacityValue.decimalValue)
243
+ if (derivedKey) {
244
+ let line = classProperties.replace(new RegExp(`'${candidate}'`, 'g'), `'${derivedKey}'`)
245
+ line = line.replace(
246
+ `'.${opacityValue.className}'`,
247
+ `'.${opacityValue.className}/${opacityValue.decimalValue}'`
248
+ )
249
+ return line
250
+ }
251
+ }
252
+ return null
253
+ }
254
+
219
255
  /**
220
256
  * Switch platform specific styles - COPIED exactly from original switchPlatform() function
221
257
  * NO CHANGES to logic, preserving 100% of original functionality
@@ -1,21 +1,2 @@
1
- // Import customRules function for resetStyles
2
- import { customRules } from './utils.js'
3
-
4
1
  // Global configurations
5
2
  export const globalOptions = {}
6
-
7
- /**
8
- * Reset styles for common Titanium components
9
- * Applies default styles to ImageView, View, and Window
10
- * @returns {string} Generated reset styles
11
- */
12
- export function resetStyles() {
13
- let convertedStyles = '\n// Custom Styles and Resets\n'
14
-
15
- convertedStyles += customRules({ ios: { hires: true } }, 'ImageView')
16
- // convertedStyles += customRules({ default: { width: 'Ti.UI.FILL', height: 'Ti.UI.SIZE' } }, 'Label');
17
- convertedStyles += customRules({ default: { width: 'Ti.UI.SIZE', height: 'Ti.UI.SIZE' } }, 'View')
18
- convertedStyles += customRules({ default: { backgroundColor: '#ffffff' } }, 'Window')
19
-
20
- return convertedStyles
21
- }