@kouji-ui/components 0.9.1 → 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.
Files changed (73) hide show
  1. package/fesm2022/kouji-ui-components.mjs +137 -65
  2. package/fesm2022/kouji-ui-components.mjs.map +1 -1
  3. package/package.json +1 -1
  4. package/src/accordion/accordion.css +68 -0
  5. package/src/action-sheet/action-sheet.css +79 -0
  6. package/src/alert/alert.css +133 -0
  7. package/src/avatar/avatar.css +93 -0
  8. package/src/badge/badge.css +59 -0
  9. package/src/breadcrumb/breadcrumb.css +145 -0
  10. package/src/button/button.css +295 -0
  11. package/src/button-group/button-group.css +114 -0
  12. package/src/calendar/calendar.css +129 -0
  13. package/src/card/card.css +120 -0
  14. package/src/carousel/carousel.css +181 -0
  15. package/src/cascade-select/cascade-select.css +120 -0
  16. package/src/chart/chart.css +26 -0
  17. package/src/chat/chat-ai.css +352 -0
  18. package/src/chat/chat.css +231 -0
  19. package/src/checkbox/checkbox.css +74 -0
  20. package/src/color-picker/color-picker.css +183 -0
  21. package/src/combobox/combobox.css +101 -0
  22. package/src/command-palette/command-palette.css +234 -0
  23. package/src/confirm-popup/confirm-popup.css +47 -0
  24. package/src/date-picker/date-picker.css +61 -0
  25. package/src/date-range-presets/date-range-presets.css +49 -0
  26. package/src/datetime-picker/datetime-picker.css +84 -0
  27. package/src/dialog/dialog.css +56 -0
  28. package/src/direction-toggle/direction-toggle.css +55 -0
  29. package/src/divider/divider.css +93 -0
  30. package/src/drawer/drawer.css +130 -0
  31. package/src/dropdown-menu/dropdown-menu.css +108 -0
  32. package/src/editor/editor.css +140 -0
  33. package/src/empty-state/empty-state.css +114 -0
  34. package/src/field/field.css +148 -0
  35. package/src/file-upload/file-upload.css +207 -0
  36. package/src/form/form.css +63 -0
  37. package/src/input/input.css +70 -0
  38. package/src/input-group/input-group.css +125 -0
  39. package/src/input-mask/input-mask.css +39 -0
  40. package/src/input-otp/input-otp.css +87 -0
  41. package/src/kbd/kbd.css +67 -0
  42. package/src/link/link.css +104 -0
  43. package/src/list/list.css +166 -0
  44. package/src/menubar/menubar.css +62 -0
  45. package/src/number-input/number-input.css +115 -0
  46. package/src/overflow/overflow.css +43 -0
  47. package/src/overlay/overlay.css +45 -0
  48. package/src/overlay-badge/overlay-badge.css +118 -0
  49. package/src/pagination/pagination.css +146 -0
  50. package/src/password-input/password-input.css +155 -0
  51. package/src/popover/popover.css +71 -0
  52. package/src/progress-bar/progress-bar.css +113 -0
  53. package/src/radio/radio.css +58 -0
  54. package/src/rich-text/rich-text-editor.css +351 -0
  55. package/src/select/select.css +91 -0
  56. package/src/sheet/sheet.css +121 -0
  57. package/src/skeleton/skeleton.css +111 -0
  58. package/src/skip-link/skip-link.css +58 -0
  59. package/src/slider/slider.css +172 -0
  60. package/src/speed-dial/speed-dial.css +137 -0
  61. package/src/spinner/spinner.css +161 -0
  62. package/src/stepper/stepper.css +147 -0
  63. package/src/table/table-filters/filters.css +53 -0
  64. package/src/table/table.css +509 -0
  65. package/src/tabs/tabs.css +162 -0
  66. package/src/tag/tag.css +183 -0
  67. package/src/textarea/textarea.css +117 -0
  68. package/src/time-picker/time-picker.css +126 -0
  69. package/src/toast/toast.css +115 -0
  70. package/src/toggle/toggle.css +123 -0
  71. package/src/tooltip/tooltip.css +61 -0
  72. package/src/tree-select/tree-select.css +220 -0
  73. package/types/kouji-ui-components.d.ts +17 -1
