@kwtv/components 0.3.0 → 0.5.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 +46 -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 +37 -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
@@ -28,66 +28,70 @@ const classes = ["ui-navlink", current && "is-current", className]
28
28
  </a>
29
29
 
30
30
  <style>
31
- .ui-navlink {
32
- position: relative;
33
- display: inline-flex;
34
- align-items: center;
35
- gap: var(--space-1-5);
36
- /* 7 px block / 10 px inline padding with an equal negative margin, so the focus ring has room but the header rhythm does not shift. */
37
- padding: 7px 10px;
38
- margin: -7px -10px;
39
- border-radius: var(--radius-sm);
40
- font-family: var(--font-sans);
41
- font-size: var(--text-sm);
42
- font-weight: var(--weight-medium);
43
- line-height: 1;
44
- color: var(--text);
45
- text-decoration: none;
46
- background: none;
47
- border: 0;
48
- cursor: pointer;
49
- transition: color var(--duration-fast) var(--ease-standard);
50
- }
31
+ @layer reset, tokens, base, components, motion, utilities;
51
32
 
52
- .ui-navlink::after {
53
- content: "";
54
- position: absolute;
55
- left: 10px;
56
- right: 10px;
57
- bottom: 2px;
58
- height: 2px;
59
- background: currentColor;
60
- opacity: 0;
61
- transition: opacity var(--duration-fast) var(--ease-standard);
62
- }
33
+ @layer components {
34
+ .ui-navlink {
35
+ position: relative;
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: var(--space-1-5);
39
+ /* 7 px block / 10 px inline padding with an equal negative margin, so the focus ring has room but the header rhythm does not shift. */
40
+ padding: 7px 10px;
41
+ margin: -7px -10px;
42
+ border-radius: var(--radius-sm);
43
+ font-family: var(--font-sans);
44
+ font-size: var(--text-sm);
45
+ font-weight: var(--weight-medium);
46
+ line-height: 1;
47
+ color: var(--text);
48
+ text-decoration: none;
49
+ background: none;
50
+ border: 0;
51
+ cursor: pointer;
52
+ transition: color var(--duration-fast) var(--ease-standard);
53
+ }
63
54
 
64
- .ui-navlink:hover,
65
- .ui-navlink.is-hover {
66
- color: var(--link-hover);
67
- }
68
- .ui-navlink:hover::after,
69
- .ui-navlink.is-hover::after {
70
- opacity: 1;
71
- }
55
+ .ui-navlink::after {
56
+ content: "";
57
+ position: absolute;
58
+ left: 10px;
59
+ right: 10px;
60
+ bottom: 2px;
61
+ height: 2px;
62
+ background: currentColor;
63
+ opacity: 0;
64
+ transition: opacity var(--duration-fast) var(--ease-standard);
65
+ }
72
66
 
73
- .ui-navlink.is-current {
74
- font-weight: var(--weight-semibold);
75
- }
76
- .ui-navlink.is-current::after {
77
- opacity: 1;
78
- }
67
+ .ui-navlink:hover,
68
+ .ui-navlink.is-hover {
69
+ color: var(--link-hover);
70
+ }
71
+ .ui-navlink:hover::after,
72
+ .ui-navlink.is-hover::after {
73
+ opacity: 1;
74
+ }
79
75
 
80
- .ui-navlink:focus-visible,
81
- .ui-navlink.is-focus {
82
- outline: 2px solid var(--focus);
83
- outline-offset: 2px;
84
- box-shadow: 0 0 0 4px var(--focus-outer);
85
- }
76
+ .ui-navlink.is-current {
77
+ font-weight: var(--weight-semibold);
78
+ }
79
+ .ui-navlink.is-current::after {
80
+ opacity: 1;
81
+ }
86
82
 
87
- @media (prefers-reduced-motion: reduce) {
88
- .ui-navlink,
89
- .ui-navlink::after {
90
- transition: none;
83
+ .ui-navlink:focus-visible,
84
+ .ui-navlink.is-focus {
85
+ outline: 2px solid var(--focus);
86
+ outline-offset: 2px;
87
+ box-shadow: 0 0 0 4px var(--focus-outer);
88
+ }
89
+
90
+ @media (prefers-reduced-motion: reduce) {
91
+ .ui-navlink,
92
+ .ui-navlink::after {
93
+ transition: none;
94
+ }
91
95
  }
92
96
  }
93
97
  </style>
@@ -58,65 +58,69 @@ const classes = ["ui-news", stacked && "ui-news--stacked", className]
58
58
  </form>
59
59
 
60
60
  <style>
61
- .ui-news {
62
- display: flex;
63
- gap: var(--space-2);
64
- max-width: 420px;
65
- }
61
+ @layer reset, tokens, base, components, motion, utilities;
66
62
 
67
- .ui-news--stacked {
68
- flex-direction: column;
69
- }
63
+ @layer components {
64
+ .ui-news {
65
+ display: flex;
66
+ gap: var(--space-2);
67
+ max-width: 420px;
68
+ }
70
69
 
71
- .ui-news__input {
72
- flex: 1;
73
- min-width: 0;
74
- min-height: 48px;
75
- padding: 0 var(--space-4);
76
- background: var(--surface-light);
77
- border: 1px solid var(--border-strong-light);
78
- border-radius: var(--radius-md);
79
- font-family: var(--font-sans);
80
- font-size: var(--text-sm);
81
- color: var(--text-light);
82
- }
83
- .ui-news__input::placeholder {
84
- color: var(--text-muted-light);
85
- }
86
- .ui-news__input:focus-visible,
87
- .ui-news__input.is-focus {
88
- outline: 2px solid var(--focus);
89
- outline-offset: 2px;
90
- box-shadow: 0 0 0 4px var(--focus-outer);
91
- }
70
+ .ui-news--stacked {
71
+ flex-direction: column;
72
+ }
92
73
 
93
- .ui-news__btn {
94
- flex: none;
95
- min-height: 48px;
96
- padding: 0 var(--space-5);
97
- background: var(--sage-light);
98
- color: var(--sage-xdark);
99
- border: 0;
100
- border-radius: var(--radius-md);
101
- font-family: var(--font-sans);
102
- font-size: var(--text-sm);
103
- font-weight: var(--weight-semibold);
104
- cursor: pointer;
105
- transition: background-color var(--duration-fast) var(--ease-standard);
106
- }
107
- .ui-news__btn:hover,
108
- .ui-news__btn.is-hover {
109
- background: var(--sage-xlight);
110
- }
111
- .ui-news__btn:focus-visible {
112
- outline: 2px solid var(--focus);
113
- outline-offset: 2px;
114
- box-shadow: 0 0 0 4px var(--focus-outer);
115
- }
74
+ .ui-news__input {
75
+ flex: 1;
76
+ min-width: 0;
77
+ min-height: 48px;
78
+ padding: 0 var(--space-4);
79
+ background: var(--surface-light);
80
+ border: 1px solid var(--border-strong-light);
81
+ border-radius: var(--radius-md);
82
+ font-family: var(--font-sans);
83
+ font-size: var(--text-sm);
84
+ color: var(--text-light);
85
+ }
86
+ .ui-news__input::placeholder {
87
+ color: var(--text-muted-light);
88
+ }
89
+ .ui-news__input:focus-visible,
90
+ .ui-news__input.is-focus {
91
+ outline: 2px solid var(--focus);
92
+ outline-offset: 2px;
93
+ box-shadow: 0 0 0 4px var(--focus-outer);
94
+ }
116
95
 
117
- @media (prefers-reduced-motion: reduce) {
118
96
  .ui-news__btn {
119
- transition: none;
97
+ flex: none;
98
+ min-height: 48px;
99
+ padding: 0 var(--space-5);
100
+ background: var(--sage-light);
101
+ color: var(--sage-xdark);
102
+ border: 0;
103
+ border-radius: var(--radius-md);
104
+ font-family: var(--font-sans);
105
+ font-size: var(--text-sm);
106
+ font-weight: var(--weight-semibold);
107
+ cursor: pointer;
108
+ transition: background-color var(--duration-fast) var(--ease-standard);
109
+ }
110
+ .ui-news__btn:hover,
111
+ .ui-news__btn.is-hover {
112
+ background: var(--sage-xlight);
113
+ }
114
+ .ui-news__btn:focus-visible {
115
+ outline: 2px solid var(--focus);
116
+ outline-offset: 2px;
117
+ box-shadow: 0 0 0 4px var(--focus-outer);
118
+ }
119
+
120
+ @media (prefers-reduced-motion: reduce) {
121
+ .ui-news__btn {
122
+ transition: none;
123
+ }
120
124
  }
121
125
  }
122
126
  </style>
@@ -168,49 +168,53 @@ const hasNext = current < total;
168
168
  </script>
169
169
 
170
170
  <style>
171
- .ui-pager {
172
- display: flex;
173
- align-items: center;
174
- gap: var(--space-1);
175
- font-size: var(--text-sm);
176
- }
171
+ @layer reset, tokens, base, components, motion, utilities;
172
+
173
+ @layer components {
174
+ .ui-pager {
175
+ display: flex;
176
+ align-items: center;
177
+ gap: var(--space-1);
178
+ font-size: var(--text-sm);
179
+ }
177
180
 
178
- .ui-pager a,
179
- .ui-pager span:not(.ui-pager__gap) {
180
- display: inline-flex;
181
- align-items: center;
182
- justify-content: center;
183
- min-width: 36px;
184
- height: 36px;
185
- padding: 0 var(--space-1);
186
- border-radius: var(--radius-md);
187
- color: var(--link);
188
- text-decoration: none;
189
- }
181
+ .ui-pager a,
182
+ .ui-pager span:not(.ui-pager__gap) {
183
+ display: inline-flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ min-width: 36px;
187
+ height: 36px;
188
+ padding: 0 var(--space-1);
189
+ border-radius: var(--radius-md);
190
+ color: var(--link);
191
+ text-decoration: none;
192
+ }
190
193
 
191
- .ui-pager a:hover {
192
- background: var(--surface-hover);
193
- color: var(--link-hover);
194
- }
195
- .ui-pager a:focus-visible {
196
- outline: 2px solid var(--focus);
197
- outline-offset: 2px;
198
- }
194
+ .ui-pager a:hover {
195
+ background: var(--surface-hover);
196
+ color: var(--link-hover);
197
+ }
198
+ .ui-pager a:focus-visible {
199
+ outline: 2px solid var(--focus);
200
+ outline-offset: 2px;
201
+ }
199
202
 
200
- .ui-pager a.is-current {
201
- background: var(--primary);
202
- color: var(--primary-fg);
203
- font-weight: var(--weight-semibold);
204
- }
203
+ .ui-pager a.is-current {
204
+ background: var(--primary);
205
+ color: var(--primary-fg);
206
+ font-weight: var(--weight-semibold);
207
+ }
205
208
 
206
- .ui-pager .is-disabled {
207
- color: var(--border);
208
- cursor: not-allowed;
209
- }
209
+ .ui-pager .is-disabled {
210
+ color: var(--border);
211
+ cursor: not-allowed;
212
+ }
210
213
 
211
- .ui-pager__gap {
212
- min-width: 24px;
213
- text-align: center;
214
- color: var(--text-muted);
214
+ .ui-pager__gap {
215
+ min-width: 24px;
216
+ text-align: center;
217
+ color: var(--text-muted);
218
+ }
215
219
  }
216
220
  </style>
@@ -58,85 +58,89 @@ const classes = [
58
58
  </label>
59
59
 
60
60
  <style>
61
- .ui-pick {
62
- display: flex;
63
- align-items: flex-start;
64
- gap: var(--space-3);
65
- padding: var(--space-4);
66
- background: var(--surface);
67
- border: 1px solid var(--border);
68
- border-radius: var(--radius-lg);
69
- cursor: pointer;
70
- transition:
71
- border-color var(--duration-fast) var(--ease-standard),
72
- background-color var(--duration-fast) var(--ease-standard);
73
- }
61
+ @layer reset, tokens, base, components, motion, utilities;
74
62
 
75
- .ui-pick input {
76
- width: 18px;
77
- height: 18px;
78
- margin-top: 2px;
79
- flex-shrink: 0;
80
- accent-color: var(--primary);
81
- cursor: pointer;
82
- }
63
+ @layer components {
64
+ .ui-pick {
65
+ display: flex;
66
+ align-items: flex-start;
67
+ gap: var(--space-3);
68
+ padding: var(--space-4);
69
+ background: var(--surface);
70
+ border: 1px solid var(--border);
71
+ border-radius: var(--radius-lg);
72
+ cursor: pointer;
73
+ transition:
74
+ border-color var(--duration-fast) var(--ease-standard),
75
+ background-color var(--duration-fast) var(--ease-standard);
76
+ }
83
77
 
84
- .ui-pick input:focus-visible {
85
- outline: 2px solid var(--focus);
86
- outline-offset: 2px;
87
- box-shadow: 0 0 0 4px var(--focus-outer);
88
- }
78
+ .ui-pick input {
79
+ width: 18px;
80
+ height: 18px;
81
+ margin-top: 2px;
82
+ flex-shrink: 0;
83
+ accent-color: var(--primary);
84
+ cursor: pointer;
85
+ }
89
86
 
90
- .ui-pick__text {
91
- display: flex;
92
- flex-direction: column;
93
- gap: var(--space-1);
94
- font-family: var(--font-sans);
95
- }
87
+ .ui-pick input:focus-visible {
88
+ outline: 2px solid var(--focus);
89
+ outline-offset: 2px;
90
+ box-shadow: 0 0 0 4px var(--focus-outer);
91
+ }
96
92
 
97
- .ui-pick__title {
98
- font-size: var(--text-sm);
99
- font-weight: var(--weight-semibold);
100
- color: var(--text);
101
- }
93
+ .ui-pick__text {
94
+ display: flex;
95
+ flex-direction: column;
96
+ gap: var(--space-1);
97
+ font-family: var(--font-sans);
98
+ }
102
99
 
103
- .ui-pick__note {
104
- font-size: var(--text-xs);
105
- line-height: var(--leading-xs);
106
- color: var(--text-muted);
107
- }
100
+ .ui-pick__title {
101
+ font-size: var(--text-sm);
102
+ font-weight: var(--weight-semibold);
103
+ color: var(--text);
104
+ }
108
105
 
109
- .ui-pick:hover,
110
- .ui-pick.is-hover {
111
- border-color: var(--border-strong);
112
- }
106
+ .ui-pick__note {
107
+ font-size: var(--text-xs);
108
+ line-height: var(--leading-xs);
109
+ color: var(--text-muted);
110
+ }
113
111
 
114
- /* Selected: 2 px border. */
115
- .ui-pick.is-selected {
116
- border-width: 2px;
117
- border-color: var(--border-strong);
118
- background: var(--surface-accent);
119
- }
112
+ .ui-pick:hover,
113
+ .ui-pick.is-hover {
114
+ border-color: var(--border-strong);
115
+ }
120
116
 
121
- .ui-pick.is-selected .ui-pick__title {
122
- color: var(--surface-accent-fg, var(--text));
123
- }
117
+ /* Selected: 2 px border. */
118
+ .ui-pick.is-selected {
119
+ border-width: 2px;
120
+ border-color: var(--border-strong);
121
+ background: var(--surface-accent);
122
+ }
124
123
 
125
- /* The selected card sits on the sage accent surface, where --text-muted only
126
- reaches 3.6:1. The accent surface carries its own muted role for exactly
127
- this case. */
128
- .ui-pick.is-selected .ui-pick__note {
129
- color: var(--surface-accent-muted, var(--text));
130
- }
124
+ .ui-pick.is-selected .ui-pick__title {
125
+ color: var(--surface-accent-fg, var(--text));
126
+ }
131
127
 
132
- .ui-pick.is-disabled {
133
- opacity: 0.5;
134
- cursor: not-allowed;
135
- }
128
+ /* The selected card sits on the sage accent surface, where --text-muted only */
129
+ /* reaches 3.6:1. The accent surface carries its own muted role for exactly */
130
+ /* this case. */
131
+ .ui-pick.is-selected .ui-pick__note {
132
+ color: var(--surface-accent-muted, var(--text));
133
+ }
136
134
 
137
- @media (prefers-reduced-motion: reduce) {
138
- .ui-pick {
139
- transition: none;
135
+ .ui-pick.is-disabled {
136
+ opacity: 0.5;
137
+ cursor: not-allowed;
138
+ }
139
+
140
+ @media (prefers-reduced-motion: reduce) {
141
+ .ui-pick {
142
+ transition: none;
143
+ }
140
144
  }
141
145
  }
142
146
  </style>