@greese/ui 1.0.0 → 1.2.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 (210) hide show
  1. package/README.md +19 -14
  2. package/dist/_maps.scss +1 -1
  3. package/dist/_tokens-base.scss +30 -6
  4. package/dist/_tokens.scss +31 -2
  5. package/dist/_utilities-table.scss +1615 -0
  6. package/dist/clipboard.d.ts +18 -0
  7. package/dist/clipboard.js +62 -0
  8. package/dist/css/Button.css +2 -2
  9. package/dist/css/Carousel.css +145 -47
  10. package/dist/css/Checkbox.css +2 -2
  11. package/dist/css/Chip.css +38 -8
  12. package/dist/css/ChoiceGroup.css +42 -1
  13. package/dist/css/Collapsible.css +1 -0
  14. package/dist/css/ColorPicker.css +84 -0
  15. package/dist/css/Combobox.css +2 -2
  16. package/dist/css/Dialog.css +24 -22
  17. package/dist/css/EditableField.css +219 -0
  18. package/dist/css/Input.css +11 -2
  19. package/dist/css/Menu.css +9 -0
  20. package/dist/css/NumberField.css +53 -8
  21. package/dist/css/NumberStepper.css +9 -0
  22. package/dist/css/OtpField.css +1 -1
  23. package/dist/css/PageTransition.css +12 -0
  24. package/dist/css/Radio.css +2 -2
  25. package/dist/css/ScrollCarousel.css +225 -0
  26. package/dist/css/SegmentedControl.css +2 -2
  27. package/dist/css/Select.css +3 -2
  28. package/dist/css/Slider.css +45 -5
  29. package/dist/css/Switch.css +6 -6
  30. package/dist/css/Text.css +14 -14
  31. package/dist/css/Textarea.css +1 -1
  32. package/dist/css/core.css +36 -6
  33. package/dist/css/resets.css +162 -0
  34. package/dist/css.d.ts +2 -0
  35. package/dist/css.js +2 -0
  36. package/dist/greese.css +990 -138
  37. package/dist/index.d.ts +2 -1
  38. package/dist/index.js +2 -1
  39. package/dist/scss/components/_Accordion.scss +2 -0
  40. package/dist/scss/components/_ActionSelect.scss +2 -0
  41. package/dist/scss/components/_Alert.scss +2 -0
  42. package/dist/scss/components/_AppBar.scss +2 -0
  43. package/dist/scss/components/_AspectRatio.scss +2 -0
  44. package/dist/scss/components/_AutoLayout.scss +2 -0
  45. package/dist/scss/components/_Avatar.scss +2 -0
  46. package/dist/scss/components/_Badge.scss +2 -0
  47. package/dist/scss/components/_Box.scss +2 -0
  48. package/dist/scss/components/_Breadcrumbs.scss +2 -0
  49. package/dist/scss/components/_Button.scss +2 -0
  50. package/dist/scss/components/_ButtonGroup.scss +2 -0
  51. package/dist/scss/components/_Card.scss +2 -0
  52. package/dist/scss/components/_Carousel.scss +2 -0
  53. package/dist/scss/components/_Center.scss +2 -0
  54. package/dist/scss/components/_ChatBubble.scss +2 -0
  55. package/dist/scss/components/_Checkbox.scss +2 -0
  56. package/dist/scss/components/_Chip.scss +2 -0
  57. package/dist/scss/components/_ChoiceGroup.scss +2 -0
  58. package/dist/scss/components/_Code.scss +2 -0
  59. package/dist/scss/components/_Collapsible.scss +2 -0
  60. package/dist/scss/components/_ColorPicker.scss +2 -0
  61. package/dist/scss/components/_Combobox.scss +2 -0
  62. package/dist/scss/components/_Container.scss +2 -0
  63. package/dist/scss/components/_Countdown.scss +2 -0
  64. package/dist/scss/components/_DateField.scss +2 -0
  65. package/dist/scss/components/_Dialog.scss +2 -0
  66. package/dist/scss/components/_Diff.scss +2 -0
  67. package/dist/scss/components/_Divider.scss +2 -0
  68. package/dist/scss/components/_Dock.scss +2 -0
  69. package/dist/scss/components/_EditableField.scss +2 -0
  70. package/dist/scss/components/_Field.scss +2 -0
  71. package/dist/scss/components/_Fieldset.scss +2 -0
  72. package/dist/scss/components/_FileInput.scss +2 -0
  73. package/dist/scss/components/_Footer.scss +2 -0
  74. package/dist/scss/components/_Grid.scss +2 -0
  75. package/dist/scss/components/_Header.scss +2 -0
  76. package/dist/scss/components/_Heading.scss +2 -0
  77. package/dist/scss/components/_Icon.scss +2 -0
  78. package/dist/scss/components/_IconButton.scss +2 -0
  79. package/dist/scss/components/_Image.scss +2 -0
  80. package/dist/scss/components/_Indicator.scss +2 -0
  81. package/dist/scss/components/_Input.scss +2 -0
  82. package/dist/scss/components/_Key.scss +2 -0
  83. package/dist/scss/components/_Link.scss +2 -0
  84. package/dist/scss/components/_List.scss +2 -0
  85. package/dist/scss/components/_Media.scss +2 -0
  86. package/dist/scss/components/_Menu.scss +2 -0
  87. package/dist/scss/components/_Motion.scss +2 -0
  88. package/dist/scss/components/_NumberField.scss +2 -0
  89. package/dist/scss/components/_NumberStepper.scss +2 -0
  90. package/dist/scss/components/_OtpField.scss +2 -0
  91. package/dist/scss/components/_PageTransition.scss +2 -0
  92. package/dist/scss/components/_Pagination.scss +2 -0
  93. package/dist/scss/components/_Popover.scss +2 -0
  94. package/dist/scss/components/_Progress.scss +2 -0
  95. package/dist/scss/components/_RadialProgress.scss +2 -0
  96. package/dist/scss/components/_Radio.scss +2 -0
  97. package/dist/scss/components/_Rating.scss +2 -0
  98. package/dist/scss/components/_ScrollCarousel.scss +2 -0
  99. package/dist/scss/components/_ScrollSpy.scss +2 -0
  100. package/dist/scss/components/_SegmentedControl.scss +2 -0
  101. package/dist/scss/components/_Select.scss +2 -0
  102. package/dist/scss/components/_Sidebar.scss +2 -0
  103. package/dist/scss/components/_Skeleton.scss +2 -0
  104. package/dist/scss/components/_Slider.scss +2 -0
  105. package/dist/scss/components/_Spacer.scss +2 -0
  106. package/dist/scss/components/_SpeedDial.scss +2 -0
  107. package/dist/scss/components/_Spinner.scss +2 -0
  108. package/dist/scss/components/_Stack.scss +2 -0
  109. package/dist/scss/components/_Stat.scss +2 -0
  110. package/dist/scss/components/_Status.scss +2 -0
  111. package/dist/scss/components/_Steps.scss +2 -0
  112. package/dist/scss/components/_Swap.scss +2 -0
  113. package/dist/scss/components/_Switch.scss +2 -0
  114. package/dist/scss/components/_Table.scss +2 -0
  115. package/dist/scss/components/_Tabs.scss +2 -0
  116. package/dist/scss/components/_Text.scss +2 -0
  117. package/dist/scss/components/_TextRotate.scss +2 -0
  118. package/dist/scss/components/_Textarea.scss +2 -0
  119. package/dist/scss/components/_ThemeProvider.scss +2 -0
  120. package/dist/scss/components/_Tile.scss +2 -0
  121. package/dist/scss/components/_Toast.scss +2 -0
  122. package/dist/scss/components/_ToggleButton.scss +2 -0
  123. package/dist/scss/components/_Tooltip.scss +2 -0
  124. package/dist/scss/components/_Type.scss +2 -0
  125. package/dist/scss/components/_Visibility.scss +2 -0
  126. package/dist/scss/components/_VisuallyHidden.scss +2 -0
  127. package/dist/shapes.d.ts +12 -1
  128. package/dist/shapes.js +11 -10
  129. package/dist/style-manifest.json +18837 -132
  130. package/dist/theme.js +6 -1
  131. package/dist/themeFiles/index.d.ts +9 -0
  132. package/dist/themeFiles/index.js +9 -0
  133. package/dist/themeFiles/scssModule.d.ts +100 -0
  134. package/dist/themeFiles/scssModule.js +384 -0
  135. package/dist/themeFiles/spec.d.ts +198 -0
  136. package/dist/themeFiles/spec.js +877 -0
  137. package/dist/tokens.css +30 -1
  138. package/dist/typography.js +1 -1
  139. package/dist/utilities.css +435 -0
  140. package/dist/utilities.d.ts +8 -0
  141. package/dist/utilities.js +75 -0
  142. package/package.json +20 -1
  143. package/src/components/AutoLayout/AutoLayout.scss +2 -26
  144. package/src/components/Carousel/Carousel.scss +122 -126
  145. package/src/components/Checkbox/Checkbox.scss +2 -2
  146. package/src/components/Chip/Chip.scss +63 -8
  147. package/src/components/ChoiceGroup/ChoiceGroup.scss +19 -1
  148. package/src/components/Collapsible/Collapsible.scss +3 -0
  149. package/src/components/ColorPicker/ColorPicker.scss +95 -0
  150. package/src/components/Combobox/Combobox.scss +4 -2
  151. package/src/components/Dialog/Dialog.scss +24 -7
  152. package/src/components/EditableField/EditableField.scss +275 -0
  153. package/src/components/Grid/Grid.scss +2 -70
  154. package/src/components/Input/Input.scss +29 -0
  155. package/src/components/Menu/Menu.scss +18 -0
  156. package/src/components/NumberField/NumberField.scss +56 -9
  157. package/src/components/NumberStepper/NumberStepper.scss +13 -0
  158. package/src/components/PageTransition/PageTransition.scss +29 -0
  159. package/src/components/Radio/Radio.scss +2 -2
  160. package/src/components/ScrollCarousel/ScrollCarousel.scss +142 -0
  161. package/src/components/Select/Select.scss +4 -0
  162. package/src/components/Slider/Slider.scss +51 -6
  163. package/src/components/Stack/Stack.scss +2 -48
  164. package/src/components/Switch/Switch.scss +9 -6
  165. package/src/components/Text/Text.scss +5 -2
  166. package/src/styles/_breakpoint-vars.scss +17 -11
  167. package/src/styles/_controls.scss +2 -2
  168. package/src/styles/_core.scss +1 -0
  169. package/src/styles/_kit.scss +483 -56
  170. package/src/styles/_layout-props.scss +197 -0
  171. package/src/styles/_manifest.scss +55 -25
  172. package/src/styles/_mixins.scss +53 -15
  173. package/src/styles/_slides.scss +112 -0
  174. package/src/styles/_utilities.scss +104 -0
  175. package/src/styles/breakpoints.test.ts +21 -1
  176. package/src/styles/entryPoints.test.ts +25 -2
  177. package/src/styles/index.scss +3 -1
  178. package/src/styles/kit.test.ts +171 -1
  179. package/src/styles/public/_breakpoints.scss +43 -0
  180. package/src/styles/public/_slides.scss +3 -0
  181. package/src/styles/public/_utilities.scss +3 -0
  182. package/src/styles/resets.scss +7 -0
  183. package/src/styles/utilities.test.ts +39 -0
  184. package/themes/bevel.css +187 -187
  185. package/themes/bevel.scss +960 -958
  186. package/themes/candy.css +87 -0
  187. package/themes/candy.scss +32 -0
  188. package/themes/extrude.css +42 -42
  189. package/themes/folio.css +200 -200
  190. package/themes/folio.scss +880 -878
  191. package/themes/forest.css +87 -0
  192. package/themes/forest.scss +32 -0
  193. package/themes/grape.css +87 -0
  194. package/themes/grape.scss +32 -0
  195. package/themes/greese.css +36 -0
  196. package/themes/greese.scss +21 -0
  197. package/themes/mono.css +87 -0
  198. package/themes/mono.scss +32 -0
  199. package/themes/ocean.css +87 -0
  200. package/themes/ocean.scss +32 -0
  201. package/themes/outline.css +18 -18
  202. package/themes/pebble.css +8 -8
  203. package/themes/ridge.css +188 -188
  204. package/themes/ridge.scss +820 -818
  205. package/themes/soft.css +11 -11
  206. package/themes/sunset.css +87 -0
  207. package/themes/sunset.scss +32 -0
  208. package/themes/ticket.css +180 -180
  209. package/themes/ticket.scss +881 -879
  210. package/themes/tilt.css +25 -25