@@ -0,0 +1,130 @@
1
+ @layer kj.component {
2
+ .kj-drawer {
3
+ --kj-drawer-bg: var(--kj-bg-elevated);
4
+ --kj-drawer-fg: var(--kj-fg-default);
5
+ --kj-drawer-border-color: var(--kj-border-default);
6
+ --kj-drawer-shadow: var(--kj-shadow-lg);
7
+ --kj-drawer-size: 22rem;
8
+
9
+ position: fixed;
10
+ display: flex;
11
+ flex-direction: column;
12
+ background: var(--kj-drawer-bg);
13
+ color: var(--kj-drawer-fg);
14
+ box-shadow: var(--kj-drawer-shadow);
15
+ overflow: hidden;
16
+ z-index: var(--kj-overlay-z, 1000);
17
+ box-sizing: border-box;
18
+ padding: var(--kj-space-lg);
19
+ }
20
+
21
+ .kj-drawer[data-kj-side="right"] {
22
+ top: 0;
23
+ right: 0;
24
+ bottom: 0;
25
+ width: min(var(--kj-drawer-size), 100vw);
26
+ border-left: var(--kj-border) solid var(--kj-drawer-border-color);
27
+ }
28
+ .kj-drawer[data-kj-side="left"] {
29
+ top: 0;
30
+ left: 0;
31
+ bottom: 0;
32
+ width: min(var(--kj-drawer-size), 100vw);
33
+ border-right: var(--kj-border) solid var(--kj-drawer-border-color);
34
+ }
35
+ .kj-drawer[data-kj-side="top"] {
36
+ top: 0;
37
+ left: 0;
38
+ right: 0;
39
+ height: min(var(--kj-drawer-size), 100vh);
40
+ border-bottom: var(--kj-border) solid var(--kj-drawer-border-color);
41
+ }
42
+ .kj-drawer[data-kj-side="bottom"] {
43
+ bottom: 0;
44
+ left: 0;
45
+ right: 0;
46
+ height: min(var(--kj-drawer-size), 100vh);
47
+ border-top: var(--kj-border) solid var(--kj-drawer-border-color);
48
+ }
49
+
50
+ /* Modal scrim — pseudo-element on the portaled wrapper. */
51
+ [data-kj-drawer-container]::before {
52
+ content: '';
53
+ position: fixed;
54
+ inset: 0;
55
+ background: rgb(0 0 0 / 0.5);
56
+ z-index: calc(var(--kj-overlay-z, 1000) - 1);
57
+ pointer-events: auto;
58
+ }
59
+ [data-kj-drawer-container]:has(.kj-drawer[role="region"])::before {
60
+ display: none;
61
+ }
62
+
63
+ @media (prefers-reduced-motion: no-preference) {
64
+ .kj-drawer {
65
+ transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
66
+ }
67
+ .kj-drawer[data-state="open"] {
68
+ transform: translate3d(0, 0, 0);
69
+ }
70
+ .kj-drawer[data-kj-side="right"][data-state="closed"] { transform: translate3d(100%, 0, 0); }
71
+ .kj-drawer[data-kj-side="left"][data-state="closed"] { transform: translate3d(-100%, 0, 0); }
72
+ .kj-drawer[data-kj-side="top"][data-state="closed"] { transform: translate3d(0, -100%, 0); }
73
+ .kj-drawer[data-kj-side="bottom"][data-state="closed"] { transform: translate3d(0, 100%, 0); }
74
+ }
75
+
76
+ @media (prefers-reduced-motion: reduce) {
77
+ .kj-drawer {
78
+ transition: opacity 120ms linear;
79
+ }
80
+ .kj-drawer[data-state="open"] { opacity: 1; }
81
+ .kj-drawer[data-state="closed"] { opacity: 0; }
82
+ }
83
+
84
+ .kj-drawer-header {
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: flex-start;
88
+ padding: var(--kj-space-lg) var(--kj-space-xl);
89
+ border-bottom: var(--kj-border) solid var(--kj-border-muted);
90
+ flex-shrink: 0;
91
+ }
92
+ .kj-drawer-header[data-align="center"] { justify-content: center; }
93
+
94
+ .kj-drawer-title {
95
+ display: block;
96
+ margin: 0;
97
+ font: 600 1.125rem / 1.3 var(--kj-font-sans);
98
+ color: var(--kj-fg-default);
99
+ }
100
+
101
+ .kj-drawer-description {
102
+ display: block;
103
+ margin: var(--kj-space-xs) 0 0;
104
+ color: var(--kj-fg-muted);
105
+ font: 0.875rem / 1.4 var(--kj-font-sans);
106
+ opacity: 0.8;
107
+ }
108
+
109
+ .kj-drawer-body {
110
+ flex: 1;
111
+ color: var(--kj-fg-default);
112
+ font: 0.9375rem / 1.5 var(--kj-font-sans);
113
+ min-height: 0;
114
+ }
115
+ .kj-drawer-body[data-padded] { padding: var(--kj-space-lg) var(--kj-space-xl); }
116
+ .kj-drawer-body[data-scroll] { overflow-y: auto; }
117
+
118
+ .kj-drawer-footer {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: var(--kj-space-sm);
122
+ padding: var(--kj-space-lg) var(--kj-space-xl);
123
+ border-top: var(--kj-border) solid var(--kj-border-muted);
124
+ flex-shrink: 0;
125
+ }
126
+ .kj-drawer-footer[data-align="start"] { justify-content: flex-start; }
127
+ .kj-drawer-footer[data-align="center"] { justify-content: center; }
128
+ .kj-drawer-footer[data-align="end"] { justify-content: flex-end; }
129
+ .kj-drawer-footer[data-align="between"] { justify-content: space-between; }
130
+ }
@@ -0,0 +1,108 @@
1
+ @layer kj.component {
2
+ /* The trigger and most wrappers use display: contents — they don't add a
3
+ box. Theme tokens land on `.kj-dropdown-menu` (the panel), which the
4
+ directive moves to a body-level container on open so it escapes any
5
+ clipping ancestor. */
6
+
7
+ .kj-dropdown-menu {
8
+ --kj-dropdown-menu-bg: var(--kj-bg-elevated);
9
+ --kj-dropdown-menu-fg: var(--kj-fg-default);
10
+ --kj-dropdown-menu-border-color: var(--kj-border-default);
11
+ --kj-dropdown-menu-radius: var(--kj-radius-box);
12
+ --kj-dropdown-menu-padding: var(--kj-space-xs);
13
+ --kj-dropdown-menu-shadow: var(--kj-shadow-md);
14
+
15
+ display: flex;
16
+ flex-direction: column;
17
+ box-sizing: border-box;
18
+ min-width: 12rem;
19
+ max-width: min(20rem, calc(100vw - 2rem));
20
+ background: var(--kj-dropdown-menu-bg);
21
+ color: var(--kj-dropdown-menu-fg);
22
+ border: var(--kj-border) solid var(--kj-dropdown-menu-border-color);
23
+ border-radius: var(--kj-dropdown-menu-radius);
24
+ padding: var(--kj-dropdown-menu-padding);
25
+ font: 0.875rem / 1.5 var(--kj-font-sans);
26
+ box-shadow: var(--kj-dropdown-menu-shadow);
27
+ pointer-events: auto;
28
+ z-index: var(--kj-overlay-z, 1000);
29
+ }
30
+
31
+ .kj-dropdown-menu[hidden] { display: none; }
32
+
33
+ .kj-dropdown-menu-item {
34
+ --kj-dropdown-menu-item-padding-x: var(--kj-space-md);
35
+ --kj-dropdown-menu-item-padding-y: var(--kj-space-sm);
36
+ --kj-dropdown-menu-item-min-height: 2.75rem; /* 44px AAA touch target */
37
+ --kj-dropdown-menu-item-radius: var(--kj-radius-field);
38
+ --kj-dropdown-menu-item-hover-bg: var(--kj-bg-surface);
39
+ --kj-dropdown-menu-item-active-bg: var(--kj-bg-field);
40
+
41
+ display: flex;
42
+ align-items: center;
43
+ justify-content: flex-start;
44
+ gap: var(--kj-space-sm);
45
+ width: 100%;
46
+ min-height: var(--kj-dropdown-menu-item-min-height);
47
+ box-sizing: border-box;
48
+ padding: var(--kj-dropdown-menu-item-padding-y) var(--kj-dropdown-menu-item-padding-x);
49
+ margin: 0;
50
+ background: transparent;
51
+ color: inherit;
52
+ border: none;
53
+ border-radius: var(--kj-dropdown-menu-item-radius);
54
+ font: inherit;
55
+ text-align: start;
56
+ cursor: pointer;
57
+ user-select: none;
58
+ }
59
+
60
+ .kj-dropdown-menu-item:hover:not([data-disabled]) {
61
+ background: var(--kj-dropdown-menu-item-hover-bg);
62
+ }
63
+ .kj-dropdown-menu-item:focus-visible {
64
+ outline: 2px solid var(--kj-bg-primary);
65
+ outline-offset: -2px;
66
+ }
67
+ .kj-dropdown-menu-item[aria-current="true"] {
68
+ background: var(--kj-dropdown-menu-item-current-bg, var(--kj-bg-field));
69
+ color: var(--kj-dropdown-menu-item-current-fg, var(--kj-fg-primary));
70
+ font-weight: 500;
71
+ }
72
+ .kj-dropdown-menu-item[data-disabled] {
73
+ cursor: not-allowed;
74
+ opacity: 0.5;
75
+ }
76
+
77
+ .kj-dropdown-menu-separator {
78
+ display: block;
79
+ height: 1px;
80
+ margin: var(--kj-space-xs) calc(var(--kj-space-xs) * -1);
81
+ background: color-mix(in oklab, var(--kj-fg-default) 12%, transparent);
82
+ border: 0;
83
+ }
84
+
85
+ .kj-dropdown-menu-label {
86
+ display: block;
87
+ padding: var(--kj-space-xs) var(--kj-space-md);
88
+ font-size: 0.75rem;
89
+ font-weight: 600;
90
+ text-transform: uppercase;
91
+ letter-spacing: 0.04em;
92
+ color: var(--kj-fg-default);
93
+ opacity: 0.65;
94
+ }
95
+
96
+ .kj-dropdown-menu-group {
97
+ display: flex;
98
+ flex-direction: column;
99
+ }
100
+
101
+ @media (prefers-reduced-motion: no-preference) {
102
+ .kj-dropdown-menu {
103
+ transition: opacity 120ms ease-out, transform 120ms ease-out;
104
+ }
105
+ .kj-dropdown-menu[data-state="closed"] { opacity: 0; transform: scale(0.98); }
106
+ .kj-dropdown-menu[data-state="open"] { opacity: 1; transform: scale(1); }
107
+ }
108
+ }
@@ -0,0 +1,140 @@
1
+ :host {
2
+ display: block;
3
+ border: 1px solid var(--kj-border-default);
4
+ border-radius: var(--kj-radius-md, 0);
5
+ overflow: hidden;
6
+ background: var(--kj-bg-surface);
7
+ }
8
+
9
+ .kj-editor-wrap {
10
+ display: flex;
11
+ flex-direction: column;
12
+ height: 100%;
13
+ min-height: 12rem;
14
+ }
15
+
16
+ /* ── Auto-height mode: grow to fit content instead of filling the container. ──
17
+ The directive sets the host's inline height from Monaco's content height; the
18
+ body must stop being a flex-fill / absolute-positioned region so that height
19
+ applies. */
20
+ :host([data-auto-height]) {
21
+ height: auto;
22
+ }
23
+ :host([data-auto-height]) .kj-editor-wrap {
24
+ height: auto;
25
+ min-height: 0;
26
+ }
27
+ :host([data-auto-height]) .kj-editor-body {
28
+ position: static;
29
+ flex: none;
30
+ min-height: 3rem;
31
+ }
32
+ :host([data-auto-height]) .kj-editor-host {
33
+ position: relative;
34
+ inset: auto;
35
+ }
36
+
37
+ /* ── Toolbar ── */
38
+ .kj-editor-toolbar,
39
+ .kj-editor-status {
40
+ display: flex;
41
+ align-items: center;
42
+ gap: var(--kj-space-sm);
43
+ padding: var(--kj-space-sm) var(--kj-space-lg);
44
+ background: var(--kj-bg-body);
45
+ flex-shrink: 0;
46
+ }
47
+ .kj-editor-toolbar {
48
+ border-bottom: 1px solid var(--kj-border-default);
49
+ }
50
+ .kj-editor-status {
51
+ border-top: 1px solid var(--kj-border-default);
52
+ }
53
+
54
+ .kj-editor-spacer {
55
+ flex: 1;
56
+ }
57
+
58
+ .kj-editor-lang {
59
+ font-family: var(--kj-font-mono);
60
+ font-size: 0.65rem;
61
+ letter-spacing: 0.12em;
62
+ text-transform: uppercase;
63
+ color: var(--kj-fg-primary);
64
+ background: color-mix(in oklab, var(--kj-bg-primary) 8%, transparent);
65
+ padding: 0.15rem var(--kj-space-sm);
66
+ border: 1px solid color-mix(in oklab, var(--kj-bg-primary) 22%, transparent);
67
+ }
68
+
69
+ .kj-editor-copy {
70
+ background: none;
71
+ border: none;
72
+ color: var(--kj-fg-muted);
73
+ font-family: var(--kj-font-mono);
74
+ font-size: 0.7rem;
75
+ letter-spacing: 0.06em;
76
+ cursor: pointer;
77
+ /* 44x44 touch target (WCAG 2.5.5) via padding on a compact control. */
78
+ min-height: 44px;
79
+ min-width: 44px;
80
+ padding: 0 var(--kj-space-sm);
81
+ transition: color 0.15s;
82
+ }
83
+ .kj-editor-copy:hover {
84
+ color: var(--kj-fg-default);
85
+ }
86
+ .kj-editor-copy:focus-visible {
87
+ outline: 2px solid var(--kj-border-focus, var(--kj-bg-primary));
88
+ outline-offset: 2px;
89
+ }
90
+
91
+ /* ── Status bar ── */
92
+ .kj-editor-pos {
93
+ font-family: var(--kj-font-mono);
94
+ font-size: 0.7rem;
95
+ color: var(--kj-fg-muted);
96
+ }
97
+ .kj-editor-hint {
98
+ font-size: 0.7rem;
99
+ color: var(--kj-fg-muted);
100
+ }
101
+
102
+ /* ── Monaco host ── */
103
+ .kj-editor-body {
104
+ position: relative;
105
+ flex: 1;
106
+ min-height: 8rem;
107
+ }
108
+ .kj-editor-host {
109
+ position: absolute;
110
+ inset: 0;
111
+ overflow: hidden;
112
+ }
113
+
114
+ .kj-editor-loading {
115
+ position: absolute;
116
+ inset: 0;
117
+ display: flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ background: var(--kj-bg-surface);
121
+ z-index: 1;
122
+ }
123
+
124
+ /* ── Pierce Monaco's uncontrolled DOM to match kj tokens ──
125
+ Monaco renders elements we don't own; the defined kj-editor theme handles
126
+ most chrome, this backstops backgrounds/scrollbar for the container. */
127
+ .kj-editor-host ::ng-deep .monaco-editor,
128
+ .kj-editor-host ::ng-deep .monaco-editor-background,
129
+ .kj-editor-host ::ng-deep .monaco-editor .margin {
130
+ background-color: var(--kj-bg-surface) !important;
131
+ }
132
+ .kj-editor-host ::ng-deep .monaco-editor .scrollbar .slider {
133
+ background: var(--kj-bg-field, var(--kj-bg-elevated)) !important;
134
+ }
135
+
136
+ @media (prefers-reduced-motion: reduce) {
137
+ .kj-editor-copy {
138
+ transition: none;
139
+ }
140
+ }
@@ -0,0 +1,114 @@
1
+ /* ─────────────────────────────────────────────────────────────
2
+ .kj-empty-state — components-only family
3
+ ──────────────────────────────────────────────────────────── */
4
+
5
+ @layer kj.component {
6
+ .kj-empty-state {
7
+ --kj-empty-state-bg: transparent;
8
+ --kj-empty-state-fg: var(--kj-fg-default);
9
+ --kj-empty-state-muted-fg: var(--kj-fg-muted);
10
+ --kj-empty-state-accent: var(--kj-border-default);
11
+ --kj-empty-state-padding-y: var(--kj-space-2xl, 2rem);
12
+ --kj-empty-state-padding-x: var(--kj-space-xl, 1.5rem);
13
+ --kj-empty-state-gap: var(--kj-space-md, 0.75rem);
14
+ --kj-empty-state-icon-size: 3rem;
15
+ --kj-empty-state-title-size: 1.125rem;
16
+ --kj-empty-state-desc-size: 0.9375rem;
17
+ --kj-empty-state-max-width: 32rem;
18
+
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ justify-content: center;
23
+ text-align: center;
24
+ gap: var(--kj-empty-state-gap);
25
+ padding: var(--kj-empty-state-padding-y) var(--kj-empty-state-padding-x);
26
+ background: var(--kj-empty-state-bg);
27
+ color: var(--kj-empty-state-fg);
28
+ }
29
+
30
+ .kj-empty-state[data-size="sm"] {
31
+ --kj-empty-state-padding-y: var(--kj-space-lg, 1rem);
32
+ --kj-empty-state-padding-x: var(--kj-space-md, 0.75rem);
33
+ --kj-empty-state-gap: var(--kj-space-sm, 0.5rem);
34
+ --kj-empty-state-icon-size: 2rem;
35
+ --kj-empty-state-title-size: 1rem;
36
+ --kj-empty-state-desc-size: 0.875rem;
37
+ }
38
+
39
+ .kj-empty-state[data-size="lg"] {
40
+ --kj-empty-state-padding-y: var(--kj-space-3xl, 3rem);
41
+ --kj-empty-state-padding-x: var(--kj-space-2xl, 2rem);
42
+ --kj-empty-state-gap: var(--kj-space-lg, 1rem);
43
+ --kj-empty-state-icon-size: 4.5rem;
44
+ --kj-empty-state-title-size: 1.5rem;
45
+ --kj-empty-state-desc-size: 1rem;
46
+ }
47
+
48
+ .kj-empty-state[data-variant="error"] {
49
+ --kj-empty-state-accent: var(--kj-fg-danger, #b91c1c);
50
+ }
51
+ .kj-empty-state[data-variant="error"] .kj-empty-state-icon {
52
+ color: var(--kj-empty-state-accent);
53
+ }
54
+
55
+ .kj-empty-state-icon {
56
+ display: inline-flex;
57
+ align-items: center;
58
+ justify-content: center;
59
+ width: var(--kj-empty-state-icon-size);
60
+ height: var(--kj-empty-state-icon-size);
61
+ color: var(--kj-empty-state-muted-fg);
62
+ line-height: 1;
63
+ }
64
+ .kj-empty-state-icon svg,
65
+ .kj-empty-state-icon img {
66
+ width: 100%;
67
+ height: 100%;
68
+ display: block;
69
+ }
70
+
71
+ .kj-empty-state-title {
72
+ font: 600 var(--kj-empty-state-title-size) / 1.3 var(--kj-font-sans);
73
+ color: var(--kj-empty-state-fg);
74
+ margin: 0;
75
+ max-width: var(--kj-empty-state-max-width);
76
+ }
77
+
78
+ .kj-empty-state-description {
79
+ font: var(--kj-empty-state-desc-size) / 1.5 var(--kj-font-sans);
80
+ color: var(--kj-empty-state-muted-fg);
81
+ margin: 0;
82
+ max-width: var(--kj-empty-state-max-width);
83
+ }
84
+
85
+ .kj-empty-state-actions {
86
+ display: flex;
87
+ flex-direction: column;
88
+ align-items: center;
89
+ gap: var(--kj-space-sm, 0.5rem);
90
+ margin-top: var(--kj-space-sm, 0.5rem);
91
+ }
92
+
93
+ .kj-empty-state-actions__primary {
94
+ display: flex;
95
+ align-items: center;
96
+ justify-content: center;
97
+ gap: var(--kj-space-sm, 0.5rem);
98
+ flex-wrap: wrap;
99
+ }
100
+
101
+ .kj-empty-state-actions__secondary {
102
+ display: none;
103
+ align-items: center;
104
+ justify-content: center;
105
+ gap: var(--kj-space-sm, 0.5rem);
106
+ font-size: 0.8125rem;
107
+ color: var(--kj-empty-state-muted-fg);
108
+ }
109
+
110
+ .kj-empty-state-actions[data-has-secondary] .kj-empty-state-actions__secondary,
111
+ .kj-empty-state-actions:has(.kj-empty-state-actions__secondary > *) .kj-empty-state-actions__secondary {
112
+ display: flex;
113
+ }
114
+ }
@@ -0,0 +1,148 @@
1
+ /* ─────────────────────────────────────────────────────────────
2
+ .kj-field — vertical-stack form-row container.
3
+ The wrapper itself is `display: contents`-style transparent;
4
+ .kj-field renders the actual flex container so projected
5
+ children participate in the stack without an extra div.
6
+ ──────────────────────────────────────────────────────────── */
7
+
8
+ @layer kj.component {
9
+ kj-field.kj-field {
10
+ --kj-field-gap: var(--kj-space-xs);
11
+ --kj-field-label-fg: var(--kj-fg-default);
12
+ --kj-field-label-font: var(--kj-font-sans);
13
+ --kj-field-label-font-size: var(--kj-text-sm);
14
+ --kj-field-label-weight: 500;
15
+ --kj-field-help-fg: var(--kj-fg-muted);
16
+ --kj-field-help-font-size: var(--kj-text-xs);
17
+ --kj-field-error-fg: var(--kj-fg-danger);
18
+ --kj-field-error-font-size: var(--kj-text-xs);
19
+ --kj-field-required-fg: var(--kj-fg-danger);
20
+ --kj-field-disabled-opacity: 0.55;
21
+
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: var(--kj-field-gap);
25
+ width: 100%;
26
+ }
27
+
28
+ kj-field.kj-field[data-orientation="horizontal"] {
29
+ flex-direction: row;
30
+ align-items: center;
31
+ gap: var(--kj-space-md);
32
+ }
33
+
34
+ kj-field.kj-field[data-disabled] {
35
+ opacity: var(--kj-field-disabled-opacity);
36
+ cursor: not-allowed;
37
+ }
38
+
39
+ /* Label */
40
+ .kj-field-label {
41
+ color: var(--kj-field-label-fg);
42
+ font: var(--kj-field-label-weight) var(--kj-field-label-font-size) / 1.4
43
+ var(--kj-field-label-font);
44
+ }
45
+ .kj-field-label[data-required]::after {
46
+ content: " *";
47
+ color: var(--kj-field-required-fg);
48
+ /* Aria-hidden via CSS — the * is purely visual; aria-required carries
49
+ semantics on the inner control. */
50
+ }
51
+ .kj-field-label[data-invalid] {
52
+ color: var(--kj-field-error-fg);
53
+ }
54
+
55
+ /* Help / description */
56
+ .kj-field-help {
57
+ color: var(--kj-field-help-fg);
58
+ font: var(--kj-field-help-font-size) / 1.4 var(--kj-font-sans);
59
+ }
60
+
61
+ /* Error */
62
+ .kj-field-error {
63
+ color: var(--kj-field-error-fg);
64
+ font: var(--kj-field-error-font-size) / 1.4 var(--kj-font-sans);
65
+ }
66
+
67
+ /* Reserved error slot — keeps one text line of height while valid so the
68
+ error appearing/disappearing never shifts the surrounding layout. */
69
+ .kj-field-error[data-reserve] {
70
+ display: block;
71
+ min-height: calc(var(--kj-field-error-font-size) * 1.4);
72
+ }
73
+ .kj-field-error[data-hidden] {
74
+ visibility: hidden;
75
+ }
76
+
77
+ /* Compound input layout */
78
+ .kj-field-group {
79
+ --kj-field-group-bg: var(--kj-bg-field);
80
+ --kj-field-group-fg: var(--kj-fg-default);
81
+ --kj-field-group-border-color: var(--kj-border-default);
82
+ --kj-field-group-radius: var(--kj-radius-field);
83
+ --kj-field-group-addon-fg: var(--kj-fg-muted);
84
+ --kj-field-group-addon-bg: var(--kj-bg-surface);
85
+ --kj-field-group-padding-x: var(--kj-space-md);
86
+
87
+ display: inline-flex;
88
+ align-items: stretch;
89
+ width: 100%;
90
+ background: var(--kj-field-group-bg);
91
+ color: var(--kj-field-group-fg);
92
+ border: var(--kj-border) solid var(--kj-field-group-border-color);
93
+ border-radius: var(--kj-field-group-radius);
94
+ overflow: hidden;
95
+ transition: var(--kj-transition);
96
+ }
97
+ .kj-field-group:focus-within {
98
+ border-color: var(--kj-border-focus, var(--kj-bg-primary));
99
+ outline: 2px solid var(--kj-bg-primary);
100
+ outline-offset: -2px;
101
+ }
102
+ .kj-field-group[data-invalid] {
103
+ border-color: var(--kj-border-danger, var(--kj-fg-danger));
104
+ }
105
+ .kj-field-group[data-disabled] {
106
+ opacity: var(--kj-field-disabled-opacity);
107
+ cursor: not-allowed;
108
+ }
109
+
110
+ .kj-field-group__prefix,
111
+ .kj-field-group__suffix {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ padding: 0 var(--kj-field-group-padding-x);
115
+ color: var(--kj-field-group-addon-fg);
116
+ background: var(--kj-field-group-addon-bg);
117
+ font: var(--kj-text-sm) / 1 var(--kj-font-sans);
118
+ white-space: nowrap;
119
+ }
120
+ /* Hide empty addon slots so the layout collapses cleanly when only one
121
+ side is used. The :empty selector handles the comment-only / no-content
122
+ case in projected slots. */
123
+ .kj-field-group__prefix:empty,
124
+ .kj-field-group__suffix:empty {
125
+ display: none;
126
+ }
127
+
128
+ .kj-field-group__control {
129
+ display: inline-flex;
130
+ flex: 1 1 auto;
131
+ min-width: 0;
132
+ }
133
+ /* Inner controls inside a group should drop their own border / radius and
134
+ fill the group's box. Targeting common inner-control classes; the
135
+ consumer is responsible for ensuring their custom controls cooperate. */
136
+ .kj-field-group__control > .kj-input,
137
+ .kj-field-group__control > input,
138
+ .kj-field-group__control > kj-input,
139
+ .kj-field-group__control > kj-input > .kj-input {
140
+ border: 0;
141
+ border-radius: 0;
142
+ width: 100%;
143
+ }
144
+ .kj-field-group__control > .kj-input:focus-visible,
145
+ .kj-field-group__control > input:focus-visible {
146
+ outline: none;
147
+ }
148
+ }