@behivetech/atoms.button 0.0.0-stage → 0.4.2
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/README.md +54 -2
- package/button.example.tsx +17 -0
- package/button.module.scss +263 -0
- package/button.tsx +71 -0
- package/dist/index.cjs +210 -0
- package/dist/index.css +139 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +196 -0
- package/docs.json +64 -0
- package/index.ts +2 -0
- package/package.json +58 -3
package/README.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Button
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A flexible button component with variants, sizes, loading and disabled states.
|
|
4
|
+
|
|
5
|
+
## Variants
|
|
6
|
+
|
|
7
|
+
```jsx
|
|
8
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
9
|
+
<Button variant="primary">Primary</Button>
|
|
10
|
+
<Button variant="secondary">Secondary</Button>
|
|
11
|
+
<Button variant="ghost">Ghost</Button>
|
|
12
|
+
<Button variant="danger">Danger</Button>
|
|
13
|
+
</div>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Sizes
|
|
17
|
+
|
|
18
|
+
```jsx
|
|
19
|
+
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
|
|
20
|
+
<Button size="sm">Small</Button>
|
|
21
|
+
<Button size="md">Medium</Button>
|
|
22
|
+
<Button size="lg">Large</Button>
|
|
23
|
+
</div>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## States
|
|
27
|
+
|
|
28
|
+
```jsx
|
|
29
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
30
|
+
<Button loading>Loading</Button>
|
|
31
|
+
<Button disabled>Disabled</Button>
|
|
32
|
+
</div>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Icon-only
|
|
36
|
+
|
|
37
|
+
For buttons whose content is a single icon (glyph, `<svg>`, etc.) with no visible label, pass `iconOnly` and provide an `aria-label` for accessibility.
|
|
38
|
+
|
|
39
|
+
```jsx
|
|
40
|
+
<Button iconOnly aria-label="Delete" variant="danger">
|
|
41
|
+
✕
|
|
42
|
+
</Button>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Props
|
|
46
|
+
|
|
47
|
+
| Prop | Type | Default | Description |
|
|
48
|
+
| ----------- | ----------------------------------------- | --------- | -------------------------------------------------------------------------- |
|
|
49
|
+
| `variant` | `primary \| secondary \| ghost \| danger` | `primary` | Visual style |
|
|
50
|
+
| `size` | `sm \| md \| lg` | `md` | Button size |
|
|
51
|
+
| `loading` | `boolean` | `false` | Shows spinner, disables interaction |
|
|
52
|
+
| `iconOnly` | `boolean` | `false` | Square, padding-free layout for icon-only content — pair with `aria-label` |
|
|
53
|
+
| `disabled` | `boolean` | `false` | Disables the button |
|
|
54
|
+
| `children` | `ReactNode` | — | Button label |
|
|
55
|
+
| `className` | `string` | — | Additional class names |
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Button } from "./button.js";
|
|
2
|
+
|
|
3
|
+
export const PrimaryButton = () => <Button variant="primary">Primary</Button>;
|
|
4
|
+
export const SecondaryButton = () => (
|
|
5
|
+
<Button variant="secondary">Secondary</Button>
|
|
6
|
+
);
|
|
7
|
+
export const GhostButton = () => <Button variant="ghost">Ghost</Button>;
|
|
8
|
+
export const DangerButton = () => <Button variant="danger">Danger</Button>;
|
|
9
|
+
export const SmallButton = () => <Button size="sm">Small</Button>;
|
|
10
|
+
export const LargeButton = () => <Button size="lg">Large</Button>;
|
|
11
|
+
export const LoadingButton = () => <Button loading>Loading</Button>;
|
|
12
|
+
export const DisabledButton = () => <Button disabled>Disabled</Button>;
|
|
13
|
+
export const IconOnlyButton = () => (
|
|
14
|
+
<Button iconOnly aria-label="Delete" variant="danger">
|
|
15
|
+
✕
|
|
16
|
+
</Button>
|
|
17
|
+
);
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
// Material Design 3 button.
|
|
2
|
+
//
|
|
3
|
+
// The public API is unchanged — `variant` × `size`, plus `loading`, `iconOnly`
|
|
4
|
+
// and `asChild`. What changed is that every value now comes from an
|
|
5
|
+
// `--md-sys-*` token, so the component re-themes with the palette instead of
|
|
6
|
+
// carrying a brand of its own.
|
|
7
|
+
//
|
|
8
|
+
// Variant names map onto MD3's button types rather than being renamed, because
|
|
9
|
+
// the prop is part of this package's published API:
|
|
10
|
+
//
|
|
11
|
+
// primary -> Filled secondary -> Outlined
|
|
12
|
+
// ghost -> Text danger -> Filled, on the error role
|
|
13
|
+
//
|
|
14
|
+
// Each color falls back to the pre-MD3 `--color-*` name, which
|
|
15
|
+
// `cms.base-styles` aliases to the matching MD3 role. That keeps this working
|
|
16
|
+
// against an older base-styles instead of rendering unstyled.
|
|
17
|
+
//
|
|
18
|
+
// **Structure.** Modifiers belong to the root only — a child never carries
|
|
19
|
+
// `--sm`. Inside a modifier block, `&.BHT__Button` is the root element
|
|
20
|
+
// (compound) and `.BHT__Button` without the `&` is a descendant (a child node).
|
|
21
|
+
// Pseudo-class blocks (`&:hover`, `&:disabled`) are states rather than
|
|
22
|
+
// modifiers and stay unwrapped.
|
|
23
|
+
|
|
24
|
+
.BHT__Button {
|
|
25
|
+
// `isolation` keeps the state layer's stacking context local, so a button
|
|
26
|
+
// inside a positioned parent can't have its ::after escape behind a sibling.
|
|
27
|
+
position: relative;
|
|
28
|
+
isolation: isolate;
|
|
29
|
+
display: inline-flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
gap: var(--spacing-2, 0.5rem);
|
|
33
|
+
border: 1px solid transparent;
|
|
34
|
+
// MD3 buttons are pill-shaped. This is the single most visible change from
|
|
35
|
+
// the previous styling, which used the 6px `--radius-md`.
|
|
36
|
+
border-radius: var(--md-sys-shape-corner-full, 9999px);
|
|
37
|
+
font-family: var(--md-sys-typescale-label-large-font, var(--font-body));
|
|
38
|
+
font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
39
|
+
font-weight: var(--md-sys-typescale-label-large-weight, 500);
|
|
40
|
+
line-height: var(--md-sys-typescale-label-large-line-height, 1.25rem);
|
|
41
|
+
letter-spacing: var(--md-sys-typescale-label-large-tracking, 0.0071em);
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
white-space: nowrap;
|
|
44
|
+
text-decoration: none;
|
|
45
|
+
user-select: none;
|
|
46
|
+
transition:
|
|
47
|
+
background var(--md-sys-motion-duration-short-3, 150ms)
|
|
48
|
+
var(--md-sys-motion-easing-standard, ease),
|
|
49
|
+
color var(--md-sys-motion-duration-short-3, 150ms)
|
|
50
|
+
var(--md-sys-motion-easing-standard, ease),
|
|
51
|
+
border-color var(--md-sys-motion-duration-short-3, 150ms)
|
|
52
|
+
var(--md-sys-motion-easing-standard, ease);
|
|
53
|
+
|
|
54
|
+
// --- Children ------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
&__label {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__spinner {
|
|
62
|
+
display: inline-block;
|
|
63
|
+
width: 1em;
|
|
64
|
+
height: 1em;
|
|
65
|
+
border: 2px solid currentColor;
|
|
66
|
+
border-top-color: transparent;
|
|
67
|
+
border-radius: var(--md-sys-shape-corner-full, 9999px);
|
|
68
|
+
animation: button-spin 0.6s linear infinite;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// --- State layer ---------------------------------------------------------
|
|
72
|
+
//
|
|
73
|
+
// **This replaces six hardcoded brand colors and two `filter: brightness()`
|
|
74
|
+
// rules, and it is the whole reason the component re-themes.**
|
|
75
|
+
//
|
|
76
|
+
// MD3 expresses interaction as a translucent veil of the *content* color over
|
|
77
|
+
// the container. `currentColor` is already that content color in every
|
|
78
|
+
// variant — `on-primary` on a filled button, `primary` on an outlined or text
|
|
79
|
+
// one — so one rule serves all four variants and follows the palette for
|
|
80
|
+
// free. The old `rgba(247, 179, 52, 0.1)` was a fixed amber that stayed amber
|
|
81
|
+
// no matter what `--color-primary` was set to, and `filter: brightness()`
|
|
82
|
+
// lightens on a dark surface and washes out on a light one.
|
|
83
|
+
&::after {
|
|
84
|
+
content: "";
|
|
85
|
+
position: absolute;
|
|
86
|
+
inset: 0;
|
|
87
|
+
border-radius: inherit;
|
|
88
|
+
background: currentColor;
|
|
89
|
+
opacity: 0;
|
|
90
|
+
pointer-events: none;
|
|
91
|
+
transition: opacity var(--md-sys-motion-duration-short-2, 100ms)
|
|
92
|
+
var(--md-sys-motion-easing-standard, ease);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&:hover:not(:disabled)::after {
|
|
96
|
+
opacity: var(--md-sys-state-hover-opacity, 0.08);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&:focus-visible::after {
|
|
100
|
+
opacity: var(--md-sys-state-focus-opacity, 0.1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&:active:not(:disabled)::after {
|
|
104
|
+
opacity: var(--md-sys-state-pressed-opacity, 0.1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// --- Touch target --------------------------------------------------------
|
|
108
|
+
//
|
|
109
|
+
// **The component previously had no minimum target, and `sm` (32px) and the
|
|
110
|
+
// default `md` (40px) both sat under the 48dp floor.** Rather than inflating
|
|
111
|
+
// the visual size — which would reflow every layout already built on these
|
|
112
|
+
// buttons — an invisible pseudo-element extends the *hit area* to 48px while
|
|
113
|
+
// the button keeps its drawn height.
|
|
114
|
+
//
|
|
115
|
+
// Deliberately px, not rem. A touch target is a physical property of the
|
|
116
|
+
// finger, not of the type size, so it must not shrink when a reader sets a
|
|
117
|
+
// smaller font.
|
|
118
|
+
&::before {
|
|
119
|
+
content: "";
|
|
120
|
+
position: absolute;
|
|
121
|
+
left: 0;
|
|
122
|
+
right: 0;
|
|
123
|
+
top: 50%;
|
|
124
|
+
translate: 0 -50%;
|
|
125
|
+
height: 100%;
|
|
126
|
+
min-height: 48px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// --- Focus ---------------------------------------------------------------
|
|
130
|
+
//
|
|
131
|
+
// There was no focus style at all before this: a keyboard user had no idea
|
|
132
|
+
// which control they were on. `:focus-visible` rather than `:focus` so a
|
|
133
|
+
// pointer click doesn't leave a ring behind.
|
|
134
|
+
&:focus-visible {
|
|
135
|
+
outline: 3px solid var(--md-sys-color-secondary, var(--color-border-focus));
|
|
136
|
+
outline-offset: 2px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- Size modifiers ------------------------------------------------------
|
|
140
|
+
//
|
|
141
|
+
// Heights are unchanged, so existing layouts keep their rhythm; the 48px
|
|
142
|
+
// floor above is what makes the two smaller ones accessible.
|
|
143
|
+
&--sm {
|
|
144
|
+
&.BHT__Button {
|
|
145
|
+
padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);
|
|
146
|
+
min-height: 2rem;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&--md {
|
|
151
|
+
&.BHT__Button {
|
|
152
|
+
padding: var(--spacing-2, 0.5rem) var(--spacing-5, 1.25rem);
|
|
153
|
+
min-height: 2.5rem;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
&--lg {
|
|
158
|
+
&.BHT__Button {
|
|
159
|
+
font-size: var(--md-sys-typescale-title-medium-size, 1rem);
|
|
160
|
+
padding: var(--spacing-3, 0.75rem) var(--spacing-6, 1.5rem);
|
|
161
|
+
min-height: 3rem;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --- Variant modifiers ---------------------------------------------------
|
|
166
|
+
|
|
167
|
+
&--primary {
|
|
168
|
+
&.BHT__Button {
|
|
169
|
+
background: var(--md-sys-color-primary, var(--color-primary));
|
|
170
|
+
color: var(--md-sys-color-on-primary, var(--color-on-primary));
|
|
171
|
+
border-color: transparent;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
&--secondary {
|
|
176
|
+
&.BHT__Button {
|
|
177
|
+
background: transparent;
|
|
178
|
+
color: var(--md-sys-color-primary, var(--color-primary));
|
|
179
|
+
border-color: var(--md-sys-color-outline, var(--color-border-strong));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&--ghost {
|
|
184
|
+
&.BHT__Button {
|
|
185
|
+
background: transparent;
|
|
186
|
+
color: var(--md-sys-color-primary, var(--color-primary));
|
|
187
|
+
border-color: transparent;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
&--danger {
|
|
192
|
+
&.BHT__Button {
|
|
193
|
+
background: var(--md-sys-color-error, var(--color-error));
|
|
194
|
+
color: var(--md-sys-color-on-error, #ffffff);
|
|
195
|
+
border-color: transparent;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// --- Icon-only -----------------------------------------------------------
|
|
200
|
+
//
|
|
201
|
+
// The width rules previously read `.Button--sm` and the label rule
|
|
202
|
+
// `.Button__label`, both missing the `BHT__` the markup actually carries, so
|
|
203
|
+
// every rule in this block matched nothing and icon-only buttons had no
|
|
204
|
+
// width at all.
|
|
205
|
+
&--icon-only {
|
|
206
|
+
&.BHT__Button {
|
|
207
|
+
padding: 0;
|
|
208
|
+
|
|
209
|
+
&--sm {
|
|
210
|
+
width: 2rem;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
&--md {
|
|
214
|
+
width: 2.5rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
&--lg {
|
|
218
|
+
width: 3rem;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.BHT__Button {
|
|
223
|
+
&__label {
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// --- Disabled / loading --------------------------------------------------
|
|
232
|
+
//
|
|
233
|
+
// MD3 expresses disabled as 38% of the content color on a 12% container
|
|
234
|
+
// rather than a blanket opacity, but a flat `opacity` is what the rest of
|
|
235
|
+
// this library uses and changing it here alone would make Button the odd one
|
|
236
|
+
// out. Worth revisiting across the set, not in isolation.
|
|
237
|
+
&--disabled {
|
|
238
|
+
&.BHT__Button {
|
|
239
|
+
opacity: 0.45;
|
|
240
|
+
cursor: not-allowed;
|
|
241
|
+
pointer-events: none;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
&:disabled {
|
|
246
|
+
opacity: 0.45;
|
|
247
|
+
cursor: not-allowed;
|
|
248
|
+
pointer-events: none;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
&--loading {
|
|
252
|
+
&.BHT__Button {
|
|
253
|
+
cursor: wait;
|
|
254
|
+
pointer-events: none;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@keyframes button-spin {
|
|
260
|
+
to {
|
|
261
|
+
transform: rotate(360deg);
|
|
262
|
+
}
|
|
263
|
+
}
|
package/button.tsx
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes } from "react";
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { getClassName } from "@bht-component-registry/class-names";
|
|
4
|
+
import styles from "./button.module.scss";
|
|
5
|
+
|
|
6
|
+
export type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
|
|
7
|
+
export type ButtonSize = "sm" | "md" | "lg";
|
|
8
|
+
|
|
9
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
10
|
+
/** Controls the color/style treatment; defaults to primary */
|
|
11
|
+
variant?: ButtonVariant;
|
|
12
|
+
/** Controls the size; defaults to md */
|
|
13
|
+
size?: ButtonSize;
|
|
14
|
+
/** Shows a spinner and disables the button while an action is in flight */
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
/** Renders the button as a square icon-only control with no visible label spacing */
|
|
17
|
+
iconOnly?: boolean;
|
|
18
|
+
/** Additional class names to merge with the component root element */
|
|
19
|
+
className?: string;
|
|
20
|
+
/** Button label/content */
|
|
21
|
+
children?: React.ReactNode;
|
|
22
|
+
/** Renders the button's props onto its single child element (via Radix `Slot`) instead of a `<button>` */
|
|
23
|
+
asChild?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Button = ({
|
|
27
|
+
variant = "primary",
|
|
28
|
+
size = "md",
|
|
29
|
+
loading = false,
|
|
30
|
+
iconOnly = false,
|
|
31
|
+
disabled,
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
34
|
+
asChild = false,
|
|
35
|
+
...rest
|
|
36
|
+
}: ButtonProps) => {
|
|
37
|
+
const [rootClass, getChildClass] = getClassName({
|
|
38
|
+
className,
|
|
39
|
+
rootClass: "BHT__Button",
|
|
40
|
+
modifiers: {
|
|
41
|
+
[variant]: true,
|
|
42
|
+
[size]: true,
|
|
43
|
+
loading,
|
|
44
|
+
disabled: !!disabled,
|
|
45
|
+
"icon-only": iconOnly,
|
|
46
|
+
},
|
|
47
|
+
styles,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const Comp = (asChild ? Slot : "button") as React.ElementType;
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<Comp
|
|
54
|
+
{...rest}
|
|
55
|
+
className={rootClass}
|
|
56
|
+
disabled={disabled || loading}
|
|
57
|
+
aria-busy={loading || undefined}
|
|
58
|
+
>
|
|
59
|
+
{asChild ? (
|
|
60
|
+
children
|
|
61
|
+
) : (
|
|
62
|
+
<>
|
|
63
|
+
{loading && (
|
|
64
|
+
<span className={getChildClass("spinner")} aria-hidden="true" />
|
|
65
|
+
)}
|
|
66
|
+
<span className={getChildClass("label")}>{children}</span>
|
|
67
|
+
</>
|
|
68
|
+
)}
|
|
69
|
+
</Comp>
|
|
70
|
+
);
|
|
71
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../../../../node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js
|
|
34
|
+
var require_classnames = __commonJS({
|
|
35
|
+
"../../../../node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js"(exports2, module2) {
|
|
36
|
+
"use strict";
|
|
37
|
+
(function() {
|
|
38
|
+
"use strict";
|
|
39
|
+
var hasOwn = {}.hasOwnProperty;
|
|
40
|
+
function classNames() {
|
|
41
|
+
var classes = "";
|
|
42
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
43
|
+
var arg = arguments[i];
|
|
44
|
+
if (arg) {
|
|
45
|
+
classes = appendClass(classes, parseValue(arg));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return classes;
|
|
49
|
+
}
|
|
50
|
+
function parseValue(arg) {
|
|
51
|
+
if (typeof arg === "string" || typeof arg === "number") {
|
|
52
|
+
return arg;
|
|
53
|
+
}
|
|
54
|
+
if (typeof arg !== "object") {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(arg)) {
|
|
58
|
+
return classNames.apply(null, arg);
|
|
59
|
+
}
|
|
60
|
+
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) {
|
|
61
|
+
return arg.toString();
|
|
62
|
+
}
|
|
63
|
+
var classes = "";
|
|
64
|
+
for (var key in arg) {
|
|
65
|
+
if (hasOwn.call(arg, key) && arg[key]) {
|
|
66
|
+
classes = appendClass(classes, key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return classes;
|
|
70
|
+
}
|
|
71
|
+
function appendClass(value, newClass) {
|
|
72
|
+
if (!newClass) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
if (value) {
|
|
76
|
+
return value + " " + newClass;
|
|
77
|
+
}
|
|
78
|
+
return value + newClass;
|
|
79
|
+
}
|
|
80
|
+
if (typeof module2 !== "undefined" && module2.exports) {
|
|
81
|
+
classNames.default = classNames;
|
|
82
|
+
module2.exports = classNames;
|
|
83
|
+
} else if (typeof define === "function" && typeof define.amd === "object" && define.amd) {
|
|
84
|
+
define("classnames", [], function() {
|
|
85
|
+
return classNames;
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
window.classNames = classNames;
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// index.ts
|
|
95
|
+
var index_exports = {};
|
|
96
|
+
__export(index_exports, {
|
|
97
|
+
Button: () => Button
|
|
98
|
+
});
|
|
99
|
+
module.exports = __toCommonJS(index_exports);
|
|
100
|
+
|
|
101
|
+
// button.tsx
|
|
102
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
103
|
+
|
|
104
|
+
// ../../../../packages/registry/class-names/dist/index.js
|
|
105
|
+
var import_classnames = __toESM(require_classnames(), 1);
|
|
106
|
+
var getClassName = ({
|
|
107
|
+
className,
|
|
108
|
+
modifiers = {},
|
|
109
|
+
rootClass,
|
|
110
|
+
styles = {}
|
|
111
|
+
}) => {
|
|
112
|
+
function getModifiers() {
|
|
113
|
+
const updatedModifiers = {};
|
|
114
|
+
const modifierKeys = Object.keys(modifiers);
|
|
115
|
+
if (modifierKeys.length) {
|
|
116
|
+
modifierKeys.forEach((modKey) => {
|
|
117
|
+
const classKey = `${rootClass}--${modKey}`;
|
|
118
|
+
const newClassName = styles[classKey] || classKey;
|
|
119
|
+
updatedModifiers[newClassName] = modifiers[modKey] ?? false;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return updatedModifiers;
|
|
123
|
+
}
|
|
124
|
+
function getChildClass(childClassName) {
|
|
125
|
+
const classKey = `${rootClass}__${childClassName}`;
|
|
126
|
+
return styles[classKey] || classKey;
|
|
127
|
+
}
|
|
128
|
+
function getRootStyles() {
|
|
129
|
+
return (0, import_classnames.default)(
|
|
130
|
+
className,
|
|
131
|
+
{
|
|
132
|
+
...getModifiers()
|
|
133
|
+
},
|
|
134
|
+
styles[rootClass] || rootClass
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return [getRootStyles(), getChildClass];
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// button.module.scss
|
|
141
|
+
var button_module_default = {
|
|
142
|
+
"BHT__Button": "BHT__Button",
|
|
143
|
+
"BHT__Button__label": "BHT__Button__label",
|
|
144
|
+
"BHT__Button__spinner": "BHT__Button__spinner",
|
|
145
|
+
"button-spin": "button-spin",
|
|
146
|
+
"BHT__Button--sm": "BHT__Button--sm",
|
|
147
|
+
"BHT__Button--md": "BHT__Button--md",
|
|
148
|
+
"BHT__Button--lg": "BHT__Button--lg",
|
|
149
|
+
"BHT__Button--primary": "BHT__Button--primary",
|
|
150
|
+
"BHT__Button--secondary": "BHT__Button--secondary",
|
|
151
|
+
"BHT__Button--ghost": "BHT__Button--ghost",
|
|
152
|
+
"BHT__Button--danger": "BHT__Button--danger",
|
|
153
|
+
"BHT__Button--icon-only": "BHT__Button--icon-only",
|
|
154
|
+
"BHT__Button--disabled": "BHT__Button--disabled",
|
|
155
|
+
"BHT__Button--loading": "BHT__Button--loading"
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
// button.tsx
|
|
159
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
160
|
+
var Button = ({
|
|
161
|
+
variant = "primary",
|
|
162
|
+
size = "md",
|
|
163
|
+
loading = false,
|
|
164
|
+
iconOnly = false,
|
|
165
|
+
disabled,
|
|
166
|
+
className,
|
|
167
|
+
children,
|
|
168
|
+
asChild = false,
|
|
169
|
+
...rest
|
|
170
|
+
}) => {
|
|
171
|
+
const [rootClass, getChildClass] = getClassName({
|
|
172
|
+
className,
|
|
173
|
+
rootClass: "BHT__Button",
|
|
174
|
+
modifiers: {
|
|
175
|
+
[variant]: true,
|
|
176
|
+
[size]: true,
|
|
177
|
+
loading,
|
|
178
|
+
disabled: !!disabled,
|
|
179
|
+
"icon-only": iconOnly
|
|
180
|
+
},
|
|
181
|
+
styles: button_module_default
|
|
182
|
+
});
|
|
183
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
185
|
+
Comp,
|
|
186
|
+
{
|
|
187
|
+
...rest,
|
|
188
|
+
className: rootClass,
|
|
189
|
+
disabled: disabled || loading,
|
|
190
|
+
"aria-busy": loading || void 0,
|
|
191
|
+
children: asChild ? children : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
192
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: getChildClass("spinner"), "aria-hidden": "true" }),
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: getChildClass("label"), children })
|
|
194
|
+
] })
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
};
|
|
198
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
199
|
+
0 && (module.exports = {
|
|
200
|
+
Button
|
|
201
|
+
});
|
|
202
|
+
/*! Bundled license information:
|
|
203
|
+
|
|
204
|
+
classnames/index.js:
|
|
205
|
+
(*!
|
|
206
|
+
Copyright (c) 2018 Jed Watson.
|
|
207
|
+
Licensed under the MIT License (MIT), see
|
|
208
|
+
http://jedwatson.github.io/classnames
|
|
209
|
+
*)
|
|
210
|
+
*/
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* esbuild-sass-plugin:css-chunkbutton.module.scss */
|
|
2
|
+
.BHT__Button {
|
|
3
|
+
position: relative;
|
|
4
|
+
isolation: isolate;
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
gap: var(--spacing-2, 0.5rem);
|
|
9
|
+
border: 1px solid transparent;
|
|
10
|
+
border-radius: var(--md-sys-shape-corner-full, 9999px);
|
|
11
|
+
font-family: var(--md-sys-typescale-label-large-font, var(--font-body));
|
|
12
|
+
font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
|
|
13
|
+
font-weight: var(--md-sys-typescale-label-large-weight, 500);
|
|
14
|
+
line-height: var(--md-sys-typescale-label-large-line-height, 1.25rem);
|
|
15
|
+
letter-spacing: var(--md-sys-typescale-label-large-tracking, 0.0071em);
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
white-space: nowrap;
|
|
18
|
+
text-decoration: none;
|
|
19
|
+
user-select: none;
|
|
20
|
+
transition:
|
|
21
|
+
background var(--md-sys-motion-duration-short-3, 150ms) var(--md-sys-motion-easing-standard, ease),
|
|
22
|
+
color var(--md-sys-motion-duration-short-3, 150ms) var(--md-sys-motion-easing-standard, ease),
|
|
23
|
+
border-color var(--md-sys-motion-duration-short-3, 150ms) var(--md-sys-motion-easing-standard, ease);
|
|
24
|
+
}
|
|
25
|
+
.BHT__Button__label {
|
|
26
|
+
display: inline-flex;
|
|
27
|
+
align-items: center;
|
|
28
|
+
}
|
|
29
|
+
.BHT__Button__spinner {
|
|
30
|
+
display: inline-block;
|
|
31
|
+
width: 1em;
|
|
32
|
+
height: 1em;
|
|
33
|
+
border: 2px solid currentColor;
|
|
34
|
+
border-top-color: transparent;
|
|
35
|
+
border-radius: var(--md-sys-shape-corner-full, 9999px);
|
|
36
|
+
animation: button-spin 0.6s linear infinite;
|
|
37
|
+
}
|
|
38
|
+
.BHT__Button::after {
|
|
39
|
+
content: "";
|
|
40
|
+
position: absolute;
|
|
41
|
+
inset: 0;
|
|
42
|
+
border-radius: inherit;
|
|
43
|
+
background: currentColor;
|
|
44
|
+
opacity: 0;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
transition: opacity var(--md-sys-motion-duration-short-2, 100ms) var(--md-sys-motion-easing-standard, ease);
|
|
47
|
+
}
|
|
48
|
+
.BHT__Button:hover:not(:disabled)::after {
|
|
49
|
+
opacity: var(--md-sys-state-hover-opacity, 0.08);
|
|
50
|
+
}
|
|
51
|
+
.BHT__Button:focus-visible::after {
|
|
52
|
+
opacity: var(--md-sys-state-focus-opacity, 0.1);
|
|
53
|
+
}
|
|
54
|
+
.BHT__Button:active:not(:disabled)::after {
|
|
55
|
+
opacity: var(--md-sys-state-pressed-opacity, 0.1);
|
|
56
|
+
}
|
|
57
|
+
.BHT__Button::before {
|
|
58
|
+
content: "";
|
|
59
|
+
position: absolute;
|
|
60
|
+
left: 0;
|
|
61
|
+
right: 0;
|
|
62
|
+
top: 50%;
|
|
63
|
+
translate: 0 -50%;
|
|
64
|
+
height: 100%;
|
|
65
|
+
min-height: 48px;
|
|
66
|
+
}
|
|
67
|
+
.BHT__Button:focus-visible {
|
|
68
|
+
outline: 3px solid var(--md-sys-color-secondary, var(--color-border-focus));
|
|
69
|
+
outline-offset: 2px;
|
|
70
|
+
}
|
|
71
|
+
.BHT__Button--sm.BHT__Button {
|
|
72
|
+
padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);
|
|
73
|
+
min-height: 2rem;
|
|
74
|
+
}
|
|
75
|
+
.BHT__Button--md.BHT__Button {
|
|
76
|
+
padding: var(--spacing-2, 0.5rem) var(--spacing-5, 1.25rem);
|
|
77
|
+
min-height: 2.5rem;
|
|
78
|
+
}
|
|
79
|
+
.BHT__Button--lg.BHT__Button {
|
|
80
|
+
font-size: var(--md-sys-typescale-title-medium-size, 1rem);
|
|
81
|
+
padding: var(--spacing-3, 0.75rem) var(--spacing-6, 1.5rem);
|
|
82
|
+
min-height: 3rem;
|
|
83
|
+
}
|
|
84
|
+
.BHT__Button--primary.BHT__Button {
|
|
85
|
+
background: var(--md-sys-color-primary, var(--color-primary));
|
|
86
|
+
color: var(--md-sys-color-on-primary, var(--color-on-primary));
|
|
87
|
+
border-color: transparent;
|
|
88
|
+
}
|
|
89
|
+
.BHT__Button--secondary.BHT__Button {
|
|
90
|
+
background: transparent;
|
|
91
|
+
color: var(--md-sys-color-primary, var(--color-primary));
|
|
92
|
+
border-color: var(--md-sys-color-outline, var(--color-border-strong));
|
|
93
|
+
}
|
|
94
|
+
.BHT__Button--ghost.BHT__Button {
|
|
95
|
+
background: transparent;
|
|
96
|
+
color: var(--md-sys-color-primary, var(--color-primary));
|
|
97
|
+
border-color: transparent;
|
|
98
|
+
}
|
|
99
|
+
.BHT__Button--danger.BHT__Button {
|
|
100
|
+
background: var(--md-sys-color-error, var(--color-error));
|
|
101
|
+
color: var(--md-sys-color-on-error, #ffffff);
|
|
102
|
+
border-color: transparent;
|
|
103
|
+
}
|
|
104
|
+
.BHT__Button--icon-only.BHT__Button {
|
|
105
|
+
padding: 0;
|
|
106
|
+
}
|
|
107
|
+
.BHT__Button--icon-only.BHT__Button--sm {
|
|
108
|
+
width: 2rem;
|
|
109
|
+
}
|
|
110
|
+
.BHT__Button--icon-only.BHT__Button--md {
|
|
111
|
+
width: 2.5rem;
|
|
112
|
+
}
|
|
113
|
+
.BHT__Button--icon-only.BHT__Button--lg {
|
|
114
|
+
width: 3rem;
|
|
115
|
+
}
|
|
116
|
+
.BHT__Button--icon-only .BHT__Button__label {
|
|
117
|
+
display: inline-flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
}
|
|
121
|
+
.BHT__Button--disabled.BHT__Button {
|
|
122
|
+
opacity: 0.45;
|
|
123
|
+
cursor: not-allowed;
|
|
124
|
+
pointer-events: none;
|
|
125
|
+
}
|
|
126
|
+
.BHT__Button:disabled {
|
|
127
|
+
opacity: 0.45;
|
|
128
|
+
cursor: not-allowed;
|
|
129
|
+
pointer-events: none;
|
|
130
|
+
}
|
|
131
|
+
.BHT__Button--loading.BHT__Button {
|
|
132
|
+
cursor: wait;
|
|
133
|
+
pointer-events: none;
|
|
134
|
+
}
|
|
135
|
+
@keyframes button-spin {
|
|
136
|
+
to {
|
|
137
|
+
transform: rotate(360deg);
|
|
138
|
+
}
|
|
139
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
type ButtonVariant = "primary" | "secondary" | "ghost" | "danger";
|
|
5
|
+
type ButtonSize = "sm" | "md" | "lg";
|
|
6
|
+
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
7
|
+
/** Controls the color/style treatment; defaults to primary */
|
|
8
|
+
variant?: ButtonVariant;
|
|
9
|
+
/** Controls the size; defaults to md */
|
|
10
|
+
size?: ButtonSize;
|
|
11
|
+
/** Shows a spinner and disables the button while an action is in flight */
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
/** Renders the button as a square icon-only control with no visible label spacing */
|
|
14
|
+
iconOnly?: boolean;
|
|
15
|
+
/** Additional class names to merge with the component root element */
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Button label/content */
|
|
18
|
+
children?: React.ReactNode;
|
|
19
|
+
/** Renders the button's props onto its single child element (via Radix `Slot`) instead of a `<button>` */
|
|
20
|
+
asChild?: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare const Button: ({ variant, size, loading, iconOnly, disabled, className, children, asChild, ...rest }: ButtonProps) => react.JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// ../../../../node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js
|
|
28
|
+
var require_classnames = __commonJS({
|
|
29
|
+
"../../../../node_modules/.pnpm/classnames@2.5.1/node_modules/classnames/index.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
(function() {
|
|
32
|
+
"use strict";
|
|
33
|
+
var hasOwn = {}.hasOwnProperty;
|
|
34
|
+
function classNames() {
|
|
35
|
+
var classes = "";
|
|
36
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
37
|
+
var arg = arguments[i];
|
|
38
|
+
if (arg) {
|
|
39
|
+
classes = appendClass(classes, parseValue(arg));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return classes;
|
|
43
|
+
}
|
|
44
|
+
function parseValue(arg) {
|
|
45
|
+
if (typeof arg === "string" || typeof arg === "number") {
|
|
46
|
+
return arg;
|
|
47
|
+
}
|
|
48
|
+
if (typeof arg !== "object") {
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(arg)) {
|
|
52
|
+
return classNames.apply(null, arg);
|
|
53
|
+
}
|
|
54
|
+
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes("[native code]")) {
|
|
55
|
+
return arg.toString();
|
|
56
|
+
}
|
|
57
|
+
var classes = "";
|
|
58
|
+
for (var key in arg) {
|
|
59
|
+
if (hasOwn.call(arg, key) && arg[key]) {
|
|
60
|
+
classes = appendClass(classes, key);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return classes;
|
|
64
|
+
}
|
|
65
|
+
function appendClass(value, newClass) {
|
|
66
|
+
if (!newClass) {
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
if (value) {
|
|
70
|
+
return value + " " + newClass;
|
|
71
|
+
}
|
|
72
|
+
return value + newClass;
|
|
73
|
+
}
|
|
74
|
+
if (typeof module !== "undefined" && module.exports) {
|
|
75
|
+
classNames.default = classNames;
|
|
76
|
+
module.exports = classNames;
|
|
77
|
+
} else if (typeof define === "function" && typeof define.amd === "object" && define.amd) {
|
|
78
|
+
define("classnames", [], function() {
|
|
79
|
+
return classNames;
|
|
80
|
+
});
|
|
81
|
+
} else {
|
|
82
|
+
window.classNames = classNames;
|
|
83
|
+
}
|
|
84
|
+
})();
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// button.tsx
|
|
89
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
90
|
+
|
|
91
|
+
// ../../../../packages/registry/class-names/dist/index.js
|
|
92
|
+
var import_classnames = __toESM(require_classnames(), 1);
|
|
93
|
+
var getClassName = ({
|
|
94
|
+
className,
|
|
95
|
+
modifiers = {},
|
|
96
|
+
rootClass,
|
|
97
|
+
styles = {}
|
|
98
|
+
}) => {
|
|
99
|
+
function getModifiers() {
|
|
100
|
+
const updatedModifiers = {};
|
|
101
|
+
const modifierKeys = Object.keys(modifiers);
|
|
102
|
+
if (modifierKeys.length) {
|
|
103
|
+
modifierKeys.forEach((modKey) => {
|
|
104
|
+
const classKey = `${rootClass}--${modKey}`;
|
|
105
|
+
const newClassName = styles[classKey] || classKey;
|
|
106
|
+
updatedModifiers[newClassName] = modifiers[modKey] ?? false;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return updatedModifiers;
|
|
110
|
+
}
|
|
111
|
+
function getChildClass(childClassName) {
|
|
112
|
+
const classKey = `${rootClass}__${childClassName}`;
|
|
113
|
+
return styles[classKey] || classKey;
|
|
114
|
+
}
|
|
115
|
+
function getRootStyles() {
|
|
116
|
+
return (0, import_classnames.default)(
|
|
117
|
+
className,
|
|
118
|
+
{
|
|
119
|
+
...getModifiers()
|
|
120
|
+
},
|
|
121
|
+
styles[rootClass] || rootClass
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return [getRootStyles(), getChildClass];
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// button.module.scss
|
|
128
|
+
var button_module_default = {
|
|
129
|
+
"BHT__Button": "BHT__Button",
|
|
130
|
+
"BHT__Button__label": "BHT__Button__label",
|
|
131
|
+
"BHT__Button__spinner": "BHT__Button__spinner",
|
|
132
|
+
"button-spin": "button-spin",
|
|
133
|
+
"BHT__Button--sm": "BHT__Button--sm",
|
|
134
|
+
"BHT__Button--md": "BHT__Button--md",
|
|
135
|
+
"BHT__Button--lg": "BHT__Button--lg",
|
|
136
|
+
"BHT__Button--primary": "BHT__Button--primary",
|
|
137
|
+
"BHT__Button--secondary": "BHT__Button--secondary",
|
|
138
|
+
"BHT__Button--ghost": "BHT__Button--ghost",
|
|
139
|
+
"BHT__Button--danger": "BHT__Button--danger",
|
|
140
|
+
"BHT__Button--icon-only": "BHT__Button--icon-only",
|
|
141
|
+
"BHT__Button--disabled": "BHT__Button--disabled",
|
|
142
|
+
"BHT__Button--loading": "BHT__Button--loading"
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// button.tsx
|
|
146
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
147
|
+
var Button = ({
|
|
148
|
+
variant = "primary",
|
|
149
|
+
size = "md",
|
|
150
|
+
loading = false,
|
|
151
|
+
iconOnly = false,
|
|
152
|
+
disabled,
|
|
153
|
+
className,
|
|
154
|
+
children,
|
|
155
|
+
asChild = false,
|
|
156
|
+
...rest
|
|
157
|
+
}) => {
|
|
158
|
+
const [rootClass, getChildClass] = getClassName({
|
|
159
|
+
className,
|
|
160
|
+
rootClass: "BHT__Button",
|
|
161
|
+
modifiers: {
|
|
162
|
+
[variant]: true,
|
|
163
|
+
[size]: true,
|
|
164
|
+
loading,
|
|
165
|
+
disabled: !!disabled,
|
|
166
|
+
"icon-only": iconOnly
|
|
167
|
+
},
|
|
168
|
+
styles: button_module_default
|
|
169
|
+
});
|
|
170
|
+
const Comp = asChild ? Slot : "button";
|
|
171
|
+
return /* @__PURE__ */ jsx(
|
|
172
|
+
Comp,
|
|
173
|
+
{
|
|
174
|
+
...rest,
|
|
175
|
+
className: rootClass,
|
|
176
|
+
disabled: disabled || loading,
|
|
177
|
+
"aria-busy": loading || void 0,
|
|
178
|
+
children: asChild ? children : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
179
|
+
loading && /* @__PURE__ */ jsx("span", { className: getChildClass("spinner"), "aria-hidden": "true" }),
|
|
180
|
+
/* @__PURE__ */ jsx("span", { className: getChildClass("label"), children })
|
|
181
|
+
] })
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
export {
|
|
186
|
+
Button
|
|
187
|
+
};
|
|
188
|
+
/*! Bundled license information:
|
|
189
|
+
|
|
190
|
+
classnames/index.js:
|
|
191
|
+
(*!
|
|
192
|
+
Copyright (c) 2018 Jed Watson.
|
|
193
|
+
Licensed under the MIT License (MIT), see
|
|
194
|
+
http://jedwatson.github.io/classnames
|
|
195
|
+
*)
|
|
196
|
+
*/
|
package/docs.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://github.com/behivetech/bht-component-registry/docs.schema.json",
|
|
3
|
+
"version": 2,
|
|
4
|
+
"generatedAt": "2026-10-20T05:49:23.249Z",
|
|
5
|
+
"docs": [
|
|
6
|
+
{
|
|
7
|
+
"displayName": "Button",
|
|
8
|
+
"description": "",
|
|
9
|
+
"extendsNative": true,
|
|
10
|
+
"props": [
|
|
11
|
+
{
|
|
12
|
+
"name": "asChild",
|
|
13
|
+
"type": "boolean",
|
|
14
|
+
"required": false,
|
|
15
|
+
"defaultValue": "false",
|
|
16
|
+
"description": "Renders the button's props onto its single child element (via Radix `Slot`) instead of a `<button>`"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "children",
|
|
20
|
+
"type": "ReactNode",
|
|
21
|
+
"required": false,
|
|
22
|
+
"defaultValue": null,
|
|
23
|
+
"description": "Button label/content"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "className",
|
|
27
|
+
"type": "string",
|
|
28
|
+
"required": false,
|
|
29
|
+
"defaultValue": null,
|
|
30
|
+
"description": "Additional class names to merge with the component root element"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"name": "iconOnly",
|
|
34
|
+
"type": "boolean",
|
|
35
|
+
"required": false,
|
|
36
|
+
"defaultValue": "false",
|
|
37
|
+
"description": "Renders the button as a square icon-only control with no visible label spacing"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "loading",
|
|
41
|
+
"type": "boolean",
|
|
42
|
+
"required": false,
|
|
43
|
+
"defaultValue": "false",
|
|
44
|
+
"description": "Shows a spinner and disables the button while an action is in flight"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "size",
|
|
48
|
+
"type": "\"sm\" | \"md\" | \"lg\"",
|
|
49
|
+
"required": false,
|
|
50
|
+
"defaultValue": "md",
|
|
51
|
+
"description": "Controls the size; defaults to md"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "variant",
|
|
55
|
+
"type": "\"primary\" | \"secondary\" | \"ghost\" | \"danger\"",
|
|
56
|
+
"required": false,
|
|
57
|
+
"defaultValue": "primary",
|
|
58
|
+
"description": "Controls the color/style treatment; defaults to primary"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
"functions": []
|
|
64
|
+
}
|
package/index.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@behivetech/atoms.button",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.4.2",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"private": false,
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"./styles.css": "./dist/index.css"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"index.ts",
|
|
19
|
+
"button.tsx",
|
|
20
|
+
"button.module.scss",
|
|
21
|
+
"*.example.tsx",
|
|
22
|
+
"docs.json"
|
|
23
|
+
],
|
|
24
|
+
"registry": {
|
|
25
|
+
"status": "stable",
|
|
26
|
+
"tags": []
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@radix-ui/react-slot": "^1.1.0",
|
|
30
|
+
"react": "^19.2.7",
|
|
31
|
+
"react-dom": "^19.2.7"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@radix-ui/react-slot": "^1.3.3",
|
|
35
|
+
"@types/react": "19.2.17",
|
|
36
|
+
"@types/react-dom": "19.2.3",
|
|
37
|
+
"eslint": "^9.39.5",
|
|
38
|
+
"tsup": "^8.5.1",
|
|
39
|
+
"typescript": "^6.0.3",
|
|
40
|
+
"vitest": "^4.1.10",
|
|
41
|
+
"@bht-component-registry/env": "0.1.0",
|
|
42
|
+
"@bht-component-registry/class-names": "0.0.6"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/behivetech/bht-galaxy.git",
|
|
47
|
+
"directory": "registry/behivetech/atoms/button"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"registry": "https://registry.npmjs.org",
|
|
51
|
+
"access": "public",
|
|
52
|
+
"provenance": true
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsup && bht-registry-docgen",
|
|
56
|
+
"dev": "tsup --watch",
|
|
57
|
+
"lint": "eslint . --max-warnings 0",
|
|
58
|
+
"check-types": "tsc --noEmit",
|
|
59
|
+
"test": "vitest run"
|
|
60
|
+
}
|
|
6
61
|
}
|