@codeleap/styles 5.8.2 → 5.8.4

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.
Files changed (69) hide show
  1. package/package.json +9 -15
  2. package/package.json.bak +8 -14
  3. package/src/classes/Cacher.ts +169 -0
  4. package/src/classes/StaleControl.ts +125 -0
  5. package/src/classes/StyleCache.ts +116 -0
  6. package/src/classes/StylePersistor.ts +62 -0
  7. package/src/{lib → classes}/StyleRegistry.ts +7 -12
  8. package/src/classes/index.ts +2 -0
  9. package/src/classes/tests/Cache.spec.ts +371 -0
  10. package/src/classes/tests/StaleControl.spec.ts +175 -0
  11. package/src/classes/tests/StyleCache.spec.ts +452 -0
  12. package/src/classes/tests/StylePersistor.spec.ts +231 -0
  13. package/src/{lib/constants.ts → constants.ts} +1 -0
  14. package/src/hooks/index.ts +4 -0
  15. package/src/hooks/tests/useCompositionStyles.spec.ts +107 -0
  16. package/src/hooks/tests/useStyleObserver.spec.ts +89 -0
  17. package/src/hooks/useCompositionStyles.ts +33 -0
  18. package/src/hooks/useNestedStylesByKey.ts +13 -0
  19. package/src/hooks/useStyleObserver.ts +19 -0
  20. package/src/hooks/useTheme.ts +16 -0
  21. package/src/index.ts +9 -5
  22. package/src/lib/createStyles.ts +10 -1
  23. package/src/lib/createTheme.ts +22 -13
  24. package/src/lib/index.ts +1 -10
  25. package/src/lib/tests/createStyles.spec.ts +151 -0
  26. package/src/tests/colors/baseColors.ts +166 -0
  27. package/src/tests/colors/darkMode.ts +232 -0
  28. package/src/tests/colors/lightMode.ts +285 -0
  29. package/src/tests/measures.ts +31 -0
  30. package/src/tests/theme.ts +58 -0
  31. package/src/theme/generateColorScheme.ts +53 -0
  32. package/src/theme/index.ts +3 -0
  33. package/src/theme/tests/generateColorScheme.spec.ts +118 -0
  34. package/src/theme/tests/themeStore.spec.ts +698 -0
  35. package/src/theme/tests/validateTheme.spec.ts +173 -0
  36. package/src/{lib → theme}/themeStore.ts +68 -3
  37. package/src/{lib → theme}/validateTheme.ts +13 -0
  38. package/src/tools/colors.ts +83 -39
  39. package/src/tools/deepClone.ts +10 -0
  40. package/src/tools/deepmerge.ts +10 -0
  41. package/src/{lib → tools}/hashKey.ts +7 -0
  42. package/src/tools/index.ts +6 -1
  43. package/src/tools/minifier.ts +38 -0
  44. package/src/tools/tests/colors.spec.ts +233 -0
  45. package/src/tools/tests/deepClone.spec.ts +102 -0
  46. package/src/tools/tests/deepmerge.spec.ts +155 -0
  47. package/src/tools/tests/hashKey.spec.ts +69 -0
  48. package/src/tools/tests/minifier.spec.ts +173 -0
  49. package/src/types/store.ts +2 -2
  50. package/src/types/style.ts +3 -3
  51. package/src/types/theme.ts +4 -4
  52. package/src/{lib/utils.ts → utils.ts} +3 -3
  53. package/src/{lib → variants}/borderCreator.ts +2 -2
  54. package/src/{lib → variants}/createAppVariants.ts +1 -1
  55. package/src/{lib → variants}/dynamicVariants.ts +1 -1
  56. package/src/variants/index.ts +6 -0
  57. package/src/{lib → variants}/spacing.ts +37 -24
  58. package/src/variants/tests/borderCreator.spec.ts +180 -0
  59. package/src/variants/tests/dynamicVariants.spec.ts +194 -0
  60. package/src/variants/tests/spacing.spec.ts +177 -0
  61. package/src/lib/Cacher.ts +0 -112
  62. package/src/lib/StaleControl.ts +0 -73
  63. package/src/lib/StyleCache.ts +0 -81
  64. package/src/lib/StylePersistor.ts +0 -28
  65. package/src/lib/hooks.ts +0 -64
  66. package/src/lib/minifier.ts +0 -20
  67. /package/src/{lib → tools}/multiplierProperty.ts +0 -0
  68. /package/src/{lib → variants}/defaultVariants.ts +0 -0
  69. /package/src/{lib → variants}/mediaQuery.ts +0 -0
