tyrell-components 1.0.0-RC13 → 1.0.0-RC15
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/README.md +10 -2
- package/css/tyrell-theme.css +192 -180
- package/css/tyrell.css +23 -0
- package/dist/tyrell-colors-static.css +1 -316
- package/dist/tyrell-theme.css +1 -1454
- package/dist/tyrell.css +1 -1371
- package/dist/tyrell.js +1 -1
- package/lib/base/ty-component.d.ts +20 -10
- package/lib/base/ty-component.js +196 -319
- package/lib/components/button.d.ts +3 -17
- package/lib/components/button.js +261 -295
- package/lib/components/calendar-month.d.ts +4 -50
- package/lib/components/calendar-month.js +443 -582
- package/lib/components/calendar-navigation.d.ts +3 -48
- package/lib/components/calendar-navigation.js +239 -362
- package/lib/components/calendar.d.ts +8 -83
- package/lib/components/calendar.js +616 -829
- package/lib/components/checkbox.d.ts +5 -72
- package/lib/components/checkbox.js +273 -416
- package/lib/components/copy.d.ts +4 -57
- package/lib/components/copy.js +280 -397
- package/lib/components/date-picker.d.ts +21 -163
- package/lib/components/date-picker.js +1143 -1674
- package/lib/components/file-upload.d.ts +9 -15
- package/lib/components/file-upload.js +404 -426
- package/lib/components/icon.d.ts +3 -24
- package/lib/components/icon.js +141 -230
- package/lib/components/input.d.ts +8 -108
- package/lib/components/input.js +593 -784
- package/lib/components/modal.d.ts +17 -26
- package/lib/components/modal.js +340 -484
- package/lib/components/option.d.ts +2 -9
- package/lib/components/option.js +168 -216
- package/lib/components/popup.d.ts +2 -17
- package/lib/components/popup.js +249 -380
- package/lib/components/radio.d.ts +5 -25
- package/lib/components/radio.js +407 -461
- package/lib/components/resize-observer.d.ts +3 -30
- package/lib/components/resize-observer.js +69 -103
- package/lib/components/scroll-container.d.ts +2 -12
- package/lib/components/scroll-container.js +293 -338
- package/lib/components/select.d.ts +87 -159
- package/lib/components/select.js +1609 -2090
- package/lib/components/selected-tags.d.ts +5 -48
- package/lib/components/selected-tags.js +188 -276
- package/lib/components/step.d.ts +1 -6
- package/lib/components/step.js +62 -68
- package/lib/components/switch.d.ts +1 -12
- package/lib/components/switch.js +214 -247
- package/lib/components/tab.d.ts +1 -6
- package/lib/components/tab.js +62 -69
- package/lib/components/tabs.d.ts +6 -63
- package/lib/components/tabs.js +545 -777
- package/lib/components/tag.d.ts +3 -37
- package/lib/components/tag.js +236 -335
- package/lib/components/textarea.d.ts +7 -87
- package/lib/components/textarea.js +457 -627
- package/lib/components/tooltip.d.ts +3 -11
- package/lib/components/tooltip.js +307 -443
- package/lib/components/wizard.d.ts +6 -54
- package/lib/components/wizard.js +405 -618
- package/lib/icons/fontawesome/brands.d.ts +0 -1
- package/lib/icons/fontawesome/brands.js +0 -8
- package/lib/icons/fontawesome/regular.d.ts +0 -1
- package/lib/icons/fontawesome/regular.js +0 -8
- package/lib/icons/fontawesome/solid.d.ts +0 -1
- package/lib/icons/fontawesome/solid.js +0 -8
- package/lib/icons/heroicons/micro.d.ts +0 -1
- package/lib/icons/heroicons/micro.js +392 -400
- package/lib/icons/heroicons/mini.d.ts +0 -1
- package/lib/icons/heroicons/mini.js +382 -390
- package/lib/icons/heroicons/outline.d.ts +0 -1
- package/lib/icons/heroicons/outline.js +337 -345
- package/lib/icons/heroicons/solid.d.ts +0 -1
- package/lib/icons/heroicons/solid.js +407 -415
- package/lib/icons/lucide.d.ts +0 -1
- package/lib/icons/lucide.js +24479 -26351
- package/lib/icons/material/filled.d.ts +0 -1
- package/lib/icons/material/filled.js +9653 -9663
- package/lib/icons/material/outlined.d.ts +0 -1
- package/lib/icons/material/outlined.js +10271 -10281
- package/lib/icons/material/round.d.ts +0 -1
- package/lib/icons/material/round.js +10495 -10505
- package/lib/icons/material/sharp.d.ts +0 -1
- package/lib/icons/material/sharp.js +9905 -9915
- package/lib/icons/material/two-tone.d.ts +0 -1
- package/lib/icons/material/two-tone.js +12792 -12802
- package/lib/index.d.ts +0 -1
- package/lib/index.js +21 -41
- package/lib/styles/button.d.ts +2 -20
- package/lib/styles/button.js +202 -404
- package/lib/styles/calendar-month.d.ts +1 -5
- package/lib/styles/calendar-month.js +127 -244
- package/lib/styles/calendar-navigation.d.ts +2 -6
- package/lib/styles/calendar-navigation.js +64 -104
- package/lib/styles/calendar.d.ts +1 -2
- package/lib/styles/calendar.js +9 -22
- package/lib/styles/checkbox.d.ts +0 -1
- package/lib/styles/checkbox.js +45 -94
- package/lib/styles/copy.d.ts +0 -1
- package/lib/styles/copy.js +67 -106
- package/lib/styles/custom-scrollbar.d.ts +1 -2
- package/lib/styles/custom-scrollbar.js +80 -115
- package/lib/styles/date-picker.d.ts +1 -5
- package/lib/styles/date-picker.js +261 -335
- package/lib/styles/field-size.d.ts +6 -0
- package/lib/styles/field-size.js +91 -0
- package/lib/styles/file-upload.d.ts +1 -2
- package/lib/styles/file-upload.js +143 -188
- package/lib/styles/icon.d.ts +2 -6
- package/lib/styles/icon.js +92 -170
- package/lib/styles/input.d.ts +1 -6
- package/lib/styles/input.js +125 -290
- package/lib/styles/modal.d.ts +1 -2
- package/lib/styles/modal.js +71 -108
- package/lib/styles/option.d.ts +2 -6
- package/lib/styles/option.js +49 -64
- package/lib/styles/popup.d.ts +1 -2
- package/lib/styles/popup.js +42 -77
- package/lib/styles/radio.d.ts +0 -1
- package/lib/styles/radio.js +69 -110
- package/lib/styles/resize-observer.d.ts +1 -2
- package/lib/styles/resize-observer.js +2 -12
- package/lib/styles/scroll-container.d.ts +1 -2
- package/lib/styles/scroll-container.js +100 -149
- package/lib/styles/select-base.d.ts +0 -1
- package/lib/styles/select-base.js +597 -785
- package/lib/styles/select.d.ts +1 -2
- package/lib/styles/select.js +140 -236
- package/lib/styles/step.d.ts +1 -2
- package/lib/styles/step.js +22 -33
- package/lib/styles/switch.d.ts +0 -1
- package/lib/styles/switch.js +34 -73
- package/lib/styles/tab.d.ts +1 -2
- package/lib/styles/tab.js +22 -34
- package/lib/styles/tabs.d.ts +3 -11
- package/lib/styles/tabs.js +190 -222
- package/lib/styles/tag.d.ts +1 -5
- package/lib/styles/tag.js +136 -218
- package/lib/styles/textarea.d.ts +1 -2
- package/lib/styles/textarea.js +210 -319
- package/lib/styles/tooltip.d.ts +0 -1
- package/lib/styles/tooltip.js +3 -13
- package/lib/styles/wizard.d.ts +5 -21
- package/lib/styles/wizard.js +170 -306
- package/lib/types/common.d.ts +2 -2
- package/lib/types/common.js +6 -17
- package/lib/utils/calendar-utils.d.ts +4 -21
- package/lib/utils/calendar-utils.js +100 -273
- package/lib/utils/custom-scrollbar.d.ts +6 -20
- package/lib/utils/custom-scrollbar.js +273 -317
- package/lib/utils/flavor-sheet.d.ts +0 -1
- package/lib/utils/flavor-sheet.js +14 -37
- package/lib/utils/icon-registry.d.ts +0 -2
- package/lib/utils/icon-registry.js +137 -243
- package/lib/utils/icons.d.ts +0 -1
- package/lib/utils/icons.js +0 -9
- package/lib/utils/loader-registry.d.ts +0 -1
- package/lib/utils/loader-registry.js +3 -35
- package/lib/utils/locale.d.ts +2 -23
- package/lib/utils/locale.js +34 -120
- package/lib/utils/mobile.d.ts +0 -1
- package/lib/utils/mobile.js +1 -18
- package/lib/utils/number-format.d.ts +6 -3
- package/lib/utils/number-format.js +54 -110
- package/lib/utils/positioning.d.ts +50 -7
- package/lib/utils/positioning.js +224 -234
- package/lib/utils/property-capture.d.ts +5 -27
- package/lib/utils/property-capture.js +36 -144
- package/lib/utils/property-manager.d.ts +0 -1
- package/lib/utils/property-manager.js +126 -196
- package/lib/utils/resize-observer.d.ts +0 -1
- package/lib/utils/resize-observer.js +23 -59
- package/lib/utils/scroll-lock.d.ts +4 -11
- package/lib/utils/scroll-lock.js +65 -172
- package/lib/utils/styles.d.ts +0 -1
- package/lib/utils/styles.js +17 -41
- package/lib/version.d.ts +1 -2
- package/lib/version.js +1 -11
- package/package.json +4 -4
- package/lib/base/ty-component.d.ts.map +0 -1
- package/lib/base/ty-component.js.map +0 -1
- package/lib/components/button.d.ts.map +0 -1
- package/lib/components/button.js.map +0 -1
- package/lib/components/calendar-month.d.ts.map +0 -1
- package/lib/components/calendar-month.js.map +0 -1
- package/lib/components/calendar-navigation.d.ts.map +0 -1
- package/lib/components/calendar-navigation.js.map +0 -1
- package/lib/components/calendar.d.ts.map +0 -1
- package/lib/components/calendar.js.map +0 -1
- package/lib/components/checkbox.d.ts.map +0 -1
- package/lib/components/checkbox.js.map +0 -1
- package/lib/components/copy.d.ts.map +0 -1
- package/lib/components/copy.js.map +0 -1
- package/lib/components/date-picker.d.ts.map +0 -1
- package/lib/components/date-picker.js.map +0 -1
- package/lib/components/file-upload.d.ts.map +0 -1
- package/lib/components/file-upload.js.map +0 -1
- package/lib/components/icon.d.ts.map +0 -1
- package/lib/components/icon.js.map +0 -1
- package/lib/components/input.d.ts.map +0 -1
- package/lib/components/input.js.map +0 -1
- package/lib/components/modal.d.ts.map +0 -1
- package/lib/components/modal.js.map +0 -1
- package/lib/components/option.d.ts.map +0 -1
- package/lib/components/option.js.map +0 -1
- package/lib/components/popup.d.ts.map +0 -1
- package/lib/components/popup.js.map +0 -1
- package/lib/components/radio.d.ts.map +0 -1
- package/lib/components/radio.js.map +0 -1
- package/lib/components/resize-observer.d.ts.map +0 -1
- package/lib/components/resize-observer.js.map +0 -1
- package/lib/components/scroll-container.d.ts.map +0 -1
- package/lib/components/scroll-container.js.map +0 -1
- package/lib/components/select.d.ts.map +0 -1
- package/lib/components/select.js.map +0 -1
- package/lib/components/selected-tags.d.ts.map +0 -1
- package/lib/components/selected-tags.js.map +0 -1
- package/lib/components/step.d.ts.map +0 -1
- package/lib/components/step.js.map +0 -1
- package/lib/components/switch.d.ts.map +0 -1
- package/lib/components/switch.js.map +0 -1
- package/lib/components/tab.d.ts.map +0 -1
- package/lib/components/tab.js.map +0 -1
- package/lib/components/tabs.d.ts.map +0 -1
- package/lib/components/tabs.js.map +0 -1
- package/lib/components/tag.d.ts.map +0 -1
- package/lib/components/tag.js.map +0 -1
- package/lib/components/textarea.d.ts.map +0 -1
- package/lib/components/textarea.js.map +0 -1
- package/lib/components/tooltip.d.ts.map +0 -1
- package/lib/components/tooltip.js.map +0 -1
- package/lib/components/wizard.d.ts.map +0 -1
- package/lib/components/wizard.js.map +0 -1
- package/lib/icons/fontawesome/brands.d.ts.map +0 -1
- package/lib/icons/fontawesome/brands.js.map +0 -1
- package/lib/icons/fontawesome/regular.d.ts.map +0 -1
- package/lib/icons/fontawesome/regular.js.map +0 -1
- package/lib/icons/fontawesome/solid.d.ts.map +0 -1
- package/lib/icons/fontawesome/solid.js.map +0 -1
- package/lib/icons/heroicons/micro.d.ts.map +0 -1
- package/lib/icons/heroicons/micro.js.map +0 -1
- package/lib/icons/heroicons/mini.d.ts.map +0 -1
- package/lib/icons/heroicons/mini.js.map +0 -1
- package/lib/icons/heroicons/outline.d.ts.map +0 -1
- package/lib/icons/heroicons/outline.js.map +0 -1
- package/lib/icons/heroicons/solid.d.ts.map +0 -1
- package/lib/icons/heroicons/solid.js.map +0 -1
- package/lib/icons/lucide.d.ts.map +0 -1
- package/lib/icons/lucide.js.map +0 -1
- package/lib/icons/material/filled.d.ts.map +0 -1
- package/lib/icons/material/filled.js.map +0 -1
- package/lib/icons/material/outlined.d.ts.map +0 -1
- package/lib/icons/material/outlined.js.map +0 -1
- package/lib/icons/material/round.d.ts.map +0 -1
- package/lib/icons/material/round.js.map +0 -1
- package/lib/icons/material/sharp.d.ts.map +0 -1
- package/lib/icons/material/sharp.js.map +0 -1
- package/lib/icons/material/two-tone.d.ts.map +0 -1
- package/lib/icons/material/two-tone.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/styles/button.d.ts.map +0 -1
- package/lib/styles/button.js.map +0 -1
- package/lib/styles/calendar-month.d.ts.map +0 -1
- package/lib/styles/calendar-month.js.map +0 -1
- package/lib/styles/calendar-navigation.d.ts.map +0 -1
- package/lib/styles/calendar-navigation.js.map +0 -1
- package/lib/styles/calendar.d.ts.map +0 -1
- package/lib/styles/calendar.js.map +0 -1
- package/lib/styles/checkbox.d.ts.map +0 -1
- package/lib/styles/checkbox.js.map +0 -1
- package/lib/styles/copy.d.ts.map +0 -1
- package/lib/styles/copy.js.map +0 -1
- package/lib/styles/custom-scrollbar.d.ts.map +0 -1
- package/lib/styles/custom-scrollbar.js.map +0 -1
- package/lib/styles/date-picker.d.ts.map +0 -1
- package/lib/styles/date-picker.js.map +0 -1
- package/lib/styles/file-upload.d.ts.map +0 -1
- package/lib/styles/file-upload.js.map +0 -1
- package/lib/styles/icon.d.ts.map +0 -1
- package/lib/styles/icon.js.map +0 -1
- package/lib/styles/input.d.ts.map +0 -1
- package/lib/styles/input.js.map +0 -1
- package/lib/styles/modal.d.ts.map +0 -1
- package/lib/styles/modal.js.map +0 -1
- package/lib/styles/multiselect.d.ts +0 -8
- package/lib/styles/multiselect.d.ts.map +0 -1
- package/lib/styles/multiselect.js +0 -849
- package/lib/styles/multiselect.js.map +0 -1
- package/lib/styles/option.d.ts.map +0 -1
- package/lib/styles/option.js.map +0 -1
- package/lib/styles/popup.d.ts.map +0 -1
- package/lib/styles/popup.js.map +0 -1
- package/lib/styles/radio.d.ts.map +0 -1
- package/lib/styles/radio.js.map +0 -1
- package/lib/styles/resize-observer.d.ts.map +0 -1
- package/lib/styles/resize-observer.js.map +0 -1
- package/lib/styles/scroll-container.d.ts.map +0 -1
- package/lib/styles/scroll-container.js.map +0 -1
- package/lib/styles/select-base.d.ts.map +0 -1
- package/lib/styles/select-base.js.map +0 -1
- package/lib/styles/select.d.ts.map +0 -1
- package/lib/styles/select.js.map +0 -1
- package/lib/styles/step.d.ts.map +0 -1
- package/lib/styles/step.js.map +0 -1
- package/lib/styles/switch.d.ts.map +0 -1
- package/lib/styles/switch.js.map +0 -1
- package/lib/styles/tab.d.ts.map +0 -1
- package/lib/styles/tab.js.map +0 -1
- package/lib/styles/tabs.d.ts.map +0 -1
- package/lib/styles/tabs.js.map +0 -1
- package/lib/styles/tag.d.ts.map +0 -1
- package/lib/styles/tag.js.map +0 -1
- package/lib/styles/textarea.d.ts.map +0 -1
- package/lib/styles/textarea.js.map +0 -1
- package/lib/styles/tooltip.d.ts.map +0 -1
- package/lib/styles/tooltip.js.map +0 -1
- package/lib/styles/wizard.d.ts.map +0 -1
- package/lib/styles/wizard.js.map +0 -1
- package/lib/types/common.d.ts.map +0 -1
- package/lib/types/common.js.map +0 -1
- package/lib/utils/calendar-utils.d.ts.map +0 -1
- package/lib/utils/calendar-utils.js.map +0 -1
- package/lib/utils/custom-scrollbar.d.ts.map +0 -1
- package/lib/utils/custom-scrollbar.js.map +0 -1
- package/lib/utils/flavor-sheet.d.ts.map +0 -1
- package/lib/utils/flavor-sheet.js.map +0 -1
- package/lib/utils/icon-registry.d.ts.map +0 -1
- package/lib/utils/icon-registry.js.map +0 -1
- package/lib/utils/icons.d.ts.map +0 -1
- package/lib/utils/icons.js.map +0 -1
- package/lib/utils/loader-registry.d.ts.map +0 -1
- package/lib/utils/loader-registry.js.map +0 -1
- package/lib/utils/locale.d.ts.map +0 -1
- package/lib/utils/locale.js.map +0 -1
- package/lib/utils/mobile.d.ts.map +0 -1
- package/lib/utils/mobile.js.map +0 -1
- package/lib/utils/number-format.d.ts.map +0 -1
- package/lib/utils/number-format.js.map +0 -1
- package/lib/utils/parse-boolean.d.ts +0 -39
- package/lib/utils/parse-boolean.d.ts.map +0 -1
- package/lib/utils/parse-boolean.js +0 -58
- package/lib/utils/parse-boolean.js.map +0 -1
- package/lib/utils/positioning.d.ts.map +0 -1
- package/lib/utils/positioning.js.map +0 -1
- package/lib/utils/property-capture.d.ts.map +0 -1
- package/lib/utils/property-capture.js.map +0 -1
- package/lib/utils/property-manager.d.ts.map +0 -1
- package/lib/utils/property-manager.js.map +0 -1
- package/lib/utils/resize-observer.d.ts.map +0 -1
- package/lib/utils/resize-observer.js.map +0 -1
- package/lib/utils/scroll-lock.d.ts.map +0 -1
- package/lib/utils/scroll-lock.js.map +0 -1
- package/lib/utils/styles.d.ts.map +0 -1
- package/lib/utils/styles.js.map +0 -1
- package/lib/version.d.ts.map +0 -1
- package/lib/version.js.map +0 -1
package/lib/styles/button.js
CHANGED
|
@@ -1,93 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Button Component Styles
|
|
3
|
-
*
|
|
4
|
-
* Three appearance variants × five semantic flavors × three tones (+/base/-).
|
|
5
|
-
* Each variant uses ONE token system:
|
|
6
|
-
*
|
|
7
|
-
* - solid → flat per-segment tokens --ty-solid-{flavor}{,-hover,-active,
|
|
8
|
-
* -strong,-soft,-fg}. Derived in tyrell-theme.css via OKLCH on
|
|
9
|
-
* 3 axes (color / hover-active / theme chroma-hue); literal in
|
|
10
|
-
* tyrell.css. The component does no color math for the fill.
|
|
11
|
-
* Depth chrome (border + drop shadow) IS computed here, from
|
|
12
|
-
* the fill, via relative color — see "Depth chrome" below.
|
|
13
|
-
* - outlined → --ty-color-{flavor}-{strong|base|soft} (text === border at
|
|
14
|
-
* rest); hover/active/focus always resolve to -strong,
|
|
15
|
-
* whatever the resting tone was — see "Hover escalation".
|
|
16
|
-
* - ghost → same as outlined, text only (no border), --ty-bg-{flavor}-soft
|
|
17
|
-
* background on hover.
|
|
18
|
-
*
|
|
19
|
-
* Neutral is the exception in both outlined and ghost: its `+` tone reads
|
|
20
|
-
* --ty-solid-neutral-strong (the ink dial solid buttons use — the only
|
|
21
|
-
* value that actually inverts light↔dark for full contrast) instead of the
|
|
22
|
-
* generic --ty-color-neutral-strong text-emphasis token. Base/soft neutral
|
|
23
|
-
* stay on the generic token like every other flavor.
|
|
24
|
-
*
|
|
25
|
-
* Depth chrome (solid only): a 1px border + soft drop shadow, both derived
|
|
26
|
-
* from the fill via oklch(from …), scaled by --ty-button-depth (0–1). The
|
|
27
|
-
* border reads the TONE'S RESTING fill (not the current/hover one) so it
|
|
28
|
-
* stays stationary while the fill rises toward it on interaction. Offset
|
|
29
|
-
* direction/magnitude is --ty-button-border-l (mode-flipped: no border at
|
|
30
|
-
* all for colored solids in dark, a lit edge in light) with its own
|
|
31
|
-
* stronger dial for neutral, --ty-button-border-l-neutral (ink has no hue
|
|
32
|
-
* to separate it from the canvas). Escape hatches --ty-solid-border-color
|
|
33
|
-
* / --ty-solid-border-width outrank the derivation entirely.
|
|
34
|
-
*
|
|
35
|
-
* Hover escalation (outlined/ghost): :hover/:active/:focus-visible always
|
|
36
|
-
* resolve to the -strong tier regardless of starting tone — soft and base
|
|
37
|
-
* both rise to the same peak on interaction. Composes with `muted` rather
|
|
38
|
-
* than fighting it (see the escalation rules themselves for the exact
|
|
39
|
-
* split) — a pressed muted button lands on the same color as a pressed
|
|
40
|
-
* plain one of the same flavor.
|
|
41
|
-
*
|
|
42
|
-
* Per-instance overrides via host CSS variables:
|
|
43
|
-
* --ty-button-bg, --ty-button-bg-hover, --ty-button-color, --ty-button-border,
|
|
44
|
-
* --ty-solid-border-color, --ty-solid-border-width
|
|
45
|
-
*/
|
|
46
1
|
import { FLAVORS } from '../types/common.js';
|
|
47
|
-
/* One block per flavor, per appearance. Selectors and tokens are formulaic —
|
|
48
|
-
see the section comments below for which token system each appearance uses.
|
|
49
|
-
|
|
50
|
-
Each generator takes an optional fallback flavor `fb`: token references
|
|
51
|
-
then become var(--ty-*-f, var(--ty-*-fb)). Built-ins pass no fallback
|
|
52
|
-
(their tokens always exist); buttonCustomFlavorCss() passes 'neutral' so a
|
|
53
|
-
custom flavor with missing tokens degrades to neutral instead of an
|
|
54
|
-
invisible button. */
|
|
55
2
|
const tokenRef = (prefix, f, suffix, fb) => fb
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
/* Nudge a fill by an interaction offset (hover/active), tone-aware: each
|
|
59
|
-
tone's states derive from the TONE's own fill, not the base fill —
|
|
60
|
-
otherwise tone- hover jumps from the soft fill to near-base darkness.
|
|
61
|
-
States deliberately do NOT re-derive the text color: fg is decided by
|
|
62
|
-
the tone's REST fill and stays stable through interaction — the ±0.04/
|
|
63
|
-
0.08 L nudges keep AA for any rest-passing fill, and re-deriving would
|
|
64
|
-
flicker black↔white whenever a nudge crosses the fg threshold. */
|
|
3
|
+
? `var(${prefix}-${f}${suffix}, var(${prefix}-${fb}${suffix}))`
|
|
4
|
+
: `var(${prefix}-${f}${suffix})`;
|
|
65
5
|
const nudged = (fillExpr, offsetDial) => `oklch(from ${fillExpr} calc(l + var(--ty-${offsetDial})) c h)`;
|
|
66
|
-
/* Fill-relative nudge: moves TOWARD mid-lightness by the dial's magnitude,
|
|
67
|
-
whatever the fill. Needed for neutral+ — full-contrast ink sits at an L
|
|
68
|
-
extreme in both modes (near-black light / near-white dark), where the
|
|
69
|
-
MODE-directional dials clip into the L ceiling/floor and vanish. */
|
|
70
6
|
const nudgedMid = (fillExpr, offsetDial) => `oklch(from ${fillExpr} calc(l + sign(0.5 - l) * abs(var(--ty-${offsetDial}))) c h)`;
|
|
71
|
-
/* Solid rules assign --_solid-bg (the CURRENT fill — swapped by hover/
|
|
72
|
-
active) and --_solid-rest (the tone's RESTING fill — set only by rest/
|
|
73
|
-
tone rules, never by state rules). The base button.solid rule holds the
|
|
74
|
-
single set of formulas that consume them: background follows --_solid-bg;
|
|
75
|
-
the depth border derives from --_solid-rest so it stays STATIONARY while
|
|
76
|
-
the fill steps up on hover — the fill rises toward the lit edge instead
|
|
77
|
-
of dragging the edge along with it. */
|
|
78
7
|
const solidFlavor = (f, fb) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
? ' --_border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));'
|
|
86
|
-
: ' --_border-l: var(--ty-button-border-l, -0.15);';
|
|
87
|
-
// Neutral+ is full-contrast ink at an L extreme — its hover/active must
|
|
88
|
-
// move toward mid (fill-relative), not in the mode's direction.
|
|
89
|
-
const plusNudge = f === 'neutral' ? nudgedMid : nudged;
|
|
90
|
-
return `
|
|
8
|
+
const solid = (suffix) => tokenRef('--ty-solid', f, suffix, fb);
|
|
9
|
+
const borderL = f === 'neutral'
|
|
10
|
+
? ' --_border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));'
|
|
11
|
+
: ' --_border-l: var(--_muted-border-l, var(--ty-button-border-l, -0.15));';
|
|
12
|
+
const plusNudge = f === 'neutral' ? nudgedMid : nudged;
|
|
13
|
+
return `
|
|
91
14
|
button.solid.${f} { --_ring: ${tokenRef('--ty-color', f, '', fb)}; --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('')}));${borderL} color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-fg')})); }
|
|
92
15
|
button.solid.${f}.tone-plus { --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-strong')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-strong')})); color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-strong-fg')})); }
|
|
93
16
|
button.solid.${f}.tone-minus { --_solid-bg: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-soft')})); --_solid-rest: var(--ty-button-bg, var(--_muted-solid-bg, ${solid('-soft')})); color: var(--ty-button-color, var(--_muted-solid-fg, ${solid('-soft-fg')})); }
|
|
@@ -100,439 +23,314 @@ button.solid.${f}.tone-minus:active:not(:disabled) { --_solid-bg: ${nudged(solid
|
|
|
100
23
|
`;
|
|
101
24
|
};
|
|
102
25
|
const outlinedFlavor = (f, fb) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// base/soft at the solid ink ramp was a real bug (dark-mode contrast
|
|
107
|
-
// against the canvas measured 1.01/1.20 — invisible; WCAG minimum is
|
|
108
|
-
// 4.5). Strong stays on ink: at 0.93 dark / 0.15 light it's still 16.5:1,
|
|
109
|
-
// and matches solid's "+" for the loud-CTA identity that was the ask.
|
|
110
|
-
const textInk = (suffix) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix));
|
|
111
|
-
return `
|
|
26
|
+
const color = (suffix) => tokenRef('--ty-color', f, suffix, fb);
|
|
27
|
+
const textInk = (suffix) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix));
|
|
28
|
+
return `
|
|
112
29
|
button.outlined.${f} {
|
|
113
|
-
|
|
114
|
-
|
|
30
|
+
color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('')}));
|
|
31
|
+
border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('')}));
|
|
115
32
|
}
|
|
116
33
|
button.outlined.${f}.tone-plus {
|
|
117
|
-
|
|
118
|
-
|
|
34
|
+
color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('-strong')}));
|
|
35
|
+
border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('-strong')}));
|
|
119
36
|
}
|
|
120
37
|
button.outlined.${f}.tone-minus {
|
|
121
|
-
|
|
122
|
-
|
|
38
|
+
color: var(--ty-button-color, var(--_muted-outlined-line, ${textInk('-soft')}));
|
|
39
|
+
border-color: var(--ty-button-border, var(--_muted-outlined-line, ${textInk('-soft')}));
|
|
123
40
|
}
|
|
124
41
|
button.outlined.${f}:hover:not(:disabled) {
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
/* Rest is whatever tone you picked; hover/active/focus always escalates to
|
|
128
|
-
the SAME peak — most-emphasized ("+") color, regardless of starting
|
|
129
|
-
tone. tone-plus is already there at rest, so this is a no-op for it.
|
|
130
|
-
:hover only, :not(.muted) — muted's hover-reveal is a DIFFERENT contract
|
|
131
|
-
(reveal the plain button's RESTING color, tested directly against it);
|
|
132
|
-
this rule would outrank that fallback and show strong instead.
|
|
133
|
-
:active/:focus-visible apply to muted too (no exclusion) — muted's own
|
|
134
|
-
reveal-on-press mechanism has much lower specificity than this rule, so
|
|
135
|
-
it simply wins outright, landing muted and plain on the same escalated
|
|
136
|
-
color when both are pressed — which is what muted's OWN test expects. */
|
|
42
|
+
background: var(--ty-button-bg-hover, ${tokenRef('--ty-bg', f, '-soft', fb)});
|
|
43
|
+
}
|
|
137
44
|
button.outlined.${f}:not(.muted):hover:not(:disabled),
|
|
138
45
|
button.outlined.${f}:active:not(:disabled),
|
|
139
46
|
button.outlined.${f}:focus-visible {
|
|
140
|
-
|
|
141
|
-
|
|
47
|
+
color: var(--ty-button-color, ${textInk('-strong')});
|
|
48
|
+
border-color: var(--ty-button-border, ${textInk('-strong')});
|
|
142
49
|
}
|
|
143
50
|
`;
|
|
144
51
|
};
|
|
145
52
|
const ghostFlavor = (f, fb) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
// solid ink ramp doesn't need to invert for readability, a fill reads as
|
|
150
|
-
// a shape regardless of its own lightness. Pointing base/soft neutral
|
|
151
|
-
// text at ink was a real bug: dark-mode contrast against the canvas
|
|
152
|
-
// measured 1.01/1.20 (WCAG minimum is 4.5), i.e. invisible. Strong stays
|
|
153
|
-
// on ink — at 0.93 dark / 0.15 light it's still far above threshold
|
|
154
|
-
// (16.5:1), and matches solid's "+" for the loud-CTA identity that was
|
|
155
|
-
// the actual ask.
|
|
156
|
-
const ink = (suffix) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix));
|
|
157
|
-
return `
|
|
53
|
+
const color = (suffix) => tokenRef('--ty-color', f, suffix, fb);
|
|
54
|
+
const ink = (suffix) => (f === 'neutral' && suffix === '-strong' ? `var(--ty-solid-neutral${suffix})` : color(suffix));
|
|
55
|
+
return `
|
|
158
56
|
button.ghost.${f} { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('')})); }
|
|
159
57
|
button.ghost.${f}.tone-plus { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('-strong')})); }
|
|
160
58
|
button.ghost.${f}.tone-minus { color: var(--ty-button-color, var(--_muted-ghost-fg, ${ink('-soft')})); }
|
|
161
59
|
button.ghost.${f}:hover:not(:disabled) {
|
|
162
|
-
|
|
60
|
+
background: var(--ty-button-bg-hover, ${tokenRef('--ty-bg', f, '-soft', fb)});
|
|
163
61
|
}
|
|
164
|
-
/* See outlinedFlavor above — same escalation-to-peak, same :hover-only
|
|
165
|
-
:not(.muted) split, text only. */
|
|
166
62
|
button.ghost.${f}:not(.muted):hover:not(:disabled),
|
|
167
63
|
button.ghost.${f}:active:not(:disabled),
|
|
168
64
|
button.ghost.${f}:focus-visible {
|
|
169
|
-
|
|
65
|
+
color: var(--ty-button-color, ${ink('-strong')});
|
|
170
66
|
}
|
|
171
67
|
`;
|
|
172
68
|
};
|
|
173
|
-
/** Rules for one custom (non-built-in) flavor across all three appearances. */
|
|
174
69
|
export const buttonCustomFlavorCss = (base) => solidFlavor(base, 'neutral') + outlinedFlavor(base, 'neutral') + ghostFlavor(base, 'neutral');
|
|
175
70
|
export const buttonStyles = `
|
|
176
71
|
:host {
|
|
177
|
-
|
|
178
|
-
|
|
72
|
+
display: inline-block;
|
|
73
|
+
font-family: inherit;
|
|
179
74
|
}
|
|
180
|
-
|
|
181
75
|
:host([wide]) {
|
|
182
|
-
|
|
183
|
-
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-grow: 1;
|
|
78
|
+
}
|
|
79
|
+
:host {
|
|
80
|
+
--ty-button-height: 1.75rem;
|
|
81
|
+
--ty-button-min-width: 4rem;
|
|
82
|
+
--ty-button-pad-x: var(--ty-spacing-2);
|
|
83
|
+
--ty-button-pad-y: 0px;
|
|
84
|
+
--ty-button-font: var(--ty-font-xs);
|
|
85
|
+
--ty-button-leading: var(--ty-leading-xs);
|
|
86
|
+
--ty-button-tracking: var(--ty-tracking-xs);
|
|
87
|
+
--ty-button-gap: var(--ty-spacing-1);
|
|
88
|
+
--ty-button-action-size: 1.5rem;
|
|
89
|
+
--ty-button-action-icon: 0.875rem;
|
|
90
|
+
}
|
|
91
|
+
:host([size="xs"]) {
|
|
92
|
+
--ty-button-height: 1.5rem;
|
|
93
|
+
--ty-button-pad-x: var(--ty-spacing-2);
|
|
94
|
+
--ty-button-pad-y: 0px;
|
|
95
|
+
--ty-button-font: var(--ty-font-xs);
|
|
96
|
+
--ty-button-leading: var(--ty-leading-xs);
|
|
97
|
+
--ty-button-tracking: var(--ty-tracking-xs);
|
|
98
|
+
--ty-button-gap: var(--ty-spacing-1);
|
|
99
|
+
--ty-button-action-size: 1.375rem;
|
|
100
|
+
--ty-button-action-icon: 0.75rem;
|
|
101
|
+
}
|
|
102
|
+
:host([size="md"]) {
|
|
103
|
+
--ty-button-height: 2rem;
|
|
104
|
+
--ty-button-pad-x: var(--ty-spacing-3);
|
|
105
|
+
--ty-button-pad-y: 0.375rem;
|
|
106
|
+
--ty-button-font: var(--ty-font-sm);
|
|
107
|
+
--ty-button-leading: var(--ty-leading-sm);
|
|
108
|
+
--ty-button-tracking: var(--ty-tracking-sm);
|
|
109
|
+
--ty-button-gap: var(--ty-spacing-2);
|
|
110
|
+
--ty-button-action-size: 2rem;
|
|
111
|
+
--ty-button-action-icon: 1rem;
|
|
112
|
+
}
|
|
113
|
+
:host([size="lg"]) {
|
|
114
|
+
--ty-button-height: 2.25rem;
|
|
115
|
+
--ty-button-pad-x: var(--ty-spacing-4);
|
|
116
|
+
--ty-button-pad-y: 0.375rem;
|
|
117
|
+
--ty-button-font: var(--ty-font-sm);
|
|
118
|
+
--ty-button-leading: var(--ty-leading-sm);
|
|
119
|
+
--ty-button-tracking: var(--ty-tracking-sm);
|
|
120
|
+
--ty-button-gap: var(--ty-spacing-2);
|
|
121
|
+
--ty-button-action-size: 2.25rem;
|
|
122
|
+
--ty-button-action-icon: 1.125rem;
|
|
123
|
+
}
|
|
124
|
+
:host([size="xl"]) {
|
|
125
|
+
--ty-button-height: 2.5rem;
|
|
126
|
+
--ty-button-pad-x: var(--ty-spacing-6);
|
|
127
|
+
--ty-button-pad-y: var(--ty-spacing-2);
|
|
128
|
+
--ty-button-font: var(--ty-font-base);
|
|
129
|
+
--ty-button-leading: var(--ty-leading-base);
|
|
130
|
+
--ty-button-tracking: var(--ty-tracking-base);
|
|
131
|
+
--ty-button-gap: var(--ty-spacing-2);
|
|
132
|
+
--ty-button-action-size: 2.5rem;
|
|
133
|
+
--ty-button-action-icon: 1.25rem;
|
|
184
134
|
}
|
|
185
|
-
|
|
186
135
|
button {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
136
|
+
font-family: inherit;
|
|
137
|
+
position: relative;
|
|
138
|
+
display: flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
justify-content: center;
|
|
141
|
+
gap: var(--ty-button-gap);
|
|
142
|
+
height: var(--ty-button-height);
|
|
143
|
+
padding: var(--ty-button-pad-y) var(--ty-button-pad-x);
|
|
144
|
+
font-size: var(--ty-button-font);
|
|
145
|
+
line-height: var(--ty-button-leading);
|
|
146
|
+
letter-spacing: var(--ty-button-tracking);
|
|
147
|
+
font-weight: var(--ty-weight-action, var(--ty-font-medium));
|
|
148
|
+
white-space: nowrap;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
user-select: none;
|
|
151
|
+
transition: var(--ty-local-transition, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease);
|
|
152
|
+
background: transparent;
|
|
153
|
+
color: var(--ty-color-neutral);
|
|
154
|
+
border: 1px solid transparent;
|
|
155
|
+
}
|
|
208
156
|
button:not(.action) {
|
|
209
|
-
|
|
157
|
+
min-width: var(--ty-button-min-width);
|
|
210
158
|
}
|
|
211
|
-
|
|
212
159
|
button:not(.pill) {
|
|
213
|
-
|
|
160
|
+
border-radius: var(--ty-radius-md);
|
|
214
161
|
}
|
|
215
|
-
|
|
216
162
|
button.xs:not(.pill) { border-radius: var(--ty-button-radius-xs, var(--ty-radius-md)); }
|
|
217
163
|
button.sm:not(.pill) { border-radius: var(--ty-button-radius-sm, var(--ty-radius-md)); }
|
|
218
164
|
button.md:not(.pill) { border-radius: var(--ty-button-radius-md, var(--ty-radius-md)); }
|
|
219
165
|
button.lg:not(.pill) { border-radius: var(--ty-button-radius-lg, var(--ty-radius-md)); }
|
|
220
166
|
button.xl:not(.pill) { border-radius: var(--ty-button-radius-xl, var(--ty-radius-md)); }
|
|
221
|
-
|
|
222
167
|
button:focus-visible {
|
|
223
|
-
|
|
168
|
+
outline: none;
|
|
224
169
|
}
|
|
225
|
-
|
|
226
170
|
button:disabled {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/* ===== LOADING STATE =====
|
|
232
|
-
Spinner overlays the button center; original content kept in flow but
|
|
233
|
-
hidden via visibility so width/height are preserved (no layout shift).
|
|
234
|
-
*/
|
|
171
|
+
cursor: not-allowed;
|
|
172
|
+
opacity: 0.6;
|
|
173
|
+
}
|
|
235
174
|
.loader-icon {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
175
|
+
display: none;
|
|
176
|
+
align-items: center;
|
|
177
|
+
justify-content: center;
|
|
178
|
+
flex-shrink: 0;
|
|
179
|
+
width: 1em;
|
|
180
|
+
height: 1em;
|
|
181
|
+
color: currentColor;
|
|
243
182
|
}
|
|
244
183
|
.loader-icon svg {
|
|
245
|
-
|
|
246
|
-
|
|
184
|
+
width: 100%;
|
|
185
|
+
height: 100%;
|
|
247
186
|
}
|
|
248
187
|
button.loading {
|
|
249
|
-
|
|
188
|
+
cursor: wait;
|
|
250
189
|
}
|
|
251
190
|
button.loading > *:not(.loader-icon) {
|
|
252
|
-
|
|
191
|
+
visibility: hidden;
|
|
253
192
|
}
|
|
254
193
|
button.loading > .loader-icon {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
194
|
+
display: inline-flex;
|
|
195
|
+
position: absolute;
|
|
196
|
+
top: 50%;
|
|
197
|
+
left: 50%;
|
|
198
|
+
transform: translate(-50%, -50%);
|
|
199
|
+
animation: ty-button-spin 0.7s linear infinite;
|
|
261
200
|
}
|
|
262
201
|
@keyframes ty-button-spin {
|
|
263
|
-
|
|
202
|
+
to { transform: translate(-50%, -50%) rotate(360deg); }
|
|
264
203
|
}
|
|
265
204
|
@media (prefers-reduced-motion: reduce) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
205
|
+
button.loading > .loader-icon {
|
|
206
|
+
animation-duration: 1.6s;
|
|
207
|
+
}
|
|
269
208
|
}
|
|
270
|
-
|
|
271
209
|
::slotted(*) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
210
|
+
display: inline-flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
justify-content: center;
|
|
275
213
|
}
|
|
276
|
-
|
|
277
214
|
::slotted(ty-icon) {
|
|
278
|
-
|
|
215
|
+
flex-shrink: 0;
|
|
279
216
|
}
|
|
280
|
-
|
|
281
217
|
:host([wide]) button {
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/* ===== SIZES =====
|
|
286
|
-
Buttons run a 4px ladder (24-40px). Shared scale with fields
|
|
287
|
-
(--ty-size-sm/md/lg — see tyrell.css): field sm = button md (32px),
|
|
288
|
-
field md = button lg (36px), field lg = button xl (40px) — a button
|
|
289
|
-
and a field of the paired size sit flush, same height, in a row. */
|
|
290
|
-
|
|
291
|
-
button.xs {
|
|
292
|
-
padding: 0 var(--ty-spacing-2);
|
|
293
|
-
font-size: var(--ty-font-xs);
|
|
294
|
-
line-height: var(--ty-leading-xs);
|
|
295
|
-
letter-spacing: var(--ty-tracking-xs);
|
|
296
|
-
gap: var(--ty-spacing-1);
|
|
297
|
-
height: 1.5rem; /* 24px */
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
button.sm {
|
|
301
|
-
padding: 0 var(--ty-spacing-2);
|
|
302
|
-
font-size: var(--ty-font-xs);
|
|
303
|
-
line-height: var(--ty-leading-xs);
|
|
304
|
-
letter-spacing: var(--ty-tracking-xs);
|
|
305
|
-
gap: var(--ty-spacing-1);
|
|
306
|
-
height: 1.75rem; /* 28px */
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
button.md {
|
|
310
|
-
padding: 0.375rem var(--ty-spacing-3);
|
|
311
|
-
font-size: var(--ty-font-sm);
|
|
312
|
-
line-height: var(--ty-leading-sm);
|
|
313
|
-
letter-spacing: var(--ty-tracking-sm);
|
|
314
|
-
gap: var(--ty-spacing-2);
|
|
315
|
-
height: 2rem; /* 32px — matches field sm */
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
button.lg {
|
|
319
|
-
padding: 0.375rem var(--ty-spacing-4);
|
|
320
|
-
font-size: var(--ty-font-sm);
|
|
321
|
-
line-height: var(--ty-leading-sm);
|
|
322
|
-
letter-spacing: var(--ty-tracking-sm);
|
|
323
|
-
gap: var(--ty-spacing-2);
|
|
324
|
-
height: 2.25rem; /* 36px — matches field md */
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
button.xl {
|
|
328
|
-
padding: var(--ty-spacing-2) var(--ty-spacing-6);
|
|
329
|
-
font-size: var(--ty-font-base);
|
|
330
|
-
line-height: var(--ty-leading-base);
|
|
331
|
-
letter-spacing: var(--ty-tracking-base);
|
|
332
|
-
gap: var(--ty-spacing-2);
|
|
333
|
-
height: 2.5rem; /* 40px — matches field lg */
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/* ===== ACTION (icon-only square) ===== */
|
|
337
|
-
|
|
218
|
+
flex-grow: 1;
|
|
219
|
+
}
|
|
338
220
|
button.action {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
221
|
+
gap: 0px !important;
|
|
222
|
+
height: var(--ty-button-action-size);
|
|
223
|
+
width: var(--ty-button-action-size);
|
|
224
|
+
padding: 0px !important;
|
|
343
225
|
}
|
|
344
|
-
|
|
345
226
|
button.action ::slotted(ty-icon) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
button.action.xs { height: 1.375rem; width: 1.375rem; }
|
|
351
|
-
button.action.xs ::slotted(ty-icon) { height: 0.75rem; width: 0.75rem; }
|
|
352
|
-
|
|
353
|
-
button.action.sm { height: 1.5rem; width: 1.5rem; }
|
|
354
|
-
button.action.sm ::slotted(ty-icon) { height: 0.875rem; width: 0.875rem; }
|
|
355
|
-
|
|
356
|
-
button.action.lg { height: 2.25rem; width: 2.25rem; }
|
|
357
|
-
button.action.lg ::slotted(ty-icon) { height: 1.125rem; width: 1.125rem; }
|
|
358
|
-
|
|
359
|
-
button.action.xl { height: 2.5rem; width: 2.5rem; }
|
|
360
|
-
button.action.xl ::slotted(ty-icon) { height: 1.25rem; width: 1.25rem; }
|
|
361
|
-
|
|
362
|
-
/* ===== MUTED =====
|
|
363
|
-
Show the neutral tokens at rest instead of the flavor color; reveal the
|
|
364
|
-
real flavor on interaction. Implemented as a fallback tier the flavor
|
|
365
|
-
rules above already read (--_muted-*), which sits behind the public
|
|
366
|
-
--ty-button-{bg,color,border} override slots and ahead of the flavor's
|
|
367
|
-
own token — so a custom brand color still wins, muted or not. Unsetting
|
|
368
|
-
--_muted-* on interaction falls the var() chain through to whatever's
|
|
369
|
-
next (the user's override, or the real flavor color).
|
|
370
|
-
Hover reveal is gated to real pointers (touch has no hover); :active /
|
|
371
|
-
:focus-visible cover the tap case so touch still gets the color on press. */
|
|
372
|
-
|
|
373
|
-
/* --_muted-solid-* reads the SOLID neutral ink tokens — a fill's L doesn't
|
|
374
|
-
need page contrast. --_muted-outlined-line / --_muted-ghost-fg are bare
|
|
375
|
-
text/border and DO — they stay on the regular text ladder (it already
|
|
376
|
-
inverts correctly per mode), except tone-plus, which is legible AND
|
|
377
|
-
loud on the ink dial (16.5:1 dark, matches solid's "+" identity). Base/
|
|
378
|
-
soft on ink measured 1.01/1.20 dark contrast against the canvas —
|
|
379
|
-
invisible; WCAG minimum is 4.5. */
|
|
227
|
+
height: var(--ty-button-action-icon);
|
|
228
|
+
width: var(--ty-button-action-icon);
|
|
229
|
+
}
|
|
380
230
|
button.muted {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
231
|
+
--_muted-solid-bg: var(--ty-solid-neutral);
|
|
232
|
+
--_muted-solid-fg: var(--ty-solid-neutral-fg);
|
|
233
|
+
--_muted-outlined-line: var(--ty-color-neutral);
|
|
234
|
+
--_muted-ghost-fg: var(--ty-color-neutral);
|
|
235
|
+
--_muted-border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));
|
|
385
236
|
}
|
|
386
237
|
button.muted.tone-plus {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
--_muted-solid-fg: var(--ty-solid-neutral-strong-fg);
|
|
392
|
-
--_muted-outlined-line: var(--ty-solid-neutral-strong);
|
|
393
|
-
--_muted-ghost-fg: var(--ty-solid-neutral-strong);
|
|
238
|
+
--_muted-solid-bg: var(--ty-solid-neutral-strong);
|
|
239
|
+
--_muted-solid-fg: var(--ty-solid-neutral-strong-fg);
|
|
240
|
+
--_muted-outlined-line: var(--ty-solid-neutral-strong);
|
|
241
|
+
--_muted-ghost-fg: var(--ty-solid-neutral-strong);
|
|
394
242
|
}
|
|
395
243
|
button.muted.tone-minus {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
244
|
+
--_muted-solid-bg: var(--ty-solid-neutral-soft);
|
|
245
|
+
--_muted-solid-fg: var(--ty-solid-neutral-soft-fg);
|
|
246
|
+
--_muted-outlined-line: var(--ty-color-neutral-soft);
|
|
247
|
+
--_muted-ghost-fg: var(--ty-color-neutral-soft);
|
|
400
248
|
}
|
|
401
249
|
@media (hover: hover) and (pointer: fine) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
250
|
+
button.muted:hover:not(:disabled) {
|
|
251
|
+
--_muted-solid-bg: unset;
|
|
252
|
+
--_muted-solid-fg: unset;
|
|
253
|
+
--_muted-outlined-line: unset;
|
|
254
|
+
--_muted-ghost-fg: unset;
|
|
255
|
+
--_muted-border-l: unset;
|
|
256
|
+
}
|
|
408
257
|
}
|
|
409
258
|
button.muted:active:not(:disabled),
|
|
410
259
|
button.muted:focus-visible:not(:disabled) {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
/* ===== PILL ===== */
|
|
418
|
-
|
|
260
|
+
--_muted-solid-bg: unset;
|
|
261
|
+
--_muted-solid-fg: unset;
|
|
262
|
+
--_muted-outlined-line: unset;
|
|
263
|
+
--_muted-ghost-fg: unset;
|
|
264
|
+
--_muted-border-l: unset;
|
|
265
|
+
}
|
|
419
266
|
button.pill {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
267
|
+
border-radius: 9999px;
|
|
268
|
+
padding-left: 1.25em;
|
|
269
|
+
padding-right: 1.25em;
|
|
423
270
|
}
|
|
424
|
-
|
|
425
271
|
button.pill.xs { padding-left: 1em; padding-right: 1em; }
|
|
426
272
|
button.pill.sm { padding-left: 1.125em; padding-right: 1.125em; }
|
|
427
273
|
button.pill.lg { padding-left: 1.5em; padding-right: 1.5em; }
|
|
428
274
|
button.pill.xl { padding-left: 1.75em; padding-right: 1.75em; }
|
|
429
|
-
|
|
430
275
|
button.pill:has(ty-icon:only-child),
|
|
431
276
|
button.pill:has(slot[name="start"]:only-child),
|
|
432
277
|
button.pill:has(slot[name="end"]:only-child) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
278
|
+
padding: 0;
|
|
279
|
+
aspect-ratio: 1;
|
|
280
|
+
min-width: var(--ty-size-md);
|
|
436
281
|
}
|
|
437
|
-
|
|
438
282
|
button.pill.xs:has(ty-icon:only-child) { min-width: 1.375rem; min-height: 1.375rem; }
|
|
439
283
|
button.pill.sm:has(ty-icon:only-child) { min-width: 1.5rem; min-height: 1.5rem; }
|
|
440
284
|
button.pill.md:has(ty-icon:only-child) { min-width: 2rem; min-height: 2rem; }
|
|
441
285
|
button.pill.lg:has(ty-icon:only-child) { min-width: 2.25rem; min-height: 2.25rem; }
|
|
442
286
|
button.pill.xl:has(ty-icon:only-child) { min-width: 2.5rem; min-height: 2.5rem; }
|
|
443
|
-
|
|
444
|
-
/* ============================================================
|
|
445
|
-
SOLID — flat: one variable per segment. No color math here; all the
|
|
446
|
-
--ty-solid-{flavor}-{hover,active,strong,soft} tokens are DERIVED in
|
|
447
|
-
tyrell-theme.css (OKLCH) or set literally in tyrell.css. Override any
|
|
448
|
-
single token to recolor that one segment. Bare .solid = custom-flavor
|
|
449
|
-
fallback, themable via --ty-button-{bg,bg-hover,color}.
|
|
450
|
-
============================================================ */
|
|
451
|
-
|
|
452
287
|
button.solid {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
(A top-edge sheen — inset 0 1px 0 <lightened fill> — used to live here
|
|
464
|
-
too; dropped, it read as a dizzying bright line rather than a subtle
|
|
465
|
-
highlight.) depth 0 = border matches fill exactly and the shadow goes
|
|
466
|
-
transparent — pixel-flat, but the 1px border stays in the layout so
|
|
467
|
-
toggling depth never shifts geometry (and solid now shares the same
|
|
468
|
-
box as outlined/ghost, which always had a 1px border).
|
|
469
|
-
--ty-button-border-l flips sign with the mode (tyrell.css): dark mode
|
|
470
|
-
runs a LIGHTER-than-fill hairline (fills read washed-out against dark
|
|
471
|
-
surfaces without a lit edge), light mode a slightly darker one.
|
|
472
|
-
Direct escape hatches outrank the derivation: --ty-solid-border-color
|
|
473
|
-
pins the border to ANY color (the L-offset dials stop mattering), and
|
|
474
|
-
--ty-solid-border-width changes thickness (widths ≠ 1px do shift
|
|
475
|
-
geometry — that's inherent).
|
|
476
|
-
Browsers without relative color drop these declarations: border falls
|
|
477
|
-
back to the base button's 1px transparent, shadows to none. */
|
|
478
|
-
border: var(--ty-solid-border-width, 1px) solid
|
|
479
|
-
var(--ty-solid-border-color,
|
|
480
|
-
oklch(from var(--_solid-rest, var(--_solid-bg)) calc(l + var(--_border-l, -0.15) * var(--ty-button-depth, 0.35)) c h));
|
|
481
|
-
box-shadow: 0 1px 2px oklch(0 0 0 / calc(0.4 * var(--ty-button-depth, 0.35)));
|
|
288
|
+
--_ring: var(--ty-color-neutral);
|
|
289
|
+
--_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral));
|
|
290
|
+
--_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral));
|
|
291
|
+
--_border-l: var(--ty-button-border-l-neutral, var(--ty-button-border-l, -0.15));
|
|
292
|
+
background: var(--_solid-bg);
|
|
293
|
+
color: var(--ty-button-color, var(--ty-solid-neutral-fg));
|
|
294
|
+
border: var(--ty-solid-border-width, 1px) solid
|
|
295
|
+
var(--ty-solid-border-color,
|
|
296
|
+
oklch(from var(--_solid-rest, var(--_solid-bg)) calc(l + var(--_border-l, -0.15) * var(--ty-button-depth, 0.35)) c h));
|
|
297
|
+
box-shadow: 0 1px 2px oklch(0 0 0 / calc(0.4 * var(--ty-button-depth, 0.35)));
|
|
482
298
|
}
|
|
483
299
|
button.solid.tone-plus { --_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral-strong)); --_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral-strong)); color: var(--ty-button-color, var(--ty-solid-neutral-strong-fg)); }
|
|
484
300
|
button.solid.tone-minus { --_solid-bg: var(--ty-button-bg, var(--ty-solid-neutral-soft)); --_solid-rest: var(--ty-button-bg, var(--ty-solid-neutral-soft)); color: var(--ty-button-color, var(--ty-solid-neutral-soft-fg)); }
|
|
485
301
|
button.solid:hover:not(:disabled) { --_solid-bg: var(--ty-button-bg-hover, var(--ty-solid-neutral-hover)); }
|
|
486
302
|
button.solid:active:not(:disabled) { --_solid-bg: var(--ty-solid-neutral-active); }
|
|
487
303
|
button.solid.tone-plus:hover:not(:disabled) {
|
|
488
|
-
|
|
304
|
+
--_solid-bg: var(--ty-button-bg-hover, oklch(from var(--ty-solid-neutral-strong) calc(l + sign(0.5 - l) * abs(var(--ty-solid-hover-l))) c h));
|
|
489
305
|
}
|
|
490
306
|
button.solid.tone-plus:active:not(:disabled) {
|
|
491
|
-
|
|
307
|
+
--_solid-bg: oklch(from var(--ty-solid-neutral-strong) calc(l + sign(0.5 - l) * abs(var(--ty-solid-active-l))) c h);
|
|
492
308
|
}
|
|
493
309
|
button.solid.tone-minus:hover:not(:disabled) {
|
|
494
|
-
|
|
310
|
+
--_solid-bg: var(--ty-button-bg-hover, oklch(from var(--ty-solid-neutral-soft) calc(l + var(--ty-solid-hover-l)) c h));
|
|
495
311
|
}
|
|
496
312
|
button.solid.tone-minus:active:not(:disabled) {
|
|
497
|
-
|
|
313
|
+
--_solid-bg: oklch(from var(--ty-solid-neutral-soft) calc(l + var(--ty-solid-active-l)) c h);
|
|
498
314
|
}
|
|
499
|
-
|
|
500
315
|
${FLAVORS.map((f) => solidFlavor(f)).join('')}
|
|
501
316
|
button.solid:focus-visible {
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/* ============================================================
|
|
506
|
-
OUTLINED — transparent bg, text === border (uses --ty-color-*)
|
|
507
|
-
Bare .outlined rule = fallback for custom flavors. For outlined,
|
|
508
|
-
text is bound to border color (the rule "text === border"), so the
|
|
509
|
-
fallback chain prefers --ty-button-border, then --ty-button-color.
|
|
510
|
-
============================================================ */
|
|
511
|
-
|
|
317
|
+
box-shadow: 0 0 0 2px var(--ty-focus-ring-gap), 0 0 0 4px var(--_ring);
|
|
318
|
+
}
|
|
512
319
|
button.outlined {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
320
|
+
background: transparent;
|
|
321
|
+
color: var(--ty-button-border, var(--ty-button-color, var(--ty-color-neutral)));
|
|
322
|
+
border-color: var(--ty-button-border, var(--ty-button-color, var(--ty-color-neutral)));
|
|
516
323
|
}
|
|
517
324
|
button.outlined:hover:not(:disabled) {
|
|
518
|
-
|
|
325
|
+
background: var(--ty-button-bg-hover, var(--ty-bg-neutral-soft));
|
|
519
326
|
}
|
|
520
|
-
|
|
521
327
|
${FLAVORS.map((f) => outlinedFlavor(f)).join('')}
|
|
522
|
-
|
|
523
|
-
/* ============================================================
|
|
524
|
-
GHOST — text only, hover bg (uses --ty-color-* + --ty-bg-*-soft)
|
|
525
|
-
Bare .ghost rule = fallback for custom flavors.
|
|
526
|
-
============================================================ */
|
|
527
|
-
|
|
528
328
|
button.ghost {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
329
|
+
background: transparent;
|
|
330
|
+
border: none;
|
|
331
|
+
color: var(--ty-button-color, var(--ty-color-neutral));
|
|
532
332
|
}
|
|
533
333
|
button.ghost:hover:not(:disabled) {
|
|
534
|
-
|
|
334
|
+
background: var(--ty-button-bg-hover, var(--ty-bg-neutral-soft));
|
|
535
335
|
}
|
|
536
|
-
|
|
537
336
|
${FLAVORS.map((f) => ghostFlavor(f)).join('')}`;
|
|
538
|
-
//# sourceMappingURL=button.js.map
|