gbs-add-block 2.0.4 → 2.3.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 (129) hide show
  1. package/.gbs/skills/gbs-components/SKILL.md +190 -134
  2. package/.gbs/skills/gbs-components/references/install.md +25 -3
  3. package/.gbs/skills/gbs-components/references/styling.md +246 -201
  4. package/CHANGELOG.md +74 -0
  5. package/README.md +157 -11
  6. package/index.cjs +212 -3
  7. package/package.json +41 -10
  8. package/schema/passport-v1.schema.json +204 -0
  9. package/source/beta-components/accordion/passport.json +259 -0
  10. package/source/beta-components/accordion/styles.css +207 -208
  11. package/source/beta-components/alert/passport.json +250 -0
  12. package/source/beta-components/alert/styles.css +154 -155
  13. package/source/beta-components/avatar/passport.json +294 -0
  14. package/source/beta-components/avatar/styles.css +201 -203
  15. package/source/beta-components/badge/passport.json +332 -0
  16. package/source/beta-components/badge/styles.css +203 -204
  17. package/source/beta-components/breadcrumb/passport.json +243 -0
  18. package/source/beta-components/breadcrumb/styles.css +138 -139
  19. package/source/beta-components/button/passport.json +402 -0
  20. package/source/beta-components/button/passport.manual.json +31 -0
  21. package/source/beta-components/button/styles.css +232 -233
  22. package/source/beta-components/card/passport.json +337 -0
  23. package/source/beta-components/card/styles.css +230 -231
  24. package/source/beta-components/checkbox/passport.json +456 -0
  25. package/source/beta-components/checkbox/styles.css +211 -212
  26. package/source/beta-components/combobox/passport.json +456 -0
  27. package/source/beta-components/combobox/styles.css +419 -417
  28. package/source/beta-components/data-grid/agent/coerce.ts +368 -0
  29. package/source/beta-components/data-grid/agent/contract.ts +410 -0
  30. package/source/beta-components/data-grid/agent/dataset.ts +92 -0
  31. package/source/beta-components/data-grid/agent/engine.ts +470 -0
  32. package/source/beta-components/data-grid/agent/executors.ts +155 -0
  33. package/source/beta-components/data-grid/agent/index.ts +79 -0
  34. package/source/beta-components/data-grid/agent/intent.ts +324 -0
  35. package/source/beta-components/data-grid/agent/operations.ts +335 -0
  36. package/source/beta-components/data-grid/agent/validate.ts +630 -0
  37. package/source/beta-components/data-grid/agent/webmcp.ts +107 -0
  38. package/source/beta-components/data-grid/index.ts +14 -7
  39. package/source/beta-components/data-grid/passport.json +1051 -0
  40. package/source/beta-components/data-grid/passport.manual.json +255 -0
  41. package/source/beta-components/data-grid/react/AskGrid.tsx +164 -0
  42. package/source/beta-components/data-grid/react/DataGrid.tsx +39 -0
  43. package/source/beta-components/data-grid/styles.css +874 -717
  44. package/source/beta-components/date-picker/passport.json +407 -0
  45. package/source/beta-components/date-picker/styles.css +445 -446
  46. package/source/beta-components/dialog/passport.json +344 -0
  47. package/source/beta-components/dialog/styles.css +280 -278
  48. package/source/beta-components/file-uploader/passport.json +518 -0
  49. package/source/beta-components/file-uploader/styles.css +394 -395
  50. package/source/beta-components/input/passport.json +536 -0
  51. package/source/beta-components/input/styles.css +295 -296
  52. package/source/beta-components/menu/passport.json +322 -0
  53. package/source/beta-components/menu/styles.css +224 -222
  54. package/source/beta-components/modal/passport.json +289 -0
  55. package/source/beta-components/modal/styles.css +241 -239
  56. package/source/beta-components/number-input/passport.json +541 -0
  57. package/source/beta-components/number-input/styles.css +230 -231
  58. package/source/beta-components/popover/passport.json +238 -0
  59. package/source/beta-components/popover/styles.css +148 -146
  60. package/source/beta-components/progress/passport.json +270 -0
  61. package/source/beta-components/progress/styles.css +200 -202
  62. package/source/beta-components/radio-group/passport.json +477 -0
  63. package/source/beta-components/radio-group/styles.css +241 -242
  64. package/source/beta-components/shared/core/agent/adapter.ts +65 -0
  65. package/source/beta-components/shared/core/agent/history.ts +120 -0
  66. package/source/beta-components/shared/core/agent/index.ts +46 -0
  67. package/source/beta-components/shared/core/agent/numbers.ts +217 -0
  68. package/source/beta-components/shared/core/agent/schema.ts +180 -0
  69. package/source/beta-components/shared/core/agent/types.ts +169 -0
  70. package/source/beta-components/shared/core/agent/webmcp.ts +328 -0
  71. package/source/beta-components/shared/index.ts +9 -0
  72. package/source/beta-components/shared/react/GramproAIProvider.tsx +50 -0
  73. package/source/beta-components/shared/react/useAskAgent.ts +217 -0
  74. package/source/beta-components/shared/styles.css +79 -0
  75. package/source/beta-components/shared/version.json +4 -4
  76. package/source/beta-components/shared/version.ts +6 -6
  77. package/source/beta-components/skeleton/passport.json +251 -0
  78. package/source/beta-components/skeleton/styles.css +185 -186
  79. package/source/beta-components/spinner/passport.json +245 -0
  80. package/source/beta-components/spinner/styles.css +145 -146
  81. package/source/beta-components/switch/passport.json +421 -0
  82. package/source/beta-components/switch/styles.css +194 -196
  83. package/source/beta-components/tabs/passport.json +315 -0
  84. package/source/beta-components/tabs/styles.css +234 -235
  85. package/source/beta-components/textarea/passport.json +382 -0
  86. package/source/beta-components/textarea/styles.css +158 -159
  87. package/source/beta-components/toaster/passport.json +221 -0
  88. package/source/beta-components/toaster/styles.css +282 -283
  89. package/source/beta-components/tooltip/passport.json +170 -0
  90. package/source/beta-components/tooltip/styles.css +71 -72
  91. package/tools/env.cjs +61 -0
  92. package/tools/passport/cli.cjs +79 -0
  93. package/tools/passport/extract.cjs +493 -0
  94. package/tools/passport/index.cjs +185 -0
  95. package/tools/passport/merge.cjs +131 -0
  96. package/tools/passport/policy.cjs +65 -0
  97. package/tools/passport/validate.cjs +277 -0
  98. package/tools/ts-require.cjs +79 -0
  99. package/source/beta-components/accordion/__tests__/core.test.ts +0 -58
  100. package/source/beta-components/alert/__tests__/core.test.ts +0 -17
  101. package/source/beta-components/avatar/__tests__/core.test.ts +0 -88
  102. package/source/beta-components/badge/__tests__/core.test.ts +0 -46
  103. package/source/beta-components/breadcrumb/__tests__/core.test.ts +0 -58
  104. package/source/beta-components/button/__tests__/core.test.ts +0 -31
  105. package/source/beta-components/card/__tests__/core.test.ts +0 -57
  106. package/source/beta-components/checkbox/__tests__/core.test.ts +0 -40
  107. package/source/beta-components/combobox/__tests__/core.test.ts +0 -134
  108. package/source/beta-components/data-grid/__tests__/core.test.ts +0 -356
  109. package/source/beta-components/data-grid/__tests__/export.test.ts +0 -70
  110. package/source/beta-components/data-grid/__tests__/pdf.test.ts +0 -209
  111. package/source/beta-components/date-picker/__tests__/core.test.ts +0 -273
  112. package/source/beta-components/dialog/__tests__/core.test.ts +0 -86
  113. package/source/beta-components/file-uploader/__tests__/core.test.ts +0 -395
  114. package/source/beta-components/input/__tests__/core.test.ts +0 -75
  115. package/source/beta-components/menu/__tests__/core.test.ts +0 -120
  116. package/source/beta-components/modal/__tests__/core.test.ts +0 -55
  117. package/source/beta-components/number-input/__tests__/core.test.ts +0 -151
  118. package/source/beta-components/progress/__tests__/core.test.ts +0 -56
  119. package/source/beta-components/radio-group/__tests__/core.test.ts +0 -64
  120. package/source/beta-components/shared/__tests__/boundaries.test.ts +0 -95
  121. package/source/beta-components/shared/__tests__/core.test.ts +0 -55
  122. package/source/beta-components/shared/__tests__/position.test.ts +0 -143
  123. package/source/beta-components/skeleton/__tests__/core.test.ts +0 -41
  124. package/source/beta-components/spinner/__tests__/core.test.ts +0 -48
  125. package/source/beta-components/switch/__tests__/core.test.ts +0 -64
  126. package/source/beta-components/tabs/__tests__/core.test.ts +0 -51
  127. package/source/beta-components/textarea/__tests__/core.test.ts +0 -38
  128. package/source/beta-components/toaster/__tests__/core.test.ts +0 -256
  129. package/source/beta-components/tooltip/__tests__/core.test.ts +0 -42
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "../../../schema/passport-v1.schema.json",
3
+ "component": "Button",
4
+ "purpose": "Trigger an action. Not for navigation unless `render` supplies a link element.",
5
+ "intentDomains": ["ActionIntent"],
6
+ "accessibility": {
7
+ "supplied": [
8
+ "native <button> semantics, including Enter and Space activation",
9
+ "disabled state via the native attribute",
10
+ "focus-visible ring",
11
+ "the spinner is aria-hidden; loadingText is announced"
12
+ ],
13
+ "required": [
14
+ "aria-label when the button is icon-only (`icon` with no children)",
15
+ "type=\"submit\" on the button that submits a form; the default is \"button\""
16
+ ]
17
+ },
18
+ "composition": {
19
+ "mustNotContain": ["Button", "a"],
20
+ "notes": "Nesting interactive elements is invalid HTML and traps keyboard focus. Use `render` to change the element instead of wrapping it."
21
+ },
22
+ "safeMutations": {
23
+ "allowed": ["variant", "size", "fullWidth", "leading", "trailing", "icon", "loadingText"],
24
+ "forbidden": ["type", "onClick", "render", "loading", "disabled"],
25
+ "rationale": "Appearance is safe for an agent to change. `type` and `onClick` change behaviour; `loading` and `disabled` are owned by the component's own async handling."
26
+ },
27
+ "propNotes": {
28
+ "render": "Escape hatch for router links. Changes the rendered element, so composition rules apply to whatever it returns.",
29
+ "loading": "Managed automatically when `onClick` returns a promise. Setting it manually opts out of that."
30
+ }
31
+ }
@@ -1,233 +1,232 @@
1
- /*
2
- * Button styles.
3
- *
4
- * Tokens read the shared --gbs-* variables when they are set on an ancestor
5
- * (set them on :root to theme every component at once) and fall back to the
6
- * same default palette otherwise. Rules live in the `components` layer, so utility classes passed
7
- * through `className` / `classNames` override them.
8
- */
9
- @layer theme, base, components, utilities;
10
-
11
- @layer components {
12
- .bt-root {
13
- --bt-bg: var(--gbs-bg, var(--dg-bg, light-dark(#ffffff, #0b0b0e)));
14
- --bt-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
15
- --bt-border: var(--gbs-border, var(--dg-border, light-dark(#e4e4e7, #27272a)));
16
- --bt-hover: var(--gbs-hover, var(--dg-hover, light-dark(#f4f4f5, #1f1f23)));
17
- --bt-subtle: var(--gbs-subtle, light-dark(#f4f4f5, #1c1c20));
18
- --bt-accent: var(--gbs-accent, var(--dg-accent, light-dark(#2563eb, #60a5fa)));
19
- --bt-accent-fg: var(--gbs-accent-fg, var(--dg-accent-fg, light-dark(#ffffff, #0b1220)));
20
- --bt-danger: var(--gbs-danger, var(--dg-danger, light-dark(#dc2626, #f87171)));
21
- --bt-danger-fg: var(--gbs-danger-fg, light-dark(#ffffff, #1c0606));
22
- --bt-focus: var(--gbs-focus, var(--dg-focus, light-dark(#2563eb, #60a5fa)));
23
- --bt-radius: var(--gbs-radius, var(--dg-radius, 8px));
24
- --bt-font-size: var(--gbs-font-size, var(--dg-font-size, 13px));
25
- --bt-height: 36px;
26
- --bt-px: 14px;
27
- --bt-gap: 8px;
28
-
29
- /* Per variant. */
30
- --bt-fill: var(--bt-accent);
31
- --bt-fill-hover: color-mix(in oklab, var(--bt-accent), var(--bt-fg) 12%);
32
- --bt-ink: var(--bt-accent-fg);
33
- --bt-line: var(--bt-accent);
34
-
35
- color-scheme: inherit;
36
- box-sizing: border-box;
37
- position: relative;
38
- display: inline-grid;
39
- place-items: center;
40
- height: var(--bt-height);
41
- padding: 0 var(--bt-px);
42
- border: 1px solid var(--bt-line);
43
- border-radius: var(--bt-radius);
44
- background: var(--bt-fill);
45
- color: var(--bt-ink);
46
- font: inherit;
47
- font-size: var(--bt-font-size);
48
- font-weight: 500;
49
- line-height: 1;
50
- white-space: nowrap;
51
- text-decoration: none;
52
- vertical-align: middle;
53
- cursor: pointer;
54
- user-select: none;
55
- -webkit-tap-highlight-color: transparent;
56
- transition:
57
- background-color 120ms ease,
58
- border-color 120ms ease,
59
- color 120ms ease,
60
- scale 120ms ease;
61
- }
62
-
63
- :where(.dark, [data-theme="dark"]) .bt-root {
64
- color-scheme: dark;
65
- }
66
- :where(.light, [data-theme="light"]) .bt-root {
67
- color-scheme: light;
68
- }
69
-
70
- :where(.bt-root) *,
71
- :where(.bt-root) *::before,
72
- :where(.bt-root) *::after {
73
- box-sizing: border-box;
74
- }
75
-
76
- /* ------------------------------------------------------------ variants */
77
-
78
- .bt-root[data-variant="secondary"] {
79
- --bt-fill: var(--bt-subtle);
80
- --bt-fill-hover: color-mix(in oklab, var(--bt-subtle), var(--bt-fg) 8%);
81
- --bt-ink: var(--bt-fg);
82
- --bt-line: transparent;
83
- }
84
- .bt-root[data-variant="outline"] {
85
- --bt-fill: var(--bt-bg);
86
- --bt-fill-hover: var(--bt-hover);
87
- --bt-ink: var(--bt-fg);
88
- --bt-line: var(--bt-border);
89
- }
90
- .bt-root[data-variant="ghost"] {
91
- --bt-fill: transparent;
92
- --bt-fill-hover: var(--bt-hover);
93
- --bt-ink: var(--bt-fg);
94
- --bt-line: transparent;
95
- }
96
- .bt-root[data-variant="danger"] {
97
- --bt-fill: var(--bt-danger);
98
- --bt-fill-hover: color-mix(in oklab, var(--bt-danger), var(--bt-fg) 12%);
99
- --bt-ink: var(--bt-danger-fg);
100
- --bt-line: var(--bt-danger);
101
- }
102
- .bt-root[data-variant="link"] {
103
- --bt-fill: transparent;
104
- --bt-fill-hover: transparent;
105
- --bt-ink: var(--bt-accent);
106
- --bt-line: transparent;
107
- --bt-px: 0px;
108
- height: auto;
109
- text-underline-offset: 3px;
110
- }
111
- .bt-root[data-variant="link"]:hover:not([aria-disabled="true"], :disabled) {
112
- text-decoration: underline;
113
- }
114
-
115
- /* --------------------------------------------------------------- sizes */
116
-
117
- .bt-root[data-size="sm"] {
118
- --bt-height: 30px;
119
- --bt-px: 10px;
120
- --bt-gap: 6px;
121
- --bt-font-size: 12px;
122
- }
123
- .bt-root[data-size="lg"] {
124
- --bt-height: 44px;
125
- --bt-px: 18px;
126
- --bt-gap: 10px;
127
- --bt-font-size: 14px;
128
- }
129
-
130
- /* -------------------------------------------------------------- states */
131
-
132
- .bt-root:hover:not([aria-disabled="true"], :disabled) {
133
- background: var(--bt-fill-hover);
134
- }
135
- .bt-root:active:not([aria-disabled="true"], :disabled) {
136
- scale: 0.98;
137
- }
138
- .bt-root:focus-visible {
139
- outline: 2px solid var(--bt-focus);
140
- outline-offset: 2px;
141
- }
142
- .bt-root:disabled,
143
- .bt-root[aria-disabled="true"]:not([data-busy]) {
144
- opacity: 0.5;
145
- cursor: not-allowed;
146
- }
147
- .bt-root[data-busy] {
148
- cursor: progress;
149
- }
150
-
151
- .bt-root[data-icon-only] {
152
- width: var(--bt-height);
153
- padding: 0;
154
- }
155
- .bt-root[data-full-width] {
156
- width: 100%;
157
- }
158
-
159
- /* ------------------------------------------------------------- content */
160
-
161
- .bt-content,
162
- .bt-spinner {
163
- grid-area: 1 / 1;
164
- display: inline-flex;
165
- align-items: center;
166
- justify-content: center;
167
- gap: var(--bt-gap);
168
- min-width: 0;
169
- }
170
- /* The label keeps its space while the spinner sits on top… */
171
- .bt-content[data-hidden] {
172
- visibility: hidden;
173
- }
174
- /* …unless loading text replaces it. */
175
- .bt-root[data-loading-text] .bt-content {
176
- display: none;
177
- }
178
-
179
- .bt-icon {
180
- display: inline-flex;
181
- flex: none;
182
- }
183
- .bt-icon > svg {
184
- width: 1.15em;
185
- height: 1.15em;
186
- }
187
-
188
- .bt-spinner-ring {
189
- width: 1.15em;
190
- height: 1.15em;
191
- fill: none;
192
- stroke: currentColor;
193
- stroke-width: 2.5;
194
- stroke-linecap: round;
195
- stroke-dasharray: 30 100;
196
- animation: bt-rotate 0.8s linear infinite;
197
- }
198
- @keyframes bt-rotate {
199
- to {
200
- transform: rotate(360deg);
201
- }
202
- }
203
-
204
- .bt-sr-only {
205
- position: absolute;
206
- width: 1px;
207
- height: 1px;
208
- margin: -1px;
209
- padding: 0;
210
- overflow: hidden;
211
- clip-path: inset(50%);
212
- white-space: nowrap;
213
- border: 0;
214
- }
215
-
216
- @media (prefers-reduced-motion: reduce) {
217
- .bt-root {
218
- transition: none;
219
- }
220
- .bt-root:active:not([aria-disabled="true"], :disabled) {
221
- scale: none;
222
- }
223
- .bt-spinner-ring {
224
- animation-duration: 2.4s;
225
- }
226
- }
227
-
228
- @media (forced-colors: active) {
229
- .bt-root {
230
- border-color: ButtonText;
231
- }
232
- }
233
- }
1
+ /*
2
+ * Button styles.
3
+ *
4
+ * Tokens read the shared --gbs-* variables when they are set on an ancestor
5
+ * (set them on :root to theme every component at once) and fall back to the
6
+ * same default palette otherwise. Rules are unlayered: they beat a framework
7
+ * reset on specificity, and lose to anything you pass through `className`.
8
+ * With Tailwind v4, import this file after the framework and inside its
9
+ * components layer - see the README.
10
+ */
11
+
12
+ .bt-root {
13
+ --bt-bg: var(--gbs-bg, var(--dg-bg, light-dark(#ffffff, #0b0b0e)));
14
+ --bt-fg: var(--gbs-fg, var(--dg-fg, light-dark(#18181b, #f4f4f5)));
15
+ --bt-border: var(--gbs-border, var(--dg-border, light-dark(#e4e4e7, #27272a)));
16
+ --bt-hover: var(--gbs-hover, var(--dg-hover, light-dark(#f4f4f5, #1f1f23)));
17
+ --bt-subtle: var(--gbs-subtle, light-dark(#f4f4f5, #1c1c20));
18
+ --bt-accent: var(--gbs-accent, var(--dg-accent, light-dark(#2563eb, #60a5fa)));
19
+ --bt-accent-fg: var(--gbs-accent-fg, var(--dg-accent-fg, light-dark(#ffffff, #0b1220)));
20
+ --bt-danger: var(--gbs-danger, var(--dg-danger, light-dark(#dc2626, #f87171)));
21
+ --bt-danger-fg: var(--gbs-danger-fg, light-dark(#ffffff, #1c0606));
22
+ --bt-focus: var(--gbs-focus, var(--dg-focus, light-dark(#2563eb, #60a5fa)));
23
+ --bt-radius: var(--gbs-radius, var(--dg-radius, 8px));
24
+ --bt-font-size: var(--gbs-font-size, var(--dg-font-size, 13px));
25
+ --bt-height: 36px;
26
+ --bt-px: 14px;
27
+ --bt-gap: 8px;
28
+
29
+ /* Per variant. */
30
+ --bt-fill: var(--bt-accent);
31
+ --bt-fill-hover: color-mix(in oklab, var(--bt-accent), var(--bt-fg) 12%);
32
+ --bt-ink: var(--bt-accent-fg);
33
+ --bt-line: var(--bt-accent);
34
+
35
+ color-scheme: inherit;
36
+ box-sizing: border-box;
37
+ position: relative;
38
+ display: inline-grid;
39
+ place-items: center;
40
+ height: var(--bt-height);
41
+ padding: 0 var(--bt-px);
42
+ border: 1px solid var(--bt-line);
43
+ border-radius: var(--bt-radius);
44
+ background: var(--bt-fill);
45
+ color: var(--bt-ink);
46
+ font: inherit;
47
+ font-size: var(--bt-font-size);
48
+ font-weight: 500;
49
+ line-height: 1;
50
+ white-space: nowrap;
51
+ text-decoration: none;
52
+ vertical-align: middle;
53
+ cursor: pointer;
54
+ user-select: none;
55
+ -webkit-tap-highlight-color: transparent;
56
+ transition:
57
+ background-color 120ms ease,
58
+ border-color 120ms ease,
59
+ color 120ms ease,
60
+ scale 120ms ease;
61
+ }
62
+
63
+ :where(.dark, [data-theme="dark"]) .bt-root {
64
+ color-scheme: dark;
65
+ }
66
+ :where(.light, [data-theme="light"]) .bt-root {
67
+ color-scheme: light;
68
+ }
69
+
70
+ :where(.bt-root) *,
71
+ :where(.bt-root) *::before,
72
+ :where(.bt-root) *::after {
73
+ box-sizing: border-box;
74
+ }
75
+
76
+ /* ------------------------------------------------------------ variants */
77
+
78
+ .bt-root[data-variant="secondary"] {
79
+ --bt-fill: var(--bt-subtle);
80
+ --bt-fill-hover: color-mix(in oklab, var(--bt-subtle), var(--bt-fg) 8%);
81
+ --bt-ink: var(--bt-fg);
82
+ --bt-line: transparent;
83
+ }
84
+ .bt-root[data-variant="outline"] {
85
+ --bt-fill: var(--bt-bg);
86
+ --bt-fill-hover: var(--bt-hover);
87
+ --bt-ink: var(--bt-fg);
88
+ --bt-line: var(--bt-border);
89
+ }
90
+ .bt-root[data-variant="ghost"] {
91
+ --bt-fill: transparent;
92
+ --bt-fill-hover: var(--bt-hover);
93
+ --bt-ink: var(--bt-fg);
94
+ --bt-line: transparent;
95
+ }
96
+ .bt-root[data-variant="danger"] {
97
+ --bt-fill: var(--bt-danger);
98
+ --bt-fill-hover: color-mix(in oklab, var(--bt-danger), var(--bt-fg) 12%);
99
+ --bt-ink: var(--bt-danger-fg);
100
+ --bt-line: var(--bt-danger);
101
+ }
102
+ .bt-root[data-variant="link"] {
103
+ --bt-fill: transparent;
104
+ --bt-fill-hover: transparent;
105
+ --bt-ink: var(--bt-accent);
106
+ --bt-line: transparent;
107
+ --bt-px: 0px;
108
+ height: auto;
109
+ text-underline-offset: 3px;
110
+ }
111
+ .bt-root[data-variant="link"]:hover:not([aria-disabled="true"], :disabled) {
112
+ text-decoration: underline;
113
+ }
114
+
115
+ /* --------------------------------------------------------------- sizes */
116
+
117
+ .bt-root[data-size="sm"] {
118
+ --bt-height: 30px;
119
+ --bt-px: 10px;
120
+ --bt-gap: 6px;
121
+ --bt-font-size: 12px;
122
+ }
123
+ .bt-root[data-size="lg"] {
124
+ --bt-height: 44px;
125
+ --bt-px: 18px;
126
+ --bt-gap: 10px;
127
+ --bt-font-size: 14px;
128
+ }
129
+
130
+ /* -------------------------------------------------------------- states */
131
+
132
+ .bt-root:hover:not([aria-disabled="true"], :disabled) {
133
+ background: var(--bt-fill-hover);
134
+ }
135
+ .bt-root:active:not([aria-disabled="true"], :disabled) {
136
+ scale: 0.98;
137
+ }
138
+ .bt-root:focus-visible {
139
+ outline: 2px solid var(--bt-focus);
140
+ outline-offset: 2px;
141
+ }
142
+ .bt-root:disabled,
143
+ .bt-root[aria-disabled="true"]:not([data-busy]) {
144
+ opacity: 0.5;
145
+ cursor: not-allowed;
146
+ }
147
+ .bt-root[data-busy] {
148
+ cursor: progress;
149
+ }
150
+
151
+ .bt-root[data-icon-only] {
152
+ width: var(--bt-height);
153
+ padding: 0;
154
+ }
155
+ .bt-root[data-full-width] {
156
+ width: 100%;
157
+ }
158
+
159
+ /* ------------------------------------------------------------- content */
160
+
161
+ .bt-content,
162
+ .bt-spinner {
163
+ grid-area: 1 / 1;
164
+ display: inline-flex;
165
+ align-items: center;
166
+ justify-content: center;
167
+ gap: var(--bt-gap);
168
+ min-width: 0;
169
+ }
170
+ /* The label keeps its space while the spinner sits on top… */
171
+ .bt-content[data-hidden] {
172
+ visibility: hidden;
173
+ }
174
+ /* …unless loading text replaces it. */
175
+ .bt-root[data-loading-text] .bt-content {
176
+ display: none;
177
+ }
178
+
179
+ .bt-icon {
180
+ display: inline-flex;
181
+ flex: none;
182
+ }
183
+ .bt-icon > svg {
184
+ width: 1.15em;
185
+ height: 1.15em;
186
+ }
187
+
188
+ .bt-spinner-ring {
189
+ width: 1.15em;
190
+ height: 1.15em;
191
+ fill: none;
192
+ stroke: currentColor;
193
+ stroke-width: 2.5;
194
+ stroke-linecap: round;
195
+ stroke-dasharray: 30 100;
196
+ animation: bt-rotate 0.8s linear infinite;
197
+ }
198
+ @keyframes bt-rotate {
199
+ to {
200
+ transform: rotate(360deg);
201
+ }
202
+ }
203
+
204
+ .bt-sr-only {
205
+ position: absolute;
206
+ width: 1px;
207
+ height: 1px;
208
+ margin: -1px;
209
+ padding: 0;
210
+ overflow: hidden;
211
+ clip-path: inset(50%);
212
+ white-space: nowrap;
213
+ border: 0;
214
+ }
215
+
216
+ @media (prefers-reduced-motion: reduce) {
217
+ .bt-root {
218
+ transition: none;
219
+ }
220
+ .bt-root:active:not([aria-disabled="true"], :disabled) {
221
+ scale: none;
222
+ }
223
+ .bt-spinner-ring {
224
+ animation-duration: 2.4s;
225
+ }
226
+ }
227
+
228
+ @media (forced-colors: active) {
229
+ .bt-root {
230
+ border-color: ButtonText;
231
+ }
232
+ }