@@ -0,0 +1,173 @@
1
+ import { test, expect, describe } from 'bun:test'
2
+ import { compress, decompress, minifier } from '../minifier'
3
+
4
+ describe('minifier', () => {
5
+ describe('compress', () => {
6
+ test('should compress string values', () => {
7
+ const original = 'hello world'
8
+ const compressed = compress(original)
9
+
10
+ expect(typeof compressed).toBe('string')
11
+ expect(compressed).not.toBe(original)
12
+ expect(compressed.length).toBeGreaterThan(0)
13
+ })
14
+
15
+ test('should compress objects', () => {
16
+ const original = { name: 'John', age: 30, items: [1, 2, 3] }
17
+ const compressed = compress(original)
18
+
19
+ expect(typeof compressed).toBe('string')
20
+ expect(compressed).not.toEqual(original)
21
+ })
22
+
23
+ test('should return falsy values unchanged', () => {
24
+ expect(compress(null)).toBe(null)
25
+ expect(compress(undefined)).toBe(undefined)
26
+ expect(compress('')).toBe('')
27
+ expect(compress(0)).toBe(0)
28
+ expect(compress(false)).toBe(false)
29
+ })
30
+
31
+ test('should handle arrays', () => {
32
+ const original = [1, 2, { a: 'test' }, [4, 5]]
33
+ const compressed = compress(original)
34
+
35
+ expect(typeof compressed).toBe('string')
36
+ expect(compressed.length).toBeGreaterThan(0)
37
+ })
38
+
39
+ test('should handle nested objects', () => {
40
+ const original = {
41
+ level1: {
42
+ level2: {
43
+ level3: {
44
+ data: 'nested value',
45
+ numbers: [1, 2, 3, 4, 5]
46
+ }
47
+ }
48
+ }
49
+ }
50
+ const compressed = compress(original)
51
+
52
+ expect(typeof compressed).toBe('string')
53
+ expect(compressed.length).toBeGreaterThan(0)
54
+ })
55
+ })
56
+
57
+ describe('decompress', () => {
58
+ test('should decompress string values', () => {
59
+ const original = 'hello world'
60
+ const compressed = compress(original)
61
+ const decompressed = decompress(compressed)
62
+
63
+ expect(decompressed).toBe(original)
64
+ })
65
+
66
+ test('should decompress objects', () => {
67
+ const original = { name: 'John', age: 30, items: [1, 2, 3] }
68
+ const compressed = compress(original)
69
+ const decompressed = decompress(compressed)
70
+
71
+ expect(decompressed).toEqual(original)
72
+ expect(decompressed).not.toBe(original) // Different object reference
73
+ })
74
+
75
+ test('should return falsy values unchanged', () => {
76
+ expect(decompress(null)).toBe(null)
77
+ expect(decompress(undefined)).toBe(undefined)
78
+ expect(decompress('')).toBe('')
79
+ expect(decompress(0)).toBe(0)
80
+ expect(decompress(false)).toBe(false)
81
+ })
82
+
83
+ test('should handle arrays', () => {
84
+ const original = [1, 2, { a: 'test' }, [4, 5]]
85
+ const compressed = compress(original)
86
+ const decompressed = decompress(compressed)
87
+
88
+ expect(decompressed).toEqual(original)
89
+ })
90
+
91
+ test('should handle nested objects', () => {
92
+ const original = {
93
+ level1: {
94
+ level2: {
95
+ level3: {
96
+ data: 'nested value',
97
+ numbers: [1, 2, 3, 4, 5]
98
+ }
99
+ }
100
+ }
101
+ }
102
+ const compressed = compress(original)
103
+ const decompressed = decompress(compressed)
104
+
105
+ expect(decompressed).toEqual(original)
106
+ })
107
+ })
108
+
109
+ describe('roundtrip compression', () => {
110
+ test('should maintain data integrity through compress/decompress cycle', () => {
111
+ const testCases = [
112
+ 'simple string',
113
+ { simple: 'object' },
114
+ [1, 2, 3, 4, 5],
115
+ { mixed: ['array', { nested: true }] },
116
+ 42,
117
+ true,
118
+ { date: '2023-01-01', count: 100 }
119
+ ]
120
+
121
+ testCases.forEach(original => {
122
+ const compressed = compress(original)
123
+ const decompressed = decompress(compressed)
124
+ expect(decompressed).toEqual(original)
125
+ })
126
+ })
127
+
128
+ test('should actually compress large repetitive data', () => {
129
+ const original = {
130
+ data: Array(1000).fill('repeated string data that should compress well')
131
+ }
132
+ const compressed = compress(original)
133
+ const originalStr = JSON.stringify(original)
134
+
135
+ expect(compressed.length).toBeLessThan(originalStr.length)
136
+
137
+ const decompressed = decompress(compressed)
138
+ expect(decompressed).toEqual(original)
139
+ })
140
+ })
141
+
142
+ describe('minifier object', () => {
143
+ test('should have compress and decompress methods', () => {
144
+ expect(typeof minifier.compress).toBe('function')
145
+ expect(typeof minifier.decompress).toBe('function')
146
+ })
147
+
148
+ test('should work the same as individual functions', () => {
149
+ const original = { test: 'data' }
150
+
151
+ const compressed1 = compress(original)
152
+ const compressed2 = minifier.compress(original)
153
+ expect(compressed1).toBe(compressed2)
154
+
155
+ const decompressed1 = decompress(compressed1)
156
+ const decompressed2 = minifier.decompress(compressed1)
157
+ expect(decompressed1).toEqual(decompressed2)
158
+ })
159
+ })
160
+
161
+ describe('error handling', () => {
162
+ test('should return null for invalid compressed data', () => {
163
+ const result = decompress('invalid-base64-data')
164
+ expect(result).toBe(null)
165
+ })
166
+
167
+ test('should throw error for non-JSON compressed data', () => {
168
+ // Create a valid base64 string that decompresses to non-JSON
169
+ const nonJsonCompressed = compress('valid data').slice(0, -1) + 'X' // Corrupt the data
170
+ expect(() => decompress(nonJsonCompressed)).toThrow()
171
+ })
172
+ })
173
+ })
@@ -1,5 +1,5 @@
1
1
  export interface StateStorage {
2
- getItem: (name: string) => string | null
3
- setItem: (name: string, value: string) => void
2
+ getItem: (name: string) => any | null
3
+ setItem: (name: string, value: any) => void
4
4
  removeItem: (name: string) => void
5
5
  }
