lumina-sass 2.1.4 → 2.3.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/README.md CHANGED
@@ -104,6 +104,7 @@ A complete set of flexbox mixins and maps to help you build layouts quickly.
104
104
  To learn how to contribute or understand the release process, please see:
105
105
 
106
106
  - [**Development Guide**](docs/developer/development.md) - Project structure and setup rules.
107
+ - [**Testing Guide**](docs/developer/testing.md) - How to write and run Sass unit tests.
107
108
  - [**Releasing & Publishing**](docs/developer/releasing.md) - Details on the release process.
108
109
 
109
110
  ---
@@ -182,7 +183,11 @@ lumina-sass/
182
183
  ---
183
184
 
184
185
  ## 6️⃣ Testing & Verification Workflow
185
- 1. **Local import test**
186
+ 1. **Run Unit Tests**
187
+ ```bash
188
+ npm test
189
+ ```
190
+ 2. **Local import test**
186
191
  ```bash
187
192
  node -e "import 'lumina-sass/flexbox'" # should succeed
188
193
  node -e "import 'lumina-sass/utils'" # should fail
@@ -217,6 +222,7 @@ lumina-sass/
217
222
  | Activate LTS Node | `fnm use lts` |
218
223
  | Install dependencies | `npm install` |
219
224
  | Build the package | `npm run build` |
225
+ | Run tests | `npm test` |
220
226
  | Serve demo (optional) | `npm run serve` |
221
227
  | Stage a file | `git add <path>` |
222
228
  | Signed commit (example) | `git commit -S -m "feat: description of change."` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumina-sass",
3
- "version": "2.1.4",
3
+ "version": "2.3.0",
4
4
  "description": "Lumina Sass design tokens, mixins and public sub-modules (flexbox, color, mix).",
5
5
  "main": "src/_index.sass",
6
6
  "sass": "src/_index.sass",
@@ -32,7 +32,8 @@
32
32
  "dev": "npm run build && npm run serve",
33
33
  "build:demo": "sass demo/style.sass demo/style.css",
34
34
  "build": "sass src/_index.sass test/index.css && sass src/color/_index.sass test/color.css && sass src/mix/_index.sass test/mix.css && sass src/flexbox/_index.sass test/flexbox.css && sass src/flexbox/_index.sass test/flexbox.css",
35
- "test": "echo \"Error: no test specified\" && exit 1"
35
+ "test:sass": "sass src/test/mixins.spec.sass src/test/mixins.spec.css",
36
+ "test": "npm run test:sass"
36
37
  },
37
38
  "files": [
38
39
  "src"
@@ -42,6 +43,7 @@
42
43
  "devDependencies": {
43
44
  "http-server": "^14.1.1",
44
45
  "sass": "^1.85.1",
46
+ "sass-true": "^10.1.0",
45
47
  "standard-version": "^9.5.0"
46
48
  }
47
49
  }
@@ -1,105 +1,30 @@
1
- @use 'sass:list'
1
+ @use 'sass:map'
2
2
 
3
- // Font family collections used throughout the project.
4
- // The lists are deliberately extensive to cover most common web‑safe and Google‑font families.
5
-
6
- // Sans‑serif fonts – primary list referenced by `fonts.$sans-serif`.
7
3
  $sans-serif: (
8
- 'Roboto',
9
- 'Helvetica',
10
- 'Arial',
11
- 'Work Sans',
12
- 'Nunito',
13
- 'Open Sans',
14
- 'Lato',
15
- 'Montserrat',
16
- 'Source Sans Pro',
17
- 'Inter',
18
- 'Tahoma',
19
- 'Verdana',
20
- 'Gill Sans',
21
- 'Futura',
22
- 'Ubuntu',
23
- 'Noto Sans',
24
- 'Noto Sans KR',
25
- 'Noto Sans JP',
26
- 'Noto Sans SC',
27
- 'Noto Sans Arabic',
28
- 'Noto Sans Hebrew'
4
+ 'Roboto': sans-serif, 'Helvetica': sans-serif, 'Arial': sans-serif,
5
+ 'Work Sans': sans-serif, 'Nunito': sans-serif, 'Open Sans': sans-serif,
6
+ 'Lato': sans-serif, 'Montserrat': sans-serif, 'Source Sans Pro': sans-serif,
7
+ 'Inter': sans-serif, 'Tahoma': sans-serif, 'Verdana': sans-serif,
8
+ 'Gill Sans': sans-serif, 'Futura': sans-serif, 'Ubuntu': sans-serif,
9
+ 'Noto Sans': sans-serif, 'Noto Sans KR': sans-serif, 'Noto Sans JP': sans-serif,
10
+ 'Noto Sans SC': sans-serif, 'Noto Sans Arabic': sans-serif, 'Noto Sans Hebrew': sans-serif
29
11
  )
30
12
 
31
- // Serif fonts – provided for completeness, may be used elsewhere.
32
13
  $serif: (
33
- 'Georgia',
34
- 'Times New Roman',
35
- 'Palatino',
36
- 'Libre Baskerville',
37
- 'Merriweather',
38
- 'PT Serif',
39
- 'Noto Serif',
40
- 'Noto Serif KR',
41
- 'Noto Serif JP',
42
- 'Noto Serif SC'
14
+ 'Georgia': serif, 'Times New Roman': serif, 'Palatino': serif,
15
+ 'Libre Baskerville': serif, 'Merriweather': serif, 'PT Serif': serif,
16
+ 'Noto Serif': serif, 'Noto Serif KR': serif, 'Noto Serif JP': serif,
17
+ 'Noto Serif SC': serif
43
18
  )
44
19
 
45
- // Monospace fonts – useful for code blocks and UI elements.
46
20
  $mono: (
47
- 'Courier New',
48
- 'Consolas',
49
- 'Ubuntu Mono',
50
- 'Source Code Pro',
51
- 'Fira Code',
52
- 'Inconsolata',
53
- 'Menlo',
54
- 'Monaco',
55
- 'Noto Mono'
21
+ 'Courier New': monospace, 'Consolas': monospace, 'Ubuntu Mono': monospace,
22
+ 'Source Code Pro': monospace, 'Fira Code': monospace, 'Inconsolata': monospace,
23
+ 'Menlo': monospace, 'Monaco': monospace, 'Noto Mono': monospace
56
24
  )
57
25
 
58
- // Map each font name to its generic family. This is used by `font-family-of()`.
59
- $font-family: (
60
- // Sans‑serif
61
- 'Roboto': sans-serif,
62
- 'Helvetica': sans-serif,
63
- 'Arial': sans-serif,
64
- 'Work Sans': sans-serif,
65
- 'Nunito': sans-serif,
66
- 'Open Sans': sans-serif,
67
- 'Lato': sans-serif,
68
- 'Montserrat': sans-serif,
69
- 'Source Sans Pro': sans-serif,
70
- 'Inter': sans-serif,
71
- 'Tahoma': sans-serif,
72
- 'Verdana': sans-serif,
73
- 'Gill Sans': sans-serif,
74
- 'Futura': sans-serif,
75
- 'Ubuntu': sans-serif,
76
- 'Noto Sans': sans-serif,
77
- 'Noto Sans KR': sans-serif,
78
- 'Noto Sans JP': sans-serif,
79
- 'Noto Sans SC': sans-serif,
80
- 'Noto Sans Arabic': sans-serif,
81
- 'Noto Sans Hebrew': sans-serif,
82
-
83
- // Serif
84
- 'Georgia': serif,
85
- 'Times New Roman': serif,
86
- 'Palatino': serif,
87
- 'Libre Baskerville': serif,
88
- 'Merriweather': serif,
89
- 'PT Serif': serif,
90
- 'Noto Serif': serif,
91
- 'Noto Serif KR': serif,
92
- 'Noto Serif JP': serif,
93
- 'Noto Serif SC': serif,
94
-
95
- // Monospace
96
- 'Courier New': monospace,
97
- 'Consolas': monospace,
98
- 'Ubuntu Mono': monospace,
99
- 'Source Code Pro': monospace,
100
- 'Fira Code': monospace,
101
- 'Inconsolata': monospace,
102
- 'Menlo': monospace,
103
- 'Monaco': monospace,
104
- 'Noto Mono': monospace
26
+ $fonts: (
27
+ 'mono': $mono,
28
+ 'serif': $serif,
29
+ 'sans-serif': $sans-serif
105
30
  )
@@ -1,7 +1,7 @@
1
1
  @use '../color/_index' as color
2
2
 
3
3
 
4
- $academic: ('school': (icon: "\F62F"), 'diploma': (icon: "\F153"))
4
+ $academic: ('school': (icon: "\F671"), 'diploma': (icon: "\F11D"))
5
5
  $utility-inputs: ('color': (icon: '\F4B0'), 'hidden': (icon: '\F0E7'))
6
6
  $boolean-controls: ('radio': (icon: '\F110'), 'checkbox': (icon: '\F272'))
7
7
  $video-controls: ('play-video': (icon: '\F4F4'), 'pause-video': (icon: '\F4C4'))
@@ -18,11 +18,11 @@
18
18
  @if $props
19
19
  .#{$name}
20
20
  &::before
21
- content: map.get($props, icon)
22
- @if $color
23
- color: $color !important
21
+ @if $color
22
+ color: $color !important
24
23
 
25
- font-family: $font-family
24
+ font-family: $font-family
25
+ content: map.get($props, icon)
26
26
  @else
27
27
  @warn "Icon #{$name} not found in icon mapping."
28
28
 
@@ -33,11 +33,12 @@
33
33
  @each $icon, $props in $maps
34
34
  .#{$icon}
35
35
  &::before
36
- content: map.get($props, icon)
37
- @if $color
38
- color: $color !important
36
+ @if $color
37
+ color: $color !important
39
38
 
40
- font-family: $font-family
39
+ font-family: $font-family
40
+ content: map.get($props, icon)
41
+
41
42
  @else
42
43
  $names: $name
43
44
  @if meta.type-of($name) != 'list'
@@ -26,9 +26,11 @@
26
26
  /* Semantic Media Query Helpers – delegate through the base mixin */
27
27
  @mixin prefers-color-scheme($mode)
28
28
  @include media-queries-base('(prefers-color-scheme: #{$mode})')
29
+ @content
29
30
 
30
31
  @mixin prefers-orientation($orientation)
31
32
  @include media-queries-base('orientation', $orientation)
33
+ @content
32
34
 
33
35
  // Device media query helper – generates a media query for a single device
34
36
  @mixin device-media($device, $orientation: portrait)
@@ -58,19 +60,19 @@
58
60
  // Portrait video – forced 9:16 ratio
59
61
  video.portrait-media
60
62
  max-inline-size: 20em !important
61
- @include mix.aspect-ratio($width: 9, $length: 16)
63
+ @include aspect-ratio(9, 16)
62
64
 
63
65
  // Landscape video – default ratio
64
66
  video.landscape-media
65
67
  object-position: center 35%
66
- @include mix.aspect-ratio()
68
+ @include aspect-ratio()
67
69
 
68
70
  // Image and picture handling
69
71
  picture,
70
72
  img
71
73
  inline-size: 100%
72
74
  object-fit: $object-fit
73
- @include mix.aspect-ratio($width, $length)
75
+ @include aspect-ratio($width, $length)
74
76
  @if $position != null or $percentage != null
75
77
  object-position: $position $percentage
76
78
 
@@ -79,16 +81,13 @@
79
81
  img
80
82
  inline-size: 100%
81
83
  object-fit: $object-fit
82
- @include mix.aspect-ratio($width, $length)
84
+ @include aspect-ratio($width, $length)
83
85
  @if $position != null or $percentage != null
84
86
  object-position: $position $percentage
85
87
 
86
88
  // Figcaption styling if size provided
87
89
  figcaption
88
- @include typo.font($size, $style)
90
+ @include typo.font($size: $size, $style: $style)
89
91
 
90
92
  @mixin aspect-ratio($width: 16, $length: 9)
91
- aspect-ratio: calc($width / $length)/ $length
92
-
93
- @include aspect-ratio(9, 16)
94
- aspect-ratio: calc($width / $length)/ $length
93
+ aspect-ratio: #{$width} / #{$length}
@@ -38,8 +38,23 @@
38
38
  @if $style != null
39
39
  font-style: $style
40
40
 
41
+ @mixin font-sans($font, $size: 1rem, $weight: normal, $style: normal)
42
+ @include font($font, $size, sans-serif, $style, $weight)
43
+
44
+ @mixin font-serif($font, $size: 1rem, $weight: normal, $style: normal)
45
+ @include font($font, $size, serif, $style, $weight)
46
+
47
+ @mixin font-mono($font, $size: 1rem, $weight: normal, $style: normal)
48
+ @include font($font, $size, monospace, $style, $weight)
49
+
41
50
  // Helper: return the generic family for a given font name using the fonts map.
42
51
  @function font-family-of($font)
43
- @if map.has-key(fonts.$font-family, $font)
44
- @return map.get(fonts.$font-family, $font)
52
+ @if map.has-key(fonts.$fonts, $font)
53
+ @if $font == 'mono'
54
+ @return monospace
55
+ @return $font
56
+
57
+ @each $category, $map in fonts.$fonts
58
+ @if map.has-key($map, $font)
59
+ @return map.get($map, $font)
45
60
  @return null
@@ -0,0 +1,185 @@
1
+ @use 'sass:meta'
2
+ @use '../../node_modules/sass-true' as true
3
+ @use '../mix/_generators' as generators
4
+ @use '../mix/_media' as media
5
+ @use '../mix/_typography' as typo
6
+
7
+ @include true.test-module('Icon Generator')
8
+ @include true.test('Generates school icon class')
9
+ @include true.assert
10
+ @include true.output
11
+ @include generators.icon-generator('school')
12
+
13
+ @include true.expect
14
+ .school
15
+ &::before
16
+ color: rgb(64, 64, 64) !important
17
+ font-family: 'bootstrap-icons'
18
+ content: "\F671"
19
+
20
+ @include true.test-module('Flexbox Generator')
21
+ @include true.test('Generates flex-row properties')
22
+ @include true.assert
23
+ @include true.output
24
+ @include generators.flexbox-generator('flex-row')
25
+
26
+ @include true.expect
27
+ display: flex
28
+ flex-wrap: nowrap
29
+ flex-direction: row
30
+
31
+ @include true.test-module('Input Generator')
32
+ @include true.test('Generates text input type')
33
+ @include true.assert
34
+ @include true.output
35
+ @include generators.input-generator('text')
36
+
37
+ @include true.expect
38
+ input[type="text"]
39
+ border: rgb(204, 204, 204) solid 1px
40
+ padding: 0.5rem 1rem
41
+ border-radius: 0.5rem
42
+ background-color: rgb(255, 255, 255)
43
+ font-size: 1rem
44
+ line-height: 1.5
45
+ box-sizing: border-box
46
+ outline: 1px solid rgb(0, 120, 215)
47
+ focus-outline: rgb(0, 120, 215)
48
+ cursor: text
49
+
50
+ input[type="text"]::focus
51
+ outline: rgb(0, 120, 215)
52
+
53
+ &::-webkit-slider-runnable-track
54
+ height: 0.4rem
55
+ background: #ddd
56
+ border-radius: 0.2rem
57
+
58
+ &::-webkit-slider-thumb
59
+ -webkit-appearance: none
60
+ width: 1rem
61
+ height: 1rem
62
+ background: #0078d7
63
+ border-radius: 50%
64
+ margin-top: -0.3rem
65
+
66
+ @include true.test-module('Media Queries')
67
+ @include true.test('Generates max-width media query for breakpoint md')
68
+ @include true.assert
69
+ @include true.output
70
+ @include media.media-queries('md')
71
+ color: blue
72
+
73
+ @include true.expect
74
+ @media (max-width: 64rem)
75
+ color: blue
76
+
77
+ @include true.test('Generates prefers-color-scheme')
78
+ @include true.assert
79
+ @include true.output
80
+ @include media.prefers-color-scheme(dark)
81
+ background: black
82
+
83
+ @include true.expect
84
+ @media (prefers-color-scheme: dark)
85
+ background: black
86
+
87
+ @include true.test('Generates device-media for iphone')
88
+ @include true.assert
89
+ @include true.output
90
+ @include media.device-media('iphone')
91
+ color: white
92
+
93
+ @include true.expect
94
+ @media only screen and (min-width: 20rem) and (max-width: 20.125rem) and (min-height: 30rem) and (max-height: 30.125rem) and (orientation: portrait)
95
+ color: white
96
+
97
+ @include true.test-module('Typography')
98
+ @include true.test('Generates font styles')
99
+ @include true.assert
100
+ @include true.output
101
+ @include typo.font($size: 2rem, $weight: bold)
102
+
103
+ @include true.expect
104
+ font-size: 2rem
105
+ font-weight: bold
106
+ font-style: normal
107
+
108
+ @include true.test('Generates font-sans styles')
109
+ @include true.assert
110
+ @include true.output
111
+ @include typo.font-sans('Roboto', $size: 1.5rem)
112
+
113
+ @include true.expect
114
+ font-family: "Roboto", sans-serif
115
+ font-size: 1.5rem
116
+ font-weight: normal
117
+ font-style: normal
118
+
119
+ @include true.test('Generates font-serif styles')
120
+ @include true.assert
121
+ @include true.output
122
+ @include typo.font-serif('Georgia', $size: 1.2rem)
123
+
124
+ @include true.expect
125
+ font-family: "Georgia", serif
126
+ font-size: 1.2rem
127
+ font-weight: normal
128
+ font-style: normal
129
+
130
+ @include true.test('Generates font-mono styles')
131
+ @include true.assert
132
+ @include true.output
133
+ @include typo.font-mono('Fira Code', $weight: 500)
134
+
135
+ @include true.expect
136
+ font-family: "Fira Code", monospace
137
+ font-size: 1rem
138
+ font-weight: 500
139
+ font-style: normal
140
+
141
+ @include true.test('Returns correct font-family for known font')
142
+ @include true.assert-equal(typo.font-family-of('Open Sans'), sans-serif)
143
+
144
+ @include true.test('Detects generic category names')
145
+ @include true.assert-equal(typo.font-family-of('mono'), monospace)
146
+ @include true.assert-equal(typo.font-family-of('serif'), serif)
147
+
148
+ @include true.test-module('Layout Helpers')
149
+ @include true.test('Generates aspect-ratio')
150
+ @include true.assert
151
+ @include true.output
152
+ @include media.aspect-ratio(16, 9)
153
+
154
+ @include true.expect
155
+ aspect-ratio: 16 / 9
156
+
157
+ @include true.test('Generates figure structure')
158
+ @include true.assert
159
+ @include true.output
160
+ @include media.figure()
161
+
162
+ @include true.expect
163
+ figure video.portrait-media
164
+ max-inline-size: 20em !important
165
+ aspect-ratio: 9 / 16
166
+
167
+ figure video.landscape-media
168
+ object-position: center 35%
169
+ aspect-ratio: 16 / 9
170
+
171
+ figure picture, figure img
172
+ inline-size: 100%
173
+ object-fit: cover
174
+ aspect-ratio: 16 / 9
175
+
176
+ figure picture img
177
+ inline-size: 100%
178
+ object-fit: cover
179
+ aspect-ratio: 16 / 9
180
+
181
+ figure picture figcaption
182
+ font-weight: normal
183
+ font-style: italic
184
+
185
+ @include true.report