@nuvoui/core 0.3.0 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuvoui/core",
3
- "version": "0.3.0",
3
+ "version": "1.0.1",
4
4
  "description": "NuvoUI Core SCSS Library",
5
5
  "main": "dist/index.css",
6
6
  "module": "src/styles/index.scss",
@@ -10,8 +10,7 @@
10
10
  ],
11
11
  "scripts": {
12
12
  "dev": "vite",
13
- "build": "vite build && npm run build:scss",
14
- "build:scss": "sass src/styles/index.scss:dist/index.css --style compressed",
13
+ "build": "vite build",
15
14
  "prepare": "npm run build",
16
15
  "lint": "stylelint \"src/**/*.scss\"",
17
16
  "format": "prettier --write \"src/**/*.{scss,js,json}\"",
@@ -48,7 +47,10 @@
48
47
  "postcss-cli": "^11.0.0",
49
48
  "postcss-import": "^16.1.0",
50
49
  "postcss-nested": "^7.0.2",
50
+ "prettier": "^3.3.3",
51
51
  "sass": "^1.81.0",
52
+ "stylelint": "^16.10.0",
53
+ "stylelint-config-standard-scss": "^13.1.0",
52
54
  "vite": "^5.4.11"
53
55
  },
54
56
  "peerDependencies": {
package/src/logo.png ADDED
Binary file
package/src/logo.svg ADDED
@@ -0,0 +1,12 @@
1
+ <svg width="418" height="418" viewBox="0 0 418 418" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <mask id="mask0_4118_5137" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="418" height="418">
3
+ <rect width="418" height="418" fill="#F1F4D8"/>
4
+ </mask>
5
+ <g mask="url(#mask0_4118_5137)">
6
+ <rect width="418" height="418" fill="#F1F4D8"/>
7
+ <path d="M418 419H77L296.5 262.5L418 201V419Z" fill="#0476A4"/>
8
+ <path d="M316.794 -185.998L487.294 109.316L242.011 -2.52617L128 -76.9983L316.794 -185.998Z" fill="#0476A4"/>
9
+ <line x1="-17.2721" y1="410.484" x2="431.728" y2="185.484" stroke="#5FCFFF" stroke-width="28"/>
10
+ <circle cx="267" cy="183" r="66.5" stroke="#FF7B00" stroke-width="15"/>
11
+ </g>
12
+ </svg>
@@ -1,8 +1,12 @@
1
1
  @use 'sass:map';
2
2
 
3
- // Import variables
3
+ /* Import variables */
4
4
  @use '../utilities/variables' as *;
5
5
 
6
+ :root {
7
+ --font-family-base: system-ui, -apple-system, "BlinkMacSystemFont", 'Segoe UI', "Roboto", "Oxygen", "Ubuntu", "Cantarell", sans-serif;
8
+ }
9
+
6
10
  // Base typography styles
7
11
  html {
8
12
  font-size: 16px;
@@ -68,8 +72,22 @@ a {
68
72
  }
69
73
  }
70
74
 
71
- // Lists
72
- ul, ol {
73
- margin-bottom: 1rem;
74
- padding-left: 2rem;
75
+ .sr-only {
76
+ position: absolute !important;
77
+ width: 1px !important;
78
+ height: 1px !important;
79
+ padding: 0 !important;
80
+ margin: -1px !important;
81
+ overflow: hidden !important;
82
+ clip: rect(0, 0, 0, 0) !important;
83
+ white-space: nowrap !important;
84
+ border: 0 !important;
85
+ }
86
+
87
+ .focus\:outline-none:focus {
88
+ outline: none;
89
+ }
90
+
91
+ .focus\:ring:focus {
92
+ box-shadow: 0 0 0 3px rgb(66 153 225 / 50%);
75
93
  }
@@ -26,7 +26,8 @@ dd {
26
26
  // Set core body defaults
27
27
  body {
28
28
  min-height: 100vh;
29
- text-rendering: optimizeSpeed;
29
+ min-height: 100dvh;
30
+ text-rendering: optimizespeed;
30
31
  line-height: 1.5;
31
32
  -webkit-font-smoothing: antialiased;
32
33
  -moz-osx-font-smoothing: grayscale;
@@ -50,8 +51,9 @@ textarea,
50
51
  select {
51
52
  font: inherit;
52
53
  transition: all 0.2s ease-in-out;
54
+
53
55
  &:focus {
54
- box-shadow: inset 0 0 7px 0px #60b0cd; /* Change this to your preferred color and width */
56
+ box-shadow: inset 0 0 7px 0 #60b0cd; /* Change this to your preferred color and width */
55
57
  outline: 2px solid #40c1bf; /* Change this to your preferred color and width */
56
58
  }
57
59
  }
@@ -69,9 +71,21 @@ select {
69
71
  }
70
72
 
71
73
  // Remove list styles
72
- ul[role='list'],
73
- ol[role='list'] {
74
+ ul,
75
+ ol {
74
76
  list-style: none;
77
+ margin: 0;
78
+ padding: 0;
79
+
80
+ // Modern properties
81
+ padding-inline-start: 0; // Replaces padding-left
82
+ margin-block: 0; // Replaces margin-top/bottom
83
+ }
84
+
85
+ li {
86
+ margin: 0;
87
+ padding: 0;
88
+ margin-block: 0;
75
89
  }
76
90
 
77
91
  // Set core root defaults
@@ -3,16 +3,9 @@
3
3
 
4
4
  @use '../utilities/variables' as *;
5
5
  @use '../utilities/typography' as *;
6
+ @use '../utilities/borders' as *;
6
7
  @use '../themes/theme' as *;
7
8
 
8
- // Define text size map
9
- $text-size-map: (
10
- 'xs': 0.75rem,
11
- 'sm': 0.875rem,
12
- 'md': 1rem,
13
- 'lg': 1.125rem,
14
- 'xl': 1.25rem
15
- );
16
9
 
17
10
  // Button Base Mixins
18
11
  @mixin btn-base {
@@ -54,25 +47,22 @@ $text-size-map: (
54
47
  // Button Variants
55
48
  @mixin btn-solid($color) {
56
49
  background-color: theme-color($color);
57
- color: white;//var(--text-inverse);
50
+ color: if($color == 'light', black, white); /* var(--text-inverse); */
58
51
 
59
- &:hover:not(:disabled) {
60
- background-color: theme-color($color, 'hover');
61
- }
62
-
63
- &:active:not(:disabled) {
64
- background-color: theme-color($color, 'active');
65
- }
66
-
67
- &:disabled {
68
- background-color: theme-color($color, 'disabled');
69
- }
52
+ &:disabled { background-color: theme-color($color, 'disabled'); }
53
+ &:hover:not(:disabled) { background-color: theme-color($color, 'hover'); }
54
+ &:active:not(:disabled) { background-color: theme-color($color, 'active'); }
70
55
  }
71
56
 
72
57
  @mixin btn-outline($color) {
73
58
  background-color: transparent;
74
59
  border-color: theme-color($color);
75
60
  color: theme-color($color);
61
+
62
+ &:disabled {
63
+ border-color: theme-color($color, 'disabled');
64
+ color: theme-color($color, 'disabled');
65
+ }
76
66
 
77
67
  &:hover:not(:disabled) {
78
68
  background-color: theme-color($color);
@@ -82,17 +72,16 @@ $text-size-map: (
82
72
  &:active:not(:disabled) {
83
73
  background-color: theme-color($color, 'active');
84
74
  }
85
-
86
- &:disabled {
87
- border-color: theme-color($color, 'disabled');
88
- color: theme-color($color, 'disabled');
89
- }
90
75
  }
91
76
 
92
77
  @mixin btn-ghost($color) {
93
78
  background-color: transparent;
94
79
  color: theme-color($color);
95
80
 
81
+ &:disabled {
82
+ color: theme-color($color, 'disabled');
83
+ }
84
+
96
85
  &:hover:not(:disabled) {
97
86
  background-color: theme-color($color, '10');
98
87
  }
@@ -100,24 +89,11 @@ $text-size-map: (
100
89
  &:active:not(:disabled) {
101
90
  background-color: theme-color($color, '25');
102
91
  }
103
-
104
- &:disabled {
105
- color: theme-color($color, 'disabled');
106
- }
107
92
  }
108
93
 
109
94
  // Button Sizes
110
95
  @mixin btn-size($size) {
111
- font-size: map.get($text-size-map, $size);
112
-
113
- $padding-map: (
114
- 'xs': 0.25rem 0.5rem,
115
- 'sm': 0.375rem 0.75rem,
116
- 'md': 0.5rem 1rem,
117
- 'lg': 0.75rem 1.5rem,
118
- 'xl': 1rem 2rem
119
- );
120
-
96
+ font-size: map.get($font-sizes, $size);
121
97
  padding: map.get($padding-map, $size);
122
98
 
123
99
  .btn.icon {
@@ -133,11 +109,11 @@ $text-size-map: (
133
109
  height: map.get($icon-sizes, $size);
134
110
  }
135
111
  }
136
-
112
+
137
113
  // Button Shapes
138
114
  @mixin btn-shape($shape) {
139
115
  @if $shape == 'rounded' {
140
- border-radius: 0.375rem;
116
+ @include rounded(0.375rem);
141
117
  } @else if $shape == 'pill' {
142
118
  border-radius: 9999px;
143
119
  } @else if $shape == 'square' {
@@ -145,13 +121,48 @@ $text-size-map: (
145
121
  }
146
122
  }
147
123
 
124
+ @mixin btn-group-base {
125
+ display: inline-flex;
126
+ position: relative;
127
+ .btn { position: relative; }
128
+
129
+ // Handle z-index for hover states
130
+ .btn:hover { z-index: 1; }
131
+
132
+ // Remove double borders between buttons
133
+ .btn:not(:first-child) { margin-left: -1px; }
134
+
135
+ .btn:not(:first-child, :last-child) { border-radius: 0; }
136
+
137
+ .btn:first-child:dir(ltr) {
138
+ border-top-right-radius: 0;
139
+ border-bottom-right-radius: 0;
140
+ }
141
+
142
+ .btn:last-child:dir(ltr) {
143
+ border-top-left-radius: 0;
144
+ border-bottom-left-radius: 0;
145
+ }
146
+
147
+ @if $enable-rtl {
148
+ .btn:first-child:dir(rtl) {
149
+ border-top-left-radius: 0;
150
+ border-bottom-left-radius: 0;
151
+ }
152
+
153
+ .btn:last-child:dir(rtl) {
154
+ border-top-right-radius: 0;
155
+ border-bottom-right-radius: 0;
156
+ }
157
+ }
158
+ }
159
+
148
160
  // Base Button Class
149
161
  .btn {
150
162
  @include btn-base;
151
163
  @include btn-size('md');
152
164
  @include btn-shape('rounded');
153
165
 
154
-
155
166
  // Outline variant
156
167
  &.outline {
157
168
  @include btn-outline('text-secondary'); // Default outline style
@@ -185,17 +196,6 @@ $text-size-map: (
185
196
  }
186
197
 
187
198
 
188
- // Sizes
189
- .btn.xs { @include btn-size('xs'); }
190
- .btn.sm { @include btn-size('sm'); }
191
- .btn.md { @include btn-size('md'); }
192
- .btn.lg { @include btn-size('lg'); }
193
- .btn.xl { @include btn-size('xl'); }
194
-
195
- // Shapes
196
- .btn.rounded { @include btn-shape('rounded'); }
197
- .btn.pill { @include btn-shape('pill'); }
198
- .btn.square { @include btn-shape('square'); }
199
199
 
200
200
  // Icon Only Buttons
201
201
  .btn.icon {
@@ -207,41 +207,55 @@ $text-size-map: (
207
207
  &.btn-xl { padding: 1rem; }
208
208
  }
209
209
 
210
- // Loading Animation
211
- @keyframes spin {
212
- to { transform: rotate(360deg); }
213
- }
214
-
215
- /**
210
+ // Sizes
211
+ .btn-group.xs > .btn, .btn.xs { @include btn-size('xs'); }
212
+ .btn-group.sm > .btn, .btn.sm { @include btn-size('sm'); }
213
+ .btn-group.md > .btn, .btn.md { @include btn-size('md'); }
214
+ .btn-group.lg > .btn, .btn.lg { @include btn-size('lg'); }
215
+ .btn-group.xl > .btn, .btn.xl { @include btn-size('xl'); }
216
216
 
217
+ // Shapes
218
+ .btn-group.rounded > .btn, .btn.rounded { @include btn-shape('rounded'); }
219
+ .btn-group.pill > .btn, .btn.pill { @include btn-shape('pill'); }
220
+ .btn-group.square > .btn, .btn.square { @include btn-shape('square'); }
217
221
 
218
- <!-- Basic buttons -->
219
- <button class="btn primary">Primary</button>
220
- <button class="btn outline secondary">Secondary</button>
221
- <button class="btn ghost info">Info</button>
222
+ .btn-group {
223
+ @include btn-group-base;
222
224
 
223
- <!-- Sizes -->
224
- <button class="btn primary xs">Extra Small</button>
225
- <button class="btn primary xl">Extra Large</button>
225
+ // Color variants for solid buttons
226
+ @each $name, $color in $colors {
227
+ &.#{$name} > .btn{
228
+ @include btn-solid($name);
229
+ }
230
+ }
231
+ }
226
232
 
227
- <!-- Shapes -->
228
- <button class="btn primary pill">Pill Button</button>
233
+ // Outline variant
234
+ .btn-group.outline > .btn {
235
+ @include btn-outline('text-secondary'); // Default outline style
236
+ }
229
237
 
230
- <!-- With Icons -->
231
- <button class="btn btn-primary">
232
- <svg class="btn-icon"><!-- icon --></svg>
233
- With Icon
234
- </button>
238
+ // Color variants override
239
+ @each $name, $color in $colors {
240
+ .btn-group.outline.#{$name} > .btn {
241
+ @include btn-outline($name);
242
+ }
243
+ }
235
244
 
236
- <!-- Icon Only -->
237
- <button class="btn btn-primary btn-icon-only">
238
- <svg class="btn-icon"><!-- icon --></svg>
239
- </button>
240
245
 
241
- <!-- Loading State -->
242
- <button class="btn btn-primary loading">Loading</button>
246
+ // Outline variant
247
+ .btn-group.ghost > .btn {
248
+ @include btn-ghost('text-secondary'); // Default outline style
249
+ }
243
250
 
244
- <!-- Disabled State -->
245
- <button class="btn btn-primary" disabled>Disabled</button>
251
+ // Color variants override
252
+ @each $name, $color in $colors {
253
+ .btn-group.ghost.#{$name} > .btn {
254
+ @include btn-ghost($name);
255
+ }
256
+ }
246
257
 
247
- */
258
+ // Loading Animation
259
+ @keyframes spin {
260
+ to { transform: rotate(360deg); }
261
+ }
@@ -1,23 +0,0 @@
1
- // Base checkbox reset
2
- .checkbox {
3
- @apply appearance-none cursor-pointer select-none;
4
- @apply w-4 h-4 border-2 rounded;
5
- @apply transition-all duration-200;
6
- @apply focus-visible:outline-2 focus-visible:outline-offset-2;
7
-
8
- &:checked {
9
- @apply bg-current border-current;
10
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='white' d='M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z'/%3E%3C/svg%3E");
11
- }
12
-
13
- &:indeterminate {
14
- @apply bg-current border-current;
15
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='white' d='M2 8a.75.75 0 0 1 .75-.75h10.5a.75.75 0 0 1 0 1.5H2.75A.75.75 0 0 1 2 8z'/%3E%3C/svg%3E");
16
- }
17
- }
18
-
19
- // Size variants
20
- .checkbox-sm { @apply w-3 h-3; }
21
- .checkbox-md { @apply w-4 h-4; }
22
- .checkbox-lg { @apply w-5 h-5; }
23
- .checkbox-xl { @apply w-6 h-6; }
@@ -3,11 +3,7 @@
3
3
  @use '../utilities/variables' as *;
4
4
  @use '../themes/theme' as Theme;
5
5
 
6
- // Form Container Mixins
7
- @mixin form-group {
8
- position: relative;
9
- margin-bottom: 1.5rem;
10
- }
6
+
11
7
 
12
8
  @mixin form-inline {
13
9
  display: flex;
@@ -51,13 +47,21 @@
51
47
  border-color: var(--primary);
52
48
  box-shadow: 0 0 0 4px rgba(var(--primary-rgb), 0.1);
53
49
  }
50
+ }
51
+
52
+
53
+ // Handle input with value or placeholder
54
+ @mixin form-group {
55
+ position: relative;
56
+ margin-bottom: 1.5rem;
54
57
 
55
- &:not(:placeholder-shown) + label {
58
+ &:has(input:not(:placeholder-shown)) > label.form-label,
59
+ &:has(input:focus) > label.form-label {
56
60
  @include form-label-float;
57
61
  }
58
-
59
- &:focus + label {
60
- @include form-label-float;
62
+
63
+ // Change label color if input is focused
64
+ &:has(input:focus) > label {
61
65
  color: var(--primary);
62
66
  }
63
67
  }
@@ -82,15 +86,16 @@
82
86
  // Select Mixins
83
87
  @mixin form-select {
84
88
  @include form-input;
89
+
85
90
  appearance: none;
86
- background-image: url("data:image/svg+xml,...");
91
+ background-image: url("data:image/svg+xml,..."); // todo: colored arrow svg
87
92
  background-repeat: no-repeat;
88
93
  background-position: right 1rem center;
89
94
  padding-right: 2.5rem;
90
95
  }
91
96
 
92
97
  // Checkbox & Radio Mixins
93
- @mixin form-check {
98
+ @mixin form-selection {
94
99
  position: relative;
95
100
  display: inline-flex;
96
101
  align-items: center;
@@ -98,41 +103,74 @@
98
103
  user-select: none;
99
104
  }
100
105
 
101
- @mixin form-check-input {
106
+ @mixin form-selection-input {
107
+ &[type="checkbox"]{
108
+ border-radius: 0.25rem;
109
+ }
110
+
111
+ &[type="radio"]{
112
+ border-radius: 20rem;
113
+ }
114
+
102
115
  appearance: none;
103
116
  width: 1.25rem;
104
117
  height: 1.25rem;
105
118
  border: 2px solid var(--border-color);
106
- border-radius: 0.25rem;
107
119
  margin-right: 0.5rem;
108
120
  cursor: pointer;
109
121
 
110
122
  &:checked {
111
- background-color: var(--primary);
112
- border-color: var(--primary);
113
- background-image: url("data:image/svg+xml,...");
123
+ background-color: var(--primary); border-color: var(--primary);
124
+ @each $name, $color in $colors {
125
+ &.#{$name} {
126
+ background-color: Theme.theme-color($name); border-color: Theme.theme-color($name);}
127
+ }
128
+
129
+ background-image: url("data:image/svg+xml,..."); // todo: colored arrow svg
114
130
  }
115
131
  }
116
132
 
133
+ // Input Sizes
134
+ @mixin input-size($size) {
135
+ font-size: map.get($font-sizes, $size);
136
+ padding: map.get($padding-map, $size);
137
+ }
138
+
117
139
  // Classes
118
140
  .form-group { @include form-group; }
119
141
  .form-inline { @include form-inline; }
120
142
  .form-label { @include form-label; }
121
143
  .form-input { @include form-input; }
122
144
  .form-select { @include form-select; }
123
- .form-check { @include form-check; }
124
- .form-check-input { @include form-check-input; }
145
+ .form-check, .form-radio { @include form-selection; }
146
+ .form-check-input, .form-radio-input { @include form-selection-input; }
125
147
 
126
148
  // Validation Classes
127
149
  .is-valid { @include form-valid; }
128
150
  .is-invalid { @include form-invalid; }
129
151
 
130
- // Sizes
131
- @for $i from 0 through 5 {
132
- .form-input-#{$i} {
133
- @include form-input;
134
- padding: $i;
135
- }
152
+
153
+ small{
154
+ font-size: 0.875rem;
155
+ position: absolute;
156
+ right: 20px;
157
+ top: -10px;
158
+ background: #f8f9fa;
159
+ padding: 0 10px;
160
+ }
161
+
162
+ // Base Input Class
163
+ .form-input, .form-select {
164
+ @include input-size('md'); // Default size
165
+
166
+ // Sizes
167
+ &.xs { @include input-size('xs'); }
168
+ &.sm { @include input-size('sm'); }
169
+ &.md { @include input-size('md'); }
170
+ &.lg { @include input-size('lg'); }
171
+ &.xl { @include input-size('xl'); }
172
+ &.xxl { @include input-size('2xl'); }
173
+ &.xxxl { @include input-size('3xl'); }
136
174
  }
137
175
 
138
176
  // Dark Mode Support
@@ -0,0 +1,72 @@
1
+ @use "sass:math";
2
+ @use 'sass:color';
3
+ @use 'sass:map';
4
+
5
+ @use '../utilities/media-queries' as Responsive;
6
+ @use '../utilities/variables' as *;
7
+
8
+ // _mixins.scss
9
+ @mixin hamburger($color: currentColor, $size: 24px, $thickness: 2px) {
10
+ .hamburger {
11
+ --hamburger-color: #{$color};
12
+ --hamburger-size: #{$size};
13
+ --hamburger-thickness: #{$thickness};
14
+
15
+ &:focus {
16
+ outline: none;
17
+ box-shadow: none;
18
+ }
19
+
20
+ // display: none;
21
+ cursor: pointer;
22
+ width: var(--hamburger-size);
23
+ height: var(--hamburger-size);
24
+ position: relative;
25
+ border: 0;
26
+ background: transparent;
27
+ padding: 0;
28
+
29
+ span {
30
+ display: block;
31
+ position: absolute;
32
+ left: 0;
33
+ right: 0;
34
+ height: var(--hamburger-thickness);
35
+ background-color: var(--hamburger-color);
36
+ transform-origin: center;
37
+ transition: transform 0.2s ease,
38
+ opacity 0.2s ease;
39
+
40
+ &:first-child {
41
+ top: 20%;
42
+ }
43
+
44
+ &:nth-child(2) {
45
+ top: 50%;
46
+ transform: translateY(-50%);
47
+ }
48
+
49
+ &:last-child {
50
+ bottom: 20%;
51
+ }
52
+ }
53
+
54
+ &[aria-expanded="true"] span {
55
+ &:first-child {
56
+ transform: translateY(7px) rotate(45deg);
57
+ }
58
+
59
+ &:nth-child(2) {
60
+ opacity: 0;
61
+ }
62
+
63
+ &:last-child {
64
+ transform: translateY(-7px) rotate(-45deg);
65
+ }
66
+ }
67
+
68
+ @include Responsive.media-up('md') {
69
+ display: none;
70
+ }
71
+ }
72
+ }