@kouji-ui/components 0.9.2 → 0.9.3
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/package.json +1 -1
- package/src/accordion/accordion.css +68 -0
- package/src/action-sheet/action-sheet.css +79 -0
- package/src/alert/alert.css +133 -0
- package/src/avatar/avatar.css +93 -0
- package/src/badge/badge.css +59 -0
- package/src/breadcrumb/breadcrumb.css +145 -0
- package/src/button/button.css +295 -0
- package/src/button-group/button-group.css +114 -0
- package/src/calendar/calendar.css +129 -0
- package/src/card/card.css +120 -0
- package/src/carousel/carousel.css +181 -0
- package/src/cascade-select/cascade-select.css +120 -0
- package/src/chart/chart.css +26 -0
- package/src/chat/chat-ai.css +352 -0
- package/src/chat/chat.css +231 -0
- package/src/checkbox/checkbox.css +74 -0
- package/src/color-picker/color-picker.css +183 -0
- package/src/combobox/combobox.css +101 -0
- package/src/command-palette/command-palette.css +234 -0
- package/src/confirm-popup/confirm-popup.css +47 -0
- package/src/date-picker/date-picker.css +61 -0
- package/src/date-range-presets/date-range-presets.css +49 -0
- package/src/datetime-picker/datetime-picker.css +84 -0
- package/src/dialog/dialog.css +56 -0
- package/src/direction-toggle/direction-toggle.css +55 -0
- package/src/divider/divider.css +93 -0
- package/src/drawer/drawer.css +130 -0
- package/src/dropdown-menu/dropdown-menu.css +108 -0
- package/src/editor/editor.css +140 -0
- package/src/empty-state/empty-state.css +114 -0
- package/src/field/field.css +148 -0
- package/src/file-upload/file-upload.css +207 -0
- package/src/form/form.css +63 -0
- package/src/input/input.css +70 -0
- package/src/input-group/input-group.css +125 -0
- package/src/input-mask/input-mask.css +39 -0
- package/src/input-otp/input-otp.css +87 -0
- package/src/kbd/kbd.css +67 -0
- package/src/link/link.css +104 -0
- package/src/list/list.css +166 -0
- package/src/menubar/menubar.css +62 -0
- package/src/number-input/number-input.css +115 -0
- package/src/overflow/overflow.css +43 -0
- package/src/overlay/overlay.css +45 -0
- package/src/overlay-badge/overlay-badge.css +118 -0
- package/src/pagination/pagination.css +146 -0
- package/src/password-input/password-input.css +155 -0
- package/src/popover/popover.css +71 -0
- package/src/progress-bar/progress-bar.css +113 -0
- package/src/radio/radio.css +58 -0
- package/src/rich-text/rich-text-editor.css +351 -0
- package/src/select/select.css +91 -0
- package/src/sheet/sheet.css +121 -0
- package/src/skeleton/skeleton.css +111 -0
- package/src/skip-link/skip-link.css +58 -0
- package/src/slider/slider.css +172 -0
- package/src/speed-dial/speed-dial.css +137 -0
- package/src/spinner/spinner.css +161 -0
- package/src/stepper/stepper.css +147 -0
- package/src/table/table-filters/filters.css +53 -0
- package/src/table/table.css +509 -0
- package/src/tabs/tabs.css +162 -0
- package/src/tag/tag.css +183 -0
- package/src/textarea/textarea.css +117 -0
- package/src/time-picker/time-picker.css +126 -0
- package/src/toast/toast.css +115 -0
- package/src/toggle/toggle.css +123 -0
- package/src/tooltip/tooltip.css +61 -0
- package/src/tree-select/tree-select.css +220 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
.kj-skip-link — WCAG 2.4.1 "skip to content" link.
|
|
3
|
+
Visually hidden (parked above the viewport, NOT display:none so
|
|
4
|
+
it stays in the tab order) until focused, then slides on-screen
|
|
5
|
+
with a solid high-contrast surface. Component tokens default to
|
|
6
|
+
shared-layer values from @kouji-ui/themes.
|
|
7
|
+
──────────────────────────────────────────────────────────── */
|
|
8
|
+
|
|
9
|
+
@layer kj.component {
|
|
10
|
+
.kj-skip-link {
|
|
11
|
+
/* component knobs — themes / users can override any of these */
|
|
12
|
+
--kj-skip-link-bg: var(--kj-bg-primary);
|
|
13
|
+
--kj-skip-link-fg: var(--kj-fg-on-primary);
|
|
14
|
+
--kj-skip-link-radius: var(--kj-radius-field, 0.25rem);
|
|
15
|
+
--kj-skip-link-shadow: var(--kj-shadow-lg);
|
|
16
|
+
--kj-skip-link-offset: var(--kj-space-sm, 0.5rem);
|
|
17
|
+
--kj-skip-link-z: 1000;
|
|
18
|
+
|
|
19
|
+
position: fixed;
|
|
20
|
+
/* Parked just above the viewport — off-screen but focusable. */
|
|
21
|
+
top: 0;
|
|
22
|
+
left: var(--kj-skip-link-offset);
|
|
23
|
+
z-index: var(--kj-skip-link-z);
|
|
24
|
+
transform: translateY(-150%);
|
|
25
|
+
transition: transform var(--kj-transition, 150ms ease);
|
|
26
|
+
|
|
27
|
+
display: inline-block;
|
|
28
|
+
padding: 0.625rem 1rem;
|
|
29
|
+
min-height: 44px; /* WCAG 2.5.5 comfortable target once revealed */
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
|
|
32
|
+
background: var(--kj-skip-link-bg);
|
|
33
|
+
color: var(--kj-skip-link-fg);
|
|
34
|
+
border-radius: var(--kj-skip-link-radius);
|
|
35
|
+
box-shadow: var(--kj-skip-link-shadow);
|
|
36
|
+
font: inherit;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
line-height: 1.4;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Revealed on focus (:focus covers browsers/AT that don't match
|
|
44
|
+
:focus-visible for programmatic focus, e.g. skip-to-here). */
|
|
45
|
+
.kj-skip-link:focus,
|
|
46
|
+
.kj-skip-link:focus-visible {
|
|
47
|
+
transform: translateY(var(--kj-skip-link-offset));
|
|
48
|
+
outline: 3px solid var(--kj-fg-primary);
|
|
49
|
+
outline-offset: 2px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Honour reduced-motion: reveal instantly rather than sliding. */
|
|
53
|
+
@media (prefers-reduced-motion: reduce) {
|
|
54
|
+
.kj-skip-link {
|
|
55
|
+
transition: none;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
.kj-slider — wrapper around the KjSlider directive family.
|
|
3
|
+
|
|
4
|
+
The directive layer is headless. This wrapper translates the
|
|
5
|
+
directive context into pixels: track height/width, thumb size,
|
|
6
|
+
filled-portion offsets via the --kj-slider-start / --kj-slider-end
|
|
7
|
+
custom properties published by [kjSliderRange].
|
|
8
|
+
──────────────────────────────────────────────────────────── */
|
|
9
|
+
|
|
10
|
+
@layer kj.component {
|
|
11
|
+
.kj-slider {
|
|
12
|
+
--kj-slider-track-thickness: 0.375rem; /* 6px */
|
|
13
|
+
--kj-slider-track-bg: var(--kj-bg-field);
|
|
14
|
+
--kj-slider-fill-bg: var(--kj-bg-primary);
|
|
15
|
+
--kj-slider-thumb-size: 1.25rem; /* 20px visual */
|
|
16
|
+
--kj-slider-thumb-hit: 2.75rem; /* 44px touch — WCAG 2.5.5 */
|
|
17
|
+
--kj-slider-thumb-bg: var(--kj-bg-primary);
|
|
18
|
+
--kj-slider-thumb-fg: var(--kj-fg-on-primary);
|
|
19
|
+
--kj-slider-thumb-border: 2px solid var(--kj-bg-body);
|
|
20
|
+
--kj-slider-tick-size: 0.25rem; /* 4px */
|
|
21
|
+
--kj-slider-tick-bg: var(--kj-fg-default);
|
|
22
|
+
--kj-slider-radius: 999px;
|
|
23
|
+
--kj-slider-vertical-length: 12rem; /* 192px default */
|
|
24
|
+
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
user-select: none;
|
|
28
|
+
-webkit-user-select: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.kj-slider[data-orientation="horizontal"] {
|
|
32
|
+
width: 100%;
|
|
33
|
+
min-height: var(--kj-slider-thumb-hit);
|
|
34
|
+
padding: calc((var(--kj-slider-thumb-hit) - var(--kj-slider-track-thickness)) / 2) 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.kj-slider[data-orientation="vertical"] {
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
height: var(--kj-slider-vertical-length);
|
|
40
|
+
min-width: var(--kj-slider-thumb-hit);
|
|
41
|
+
padding: 0 calc((var(--kj-slider-thumb-hit) - var(--kj-slider-track-thickness)) / 2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.kj-slider[data-disabled] {
|
|
45
|
+
opacity: 0.55;
|
|
46
|
+
pointer-events: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ── Track ───────────────────────────────────────────────── */
|
|
50
|
+
.kj-slider__track {
|
|
51
|
+
position: relative;
|
|
52
|
+
flex: 1 1 auto;
|
|
53
|
+
background: var(--kj-slider-track-bg);
|
|
54
|
+
border-radius: var(--kj-slider-radius);
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__track {
|
|
59
|
+
height: var(--kj-slider-track-thickness);
|
|
60
|
+
width: 100%;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__track {
|
|
64
|
+
width: var(--kj-slider-track-thickness);
|
|
65
|
+
height: 100%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* ── Range fill ──────────────────────────────────────────── */
|
|
69
|
+
.kj-slider__range {
|
|
70
|
+
position: absolute;
|
|
71
|
+
background: var(--kj-slider-fill-bg);
|
|
72
|
+
border-radius: inherit;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__range {
|
|
76
|
+
top: 0;
|
|
77
|
+
bottom: 0;
|
|
78
|
+
left: calc(var(--kj-slider-start, 0) * 100%);
|
|
79
|
+
right: calc((1 - var(--kj-slider-end, 0)) * 100%);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__range {
|
|
83
|
+
left: 0;
|
|
84
|
+
right: 0;
|
|
85
|
+
bottom: calc(var(--kj-slider-start, 0) * 100%);
|
|
86
|
+
top: calc((1 - var(--kj-slider-end, 0)) * 100%);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ── Thumb ───────────────────────────────────────────────── */
|
|
90
|
+
.kj-slider__thumb {
|
|
91
|
+
position: absolute;
|
|
92
|
+
width: var(--kj-slider-thumb-size);
|
|
93
|
+
height: var(--kj-slider-thumb-size);
|
|
94
|
+
background: var(--kj-slider-thumb-bg);
|
|
95
|
+
color: var(--kj-slider-thumb-fg);
|
|
96
|
+
border: var(--kj-slider-thumb-border);
|
|
97
|
+
border-radius: 50%;
|
|
98
|
+
box-shadow: 0 1px 3px rgb(0 0 0 / 0.2);
|
|
99
|
+
cursor: grab;
|
|
100
|
+
padding: 0;
|
|
101
|
+
transition: transform var(--kj-transition, 120ms ease), box-shadow var(--kj-transition, 120ms ease);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.kj-slider__thumb:hover { transform: scale(1.05); }
|
|
105
|
+
.kj-slider__thumb[data-dragging] { cursor: grabbing; transform: scale(1.1); }
|
|
106
|
+
|
|
107
|
+
.kj-slider__thumb[data-focus-visible] {
|
|
108
|
+
outline: 2px solid var(--kj-bg-primary);
|
|
109
|
+
outline-offset: 3px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__thumb {
|
|
113
|
+
top: 50%;
|
|
114
|
+
left: calc(var(--kj-slider-thumb-fraction, 0) * 100%);
|
|
115
|
+
transform: translate(-50%, -50%);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__thumb:hover {
|
|
119
|
+
transform: translate(-50%, -50%) scale(1.05);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__thumb[data-dragging] {
|
|
123
|
+
transform: translate(-50%, -50%) scale(1.1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__thumb {
|
|
127
|
+
left: 50%;
|
|
128
|
+
bottom: calc(var(--kj-slider-thumb-fraction, 0) * 100%);
|
|
129
|
+
transform: translate(-50%, 50%);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__thumb:hover {
|
|
133
|
+
transform: translate(-50%, 50%) scale(1.05);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__thumb[data-dragging] {
|
|
137
|
+
transform: translate(-50%, 50%) scale(1.1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ── Tick marks (decorative) ─────────────────────────────── */
|
|
141
|
+
.kj-slider__ticks {
|
|
142
|
+
position: absolute;
|
|
143
|
+
inset: 0;
|
|
144
|
+
pointer-events: none;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.kj-slider__tick {
|
|
148
|
+
position: absolute;
|
|
149
|
+
width: var(--kj-slider-tick-size);
|
|
150
|
+
height: var(--kj-slider-tick-size);
|
|
151
|
+
background: var(--kj-slider-tick-bg);
|
|
152
|
+
opacity: 0.5;
|
|
153
|
+
border-radius: 50%;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.kj-slider[data-orientation="horizontal"] .kj-slider__tick {
|
|
157
|
+
top: 50%;
|
|
158
|
+
left: calc(var(--kj-slider-tick-fraction, 0) * 100%);
|
|
159
|
+
transform: translate(-50%, -50%);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.kj-slider[data-orientation="vertical"] .kj-slider__tick {
|
|
163
|
+
left: 50%;
|
|
164
|
+
bottom: calc(var(--kj-slider-tick-fraction, 0) * 100%);
|
|
165
|
+
transform: translate(-50%, 50%);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ── Reduced motion ──────────────────────────────────────── */
|
|
169
|
+
@media (prefers-reduced-motion: reduce) {
|
|
170
|
+
.kj-slider__thumb { transition: none; }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
.kj-speed-dial — viewport-anchored FAB + fan-out action cluster
|
|
3
|
+
The root component is a positioning shell (fixed when
|
|
4
|
+
data-position="*-*"). The trigger and actions are buttons that
|
|
5
|
+
theme through .kj-button — overrides target the kj-button-*
|
|
6
|
+
tokens so theme presets still apply.
|
|
7
|
+
──────────────────────────────────────────────────────────── */
|
|
8
|
+
|
|
9
|
+
@layer kj.component {
|
|
10
|
+
.kj-speed-dial {
|
|
11
|
+
--kj-speed-dial-gap: var(--kj-space-md);
|
|
12
|
+
--kj-speed-dial-edge: var(--kj-space-2xl);
|
|
13
|
+
--kj-speed-dial-trigger-size: 3.5rem;
|
|
14
|
+
--kj-speed-dial-action-size: 2.75rem;
|
|
15
|
+
--kj-speed-dial-shadow: 0 6px 16px rgb(0 0 0 / 0.18);
|
|
16
|
+
--kj-speed-dial-stagger: 30ms;
|
|
17
|
+
--kj-speed-dial-duration: 180ms;
|
|
18
|
+
|
|
19
|
+
position: relative;
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
align-items: center;
|
|
23
|
+
gap: var(--kj-speed-dial-gap);
|
|
24
|
+
z-index: 100;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.kj-speed-dial[data-direction='up'] { flex-direction: column-reverse; }
|
|
28
|
+
.kj-speed-dial[data-direction='down'] { flex-direction: column; }
|
|
29
|
+
.kj-speed-dial[data-direction='left'] { flex-direction: row-reverse; }
|
|
30
|
+
.kj-speed-dial[data-direction='right'] { flex-direction: row; }
|
|
31
|
+
|
|
32
|
+
.kj-speed-dial[data-position='bottom-right'] {
|
|
33
|
+
position: fixed;
|
|
34
|
+
right: var(--kj-speed-dial-edge);
|
|
35
|
+
bottom: var(--kj-speed-dial-edge);
|
|
36
|
+
}
|
|
37
|
+
.kj-speed-dial[data-position='bottom-left'] {
|
|
38
|
+
position: fixed;
|
|
39
|
+
left: var(--kj-speed-dial-edge);
|
|
40
|
+
bottom: var(--kj-speed-dial-edge);
|
|
41
|
+
}
|
|
42
|
+
.kj-speed-dial[data-position='top-right'] {
|
|
43
|
+
position: fixed;
|
|
44
|
+
right: var(--kj-speed-dial-edge);
|
|
45
|
+
top: var(--kj-speed-dial-edge);
|
|
46
|
+
}
|
|
47
|
+
.kj-speed-dial[data-position='top-left'] {
|
|
48
|
+
position: fixed;
|
|
49
|
+
left: var(--kj-speed-dial-edge);
|
|
50
|
+
top: var(--kj-speed-dial-edge);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.kj-speed-dial-trigger {
|
|
54
|
+
--kj-button-radius: 9999px;
|
|
55
|
+
--kj-button-padding-x: 0;
|
|
56
|
+
--kj-button-padding-y: 0;
|
|
57
|
+
--kj-button-shadow: var(--kj-speed-dial-shadow);
|
|
58
|
+
|
|
59
|
+
width: var(--kj-speed-dial-trigger-size);
|
|
60
|
+
height: var(--kj-speed-dial-trigger-size);
|
|
61
|
+
min-width: var(--kj-speed-dial-trigger-size);
|
|
62
|
+
flex: 0 0 auto;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.kj-speed-dial-trigger[data-state='open'] > * {
|
|
66
|
+
transform: rotate(45deg);
|
|
67
|
+
transition: transform var(--kj-speed-dial-duration) ease;
|
|
68
|
+
}
|
|
69
|
+
.kj-speed-dial-trigger > * {
|
|
70
|
+
display: inline-flex;
|
|
71
|
+
transition: transform var(--kj-speed-dial-duration) ease;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.kj-speed-dial-actions {
|
|
75
|
+
display: inline-flex;
|
|
76
|
+
gap: var(--kj-speed-dial-gap);
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
pointer-events: none;
|
|
80
|
+
opacity: 0;
|
|
81
|
+
transition: opacity var(--kj-speed-dial-duration) ease;
|
|
82
|
+
}
|
|
83
|
+
.kj-speed-dial-actions[data-direction='up'] { flex-direction: column-reverse; }
|
|
84
|
+
.kj-speed-dial-actions[data-direction='down'] { flex-direction: column; }
|
|
85
|
+
.kj-speed-dial-actions[data-direction='left'] { flex-direction: row-reverse; }
|
|
86
|
+
.kj-speed-dial-actions[data-direction='right'] { flex-direction: row; }
|
|
87
|
+
|
|
88
|
+
.kj-speed-dial-actions[aria-hidden='true'] {
|
|
89
|
+
visibility: hidden;
|
|
90
|
+
pointer-events: none;
|
|
91
|
+
}
|
|
92
|
+
.kj-speed-dial-actions[data-expanded] {
|
|
93
|
+
opacity: 1;
|
|
94
|
+
visibility: visible;
|
|
95
|
+
pointer-events: auto;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.kj-speed-dial-actions[data-direction='up'] > * { transform: translateY(8px); }
|
|
99
|
+
.kj-speed-dial-actions[data-direction='down'] > * { transform: translateY(-8px); }
|
|
100
|
+
.kj-speed-dial-actions[data-direction='left'] > * { transform: translateX(8px); }
|
|
101
|
+
.kj-speed-dial-actions[data-direction='right'] > * { transform: translateX(-8px); }
|
|
102
|
+
.kj-speed-dial-actions[data-expanded] > * {
|
|
103
|
+
transform: translate3d(0, 0, 0);
|
|
104
|
+
transition: transform var(--kj-speed-dial-duration) ease,
|
|
105
|
+
opacity var(--kj-speed-dial-duration) ease;
|
|
106
|
+
transition-delay: calc(var(--kj-speed-dial-stagger) * var(--kj-speed-dial-i, 0));
|
|
107
|
+
}
|
|
108
|
+
.kj-speed-dial-actions > *:nth-child(1) { --kj-speed-dial-i: 0; }
|
|
109
|
+
.kj-speed-dial-actions > *:nth-child(2) { --kj-speed-dial-i: 1; }
|
|
110
|
+
.kj-speed-dial-actions > *:nth-child(3) { --kj-speed-dial-i: 2; }
|
|
111
|
+
.kj-speed-dial-actions > *:nth-child(4) { --kj-speed-dial-i: 3; }
|
|
112
|
+
.kj-speed-dial-actions > *:nth-child(5) { --kj-speed-dial-i: 4; }
|
|
113
|
+
.kj-speed-dial-actions > *:nth-child(6) { --kj-speed-dial-i: 5; }
|
|
114
|
+
|
|
115
|
+
.kj-speed-dial-action {
|
|
116
|
+
--kj-button-radius: 9999px;
|
|
117
|
+
--kj-button-padding-x: 0;
|
|
118
|
+
--kj-button-padding-y: 0;
|
|
119
|
+
--kj-button-shadow: var(--kj-speed-dial-shadow);
|
|
120
|
+
|
|
121
|
+
width: var(--kj-speed-dial-action-size);
|
|
122
|
+
height: var(--kj-speed-dial-action-size);
|
|
123
|
+
min-width: var(--kj-speed-dial-action-size);
|
|
124
|
+
flex: 0 0 auto;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@media (prefers-reduced-motion: reduce) {
|
|
128
|
+
.kj-speed-dial-trigger > *,
|
|
129
|
+
.kj-speed-dial-actions,
|
|
130
|
+
.kj-speed-dial-actions > * {
|
|
131
|
+
transition: none;
|
|
132
|
+
}
|
|
133
|
+
.kj-speed-dial-actions > * {
|
|
134
|
+
transform: none;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
.kj-spinner — component-layer tokens + structural CSS
|
|
3
|
+
|
|
4
|
+
The directive owns role/label/data-attribute reflection. The CSS
|
|
5
|
+
below renders the visual glyph via the inner `.kj-spinner__glyph`
|
|
6
|
+
element (kept `aria-hidden="true"` in the template so AT only sees
|
|
7
|
+
the host's `role="status"` + `aria-label`). Variant + size + animation
|
|
8
|
+
routing all happens through `data-*` attributes on the wrapper host.
|
|
9
|
+
──────────────────────────────────────────────────────────── */
|
|
10
|
+
|
|
11
|
+
@layer kj.component {
|
|
12
|
+
.kj-spinner {
|
|
13
|
+
--kj-spinner-size: 1.25rem; /* md default */
|
|
14
|
+
--kj-spinner-color: currentColor; /* neutral resolves to currentColor */
|
|
15
|
+
--kj-spinner-track: color-mix(in srgb, currentColor 20%, transparent);
|
|
16
|
+
--kj-spinner-duration: 0.7s;
|
|
17
|
+
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
inline-size: var(--kj-spinner-size);
|
|
22
|
+
block-size: var(--kj-spinner-size);
|
|
23
|
+
color: var(--kj-spinner-color);
|
|
24
|
+
/* Keep the glyph centred without offering a hit-target — spinners are
|
|
25
|
+
not interactive. */
|
|
26
|
+
pointer-events: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Sizes — circular shapes use --kj-spinner-size for both axes. Linear
|
|
30
|
+
shapes (dots / bars) override inline-size on the host below. */
|
|
31
|
+
.kj-spinner[data-size="xs"] { --kj-spinner-size: 0.75rem; }
|
|
32
|
+
.kj-spinner[data-size="sm"] { --kj-spinner-size: 1rem; }
|
|
33
|
+
.kj-spinner[data-size="md"] { --kj-spinner-size: 1.25rem; }
|
|
34
|
+
.kj-spinner[data-size="lg"] { --kj-spinner-size: 1.75rem; }
|
|
35
|
+
|
|
36
|
+
/* Variant routing — neutral inherits currentColor (matches the
|
|
37
|
+
daisyUI / lucide convention so a spinner inside a primary button
|
|
38
|
+
picks up the button's text colour). */
|
|
39
|
+
.kj-spinner[data-variant="neutral"] { --kj-spinner-color: currentColor; }
|
|
40
|
+
.kj-spinner[data-variant="primary"] { --kj-spinner-color: var(--kj-fg-primary); }
|
|
41
|
+
.kj-spinner[data-variant="secondary"] { --kj-spinner-color: var(--kj-fg-default); }
|
|
42
|
+
.kj-spinner[data-variant="success"] { --kj-spinner-color: var(--kj-fg-success, #16a34a); }
|
|
43
|
+
.kj-spinner[data-variant="warning"] { --kj-spinner-color: var(--kj-fg-warning, #d97706); }
|
|
44
|
+
.kj-spinner[data-variant="error"] { --kj-spinner-color: var(--kj-fg-danger, #dc2626); }
|
|
45
|
+
.kj-spinner[data-variant="info"] { --kj-spinner-color: var(--kj-fg-info, #2563eb); }
|
|
46
|
+
|
|
47
|
+
/* Glyph host — themes can repaint the inner element per data-animation. */
|
|
48
|
+
.kj-spinner__glyph {
|
|
49
|
+
display: inline-block;
|
|
50
|
+
inline-size: 100%;
|
|
51
|
+
block-size: 100%;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* ── Animation: spin (default) — rotating arc ─────────────────────── */
|
|
55
|
+
.kj-spinner[data-animation="spin"] .kj-spinner__glyph {
|
|
56
|
+
border: 2px solid var(--kj-spinner-track);
|
|
57
|
+
border-block-start-color: var(--kj-spinner-color);
|
|
58
|
+
border-radius: 50%;
|
|
59
|
+
animation: kj-spinner-spin var(--kj-spinner-duration) linear infinite;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ── Animation: pulse — single fading circle ──────────────────────── */
|
|
63
|
+
.kj-spinner[data-animation="pulse"] .kj-spinner__glyph {
|
|
64
|
+
background: var(--kj-spinner-color);
|
|
65
|
+
border-radius: 50%;
|
|
66
|
+
animation: kj-spinner-pulse calc(var(--kj-spinner-duration) * 2) ease-in-out infinite;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* ── Animation: dots — three pulsing dots side by side ────────────── */
|
|
70
|
+
.kj-spinner[data-animation="dots"] {
|
|
71
|
+
/* Linear shape — width is auto, height is the size token. */
|
|
72
|
+
inline-size: auto;
|
|
73
|
+
}
|
|
74
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph {
|
|
75
|
+
display: inline-flex;
|
|
76
|
+
gap: calc(var(--kj-spinner-size) * 0.25);
|
|
77
|
+
inline-size: auto;
|
|
78
|
+
block-size: 100%;
|
|
79
|
+
}
|
|
80
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph::before,
|
|
81
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph::after,
|
|
82
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph {
|
|
83
|
+
/* Each dot via pseudo + the glyph itself acts as a flex container. */
|
|
84
|
+
}
|
|
85
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph::before,
|
|
86
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph::after {
|
|
87
|
+
content: "";
|
|
88
|
+
inline-size: calc(var(--kj-spinner-size) * 0.3);
|
|
89
|
+
block-size: calc(var(--kj-spinner-size) * 0.3);
|
|
90
|
+
background: var(--kj-spinner-color);
|
|
91
|
+
border-radius: 50%;
|
|
92
|
+
animation: kj-spinner-dots calc(var(--kj-spinner-duration) * 2) ease-in-out infinite;
|
|
93
|
+
}
|
|
94
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph {
|
|
95
|
+
background: transparent;
|
|
96
|
+
}
|
|
97
|
+
/* Middle dot rendered via box-shadow on ::before for a 3-dot row without
|
|
98
|
+
extra DOM. The two pseudos animate offset; the middle dot is the glyph
|
|
99
|
+
element's own background dot. */
|
|
100
|
+
.kj-spinner[data-animation="dots"] .kj-spinner__glyph::after {
|
|
101
|
+
animation-delay: calc(var(--kj-spinner-duration) * 0.4);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ── Animation: bars — vertical bars rising/falling ───────────────── */
|
|
105
|
+
.kj-spinner[data-animation="bars"] {
|
|
106
|
+
inline-size: auto;
|
|
107
|
+
}
|
|
108
|
+
.kj-spinner[data-animation="bars"] .kj-spinner__glyph {
|
|
109
|
+
display: inline-flex;
|
|
110
|
+
align-items: stretch;
|
|
111
|
+
gap: calc(var(--kj-spinner-size) * 0.15);
|
|
112
|
+
inline-size: auto;
|
|
113
|
+
block-size: 100%;
|
|
114
|
+
}
|
|
115
|
+
.kj-spinner[data-animation="bars"] .kj-spinner__glyph::before,
|
|
116
|
+
.kj-spinner[data-animation="bars"] .kj-spinner__glyph::after {
|
|
117
|
+
content: "";
|
|
118
|
+
inline-size: calc(var(--kj-spinner-size) * 0.2);
|
|
119
|
+
background: var(--kj-spinner-color);
|
|
120
|
+
border-radius: calc(var(--kj-spinner-size) * 0.05);
|
|
121
|
+
animation: kj-spinner-bars calc(var(--kj-spinner-duration) * 1.6) ease-in-out infinite;
|
|
122
|
+
transform-origin: center;
|
|
123
|
+
}
|
|
124
|
+
.kj-spinner[data-animation="bars"] .kj-spinner__glyph::after {
|
|
125
|
+
animation-delay: calc(var(--kj-spinner-duration) * 0.4);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* ── Reduced motion — directive sets `data-reduced-motion="true"` ──── */
|
|
129
|
+
/* WCAG 2.3.3 (AAA): swap continuous rotation for a slow opacity pulse. */
|
|
130
|
+
.kj-spinner[data-reduced-motion="true"] .kj-spinner__glyph,
|
|
131
|
+
.kj-spinner[data-reduced-motion="true"] .kj-spinner__glyph::before,
|
|
132
|
+
.kj-spinner[data-reduced-motion="true"] .kj-spinner__glyph::after {
|
|
133
|
+
animation: kj-spinner-reduced-motion 1.6s ease-in-out infinite !important;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Keyframes live outside the cascade layer so consumers can't accidentally
|
|
138
|
+
defeat them with a higher-priority unlayered rule. */
|
|
139
|
+
@keyframes kj-spinner-spin {
|
|
140
|
+
to { transform: rotate(360deg); }
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@keyframes kj-spinner-pulse {
|
|
144
|
+
0%, 100% { opacity: 0.35; transform: scale(0.85); }
|
|
145
|
+
50% { opacity: 1; transform: scale(1); }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@keyframes kj-spinner-dots {
|
|
149
|
+
0%, 80%, 100% { transform: scale(0.4); opacity: 0.4; }
|
|
150
|
+
40% { transform: scale(1); opacity: 1; }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@keyframes kj-spinner-bars {
|
|
154
|
+
0%, 40%, 100% { transform: scaleY(0.4); }
|
|
155
|
+
20% { transform: scaleY(1); }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@keyframes kj-spinner-reduced-motion {
|
|
159
|
+
0%, 100% { opacity: 0.45; }
|
|
160
|
+
50% { opacity: 1; }
|
|
161
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
@layer kj.component {
|
|
2
|
+
.kj-stepper {
|
|
3
|
+
--kj-stepper-gap: var(--kj-space-md);
|
|
4
|
+
--kj-stepper-indicator-size: 2rem;
|
|
5
|
+
--kj-stepper-bg: var(--kj-bg-body);
|
|
6
|
+
--kj-stepper-border: var(--kj-border-default);
|
|
7
|
+
--kj-stepper-active: var(--kj-bg-primary);
|
|
8
|
+
--kj-stepper-active-fg: var(--kj-fg-on-primary);
|
|
9
|
+
--kj-stepper-completed: var(--kj-bg-success);
|
|
10
|
+
--kj-stepper-error: var(--kj-bg-danger);
|
|
11
|
+
--kj-stepper-muted: var(--kj-fg-muted);
|
|
12
|
+
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: var(--kj-space-lg);
|
|
16
|
+
list-style: none;
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.kj-stepper[data-orientation="horizontal"] {
|
|
22
|
+
flex-direction: row;
|
|
23
|
+
flex-wrap: wrap;
|
|
24
|
+
align-items: flex-start;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.kj-step {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: var(--kj-space-sm);
|
|
31
|
+
flex: 1 1 auto;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.kj-stepper[data-orientation="vertical"] .kj-step {
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: stretch;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.kj-step__label {
|
|
40
|
+
appearance: none;
|
|
41
|
+
background: none;
|
|
42
|
+
border: 0;
|
|
43
|
+
padding: var(--kj-space-sm) var(--kj-space-md);
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(--kj-space-sm);
|
|
47
|
+
color: var(--kj-stepper-muted);
|
|
48
|
+
font: 0.875rem / 1.4 var(--kj-font-sans);
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
border-radius: var(--kj-radius-field);
|
|
52
|
+
transition: var(--kj-transition);
|
|
53
|
+
text-align: left;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.kj-step__label::before {
|
|
57
|
+
content: counter(kj-step-counter);
|
|
58
|
+
counter-increment: kj-step-counter;
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
width: var(--kj-stepper-indicator-size);
|
|
63
|
+
height: var(--kj-stepper-indicator-size);
|
|
64
|
+
border-radius: 50%;
|
|
65
|
+
border: var(--kj-border) solid var(--kj-stepper-border);
|
|
66
|
+
background: var(--kj-stepper-bg);
|
|
67
|
+
color: var(--kj-stepper-muted);
|
|
68
|
+
font-size: 0.75rem;
|
|
69
|
+
flex-shrink: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.kj-stepper { counter-reset: kj-step-counter; }
|
|
73
|
+
|
|
74
|
+
.kj-step__label:hover { color: var(--kj-fg-default); }
|
|
75
|
+
.kj-step__label:focus-visible { outline: 2px solid var(--kj-stepper-active); outline-offset: 2px; }
|
|
76
|
+
|
|
77
|
+
.kj-step[data-active="true"] > .kj-step__label,
|
|
78
|
+
.kj-step[data-active="true"] .kj-step__label {
|
|
79
|
+
color: var(--kj-fg-default);
|
|
80
|
+
}
|
|
81
|
+
.kj-step[data-active="true"] > .kj-step__label::before,
|
|
82
|
+
.kj-step[data-active="true"] .kj-step__label::before {
|
|
83
|
+
background: var(--kj-stepper-active);
|
|
84
|
+
border-color: var(--kj-stepper-active);
|
|
85
|
+
color: var(--kj-stepper-active-fg);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.kj-step[data-completed="true"] > .kj-step__label::before,
|
|
89
|
+
.kj-step[data-completed="true"] .kj-step__label::before {
|
|
90
|
+
background: var(--kj-stepper-completed);
|
|
91
|
+
border-color: var(--kj-stepper-completed);
|
|
92
|
+
color: var(--kj-fg-on-success, #fff);
|
|
93
|
+
content: "\2713"; /* check mark */
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.kj-step[data-error="true"] > .kj-step__label::before,
|
|
97
|
+
.kj-step[data-error="true"] .kj-step__label::before {
|
|
98
|
+
background: var(--kj-stepper-error);
|
|
99
|
+
border-color: var(--kj-stepper-error);
|
|
100
|
+
color: var(--kj-fg-on-danger, #fff);
|
|
101
|
+
content: "!";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.kj-step[data-disabled="true"] > .kj-step__label,
|
|
105
|
+
.kj-step[data-disabled="true"] .kj-step__label,
|
|
106
|
+
.kj-step__label[aria-disabled="true"],
|
|
107
|
+
.kj-step__label[disabled] {
|
|
108
|
+
opacity: 0.45;
|
|
109
|
+
cursor: not-allowed;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.kj-step__content {
|
|
113
|
+
display: block;
|
|
114
|
+
color: var(--kj-fg-default);
|
|
115
|
+
font: 0.875rem / 1.5 var(--kj-font-sans);
|
|
116
|
+
padding: var(--kj-space-md);
|
|
117
|
+
background: var(--kj-bg-body);
|
|
118
|
+
border: var(--kj-border) solid var(--kj-stepper-border);
|
|
119
|
+
border-radius: var(--kj-radius-box);
|
|
120
|
+
}
|
|
121
|
+
.kj-step__content[hidden] { display: none; }
|
|
122
|
+
|
|
123
|
+
.kj-stepper-action {
|
|
124
|
+
appearance: none;
|
|
125
|
+
border: var(--kj-border) solid var(--kj-stepper-border);
|
|
126
|
+
background: var(--kj-bg-body);
|
|
127
|
+
color: var(--kj-fg-default);
|
|
128
|
+
padding: var(--kj-space-sm) var(--kj-space-md);
|
|
129
|
+
border-radius: var(--kj-radius-field);
|
|
130
|
+
font: 0.875rem / 1 var(--kj-font-sans);
|
|
131
|
+
cursor: pointer;
|
|
132
|
+
transition: var(--kj-transition);
|
|
133
|
+
}
|
|
134
|
+
.kj-stepper-action:hover:not([disabled]):not([aria-disabled="true"]) {
|
|
135
|
+
border-color: var(--kj-stepper-active);
|
|
136
|
+
color: var(--kj-stepper-active);
|
|
137
|
+
}
|
|
138
|
+
.kj-stepper-action:focus-visible { outline: 2px solid var(--kj-stepper-active); outline-offset: 2px; }
|
|
139
|
+
.kj-stepper-action[disabled],
|
|
140
|
+
.kj-stepper-action[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
|
|
141
|
+
|
|
142
|
+
.kj-stepper-action--next {
|
|
143
|
+
background: var(--kj-stepper-active);
|
|
144
|
+
color: var(--kj-stepper-active-fg);
|
|
145
|
+
border-color: var(--kj-stepper-active);
|
|
146
|
+
}
|
|
147
|
+
}
|