@kwtv/components 0.3.0 → 0.4.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.
Files changed (49) hide show
  1. package/README.md +35 -0
  2. package/package.json +2 -2
  3. package/src/astro/Accordion.astro +10 -6
  4. package/src/astro/AccordionItem.astro +47 -43
  5. package/src/astro/ActiveFilterTags.astro +29 -25
  6. package/src/astro/Alert.astro +45 -41
  7. package/src/astro/Badge.astro +80 -76
  8. package/src/astro/Band.astro +104 -58
  9. package/src/astro/Breadcrumb.astro +33 -29
  10. package/src/astro/Button.astro +132 -128
  11. package/src/astro/Card.astro +64 -60
  12. package/src/astro/CartLine.astro +59 -55
  13. package/src/astro/Checkbox.astro +36 -32
  14. package/src/astro/Chip.astro +68 -64
  15. package/src/astro/DotGrid.astro +50 -46
  16. package/src/astro/EmptyState.astro +26 -22
  17. package/src/astro/FilterGroup.astro +29 -25
  18. package/src/astro/Filters.astro +50 -46
  19. package/src/astro/Footer.astro +179 -175
  20. package/src/astro/FooterColumn.astro +39 -35
  21. package/src/astro/Header.astro +67 -63
  22. package/src/astro/Icon.astro +1 -1
  23. package/src/astro/IconButton.astro +64 -60
  24. package/src/astro/Marquee.astro +33 -29
  25. package/src/astro/NavDropdown.astro +120 -116
  26. package/src/astro/NavLink.astro +59 -55
  27. package/src/astro/Newsletter.astro +58 -54
  28. package/src/astro/Pager.astro +43 -39
  29. package/src/astro/PickCard.astro +72 -68
  30. package/src/astro/ProductCard.astro +120 -116
  31. package/src/astro/Radio.astro +36 -32
  32. package/src/astro/Skeleton.astro +43 -39
  33. package/src/astro/Social.astro +26 -22
  34. package/src/astro/StepIndicator.astro +55 -51
  35. package/src/astro/Sticker.astro +50 -46
  36. package/src/astro/Swatch.astro +44 -40
  37. package/src/astro/Table.astro +58 -54
  38. package/src/astro/TableCard.astro +39 -35
  39. package/src/astro/TextField.astro +92 -88
  40. package/src/astro/Totals.astro +39 -35
  41. package/src/react/Drawer.css +60 -56
  42. package/src/react/Modal.css +97 -93
  43. package/src/react/NewsCarousel.css +108 -104
  44. package/src/react/QuantityStepper.css +84 -80
  45. package/src/react/Select.css +159 -155
  46. package/src/react/Toast.css +128 -124
  47. package/src/styles/base.css +30 -26
  48. package/src/styles/controls.css +183 -179
  49. package/src/styles/motion.css +203 -199
@@ -74,133 +74,137 @@ const classes = ["ui-product", soldOut && "is-disabled", className]
74
74
  </a>
75
75
 
76
76
  <style>
77
- .ui-product {
78
- position: relative;
79
- display: flex;
80
- flex-direction: column;
81
- border: 1px solid var(--border);
82
- border-radius: var(--radius-lg);
83
- overflow: hidden;
84
- background: var(--surface);
85
- color: var(--text);
86
- text-decoration: none;
87
- transition: border-color var(--duration-fast) var(--ease-standard);
88
- }
77
+ @layer reset, tokens, base, components, motion, utilities;
89
78
 
