@oleksandr-94/aura-css 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +593 -0
  3. package/dist/aura-flat.css +1611 -0
  4. package/dist/aura-flat.min.css +1 -0
  5. package/dist/aura-neu.css +1622 -0
  6. package/dist/aura-neu.min.css +1 -0
  7. package/dist/aura.css +1634 -0
  8. package/dist/aura.min.css +1 -0
  9. package/dist/interactions.d.ts +57 -0
  10. package/dist/interactions.global.min.js +1 -0
  11. package/dist/interactions.min.mjs +1 -0
  12. package/dist/interactions.mjs +208 -0
  13. package/package.json +72 -0
  14. package/src/_config.scss +72 -0
  15. package/src/_functions.scss +23 -0
  16. package/src/_layers.scss +4 -0
  17. package/src/_surface.scss +49 -0
  18. package/src/_tokens.scss +65 -0
  19. package/src/base/_a11y.scss +31 -0
  20. package/src/base/_reset.scss +7 -0
  21. package/src/components/_accordion.scss +62 -0
  22. package/src/components/_alert.scss +43 -0
  23. package/src/components/_avatar.scss +50 -0
  24. package/src/components/_badge.scss +61 -0
  25. package/src/components/_button.scss +79 -0
  26. package/src/components/_card.scss +58 -0
  27. package/src/components/_checkbox.scss +51 -0
  28. package/src/components/_dropdown.scss +73 -0
  29. package/src/components/_file.scss +42 -0
  30. package/src/components/_group.scss +51 -0
  31. package/src/components/_input.scss +85 -0
  32. package/src/components/_modal.scss +43 -0
  33. package/src/components/_pagination.scss +87 -0
  34. package/src/components/_progress.scss +44 -0
  35. package/src/components/_radio.scss +42 -0
  36. package/src/components/_range.scss +27 -0
  37. package/src/components/_rating.scss +43 -0
  38. package/src/components/_segmented.scss +60 -0
  39. package/src/components/_switch.scss +79 -0
  40. package/src/components/_table.scss +38 -0
  41. package/src/components/_tabs.scss +150 -0
  42. package/src/components/_toast.scss +59 -0
  43. package/src/components/_tooltip.scss +60 -0
  44. package/src/index.scss +32 -0
  45. package/src/js/global.js +7 -0
  46. package/src/js/interactions.auto.js +5 -0
  47. package/src/js/interactions.js +192 -0
  48. package/src/skins/_flat.scss +29 -0
  49. package/src/skins/_glass.scss +40 -0
  50. package/src/skins/_neu.scss +49 -0