@@ -1,6 +1,6 @@
1
- import { DynamicVariants } from '../lib/dynamicVariants'
2
- import { Queries } from '../lib/mediaQuery'
3
- import { DefaultVariants } from '../lib/defaultVariants'
1
+ import { DynamicVariants } from '../variants/dynamicVariants'
2
+ import { Queries } from '../variants/mediaQuery'
3
+ import { DefaultVariants } from '../variants/defaultVariants'
4
4
  import { AnyRecord, IAppVariants, IBreakpoints, ICSS, IEffects, ITheme } from './core'
5
5
  import { Multiplier, Spacing } from './spacing'
6
6
 
@@ -1,7 +1,7 @@
1
- import { BorderCreator } from '../lib/borderCreator'
2
- import { MediaQueries } from '../lib/mediaQuery'
3
- import type { DefaultVariants } from '../lib/defaultVariants'
4
- import { MultiplierFunction, Spacings } from '../lib/spacing'
1
+ import { BorderCreator } from '../variants/borderCreator'
2
+ import { MediaQueries } from '../variants/mediaQuery'
3
+ import type { DefaultVariants } from '../variants/defaultVariants'
4
+ import { MultiplierFunction, Spacings } from '../variants/spacing'
5
5
  import { ICSS, IEffect } from './core'
6
6
 
