@stamcat/craftsman 0.0.27-alpha.1 → 0.0.27-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 +393 -3
- package/Components.esm.js +21 -11
- package/README.md +6 -1
- package/Styles.esm.js +5 -5
- package/package.json +29 -7
- package/src/components/{Button.d.ts → Button/Button.d.ts} +1 -1
- package/src/components/Button/Button.esm.js +26 -0
- package/src/components/Carousel/Carousel.d.ts +12 -0
- package/src/components/Carousel/Carousel.scss +32 -0
- package/src/components/{Checkbox.esm.js → Input/Checkbox.esm.js} +2 -2
- package/src/components/Input/DatePicker.d.ts +8 -0
- package/src/components/Input/DatePicker.esm.js +24 -0
- package/src/components/Input/Input.css +1 -0
- package/src/components/Input/Input.d.ts +6 -0
- package/src/components/Input/Input.scss +163 -0
- package/src/components/Input/Input2.esm.js +33 -0
- package/src/components/{InputPassword.d.ts → Input/InputPassword.d.ts} +1 -1
- package/src/components/Input/InputPassword.esm.js +28 -0
- package/src/components/Input/InputPhone.d.ts +7 -0
- package/src/components/Input/InputPhone.esm.js +27 -0
- package/src/components/Input/InputWrapper.d.ts +10 -0
- package/src/components/Input/InputWrapper.esm.js +22 -0
- package/src/components/{RadioButton.esm.js → Input/RadioButton.esm.js} +2 -2
- package/src/components/Input/Textarea.d.ts +3 -0
- package/src/components/Input/Textarea.esm.js +24 -0
- package/src/components/{Loader.d.ts → Loader/Loader.d.ts} +1 -2
- package/src/components/Loader/Loader.esm.js +19 -0
- package/src/components/Loader/loaders.module.css +1 -0
- package/src/components/Loader/loaders.module.esm.js +21 -0
- package/src/{styles/global/components → components/Loader}/loaders.module.scss +2 -1
- package/src/components/{Modal.d.ts → Modal/Modal.d.ts} +0 -1
- package/src/components/{Modal.esm.js → Modal/Modal.esm.js} +17 -26
- package/src/components/Modal/Modal.module.css +1 -0
- package/src/components/Modal/Modal.module.esm.js +16 -0
- package/src/components/{Modal.module.scss → Modal/Modal.module.scss} +32 -18
- package/src/components/Select/Select.d.ts +14 -0
- package/src/components/Select/Select.esm.js +26 -0
- package/src/components/Text/Text.css +1 -0
- package/src/components/Text/Text.d.ts +10 -0
- package/src/components/Text/Text.scss +80 -0
- package/src/components/Text/Text2.esm.js +23 -0
- package/src/components/index.d.ts +12 -7
- package/src/stories/assets/Stam.jpg +0 -0
- package/src/stories/assets/kaluah.jpg +0 -0
- package/src/stories/assets/stam2.jpg +0 -0
- package/src/stories/assets/tito.jpg +0 -0
- package/src/stories/molecules/Carousel.scss +19 -0
- package/src/styles/_config.scss +30 -0
- package/src/styles/components/ThemeProvider.esm.js +1 -1
- package/src/styles/global/components/_button.scss +52 -51
- package/src/styles/global/components/_checkbox.scss +63 -59
- package/src/styles/global/components/_code.scss +19 -15
- package/src/styles/global/components/_input.scss +29 -37
- package/src/styles/global/components/_radioButton.scss +29 -26
- package/src/styles/global/components/_reactCalendar.css +1 -0
- package/src/styles/global/components/_reactCalendar.scss +237 -0
- package/src/styles/global/components/_reactDatePicker.css +1 -0
- package/src/styles/global/components/_reactDatePicker.scss +152 -0
- package/src/styles/global/components/_reactPhone.css +1 -0
- package/src/styles/global/components/_reactPhone.scss +265 -0
- package/src/styles/global/components/_select.scss +56 -0
- package/src/styles/global/components/_typography.scss +92 -6
- package/src/styles/global/globalStyles.d.ts +3 -0
- package/src/styles/global/globalStyles.module.scss +1 -129
- package/src/styles/global/globalStyles.scss +87 -0
- package/src/styles/index.d.ts +1 -1
- package/src/styles/theme/components.esm.js +10 -5
- package/src/styles/theme/theme.esm.js +31 -41
- package/src/styles/theme/types.d.ts +4 -1
- package/src/styles/utilities/_functions.scss +117 -0
- package/src/styles/utilities/_mixins.scss +0 -0
- package/src/styles/utilities/color.d.ts +1 -1
- package/src/styles/utilities/constants.d.ts +1 -1
- package/src/styles/utilities/layout.d.ts +1 -1
- package/src/styles/utilities/layout.esm.js +1 -1
- package/src/{styles/utilities → utilities}/types.d.ts +39 -1
- package/src/{styles/utilities → utilities}/types.esm.js +28 -3
- package/src/components/Button.esm.js +0 -28
- package/src/components/Button.module.css +0 -1
- package/src/components/Button.module.esm.js +0 -9
- package/src/components/Button.module.scss +0 -5
- package/src/components/Input.d.ts +0 -11
- package/src/components/Input.esm.js +0 -41
- package/src/components/Input.module.css +0 -1
- package/src/components/Input.module.esm.js +0 -11
- package/src/components/Input.module.scss +0 -141
- package/src/components/InputPassword.esm.js +0 -33
- package/src/components/Loader.esm.js +0 -21
- package/src/components/Modal.module.css +0 -1
- package/src/components/Modal.module.esm.js +0 -13
- package/src/styles/global/components/_mixins.scss +0 -2
- package/src/styles/global/components/button.d.ts +0 -7
- package/src/styles/global/components/loaders.module.css +0 -1
- package/src/styles/global/components/loaders.module.esm.js +0 -21
- package/src/components/{Checkbox.d.ts → Input/Checkbox.d.ts} +0 -0
- package/src/components/{RadioButton.d.ts → Input/RadioButton.d.ts} +0 -0
- package/src/{styles/global/components/loaders.d.ts → components/Loader/types.d.ts} +1 -1
- /package/src/{styles/global/components/loaders.esm.js → components/Loader/types.esm.js} +0 -0
package/AGENTS.md
CHANGED
|
@@ -11,11 +11,16 @@ Use these imports:
|
|
|
11
11
|
```tsx
|
|
12
12
|
import { Button } from "@stamcat/craftsman/Button";
|
|
13
13
|
import { Checkbox } from "@stamcat/craftsman/Checkbox";
|
|
14
|
+
import { DatePicker } from "@stamcat/craftsman/DatePicker";
|
|
14
15
|
import { Input } from "@stamcat/craftsman/Input";
|
|
15
16
|
import { InputPassword } from "@stamcat/craftsman/InputPassword";
|
|
17
|
+
import { InputPhone } from "@stamcat/craftsman/InputPhone";
|
|
16
18
|
import { Loader } from "@stamcat/craftsman/Loader";
|
|
17
19
|
import { Modal } from "@stamcat/craftsman/Modal";
|
|
18
20
|
import { RadioButton } from "@stamcat/craftsman/RadioButton";
|
|
21
|
+
import { Select } from "@stamcat/craftsman/Select";
|
|
22
|
+
import { Text } from "@stamcat/craftsman/Text";
|
|
23
|
+
import { Textarea } from "@stamcat/craftsman/Textarea";
|
|
19
24
|
```
|
|
20
25
|
|
|
21
26
|
Do not assume a root export like `@stamcat/craftsman` unless that export is explicitly added to package `exports`.
|
|
@@ -27,6 +32,125 @@ Do not assume a root export like `@stamcat/craftsman` unless that export is expl
|
|
|
27
32
|
3. Do not import storybook files or internal style utilities from consuming applications.
|
|
28
33
|
4. Prefer standard React props first; use custom props only when required.
|
|
29
34
|
|
|
35
|
+
## Code Block Rendering
|
|
36
|
+
|
|
37
|
+
Craftsman's global styles automatically style `<code>` and `<code><pre>` elements. **Never create custom inline styles or wrapper divs to simulate a code block.** Use the native elements directly:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// Inline code — renders with pill/badge style
|
|
41
|
+
<code>someValue</code>
|
|
42
|
+
|
|
43
|
+
// Block code — renders with dark background, padding, and border-radius
|
|
44
|
+
<code><pre>{`your
|
|
45
|
+
multiline
|
|
46
|
+
code here`}</pre></code>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The two modes are driven by `_code.scss`:
|
|
50
|
+
- `<code>` alone → light gray background, inline display
|
|
51
|
+
- `<code>` containing `<pre>` → dark background (`--gray800`), block display, padded and rounded
|
|
52
|
+
|
|
53
|
+
Do not create `preStyle`, `codeBlockStyle`, or equivalent inline style objects for this purpose. The global styles handle it.
|
|
54
|
+
|
|
55
|
+
## Style Utilities
|
|
56
|
+
|
|
57
|
+
Craftsman provides TypeScript helpers and matching Sass functions for color, spacing, and breakpoints. Always use these instead of hard-coded values so theming and overrides work correctly.
|
|
58
|
+
|
|
59
|
+
### color()
|
|
60
|
+
|
|
61
|
+
**TypeScript** — import from `@stamcat/craftsman/styles`:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { color, colors, hexToRgba } from "@stamcat/craftsman/styles";
|
|
65
|
+
|
|
66
|
+
// Returns var(--blue500)
|
|
67
|
+
color("blue500")
|
|
68
|
+
|
|
69
|
+
// Returns rgb(from var(--blue500) r g b / 0.5)
|
|
70
|
+
color("blue500", "rgba", 0.5)
|
|
71
|
+
|
|
72
|
+
// Fallback for environments that don't support CSS relative color syntax
|
|
73
|
+
hexToRgba(colors.blue500, 0.5)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Sass** — import `functions` as `u`:
|
|
77
|
+
|
|
78
|
+
```scss
|
|
79
|
+
@use "@stamcat/craftsman/styles/utilities/functions" as u;
|
|
80
|
+
|
|
81
|
+
.element {
|
|
82
|
+
color: #{u.color(blue500)};
|
|
83
|
+
background: #{u.color(black, rgba, 0.4)};
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- `color(name)` → `var(--name)` — always prefer this over hard-coded hex values so theme overrides apply.
|
|
88
|
+
- `color(name, rgba, alpha)` → `rgb(from var(--name) r g b / alpha)` — uses CSS relative color syntax; verify browser support for your target.
|
|
89
|
+
- Never hard-code hex color values. Always use `color()` or a CSS variable.
|
|
90
|
+
|
|
91
|
+
### width()
|
|
92
|
+
|
|
93
|
+
**TypeScript** — import from `@stamcat/craftsman/styles`:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { width } from "@stamcat/craftsman/styles";
|
|
97
|
+
|
|
98
|
+
width("gutter") // var(--w-gutter, 16px)
|
|
99
|
+
width("gutter", 0.5) // calc(var(--w-gutter, 16px) * 0.5)
|
|
100
|
+
width("column", 3) // calc((var(--w-column) * 3) + (var(--w-gutter) * 2))
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Sass** — import `functions` as `u`:
|
|
104
|
+
|
|
105
|
+
```scss
|
|
106
|
+
@use "@stamcat/craftsman/styles/utilities/functions" as u;
|
|
107
|
+
|
|
108
|
+
.card {
|
|
109
|
+
padding: #{u.width(gutter)};
|
|
110
|
+
gap: #{u.width(gutter, 0.5)};
|
|
111
|
+
max-width: #{u.width(column, 4)};
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Valid keys: `text` · `gutter` · `column` · `tablet` · `desktop` · `extDesktop` · `mobileMax` · `tabletMax` · `desktopMax`
|
|
116
|
+
|
|
117
|
+
- The `column` key automatically accounts for gutters between columns.
|
|
118
|
+
- Never use hard-coded `px` values for spacing or layout widths. Always use `width()`.
|
|
119
|
+
|
|
120
|
+
### breakpoint()
|
|
121
|
+
|
|
122
|
+
**TypeScript** — returns a full `@media` rule string for CSS-in-JS:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { breakpoint, media } from "@stamcat/craftsman/styles";
|
|
126
|
+
|
|
127
|
+
// Full rule — use inside styled-components, emotion, or style injection
|
|
128
|
+
breakpoint("desktop", "font-size: 18px;")
|
|
129
|
+
// => "@media (min-width: 1040px) { font-size: 18px; }"
|
|
130
|
+
|
|
131
|
+
// Raw query string only — use for conditional logic or matchMedia
|
|
132
|
+
media.tablet // => "(min-width: 660px)"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Sass** — `@include breakpoint(key)` wraps content in the correct `@media` query:
|
|
136
|
+
|
|
137
|
+
```scss
|
|
138
|
+
@use "@stamcat/craftsman/styles/utilities/functions" as u;
|
|
139
|
+
|
|
140
|
+
.sidebar {
|
|
141
|
+
display: none;
|
|
142
|
+
|
|
143
|
+
@include u.breakpoint(tablet) {
|
|
144
|
+
display: block;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Available breakpoint keys: `tablet` · `tabletMax` · `tabletOnly` · `desktop` · `desktopMax` · `desktopOnly` · `extDesktop` · `mobileMax` · `mobileOnly` · `mobileTablet`
|
|
150
|
+
|
|
151
|
+
- Breakpoint values come from `_config.scss` and stay in sync with any project overrides.
|
|
152
|
+
- Never hard-code `@media (min-width: 1040px)` or similar — always use `breakpoint()` so values stay consistent with config.
|
|
153
|
+
|
|
30
154
|
## Component Contracts
|
|
31
155
|
|
|
32
156
|
### Button
|
|
@@ -48,8 +172,8 @@ Behavior notes:
|
|
|
48
172
|
|
|
49
173
|
- `type` defaults to `"button"`.
|
|
50
174
|
- For `variant !== "default"`, variant is appended to `className` (for example `"primary"`).
|
|
51
|
-
-
|
|
52
|
-
- `
|
|
175
|
+
- `className` is preserved and merged after component classes.
|
|
176
|
+
- 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.
|
|
53
177
|
- If `children` is empty (per `isEmpty`), the component renders nothing.
|
|
54
178
|
- `size` is clamped to `[0.1, 10]` before styling is applied.
|
|
55
179
|
- When `size` is provided, Button scales:
|
|
@@ -310,12 +434,247 @@ Example:
|
|
|
310
434
|
<Loader type="spinner" color="var(--blue500)" width={40} aria-label="Loading" />
|
|
311
435
|
```
|
|
312
436
|
|
|
437
|
+
### Textarea
|
|
438
|
+
|
|
439
|
+
Import:
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
import { Textarea } from "@stamcat/craftsman/Textarea";
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Props:
|
|
446
|
+
|
|
447
|
+
- Inherits all native `<textarea>` props.
|
|
448
|
+
- `label?: string | ReactNode`
|
|
449
|
+
- `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
|
|
450
|
+
- `error?: string | boolean | ReactNode`
|
|
451
|
+
- `required?: boolean`
|
|
452
|
+
- `rows?: number`
|
|
453
|
+
|
|
454
|
+
Behavior notes:
|
|
455
|
+
|
|
456
|
+
- Shares the same `InputWrapper` as `Input` — label, error, and required behavior is identical.
|
|
457
|
+
- `id` is auto-generated via `useId` if not provided.
|
|
458
|
+
|
|
459
|
+
Example:
|
|
460
|
+
|
|
461
|
+
```tsx
|
|
462
|
+
<Textarea
|
|
463
|
+
label="Your Message"
|
|
464
|
+
placeholder="Type here"
|
|
465
|
+
rows={4}
|
|
466
|
+
required
|
|
467
|
+
/>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Select
|
|
471
|
+
|
|
472
|
+
Import:
|
|
473
|
+
|
|
474
|
+
```tsx
|
|
475
|
+
import { Select } from "@stamcat/craftsman/Select";
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Props:
|
|
479
|
+
|
|
480
|
+
- Inherits all native `<select>` props.
|
|
481
|
+
- `label?: string | ReactNode`
|
|
482
|
+
- `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
|
|
483
|
+
- `error?: string | boolean | ReactNode`
|
|
484
|
+
- `required?: boolean`
|
|
485
|
+
- `options?: Array<{ label: string; value: string }>`
|
|
486
|
+
|
|
487
|
+
Behavior notes:
|
|
488
|
+
|
|
489
|
+
- Built on the native `<select>` element via `InputWrapper`.
|
|
490
|
+
- Pass options as a plain array — do not render `<option>` children manually.
|
|
491
|
+
- `id` is auto-generated via `useId` if not provided.
|
|
492
|
+
|
|
493
|
+
Example:
|
|
494
|
+
|
|
495
|
+
```tsx
|
|
496
|
+
<Select
|
|
497
|
+
label="Favorite Fruit"
|
|
498
|
+
required
|
|
499
|
+
options={[
|
|
500
|
+
{ value: "", label: "Select one..." },
|
|
501
|
+
{ value: "apple", label: "Apple" },
|
|
502
|
+
{ value: "banana", label: "Banana" },
|
|
503
|
+
]}
|
|
504
|
+
/>
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### InputPhone
|
|
508
|
+
|
|
509
|
+
Import:
|
|
510
|
+
|
|
511
|
+
```tsx
|
|
512
|
+
import { InputPhone } from "@stamcat/craftsman/InputPhone";
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Props:
|
|
516
|
+
|
|
517
|
+
- Extends `PhoneInputProps` from `react-international-phone`.
|
|
518
|
+
- `label?: string | ReactNode`
|
|
519
|
+
- `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
|
|
520
|
+
- `error?: string | boolean | ReactNode`
|
|
521
|
+
- `required?: boolean`
|
|
522
|
+
- `defaultCountry?: string` (default: `"us"`)
|
|
523
|
+
- `preferredCountries?: string[]`
|
|
524
|
+
- `endAdornment?: ReactNode`
|
|
525
|
+
|
|
526
|
+
Behavior notes:
|
|
527
|
+
|
|
528
|
+
- Powered by `react-international-phone` for i18n-aware phone number formatting.
|
|
529
|
+
- Country selector dropdown opens below the field; ensure the container has at least 350px of vertical space.
|
|
530
|
+
- Use `preferredCountries` to surface commonly used countries at the top of the dropdown.
|
|
531
|
+
|
|
532
|
+
Example:
|
|
533
|
+
|
|
534
|
+
```tsx
|
|
535
|
+
<InputPhone
|
|
536
|
+
label="Phone Number"
|
|
537
|
+
defaultCountry="us"
|
|
538
|
+
preferredCountries={["us", "gb", "ca"]}
|
|
539
|
+
required
|
|
540
|
+
/>
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### DatePicker
|
|
544
|
+
|
|
545
|
+
Import:
|
|
546
|
+
|
|
547
|
+
```tsx
|
|
548
|
+
import { DatePicker } from "@stamcat/craftsman/DatePicker";
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Props:
|
|
552
|
+
|
|
553
|
+
- Extends `DatePickerProps` from `react-date-picker`.
|
|
554
|
+
- `label?: string | ReactNode`
|
|
555
|
+
- `labelPosition?: "top" | "left" | "bottom" | "right" | "inside" | "hidden"` (default: `"top"`)
|
|
556
|
+
- `error?: string | boolean | ReactNode`
|
|
557
|
+
- `required?: boolean`
|
|
558
|
+
- `value?: Date | null`
|
|
559
|
+
- `onChange?: (value: DatePickerProps["value"]) => void`
|
|
560
|
+
|
|
561
|
+
Behavior notes:
|
|
562
|
+
|
|
563
|
+
- Controlled component — parent owns `value` and `onChange`.
|
|
564
|
+
- Calendar flyout renders below the input; ensure the container has at least 400px of vertical space.
|
|
565
|
+
- Use `useState` to manage the selected date value.
|
|
566
|
+
|
|
567
|
+
Example:
|
|
568
|
+
|
|
569
|
+
```tsx
|
|
570
|
+
const [date, setDate] = useState<Date | null>(null);
|
|
571
|
+
|
|
572
|
+
<DatePicker
|
|
573
|
+
label="Appointment Date"
|
|
574
|
+
value={date}
|
|
575
|
+
onChange={setDate}
|
|
576
|
+
required
|
|
577
|
+
/>
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Text
|
|
581
|
+
|
|
582
|
+
Import:
|
|
583
|
+
|
|
584
|
+
```tsx
|
|
585
|
+
import { Text } from "@stamcat/craftsman/Text";
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
Props:
|
|
589
|
+
|
|
590
|
+
- Inherits all native HTML element props.
|
|
591
|
+
- `as?: TextTags` — HTML tag to render (default: `"div"`)
|
|
592
|
+
- `richText?: boolean` — when `true`, renders sanitized HTML from a string `children` value (always renders as `<div>`)
|
|
593
|
+
- `type?: TextType` — overrides base type styling (e.g. `"display"`, `"heading"`)
|
|
594
|
+
- `size?: TextSize` — overrides base size styling
|
|
595
|
+
- `alignment?: "center" | "left" | "right"` — legacy text-align shorthand
|
|
596
|
+
|
|
597
|
+
Behavior notes:
|
|
598
|
+
|
|
599
|
+
- Uses global HTML5 tag declarations by default; `type` and `size` override base styling.
|
|
600
|
+
- `richText` mode sanitizes HTML via DOMPurify. Always pass a string as `children` in this mode.
|
|
601
|
+
- Prefer semantic HTML5 tags via `as` over using `type`/`size` overrides.
|
|
602
|
+
|
|
603
|
+
Example:
|
|
604
|
+
|
|
605
|
+
```tsx
|
|
606
|
+
// Semantic heading
|
|
607
|
+
<Text as="h2">Section Title</Text>
|
|
608
|
+
|
|
609
|
+
// Sanitized rich text from a CMS
|
|
610
|
+
<Text richText>{'<p><strong>Hello</strong> world</p>'}</Text>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Toast (react-toastify)
|
|
614
|
+
|
|
615
|
+
Craftsman re-exports `toast` and `ToastContainer` from `react-toastify`. No custom wrapper is needed.
|
|
616
|
+
|
|
617
|
+
Import:
|
|
618
|
+
|
|
619
|
+
```tsx
|
|
620
|
+
import { toast, ToastContainer } from "react-toastify";
|
|
621
|
+
import "react-toastify/dist/ReactToastify.css";
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Usage:
|
|
625
|
+
|
|
626
|
+
- Render one `<ToastContainer>` near the root of your app.
|
|
627
|
+
- Call `toast(...)` anywhere in response to user actions.
|
|
628
|
+
- `ToastContainer` props: `position`, `autoClose`, `theme` (`"light" | "dark" | "colored"`), `closeOnClick`, `pauseOnHover`, `draggable`, `newestOnTop`.
|
|
629
|
+
|
|
630
|
+
Example:
|
|
631
|
+
|
|
632
|
+
```tsx
|
|
633
|
+
// Root layout
|
|
634
|
+
<ToastContainer position="bottom-right" autoClose={3000} theme="light" />
|
|
635
|
+
|
|
636
|
+
// Anywhere in the app
|
|
637
|
+
toast("Saved successfully!");
|
|
638
|
+
toast.error("Something went wrong.");
|
|
639
|
+
toast.success("Profile updated.");
|
|
640
|
+
toast.warning("Unsaved changes.");
|
|
641
|
+
toast.info("New version available.");
|
|
642
|
+
```
|
|
643
|
+
|
|
313
644
|
## Styling Expectations
|
|
314
645
|
|
|
315
646
|
- Components are built with SCSS modules and class-based variant hooks.
|
|
316
647
|
- If your app does not include this package's global CSS variable setup, visual output may differ.
|
|
317
648
|
- Agents should avoid hard-coding assumptions about token names beyond what the consumer app already defines.
|
|
318
649
|
|
|
650
|
+
## Theme Authoring
|
|
651
|
+
|
|
652
|
+
- `theme.root` supports JS style objects and raw CSS/Sass strings.
|
|
653
|
+
- `theme.components.*` supports JS style objects and raw CSS/Sass strings.
|
|
654
|
+
- `theme.widths` accepts a partial record of width/breakpoint keys to override the default `--w-*` CSS variables. Values are numbers in `px`.
|
|
655
|
+
- String component styles are applied to the mapped target selector (for example `button`, `input[type='checkbox']`).
|
|
656
|
+
- For multi-file Sass workflows with syntax highlighting and mixins, import compiled CSS text via `*.scss?inline`.
|
|
657
|
+
|
|
658
|
+
Valid `theme.widths` keys: `"text" | "gutter" | "column" | "tablet" | "desktop" | "extDesktop" | "mobileMax" | "tabletMax" | "desktopMax"`
|
|
659
|
+
|
|
660
|
+
Example:
|
|
661
|
+
|
|
662
|
+
```tsx
|
|
663
|
+
import greenRoot from "./green.root.scss?inline";
|
|
664
|
+
import greenButton from "./green.button.scss?inline";
|
|
665
|
+
|
|
666
|
+
export const theme = {
|
|
667
|
+
widths: {
|
|
668
|
+
gutter: 20,
|
|
669
|
+
tablet: 768,
|
|
670
|
+
},
|
|
671
|
+
root: greenRoot,
|
|
672
|
+
components: {
|
|
673
|
+
button: greenButton,
|
|
674
|
+
},
|
|
675
|
+
};
|
|
676
|
+
```
|
|
677
|
+
|
|
319
678
|
## Utility Functions
|
|
320
679
|
|
|
321
680
|
### `isEmpty`
|
|
@@ -350,6 +709,37 @@ if (Object.keys(obj).length === 0) { ... }
|
|
|
350
709
|
if (arr.length === 0) { ... }
|
|
351
710
|
```
|
|
352
711
|
|
|
712
|
+
### Style utilities parity (`color`, `width`, `breakpoint`)
|
|
713
|
+
|
|
714
|
+
These utility patterns exist in both TypeScript and Sass.
|
|
715
|
+
|
|
716
|
+
TypeScript usage:
|
|
717
|
+
|
|
718
|
+
```ts
|
|
719
|
+
import { color, width, breakpoint } from "@stamcat/craftsman/styles";
|
|
720
|
+
|
|
721
|
+
const accent = color("blue500");
|
|
722
|
+
const alphaAccent = color("blue500", "rgba", 0.32);
|
|
723
|
+
const twoColumns = width("column", 2);
|
|
724
|
+
const mobileRule = breakpoint("mobileMax", "h4{font-size:14px;}");
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Sass usage (framework source):
|
|
728
|
+
|
|
729
|
+
```scss
|
|
730
|
+
@use "./src/styles/utilities" as u;
|
|
731
|
+
|
|
732
|
+
.example {
|
|
733
|
+
color: #{u.color(blue500)};
|
|
734
|
+
background: #{u.color(blue500, rgba, 0.32)};
|
|
735
|
+
max-width: #{u.width(column, 2)};
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
@include u.breakpoint(mobileMax) {
|
|
739
|
+
.example { font-size: #{u.width(text)}; }
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
353
743
|
## Code Generation Patterns to Prefer
|
|
354
744
|
|
|
355
745
|
1. Generate fully typed React usage examples.
|
|
@@ -367,6 +757,6 @@ if (arr.length === 0) { ... }
|
|
|
367
757
|
|
|
368
758
|
If uncertain about available exports:
|
|
369
759
|
|
|
370
|
-
1. Use only `Button`, `Checkbox`, `Input`, `InputPassword`, `Loader`, `Modal`, and `
|
|
760
|
+
1. Use only `Button`, `Checkbox`, `DatePicker`, `Input`, `InputPassword`, `InputPhone`, `Loader`, `Modal`, `RadioButton`, `Select`, `Text`, and `Textarea` from their component entry points.
|
|
371
761
|
2. Do not invent package APIs.
|
|
372
762
|
3. Prefer native HTML elements for anything not explicitly exported.
|
package/Components.esm.js
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
import { __exportAll as e } from "./_virtual/_rolldown/runtime.esm.js";
|
|
2
|
-
import { Button as t } from "./src/components/Button.esm.js";
|
|
3
|
-
import { Input as n } from "./src/components/Input.esm.js";
|
|
4
|
-
import { InputPassword as r } from "./src/components/InputPassword.esm.js";
|
|
5
|
-
import { Loader as i } from "./src/components/Loader.esm.js";
|
|
6
|
-
import { RadioButton as a } from "./src/components/RadioButton.esm.js";
|
|
7
|
-
import { Checkbox as o } from "./src/components/Checkbox.esm.js";
|
|
8
|
-
import {
|
|
2
|
+
import { Button as t } from "./src/components/Button/Button.esm.js";
|
|
3
|
+
import { Input as n } from "./src/components/Input/Input2.esm.js";
|
|
4
|
+
import { InputPassword as r } from "./src/components/Input/InputPassword.esm.js";
|
|
5
|
+
import { Loader as i } from "./src/components/Loader/Loader.esm.js";
|
|
6
|
+
import { RadioButton as a } from "./src/components/Input/RadioButton.esm.js";
|
|
7
|
+
import { Checkbox as o } from "./src/components/Input/Checkbox.esm.js";
|
|
8
|
+
import { Textarea as s } from "./src/components/Input/Textarea.esm.js";
|
|
9
|
+
import { Text as c } from "./src/components/Text/Text2.esm.js";
|
|
10
|
+
import { Modal as l } from "./src/components/Modal/Modal.esm.js";
|
|
11
|
+
import { Select as u } from "./src/components/Select/Select.esm.js";
|
|
12
|
+
import { DatePicker as d } from "./src/components/Input/DatePicker.esm.js";
|
|
13
|
+
import { InputPhone as f } from "./src/components/Input/InputPhone.esm.js";
|
|
9
14
|
//#region src/components/index.ts
|
|
10
|
-
var
|
|
15
|
+
var p = /* @__PURE__ */ e({
|
|
11
16
|
Button: () => t,
|
|
12
17
|
Checkbox: () => o,
|
|
18
|
+
DatePicker: () => d,
|
|
13
19
|
Input: () => n,
|
|
14
20
|
InputPassword: () => r,
|
|
21
|
+
InputPhone: () => f,
|
|
15
22
|
Loader: () => i,
|
|
16
|
-
Modal: () =>
|
|
17
|
-
RadioButton: () => a
|
|
23
|
+
Modal: () => l,
|
|
24
|
+
RadioButton: () => a,
|
|
25
|
+
Select: () => u,
|
|
26
|
+
Text: () => c,
|
|
27
|
+
Textarea: () => s
|
|
18
28
|
});
|
|
19
29
|
//#endregion
|
|
20
|
-
export { t as Button, o as Checkbox, n as Input, r as InputPassword, i as Loader,
|
|
30
|
+
export { t as Button, o as Checkbox, d as DatePicker, n as Input, r as InputPassword, f as InputPhone, i as Loader, l as Modal, a as RadioButton, u as Select, c as Text, s as Textarea, p as components_exports };
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Use this pattern in React Server Component architectures (for example Next.js Ap
|
|
|
17
17
|
|
|
18
18
|
```tsx
|
|
19
19
|
import { ThemeProvider } from "@stamcat/craftsman/styles";
|
|
20
|
-
import "@stamcat/craftsman/styles/globalStyles
|
|
20
|
+
import "@stamcat/craftsman/styles/globalStyles";
|
|
21
21
|
|
|
22
22
|
const appTheme = {
|
|
23
23
|
root: {
|
|
@@ -50,3 +50,8 @@ import { Modal } from "@stamcat/craftsman/Modal";
|
|
|
50
50
|
|
|
51
51
|
- `ThemeProvider` injects theme CSS variables and component override rules.
|
|
52
52
|
- Global styles should be loaded once at app root.
|
|
53
|
+
- Base defaults are emitted in the `craftsman-base` layer and theme overrides in `craftsman-theme`.
|
|
54
|
+
- For equal specificity, `craftsman-theme` overrides `craftsman-base`.
|
|
55
|
+
- `theme.components.input` targets only non-radio and non-checkbox inputs.
|
|
56
|
+
- `theme.root` and `theme.components.*` support JS style objects and raw CSS/Sass strings.
|
|
57
|
+
- For Sass file workflows, import compiled CSS text via `*.scss?inline` and pass that string into the theme object.
|
package/Styles.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defaultColors as e, defaultWidths as t } from "./src/styles/utilities/constants.esm.js";
|
|
2
2
|
import { color as n, colors as r, hexToRgba as i } from "./src/styles/utilities/color.esm.js";
|
|
3
|
-
import { BaseWidthSchema as a, BreakpointSchema as o,
|
|
4
|
-
import { breakpoint as
|
|
5
|
-
import { themeBuilder as
|
|
6
|
-
import { ThemeProvider as
|
|
7
|
-
export { a as BaseWidthSchema, o as BreakpointSchema, s as
|
|
3
|
+
import { BaseWidthSchema as a, BreakpointSchema as o, ButtonType as s, CarouselPageType as c, LayoutWidthsSchema as l, MaxScreenWidthSchema as u, ScreenWidthSchema as d, TextSize as f, TextTags as p, TextType as m, zLabelPosition as h, zTextInputExclusions as g, zTextInputType as _, zTextInputTypes as v } from "./src/utilities/types.esm.js";
|
|
4
|
+
import { breakpoint as y, media as b, width as x, widths as S } from "./src/styles/utilities/layout.esm.js";
|
|
5
|
+
import { themeBuilder as C } from "./src/styles/theme/theme.esm.js";
|
|
6
|
+
import { ThemeProvider as w } from "./src/styles/components/ThemeProvider.esm.js";
|
|
7
|
+
export { a as BaseWidthSchema, o as BreakpointSchema, s as ButtonType, c as CarouselPageType, l as LayoutWidthsSchema, u as MaxScreenWidthSchema, d as ScreenWidthSchema, f as TextSize, p as TextTags, m as TextType, w as ThemeProvider, y as breakpoint, n as color, r as colors, e as defaultColors, t as defaultWidths, i as hexToRgba, b as media, C as themeBuilder, x as width, S as widths, h as zLabelPosition, g as zTextInputExclusions, _ as zTextInputType, v as zTextInputTypes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamcat/craftsman",
|
|
3
|
-
"version": "0.0.27-alpha.
|
|
3
|
+
"version": "0.0.27-alpha.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A powerful, lightweight framework for design systems",
|
|
6
6
|
"repository": {
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"clsx": "2.1.1",
|
|
27
|
-
"dompurify": "3.4.
|
|
27
|
+
"dompurify": "3.4.13",
|
|
28
|
+
"embla-carousel-react": "8.6.0",
|
|
29
|
+
"pure-react-carousel": "1.35.0",
|
|
28
30
|
"react": "19.2.7",
|
|
29
31
|
"react-date-picker": "12.0.2",
|
|
30
32
|
"react-datetime-picker": "7.0.2",
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {},
|
|
40
42
|
"overrides": {
|
|
41
|
-
"postcss": "8.5.
|
|
43
|
+
"postcss": "8.5.23",
|
|
42
44
|
"sharp": "0.35.3"
|
|
43
45
|
},
|
|
44
46
|
"exports": {
|
|
@@ -54,11 +56,11 @@
|
|
|
54
56
|
"types": "./src/utilities/index.d.ts",
|
|
55
57
|
"default": "./Utilities.esm.js"
|
|
56
58
|
},
|
|
57
|
-
"./styles/globalStyles.
|
|
58
|
-
"default": "./src/styles/global/globalStyles.
|
|
59
|
+
"./styles/globalStyles.scss": {
|
|
60
|
+
"default": "./src/styles/global/globalStyles.scss"
|
|
59
61
|
},
|
|
60
|
-
"./styles/
|
|
61
|
-
"default": "./src/styles/
|
|
62
|
+
"./styles/config": {
|
|
63
|
+
"default": "./src/styles/_config.scss"
|
|
62
64
|
},
|
|
63
65
|
"./Button": {
|
|
64
66
|
"types": "./src/components/Button.d.ts",
|
|
@@ -84,9 +86,29 @@
|
|
|
84
86
|
"types": "./src/components/Checkbox.d.ts",
|
|
85
87
|
"default": "./src/components/Checkbox.esm.js"
|
|
86
88
|
},
|
|
89
|
+
"./Textarea": {
|
|
90
|
+
"types": "./src/components/Textarea.d.ts",
|
|
91
|
+
"default": "./src/components/Textarea.esm.js"
|
|
92
|
+
},
|
|
93
|
+
"./Text": {
|
|
94
|
+
"types": "./src/components/Text.d.ts",
|
|
95
|
+
"default": "./src/components/Text.esm.js"
|
|
96
|
+
},
|
|
87
97
|
"./Modal": {
|
|
88
98
|
"types": "./src/components/Modal.d.ts",
|
|
89
99
|
"default": "./src/components/Modal.esm.js"
|
|
100
|
+
},
|
|
101
|
+
"./Select": {
|
|
102
|
+
"types": "./src/components/Select.d.ts",
|
|
103
|
+
"default": "./src/components/Select.esm.js"
|
|
104
|
+
},
|
|
105
|
+
"./DatePicker": {
|
|
106
|
+
"types": "./src/components/DatePicker.d.ts",
|
|
107
|
+
"default": "./src/components/DatePicker.esm.js"
|
|
108
|
+
},
|
|
109
|
+
"./InputPhone": {
|
|
110
|
+
"types": "./src/components/InputPhone.d.ts",
|
|
111
|
+
"default": "./src/components/InputPhone.esm.js"
|
|
90
112
|
}
|
|
91
113
|
}
|
|
92
114
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { isEmpty as e } from "../../utilities/validations.esm.js";
|
|
3
|
+
import { width as t } from "../../styles/utilities/layout.esm.js";
|
|
4
|
+
import "../../../Styles.esm.js";
|
|
5
|
+
import n from "clsx";
|
|
6
|
+
import { Fragment as r, jsx as i } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/Button/Button.tsx
|
|
8
|
+
var a = (a) => {
|
|
9
|
+
let { type: o = "button", variant: s = "default", size: c, styles: l, className: u, style: d, ...f } = a, p = typeof c == "number" ? Math.min(10, Math.max(.1, c)) : void 0, m = e(l) ? void 0 : l, h = p ? {
|
|
10
|
+
borderRadius: `calc(var(--btn-border-radius) * ${p})`,
|
|
11
|
+
padding: `calc(var(--btn-pad-y) * ${p}) calc(var(--btn-pad-x) * ${p})`,
|
|
12
|
+
fontSize: `max(10px, calc(${t("text")} * ${p}))`
|
|
13
|
+
} : {};
|
|
14
|
+
return e(a.children) ? /* @__PURE__ */ i(r, {}) : /* @__PURE__ */ i("button", {
|
|
15
|
+
type: o,
|
|
16
|
+
className: n(s, u),
|
|
17
|
+
style: {
|
|
18
|
+
...h,
|
|
19
|
+
...m,
|
|
20
|
+
...d
|
|
21
|
+
},
|
|
22
|
+
...f
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { a as Button };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { EmblaOptionsType } from 'embla-carousel';
|
|
3
|
+
import { CarouselPageType } from '../../utilities/types';
|
|
4
|
+
export type CarouselProps = {
|
|
5
|
+
slides?: React.ReactNode[];
|
|
6
|
+
options?: EmblaOptionsType;
|
|
7
|
+
className?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
buttons?: boolean;
|
|
10
|
+
pagination?: CarouselPageType;
|
|
11
|
+
};
|
|
12
|
+
export declare const Carousel: React.FC<CarouselProps>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
@use "../../styles/utilities/functions" as u;
|
|
2
|
+
|
|
3
|
+
.carousel {
|
|
4
|
+
position: relative;
|
|
5
|
+
|
|
6
|
+
&__viewport {
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
&__container {
|
|
11
|
+
display: flex;
|
|
12
|
+
touch-action: pan-y pinch-zoom;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
&__slide {
|
|
16
|
+
flex: 0 0 100%;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&__controls {
|
|
21
|
+
display: inline-flex;
|
|
22
|
+
justify-content: space-between;
|
|
23
|
+
flex-flow: row nowrap;
|
|
24
|
+
gap: #{u.width("gutter", 0.5)};
|
|
25
|
+
margin-top: #{u.width("gutter", 0.75)};
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
&__dots button {
|
|
29
|
+
margin: 0 #{u.width("gutter", 0.125)};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
}
|