astralkit 0.6.0 → 0.7.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/CHANGELOG.md +15 -0
- package/LICENSE +73 -34
- package/README.md +31 -1
- package/astralkit-theme-v4.css +135 -114
- package/astralkit-theme.css +135 -114
- package/astralkit-utilities.css +312 -1
- package/lib/presets/appearance-presets.d.ts +12 -0
- package/lib/presets/appearance-presets.js +102 -0
- package/lib/presets/chart-palettes.d.ts +29 -0
- package/lib/presets/chart-palettes.js +99 -0
- package/lib/presets/dials.d.ts +31 -0
- package/lib/presets/dials.js +330 -0
- package/lib/presets/font-pairings.d.ts +29 -0
- package/lib/presets/font-pairings.js +123 -0
- package/lib/presets/fonts.d.ts +16 -0
- package/lib/presets/fonts.js +76 -0
- package/lib/presets/index.d.ts +7 -0
- package/lib/presets/index.js +24 -0
- package/lib/presets/materials.d.ts +15 -0
- package/lib/presets/materials.js +245 -0
- package/lib/presets/theme-palettes.d.ts +90 -0
- package/lib/presets/theme-palettes.js +720 -0
- package/package.json +3 -2
- package/primitives/animations.css +43 -1
- package/tailwind.cjs +15 -9
package/astralkit-utilities.css
CHANGED
|
@@ -799,7 +799,12 @@ body.ak-ew-resizing, body.ak-ew-resizing * {
|
|
|
799
799
|
}
|
|
800
800
|
|
|
801
801
|
/* ── Focus Ring Utility ── */
|
|
802
|
-
.ak-focus-ring:focus-visible {
|
|
802
|
+
.ak-focus-ring:focus-visible {
|
|
803
|
+
/* Material-drivable: packs may restyle focus (neo-brutal = 3px dashed ink).
|
|
804
|
+
Default reproduces the house ring exactly. */
|
|
805
|
+
outline: var(--ak-focus-outline, 2px solid var(--color-ak-border-focus, var(--color-ak-primary)));
|
|
806
|
+
outline-offset: var(--ak-focus-offset, 2px);
|
|
807
|
+
}
|
|
803
808
|
|
|
804
809
|
/* ── Price Fade Transition ── */
|
|
805
810
|
.ak-price-fade { transition: opacity 0.15s ease-in-out; }
|
|
@@ -815,3 +820,309 @@ body.ak-ew-resizing, body.ak-ew-resizing * {
|
|
|
815
820
|
@keyframes ak-slideIn { from { opacity: 0; } to { opacity: 1; } }
|
|
816
821
|
@keyframes ak-fadeOut { from { opacity: 1; } to { opacity: 0; } }
|
|
817
822
|
}
|
|
823
|
+
|
|
824
|
+
/* ── Typography roles (2026-08-02) ─────────────────────────────────
|
|
825
|
+
Five roles, each an authored family+weight pair driven by variables so a
|
|
826
|
+
font pairing re-tunes the whole hierarchy coherently (family swaps without
|
|
827
|
+
weight compensation always look wrong — different families have different
|
|
828
|
+
weight curves). Components consume ROLE classes, never literal
|
|
829
|
+
font-family/font-weight for themed text. Weight vars live outside the
|
|
830
|
+
--font-weight-* namespace on purpose (v4 would generate colliding font-*
|
|
831
|
+
utilities). Mono role = the existing font-ak-mono utility. */
|
|
832
|
+
.ak-font-heading {
|
|
833
|
+
font-family: var(--font-ak-heading, var(--font-ak-sans, Inter, sans-serif));
|
|
834
|
+
font-weight: var(--ak-weight-heading, 600);
|
|
835
|
+
}
|
|
836
|
+
.ak-font-body {
|
|
837
|
+
font-family: var(--font-ak-sans, Inter, sans-serif);
|
|
838
|
+
font-weight: var(--ak-weight-body, 400);
|
|
839
|
+
}
|
|
840
|
+
.ak-font-ui {
|
|
841
|
+
font-family: var(--font-ak-ui, var(--font-ak-sans, Inter, sans-serif));
|
|
842
|
+
font-weight: var(--ak-weight-ui, 500);
|
|
843
|
+
}
|
|
844
|
+
/* Emphasized UI — buttons, pressed/active controls, row titles. The library
|
|
845
|
+
calibration is semibold on every button and active state (conventions:
|
|
846
|
+
"titles are font-semibold"; forms references all carry font-semibold CTAs)
|
|
847
|
+
while quiet UI (menu rows, inputs, nav) stays at the ui weight. Pairings
|
|
848
|
+
override via --ak-weight-ui-strong. */
|
|
849
|
+
.ak-font-ui-strong {
|
|
850
|
+
font-family: var(--font-ak-ui, var(--font-ak-sans, Inter, sans-serif));
|
|
851
|
+
font-weight: var(--ak-weight-ui-strong, 600);
|
|
852
|
+
}
|
|
853
|
+
.ak-font-label {
|
|
854
|
+
font-family: var(--font-ak-label, var(--font-ak-sans, Inter, sans-serif));
|
|
855
|
+
font-weight: var(--ak-weight-label, 600);
|
|
856
|
+
letter-spacing: var(--ak-tracking-label, 0.02em);
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
/* ── Material recipes (2026-08-02) ──────────────────────────────
|
|
860
|
+
The consumption layer for material appearances (astralkit/presets
|
|
861
|
+
MATERIAL_APPEARANCES). Components carry these classes; appearance packs
|
|
862
|
+
fill the --ak-* slots. Every default reproduces the pre-material look,
|
|
863
|
+
so unthemed apps are pixel-identical. */
|
|
864
|
+
.ak-material-control {
|
|
865
|
+
box-shadow: var(--ak-control-shadow, none);
|
|
866
|
+
transition: box-shadow 0.15s ease, transform 0.15s ease;
|
|
867
|
+
}
|
|
868
|
+
.ak-material-control:hover {
|
|
869
|
+
transform: var(--ak-control-hover-transform, none);
|
|
870
|
+
box-shadow: var(--ak-control-shadow-hover, var(--ak-control-shadow, none));
|
|
871
|
+
}
|
|
872
|
+
.ak-material-control:active {
|
|
873
|
+
box-shadow: var(--ak-control-shadow-active, var(--ak-control-shadow, none));
|
|
874
|
+
}
|
|
875
|
+
.ak-material-surface {
|
|
876
|
+
position: relative;
|
|
877
|
+
/* Two-layer background: an optional SHEEN (falls off from the single
|
|
878
|
+
top-left light source) over the fill. Defaults collapse to plain fill. */
|
|
879
|
+
background: var(--ak-surface-sheen, none), var(--ak-surface-fill, var(--color-ak-surface));
|
|
880
|
+
border: var(--ak-surface-border-w, 1px) solid var(--ak-surface-border-color, var(--color-ak-border));
|
|
881
|
+
box-shadow: var(--ak-surface-shadow, none);
|
|
882
|
+
-webkit-backdrop-filter: var(--ak-surface-blur, none);
|
|
883
|
+
backdrop-filter: var(--ak-surface-blur, none);
|
|
884
|
+
}
|
|
885
|
+
/* Directional rim — a gradient border ring (hot toward the light source,
|
|
886
|
+
dying opposite) via padding + mask-composite. Invisible until a pack sets
|
|
887
|
+
--ak-surface-rim. */
|
|
888
|
+
.ak-material-surface::before {
|
|
889
|
+
content: "";
|
|
890
|
+
position: absolute;
|
|
891
|
+
inset: 0;
|
|
892
|
+
border-radius: inherit;
|
|
893
|
+
padding: var(--ak-surface-rim-w, 1.5px);
|
|
894
|
+
background: var(--ak-surface-rim, none);
|
|
895
|
+
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
|
896
|
+
-webkit-mask-composite: xor;
|
|
897
|
+
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
|
898
|
+
mask-composite: exclude;
|
|
899
|
+
pointer-events: none;
|
|
900
|
+
}
|
|
901
|
+
/* Depth ladder: nested material surfaces step their tint up one level so
|
|
902
|
+
stacked glass reads as stacked panes. Packs opt in via the -2 slot. */
|
|
903
|
+
.ak-material-surface .ak-material-surface {
|
|
904
|
+
background: var(--ak-surface-sheen-2, var(--ak-surface-sheen, none)),
|
|
905
|
+
var(--ak-surface-fill-2, var(--ak-surface-fill, var(--color-ak-surface-2)));
|
|
906
|
+
box-shadow: var(--ak-surface-shadow-2, var(--ak-surface-shadow, none));
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/* ── Small-control material parts (batch 2) ─────────────────────────────
|
|
910
|
+
Glass Law 4: glass is for surfaces — active parts stay flat solid. The
|
|
911
|
+
knob (switch), thumb (slider) and track are material-slotted so the
|
|
912
|
+
Appearance dial re-materializes running form controls. Position is done
|
|
913
|
+
with the CSS `translate` property in components; recipes only ever touch
|
|
914
|
+
`transform`, so squish/tilt compose with position instead of clobbering it. */
|
|
915
|
+
.ak-control-knob {
|
|
916
|
+
background: var(--ak-knob-fill, #ffffff);
|
|
917
|
+
box-shadow: var(--ak-knob-shadow, 0 1px 3px rgba(0, 0, 0, 0.25));
|
|
918
|
+
transition:
|
|
919
|
+
translate 200ms var(--ak-control-spring, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
920
|
+
transform 200ms var(--ak-control-spring, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
921
|
+
background-color 150ms ease;
|
|
922
|
+
}
|
|
923
|
+
[data-state="checked"] > .ak-control-knob {
|
|
924
|
+
background: var(--ak-knob-fill-checked, var(--ak-knob-fill, #ffffff));
|
|
925
|
+
}
|
|
926
|
+
/* The squish: origin follows the travel direction so the stretch reads as
|
|
927
|
+
the knob leaning into the push. */
|
|
928
|
+
[data-ak-component="switch"]:active .ak-control-knob {
|
|
929
|
+
transform: var(--ak-knob-press, scaleX(1.12));
|
|
930
|
+
transform-origin: left center;
|
|
931
|
+
}
|
|
932
|
+
[data-ak-component="switch"][data-state="checked"]:active .ak-control-knob {
|
|
933
|
+
transform-origin: right center;
|
|
934
|
+
}
|
|
935
|
+
.ak-control-thumb {
|
|
936
|
+
background: var(--ak-thumb-fill, #ffffff);
|
|
937
|
+
border-radius: var(--ak-thumb-radius, 9999px);
|
|
938
|
+
border: var(--ak-thumb-border-w, 0px) solid var(--ak-thumb-border-color, transparent);
|
|
939
|
+
box-shadow: var(--ak-thumb-shadow, 0 1px 4px rgba(0, 0, 0, 0.3));
|
|
940
|
+
transition: transform 180ms var(--ak-control-spring, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
941
|
+
box-shadow 180ms ease;
|
|
942
|
+
}
|
|
943
|
+
.ak-control-thumb:hover {
|
|
944
|
+
transform: var(--ak-thumb-hover-transform, scale(1.1));
|
|
945
|
+
}
|
|
946
|
+
.ak-control-thumb:active {
|
|
947
|
+
transform: var(--ak-thumb-active-transform, scale(0.96));
|
|
948
|
+
}
|
|
949
|
+
/* Track border renders as an INSET RING, not a real border — layout never
|
|
950
|
+
shifts, so knob travel constants hold across every material. */
|
|
951
|
+
.ak-control-track {
|
|
952
|
+
box-shadow:
|
|
953
|
+
inset 0 0 0 var(--ak-track-border-w, 0px) var(--ak-track-border-color, transparent),
|
|
954
|
+
var(--ak-track-shadow, 0 0 0 0 transparent);
|
|
955
|
+
}
|
|
956
|
+
@media (prefers-reduced-motion: reduce) {
|
|
957
|
+
.ak-control-knob,
|
|
958
|
+
.ak-control-thumb {
|
|
959
|
+
transition: none;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/* ── Themed scrollbar (2026-08-03) ──────────────────────────────────────
|
|
964
|
+
A thin, ALWAYS-VISIBLE scrollbar on the token layer — thumb follows the
|
|
965
|
+
theme (border-strong, text-muted on hover), track transparent. Visible
|
|
966
|
+
at rest on purpose: hidden-until-hover scrollbars fail discoverability.
|
|
967
|
+
Firefox via scrollbar-*, WebKit via the pseudo-elements. */
|
|
968
|
+
.ak-scrollbar {
|
|
969
|
+
scrollbar-width: thin;
|
|
970
|
+
scrollbar-color: var(--color-ak-border-strong) transparent;
|
|
971
|
+
}
|
|
972
|
+
.ak-scrollbar::-webkit-scrollbar {
|
|
973
|
+
width: 8px;
|
|
974
|
+
height: 8px;
|
|
975
|
+
}
|
|
976
|
+
.ak-scrollbar::-webkit-scrollbar-thumb {
|
|
977
|
+
background: var(--color-ak-border-strong);
|
|
978
|
+
border-radius: 9999px;
|
|
979
|
+
}
|
|
980
|
+
.ak-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
981
|
+
background: var(--color-ak-text-muted);
|
|
982
|
+
}
|
|
983
|
+
.ak-scrollbar::-webkit-scrollbar-track {
|
|
984
|
+
background: transparent;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/* ── Quiet-hover bar (2026-08-03) ───────────────────────────────────────
|
|
988
|
+
The hover treatment for quiet controls and text links: a bar under the
|
|
989
|
+
WHOLE control (::after), not text-decoration — underlines don't propagate
|
|
990
|
+
into flex children, so any link with an icon shows a cut-off underline.
|
|
991
|
+
Materials fill the slots (brutal: 3px ink bar offset 4px = the backface's
|
|
992
|
+
bottom edge). Defaults are 0/invisible; a component can opt into a
|
|
993
|
+
default bar via the -default fallback vars (the link button does), which
|
|
994
|
+
materials still override via the primary vars. */
|
|
995
|
+
.ak-quiet-hover {
|
|
996
|
+
position: relative;
|
|
997
|
+
}
|
|
998
|
+
.ak-quiet-hover::after {
|
|
999
|
+
content: "";
|
|
1000
|
+
position: absolute;
|
|
1001
|
+
inset-inline: 0;
|
|
1002
|
+
bottom: calc(-1 * var(--ak-quiet-hover-offset, var(--ak-quiet-hover-offset-default, 0px)));
|
|
1003
|
+
height: var(--ak-quiet-hover-thickness, var(--ak-quiet-hover-thickness-default, 0px));
|
|
1004
|
+
background: var(--ak-quiet-hover-color, currentColor);
|
|
1005
|
+
opacity: 0;
|
|
1006
|
+
transition: opacity 120ms ease;
|
|
1007
|
+
pointer-events: none;
|
|
1008
|
+
}
|
|
1009
|
+
.ak-quiet-hover:hover::after,
|
|
1010
|
+
.ak-quiet-hover:focus-visible::after {
|
|
1011
|
+
opacity: 1;
|
|
1012
|
+
}
|
|
1013
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1014
|
+
.ak-quiet-hover::after {
|
|
1015
|
+
transition: none;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/* ── Overlay motion (core batch 4) ──────────────────────────────────────
|
|
1020
|
+
In/out animations for portalled overlays, driven by Radix data-state.
|
|
1021
|
+
Plain CSS so both Tailwind pipelines get them. Dialogs center with
|
|
1022
|
+
inset-0 + m-auto (NOT translate) so the pop transform never fights
|
|
1023
|
+
positioning; sheets own their transform entirely. */
|
|
1024
|
+
@keyframes ak-overlay-in { from { opacity: 0; } to { opacity: 1; } }
|
|
1025
|
+
@keyframes ak-overlay-out { from { opacity: 1; } to { opacity: 0; } }
|
|
1026
|
+
@keyframes ak-pop-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } }
|
|
1027
|
+
@keyframes ak-pop-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.96); } }
|
|
1028
|
+
@keyframes ak-slide-in-right { from { transform: translateX(100%); } to { transform: translateX(0); } }
|
|
1029
|
+
@keyframes ak-slide-out-right { from { transform: translateX(0); } to { transform: translateX(100%); } }
|
|
1030
|
+
@keyframes ak-slide-in-left { from { transform: translateX(-100%); } to { transform: translateX(0); } }
|
|
1031
|
+
@keyframes ak-slide-out-left { from { transform: translateX(0); } to { transform: translateX(-100%); } }
|
|
1032
|
+
@keyframes ak-slide-in-bottom { from { transform: translateY(100%); } to { transform: translateY(0); } }
|
|
1033
|
+
@keyframes ak-slide-out-bottom { from { transform: translateY(0); } to { transform: translateY(100%); } }
|
|
1034
|
+
@keyframes ak-slide-in-top { from { transform: translateY(-100%); } to { transform: translateY(0); } }
|
|
1035
|
+
@keyframes ak-slide-out-top { from { transform: translateY(0); } to { transform: translateY(-100%); } }
|
|
1036
|
+
.ak-overlay-anim[data-state="open"] { animation: ak-overlay-in 150ms ease; }
|
|
1037
|
+
.ak-overlay-anim[data-state="closed"] { animation: ak-overlay-out 130ms ease forwards; }
|
|
1038
|
+
.ak-pop-anim[data-state="open"],
|
|
1039
|
+
.ak-pop-anim[data-state="delayed-open"] { animation: ak-pop-in 160ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1040
|
+
.ak-pop-anim[data-state="closed"] { animation: ak-pop-out 120ms ease forwards; }
|
|
1041
|
+
.ak-sheet-anim[data-state="open"][data-side="right"] { animation: ak-slide-in-right 260ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1042
|
+
.ak-sheet-anim[data-state="closed"][data-side="right"] { animation: ak-slide-out-right 200ms ease forwards; }
|
|
1043
|
+
.ak-sheet-anim[data-state="open"][data-side="left"] { animation: ak-slide-in-left 260ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1044
|
+
.ak-sheet-anim[data-state="closed"][data-side="left"] { animation: ak-slide-out-left 200ms ease forwards; }
|
|
1045
|
+
.ak-sheet-anim[data-state="open"][data-side="bottom"] { animation: ak-slide-in-bottom 260ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1046
|
+
.ak-sheet-anim[data-state="closed"][data-side="bottom"] { animation: ak-slide-out-bottom 200ms ease forwards; }
|
|
1047
|
+
.ak-sheet-anim[data-state="open"][data-side="top"] { animation: ak-slide-in-top 260ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1048
|
+
.ak-sheet-anim[data-state="closed"][data-side="top"] { animation: ak-slide-out-top 200ms ease forwards; }
|
|
1049
|
+
/* Height-reveal for Radix Accordion/Collapsible content. */
|
|
1050
|
+
@keyframes ak-accordion-down { from { height: 0; } to { height: var(--radix-accordion-content-height); } }
|
|
1051
|
+
@keyframes ak-accordion-up { from { height: var(--radix-accordion-content-height); } to { height: 0; } }
|
|
1052
|
+
@keyframes ak-collapsible-down { from { height: 0; } to { height: var(--radix-collapsible-content-height); } }
|
|
1053
|
+
@keyframes ak-collapsible-up { from { height: var(--radix-collapsible-content-height); } to { height: 0; } }
|
|
1054
|
+
.ak-accordion-anim[data-state="open"] { animation: ak-accordion-down 200ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1055
|
+
.ak-accordion-anim[data-state="closed"] { animation: ak-accordion-up 180ms ease forwards; }
|
|
1056
|
+
.ak-collapsible-anim[data-state="open"] { animation: ak-collapsible-down 200ms cubic-bezier(0.16, 1, 0.3, 1); }
|
|
1057
|
+
.ak-collapsible-anim[data-state="closed"] { animation: ak-collapsible-up 180ms ease forwards; }
|
|
1058
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1059
|
+
.ak-overlay-anim,
|
|
1060
|
+
.ak-pop-anim,
|
|
1061
|
+
.ak-sheet-anim,
|
|
1062
|
+
.ak-accordion-anim,
|
|
1063
|
+
.ak-collapsible-anim {
|
|
1064
|
+
animation-duration: 0.01ms !important;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/* ── Button group (core) ────────────────────────────────────────────────
|
|
1069
|
+
Container-aware styling for attached button groups (the CORE-STANDARD
|
|
1070
|
+
pattern: plain CSS attribute selectors, works in both Tailwind pipelines).
|
|
1071
|
+
Inner corners collapse, outer corners keep the radius tokens, adjacent
|
|
1072
|
+
borders overlap by 1px, and the focused member wins the z-order. */
|
|
1073
|
+
/* Any direct child participates in the corner system — buttons today,
|
|
1074
|
+
inputs/selects/ButtonGroupText when those cores land. Separators opt out. */
|
|
1075
|
+
.ak-button-group {
|
|
1076
|
+
display: inline-flex;
|
|
1077
|
+
align-items: stretch;
|
|
1078
|
+
}
|
|
1079
|
+
.ak-button-group > :focus-visible {
|
|
1080
|
+
z-index: 1;
|
|
1081
|
+
}
|
|
1082
|
+
.ak-button-group[data-ak-orientation="vertical"] {
|
|
1083
|
+
flex-direction: column;
|
|
1084
|
+
}
|
|
1085
|
+
/* Fusing applies only to a leaf group — a group of groups is a toolbar
|
|
1086
|
+
(below) and its sub-groups keep their own corners. */
|
|
1087
|
+
.ak-button-group:not(:has(> .ak-button-group)) > * {
|
|
1088
|
+
position: relative;
|
|
1089
|
+
border-radius: 0;
|
|
1090
|
+
}
|
|
1091
|
+
.ak-button-group[data-ak-orientation="horizontal"]:not(:has(> .ak-button-group)) > * + :not(.ak-button-group-separator) {
|
|
1092
|
+
margin-left: -1px;
|
|
1093
|
+
}
|
|
1094
|
+
.ak-button-group[data-ak-orientation="horizontal"]:not(:has(> .ak-button-group)) > .ak-button-group-separator + * {
|
|
1095
|
+
margin-left: 0;
|
|
1096
|
+
}
|
|
1097
|
+
.ak-button-group[data-ak-orientation="horizontal"]:not(:has(> .ak-button-group)) > :first-child {
|
|
1098
|
+
border-top-left-radius: var(--radius-ak-md);
|
|
1099
|
+
border-bottom-left-radius: var(--radius-ak-md);
|
|
1100
|
+
}
|
|
1101
|
+
.ak-button-group[data-ak-orientation="horizontal"]:not(:has(> .ak-button-group)) > :last-child {
|
|
1102
|
+
border-top-right-radius: var(--radius-ak-md);
|
|
1103
|
+
border-bottom-right-radius: var(--radius-ak-md);
|
|
1104
|
+
}
|
|
1105
|
+
.ak-button-group[data-ak-orientation="vertical"]:not(:has(> .ak-button-group)) > * + :not(.ak-button-group-separator) {
|
|
1106
|
+
margin-top: -1px;
|
|
1107
|
+
}
|
|
1108
|
+
.ak-button-group[data-ak-orientation="vertical"]:not(:has(> .ak-button-group)) > .ak-button-group-separator + * {
|
|
1109
|
+
margin-top: 0;
|
|
1110
|
+
}
|
|
1111
|
+
.ak-button-group[data-ak-orientation="vertical"]:not(:has(> .ak-button-group)) > :first-child {
|
|
1112
|
+
border-top-left-radius: var(--radius-ak-md);
|
|
1113
|
+
border-top-right-radius: var(--radius-ak-md);
|
|
1114
|
+
}
|
|
1115
|
+
.ak-button-group[data-ak-orientation="vertical"]:not(:has(> .ak-button-group)) > :last-child {
|
|
1116
|
+
border-bottom-left-radius: var(--radius-ak-md);
|
|
1117
|
+
border-bottom-right-radius: var(--radius-ak-md);
|
|
1118
|
+
}
|
|
1119
|
+
/* The seam flips with the group's axis. */
|
|
1120
|
+
.ak-button-group[data-ak-orientation="vertical"] > .ak-button-group-separator {
|
|
1121
|
+
width: auto;
|
|
1122
|
+
height: 1px;
|
|
1123
|
+
align-self: stretch;
|
|
1124
|
+
}
|
|
1125
|
+
/* A group of groups is a toolbar: sub-groups space out instead of fusing. */
|
|
1126
|
+
.ak-button-group:has(> .ak-button-group) {
|
|
1127
|
+
gap: var(--spacing-ak-1, 0.5rem);
|
|
1128
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type AppearancePresetId = 'clean' | 'soft-mesh' | 'neon-edge' | 'cinematic-backlight' | 'circuit-spark' | 'portfolio-grain';
|
|
2
|
+
type AppearanceVariableName = `--ak-effect-${string}` | `--gradient-ak-${string}`;
|
|
3
|
+
export interface AppearancePreset {
|
|
4
|
+
id: AppearancePresetId;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
variables: Partial<Record<AppearanceVariableName, string>>;
|
|
8
|
+
}
|
|
9
|
+
export declare const DEFAULT_APPEARANCE_PRESET_ID: AppearancePresetId;
|
|
10
|
+
export declare const APPEARANCE_PRESETS: AppearancePreset[];
|
|
11
|
+
export declare function appearancePresetToVariables(preset: AppearancePreset): Partial<Record<AppearanceVariableName, string>>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export const DEFAULT_APPEARANCE_PRESET_ID = 'clean';
|
|
2
|
+
export const APPEARANCE_PRESETS = [
|
|
3
|
+
{
|
|
4
|
+
id: 'clean',
|
|
5
|
+
name: 'Clean',
|
|
6
|
+
description: 'No ambient atmosphere. Keeps components border-led and quiet.',
|
|
7
|
+
variables: {
|
|
8
|
+
'--ak-effect-mesh-opacity': '0',
|
|
9
|
+
'--ak-effect-grain-opacity': '0',
|
|
10
|
+
'--ak-effect-grid-opacity': '0',
|
|
11
|
+
'--ak-effect-backlight-opacity': '0',
|
|
12
|
+
'--ak-effect-vignette-opacity': '0',
|
|
13
|
+
'--ak-effect-border-opacity': '0.55',
|
|
14
|
+
'--ak-effect-glow-opacity': '0.22',
|
|
15
|
+
'--ak-effect-border-speed': '8s',
|
|
16
|
+
'--ak-effect-spark-size': '34%',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'soft-mesh',
|
|
21
|
+
name: 'Soft Mesh',
|
|
22
|
+
description: 'A calm radial mesh with light grain for premium product surfaces.',
|
|
23
|
+
variables: {
|
|
24
|
+
'--ak-effect-mesh-opacity': '0.18',
|
|
25
|
+
'--ak-effect-grain-opacity': '0.018',
|
|
26
|
+
'--ak-effect-grid-opacity': '0',
|
|
27
|
+
'--ak-effect-backlight-opacity': '0.08',
|
|
28
|
+
'--ak-effect-vignette-opacity': '0.035',
|
|
29
|
+
'--ak-effect-border-opacity': '0.62',
|
|
30
|
+
'--ak-effect-glow-opacity': '0.32',
|
|
31
|
+
'--ak-effect-border-speed': '9s',
|
|
32
|
+
'--ak-effect-spark-size': '32%',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'neon-edge',
|
|
37
|
+
name: 'Neon Edge',
|
|
38
|
+
description: 'Restrained glow and animated edge energy for dark premium demos.',
|
|
39
|
+
variables: {
|
|
40
|
+
'--ak-effect-mesh-opacity': '0.12',
|
|
41
|
+
'--ak-effect-grain-opacity': '0.014',
|
|
42
|
+
'--ak-effect-grid-opacity': '0',
|
|
43
|
+
'--ak-effect-backlight-opacity': '0.14',
|
|
44
|
+
'--ak-effect-vignette-opacity': '0.06',
|
|
45
|
+
'--ak-effect-border-opacity': '0.92',
|
|
46
|
+
'--ak-effect-glow-opacity': '0.44',
|
|
47
|
+
'--ak-effect-border-speed': '6s',
|
|
48
|
+
'--ak-effect-spark-size': '24%',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'cinematic-backlight',
|
|
53
|
+
name: 'Cinematic',
|
|
54
|
+
description: 'Large soft backlights and a faint vignette for hero-style staging.',
|
|
55
|
+
variables: {
|
|
56
|
+
'--ak-effect-mesh-opacity': '0.24',
|
|
57
|
+
'--ak-effect-grain-opacity': '0.022',
|
|
58
|
+
'--ak-effect-grid-opacity': '0',
|
|
59
|
+
'--ak-effect-backlight-opacity': '0.28',
|
|
60
|
+
'--ak-effect-vignette-opacity': '0.12',
|
|
61
|
+
'--ak-effect-border-opacity': '0.7',
|
|
62
|
+
'--ak-effect-glow-opacity': '0.5',
|
|
63
|
+
'--ak-effect-border-speed': '10s',
|
|
64
|
+
'--ak-effect-spark-size': '36%',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'circuit-spark',
|
|
69
|
+
name: 'Circuit Spark',
|
|
70
|
+
description: 'Fine grid texture with faster comet borders for systems UI.',
|
|
71
|
+
variables: {
|
|
72
|
+
'--ak-effect-mesh-opacity': '0.15',
|
|
73
|
+
'--ak-effect-grain-opacity': '0.016',
|
|
74
|
+
'--ak-effect-grid-opacity': '0.12',
|
|
75
|
+
'--ak-effect-backlight-opacity': '0.16',
|
|
76
|
+
'--ak-effect-vignette-opacity': '0.08',
|
|
77
|
+
'--ak-effect-border-opacity': '1',
|
|
78
|
+
'--ak-effect-glow-opacity': '0.48',
|
|
79
|
+
'--ak-effect-border-speed': '4.8s',
|
|
80
|
+
'--ak-effect-spark-size': '18%',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'portfolio-grain',
|
|
85
|
+
name: 'Portfolio Grain',
|
|
86
|
+
description: 'Editorial grain, muted backlight, and quiet texture.',
|
|
87
|
+
variables: {
|
|
88
|
+
'--ak-effect-mesh-opacity': '0.1',
|
|
89
|
+
'--ak-effect-grain-opacity': '0.055',
|
|
90
|
+
'--ak-effect-grid-opacity': '0',
|
|
91
|
+
'--ak-effect-backlight-opacity': '0.07',
|
|
92
|
+
'--ak-effect-vignette-opacity': '0.1',
|
|
93
|
+
'--ak-effect-border-opacity': '0.5',
|
|
94
|
+
'--ak-effect-glow-opacity': '0.28',
|
|
95
|
+
'--ak-effect-border-speed': '12s',
|
|
96
|
+
'--ak-effect-spark-size': '40%',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
export function appearancePresetToVariables(preset) {
|
|
101
|
+
return preset.variables;
|
|
102
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated chart palettes — authored 6-color series sets driving the SDK's
|
|
3
|
+
* --color-ak-chart-1..6 slots at runtime. The default (Signal) is the SDK's
|
|
4
|
+
* Tableau-derived colorblind-safe set; the others are authored alternatives,
|
|
5
|
+
* sequenced so adjacent series stay distinguishable. Independent of the UI
|
|
6
|
+
* palette on purpose (the shadcn insight worth keeping: chart hues are a
|
|
7
|
+
* separate design decision from brand hues).
|
|
8
|
+
*/
|
|
9
|
+
export type ChartPaletteId = 'signal' | 'oceanic' | 'ember' | 'prism' | 'ink';
|
|
10
|
+
type ChartVariableName = `--color-ak-chart-${1 | 2 | 3 | 4 | 5 | 6}`;
|
|
11
|
+
export interface ChartPalette {
|
|
12
|
+
id: ChartPaletteId;
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
variables: Record<ChartVariableName, string>;
|
|
16
|
+
darkVariables?: Record<ChartVariableName, string>;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_CHART_PALETTE_ID: ChartPaletteId;
|
|
19
|
+
export declare const CHART_PALETTES: ChartPalette[];
|
|
20
|
+
export declare function chartPaletteToVariables(palette: ChartPalette, opts?: { mode?: 'light' | 'dark' }): Record<string, string>;
|
|
21
|
+
export type RadiusOptionId = 'none' | 'small' | 'default' | 'large' | 'xl';
|
|
22
|
+
export interface RadiusOption {
|
|
23
|
+
id: RadiusOptionId;
|
|
24
|
+
name: string;
|
|
25
|
+
value: string;
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_RADIUS_OPTION_ID: RadiusOptionId;
|
|
28
|
+
export declare const RADIUS_OPTIONS: RadiusOption[];
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated chart palettes — authored 6-color series sets driving the SDK's
|
|
3
|
+
* --color-ak-chart-1..6 slots at runtime. The default (Signal) is the SDK's
|
|
4
|
+
* Tableau-derived colorblind-safe set; the others are authored alternatives,
|
|
5
|
+
* sequenced so adjacent series stay distinguishable. Independent of the UI
|
|
6
|
+
* palette on purpose (the shadcn insight worth keeping: chart hues are a
|
|
7
|
+
* separate design decision from brand hues).
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_CHART_PALETTE_ID = 'signal';
|
|
10
|
+
export const CHART_PALETTES = [
|
|
11
|
+
{
|
|
12
|
+
id: 'signal',
|
|
13
|
+
name: 'Default',
|
|
14
|
+
description: 'The SDK default — Tableau-derived, colorblind-safe.',
|
|
15
|
+
variables: {
|
|
16
|
+
'--color-ak-chart-1': '#4e79a7',
|
|
17
|
+
'--color-ak-chart-2': '#f28e2c',
|
|
18
|
+
'--color-ak-chart-3': '#e15759',
|
|
19
|
+
'--color-ak-chart-4': '#76b7b2',
|
|
20
|
+
'--color-ak-chart-5': '#59a14f',
|
|
21
|
+
'--color-ak-chart-6': '#edc949',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'oceanic',
|
|
26
|
+
name: 'Blues',
|
|
27
|
+
description: 'Blues and teals — calm, financial, product dashboards.',
|
|
28
|
+
variables: {
|
|
29
|
+
'--color-ak-chart-1': '#2563eb',
|
|
30
|
+
'--color-ak-chart-2': '#0891b2',
|
|
31
|
+
'--color-ak-chart-3': '#14b8a6',
|
|
32
|
+
'--color-ak-chart-4': '#6366f1',
|
|
33
|
+
'--color-ak-chart-5': '#0ea5e9',
|
|
34
|
+
'--color-ak-chart-6': '#1e40af',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'ember',
|
|
39
|
+
name: 'Warm',
|
|
40
|
+
description: 'Warm ambers and reds — energy, alerts, intensity scales.',
|
|
41
|
+
variables: {
|
|
42
|
+
'--color-ak-chart-1': '#dc2626',
|
|
43
|
+
'--color-ak-chart-2': '#f59e0b',
|
|
44
|
+
'--color-ak-chart-3': '#ea580c',
|
|
45
|
+
'--color-ak-chart-4': '#eab308',
|
|
46
|
+
'--color-ak-chart-5': '#9a3412',
|
|
47
|
+
'--color-ak-chart-6': '#fbbf24',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'prism',
|
|
52
|
+
name: 'Vivid',
|
|
53
|
+
description: 'Saturated multi-hue — marketing analytics, category splits.',
|
|
54
|
+
variables: {
|
|
55
|
+
'--color-ak-chart-1': '#8b5cf6',
|
|
56
|
+
'--color-ak-chart-2': '#ec4899',
|
|
57
|
+
'--color-ak-chart-3': '#06b6d4',
|
|
58
|
+
'--color-ak-chart-4': '#22c55e',
|
|
59
|
+
'--color-ak-chart-5': '#f59e0b',
|
|
60
|
+
'--color-ak-chart-6': '#6366f1',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'ink',
|
|
65
|
+
name: 'Mono',
|
|
66
|
+
description: 'Grayscale ramp — editorial, print-adjacent, monochrome brands.',
|
|
67
|
+
variables: {
|
|
68
|
+
'--color-ak-chart-1': '#171717',
|
|
69
|
+
'--color-ak-chart-2': '#737373',
|
|
70
|
+
'--color-ak-chart-3': '#a3a3a3',
|
|
71
|
+
'--color-ak-chart-4': '#404040',
|
|
72
|
+
'--color-ak-chart-5': '#d4d4d4',
|
|
73
|
+
'--color-ak-chart-6': '#525252',
|
|
74
|
+
},
|
|
75
|
+
// Grayscale must INVERT in dark mode or the ramp disappears into the bg.
|
|
76
|
+
darkVariables: {
|
|
77
|
+
'--color-ak-chart-1': '#e5e5e5',
|
|
78
|
+
'--color-ak-chart-2': '#8a8a8a',
|
|
79
|
+
'--color-ak-chart-3': '#525252',
|
|
80
|
+
'--color-ak-chart-4': '#bdbdbd',
|
|
81
|
+
'--color-ak-chart-5': '#404040',
|
|
82
|
+
'--color-ak-chart-6': '#a3a3a3',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
export function chartPaletteToVariables(palette, opts) {
|
|
87
|
+
const mode = (opts && opts.mode) || 'light';
|
|
88
|
+
if (mode === 'dark' && palette.darkVariables)
|
|
89
|
+
return { ...palette.darkVariables };
|
|
90
|
+
return { ...palette.variables };
|
|
91
|
+
}
|
|
92
|
+
export const DEFAULT_RADIUS_OPTION_ID = 'default';
|
|
93
|
+
export const RADIUS_OPTIONS = [
|
|
94
|
+
{ id: 'none', name: 'Square', value: '0rem' },
|
|
95
|
+
{ id: 'small', name: 'Small', value: '0.25rem' },
|
|
96
|
+
{ id: 'default', name: 'Default', value: '0.5rem' },
|
|
97
|
+
{ id: 'large', name: 'Large', value: '0.875rem' },
|
|
98
|
+
{ id: 'xl', name: 'Extra Round', value: '9999rem' },
|
|
99
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface DialPreset<Id extends string = string> {
|
|
2
|
+
id: Id
|
|
3
|
+
name: string
|
|
4
|
+
description: string
|
|
5
|
+
variables: Record<string, string>
|
|
6
|
+
darkVariables?: Record<string, string>
|
|
7
|
+
swatch?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DialModeOptions {
|
|
11
|
+
mode?: 'light' | 'dark'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type BaseColorId = 'neutral' | 'stone' | 'zinc' | 'mauve' | 'olive' | 'mist' | 'taupe'
|
|
15
|
+
export declare const DEFAULT_BASE_COLOR_ID: BaseColorId
|
|
16
|
+
export declare const BASE_COLORS: DialPreset<BaseColorId>[]
|
|
17
|
+
export declare function baseColorToVariables(base: DialPreset<BaseColorId>, opts?: DialModeOptions): Record<string, string>
|
|
18
|
+
|
|
19
|
+
export type AccentThemeId =
|
|
20
|
+
| 'default' | 'blue' | 'indigo' | 'violet' | 'purple' | 'pink' | 'rose'
|
|
21
|
+
| 'red' | 'orange' | 'amber' | 'emerald' | 'teal' | 'cyan'
|
|
22
|
+
export declare const DEFAULT_ACCENT_THEME_ID: AccentThemeId
|
|
23
|
+
export declare const ACCENT_THEMES: DialPreset<AccentThemeId>[]
|
|
24
|
+
export declare function accentThemeToVariables(theme: DialPreset<AccentThemeId>, opts?: DialModeOptions): Record<string, string>
|
|
25
|
+
|
|
26
|
+
export declare function radiusToVariables(value: number | string): Record<string, string>
|
|
27
|
+
export type TypeScaleId = 'default' | 'major-third' | 'perfect-fourth' | 'augmented-fourth' | 'perfect-fifth' | 'golden'
|
|
28
|
+
export declare const DEFAULT_TYPE_SCALE_ID: TypeScaleId
|
|
29
|
+
export declare const TYPE_SCALES: DialPreset<TypeScaleId>[]
|
|
30
|
+
export declare function typeScaleToVariables(scale: DialPreset<TypeScaleId>): Record<string, string>
|
|
31
|
+
|