7
7
  type AnyMap = {
@@ -1,6 +1,6 @@
1
- import deepmerge from '@fastify/deepmerge'
2
- import { ICSS, StyledProp } from '../types'
3
- import { spacingShortVariants, spacingVariants } from '../types/spacing'
1
+ import { ICSS, StyledProp } from './types'
2
+ import { spacingShortVariants, spacingVariants } from './types/spacing'
3
+ import { deepmerge } from './tools'
4
4
 
5
5
  export function capitalize(str: string, reverse = false) {
6
6
  if (!str.length) return str
@@ -1,7 +1,7 @@
1
1
  import { IColors, ICSS } from '../types'
2
2
  import { borderDirection } from './dynamicVariants'
3
- import { themeStore } from './themeStore'
4
- import { capitalize } from './utils'
3
+ import { themeStore } from '../theme'
4
+ import { capitalize } from '../utils'
5
5
 
6
6
  type BorderCreatorArgs = {
7
7
  color: keyof IColors | (string & {})
@@ -1,5 +1,5 @@
1
1
  import { ICSS, ITheme } from '../types'
2
- import { themeStore } from './themeStore'
2
+ import { themeStore } from '../theme'
3
3
 
4
4
  type AppVariantsMap = {
5
5
  [x: string]: ICSS | ((theme: ITheme) => ICSS)
@@ -1,5 +1,5 @@
1
1
  import { IBorderRadius, IColors, IEffects } from '../types'
2
- import { capitalize } from './utils'
2
+ import { capitalize } from '../utils'
3
3
 
4
4
  export type VariantFunction = (value: any) => any
5
5
 
@@ -0,0 +1,6 @@
1
+ export * from './borderCreator'
2
+ export * from './createAppVariants'
3
+ export * from './defaultVariants'
4
+ export * from './dynamicVariants'
5
+ export * from './mediaQuery'
6
+ export * from './spacing'
@@ -7,9 +7,9 @@ export type Spacings<T extends string, S = boolean> = {
7
7
  [Property in (S extends boolean ? SpacingVariants : SpacingShortVariants) as `${T}${string & Property}`]: MultiplierFunction;
8
8
  } & {
9
9
  [Property in T]: (multiplier: number) => ICSS;
10
- } & {
11
- value: (multiplier: number) => number
12
- }
10
+ } & {
11
+ value: (multiplier: number) => number
12
+ }
13
13
 
14
14
  const shortMapValues = {
15
15
  'x': 'Horizontal',
@@ -22,59 +22,72 @@ const shortMapValues = {
22
22
  'p': 'padding'
23
23
  }
24
24
 
25
+ const shortPositionMap = {
26
+ 'x': 'Horizontal',
27
+ 'y': 'Vertical',
28
+ 'l': 'Left',
29
+ 'r': 'Right',
30
+ 't': 'Top',
31
+ 'b': 'Bottom'
32
+ }
33
+
25
34
  export function spacingFactory<T extends string>(
26
35
  base: number,
27
36
  spacingProperty: T,
28
37
  isShort: boolean = false
29
38
  ): any {
30
- const property = isShort ? shortMapValues[spacingProperty as string] : spacingProperty
39
+ const baseProperty = isShort ? shortMapValues[spacingProperty as keyof typeof shortMapValues] : spacingProperty
31
40
  const positions = isShort ? spacingShortVariants : spacingVariants
32
41
 
33
42
  const spacings = {
34
- [`${spacingProperty}`]: (n: number | string) => ({
35
- [`${property}`]: base * Number(n),
36
- }),
43
+ [`${spacingProperty}`]: (n: number | string) => {
44
+ if (n === 'auto') {
45
+ return { [baseProperty]: 'auto' }
46
+ }
47
+ return { [baseProperty]: base * Number(n) }
48
+ },
37
49
  }
38
50
 
39
51
  for (const _position of positions) {
40
- const position = isShort ? shortMapValues[_position] : _position
52
+ const position = isShort
53
+ ? shortPositionMap[_position as keyof typeof shortPositionMap] || _position
54
+ : _position
55
+
41
56
  const key = `${spacingProperty}${_position}`
42
57
 
43
58
  let getter = null
44
59
 
45
60
  switch (position) {
46
61
  case 'Horizontal':
47
- getter = (value: number) => ({
48
- [`${property}Left`]: value,
49
- [`${property}Right`]: value,
62
+ getter = (value: number | string) => ({
63
+ [`${baseProperty}Left`]: value,
64
+ [`${baseProperty}Right`]: value,
50
65
  })
51
66
  break
52
67
  case 'Vertical':
53
- getter = (value: number) => ({
54
- [`${property}Top`]: value,
55
- [`${property}Bottom`]: value,
68
+ getter = (value: number | string) => ({
69
+ [`${baseProperty}Top`]: value,
70
+ [`${baseProperty}Bottom`]: value,
56
71
  })
57
72
  break
58
73
  case '':
59
- getter = (value: number) => ({
60
- [`${property}Top`]: value,
61
- [`${property}Left`]: value,
62
- [`${property}Right`]: value,
63
- [`${property}Bottom`]: value,
74
+ getter = (value: number | string) => ({
75
+ [`${baseProperty}Top`]: value,
76
+ [`${baseProperty}Right`]: value,
77
+ [`${baseProperty}Bottom`]: value,
78
+ [`${baseProperty}Left`]: value,
64
79
  })
65
80
  break
66
81
  default:
67
- getter = (value: number) => ({
68
- [`${property}${position}`]: value,
82
+ getter = (value: number | string) => ({
83
+ [`${baseProperty}${position}`]: value,
69
84
  })
70
85
  break
71
86
  }
72
87
 
73
88
  spacings[key] = (n: number | string) => {
74
- if (n == 'auto') return getter('auto')
75
-
89
+ if (n === 'auto') return getter('auto')
76
90
  const value = base * Number(n)
77
-
78
91
  return getter(value)
79
92
  }
80
93
  }
@@ -0,0 +1,180 @@
1
+ import { describe, expect, test, beforeEach } from 'bun:test'
2
+ import { borderCreator } from '../borderCreator'
3
+ import { mockTheme } from '../../tests/theme'
4
+
5
+ describe('borderCreator', () => {
6
+ beforeEach(() => {
7
+ mockTheme()
8
+ })
9
+
10
+ test('should create border with default parameters', () => {
11
+ const result = borderCreator({ color: '#007bff' })
12
+
13
+ expect(result).toEqual({
14
+ borderTopColor: '#007bff',
15
+ borderTopWidth: 1,
16
+ borderTopStyle: 'solid',
17
+ borderRightColor: '#007bff',
18
+ borderRightWidth: 1,
19
+ borderRightStyle: 'solid',
20
+ borderBottomColor: '#007bff',
21
+ borderBottomWidth: 1,
22
+ borderBottomStyle: 'solid',
23
+ borderLeftColor: '#007bff',
24
+ borderLeftWidth: 1,
25
+ borderLeftStyle: 'solid'
26
+ })
27
+ })
28
+
29
+ test('should create border with custom width', () => {
30
+ const result = borderCreator({
31
+ color: '#6c757d',
32
+ width: 2
33
+ })
34
+
35
+ expect(result).toEqual({
36
+ borderTopColor: '#6c757d',
37
+ borderTopWidth: 2,
38
+ borderTopStyle: 'solid',
39
+ borderRightColor: '#6c757d',
40
+ borderRightWidth: 2,
41
+ borderRightStyle: 'solid',
42
+ borderBottomColor: '#6c757d',
43
+ borderBottomWidth: 2,
44
+ borderBottomStyle: 'solid',
45
+ borderLeftColor: '#6c757d',
46
+ borderLeftWidth: 2,
47
+ borderLeftStyle: 'solid'
48
+ })
49
+ })
50
+
51
+ test('should create border with custom style', () => {
52
+ const result = borderCreator({
53
+ color: '#28a745',
54
+ style: 'dashed'
55
+ })
56
+
57
+ expect(result).toEqual({
58
+ borderTopColor: '#28a745',
59
+ borderTopWidth: 1,
60
+ borderTopStyle: 'dashed',
61
+ borderRightColor: '#28a745',
62
+ borderRightWidth: 1,
63
+ borderRightStyle: 'dashed',
64
+ borderBottomColor: '#28a745',
65
+ borderBottomWidth: 1,
66
+ borderBottomStyle: 'dashed',
67
+ borderLeftColor: '#28a745',
68
+ borderLeftWidth: 1,
69
+ borderLeftStyle: 'dashed'
70
+ })
71
+ })
72
+
73
+ test('should create border for specific directions', () => {
74
+ const result = borderCreator({
75
+ color: '#dc3545',
76
+ directions: ['top', 'bottom']
77
+ })
78
+
79
+ expect(result).toEqual({
80
+ borderTopColor: '#dc3545',
81
+ borderTopWidth: 1,
82
+ borderTopStyle: 'solid',
83
+ borderBottomColor: '#dc3545',
84
+ borderBottomWidth: 1,
85
+ borderBottomStyle: 'solid'
86
+ })
87
+
88
+ const leftResult = borderCreator({
89
+ color: '#ffc107',
90
+ directions: ['left']
91
+ })
92
+
93
+ expect(leftResult).toEqual({
94
+ borderLeftColor: '#ffc107',
95
+ borderLeftWidth: 1,
96
+ borderLeftStyle: 'solid'
97
+ })
98
+ })
99
+
100
+ test('should handle string width values', () => {
101
+ const result = borderCreator({
102
+ color: '#17a2b8',
103
+ width: '2px'
104
+ })
105
+
106
+ expect(result).toEqual({
107
+ borderTopColor: '#17a2b8',
108
+ borderTopWidth: '2px',
109
+ borderTopStyle: 'solid',
110
+ borderRightColor: '#17a2b8',
111
+ borderRightWidth: '2px',
112
+ borderRightStyle: 'solid',
113
+ borderBottomColor: '#17a2b8',
114
+ borderBottomWidth: '2px',
115
+ borderBottomStyle: 'solid',
116
+ borderLeftColor: '#17a2b8',
117
+ borderLeftWidth: '2px',
118
+ borderLeftStyle: 'solid'
119
+ })
120
+ })
121
+
122
+ test('should handle custom color strings (not from theme)', () => {
123
+ const result = borderCreator({
124
+ color: '#ff0000',
125
+ width: 3
126
+ })
127
+
128
+ expect(result).toEqual({
129
+ borderTopColor: '#ff0000',
130
+ borderTopWidth: 3,
131
+ borderTopStyle: 'solid',
132
+ borderRightColor: '#ff0000',
133
+ borderRightWidth: 3,
134
+ borderRightStyle: 'solid',
135
+ borderBottomColor: '#ff0000',
136
+ borderBottomWidth: 3,
137
+ borderBottomStyle: 'solid',
138
+ borderLeftColor: '#ff0000',
139
+ borderLeftWidth: 3,
140
+ borderLeftStyle: 'solid'
141
+ })
142
+ })
143
+
144
+ test('should handle empty directions array', () => {
145
+ const result = borderCreator({
146
+ color: '#000',
147
+ directions: []
148
+ })
149
+
150
+ expect(result).toEqual({})
151
+ })
152
+
153
+ test('should handle single direction', () => {
154
+ const result = borderCreator({
155
+ color: '#f8f9fa',
156
+ directions: ['right']
157
+ })
158
+
159
+ expect(result).toEqual({
160
+ borderRightColor: '#f8f9fa',
161
+ borderRightWidth: 1,
162
+ borderRightStyle: 'solid'
163
+ })
164
+ })
165
+
166
+ test('should handle all border directions individually', () => {
167
+ const directions = ['top', 'right', 'bottom', 'left'] as const
168
+
169
+ directions.forEach(direction => {
170
+ const result = borderCreator({
171
+ color: 'primary',
172
+ directions: [direction]
173
+ })
174
+
175
+ expect(result).toHaveProperty(`border${direction.charAt(0).toUpperCase() + direction.slice(1)}Color`)
176
+ expect(result).toHaveProperty(`border${direction.charAt(0).toUpperCase() + direction.slice(1)}Width`)
177
+ expect(result).toHaveProperty(`border${direction.charAt(0).toUpperCase() + direction.slice(1)}Style`)
178
+ })
179
+ })
180
+ })