@@ -1,161 +1,157 @@
1
1
  @use '../../styles/mixins';
2
+ @use '../../styles/slides';
3
+
4
+ // What a leaving slide's exit sets, and the base theme's values: a slide out
5
+ // the way the carousel moves, no mask.
6
+ $_exit: (
7
+ opacity: 1,
8
+ translate: calc(-100% * var(--greese-carousel-way)) 0,
9
+ scale: 1,
10
+ mask-image: none,
11
+ mask-repeat: no-repeat,
12
+ mask-position: 50% 50%,
13
+ mask-size: 100% 100%,
14
+ mask-from: 100% 100%,
15
+ transform: none,
16
+ transform-origin: 50% 50%,
17
+ );
18
+
19
+ /// A leaving slide's exit value: its own (the instance's `exit`, as an
20
+ /// effect class on the slide), else the role's for the direction it goes.
21
+ @function _exit($property) {
22
+ @return var(
23
+ --greese-motion-exit-#{$property},
24
+ var(--greese-carousel-exit-#{$property})
25
+ );
26
+ }
2
27
 
3
28
  @layer greese.components {
29
+ // One slide at a time: the others stack under it, in the same cell, so the
30
+ // carousel is as tall as its tallest slide and never jumps as it moves.
4
31
  .greese-Carousel {
5
32
  @include mixins.component-root;
6
33
 
34
+ // 1 going forward, -1 going back; mirrored right-to-left, where forward
35
+ // runs leftward.
36
+ --greese-carousel-way: 1;
37
+
38
+ // The theme's motion roles (ADR 0025): `carousel` and `carousel-exit`,
39
+ // and `carousel-back` and `carousel-back-exit` going back (each falling
40
+ // back to its forward role). The base theme slides the way it moves.
41
+ --greese-carousel-enter: var(--greese-motion-carousel, greese-carousel-in);
42
+ --greese-carousel-duration: var(
43
+ --greese-motion-carousel-duration,
44
+ var(--greese-duration-normal)
45
+ );
46
+
47
+ @each $property, $base in $_exit {
48
+ --greese-carousel-exit-#{$property}: var(
49
+ --greese-motion-carousel-exit-#{$property},
50
+ #{$base}
51
+ );
52
+ }
53
+
7
54
  position: relative;
8
55
  display: grid;
9
56
  gap: var(--greese-space-3);
10
57
  min-inline-size: 0;
11
- }
12
58
 
13
- // Native scrolling and snapping: swipe, trackpad and keys all work.
14
- .greese-Carousel-viewport {
15
- --greese-carousel-per-view: 1;
16
- --greese-carousel-gap: var(--greese-space-3);
17
-
18
- display: flex;
19
- gap: var(--greese-carousel-gap);
20
- overflow-x: auto;
21
- overscroll-behavior-x: contain;
22
- scroll-snap-type: x mandatory;
23
- scrollbar-width: none;
24
- border-radius: var(--greese-corner-panel);
25
-
26
- &::-webkit-scrollbar {
27
- display: none;
59
+ &[data-direction='back'] {
60
+ --greese-carousel-way: -1;
61
+ --greese-carousel-enter: var(
62
+ --greese-motion-carousel-back,
63
+ var(--greese-motion-carousel, greese-carousel-in)
64
+ );
65
+
66
+ @each $property, $base in $_exit {
67
+ --greese-carousel-exit-#{$property}: var(
68
+ --greese-motion-carousel-back-exit-#{$property},
69
+ var(--greese-motion-carousel-exit-#{$property}, #{$base})
70
+ );
71
+ }
28
72
  }
29
73
 
30
- @include mixins.focus-ring;
74
+ &:dir(rtl) {
75
+ --greese-carousel-way: -1;
76
+ }
31
77
 
32
- @media (prefers-reduced-motion: no-preference) {
33
- scroll-behavior: smooth;
78
+ &[data-direction='back']:dir(rtl) {
79
+ --greese-carousel-way: 1;
34
80
  }
35
81
  }
36
82
 
37
- // Each slide's width: the viewport shared by `per-view` slides and the gaps.
38
- .greese-CarouselSlide {
39
- --greese-carousel-gaps: calc(
40
- (var(--greese-carousel-per-view) - 1) * var(--greese-carousel-gap)
41
- );
83
+ .greese-Carousel-viewport {
84
+ // An exit set on an ancestor (a dialog's `greese` exit) is not the
85
+ // slides': cleared here, so they fall back to their own and the role's.
86
+ @each $property, $base in $_exit {
87
+ --greese-motion-exit-#{$property}: initial;
88
+ }
89
+
90
+ // The instance's entrance, set on the slide that arrives; cleared for
91
+ // nested carousels.
92
+ --greese-carousel-slide-enter: initial;
42
93
 
43
- flex: 0 0 calc((100% - var(--greese-carousel-gaps)) / var(--greese-carousel-per-view));
94
+ display: grid;
44
95
  min-inline-size: 0;
45
- scroll-snap-align: start;
46
- }
96
+ overflow: clip;
97
+ border-radius: var(--greese-corner-panel);
47
98
 
48
- // Previous and next sit over the viewport's edges, centred on it.
49
- .greese-Carousel-control {
50
- position: absolute;
51
- inset-block-start: calc(50% - 1.25rem - var(--greese-carousel-dots, 0px) / 2);
52
- display: inline-grid;
53
- place-items: center;
54
- inline-size: 2.5rem;
55
- block-size: 2.5rem;
56
- padding: 0;
57
- color: var(--greese-color-fg);
58
- cursor: pointer;
59
- background-color: color-mix(
60
- in oklab,
61
- var(--greese-color-surface-overlay) 88%,
62
- transparent
63
- );
64
- border: 1px solid var(--greese-color-border);
65
- border-radius: var(--greese-corner-round);
66
- box-shadow: var(--greese-shadow-md);
67
- translate: 0 -50%;
68
- transition: opacity var(--greese-duration-fast) var(--greese-easing-standard);
99
+ // Vertical drags still scroll the page; sideways ones are swipes.
100
+ touch-action: pan-y;
69
101
 
70
102
  @include mixins.focus-ring;
71
- @include mixins.touch-target;
72
-
73
- &:disabled {
74
- cursor: default;
75
- opacity: 0;
76
- }
77
-
78
- > svg {
79
- inline-size: 1.125rem;
80
- block-size: 1.125rem;
81
- }
82
103
  }
83
104
 
84
- .greese-Carousel:has(.greese-Carousel-indicators) {
85
- --greese-carousel-dots: calc(0.5rem + var(--greese-space-3));
86
- }
87
-
88
- .greese-Carousel-control--previous {
89
- inset-inline-start: var(--greese-space-2);
90
- }
91
-
92
- .greese-Carousel-control--next {
93
- inset-inline-end: var(--greese-space-2);
105
+ .greese-CarouselSlide {
106
+ grid-area: 1 / 1;
107
+ min-inline-size: 0;
94
108
 
95
- > svg {
96
- scale: -1 1;
109
+ // A wipe, iris or pocket exit's mask: held open at the size it starts
110
+ // from, then sized away as the slide leaves. Without one, it's `none`.
111
+ mask-image: _exit(mask-image);
112
+ mask-repeat: _exit(mask-repeat);
113
+ mask-position: _exit(mask-position);
114
+ mask-size: _exit(mask-from);
115
+ transform-origin: _exit(transform-origin);
116
+
117
+ &:not([data-active]) {
118
+ visibility: hidden;
119
+ opacity: _exit(opacity);
120
+ translate: _exit(translate);
121
+ scale: _exit(scale);
122
+ transform: _exit(transform);
123
+ mask-size: _exit(mask-size);
97
124
  }
98
125
  }
99
126
 
100
- // The chevron points to the inline start; mirror both in RTL.
101
- .greese-Carousel-control:dir(rtl) > svg {
102
- scale: -1 1;
103
- }
104
-
105
- .greese-Carousel-control--next:dir(rtl) > svg {
106
- scale: 1;
107
- }
108
-
109
- // Phones swipe; the buttons come back where a pointer can hover.
110
- @media (hover: none) {
111
- .greese-Carousel-control {
112
- display: none;
127
+ // Only once it has moved: the slide it opens on (a deep link's) is simply
128
+ // there. The arriving slide plays its entrance; the one leaving
129
+ // transitions to its exit, and is hidden when that ends. The arriving one
130
+ // has no transition, so its exit values never fight its entrance.
131
+ @include mixins.motion-safe {
132
+ .greese-Carousel[data-moved] > .greese-Carousel-viewport > .greese-CarouselSlide {
133
+ &[data-active] {
134
+ animation-name: var(--greese-carousel-slide-enter, var(--greese-carousel-enter));
135
+ animation-duration: var(--greese-carousel-duration);
136
+ animation-timing-function: var(--greese-easing-standard);
137
+ animation-fill-mode: backwards;
138
+ }
139
+
140
+ &:not([data-active]) {
141
+ transition-property:
142
+ visibility, opacity, translate, scale, transform, mask-size, mask-position;
143
+ transition-duration: var(--greese-carousel-duration);
144
+ transition-timing-function: var(--greese-easing-standard);
145
+ }
113
146
  }
114
147
  }
115
148
 
116
- .greese-Carousel-indicators {
117
- display: flex;
118
- flex-wrap: wrap;
119
- gap: var(--greese-space-1);
120
- justify-content: center;
121
- }
122
-
123
- // Each dot keeps one size; the active pill is drawn by clip-path, which
124
- // never changes layout. A width change would: mid-scroll, every frame of
125
- // it made WebKit re-snap the viewport and pull it back a slide.
126
- .greese-Carousel-indicator {
127
- position: relative;
128
- inline-size: 1.5rem;
129
- block-size: 0.5rem;
130
- padding: 0;
131
- cursor: pointer;
132
- background: none;
133
- border: 0;
134
-
135
- @include mixins.focus-ring;
136
- @include mixins.touch-target(24px);
137
-
138
- &::before {
139
- position: absolute;
140
- inset: 0;
141
- content: '';
142
- background-color: var(--greese-color-border-strong);
143
- border-radius: var(--greese-corner-pill);
144
- clip-path: inset(0 calc(50% - 0.25rem) round var(--greese-corner-pill));
145
- transition:
146
- clip-path var(--greese-duration-normal) var(--greese-easing-standard),
147
- background-color var(--greese-duration-normal) var(--greese-easing-standard);
148
- }
149
+ @include slides.controls('greese-Carousel', carousel);
149
150
 
150
- &[aria-current='true']::before {
151
- background-color: var(--greese-color-primary);
152
- clip-path: inset(0 round var(--greese-corner-pill));
151
+ // The base theme's entrance: in from the side the carousel moves toward.
152
+ @keyframes greese-carousel-in {
153
+ from {
154
+ translate: calc(100% * var(--greese-carousel-way)) 0;
153
155
  }
154
156
  }
155
-
156
- @include mixins.responsive-prop(
157
- 'greese-Carousel',
158
- 'per-view',
159
- --greese-carousel-per-view
160
- );
161
157
  }
@@ -5,8 +5,8 @@
5
5
  @include mixins.touch-target;
6
6
 
7
7
  position: relative;
8
- inline-size: 1.125rem;
9
- block-size: 1.125rem;
8
+ inline-size: var(--greese-choice-box, 1.125rem);
9
+ block-size: var(--greese-choice-box, 1.125rem);
10
10
  margin: 0;
11
11
  cursor: pointer;
12
12
  background-color: var(--greese-color-canvas);
@@ -1,15 +1,56 @@
1
1
  @use 'sass:list';
2
+ @use 'sass:map';
2
3
  @use '../../styles/mixins';
3
4
  @use '../../styles/tones';
4
5
 
6
+ /// A chip's size scale.
7
+ ///
8
+ /// Deliberately not `controls.$sizes`: a chip is a label, not something you
9
+ /// type in, so it runs smaller than an input of the same name and needs no
10
+ /// 44px touch floor of its own (only its toggle and remove buttons do, and
11
+ /// `mixins.touch-target` gives them one). `md` is the size every chip was
12
+ /// before the prop existed, so nothing moved when it arrived.
13
+ $chip-sizes: (
14
+ xs: (
15
+ height: 1.25rem,
16
+ padding: var(--greese-space-1),
17
+ font: var(--greese-type-caption-font-size),
18
+ remove: 1rem,
19
+ ),
20
+ sm: (
21
+ height: 1.625rem,
22
+ padding: var(--greese-space-2),
23
+ font: var(--greese-type-caption-font-size),
24
+ remove: 1.25rem,
25
+ ),
26
+ md: (
27
+ height: 2rem,
28
+ padding: var(--greese-space-3),
29
+ font: var(--greese-type-p3-font-size),
30
+ remove: 1.5rem,
31
+ ),
32
+ lg: (
33
+ height: 2.5rem,
34
+ padding: var(--greese-space-4),
35
+ font: var(--greese-type-p2-font-size),
36
+ remove: 1.75rem,
37
+ ),
38
+ xl: (
39
+ height: 3rem,
40
+ padding: var(--greese-space-5),
41
+ font: var(--greese-type-p1-font-size),
42
+ remove: 2rem,
43
+ ),
44
+ );
45
+
5
46
  @layer greese.components {
6
47
  .greese-Chip {
7
48
  display: inline-flex;
8
49
  gap: var(--greese-space-1);
9
50
  align-items: center;
10
- min-block-size: 2rem;
11
- padding-inline: var(--greese-space-3);
12
- font-size: var(--greese-type-p3-font-size);
51
+ min-block-size: var(--greese-chip-height);
52
+ padding-inline: var(--greese-chip-padding);
53
+ font-size: var(--greese-chip-font);
13
54
  line-height: 1;
14
55
  color: var(--greese-color-fg);
15
56
  white-space: nowrap;
@@ -26,6 +67,18 @@
26
67
  }
27
68
  }
28
69
 
70
+ // Sizes. Each sets the three per-instance variables the block reads, so an
71
+ // app can override one of them on a chip (or a whole area) without picking a
72
+ // different size.
73
+ @each $size, $spec in $chip-sizes {
74
+ .greese-Chip--size-#{$size} {
75
+ --greese-chip-height: #{map.get($spec, height)};
76
+ --greese-chip-padding: #{map.get($spec, padding)};
77
+ --greese-chip-font: #{map.get($spec, font)};
78
+ --greese-chip-remove: #{map.get($spec, remove)};
79
+ }
80
+ }
81
+
29
82
  $chip-tones: (
30
83
  neutral,
31
84
  primary,
@@ -95,20 +148,22 @@
95
148
 
96
149
  .greese-Chip-toggle {
97
150
  align-self: stretch;
98
- padding-inline: var(--greese-space-3);
151
+ padding-inline: var(--greese-chip-padding);
99
152
  border-radius: var(--greese-corner-pill);
100
153
  }
101
154
 
102
155
  .greese-Chip-remove {
103
156
  justify-content: center;
104
- inline-size: 1.5rem;
105
- block-size: 1.5rem;
157
+
158
+ // Scales with the chip, or it overflows a small one.
159
+ inline-size: var(--greese-chip-remove);
160
+ block-size: var(--greese-chip-remove);
106
161
  color: var(--greese-color-fg-muted);
107
162
  border-radius: var(--greese-corner-round);
108
163
 
109
164
  > svg {
110
- inline-size: 0.875rem;
111
- block-size: 0.875rem;
165
+ inline-size: 0.6em;
166
+ block-size: 0.6em;
112
167
  }
113
168
 
114
169
  @include mixins.hover {
@@ -1,3 +1,5 @@
1
+ @use 'sass:map';
2
+ @use '../../styles/controls';
1
3
  @use '../../styles/mixins';
2
4
 
3
5
  @layer greese.components {
@@ -38,6 +40,21 @@
38
40
  }
39
41
  }
40
42
 
43
+ // The size a Checkbox, Radio or Switch was given reaches its text through
44
+ // these variables: one scale for the three, so a column of mixed controls
45
+ // lines up. `controls.$sizes` is the same scale Input, Select and Button
46
+ // use.
47
+ @each $size, $spec in controls.$sizes {
48
+ .greese-Checkbox--size-#{$size},
49
+ .greese-Radio--size-#{$size},
50
+ .greese-Switch--size-#{$size},
51
+ .greese-ChoiceGroup--size-#{$size} {
52
+ --greese-choice-font: #{map.get($spec, font)};
53
+ --greese-choice-gap: #{map.get($spec, padding)};
54
+ --greese-choice-box: calc(#{map.get($spec, height)} * 0.45);
55
+ }
56
+ }
57
+
41
58
  .greese-Checkbox-text {
42
59
  display: flex;
43
60
  flex-direction: column;
@@ -45,6 +62,7 @@
45
62
  }
46
63
 
47
64
  .greese-Checkbox-label {
65
+ font-size: var(--greese-choice-font, inherit);
48
66
  cursor: pointer;
49
67
 
50
68
  [data-disabled] > .greese-Checkbox-text > & {
@@ -53,7 +71,7 @@
53
71
  }
54
72
 
55
73
  .greese-Checkbox-description {
56
- font-size: var(--greese-type-p3-font-size);
74
+ font-size: var(--greese-choice-description-font, var(--greese-type-p3-font-size));
57
75
  color: var(--greese-color-fg-muted);
58
76
  }
59
77
 
@@ -123,6 +123,9 @@
123
123
  }
124
124
 
125
125
  .greese-Collapsible-content {
126
+ // Holds its children's margins: one that escaped would count while the
127
+ // height animates and drop out at the end, a jump the size of the margin.
128
+ display: flow-root;
126
129
  padding-block-end: var(--greese-space-4);
127
130
  color: var(--greese-color-fg-muted);
128
131
 
@@ -1,3 +1,5 @@
1
+ @use 'sass:map';
2
+ @use '../../styles/controls';
1
3
  @use '../../styles/mixins';
2
4
 
3
5
  /* stylelint-disable selector-no-vendor-prefix */
@@ -21,7 +23,15 @@ $checker: repeating-conic-gradient(#c8ccd2 0% 25%, #fff 0% 50%) 0 0 / 0.75rem 0.
21
23
  var(--greese-shadow-sm);
22
24
  }
23
25
 
26
+ // The picker's own number and text fields take the size the picker was given.
24
27
  @layer greese.components {
28
+ @each $size, $spec in controls.$sizes {
29
+ .greese-ColorPicker--size-#{$size} {
30
+ --greese-colorpicker-font: #{map.get($spec, font)};
31
+ --greese-colorpicker-padding: #{map.get($spec, padding)};
32
+ }
33
+ }
34
+
25
35
  .greese-ColorPicker {
26
36
  --greese-colorpicker-thumb: 1.125rem;
27
37
 
@@ -189,10 +199,95 @@ $checker: repeating-conic-gradient(#c8ccd2 0% 25%, #fff 0% 50%) 0 0 / 0.75rem 0.
189
199
  direction: ltr;
190
200
  }
191
201
 
202
+ // The hex field and any numeric channel sets, wrapping onto new lines in a
203
+ // narrow picker rather than squeezing the fields.
204
+ .greese-ColorPicker-fields {
205
+ display: flex;
206
+ flex-wrap: wrap;
207
+ gap: var(--greese-space-2);
208
+ align-items: center;
209
+ }
210
+
192
211
  .greese-ColorPicker-hex {
212
+ flex: 1 1 7rem;
213
+ min-inline-size: 0;
193
214
  font-family: var(--greese-font-mono);
194
215
  }
195
216
 
217
+ // A channel set takes a row of its own: sharing one with the hex field left
218
+ // three numbers about 3rem each, and a blue of 246 did not fit.
219
+ .greese-ColorPicker-channels {
220
+ display: flex;
221
+ flex: 1 0 100%;
222
+ gap: var(--greese-space-2);
223
+ min-inline-size: 0;
224
+ }
225
+
226
+ // Input's own root; its `<input>` is the `-control` part inside.
227
+ .greese-ColorPicker-channel {
228
+ flex: 1;
229
+ min-inline-size: 0;
230
+ padding-inline: var(--greese-space-1);
231
+
232
+ .greese-Input-control {
233
+ font-family: var(--greese-font-mono);
234
+ text-align: end;
235
+
236
+ // Three numbers side by side have no room for a spinner, and the area
237
+ // and hue slider are how a value gets nudged.
238
+ appearance: textfield;
239
+
240
+ &::-webkit-outer-spin-button,
241
+ &::-webkit-inner-spin-button {
242
+ margin: 0;
243
+ appearance: none;
244
+ }
245
+ }
246
+
247
+ .greese-Input-adornment {
248
+ font-family: var(--greese-font-mono);
249
+ color: var(--greese-color-fg-muted);
250
+ }
251
+ }
252
+
253
+ // The picker's own small buttons: the eyedropper, and saving or clearing a
254
+ // swatch. Plain buttons rather than IconButton, so a picker that shows none
255
+ // of them doesn't carry Button's variants (see .size-limit.cjs).
256
+ .greese-ColorPicker-tool {
257
+ display: inline-flex;
258
+ flex: none;
259
+ align-items: center;
260
+ justify-content: center;
261
+ inline-size: 1.75rem;
262
+ block-size: 1.75rem;
263
+ padding: 0;
264
+ color: var(--greese-color-fg-muted);
265
+ cursor: pointer;
266
+ background: none;
267
+ border: 0;
268
+ border-radius: var(--greese-corner-inset);
269
+
270
+ @media (pointer: coarse) {
271
+ inline-size: 2.25rem;
272
+ block-size: 2.25rem;
273
+ }
274
+
275
+ &:hover:not(:disabled) {
276
+ color: var(--greese-color-fg);
277
+ background: var(--greese-color-track);
278
+ }
279
+
280
+ &:focus-visible {
281
+ outline: 2px solid var(--greese-color-focus-ring);
282
+ outline-offset: 2px;
283
+ }
284
+
285
+ &:disabled {
286
+ cursor: not-allowed;
287
+ opacity: 0.5;
288
+ }
289
+ }
290
+
196
291
  .greese-ColorPicker-swatches {
197
292
  display: flex;
198
293
  flex-wrap: wrap;
@@ -8,8 +8,10 @@
8
8
  position: relative;
9
9
  display: inline-grid;
10
10
  place-items: center;
11
- inline-size: 1.75rem;
12
- block-size: 1.75rem;
11
+
12
+ // Never taller than the field it sits in, so an xs field stays xs.
13
+ inline-size: min(1.75rem, var(--greese-input-height, 1.75rem) - 2px);
14
+ block-size: min(1.75rem, var(--greese-input-height, 1.75rem) - 2px);
13
15
  padding: 0;
14
16
  margin-inline-end: calc(-1 * var(--greese-space-2));
15
17
  color: var(--greese-color-fg-muted);
@@ -34,7 +34,7 @@ $widths: (
34
34
  );
35
35
  max-inline-size: none;
36
36
  max-block-size: calc(100dvh - 2 * var(--greese-space-4));
37
- padding: var(--greese-space-5);
37
+ padding: var(--greese-dialog-padding, var(--greese-space-5));
38
38
  overflow: hidden;
39
39
  border-radius: var(--greese-corner-surface);
40
40
 
@@ -84,8 +84,14 @@ $widths: (
84
84
  inline-size: 100vw;
85
85
  max-block-size: 100dvh;
86
86
  block-size: 100dvh;
87
- padding-block: max(var(--greese-space-5), env(safe-area-inset-top))
88
- max(var(--greese-space-5), env(safe-area-inset-bottom));
87
+ padding-block: var(
88
+ --greese-dialog-padding,
89
+ max(var(--greese-space-5), env(safe-area-inset-top))
90
+ )
91
+ var(
92
+ --greese-dialog-padding,
93
+ max(var(--greese-space-5), env(safe-area-inset-bottom))
94
+ );
89
95
  border: 0;
90
96
  border-radius: 0;
91
97
  }
@@ -120,6 +126,11 @@ $widths: (
120
126
  .greese-Dialog-body {
121
127
  flex: 1 1 auto;
122
128
  min-block-size: 0;
129
+
130
+ // Room for a focus ring at its edges, which its scrolling would clip; the
131
+ // margin gives it back, so the content stays where it was.
132
+ padding: 4px;
133
+ margin: -4px;
123
134
  overflow: auto;
124
135
  overscroll-behavior: contain;
125
136
  }
@@ -157,8 +168,14 @@ $widths: (
157
168
  }
158
169
 
159
170
  $edge: var(--greese-corner-surface);
160
- $safe-top: max(var(--greese-space-5), env(safe-area-inset-top));
161
- $safe-bottom: max(var(--greese-space-5), env(safe-area-inset-bottom));
171
+ $safe-top: var(
172
+ --greese-dialog-padding,
173
+ max(var(--greese-space-5), env(safe-area-inset-top))
174
+ );
175
+ $safe-bottom: var(
176
+ --greese-dialog-padding,
177
+ max(var(--greese-space-5), env(safe-area-inset-bottom))
178
+ );
162
179
  $side-size: min(24rem, 100vw - 3rem);
163
180
  $placements: (
164
181
  end: (
@@ -187,7 +204,7 @@ $widths: (
187
204
  inline-size: 100vw,
188
205
  block-size: auto,
189
206
  max-block-size: 85dvh,
190
- padding-block: var(--greese-space-5) $safe-bottom,
207
+ padding-block: var(--greese-dialog-padding, var(--greese-space-5)) $safe-bottom,
191
208
  radius: $edge $edge 0 0,
192
209
  from: 0 100%,
193
210
  ),
@@ -197,7 +214,7 @@ $widths: (
197
214
  inline-size: 100vw,
198
215
  block-size: auto,
199
216
  max-block-size: 85dvh,
200
- padding-block: $safe-top var(--greese-space-5),
217
+ padding-block: $safe-top var(--greese-dialog-padding, var(--greese-space-5)),
201
218
  radius: 0 0 $edge $edge,
202
219
  from: 0 -100%,
203
220
  ),