90
- .ui-product:hover,
91
- .ui-product.is-hover {
92
- border-color: var(--border-strong);
93
- }
79
+ @layer components {
80
+ .ui-product {
81
+ position: relative;
82
+ display: flex;
83
+ flex-direction: column;
84
+ border: 1px solid var(--border);
85
+ border-radius: var(--radius-lg);
86
+ overflow: hidden;
87
+ background: var(--surface);
88
+ color: var(--text);
89
+ text-decoration: none;
90
+ transition: border-color var(--duration-fast) var(--ease-standard);
91
+ }
94
92
 
95
- .ui-product:focus-visible {
96
- outline: 2px solid var(--focus);
97
- outline-offset: 2px;
98
- box-shadow: 0 0 0 4px var(--focus-outer);
99
- }
93
+ .ui-product:hover,
94
+ .ui-product.is-hover {
95
+ border-color: var(--border-strong);
96
+ }
100
97
 
101
- .ui-product__img {
102
- display: block;
103
- width: 100%;
104
- aspect-ratio: 4 / 3;
105
- object-fit: cover;
106
- background: var(--surface-hover);
107
- }
98
+ .ui-product:focus-visible {
99
+ outline: 2px solid var(--focus);
100
+ outline-offset: 2px;
101
+ box-shadow: 0 0 0 4px var(--focus-outer);
102
+ }
108
103
 
109
- .ui-product__body {
110
- display: flex;
111
- flex-direction: column;
112
- gap: var(--space-1);
113
- padding: var(--space-3) var(--space-4) var(--space-4);
114
- }
104
+ .ui-product__img {
105
+ display: block;
106
+ width: 100%;
107
+ aspect-ratio: 4 / 3;
108
+ object-fit: cover;
109
+ background: var(--surface-hover);
110
+ }
115
111
 
116
- .ui-product__title {
117
- font-size: var(--text-base);
118
- font-weight: var(--weight-semibold);
119
- color: var(--text);
120
- }
112
+ .ui-product__body {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: var(--space-1);
116
+ padding: var(--space-3) var(--space-4) var(--space-4);
117
+ }
121
118
 
122
- .ui-product__meta {
123
- font-size: var(--text-xs);
124
- color: var(--text-muted);
125
- }
119
+ .ui-product__title {
120
+ font-size: var(--text-base);
121
+ font-weight: var(--weight-semibold);
122
+ color: var(--text);
123
+ }
126
124
 
127
- .ui-product__price {
128
- display: flex;
129
- align-items: baseline;
130
- gap: var(--space-2);
131
- margin-top: var(--space-1);
132
- font-size: var(--text-lg);
133
- font-weight: var(--weight-semibold);
134
- font-variant-numeric: tabular-nums;
135
- color: var(--text);
136
- }
125
+ .ui-product__meta {
126
+ font-size: var(--text-xs);
127
+ color: var(--text-muted);
128
+ }
137
129
 
138
- .ui-product__price s {
139
- font-size: var(--text-sm);
140
- font-weight: var(--weight-regular);
141
- color: var(--text-muted);
142
- }
130
+ .ui-product__price {
131
+ display: flex;
132
+ align-items: baseline;
133
+ gap: var(--space-2);
134
+ margin-top: var(--space-1);
135
+ font-size: var(--text-lg);
136
+ font-weight: var(--weight-semibold);
137
+ font-variant-numeric: tabular-nums;
138
+ color: var(--text);
139
+ }
143
140
 
144
- /* Sold out: card stays readable and clickable. */
145
- .ui-product.is-disabled .ui-product__img {
146
- opacity: 0.7;
147
- }
148
- .ui-product.is-disabled .ui-product__price {
149
- color: var(--text-muted);
150
- font-weight: var(--weight-regular);
151
- }
141
+ .ui-product__price s {
142
+ font-size: var(--text-sm);
143
+ font-weight: var(--weight-regular);
144
+ color: var(--text-muted);
145
+ }
152
146
 
153
- /* Ribbon. One per card, decorative. 112 px box. */
154
- .ui-ribbon {
155
- position: absolute;
156
- top: 0;
157
- left: 0;
158
- width: 112px;
159
- height: 112px;
160
- overflow: hidden;
161
- pointer-events: none;
162
- z-index: 1;
163
- }
164
- .ui-ribbon i {
165
- position: absolute;
166
- top: 22px;
167
- left: -34px;
168
- width: 140px;
169
- transform: rotate(-45deg);
170
- text-align: center;
171
- font-size: var(--text-2xs);
172
- font-weight: var(--weight-bold);
173
- letter-spacing: var(--tracking-wider);
174
- text-transform: uppercase;
175
- font-style: normal;
176
- padding: var(--space-1) 0;
177
- color: var(--primary-fg);
178
- background: var(--primary);
179
- }
180
- .ui-ribbon--new i {
181
- background: var(--primary);
182
- color: var(--primary-fg);
183
- }
184
- .ui-ribbon--promo i {
185
- background: var(--accent);
186
- color: var(--accent-fg);
187
- }
188
- .ui-ribbon--last i {
189
- background: var(--warning);
190
- color: var(--primary-fg);
191
- }
192
- .ui-ribbon--fav i {
193
- background: var(--surface-accent);
194
- color: var(--surface-accent-fg);
195
- }
196
- .ui-ribbon--sold-out i {
197
- background: var(--danger-bg);
198
- color: var(--danger);
199
- }
147
+ /* Sold out: card stays readable and clickable. */
148
+ .ui-product.is-disabled .ui-product__img {
149
+ opacity: 0.7;
150
+ }
151
+ .ui-product.is-disabled .ui-product__price {
152
+ color: var(--text-muted);
153
+ font-weight: var(--weight-regular);
154
+ }
200
155
 
201
- @media (prefers-reduced-motion: reduce) {
202
- .ui-product {
203
- transition: none;
156
+ /* Ribbon. One per card, decorative. 112 px box. */
157
+ .ui-ribbon {
158
+ position: absolute;
159
+ top: 0;
160
+ left: 0;
161
+ width: 112px;
162
+ height: 112px;
163
+ overflow: hidden;
164
+ pointer-events: none;
165
+ z-index: 1;
166
+ }
167
+ .ui-ribbon i {
168
+ position: absolute;
169
+ top: 22px;
170
+ left: -34px;
171
+ width: 140px;
172
+ transform: rotate(-45deg);
173
+ text-align: center;
174
+ font-size: var(--text-2xs);
175
+ font-weight: var(--weight-bold);
176
+ letter-spacing: var(--tracking-wider);
177
+ text-transform: uppercase;
178
+ font-style: normal;
179
+ padding: var(--space-1) 0;
180
+ color: var(--primary-fg);
181
+ background: var(--primary);
182
+ }
183
+ .ui-ribbon--new i {
184
+ background: var(--primary);
185
+ color: var(--primary-fg);
186
+ }
187
+ .ui-ribbon--promo i {
188
+ background: var(--accent);
189
+ color: var(--accent-fg);
190
+ }
191
+ .ui-ribbon--last i {
192
+ background: var(--warning);
193
+ color: var(--primary-fg);
194
+ }
195
+ .ui-ribbon--fav i {
196
+ background: var(--surface-accent);
197
+ color: var(--surface-accent-fg);
198
+ }
199
+ .ui-ribbon--sold-out i {
200
+ background: var(--danger-bg);
201
+ color: var(--danger);
202
+ }
203
+
204
+ @media (prefers-reduced-motion: reduce) {
205
+ .ui-product {
206
+ transition: none;
207
+ }
204
208
  }
205
209
  }
206
210
  </style>
@@ -47,43 +47,47 @@ const classes = ["ui-check", disabled && "is-disabled", className]
47
47
  </label>
48
48
 
49
49
  <style>
50
- .ui-check {
51
- display: flex;
52
- align-items: center;
53
- gap: var(--space-2);
54
- min-height: 32px;
55
- font-family: var(--font-sans);
56
- font-size: var(--text-sm);
57
- color: var(--text);
58
- cursor: pointer;
59
- }
50
+ @layer reset, tokens, base, components, motion, utilities;
60
51
 
61
- .ui-check input {
62
- width: 17px;
63
- height: 17px;
64
- flex-shrink: 0;
65
- accent-color: var(--primary);
66
- cursor: pointer;
67
- }
52
+ @layer components {
53
+ .ui-check {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: var(--space-2);
57
+ min-height: 32px;
58
+ font-family: var(--font-sans);
59
+ font-size: var(--text-sm);
60
+ color: var(--text);
61
+ cursor: pointer;
62
+ }
68
63
 
69
- .ui-check input:focus-visible {
70
- outline: 2px solid var(--focus);
71
- outline-offset: 2px;
72
- box-shadow: 0 0 0 4px var(--focus-outer);
73
- }
64
+ .ui-check input {
65
+ width: 17px;
66
+ height: 17px;
67
+ flex-shrink: 0;
68
+ accent-color: var(--primary);
69
+ cursor: pointer;
70
+ }
74
71
 
75
- .ui-check.is-disabled {
76
- cursor: not-allowed;
77
- color: var(--text-muted);
78
- }
72
+ .ui-check input:focus-visible {
73
+ outline: 2px solid var(--focus);
74
+ outline-offset: 2px;
75
+ box-shadow: 0 0 0 4px var(--focus-outer);
76
+ }
79
77
 
80
- .ui-check.is-disabled input {
81
- cursor: not-allowed;
82
- }
78
+ .ui-check.is-disabled {
79
+ cursor: not-allowed;
80
+ color: var(--text-muted);
81
+ }
83
82
 
84
- @media (max-width: 700px), (pointer: coarse) {
85
- .ui-check {
86
- min-height: 40px;
83
+ .ui-check.is-disabled input {
84
+ cursor: not-allowed;
85
+ }
86
+
87
+ @media (max-width: 700px), (pointer: coarse) {
88
+ .ui-check {
89
+ min-height: 40px;
90
+ }
87
91
  }
88
92
  }
89
93
  </style>
@@ -42,53 +42,57 @@ const style = [
42
42
  ></span>
43
43
 
44
44
  <style>
45
- .ui-skel {
46
- display: block;
47
- background: var(--surface-hover);
48
- background-image: linear-gradient(
49
- 90deg,
50
- var(--surface-hover) 0%,
51
- var(--border) 50%,
52
- var(--surface-hover) 100%
53
- );
54
- background-size: 200% 100%;
55
- border-radius: var(--radius-md);
56
- animation: ui-skel-shimmer 1400ms ease-in-out infinite;
57
- }
45
+ @layer reset, tokens, base, components, motion, utilities;
58
46
 
59
- .ui-skel--img {
60
- width: 100%;
61
- aspect-ratio: 4 / 3;
62
- border-radius: 0;
63
- }
47
+ @layer components {
48
+ .ui-skel {
49
+ display: block;
50
+ background: var(--surface-hover);
51
+ background-image: linear-gradient(
52
+ 90deg,
53
+ var(--surface-hover) 0%,
54
+ var(--border) 50%,
55
+ var(--surface-hover) 100%
56
+ );
57
+ background-size: 200% 100%;
58
+ border-radius: var(--radius-md);
59
+ animation: ui-skel-shimmer 1400ms ease-in-out infinite;
60
+ }
64
61
 
65
- .ui-skel--title {
66
- height: 0.875rem;
67
- border-radius: var(--radius-sm);
68
- }
62
+ .ui-skel--img {
63
+ width: 100%;
64
+ aspect-ratio: 4 / 3;
65
+ border-radius: 0;
66
+ }
69
67
 
70
- .ui-skel--line {
71
- height: 0.625rem;
72
- border-radius: var(--radius-sm);
73
- }
68
+ .ui-skel--title {
69
+ height: 0.875rem;
70
+ border-radius: var(--radius-sm);
71
+ }
74
72
 
75
- .ui-skel--block {
76
- height: 1rem;
77
- }
73
+ .ui-skel--line {
74
+ height: 0.625rem;
75
+ border-radius: var(--radius-sm);
76
+ }
78
77
 
79
- @keyframes ui-skel-shimmer {
80
- 0% {
81
- background-position: 200% 0;
78
+ .ui-skel--block {
79
+ height: 1rem;
82
80
  }
83
- 100% {
84
- background-position: -200% 0;
81
+
82
+ @keyframes ui-skel-shimmer {
83
+ 0% {
84
+ background-position: 200% 0;
85
+ }
86
+ 100% {
87
+ background-position: -200% 0;
88
+ }
85
89
  }
86
- }
87
90
 
88
- @media (prefers-reduced-motion: reduce) {
89
- .ui-skel {
90
- animation: none;
91
- background-image: none;
91
+ @media (prefers-reduced-motion: reduce) {
92
+ .ui-skel {
93
+ animation: none;
94
+ background-image: none;
95
+ }
92
96
  }
93
97
  }
94
98
  </style>
@@ -27,30 +27,34 @@ const classes = ["ui-social", className].filter(Boolean).join(" ");
27
27
  </a>
28
28
 
29
29
  <style>
30
- .ui-social {
31
- display: inline-flex;
32
- align-items: center;
33
- justify-content: center;
34
- width: 40px;
35
- height: 40px;
36
- border-radius: var(--radius-md);
37
- color: var(--ivory-light);
38
- transition:
39
- color var(--duration-fast) var(--ease-standard),
40
- background-color var(--duration-fast) var(--ease-standard);
41
- }
42
- .ui-social:hover {
43
- color: var(--ivory-xlight);
44
- background: rgba(255, 255, 255, 0.08);
45
- }
46
- .ui-social:focus-visible {
47
- outline: 2px solid var(--ivory-xlight);
48
- outline-offset: 2px;
49
- }
30
+ @layer reset, tokens, base, components, motion, utilities;
50
31
 
51
- @media (prefers-reduced-motion: reduce) {
32
+ @layer components {
52
33
  .ui-social {
53
- transition: none;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ width: 40px;
38
+ height: 40px;
39
+ border-radius: var(--radius-md);
40
+ color: var(--ivory-light);
41
+ transition:
42
+ color var(--duration-fast) var(--ease-standard),
43
+ background-color var(--duration-fast) var(--ease-standard);
44
+ }
45
+ .ui-social:hover {
46
+ color: var(--ivory-xlight);
47
+ background: rgba(255, 255, 255, 0.08);
48
+ }
49
+ .ui-social:focus-visible {
50
+ outline: 2px solid var(--ivory-xlight);
51
+ outline-offset: 2px;
52
+ }
53
+
54
+ @media (prefers-reduced-motion: reduce) {
55
+ .ui-social {
56
+ transition: none;
57
+ }
54
58
  }
55
59
  }
56
60
  </style>
@@ -55,62 +55,66 @@ const classes = ["ui-steps", mobile && "ui-steps--mobile", className]
55
55
  </nav>
56
56
 
57
57
  <style>
58
- .ui-steps {
59
- display: flex;
60
- align-items: center;
61
- gap: var(--space-2);
62
- }
58
+ @layer reset, tokens, base, components, motion, utilities;
63
59
 
64
- .ui-step {
65
- display: inline-flex;
66
- align-items: center;
67
- gap: var(--space-2);
68
- font-size: var(--text-sm);
69
- color: var(--text-muted);
70
- }
60
+ @layer components {
61
+ .ui-steps {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: var(--space-2);
65
+ }
71
66
 
72
- .ui-step__dot {
73
- display: inline-flex;
74
- align-items: center;
75
- justify-content: center;
76
- width: 22px;
77
- height: 22px;
78
- border-radius: var(--radius-full);
79
- border: 1px solid var(--border);
80
- font-size: var(--text-xs);
81
- font-weight: var(--weight-semibold);
82
- background: var(--surface);
83
- color: var(--text-muted);
84
- }
67
+ .ui-step {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ gap: var(--space-2);
71
+ font-size: var(--text-sm);
72
+ color: var(--text-muted);
73
+ }
85
74
 
86
- .ui-step.is-current {
87
- color: var(--text);
88
- font-weight: var(--weight-semibold);
89
- }
90
- .ui-step.is-current .ui-step__dot {
91
- border-color: var(--primary);
92
- background: var(--primary);
93
- color: var(--primary-fg);
94
- }
75
+ .ui-step__dot {
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ width: 22px;
80
+ height: 22px;
81
+ border-radius: var(--radius-full);
82
+ border: 1px solid var(--border);
83
+ font-size: var(--text-xs);
84
+ font-weight: var(--weight-semibold);
85
+ background: var(--surface);
86
+ color: var(--text-muted);
87
+ }
95
88
 
96
- .ui-step.is-done {
97
- color: var(--text);
98
- }
99
- .ui-step.is-done .ui-step__dot {
100
- border-color: var(--primary);
101
- background: var(--primary);
102
- color: var(--primary-fg);
103
- }
89
+ .ui-step.is-current {
90
+ color: var(--text);
91
+ font-weight: var(--weight-semibold);
92
+ }
93
+ .ui-step.is-current .ui-step__dot {
94
+ border-color: var(--primary);
95
+ background: var(--primary);
96
+ color: var(--primary-fg);
97
+ }
104
98
 
105
- .ui-steps__sep {
106
- flex: 1;
107
- min-width: var(--space-4);
108
- height: 1px;
109
- background: var(--border);
110
- }
99
+ .ui-step.is-done {
100
+ color: var(--text);
101
+ }
102
+ .ui-step.is-done .ui-step__dot {
103
+ border-color: var(--primary);
104
+ background: var(--primary);
105
+ color: var(--primary-fg);
106
+ }
107
+
108
+ .ui-steps__sep {
109
+ flex: 1;
110
+ min-width: var(--space-4);
111
+ height: 1px;
112
+ background: var(--border);
113
+ }
111
114
 
112
- /* Mobile: only the current step keeps its label. */
113
- .ui-steps--mobile .ui-step:not(.is-current) .ui-step__label {
114
- display: none;
115
+ /* Mobile: only the current step keeps its label. */
116
+ .ui-steps--mobile .ui-step:not(.is-current) .ui-step__label {
117
+ display: none;
118
+ }
115
119
  }
116
120
  </style>