@stamcat/craftsman 0.0.61 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -1
- package/skills/craftsman-component-usage/SKILL.md +20 -0
- package/src/components/Button/AGENTS.md +2 -0
- package/src/components/Input/Input.css +1 -1
- package/src/components/Input/Input.scss +1 -1
- package/src/components/Select/Select.esm.js +31 -22
- package/src/styles/global/components/_button.scss +18 -3
- package/src/styles/global/globalStyles.scss +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamcat/craftsman",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A powerful, lightweight framework for design systems",
|
|
6
6
|
"repository": {
|
|
@@ -33,9 +33,11 @@
|
|
|
33
33
|
"@atlaskit/pragmatic-drag-and-drop": "^3.0.0",
|
|
34
34
|
"@floating-ui/react-dom": "^2.1.0",
|
|
35
35
|
"@wojtekmaj/react-daterange-picker": "^7.1.0",
|
|
36
|
+
"chart.js": "^4.5.1",
|
|
36
37
|
"dompurify": "^3.4.0",
|
|
37
38
|
"embla-carousel-react": "^8.6.0",
|
|
38
39
|
"react": "^19.0.0",
|
|
40
|
+
"react-chartjs-2": "^5.3.1",
|
|
39
41
|
"react-date-picker": "^12.0.0",
|
|
40
42
|
"react-datetime-picker": "^7.0.0",
|
|
41
43
|
"react-device-detect": "^2.2.0",
|
|
@@ -92,6 +94,7 @@
|
|
|
92
94
|
"is-weakref": "npm:@socketregistry/is-weakref@^1",
|
|
93
95
|
"is-weakset": "npm:@socketregistry/is-weakset@^1",
|
|
94
96
|
"isarray": "npm:@socketregistry/isarray@^1",
|
|
97
|
+
"js-yaml": "4.3.2",
|
|
95
98
|
"object-keys": "npm:@socketregistry/object-keys@^1",
|
|
96
99
|
"object.assign": "npm:@socketregistry/object.assign@^1",
|
|
97
100
|
"object.fromentries": "npm:@socketregistry/object.fromentries@^1",
|
|
@@ -165,6 +168,7 @@
|
|
|
165
168
|
"is-weakref": "npm:@socketregistry/is-weakref@^1",
|
|
166
169
|
"is-weakset": "npm:@socketregistry/is-weakset@^1",
|
|
167
170
|
"isarray": "npm:@socketregistry/isarray@^1",
|
|
171
|
+
"js-yaml": "4.3.2",
|
|
168
172
|
"object-keys": "npm:@socketregistry/object-keys@^1",
|
|
169
173
|
"object.assign": "npm:@socketregistry/object.assign@^1",
|
|
170
174
|
"object.fromentries": "npm:@socketregistry/object.fromentries@^1",
|
|
@@ -129,6 +129,26 @@ toast.warning("Unsaved changes.");
|
|
|
129
129
|
toast.info("New version available.");
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
## Charts (react-chartjs-2)
|
|
133
|
+
|
|
134
|
+
Craftsman uses `react-chartjs-2` directly, without modification — there is no Craftsman `Chart` wrapper component. Consumers install `react-chartjs-2` and its `chart.js` peer dependency themselves and use the upstream API exactly as documented at https://react-chartjs-2.js.org/examples.
|
|
135
|
+
|
|
136
|
+
Import:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Tooltip, Legend } from "chart.js";
|
|
140
|
+
import { Bar } from "react-chartjs-2";
|
|
141
|
+
|
|
142
|
+
// Register only the controllers/elements/scales/plugins the chart type needs — chart.js is tree-shakeable.
|
|
143
|
+
ChartJS.register(CategoryScale, LinearScale, BarElement, Tooltip, Legend);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Usage:
|
|
147
|
+
|
|
148
|
+
- Every chart type used (`Bar`, `Line`, `Pie`, `Doughnut`, `PolarArea`, `Radar`, `Scatter`, `Bubble`, `Chart` for mixed types) must have its corresponding `chart.js` pieces registered once at module scope before render.
|
|
149
|
+
- Dataset colors must be literal color values (hex/`rgba()`), not CSS variables (`var(--blue500)`) — chart.js draws to a `<canvas>` 2D context, which cannot resolve CSS custom properties. Use `colors` and `hexToRgba` from `@stamcat/craftsman/styles` (see the [craftsman-style-utilities skill](../craftsman-style-utilities/SKILL.md)) to stay on-palette instead of hard-coding hex strings inline.
|
|
150
|
+
- See `src/stories/organisms/Charts.stories.tsx` in this repo for a full worked example of every chart type from the react-chartjs-2 examples page.
|
|
151
|
+
|
|
132
152
|
## Code Generation Patterns to Prefer
|
|
133
153
|
|
|
134
154
|
1. Generate fully typed React usage examples.
|
|
@@ -17,6 +17,8 @@ Behavior notes:
|
|
|
17
17
|
|
|
18
18
|
- `type` defaults to `"button"`.
|
|
19
19
|
- For `variant !== "default"`, variant is appended to `className` (for example `"primary"`).
|
|
20
|
+
- `primary` and `secondary` share a distinct filled look (blue background, white text); `default` is a base outlined look; `text` is a borderless, underline-on-hover link style.
|
|
21
|
+
- A `<button>` element can wrap arbitrary content (icons, custom markup, anything) purely so it stays usable by screen readers and other automated/assistive services — the native semantics and keyboard behavior come for free. Not every `<button>` should visually look like a button though, so styling is opt-in via class names rather than the bare element: base button styles (`%button-styles`) are scoped to the `.button` class the component always applies, not the bare `button` element — plain `<button>` markup without that class receives no library styling.
|
|
20
22
|
- `className` is preserved and merged after component classes.
|
|
21
23
|
- Theme component overrides are selector-based CSS emitted by `ThemeProvider`; `theme.components.*` accepts JS style objects or raw CSS/Sass strings for the target selector.
|
|
22
24
|
- If `children` is empty (per `isEmpty`), the component renders nothing.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer cf-base{.input-pre-adornment,.input-end-adornment{z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .5);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .45);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:has(.input-field[data-has-pre-adornment=true]) .input-label{left:calc(var(--w-gutter) * 1.75)}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label,.input-wrapper[data-label-position=inside].select .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] input::placeholder{opacity:0;transition:opacity .2s}.input-field{align-items:center;display:inline-flex;position:relative}.input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * 1.5)}.input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) *
|
|
1
|
+
@layer cf-base{.input-pre-adornment,.input-end-adornment{z-index:1;align-items:center;margin-top:0;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.input-wrapper label .input-label{margin-bottom:calc(var(--w-gutter) * .25)}.input-wrapper[data-required=true] label .input-label:after{content:"*";color:var(--red700)}.input-wrapper[data-label-position=left] label{align-items:center;display:inline-flex}.input-wrapper[data-label-position=left] label .input-label{width:fit-content;margin-right:calc(var(--w-gutter) * .75)}.input-wrapper[data-label-position=left].textarea label{align-items:flex-start}.input-wrapper[data-label-position=bottom] label{flex-direction:column-reverse;align-items:flex-start;display:inline-flex}.input-wrapper[data-label-position=bottom] label .input-label{margin-bottom:0;margin-top:calc(var(--w-gutter) * .25)}.input-wrapper[data-label-position=right] label{flex-direction:row-reverse;align-items:baseline;display:inline-flex}.input-wrapper[data-label-position=right] label .input-label{margin-left:calc(var(--w-gutter) * .5);margin-bottom:0}.input-wrapper[data-label-position=inside]{--react-international-phone-height:50px;--react-international-phone-border-radius:8px;--react-international-phone-border-color:silver;position:relative}.input-wrapper[data-label-position=inside] .input-label{background-color:var(--white);z-index:1;width:fit-content;top:calc(var(--w-gutter) * .45);left:calc(var(--w-gutter) * .25);pointer-events:none;padding:0 5px;transition:top .15s,left .15s,font-size .15s,color .15s;position:absolute}.input-wrapper[data-label-position=inside]>label>.input-field>.input,.input-wrapper[data-label-position=inside]>.input{transition:border-color .2s}.input-wrapper[data-label-position=inside]:has(.input-field[data-has-pre-adornment=true]) .input-label{left:calc(var(--w-gutter) * 1.75)}.input-wrapper[data-label-position=inside]:focus-within .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75);color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within .input{border-color:var(--blue500)}.input-wrapper[data-label-position=inside]:focus-within input::placeholder{opacity:1}.input-wrapper[data-label-position=inside][data-has-input=true] .input-label,.input-wrapper[data-label-position=inside].select .input-label{top:-.5rem;left:calc(var(--w-gutter) * .125);font-size:calc(var(--w-text) * .75)}.input-wrapper[data-label-position=inside] .input[type=tel]{width:100%}.input-wrapper[data-label-position=inside] input::placeholder{opacity:0;transition:opacity .2s}.input-field{align-items:center;display:inline-flex;position:relative}.input-field[data-has-end-adornment=true]>.input{padding-right:calc(var(--w-gutter) * 1.5)}.input-field[data-has-pre-adornment=true]>.input{padding-left:calc(var(--w-gutter) * 1.75)}.input-end-adornment{right:calc(var(--w-gutter) * .5)}.input-pre-adornment{left:calc(var(--w-gutter) * .5)}.input-error{margin-top:calc(var(--w-gutter) * .25);font-size:calc(var(--w-text) * .75);color:var(--red600)}.input-view-toggle{align-items:"center";padding:0;line-height:1;display:inline-flex}}
|
|
@@ -1,28 +1,37 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import n from "
|
|
5
|
-
import
|
|
2
|
+
import { isEmpty as e } from "../../utilities/validations.esm.js";
|
|
3
|
+
import { InputWrapper as t } from "../Input/InputWrapper.esm.js";
|
|
4
|
+
import { useId as n } from "react";
|
|
5
|
+
import r from "clsx";
|
|
6
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
7
|
//#region src/components/Select/Select.tsx
|
|
7
|
-
var
|
|
8
|
-
let
|
|
9
|
-
return /* @__PURE__ */
|
|
10
|
-
label:
|
|
11
|
-
labelPosition:
|
|
12
|
-
error:
|
|
13
|
-
required:
|
|
14
|
-
className:
|
|
15
|
-
style:
|
|
16
|
-
children: /* @__PURE__ */
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
var o = ({ label: o, id: s, labelPosition: c = "top", required: l = !1, error: u, options: d = [], className: f, style: p, inputStyle: m, preAdornment: h, ...g }) => {
|
|
9
|
+
let _ = n(), v = s || _;
|
|
10
|
+
return /* @__PURE__ */ i(t, {
|
|
11
|
+
label: o,
|
|
12
|
+
labelPosition: c,
|
|
13
|
+
error: u,
|
|
14
|
+
required: l,
|
|
15
|
+
className: r("select", f),
|
|
16
|
+
style: p,
|
|
17
|
+
children: /* @__PURE__ */ a("span", {
|
|
18
|
+
className: "input-field",
|
|
19
|
+
"data-has-pre-adornment": !e(h),
|
|
20
|
+
children: [!e(h) && /* @__PURE__ */ i("span", {
|
|
21
|
+
className: "input-pre-adornment",
|
|
22
|
+
children: h
|
|
23
|
+
}), /* @__PURE__ */ i("select", {
|
|
24
|
+
id: v,
|
|
25
|
+
className: "input",
|
|
26
|
+
style: m,
|
|
27
|
+
...g,
|
|
28
|
+
children: d.map((e, t) => /* @__PURE__ */ i("option", {
|
|
29
|
+
value: e.value,
|
|
30
|
+
children: e.label
|
|
31
|
+
}, `${v}-opt-${t}`))
|
|
32
|
+
})]
|
|
24
33
|
})
|
|
25
34
|
});
|
|
26
35
|
};
|
|
27
36
|
//#endregion
|
|
28
|
-
export {
|
|
37
|
+
export { o as Select };
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
@use "../../utilities/functions" as u;
|
|
2
2
|
|
|
3
3
|
@layer cf-base {
|
|
4
|
+
%button-reset {
|
|
5
|
+
background: none;
|
|
6
|
+
border: none;
|
|
7
|
+
color: #{u.color("text")};
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
%text-link {
|
|
5
11
|
padding: 0;
|
|
6
12
|
border: none;
|
|
@@ -18,7 +24,7 @@
|
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
}
|
|
21
|
-
|
|
27
|
+
|
|
22
28
|
%button-styles {
|
|
23
29
|
--btn-size: 1;
|
|
24
30
|
color: var(--blue600);
|
|
@@ -47,7 +53,16 @@
|
|
|
47
53
|
background-color: var(--blue700);
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
|
-
|
|
56
|
+
|
|
57
|
+
&.secondary {
|
|
58
|
+
color: var(--white);
|
|
59
|
+
background-color: var(--blue500);
|
|
60
|
+
|
|
61
|
+
&:hover {
|
|
62
|
+
background-color: var(--blue700);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
51
66
|
&.text {
|
|
52
67
|
@extend %text-link;
|
|
53
68
|
}
|
|
@@ -58,7 +73,7 @@
|
|
|
58
73
|
border-color: #{u.color("gray200")};
|
|
59
74
|
color: #{u.color("gray400")};
|
|
60
75
|
|
|
61
|
-
&.primary {
|
|
76
|
+
&.primary, &.secondary {
|
|
62
77
|
border-color: #{u.color("gray200")};
|
|
63
78
|
background-color: #{u.color("gray400")};
|
|
64
79
|
color: #{u.color("gray200")};
|