@stamcat/craftsman 0.0.23-alpha.10 → 0.0.23-alpha.11
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/AGENTS.md +91 -2
- package/components/Button.d.ts +1 -0
- package/components/Modal.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Button.esm.js +22 -15
- package/src/components/Modal.esm.js +2 -4
- package/src/utilities/validations.esm.js +7 -0
- package/stories/Button.stories.d.ts +3 -0
package/AGENTS.md
CHANGED
|
@@ -12,6 +12,7 @@ Use these imports:
|
|
|
12
12
|
import { Button } from "@stamcat/craftsman/Button";
|
|
13
13
|
import { Input } from "@stamcat/craftsman/Input";
|
|
14
14
|
import { Loader } from "@stamcat/craftsman/Loader";
|
|
15
|
+
import { Modal } from "@stamcat/craftsman/Modal";
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
Do not assume a root export like `@stamcat/craftsman` unless that export is explicitly added to package `exports`.
|
|
@@ -37,12 +38,25 @@ Props:
|
|
|
37
38
|
|
|
38
39
|
- Inherits all native `<button>` props.
|
|
39
40
|
- `variant?: "primary" | "default" | "text"` (default: `"default"`)
|
|
41
|
+
- `size?: number` (default visual scale is `1`)
|
|
40
42
|
- `styles?: SerializedStyles` (Emotion override)
|
|
41
43
|
|
|
42
44
|
Behavior notes:
|
|
43
45
|
|
|
44
46
|
- `type` defaults to `"button"`.
|
|
45
47
|
- For `variant !== "default"`, variant is appended to `className` (for example `"primary"`).
|
|
48
|
+
- Theme class merge: if `theme.components.button` is a string, it is appended to the class list.
|
|
49
|
+
- `className` is preserved and merged after variant/theme classes.
|
|
50
|
+
- If `children` is empty (per `isEmpty`), the component renders nothing.
|
|
51
|
+
- `size` is clamped to `[0.1, 10]` before styling is applied.
|
|
52
|
+
- When `size` is provided, Button scales:
|
|
53
|
+
- `border-radius: calc(var(--btn-border-radius) * size)`
|
|
54
|
+
- `padding: calc(var(--btn-pad-y) * size) calc(var(--btn-pad-x) * size)`
|
|
55
|
+
- `font-size: max(10px, calc(var(--w-text) * size))`
|
|
56
|
+
- There is no dedicated icon/loading prop. Icons, loaders, and mixed content are passed as `children`.
|
|
57
|
+
- Supports both real disable (`disabled={true}`) and style-only disable (`className="disabled"`).
|
|
58
|
+
- Native button modes are supported (`type="button" | "submit" | "reset"`).
|
|
59
|
+
- Accessibility props such as `aria-label` pass through unchanged.
|
|
46
60
|
|
|
47
61
|
Example:
|
|
48
62
|
|
|
@@ -50,6 +64,33 @@ Example:
|
|
|
50
64
|
<Button variant="primary" onClick={onSave}>Save</Button>
|
|
51
65
|
```
|
|
52
66
|
|
|
67
|
+
Story-aligned usage examples:
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
// Scaled compact button (size is clamped to [0.1, 10])
|
|
71
|
+
<Button variant="primary" size={0.5}>Mini Action</Button>
|
|
72
|
+
|
|
73
|
+
// Icon content
|
|
74
|
+
<Button variant="primary">
|
|
75
|
+
<TruckIcon size={20} /> <span>Ship</span>
|
|
76
|
+
</Button>
|
|
77
|
+
|
|
78
|
+
// Loading content
|
|
79
|
+
<Button aria-label="Saving">
|
|
80
|
+
<Loader type="boxy" width={32} color="#de13ca" />
|
|
81
|
+
</Button>
|
|
82
|
+
|
|
83
|
+
// Style-only disabled appearance while still allowing click handlers
|
|
84
|
+
<Button className="disabled" onClick={onClick}>Disabled Look</Button>
|
|
85
|
+
|
|
86
|
+
// Native submit behavior
|
|
87
|
+
<Button type="submit" aria-label="Save form">Save</Button>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Implementation caution:
|
|
91
|
+
|
|
92
|
+
- Size scaling depends on CSS variables provided by the package global styles (`--btn-border-radius`, `--btn-pad-y`, `--btn-pad-x`, `--w-text`).
|
|
93
|
+
|
|
53
94
|
### Input
|
|
54
95
|
|
|
55
96
|
Import:
|
|
@@ -68,6 +109,54 @@ Example:
|
|
|
68
109
|
<Input type="email" placeholder="you@company.com" required />
|
|
69
110
|
```
|
|
70
111
|
|
|
112
|
+
### Modal
|
|
113
|
+
|
|
114
|
+
Import:
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
import { Modal } from "@stamcat/craftsman/Modal";
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Props:
|
|
121
|
+
|
|
122
|
+
- Inherits all native `<div>` props.
|
|
123
|
+
- `visible?: boolean` (when falsy, component renders nothing)
|
|
124
|
+
- `onDismiss?: () => void`
|
|
125
|
+
- `type?: "dialog" | "panel"` (default: `"dialog"`)
|
|
126
|
+
- `header?: string | React.ReactNode`
|
|
127
|
+
- `backgroundDismiss?: boolean` (default behavior: `true`)
|
|
128
|
+
- `hideDismissIcon?: boolean` (default behavior: close icon is shown)
|
|
129
|
+
- `footer?: React.ReactNode`
|
|
130
|
+
- `styles?: SerializedStyles` (applies to outer modal wrapper)
|
|
131
|
+
|
|
132
|
+
Behavior notes:
|
|
133
|
+
|
|
134
|
+
- Modal is controlled; parent owns open/close state via `visible` and `onDismiss`.
|
|
135
|
+
- Close icon and background click both dismiss through `onDismiss`.
|
|
136
|
+
- Background dismiss only runs when `backgroundDismiss` is `true` or `undefined`.
|
|
137
|
+
- Dismiss uses a short close animation before calling `onDismiss` (~280ms timeout).
|
|
138
|
+
- `type="dialog"` renders centered responsive dialog sizing; `type="panel"` renders a right-side panel.
|
|
139
|
+
- `footer` is rendered in an action row container below modal content.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
const [open, setOpen] = useState(false);
|
|
145
|
+
|
|
146
|
+
<>
|
|
147
|
+
<Button variant="primary" onClick={() => setOpen(true)}>Open</Button>
|
|
148
|
+
<Modal
|
|
149
|
+
visible={open}
|
|
150
|
+
onDismiss={() => setOpen(false)}
|
|
151
|
+
type="dialog"
|
|
152
|
+
header="Confirm Action"
|
|
153
|
+
footer={<><Button onClick={() => setOpen(false)}>Cancel</Button><Button variant="primary">Confirm</Button></>}
|
|
154
|
+
>
|
|
155
|
+
<p>Are you sure?</p>
|
|
156
|
+
</Modal>
|
|
157
|
+
</>
|
|
158
|
+
```
|
|
159
|
+
|
|
71
160
|
### Loader
|
|
72
161
|
|
|
73
162
|
Import:
|
|
@@ -151,12 +240,12 @@ if (arr.length === 0) { ... }
|
|
|
151
240
|
|
|
152
241
|
1. README is minimal; treat this guide as the source of truth for agent usage.
|
|
153
242
|
2. Theme utilities exist in source but are not guaranteed public package exports.
|
|
154
|
-
3.
|
|
243
|
+
3. `Progress` exists in source but is incomplete and intentionally omitted from this guide for now.
|
|
155
244
|
|
|
156
245
|
## Safe Fallback Strategy for Agents
|
|
157
246
|
|
|
158
247
|
If uncertain about available exports:
|
|
159
248
|
|
|
160
|
-
1. Use only `Button`, `Input`, and `
|
|
249
|
+
1. Use only `Button`, `Input`, `Loader`, and `Modal` from their component entry points.
|
|
161
250
|
2. Do not invent package APIs.
|
|
162
251
|
3. Prefer native HTML elements for anything not explicitly exported.
|
package/components/Button.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { SerializedStyles } from '@emotion/react';
|
|
|
2
2
|
import { ButtonType } from '../styles/global/components/button';
|
|
3
3
|
export type ButtonProps = React.ComponentProps<"button"> & {
|
|
4
4
|
variant?: ButtonType;
|
|
5
|
+
size?: number;
|
|
5
6
|
styles?: SerializedStyles;
|
|
6
7
|
};
|
|
7
8
|
export declare const Button: React.FC<ButtonProps>;
|
package/components/Modal.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import t from "@emotion/
|
|
3
|
-
import
|
|
1
|
+
import { isEmpty as e } from "../utilities/validations.esm.js";
|
|
2
|
+
import { css as t, useTheme as n } from "@emotion/react";
|
|
3
|
+
import r from "@emotion/styled";
|
|
4
|
+
import { Fragment as i, jsx as a } from "react/jsx-runtime";
|
|
4
5
|
//#region src/components/Button.tsx
|
|
5
|
-
var
|
|
6
|
+
var o = r.button`
|
|
6
7
|
${(e) => e.styles}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
${((e) => e.size && t`
|
|
9
|
+
border-radius: calc(var(--btn-border-radius) * ${e.size});
|
|
10
|
+
padding: calc(var(--btn-pad-y) * ${e.size}) calc(var(--btn-pad-x) * ${e.size});
|
|
11
|
+
font-size: max(10px, calc(var(--w-text) * ${e.size}));
|
|
12
|
+
`)}
|
|
13
|
+
`, s = (t) => {
|
|
14
|
+
let { type: r = "button", variant: s = "default", className: c, size: l, ...u } = t, d = typeof l == "number" ? Math.min(10, Math.max(.1, l)) : void 0, f = n(), p = typeof f?.components?.button == "string" ? f.components.button : void 0, m = [
|
|
15
|
+
s === "default" ? void 0 : s,
|
|
16
|
+
p,
|
|
17
|
+
c
|
|
18
|
+
].filter(Boolean).join(" ") || void 0;
|
|
19
|
+
return e(t.children) ? /* @__PURE__ */ a(i, {}) : /* @__PURE__ */ a(o, {
|
|
20
|
+
type: r,
|
|
21
|
+
size: d,
|
|
22
|
+
className: m,
|
|
23
|
+
...u
|
|
17
24
|
});
|
|
18
25
|
};
|
|
19
26
|
//#endregion
|
|
20
|
-
export {
|
|
27
|
+
export { s as Button };
|
|
@@ -104,7 +104,6 @@ var d = a`
|
|
|
104
104
|
}
|
|
105
105
|
`, C = i`
|
|
106
106
|
text-decoration: none;
|
|
107
|
-
// padding: 0 calc(var(--w-gutter) * 0.25) 0 var(--w-gutter);
|
|
108
107
|
height: 36px;
|
|
109
108
|
width: 36px;
|
|
110
109
|
border-radius: 50%;
|
|
@@ -122,8 +121,7 @@ var d = a`
|
|
|
122
121
|
}, 280));
|
|
123
122
|
};
|
|
124
123
|
onClickBackground = () => {
|
|
125
|
-
|
|
126
|
-
(e === !0 || e === void 0) && this.onDismiss();
|
|
124
|
+
(this.props.backgroundDismiss || !0) === !0 && this.onDismiss();
|
|
127
125
|
};
|
|
128
126
|
render() {
|
|
129
127
|
return this.props.visible ? /* @__PURE__ */ l(h, {
|
|
@@ -149,7 +147,7 @@ var d = a`
|
|
|
149
147
|
isClosing: this.state.isClosing,
|
|
150
148
|
onClick: this.onClickBackground
|
|
151
149
|
})]
|
|
152
|
-
}) :
|
|
150
|
+
}) : /* @__PURE__ */ c(s, {});
|
|
153
151
|
}
|
|
154
152
|
};
|
|
155
153
|
//#endregion
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/utilities/validations.ts
|
|
2
|
+
/* #__PURE__ */
|
|
3
|
+
function e(e) {
|
|
4
|
+
return e == null || typeof e == "object" && Object.keys(e).length === 0 || typeof e == "string" && e.trim().length === 0 || typeof e == "string" && e === " ";
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { e as isEmpty };
|
|
@@ -6,6 +6,9 @@ type Story = StoryObj<typeof meta>;
|
|
|
6
6
|
export declare const Default: Story;
|
|
7
7
|
export declare const Primary: Story;
|
|
8
8
|
export declare const Text: Story;
|
|
9
|
+
export declare const WithIcon: Story;
|
|
10
|
+
export declare const Mini: Story;
|
|
11
|
+
export declare const XL: Story;
|
|
9
12
|
export declare const Disabled: Story;
|
|
10
13
|
export declare const FullyDisabled: Story;
|
|
11
14
|
export declare const Loading: Story;
|