@@ -0,0 +1,65 @@
1
+ // ============================================================
2
+ // Aura — tokens
3
+ // Emits static scales + generates every theme from config.
4
+ // Components must only ever reference these CSS variables.
5
+ // ============================================================
6
+ @use "sass:map";
7
+ @use "./config" as cfg;
8
+ @use "./functions" as fn;
9
+
10
+ // ---- Static, theme-independent scales ----
11
+ :root {
12
+ // radius
13
+ --radius-sm: 6px;
14
+ --radius-md: 8px;
15
+ --radius-lg: 12px;
16
+ --radius-pill: 999px;
17
+ // spacing (4pt)
18
+ --space-1: 4px; --space-2: 8px; --space-3: 12px;
19
+ --space-4: 16px; --space-6: 24px; --space-8: 32px;
20
+ // type
21
+ --font: "Plus Jakarta Sans", system-ui, sans-serif;
22
+ --fs-xs: 12px; --fs-sm: 13px; --fs-md: 14px; --fs-lg: 16px; --fs-xl: 20px;
23
+ // surface effects
24
+ --blur: 20px;
25
+ // general brand gradient (auto-adapts to each theme's accents).
26
+ // Per-colour button gradients are derived inline from the button's own colour.
27
+ --gradient: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
28
+ --gradient-tint: #ffd23f; // warm highlight mixed into the light end of button gradients
29
+ // z-index scale
30
+ --z-dropdown: 1000;
31
+ --z-sticky: 1020;
32
+ --z-modal: 1050;
33
+ --z-toast: 1080;
34
+ }
35
+
36
+ // ---- Per-theme colour roles ----
37
+ @mixin emit-theme($c) {
38
+ // accents + status: derive on-* (content) and *-container automatically
39
+ @each $role in (primary, secondary, accent, success, warning, error, info) {
40
+ $val: map.get($c, $role);
41
+ @if $val {
42
+ --#{$role}: #{$val};
43
+ --on-#{$role}: #{fn.on-color($val)};
44
+ // subtle tinted fill for badges/alerts + its content colour
45
+ --#{$role}-container: color-mix(in srgb, #{$val} 16%, transparent);
46
+ --on-#{$role}-container: #{$val};
47
+ }
48
+ }
49
+ // surfaces + lines + elevation (provided explicitly)
50
+ @each $role in (surface, surface-1, surface-2, on-surface, on-surface-muted,
51
+ outline, outline-strong, glass-film, glass-film-2,
52
+ tip-bg, tip-text, shadow-1, shadow-2) {
53
+ $val: map.get($c, $role);
54
+ @if $val { --#{$role}: #{$val}; }
55
+ }
56
+ }
57
+
58
+ @each $name, $colors in cfg.$themes {
59
+ @if $name == cfg.$default-theme {
60
+ :root,
61
+ [data-theme="#{$name}"] { @include emit-theme($colors); }
62
+ } @else {
63
+ [data-theme="#{$name}"] { @include emit-theme($colors); }
64
+ }
65
+ }
@@ -0,0 +1,31 @@
1
+ // ============================================================
2
+ // Aura — accessibility base
3
+ // In the last cascade layer so it overrides Aura's own component
4
+ // motion, but stays below the host app's unlayered styles (we never
5
+ // clobber the host's animations).
6
+ // ============================================================
7
+ @use "../config" as cfg;
8
+ $p: cfg.$prefix;
9
+
10
+ @layer a11y {
11
+ // Respect the user's reduced-motion preference for Aura components.
12
+ @media (prefers-reduced-motion: reduce) {
13
+ *, *::before, *::after {
14
+ animation-duration: 1ms;
15
+ animation-iteration-count: 1;
16
+ transition-duration: 1ms;
17
+ scroll-behavior: auto;
18
+ }
19
+ }
20
+
21
+ // Screen-reader-only helper (visually hidden, still announced).
22
+ .#{$p}sr-only {
23
+ position: absolute !important;
24
+ width: 1px; height: 1px;
25
+ padding: 0; margin: -1px;
26
+ overflow: hidden;
27
+ clip: rect(0, 0, 0, 0);
28
+ white-space: nowrap;
29
+ border: 0;
30
+ }
31
+ }
@@ -0,0 +1,7 @@
1
+ // ============================================================
2
+ // Aura — minimal, non-destructive reset (scoped to a layer so a
3
+ // host app's styles always win over it).
4
+ // ============================================================
5
+ @layer base {
6
+ *, *::before, *::after { box-sizing: border-box; }
7
+ }
@@ -0,0 +1,62 @@
1
+ // ============================================================
2
+ // Aura — Accordion
3
+ // Built on native <details>/<summary> — zero JS, accessible,
4
+ // keyboard-friendly. Frameworks bind the `open` attribute.
5
+ // ============================================================
6
+ @use "../config" as cfg;
7
+ @use "../surface" as s;
8
+ $p: cfg.$prefix;
9
+
10
+ @layer components {
11
+ .#{$p}accordion {
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 8px;
15
+ }
16
+
17
+ .#{$p}accordion__item {
18
+ border-radius: var(--radius-md);
19
+ overflow: hidden;
20
+ @include s.surface(1);
21
+ }
22
+
23
+ .#{$p}accordion__head {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: space-between;
27
+ gap: 12px;
28
+ padding: 14px 16px;
29
+ font-weight: 700;
30
+ font-size: var(--fs-md);
31
+ cursor: pointer;
32
+ list-style: none;
33
+ user-select: none;
34
+
35
+ &::-webkit-details-marker { display: none; }
36
+ // CSS chevron (crisp, scales with border-width)
37
+ &::after {
38
+ content: "";
39
+ flex: none;
40
+ width: 9px;
41
+ height: 9px;
42
+ margin-inline-start: 8px;
43
+ border-right: 2px solid var(--on-surface-muted);
44
+ border-bottom: 2px solid var(--on-surface-muted);
45
+ border-bottom-right-radius: 2px;
46
+ transform: translateY(-2px) rotate(45deg);
47
+ transition: transform .2s ease;
48
+ }
49
+ &:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
50
+ }
51
+
52
+ .#{$p}accordion__item[open] > .#{$p}accordion__head::after {
53
+ transform: translateY(2px) rotate(-135deg);
54
+ }
55
+
56
+ .#{$p}accordion__body {
57
+ padding: 0 16px 16px;
58
+ color: var(--on-surface-muted);
59
+ font-size: var(--fs-sm);
60
+ line-height: 1.5;
61
+ }
62
+ }
@@ -0,0 +1,43 @@
1
+ // ============================================================
2
+ // Aura — Alert
3
+ // Message panel with an accent bar + icon. The accent colour lives
4
+ // in --_c so variants are one line. Colour tint is constant; the
5
+ // skin only adds surface feel via chip().
6
+ // ============================================================
7
+ @use "../config" as cfg;
8
+ @use "../surface" as s;
9
+ $p: cfg.$prefix;
10
+
11
+ @layer components {
12
+ .#{$p}alert {
13
+ --_c: var(--primary);
14
+
15
+ display: flex;
16
+ align-items: flex-start;
17
+ gap: 12px;
18
+ padding: 14px 16px;
19
+ border-radius: var(--radius-md);
20
+ background: color-mix(in srgb, var(--_c) 13%, var(--surface-1));
21
+ color: var(--on-surface);
22
+ border: 1px solid var(--outline);
23
+ border-left: 3px solid var(--_c);
24
+ font-size: var(--fs-md);
25
+
26
+ @include s.chip; // glass gloss / neu extrusion / flat
27
+
28
+ // ---- colour variants ----
29
+ &.#{$p}alert--success { --_c: var(--success); }
30
+ &.#{$p}alert--warning { --_c: var(--warning); }
31
+ &.#{$p}alert--error { --_c: var(--error); }
32
+ &.#{$p}alert--info { --_c: var(--info); }
33
+ }
34
+
35
+ .#{$p}alert__icon {
36
+ color: var(--_c);
37
+ font-size: 18px;
38
+ line-height: 1.35;
39
+ flex: none;
40
+ }
41
+ .#{$p}alert__title { font-weight: 700; }
42
+ .#{$p}alert__body { color: var(--on-surface-muted); font-size: var(--fs-sm); margin-top: 2px; }
43
+ }
@@ -0,0 +1,50 @@
1
+ // ============================================================
2
+ // Aura — Avatar (+ group, + status dot)
3
+ // ============================================================
4
+ @use "../config" as cfg;
5
+ $p: cfg.$prefix;
6
+
7
+ @layer components {
8
+ .#{$p}avatar {
9
+ position: relative;
10
+ display: inline-grid;
11
+ place-items: center;
12
+ width: 40px;
13
+ height: 40px;
14
+ flex: none;
15
+ border-radius: 50%;
16
+ overflow: hidden;
17
+ font-weight: 700;
18
+ font-size: var(--fs-md);
19
+ color: var(--on-surface);
20
+ background: color-mix(in srgb, var(--primary) 22%, var(--surface-2));
21
+ border: 2px solid var(--surface-1);
22
+ }
23
+ .#{$p}avatar img {
24
+ width: 100%;
25
+ height: 100%;
26
+ object-fit: cover;
27
+ border-radius: inherit;
28
+ }
29
+ .#{$p}avatar--sm { width: 30px; height: 30px; font-size: var(--fs-xs); }
30
+ .#{$p}avatar--lg { width: 56px; height: 56px; font-size: var(--fs-xl); }
31
+ .#{$p}avatar--square { border-radius: var(--radius-md); }
32
+
33
+ // ---- status dot ----
34
+ .#{$p}avatar__status {
35
+ position: absolute;
36
+ right: 0;
37
+ bottom: 0;
38
+ width: 11px;
39
+ height: 11px;
40
+ border-radius: 50%;
41
+ background: var(--on-surface-muted);
42
+ border: 2px solid var(--surface-1);
43
+ }
44
+ .#{$p}avatar__status--online { background: var(--success); }
45
+ .#{$p}avatar__status--busy { background: var(--error); }
46
+
47
+ // ---- overlapping group ----
48
+ .#{$p}avatar-group { display: inline-flex; }
49
+ .#{$p}avatar-group .#{$p}avatar:not(:first-child) { margin-left: -12px; }
50
+ }
@@ -0,0 +1,61 @@
1
+ // ============================================================
2
+ // Aura — Badge
3
+ // Small status / label pill. Colour variants use the *-container
4
+ // tokens (soft tint + readable content colour), so contrast is
5
+ // guaranteed. The colour tint is constant; the active skin only adds
6
+ // surface feel via chip() (flat / glass gloss / neu extrusion).
7
+ // ============================================================
8
+ @use "../config" as cfg;
9
+ @use "../surface" as s;
10
+ $p: cfg.$prefix;
11
+
12
+ @layer components {
13
+ .#{$p}badge {
14
+ --_bg: color-mix(in srgb, var(--on-surface) 10%, transparent);
15
+ --_fg: var(--on-surface);
16
+
17
+ display: inline-flex;
18
+ align-items: center;
19
+ gap: 6px;
20
+ padding: 3px 10px;
21
+ font-size: var(--fs-xs);
22
+ font-weight: 700;
23
+ line-height: 1.5;
24
+ white-space: nowrap;
25
+ border-radius: var(--radius-pill);
26
+ border: 1px solid transparent;
27
+ background: var(--_bg);
28
+ color: var(--_fg);
29
+
30
+ @include s.chip; // skin feel (glass gloss / neu extrusion)
31
+
32
+ // ---- colour variants (soft) ----
33
+ &.#{$p}badge--primary { --_bg: var(--primary-container); --_fg: var(--on-primary-container); }
34
+ &.#{$p}badge--secondary { --_bg: var(--secondary-container); --_fg: var(--on-secondary-container); }
35
+ &.#{$p}badge--accent { --_bg: var(--accent-container); --_fg: var(--on-accent-container); }
36
+ &.#{$p}badge--success { --_bg: var(--success-container); --_fg: var(--on-success-container); }
37
+ &.#{$p}badge--warning { --_bg: var(--warning-container); --_fg: var(--on-warning-container); }
38
+ &.#{$p}badge--error { --_bg: var(--error-container); --_fg: var(--on-error-container); }
39
+ &.#{$p}badge--info { --_bg: var(--info-container); --_fg: var(--on-info-container); }
40
+
41
+ // ---- style variant ----
42
+ &.#{$p}badge--outline {
43
+ background: transparent;
44
+ border-color: color-mix(in srgb, var(--_fg) 45%, transparent);
45
+ box-shadow: none;
46
+ }
47
+
48
+ // ---- sizes ----
49
+ &.#{$p}badge--sm { padding: 2px 8px; font-size: 11px; }
50
+ &.#{$p}badge--lg { padding: 5px 13px; font-size: var(--fs-sm); }
51
+ }
52
+
53
+ // Optional leading status dot: <span class="badge badge--success"><i class="badge__dot"></i> Active</span>
54
+ .#{$p}badge__dot {
55
+ width: 7px;
56
+ height: 7px;
57
+ border-radius: 50%;
58
+ background: currentColor;
59
+ flex: none;
60
+ }
61
+ }
@@ -0,0 +1,79 @@
1
+ // ============================================================
2
+ // Aura — Button
3
+ // Colour comes from --_bg / --_fg locals (one-line variants).
4
+ // Chrome (fill / shadow / press) comes from the active skin via
5
+ // control() — so buttons are glassy / flat / neumorphic to match.
6
+ // ============================================================
7
+ @use "../config" as cfg;
8
+ @use "../surface" as s;
9
+ $p: cfg.$prefix;
10
+
11
+ @layer components {
12
+ .#{$p}btn {
13
+ --_c: var(--primary); // semantic colour (drives fill + gradient + outline)
14
+ --_bg: var(--_c); // solid fill by default
15
+ --_fg: var(--on-primary);
16
+
17
+ display: inline-flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ gap: var(--space-2);
21
+ font: inherit;
22
+ font-weight: 700;
23
+ font-size: var(--fs-md);
24
+ line-height: 1;
25
+ padding: 10px 18px;
26
+ border-radius: var(--radius-md);
27
+ cursor: pointer;
28
+ transition: filter .15s ease, transform .05s ease, box-shadow .15s ease;
29
+
30
+ @include s.control; // skin-aware fill / shadow
31
+
32
+ &:hover { filter: brightness(1.06); }
33
+ &:active { @include s.control-active; }
34
+ &:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
35
+ &:disabled,
36
+ &.#{$p}btn--disabled { opacity: .5; cursor: not-allowed; filter: none; }
37
+
38
+ // ---- colour variants ----
39
+ &.#{$p}btn--secondary { --_c: var(--secondary); --_fg: var(--on-secondary); }
40
+ &.#{$p}btn--accent { --_c: var(--accent); --_fg: var(--on-accent); }
41
+ &.#{$p}btn--success { --_c: var(--success); --_fg: var(--on-success); }
42
+ &.#{$p}btn--warning { --_c: var(--warning); --_fg: var(--on-warning); }
43
+ &.#{$p}btn--error { --_c: var(--error); --_fg: var(--on-error); }
44
+ &.#{$p}btn--info { --_c: var(--info); --_fg: var(--on-info); }
45
+
46
+ // gradient fill — derived from the current colour (--_c). Combine with any
47
+ // colour modifier: .btn--gradient.btn--success, .btn--gradient.btn--error, …
48
+ &.#{$p}btn--gradient {
49
+ --_bg: linear-gradient(135deg,
50
+ color-mix(in srgb, var(--_c) 62%, var(--gradient-tint)) 0%,
51
+ var(--_c) 48%,
52
+ color-mix(in srgb, var(--_c) 84%, #000) 100%);
53
+ --_shadow-color: var(--_c);
54
+ }
55
+
56
+ // ---- style variants (skin chrome removed) ----
57
+ &.#{$p}btn--ghost {
58
+ background: transparent;
59
+ color: var(--on-surface);
60
+ border: 1px solid var(--outline-strong);
61
+ box-shadow: none;
62
+ &:hover { background: color-mix(in srgb, var(--on-surface) 8%, transparent); filter: none; }
63
+ &:active { box-shadow: none; transform: translateY(1px); }
64
+ }
65
+ &.#{$p}btn--outline {
66
+ background: transparent;
67
+ color: var(--_c);
68
+ border: 1px solid var(--_c);
69
+ box-shadow: none;
70
+ &:hover { background: color-mix(in srgb, var(--_c) 12%, transparent); filter: none; }
71
+ &:active { box-shadow: none; transform: translateY(1px); }
72
+ }
73
+
74
+ // ---- sizes ----
75
+ &.#{$p}btn--sm { padding: 7px 12px; font-size: var(--fs-sm); border-radius: var(--radius-sm); }
76
+ &.#{$p}btn--lg { padding: 13px 22px; font-size: var(--fs-lg); }
77
+ &.#{$p}btn--block { display: flex; width: 100%; }
78
+ }
79
+ }
@@ -0,0 +1,58 @@
1
+ // ============================================================
2
+ // Aura — Card
3
+ // Surface container rendered through the active skin. Optional
4
+ // status accent (coloured left bar) and gradient fill, both driven
5
+ // by --_c so they follow the colour and stay themeable.
6
+ // ============================================================
7
+ @use "../config" as cfg;
8
+ @use "../surface" as s;
9
+ $p: cfg.$prefix;
10
+
11
+ @layer components {
12
+ .#{$p}card {
13
+ --_c: var(--primary);
14
+ @include s.surface(1);
15
+ border-radius: var(--radius-lg);
16
+ padding: var(--space-6);
17
+ color: var(--on-surface);
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--space-4);
21
+ }
22
+
23
+ .#{$p}card__header {
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: space-between;
27
+ gap: var(--space-3);
28
+ }
29
+ .#{$p}card__title { margin: 0; font-size: var(--fs-xl); font-weight: 800; }
30
+ .#{$p}card__body { margin: 0; color: var(--on-surface-muted); font-size: var(--fs-md); line-height: 1.5; }
31
+ .#{$p}card__actions { display: flex; gap: var(--space-2); margin-top: auto; }
32
+
33
+ // ---- status accent (coloured left bar) ----
34
+ .#{$p}card--primary { --_c: var(--primary); }
35
+ .#{$p}card--success { --_c: var(--success); }
36
+ .#{$p}card--warning { --_c: var(--warning); }
37
+ .#{$p}card--error { --_c: var(--error); }
38
+ .#{$p}card--info { --_c: var(--info); }
39
+ .#{$p}card--primary,
40
+ .#{$p}card--success,
41
+ .#{$p}card--warning,
42
+ .#{$p}card--error,
43
+ .#{$p}card--info {
44
+ border-inline-start: 3px solid var(--_c);
45
+ }
46
+
47
+ // ---- gradient fill (follows --_c; combine with a colour modifier) ----
48
+ .#{$p}card--gradient {
49
+ background: linear-gradient(135deg,
50
+ color-mix(in srgb, var(--_c) 62%, var(--gradient-tint)) 0%,
51
+ var(--_c) 48%,
52
+ color-mix(in srgb, var(--_c) 84%, #000) 100%);
53
+ border: none;
54
+ color: #fff;
55
+
56
+ .#{$p}card__body { color: rgba(255, 255, 255, .82); }
57
+ }
58
+ }
@@ -0,0 +1,51 @@
1
+ // ============================================================
2
+ // Aura — Checkbox
3
+ // Custom control (appearance:none). Box is a skin-aware well via
4
+ // field(); checked/indeterminate fill with --_c + white mark.
5
+ // ============================================================
6
+ @use "../config" as cfg;
7
+ @use "../surface" as s;
8
+ $p: cfg.$prefix;
9
+
10
+ @layer components {
11
+ .#{$p}checkbox {
12
+ --_c: var(--primary);
13
+ appearance: none;
14
+ -webkit-appearance: none;
15
+ margin: 0;
16
+ flex: none;
17
+ width: 18px;
18
+ height: 18px;
19
+ border-radius: var(--radius-sm);
20
+ cursor: pointer;
21
+ position: relative;
22
+ vertical-align: middle;
23
+ transition: background .15s ease, border-color .15s ease;
24
+ @include s.field;
25
+
26
+ &:checked,
27
+ &:indeterminate { --_bg: var(--_c); --_fg: #fff; @include s.control; }
28
+
29
+ &:checked::after {
30
+ content: "";
31
+ position: absolute;
32
+ left: 50%; top: 50%;
33
+ width: 5px; height: 9px;
34
+ border: solid #fff; border-width: 0 2px 2px 0;
35
+ transform: translate(-50%, -58%) rotate(45deg);
36
+ }
37
+ &:indeterminate::after {
38
+ content: "";
39
+ position: absolute;
40
+ left: 3px; right: 3px; top: calc(50% - 1px);
41
+ height: 2px; background: #fff; border-radius: 1px;
42
+ }
43
+
44
+ &:focus-visible { outline: 2px solid var(--_c); outline-offset: 2px; }
45
+ &:disabled { opacity: .5; cursor: not-allowed; }
46
+
47
+ &.#{$p}checkbox--success { --_c: var(--success); }
48
+ &.#{$p}checkbox--warning { --_c: var(--warning); }
49
+ &.#{$p}checkbox--error { --_c: var(--error); }
50
+ }
51
+ }
@@ -0,0 +1,73 @@
1
+ // ============================================================
2
+ // Aura — Dropdown
3
+ // Driven by [data-state] on the .dropdown root. A trigger with
4
+ // data-toggle flips it; the JS handles outside-click + Esc + aria.
5
+ // The menu is a skin-aware elevated surface.
6
+ // ============================================================
7
+ @use "../config" as cfg;
8
+ @use "../surface" as s;
9
+ $p: cfg.$prefix;
10
+
11
+ @layer components {
12
+ .#{$p}dropdown {
13
+ position: relative;
14
+ display: inline-block;
15
+ }
16
+
17
+ .#{$p}dropdown__menu {
18
+ position: absolute;
19
+ top: calc(100% + 6px);
20
+ left: 0;
21
+ z-index: var(--z-dropdown);
22
+ min-width: 180px;
23
+ padding: 6px;
24
+ border-radius: var(--radius-md);
25
+ @include s.surface(2);
26
+ opacity: 0;
27
+ visibility: hidden;
28
+ transform: translateY(-4px);
29
+ transition: opacity .15s ease, transform .15s ease, visibility .15s ease;
30
+ }
31
+ .#{$p}dropdown__menu--end { left: auto; right: 0; }
32
+
33
+ .#{$p}dropdown[data-state="open"] .#{$p}dropdown__menu {
34
+ opacity: 1;
35
+ visibility: visible;
36
+ transform: none;
37
+ }
38
+
39
+ .#{$p}dropdown__item {
40
+ display: block;
41
+ width: 100%;
42
+ text-align: left;
43
+ padding: 9px 12px;
44
+ border: none;
45
+ border-radius: var(--radius-sm);
46
+ background: none;
47
+ color: var(--on-surface);
48
+ font: inherit;
49
+ font-size: var(--fs-sm);
50
+ font-weight: 600;
51
+ text-decoration: none;
52
+ cursor: pointer;
53
+
54
+ &:hover { background: color-mix(in srgb, var(--on-surface) 8%, transparent); }
55
+ }
56
+ .#{$p}dropdown__divider { height: 1px; margin: 6px 4px; background: var(--outline); }
57
+
58
+ // CSS caret for the trigger — rotates when the dropdown is open
59
+ .#{$p}dropdown__caret {
60
+ display: inline-block;
61
+ width: 8px;
62
+ height: 8px;
63
+ margin-inline-start: 6px;
64
+ border-right: 2px solid currentColor;
65
+ border-bottom: 2px solid currentColor;
66
+ border-bottom-right-radius: 2px;
67
+ transform: translateY(-2px) rotate(45deg);
68
+ transition: transform .2s ease;
69
+ }
70
+ .#{$p}dropdown[data-state="open"] .#{$p}dropdown__caret {
71
+ transform: translateY(1px) rotate(-135deg);
72
+ }
73
+ }
@@ -0,0 +1,42 @@
1
+ // ============================================================
2
+ // Aura — File input
3
+ // Styles the native ::file-selector-button as an Aura button; the
4
+ // filename text is muted. Colour follows --_c.
5
+ // ============================================================
6
+ @use "../config" as cfg;
7
+ $p: cfg.$prefix;
8
+
9
+ @layer components {
10
+ .#{$p}file {
11
+ --_c: var(--primary);
12
+ max-width: 100%;
13
+ font: inherit;
14
+ font-size: var(--fs-sm);
15
+ color: var(--on-surface-muted);
16
+ cursor: pointer;
17
+
18
+ &::file-selector-button {
19
+ font: inherit;
20
+ font-weight: 700;
21
+ font-size: var(--fs-sm);
22
+ margin-inline-end: 12px;
23
+ padding: 8px 14px;
24
+ border: none;
25
+ border-radius: var(--radius-md);
26
+ background: var(--_c);
27
+ color: var(--on-primary);
28
+ cursor: pointer;
29
+ transition: filter .15s ease;
30
+ }
31
+ &::file-selector-button:hover { filter: brightness(1.06); }
32
+
33
+ &:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--radius-md); }
34
+ &:disabled { opacity: .5; cursor: not-allowed; }
35
+
36
+ &.#{$p}file--ghost::file-selector-button {
37
+ background: transparent;
38
+ color: var(--on-surface);
39
+ border: 1px solid var(--outline-strong);
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,51 @@
1
+ // ============================================================
2
+ // Aura — Group (join)
3
+ // Joins adjacent controls — buttons AND form fields — into one
4
+ // segmented unit: square inner corners, rounded outer corners, a
5
+ // single shared border (adjacent borders overlap, never doubled).
6
+ // `.btn-group` is kept as an alias.
7
+ // ============================================================
8
+ @use "../config" as cfg;
9
+ $p: cfg.$prefix;
10
+
11
+ @layer components {
12
+ .#{$p}group,
13
+ .#{$p}btn-group {
14
+ display: inline-flex;
15
+ align-items: stretch;
16
+ border-radius: var(--radius-md);
17
+
18
+ > * {
19
+ position: relative;
20
+ border-radius: 0;
21
+ box-shadow: none; // flatten per-item chrome inside the group
22
+ }
23
+ // overlap adjacent borders → one seam, not two
24
+ > :not(:first-child) { margin-inline-start: -1px; }
25
+ // bring the active item's border above its neighbours
26
+ > :hover,
27
+ > :focus-visible,
28
+ > :focus-within { z-index: 1; }
29
+
30
+ // round only the outermost corners
31
+ > :first-child {
32
+ border-start-start-radius: var(--radius-md);
33
+ border-end-start-radius: var(--radius-md);
34
+ }
35
+ > :last-child {
36
+ border-start-end-radius: var(--radius-md);
37
+ border-end-end-radius: var(--radius-md);
38
+ }
39
+
40
+ // fields grow to fill; buttons keep their natural width
41
+ > .#{$p}input,
42
+ > .#{$p}select { flex: 1; width: auto; min-width: 0; }
43
+ }
44
+
45
+ .#{$p}group--block,
46
+ .#{$p}btn-group--block {
47
+ display: flex;
48
+ width: 100%;
49
+ > * { flex: 1; }
50
+ }
51
+ }