@greese/ui 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +55 -2
- package/bin/greese-utilities.mjs +56 -0
- package/dist/_layers.scss +2 -0
- package/dist/_maps.scss +1884 -0
- package/dist/_tokens-base.scss +174 -0
- package/dist/_tokens.scss +2140 -0
- package/dist/base.css +67 -0
- package/dist/colorScheme.d.ts +16 -0
- package/dist/colorScheme.js +13 -0
- package/dist/contrast.d.ts +15 -0
- package/dist/contrast.js +43 -0
- package/dist/css/Accordion.css +9 -0
- package/dist/css/ActionSelect.css +6 -0
- package/dist/css/Alert.css +84 -0
- package/dist/css/AppBar.css +35 -0
- package/dist/css/AspectRatio.css +40 -0
- package/dist/css/AutoLayout.css +508 -0
- package/dist/css/Avatar.css +88 -0
- package/dist/css/Badge.css +66 -0
- package/dist/css/Box.css +640 -0
- package/dist/css/Breadcrumbs.css +57 -0
- package/dist/css/Button.css +275 -0
- package/dist/css/ButtonGroup.css +40 -0
- package/dist/css/Card.css +101 -0
- package/dist/css/Carousel.css +170 -0
- package/dist/css/Center.css +11 -0
- package/dist/css/ChatBubble.css +128 -0
- package/dist/css/Checkbox.css +65 -0
- package/dist/css/Chip.css +124 -0
- package/dist/css/ChoiceGroup.css +57 -0
- package/dist/css/Code.css +29 -0
- package/dist/css/Collapsible.css +126 -0
- package/dist/css/ColorPicker.css +191 -0
- package/dist/css/Combobox.css +90 -0
- package/dist/css/Container.css +30 -0
- package/dist/css/Countdown.css +25 -0
- package/dist/css/DateField.css +15 -0
- package/dist/css/Dialog.css +640 -0
- package/dist/css/Diff.css +103 -0
- package/dist/css/Divider.css +19 -0
- package/dist/css/Dock.css +91 -0
- package/dist/css/Field.css +33 -0
- package/dist/css/Fieldset.css +54 -0
- package/dist/css/FileInput.css +65 -0
- package/dist/css/Footer.css +72 -0
- package/dist/css/Grid.css +998 -0
- package/dist/css/Header.css +89 -0
- package/dist/css/Heading.css +6 -0
- package/dist/css/Icon.css +12 -0
- package/dist/css/IconButton.css +7 -0
- package/dist/css/Image.css +69 -0
- package/dist/css/Indicator.css +41 -0
- package/dist/css/Input.css +115 -0
- package/dist/css/Key.css +42 -0
- package/dist/css/Link.css +72 -0
- package/dist/css/List.css +52 -0
- package/dist/css/Media.css +8 -0
- package/dist/css/Menu.css +161 -0
- package/dist/css/Motion.css +1356 -0
- package/dist/css/NumberField.css +49 -0
- package/dist/css/OtpField.css +90 -0
- package/dist/css/PageTransition.css +979 -0
- package/dist/css/Pagination.css +43 -0
- package/dist/css/Popover.css +93 -0
- package/dist/css/Progress.css +101 -0
- package/dist/css/RadialProgress.css +44 -0
- package/dist/css/Radio.css +41 -0
- package/dist/css/Rating.css +100 -0
- package/dist/css/ScrollSpy.css +6 -0
- package/dist/css/SegmentedControl.css +101 -0
- package/dist/css/Select.css +115 -0
- package/dist/css/Sidebar.css +207 -0
- package/dist/css/Skeleton.css +48 -0
- package/dist/css/Slider.css +75 -0
- package/dist/css/Spacer.css +34 -0
- package/dist/css/SpeedDial.css +165 -0
- package/dist/css/Spinner.css +44 -0
- package/dist/css/Stack.css +528 -0
- package/dist/css/Stat.css +107 -0
- package/dist/css/Status.css +86 -0
- package/dist/css/Steps.css +201 -0
- package/dist/css/Swap.css +49 -0
- package/dist/css/Switch.css +66 -0
- package/dist/css/Table.css +269 -0
- package/dist/css/Tabs.css +119 -0
- package/dist/css/Text.css +60 -0
- package/dist/css/TextRotate.css +147 -0
- package/dist/css/Textarea.css +107 -0
- package/dist/css/ThemeProvider.css +6 -0
- package/dist/css/Tile.css +18 -0
- package/dist/css/Toast.css +110 -0
- package/dist/css/ToggleButton.css +20 -0
- package/dist/css/Tooltip.css +94 -0
- package/dist/css/Type.css +211 -0
- package/dist/css/Visibility.css +78 -0
- package/dist/css/VisuallyHidden.css +15 -0
- package/dist/css/core.css +251 -0
- package/dist/css.d.ts +29 -0
- package/dist/css.js +28 -0
- package/dist/effect-classes.d.ts +8 -0
- package/dist/effect-classes.js +5 -0
- package/dist/effects/css.d.ts +71 -0
- package/dist/effects/css.js +184 -0
- package/dist/effects/definitions.d.ts +555 -0
- package/dist/effects/definitions.js +379 -0
- package/dist/effects/frames.d.ts +18 -0
- package/dist/effects/frames.js +68 -0
- package/dist/effects/sequence.d.ts +33 -0
- package/dist/effects/sequence.js +106 -0
- package/dist/effects.d.ts +30 -0
- package/dist/effects.js +30 -0
- package/dist/greese.css +11907 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/kebab.d.ts +2 -0
- package/dist/kebab.js +2 -0
- package/dist/palette.css +249 -0
- package/dist/palette.d.ts +599 -0
- package/dist/palette.js +334 -0
- package/dist/shapes.d.ts +193 -0
- package/dist/shapes.js +852 -0
- package/dist/storage.d.ts +47 -0
- package/dist/storage.js +118 -0
- package/dist/style-manifest.json +3010 -0
- package/dist/theme.d.ts +71 -0
- package/dist/theme.js +180 -0
- package/dist/tokens.css +253 -0
- package/dist/tokens.d.ts +343 -0
- package/dist/tokens.js +179 -0
- package/dist/typography.d.ts +55 -0
- package/dist/typography.js +144 -0
- package/dist/utilities.css +6975 -0
- package/dist/utilities.d.ts +82 -0
- package/dist/utilities.js +636 -0
- package/dist/utilitiesFiles.d.ts +18 -0
- package/dist/utilitiesFiles.js +26 -0
- package/dist/vite.d.ts +40 -0
- package/dist/vite.js +43 -0
- package/package.json +131 -4
- package/src/components/Accordion/Accordion.scss +9 -0
- package/src/components/ActionSelect/ActionSelect.scss +6 -0
- package/src/components/Alert/Alert.scss +71 -0
- package/src/components/AppBar/AppBar.scss +43 -0
- package/src/components/AspectRatio/AspectRatio.scss +22 -0
- package/src/components/AutoLayout/AutoLayout.scss +90 -0
- package/src/components/Avatar/Avatar.scss +91 -0
- package/src/components/Badge/Badge.scss +52 -0
- package/src/components/Box/Box.scss +63 -0
- package/src/components/Breadcrumbs/Breadcrumbs.scss +59 -0
- package/src/components/Button/Button.scss +231 -0
- package/src/components/ButtonGroup/ButtonGroup.scss +56 -0
- package/src/components/Card/Card.scss +99 -0
- package/src/components/Carousel/Carousel.scss +161 -0
- package/src/components/Center/Center.scss +11 -0
- package/src/components/ChatBubble/ChatBubble.scss +119 -0
- package/src/components/Checkbox/Checkbox.scss +66 -0
- package/src/components/Chip/Chip.scss +119 -0
- package/src/components/ChoiceGroup/ChoiceGroup.scss +69 -0
- package/src/components/Code/Code.scss +28 -0
- package/src/components/Collapsible/Collapsible.scss +136 -0
- package/src/components/ColorPicker/ColorPicker.scss +235 -0
- package/src/components/Combobox/Combobox.scss +83 -0
- package/src/components/Container/Container.scss +28 -0
- package/src/components/Countdown/Countdown.scss +28 -0
- package/src/components/DateField/DateField.scss +19 -0
- package/src/components/Dialog/Dialog.scss +268 -0
- package/src/components/Diff/Diff.scss +125 -0
- package/src/components/Divider/Divider.scss +22 -0
- package/src/components/Dock/Dock.scss +86 -0
- package/src/components/Field/Field.scss +38 -0
- package/src/components/Fieldset/Fieldset.scss +63 -0
- package/src/components/FileInput/FileInput.scss +66 -0
- package/src/components/Footer/Footer.scss +79 -0
- package/src/components/Grid/Grid.scss +86 -0
- package/src/components/Header/Header.scss +111 -0
- package/src/components/Heading/Heading.scss +7 -0
- package/src/components/Icon/Icon.scss +12 -0
- package/src/components/IconButton/IconButton.scss +6 -0
- package/src/components/Image/Image.scss +46 -0
- package/src/components/Indicator/Indicator.scss +48 -0
- package/src/components/Input/Input.scss +58 -0
- package/src/components/Key/Key.scss +48 -0
- package/src/components/Link/Link.scss +50 -0
- package/src/components/List/List.scss +62 -0
- package/src/components/Media/Media.scss +7 -0
- package/src/components/Menu/Menu.scss +91 -0
- package/src/components/Motion/Motion.scss +106 -0
- package/src/components/NumberField/NumberField.scss +44 -0
- package/src/components/OtpField/OtpField.scss +91 -0
- package/src/components/PageTransition/PageTransition.scss +168 -0
- package/src/components/Pagination/Pagination.scss +55 -0
- package/src/components/Popover/Popover.scss +13 -0
- package/src/components/Progress/Progress.scss +126 -0
- package/src/components/RadialProgress/RadialProgress.scss +65 -0
- package/src/components/Radio/Radio.scss +36 -0
- package/src/components/Rating/Rating.scss +121 -0
- package/src/components/ScrollSpy/ScrollSpy.scss +6 -0
- package/src/components/SegmentedControl/SegmentedControl.scss +107 -0
- package/src/components/Select/Select.scss +59 -0
- package/src/components/Sidebar/Sidebar.scss +88 -0
- package/src/components/Skeleton/Skeleton.scss +60 -0
- package/src/components/Slider/Slider.scss +96 -0
- package/src/components/Spacer/Spacer.scss +15 -0
- package/src/components/SpeedDial/SpeedDial.scss +109 -0
- package/src/components/Spinner/Spinner.scss +43 -0
- package/src/components/Stack/Stack.scss +57 -0
- package/src/components/Stat/Stat.scss +96 -0
- package/src/components/Status/Status.scss +60 -0
- package/src/components/Steps/Steps.scss +216 -0
- package/src/components/Swap/Swap.scss +62 -0
- package/src/components/Switch/Switch.scss +63 -0
- package/src/components/Table/Table.scss +183 -0
- package/src/components/Tabs/Tabs.scss +108 -0
- package/src/components/Text/Text.scss +34 -0
- package/src/components/TextRotate/TextRotate.scss +51 -0
- package/src/components/Textarea/Textarea.scss +56 -0
- package/src/components/ThemeProvider/ThemeProvider.scss +7 -0
- package/src/components/Tile/Tile.scss +23 -0
- package/src/components/Toast/Toast.scss +93 -0
- package/src/components/ToggleButton/ToggleButton.scss +23 -0
- package/src/components/Tooltip/Tooltip.scss +21 -0
- package/src/components/Type/Type.scss +35 -0
- package/src/components/Visibility/Visibility.scss +39 -0
- package/src/components/VisuallyHidden/VisuallyHidden.scss +17 -0
- package/src/styles/_breakpoint-vars.scss +16 -0
- package/src/styles/_config.scss +48 -0
- package/src/styles/_controls.scss +88 -0
- package/src/styles/_core.scss +4 -0
- package/src/styles/_effect.scss +51 -0
- package/src/styles/_floating.scss +141 -0
- package/src/styles/_kit.scss +1548 -0
- package/src/styles/_manifest.scss +670 -0
- package/src/styles/_mixins.scss +261 -0
- package/src/styles/_tones.scss +63 -0
- package/src/styles/_type-emit.scss +76 -0
- package/src/styles/_typography-vars.scss +8 -0
- package/src/styles/base.scss +80 -0
- package/src/styles/breakpoints.test.ts +73 -0
- package/src/styles/entryPoints.test.ts +68 -0
- package/src/styles/index.scss +93 -0
- package/src/styles/kit.test.ts +754 -0
- package/src/styles/public/_controls.scss +3 -0
- package/src/styles/public/_floating.scss +3 -0
- package/src/styles/public/_mixins.scss +5 -0
- package/src/styles/public/_tones.scss +4 -0
- package/themes/bevel.css +1077 -0
- package/themes/bevel.scss +1166 -0
- package/themes/depth.css +123 -0
- package/themes/depth.scss +46 -0
- package/themes/extrude.css +219 -0
- package/themes/extrude.scss +255 -0
- package/themes/folio.css +986 -0
- package/themes/folio.scss +1047 -0
- package/themes/gentle.css +66 -0
- package/themes/gentle.scss +39 -0
- package/themes/outline.css +127 -0
- package/themes/outline.scss +126 -0
- package/themes/pebble.css +65 -0
- package/themes/pebble.scss +69 -0
- package/themes/pocket.css +137 -0
- package/themes/pocket.scss +45 -0
- package/themes/ridge.css +927 -0
- package/themes/ridge.scss +998 -0
- package/themes/snappy.css +82 -0
- package/themes/snappy.scss +40 -0
- package/themes/soft.css +79 -0
- package/themes/soft.scss +84 -0
- package/themes/ticket.css +960 -0
- package/themes/ticket.scss +1031 -0
- package/themes/tilt.css +148 -0
- package/themes/tilt.scss +169 -0
- package/themes/wipe.css +186 -0
- package/themes/wipe.scss +46 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// greese ui's build-time SCSS toolkit. Nothing here reaches the browser except
|
|
2
|
+
// the CSS these mixins compile to.
|
|
3
|
+
@use 'sass:map';
|
|
4
|
+
@use 'sass:string';
|
|
5
|
+
@use 'config';
|
|
6
|
+
|
|
7
|
+
$breakpoints: config.$breakpoints;
|
|
8
|
+
|
|
9
|
+
/// Mobile-first media query: styles apply from `$bp` upward. `xs` needs none.
|
|
10
|
+
@mixin up($bp) {
|
|
11
|
+
$min: map.get($breakpoints, $bp);
|
|
12
|
+
|
|
13
|
+
@if not $min {
|
|
14
|
+
@error 'Unknown breakpoint `#{$bp}`. Expected one of #{map.keys($breakpoints)}.';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@if $min <= 0 {
|
|
18
|
+
@content;
|
|
19
|
+
} @else {
|
|
20
|
+
@media (width >= $min) {
|
|
21
|
+
@content;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Styles apply below `$bp` only: the complement of `up($bp)`.
|
|
27
|
+
@mixin down($bp) {
|
|
28
|
+
$min: map.get($breakpoints, $bp);
|
|
29
|
+
|
|
30
|
+
@if not $min or $min <= 0 {
|
|
31
|
+
@error 'down() needs a breakpoint above xs, got `#{$bp}`.';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (width < $min) {
|
|
35
|
+
@content;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// The custom property holding one breakpoint's value of a responsive prop.
|
|
40
|
+
/// Must match `responsiveVar()` in src/utils/responsive.ts.
|
|
41
|
+
@function responsive-var($block, $prop, $bp) {
|
|
42
|
+
@return --#{string.to-lower-case($block)}-#{$prop}-#{$bp};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// `$template` with its `VALUE` placeholder replaced, or `$value` alone.
|
|
46
|
+
@function _fill($template, $value) {
|
|
47
|
+
@if not $template {
|
|
48
|
+
@return $value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
$at: string.index($template, 'VALUE');
|
|
52
|
+
|
|
53
|
+
@return string.unquote(
|
|
54
|
+
string.slice($template, 1, $at - 1) + '#{$value}' + string.slice($template, $at + 5)
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// One breakpoint's rules: the value class, then a class per token.
|
|
59
|
+
@mixin _breakpoint-rules($block, $prop, $bp, $properties, $tokens, $template, $scope) {
|
|
60
|
+
$prefix: '';
|
|
61
|
+
|
|
62
|
+
@if $scope {
|
|
63
|
+
$prefix: '#{$scope} ';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#{$prefix}.#{$block}--#{$bp}-#{$prop} {
|
|
67
|
+
@each $property in $properties {
|
|
68
|
+
#{$property}: _fill($template, var(#{responsive-var($block, $prop, $bp)}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@each $key, $value in $tokens {
|
|
73
|
+
#{$prefix}.#{$block}--#{$bp}-#{$prop}-#{$key} {
|
|
74
|
+
@each $property in $properties {
|
|
75
|
+
#{$property}: _fill($template, $value);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// A responsive prop: a class per breakpoint and value that sets the
|
|
82
|
+
/// property directly (docs/adr/0001-styling-model.md).
|
|
83
|
+
///
|
|
84
|
+
/// For each breakpoint, smallest first, inside that breakpoint's media query:
|
|
85
|
+
/// - a value class, `.#{$block}--#{bp}-#{$prop}`, reading the breakpoint's
|
|
86
|
+
/// variable (`--greese-stack-gap-md`), for open-ended values that
|
|
87
|
+
/// `resolveResponsive()` sets inline;
|
|
88
|
+
/// - for each `$tokens` entry, `.#{$block}--#{bp}-#{$prop}-#{key}`.
|
|
89
|
+
///
|
|
90
|
+
/// Every class has the same specificity, so source order is the
|
|
91
|
+
/// mobile-first fallback: a larger breakpoint's class comes later and wins
|
|
92
|
+
/// where it applies, and below it the smaller one's still does. A breakpoint
|
|
93
|
+
/// with no class leaves the property to the component's own styles, so an
|
|
94
|
+
/// unset prop costs nothing and never overrides a default. There is no
|
|
95
|
+
/// `var()` chain and nothing to register: each variable is read only by the
|
|
96
|
+
/// element that sets it, which was the fastest form in measurement (ADR
|
|
97
|
+
/// 0001, 2026-10-19 addendum).
|
|
98
|
+
///
|
|
99
|
+
/// With `$container-scope`, the same rules are emitted again under
|
|
100
|
+
/// `@container`, prefixed with the scope so they win inside it.
|
|
101
|
+
///
|
|
102
|
+
/// @param $block component root class, without the dot: 'greese-Stack'
|
|
103
|
+
/// @param $prop prop segment in class and variable names: 'gap'
|
|
104
|
+
/// @param $properties CSS property, or list of them, to set
|
|
105
|
+
/// @param $tokens map of token key to CSS value, one class each
|
|
106
|
+
/// @param $template wraps each value: 'repeat(auto-fill, minmax(VALUE, 1fr))'
|
|
107
|
+
/// @param $container-scope selector prefix whose container-query variant
|
|
108
|
+
/// applies: '.greese-Grid--container >'
|
|
109
|
+
///
|
|
110
|
+
/// Use it at the top level of a layer block, not nested in a selector.
|
|
111
|
+
@mixin responsive-prop(
|
|
112
|
+
$block,
|
|
113
|
+
$prop,
|
|
114
|
+
$properties,
|
|
115
|
+
$tokens: (),
|
|
116
|
+
$template: null,
|
|
117
|
+
$container-scope: null
|
|
118
|
+
) {
|
|
119
|
+
@each $bp, $min in $breakpoints {
|
|
120
|
+
@include up($bp) {
|
|
121
|
+
@include _breakpoint-rules(
|
|
122
|
+
$block,
|
|
123
|
+
$prop,
|
|
124
|
+
$bp,
|
|
125
|
+
$properties,
|
|
126
|
+
$tokens,
|
|
127
|
+
$template,
|
|
128
|
+
null
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@if $container-scope {
|
|
134
|
+
@each $bp, $min in $breakpoints {
|
|
135
|
+
@if $min <= 0 {
|
|
136
|
+
@include _breakpoint-rules(
|
|
137
|
+
$block,
|
|
138
|
+
$prop,
|
|
139
|
+
$bp,
|
|
140
|
+
$properties,
|
|
141
|
+
$tokens,
|
|
142
|
+
$template,
|
|
143
|
+
$container-scope
|
|
144
|
+
);
|
|
145
|
+
} @else {
|
|
146
|
+
@container (width >= #{$min}) {
|
|
147
|
+
@include _breakpoint-rules(
|
|
148
|
+
$block,
|
|
149
|
+
$prop,
|
|
150
|
+
$bp,
|
|
151
|
+
$properties,
|
|
152
|
+
$tokens,
|
|
153
|
+
$template,
|
|
154
|
+
$container-scope
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/// The spacing scale as a `$tokens` map for `responsive-prop()`.
|
|
163
|
+
@function space-tokens() {
|
|
164
|
+
$map: ();
|
|
165
|
+
|
|
166
|
+
@each $key in config.$space-keys {
|
|
167
|
+
$map: map.set($map, $key, var(--greese-space-#{$key}));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@return $map;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/// Hover styles only where hover exists, so taps never leave sticky hovers.
|
|
174
|
+
@mixin hover {
|
|
175
|
+
@media (hover: hover) {
|
|
176
|
+
&:hover {
|
|
177
|
+
@content;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/// The standard keyboard focus indicator.
|
|
183
|
+
@mixin focus-ring($offset: 2px) {
|
|
184
|
+
&:focus-visible {
|
|
185
|
+
outline: 2px solid var(--greese-color-focus-ring);
|
|
186
|
+
outline-offset: $offset;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Grows the hit area to at least `$size` on touch screens without changing
|
|
191
|
+
/// the visual size. The element must be positioned (relative, absolute, …).
|
|
192
|
+
@mixin touch-target($size: 44px) {
|
|
193
|
+
@media (pointer: coarse) {
|
|
194
|
+
&::after {
|
|
195
|
+
position: absolute;
|
|
196
|
+
top: 50%;
|
|
197
|
+
left: 50%;
|
|
198
|
+
inline-size: max(100%, #{$size});
|
|
199
|
+
block-size: max(100%, #{$size});
|
|
200
|
+
content: '';
|
|
201
|
+
translate: -50% -50%;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// Content that switches in (a tab's panel, an accordion's content): the
|
|
207
|
+
/// container stays put and its children enter, a stagger apart. Not when the
|
|
208
|
+
/// container has a `greese` entrance of its own (`.greese-Motion`), which then
|
|
209
|
+
/// plays instead. A theme changes the entrance with `animation-name` on the
|
|
210
|
+
/// same selector (ADR 0025).
|
|
211
|
+
@mixin content-entrance {
|
|
212
|
+
&:not(.greese-Motion) > * {
|
|
213
|
+
@include motion-safe {
|
|
214
|
+
@include role-entrance(content, greese-content-in, normal);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@for $i from 2 through 6 {
|
|
218
|
+
&:nth-child(#{$i}) {
|
|
219
|
+
animation-delay: calc(var(--greese-motion-stagger, 0.04s) * #{$i - 1});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/// An entrance a theme assigns by role (ADR 0025): `--greese-motion-<role>`
|
|
226
|
+
/// names the effect, `--greese-motion-<role>-duration` its duration, and
|
|
227
|
+
/// `--greese-motion-enter-ease` the curve every role arrives on. Each falls
|
|
228
|
+
/// back to the base theme's. A theme points a role at an effect or a token;
|
|
229
|
+
/// the effect and the token keep their own values.
|
|
230
|
+
@mixin role-entrance($role, $name, $duration, $ease: var(--greese-easing-enter)) {
|
|
231
|
+
animation-name: var(--greese-motion-#{$role}, #{$name});
|
|
232
|
+
animation-duration: var(
|
|
233
|
+
--greese-motion-#{$role}-duration,
|
|
234
|
+
var(--greese-duration-#{$duration})
|
|
235
|
+
);
|
|
236
|
+
animation-timing-function: var(--greese-motion-enter-ease, #{$ease});
|
|
237
|
+
animation-fill-mode: backwards;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/// The entrance `content-entrance` plays unless a theme picks another.
|
|
241
|
+
@mixin content-entrance-keyframes {
|
|
242
|
+
@keyframes greese-content-in {
|
|
243
|
+
from {
|
|
244
|
+
opacity: 0;
|
|
245
|
+
translate: 0 0.25rem;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// Motion beyond duration tokens (which already collapse under reduced
|
|
251
|
+
/// motion), e.g. keyframe animations or transforms.
|
|
252
|
+
@mixin motion-safe {
|
|
253
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
254
|
+
@content;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/// Baseline for every component root.
|
|
259
|
+
@mixin component-root {
|
|
260
|
+
box-sizing: border-box;
|
|
261
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
@use 'sass:list';
|
|
2
|
+
|
|
3
|
+
// Color roles shared by every component with a `tone` prop.
|
|
4
|
+
// A tone sets two variables on the component: the color and the color of
|
|
5
|
+
// content drawn on top of it.
|
|
6
|
+
|
|
7
|
+
$tones: (
|
|
8
|
+
neutral: (
|
|
9
|
+
var(--greese-color-fg),
|
|
10
|
+
var(--greese-color-canvas),
|
|
11
|
+
),
|
|
12
|
+
muted: (
|
|
13
|
+
var(--greese-color-fg-muted),
|
|
14
|
+
var(--greese-color-canvas),
|
|
15
|
+
),
|
|
16
|
+
primary: (
|
|
17
|
+
var(--greese-color-primary),
|
|
18
|
+
var(--greese-color-primary-content),
|
|
19
|
+
),
|
|
20
|
+
secondary: (
|
|
21
|
+
var(--greese-color-secondary),
|
|
22
|
+
var(--greese-color-secondary-content),
|
|
23
|
+
),
|
|
24
|
+
tertiary: (
|
|
25
|
+
var(--greese-color-tertiary),
|
|
26
|
+
var(--greese-color-tertiary-content),
|
|
27
|
+
),
|
|
28
|
+
accent: (
|
|
29
|
+
var(--greese-color-accent),
|
|
30
|
+
var(--greese-color-accent-content),
|
|
31
|
+
),
|
|
32
|
+
positive: (
|
|
33
|
+
var(--greese-color-positive),
|
|
34
|
+
var(--greese-color-canvas),
|
|
35
|
+
),
|
|
36
|
+
negative: (
|
|
37
|
+
var(--greese-color-negative),
|
|
38
|
+
var(--greese-color-negative-content),
|
|
39
|
+
),
|
|
40
|
+
warning: (
|
|
41
|
+
var(--greese-color-warning),
|
|
42
|
+
var(--greese-color-canvas),
|
|
43
|
+
),
|
|
44
|
+
info: (
|
|
45
|
+
var(--greese-color-info),
|
|
46
|
+
var(--greese-color-canvas),
|
|
47
|
+
),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// The brand roles, in order, as a list for components that style them by hand.
|
|
51
|
+
$brand: (primary, secondary, tertiary, accent);
|
|
52
|
+
|
|
53
|
+
/// Emits `.#{$block}--#{tone}` classes setting `--#{$var}` and `--#{$var}-on`.
|
|
54
|
+
@mixin classes($block, $var, $only: null) {
|
|
55
|
+
@each $tone, $pair in $tones {
|
|
56
|
+
@if not $only or list.index($only, $tone) {
|
|
57
|
+
.#{$block}--#{$tone} {
|
|
58
|
+
--#{$var}: #{list.nth($pair, 1)};
|
|
59
|
+
--#{$var}-on: #{list.nth($pair, 2)};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Writes the type system's custom properties from a typography map, in the
|
|
2
|
+
// build's breakpoints: the smallest screen's values at the selector, then one
|
|
3
|
+
// media query per breakpoint that changes any, smallest first.
|
|
4
|
+
@use 'sass:list';
|
|
5
|
+
@use 'sass:map';
|
|
6
|
+
@use 'sass:meta';
|
|
7
|
+
@use 'sass:string';
|
|
8
|
+
@use 'config';
|
|
9
|
+
@use 'mixins';
|
|
10
|
+
|
|
11
|
+
@function value($value) {
|
|
12
|
+
@if meta.type-of($value) == string {
|
|
13
|
+
@return string.unquote($value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@if meta.type-of($value) == list {
|
|
17
|
+
@return string.unquote(meta.inspect($value));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@return $value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// One point's values as a map of `--greese-type-<variant>-<prop>: value`.
|
|
24
|
+
/// `base` also takes `xs`, which is the same point.
|
|
25
|
+
@function _point($typography, $point) {
|
|
26
|
+
$out: ();
|
|
27
|
+
|
|
28
|
+
@each $variant, $spec in $typography {
|
|
29
|
+
$style: map.get($spec, $point) or ();
|
|
30
|
+
|
|
31
|
+
@if $point == base {
|
|
32
|
+
$style: map.merge($style, map.get($spec, xs) or ());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@each $prop, $v in $style {
|
|
36
|
+
$out: map.set($out, '--greese-type-#{$variant}-#{$prop}', $v);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@return $out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@mixin _declare($declarations, $selector) {
|
|
44
|
+
@if list.length($declarations) > 0 {
|
|
45
|
+
#{$selector} {
|
|
46
|
+
@each $property, $v in $declarations {
|
|
47
|
+
#{$property}: #{value($v)};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// The smallest screen's values, for a rule that already declares tokens.
|
|
54
|
+
@function base($typography) {
|
|
55
|
+
@return _point($typography, base);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@mixin emit($typography, $selector: ':root') {
|
|
59
|
+
@include _declare(base($typography), $selector);
|
|
60
|
+
@include emit-media($typography, $selector);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// The changes at each breakpoint above the smallest.
|
|
64
|
+
@mixin emit-media($typography, $selector: ':root') {
|
|
65
|
+
@each $bp, $min in config.$breakpoints {
|
|
66
|
+
@if $bp != xs {
|
|
67
|
+
$declarations: _point($typography, $bp);
|
|
68
|
+
|
|
69
|
+
@if list.length($declarations) > 0 {
|
|
70
|
+
@include mixins.up($bp) {
|
|
71
|
+
@include _declare($declarations, $selector);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The type system's custom properties, from this build's typography and
|
|
2
|
+
// breakpoints (the defaults unless you configured them), in the token layer.
|
|
3
|
+
@use 'config';
|
|
4
|
+
@use 'type-emit';
|
|
5
|
+
|
|
6
|
+
@layer greese.tokens {
|
|
7
|
+
@include type-emit.emit(config.$typography);
|
|
8
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Opt-in global styles, compiled to dist/base.css: a light reset plus page
|
|
2
|
+
// defaults wired to the tokens. Import it only if greese ui owns the page.
|
|
3
|
+
// Usage:
|
|
4
|
+
// import '@greese/react/base.css'
|
|
5
|
+
// import '@greese/react/styles.css'
|
|
6
|
+
@use '../../dist/layers';
|
|
7
|
+
|
|
8
|
+
@layer greese.reset {
|
|
9
|
+
*,
|
|
10
|
+
*::before,
|
|
11
|
+
*::after {
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
html {
|
|
16
|
+
text-size-adjust: 100%;
|
|
17
|
+
-webkit-tap-highlight-color: transparent;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
min-block-size: 100dvh;
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
h1,
|
|
26
|
+
h2,
|
|
27
|
+
h3,
|
|
28
|
+
h4,
|
|
29
|
+
h5,
|
|
30
|
+
h6,
|
|
31
|
+
p,
|
|
32
|
+
figure,
|
|
33
|
+
blockquote,
|
|
34
|
+
dl,
|
|
35
|
+
dd {
|
|
36
|
+
margin: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
h1,
|
|
40
|
+
h2,
|
|
41
|
+
h3,
|
|
42
|
+
h4,
|
|
43
|
+
h5,
|
|
44
|
+
h6,
|
|
45
|
+
p {
|
|
46
|
+
overflow-wrap: break-word;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
img,
|
|
50
|
+
picture,
|
|
51
|
+
video,
|
|
52
|
+
canvas,
|
|
53
|
+
svg {
|
|
54
|
+
display: block;
|
|
55
|
+
max-inline-size: 100%;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
input,
|
|
59
|
+
button,
|
|
60
|
+
textarea,
|
|
61
|
+
select {
|
|
62
|
+
font: inherit;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@layer greese.base {
|
|
67
|
+
body {
|
|
68
|
+
font-family: var(--greese-font-body);
|
|
69
|
+
font-size: var(--greese-type-p2-font-size);
|
|
70
|
+
line-height: var(--greese-line-height-normal);
|
|
71
|
+
color: var(--greese-color-fg);
|
|
72
|
+
background-color: var(--greese-color-canvas);
|
|
73
|
+
-webkit-font-smoothing: antialiased;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
:focus-visible {
|
|
77
|
+
outline: 2px solid var(--greese-color-focus-ring);
|
|
78
|
+
outline-offset: 2px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
import { compileScss, STYLES } from '../test/sass.ts'
|
|
5
|
+
|
|
6
|
+
const build = (breakpoints: string): string =>
|
|
7
|
+
compileScss(`@use 'index' with ($breakpoints: ${breakpoints});`)
|
|
8
|
+
|
|
9
|
+
const DEFAULTS = 'xs: 0px, sm: 600px, md: 900px, lg: 1200px, xl: 1536px'
|
|
10
|
+
const vars = (css: string) =>
|
|
11
|
+
[...css.matchAll(/--greese-breakpoint-([a-z0-9]+): ([^;]+);/g)].map((m) => [m[1], m[2]])
|
|
12
|
+
|
|
13
|
+
describe('breakpoints, fixed when the stylesheet is built', () => {
|
|
14
|
+
it('declares the defaults as custom properties, in the tokens', () => {
|
|
15
|
+
const tokens = readFileSync(`${STYLES}../../dist/tokens.css`, 'utf8')
|
|
16
|
+
expect(vars(tokens)).toEqual([
|
|
17
|
+
['xs', '0px'],
|
|
18
|
+
['sm', '600px'],
|
|
19
|
+
['md', '900px'],
|
|
20
|
+
['lg', '1200px'],
|
|
21
|
+
['xl', '1536px'],
|
|
22
|
+
])
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('does not repeat them when built with the defaults', () => {
|
|
26
|
+
expect(vars(build(`(${DEFAULTS})`)).length).toBe(5)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('adds a key: classes, media queries and a custom property', () => {
|
|
30
|
+
const css = build(
|
|
31
|
+
'(xs: 0px, sm: 600px, tablet: 700px, md: 900px, lg: 1200px, xl: 1536px)'
|
|
32
|
+
)
|
|
33
|
+
expect(css).toContain('--greese-breakpoint-tablet: 700px;')
|
|
34
|
+
expect(css).toContain('@media (width >= 700px)')
|
|
35
|
+
expect(css).toContain('.greese-Stack--tablet-gap-3')
|
|
36
|
+
expect(css).toContain('.greese-Stack--tablet-gap {')
|
|
37
|
+
// The configured values replace the defaults in the one stylesheet.
|
|
38
|
+
const last = css.lastIndexOf('--greese-breakpoint-sm')
|
|
39
|
+
expect(css.slice(last)).toContain('--greese-breakpoint-sm: 600px')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('changes values, and the custom properties follow', () => {
|
|
43
|
+
const css = build('(xs: 0px, sm: 480px, md: 768px, lg: 1024px, xl: 1440px)')
|
|
44
|
+
expect(css).toContain('@media (width >= 768px)')
|
|
45
|
+
expect(css).not.toContain('@media (width >= 900px)')
|
|
46
|
+
// The type system follows the build's breakpoints.
|
|
47
|
+
expect(css).toMatch(
|
|
48
|
+
/@media \(width >= 768px\)[^@]*--greese-type-h1-font-size: 2\.75rem/
|
|
49
|
+
)
|
|
50
|
+
expect(css).toContain('--greese-breakpoint-md: 768px;')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('takes a key that starts with a digit when quoted', () => {
|
|
54
|
+
const css = build(`(${DEFAULTS}, '2xl': 1800px)`)
|
|
55
|
+
expect(css).toContain('--greese-breakpoint-2xl: 1800px;')
|
|
56
|
+
expect(css).toContain('.greese-Stack--2xl-gap-3')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('keeps the keys components use, and the order', () => {
|
|
60
|
+
expect(() => build('(xs: 0px, sm: 600px, md: 900px)')).toThrow(
|
|
61
|
+
/must keep the key `lg`/
|
|
62
|
+
)
|
|
63
|
+
expect(() =>
|
|
64
|
+
build('(xs: 100px, sm: 600px, md: 900px, lg: 1200px, xl: 1536px)')
|
|
65
|
+
).toThrow(/`xs` must be 0/)
|
|
66
|
+
expect(() =>
|
|
67
|
+
build('(xs: 0px, sm: 900px, md: 600px, lg: 1200px, xl: 1536px)')
|
|
68
|
+
).toThrow(/must increase/)
|
|
69
|
+
expect(() =>
|
|
70
|
+
build('(xs: 0px, sm: 600px, big-one: 700px, md: 900px, lg: 1200px, xl: 1536px)')
|
|
71
|
+
).toThrow(/one word, without dashes/)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import manifest from '../../package.json' with { type: 'json' }
|
|
4
|
+
import { compileAsProject, rules } from '../test/sass.ts'
|
|
5
|
+
|
|
6
|
+
const compile = compileAsProject
|
|
7
|
+
|
|
8
|
+
const AUTHORING = ['mixins', 'tones', 'floating', 'controls'] as const
|
|
9
|
+
|
|
10
|
+
describe('the SCSS entry points for theme authors (ADR 0021)', () => {
|
|
11
|
+
it('are exported, and each compiles alone without writing CSS', () => {
|
|
12
|
+
const exported = Object.keys(manifest.exports)
|
|
13
|
+
for (const name of AUTHORING) {
|
|
14
|
+
expect(exported, name).toContain(`./scss/${name}`)
|
|
15
|
+
expect(compile(`@use 'pkg:@greese/ui/scss/${name}';`), name).toBe('')
|
|
16
|
+
}
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('give a component’s own members, under the name its source uses', () => {
|
|
20
|
+
const css = compile(`
|
|
21
|
+
@use 'pkg:@greese/ui/scss/mixins';
|
|
22
|
+
@use 'pkg:@greese/ui/scss/floating';
|
|
23
|
+
@use 'pkg:@greese/ui/scss/controls';
|
|
24
|
+
@use 'pkg:@greese/ui/scss/tones';
|
|
25
|
+
@use 'sass:list';
|
|
26
|
+
@use 'sass:map';
|
|
27
|
+
.a {
|
|
28
|
+
@include mixins.focus-ring;
|
|
29
|
+
@include mixins.up(md) { gap: 1px; }
|
|
30
|
+
@include floating.surface;
|
|
31
|
+
@include controls.frame;
|
|
32
|
+
color: list.nth(map.get(tones.$tones, primary), 1);
|
|
33
|
+
}`)
|
|
34
|
+
expect(css).toContain('@media (width >= 900px)')
|
|
35
|
+
expect(rules(css, '.a:focus-visible')[0]?.declarations).toContainEqual([
|
|
36
|
+
'outline',
|
|
37
|
+
expect.stringMatching(/^2px solid /),
|
|
38
|
+
])
|
|
39
|
+
expect(css).toContain('var(--greese-color-primary)')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('are the modules the kit loads: a configured breakpoint reaches them', () => {
|
|
43
|
+
const css = compile(`
|
|
44
|
+
@use 'pkg:@greese/ui/scss/config' with ($breakpoints: (xs: 0px, sm: 500px, md: 700px, lg: 1000px, xl: 1400px));
|
|
45
|
+
@use 'pkg:@greese/ui/scss/kit' as greese;
|
|
46
|
+
@use 'pkg:@greese/ui/scss/mixins';
|
|
47
|
+
.a { @include mixins.up(md) { gap: 1px; } }
|
|
48
|
+
.b { @include greese.up(md) { gap: 1px; } }`)
|
|
49
|
+
expect(css.match(/@media \(width >= 700px\)/g)).toHaveLength(2)
|
|
50
|
+
expect(css).not.toContain('900px')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('hide what only the library’s own sheets can use', () => {
|
|
54
|
+
expect(() =>
|
|
55
|
+
compile(
|
|
56
|
+
`@use 'pkg:@greese/ui/scss/mixins'; .a { @include mixins.responsive-prop('greese-A', p, padding); }`
|
|
57
|
+
)
|
|
58
|
+
).toThrow(/Undefined mixin/)
|
|
59
|
+
expect(() =>
|
|
60
|
+
compile(`@use 'pkg:@greese/ui/scss/mixins'; .a { b: mixins.space-tokens(); }`)
|
|
61
|
+
).toThrow()
|
|
62
|
+
expect(() =>
|
|
63
|
+
compile(
|
|
64
|
+
`@use 'pkg:@greese/ui/scss/tones'; .a { @include tones.classes('greese-A', tone); }`
|
|
65
|
+
)
|
|
66
|
+
).toThrow(/Undefined mixin/)
|
|
67
|
+
})
|
|
68
|
+
})
|