@stamcat/craftsman 0.0.27-alpha.2 → 0.0.27-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/AGENTS.md +19 -344
  2. package/Components.esm.js +72 -11
  3. package/README.md +5 -0
  4. package/Styles.esm.js +7 -7
  5. package/Utilities.esm.js +2 -2
  6. package/_virtual/_rolldown/runtime.esm.js +18 -6
  7. package/package.json +75 -6
  8. package/src/components/Button/AGENTS.md +65 -0
  9. package/src/components/{Button.d.ts → Button/Button.d.ts} +1 -1
  10. package/src/components/Button/Button.esm.js +20 -0
  11. package/src/components/Carousel/AGENTS.md +41 -0
  12. package/src/components/Carousel/Carousel.css +1 -0
  13. package/src/components/Carousel/Carousel.d.ts +11 -0
  14. package/src/components/Carousel/Carousel.scss +34 -0
  15. package/src/components/Carousel/Carousel2.esm.js +75 -0
  16. package/src/components/Checkbox/AGENTS.md +34 -0
  17. package/src/components/Checkbox/Checkbox.d.ts +8 -0
  18. package/src/components/Checkbox/Checkbox.esm.js +18 -0
  19. package/src/components/DatePicker/AGENTS.md +36 -0
  20. package/src/components/DatePicker/DatePicker.css +1 -0
  21. package/src/components/DatePicker/DatePicker.d.ts +8 -0
  22. package/src/components/DatePicker/DatePicker.scss +61 -0
  23. package/src/components/DatePicker/DatePicker2.esm.js +29 -0
  24. package/src/components/DatePicker/ReactCalendar.css +1 -0
  25. package/src/components/DatePicker/ReactCalendar.scss +158 -0
  26. package/src/components/DatePicker/_DatePicker.scss +73 -0
  27. package/src/components/DateRangePicker/AGENTS.md +38 -0
  28. package/src/components/DateRangePicker/DateRangePicker.css +1 -0
  29. package/src/components/DateRangePicker/DateRangePicker.d.ts +8 -0
  30. package/src/components/DateRangePicker/DateRangePicker.scss +62 -0
  31. package/src/components/DateRangePicker/DateRangePicker2.esm.js +29 -0
  32. package/src/components/DateTimePicker/AGENTS.md +41 -0
  33. package/src/components/DateTimePicker/DateTimePicker.css +1 -0
  34. package/src/components/DateTimePicker/DateTimePicker.d.ts +13 -0
  35. package/src/components/DateTimePicker/DateTimePicker.scss +86 -0
  36. package/src/components/DateTimePicker/DateTimePicker2.esm.js +82 -0
  37. package/src/components/Icons/IconAmazonPay.d.ts +2 -0
  38. package/src/components/Icons/IconAmazonPay.esm.js +76 -0
  39. package/src/components/Icons/IconAmex.d.ts +2 -0
  40. package/src/components/Icons/IconAmex.esm.js +87 -0
  41. package/src/components/Icons/IconApplePay.d.ts +2 -0
  42. package/src/components/Icons/IconApplePay.esm.js +26 -0
  43. package/src/components/Icons/IconDiscover.d.ts +2 -0
  44. package/src/components/Icons/IconDiscover.esm.js +129 -0
  45. package/src/components/Icons/IconGooglePay.d.ts +2 -0
  46. package/src/components/Icons/IconGooglePay.esm.js +64 -0
  47. package/src/components/Icons/IconMaestro.d.ts +2 -0
  48. package/src/components/Icons/IconMaestro.esm.js +38 -0
  49. package/src/components/Icons/IconMastercard.d.ts +2 -0
  50. package/src/components/Icons/IconMastercard.esm.js +27 -0
  51. package/src/components/Icons/IconPayPal.d.ts +2 -0
  52. package/src/components/Icons/IconPayPal.esm.js +52 -0
  53. package/src/components/Icons/IconSepa.d.ts +2 -0
  54. package/src/components/Icons/IconSepa.esm.js +272 -0
  55. package/src/components/Icons/IconShopPay.d.ts +2 -0
  56. package/src/components/Icons/IconShopPay.esm.js +35 -0
  57. package/src/components/Icons/IconSquare.d.ts +2 -0
  58. package/src/components/Icons/IconSquare.esm.js +11 -0
  59. package/src/components/Icons/IconStripe.d.ts +2 -0
  60. package/src/components/Icons/IconStripe.esm.js +57 -0
  61. package/src/components/Icons/IconUnionPay.d.ts +2 -0
  62. package/src/components/Icons/IconUnionPay.esm.js +28 -0
  63. package/src/components/Icons/IconVenmo.d.ts +2 -0
  64. package/src/components/Icons/IconVenmo.esm.js +21 -0
  65. package/src/components/Icons/IconVisa.d.ts +2 -0
  66. package/src/components/Icons/IconVisa.esm.js +14 -0
  67. package/src/components/Icons/index.d.ts +15 -0
  68. package/src/components/Icons/index.esm.js +16 -0
  69. package/src/components/Icons/types.d.ts +4 -0
  70. package/src/components/Input/AGENTS.md +30 -0
  71. package/src/components/Input/Input.css +1 -0
  72. package/src/components/Input/Input.d.ts +6 -0
  73. package/src/components/Input/Input.scss +176 -0
  74. package/src/components/Input/Input2.esm.js +42 -0
  75. package/src/components/Input/InputWrapper.d.ts +11 -0
  76. package/src/components/Input/InputWrapper.esm.js +22 -0
  77. package/src/components/InputNumber/AGENTS.md +37 -0
  78. package/src/components/InputNumber/InputNumber.css +1 -0
  79. package/src/components/InputNumber/InputNumber.d.ts +10 -0
  80. package/src/components/InputNumber/InputNumber.scss +29 -0
  81. package/src/components/InputNumber/InputNumber2.esm.js +36 -0
  82. package/src/components/InputPassword/AGENTS.md +29 -0
  83. package/src/components/{InputPassword.d.ts → InputPassword/InputPassword.d.ts} +2 -2
  84. package/src/components/InputPassword/InputPassword.esm.js +30 -0
  85. package/src/components/InputPhone/AGENTS.md +35 -0
  86. package/src/components/InputPhone/InputPhone.css +1 -0
  87. package/src/components/InputPhone/InputPhone.d.ts +7 -0
  88. package/src/components/InputPhone/InputPhone.scss +266 -0
  89. package/src/components/InputPhone/InputPhone2.esm.js +27 -0
  90. package/src/components/Loader/AGENTS.md +31 -0
  91. package/src/components/{Loader.d.ts → Loader/Loader.d.ts} +1 -2
  92. package/src/components/Loader/Loader.esm.js +19 -0
  93. package/src/components/Loader/loaders.module.css +1 -0
  94. package/src/components/Loader/loaders.module.esm.js +21 -0
  95. package/src/{styles/global/components → components/Loader}/loaders.module.scss +2 -1
  96. package/src/components/Modal/AGENTS.md +47 -0
  97. package/src/components/Modal/Modal.css +1 -0
  98. package/src/components/{Modal.d.ts → Modal/Modal.d.ts} +0 -1
  99. package/src/components/Modal/Modal.scss +150 -0
  100. package/src/components/Modal/Modal2.esm.js +53 -0
  101. package/src/components/Notice/AGENTS.md +42 -0
  102. package/src/components/Notice/Notice.css +1 -0
  103. package/src/components/Notice/Notice.d.ts +13 -0
  104. package/src/components/Notice/Notice.scss +76 -0
  105. package/src/components/Notice/Notice2.esm.js +56 -0
  106. package/src/components/Pagination/AGENTS.md +38 -0
  107. package/src/components/Pagination/Pagination.css +1 -0
  108. package/src/components/Pagination/Pagination.d.ts +10 -0
  109. package/src/components/Pagination/Pagination.scss +22 -0
  110. package/src/components/Pagination/Pagination2.esm.js +64 -0
  111. package/src/components/RadioButton/AGENTS.md +44 -0
  112. package/src/components/RadioButton/RadioButton.d.ts +9 -0
  113. package/src/components/RadioButton/RadioButton.esm.js +18 -0
  114. package/src/components/Select/AGENTS.md +36 -0
  115. package/src/components/Select/Select.d.ts +14 -0
  116. package/src/components/Select/Select.esm.js +26 -0
  117. package/src/components/SortableList/AGENTS.md +45 -0
  118. package/src/components/SortableList/ListItem.d.ts +10 -0
  119. package/src/components/SortableList/ListItem.esm.js +67 -0
  120. package/src/components/SortableList/SortableList.css +1 -0
  121. package/src/components/SortableList/SortableList.d.ts +23 -0
  122. package/src/components/SortableList/SortableList.scss +41 -0
  123. package/src/components/SortableList/SortableList2.esm.js +54 -0
  124. package/src/components/SortableList/utilities.d.ts +7 -0
  125. package/src/components/SortableList/utilities.esm.js +4 -0
  126. package/src/components/Text/AGENTS.md +32 -0
  127. package/src/components/Text/Text.css +1 -0
  128. package/src/components/Text/Text.d.ts +10 -0
  129. package/src/components/Text/Text.scss +80 -0
  130. package/src/components/Text/Text2.esm.js +23 -0
  131. package/src/components/Textarea/AGENTS.md +32 -0
  132. package/src/components/Textarea/Textarea.d.ts +3 -0
  133. package/src/components/Textarea/Textarea.esm.js +23 -0
  134. package/src/components/TimePicker/AGENTS.md +42 -0
  135. package/src/components/TimePicker/TimePicker.css +1 -0
  136. package/src/components/TimePicker/TimePicker.d.ts +13 -0
  137. package/src/components/TimePicker/TimePicker.scss +226 -0
  138. package/src/components/TimePicker/TimePicker2.esm.js +98 -0
  139. package/src/components/TimePicker/TimePickerDisplay.d.ts +16 -0
  140. package/src/components/TimePicker/TimePickerDisplay.esm.js +54 -0
  141. package/src/components/TimePicker/TimePickerWheel.d.ts +13 -0
  142. package/src/components/TimePicker/TimePickerWheel.esm.js +61 -0
  143. package/src/components/TimePicker/constants.d.ts +7 -0
  144. package/src/components/TimePicker/constants.esm.js +3 -0
  145. package/src/components/TimePicker/utilities.d.ts +15 -0
  146. package/src/components/TimePicker/utilities.esm.js +20 -0
  147. package/src/components/Toggle/AGENTS.md +33 -0
  148. package/src/components/Toggle/Toggle.css +1 -0
  149. package/src/components/Toggle/Toggle.d.ts +5 -0
  150. package/src/components/Toggle/Toggle.scss +64 -0
  151. package/src/components/Toggle/Toggle2.esm.js +19 -0
  152. package/src/components/Tooltip/AGENTS.md +41 -0
  153. package/src/components/Tooltip/Tooltip.css +1 -0
  154. package/src/components/Tooltip/Tooltip.d.ts +12 -0
  155. package/src/components/Tooltip/Tooltip.scss +29 -0
  156. package/src/components/Tooltip/Tooltip2.esm.js +65 -0
  157. package/src/components/index.d.ts +23 -7
  158. package/src/stories/assets/Stam.jpg +0 -0
  159. package/src/stories/assets/kaluah.jpg +0 -0
  160. package/src/stories/assets/stam2.jpg +0 -0
  161. package/src/stories/assets/tito.jpg +0 -0
  162. package/src/stories/documentation/AboutUs.mdx +21 -0
  163. package/src/stories/documentation/GettingStarted.mdx +117 -0
  164. package/src/stories/documentation/Introduction.mdx +29 -0
  165. package/src/stories/documentation/Themes.mdx +264 -0
  166. package/src/stories/documentation/ToDo.mdx +15 -0
  167. package/src/stories/molecules/Carousel.scss +21 -0
  168. package/src/stories/utilities/DeviceDetection.mdx +59 -0
  169. package/src/styles/_config.scss +30 -0
  170. package/src/styles/components/ThemeProvider.esm.js +1 -1
  171. package/src/styles/global/components/_button.scss +56 -52
  172. package/src/styles/global/components/_checkbox.scss +64 -59
  173. package/src/styles/global/components/_code.scss +19 -15
  174. package/src/styles/global/components/_input.scss +29 -37
  175. package/src/styles/global/components/_radioButton.scss +30 -26
  176. package/src/styles/global/components/_select.scss +56 -0
  177. package/src/styles/global/components/_typography.scss +97 -6
  178. package/src/styles/global/globalStyles.module.scss +1 -129
  179. package/src/styles/global/globalStyles.scss +87 -1
  180. package/src/styles/index.d.ts +1 -1
  181. package/src/styles/theme/components.esm.js +11 -7
  182. package/src/styles/theme/theme.esm.js +31 -41
  183. package/src/styles/theme/types.d.ts +4 -1
  184. package/src/styles/utilities/_functions.scss +117 -0
  185. package/src/styles/utilities/_mixins.scss +0 -0
  186. package/src/styles/utilities/_placeholders.scss +6 -0
  187. package/src/styles/utilities/color.d.ts +1 -1
  188. package/src/styles/utilities/constants.d.ts +1 -1
  189. package/src/styles/utilities/layout.d.ts +1 -1
  190. package/src/styles/utilities/layout.esm.js +3 -3
  191. package/src/{styles/utilities → utilities}/types.d.ts +61 -3
  192. package/src/utilities/types.esm.js +85 -0
  193. package/src/utilities/validations.d.ts +5 -0
  194. package/src/utilities/validations.esm.js +19 -1
  195. package/src/components/Button.esm.js +0 -28
  196. package/src/components/Button.module.css +0 -1
  197. package/src/components/Button.module.esm.js +0 -9
  198. package/src/components/Button.module.scss +0 -5
  199. package/src/components/Checkbox.d.ts +0 -7
  200. package/src/components/Checkbox.esm.js +0 -11
  201. package/src/components/Input.d.ts +0 -11
  202. package/src/components/Input.esm.js +0 -41
  203. package/src/components/Input.module.css +0 -1
  204. package/src/components/Input.module.esm.js +0 -11
  205. package/src/components/Input.module.scss +0 -141
  206. package/src/components/InputPassword.esm.js +0 -33
  207. package/src/components/Loader.esm.js +0 -21
  208. package/src/components/Modal.esm.js +0 -62
  209. package/src/components/Modal.module.css +0 -1
  210. package/src/components/Modal.module.esm.js +0 -13
  211. package/src/components/Modal.module.scss +0 -133
  212. package/src/components/RadioButton.d.ts +0 -7
  213. package/src/components/RadioButton.esm.js +0 -11
  214. package/src/styles/global/components/_mixins.scss +0 -2
  215. package/src/styles/global/components/button.d.ts +0 -7
  216. package/src/styles/global/components/loaders.module.css +0 -1
  217. package/src/styles/global/components/loaders.module.esm.js +0 -21
  218. package/src/styles/utilities/types.esm.js +0 -54
  219. package/src/{styles/global/components/loaders.d.ts → components/Loader/types.d.ts} +1 -1
  220. /package/src/{styles/global/components/loaders.esm.js → components/Loader/types.esm.js} +0 -0
  221. /package/src/components/{Progress.d.ts → Progress/Progress.d.ts} +0 -0
@@ -0,0 +1,117 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Getting Started" />
4
+
5
+ # How To Use `ThemeProvider`
6
+
7
+ This guide shows the RSC-safe styling setup and how to apply:
8
+
9
+ 1. custom theme values
10
+ 2. base global styles
11
+
12
+ ## Styling Pattern
13
+
14
+ - `ThemeProvider`
15
+ - Use in any React app, including Next.js App Router
16
+ - Injects theme CSS variables and component override rules
17
+ - Emits overrides in the `craftsman-theme` CSS layer
18
+ - Renders a `<style>` element and wraps children
19
+
20
+ - Global styles
21
+ - Import once at your application root
22
+ - Emit defaults in the `craftsman-base` CSS layer
23
+ - Do not rely on provider side-effect imports for global styling in RSC setups
24
+ - Base is intentionally lower priority than theme when selector specificity is equal
25
+
26
+
27
+ ## 1. Create a Shared Theme Object
28
+
29
+ ```tsx
30
+ import type { Theme } from "@stamcat/craftsman/styles";
31
+ import appRoot from "./app.root.scss?inline";
32
+ import primaryButton from "./primary-button.scss?inline";
33
+
34
+ // Theme config supports raw style objects and raw CSS/Sass strings.
35
+ // You can intermix them within the same theme object.
36
+ export const appTheme: Theme = {
37
+ colors: {
38
+ "--blue500": "#1d4ed8",
39
+ },
40
+ root: appRoot,
41
+ components: {
42
+ button: primaryButton,
43
+ input: {
44
+ borderWidth: "2px",
45
+ },
46
+ },
47
+ };
48
+
49
+ ```
50
+
51
+ ## 2 (a). Setup In a Standard React App
52
+
53
+ ```tsx
54
+ import { ThemeProvider } from "@stamcat/craftsman/styles";
55
+ import "@stamcat/craftsman/styles/globalStyles";
56
+ import ReactDOM from "react-dom/client";
57
+ import { Button } from "@stamcat/craftsman/Button";
58
+ import { appTheme } from "./theme";
59
+
60
+ function App() {
61
+ return <Button variant="primary">Save</Button>;
62
+ }
63
+ ReactDOM.createRoot(document.getElementById("root")!).render(
64
+ <ThemeProvider theme={appTheme}>
65
+ <App />
66
+ </ThemeProvider>,
67
+ );
68
+ ```
69
+
70
+ ## 2 (b). Setup In Next.js App Router
71
+
72
+ Import global styles once in root layout, then render `ThemeProvider` with your theme:
73
+
74
+ ```tsx
75
+ import { ThemeProvider } from "@stamcat/craftsman/styles";
76
+ import "@stamcat/craftsman/styles/globalStyles";
77
+ import { appTheme } from "./theme";
78
+
79
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
80
+ return (
81
+ <html lang="en">
82
+ <body>
83
+ <ThemeProvider theme={appTheme}>{children}</ThemeProvider>
84
+ </body>
85
+ </html>
86
+ );
87
+ }
88
+ ```
89
+
90
+ RSC note:
91
+
92
+ - `ThemeProvider` emits default style-hoisting metadata for compatibility in React Server Components.
93
+ - If your app renders multiple themed providers, pass a unique `href` per provider instance to avoid hoist key collisions.
94
+
95
+ Selector note:
96
+
97
+ - `theme.components.checkbox` targets `input[type='checkbox']`.
98
+ - `theme.components.radioButton` targets `input[type='radio']`.
99
+ - For HTML-tag component keys such as `button`, `select`, and `textarea`, the override is written to both the tag selector and matching class selector, for example `button, .button`.
100
+ - For non-HTML component keys, the override is written to the component class selector, for example `.modal`.
101
+
102
+ Style declaration note:
103
+
104
+ - `theme.root` accepts either a JS style object or a raw CSS/Sass string.
105
+ - `theme.components.*` accepts either a JS style object or a raw CSS/Sass string for that target selector.
106
+ - For file-based styles, import `*.scss?inline` or `*.css?inline` and pass the resulting string.
107
+ - Use JS style objects for small inline overrides, and SCSS/CSS files when you want larger style blocks or Sass features.
108
+
109
+ - Prefer one provider at app root.
110
+ - Keep `theme` for component and CSS-variable overrides.
111
+ - Use `theme.root` CSS variables to override base design tokens like widths.
112
+
113
+ ## Editor Setup (CSS Modules IntelliSense)
114
+
115
+ - Install the recommended VS Code extension: `clinyong.vscode-css-modules`.
116
+ - The project already includes `vite-plugin-typed-css-modules` and `typescript-plugin-css-modules` for typed class names and TS language-service support.
117
+ - After installing extensions or pulling config changes, run `TypeScript: Restart TS Server` from the Command Palette.
@@ -0,0 +1,29 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Introduction" />
4
+
5
+ # Craftsman Design System Framework
6
+ A lightweight framework to create your own design system for React front-end applications.
7
+
8
+ #### What this isn't...
9
+ This is NOT a design system per-se. A design system comes out of the box fully complete with styles that support your brand. <br />
10
+ You are welcome to use this as-is without providing your own branding, however we believe you will be left wanting more..
11
+
12
+ #### What this is...
13
+ Craftsman is a Framework that requires you to define your own brand styles. The Framework provides a flexible, extensible and scalable solution for reusable components along the way.<br />
14
+ Our goal is to provide industry-standard solutions for global enterprise-level applications, empowering you - the designer or developer - to focus on what matters most: <b>User Experience.</b>
15
+
16
+ ## Why not just use `{some_existing_framework}`?
17
+ Many of the existing frameworks out in the wild are far too opinionated. As a result, they become bloated, trying to solve problems you'll never have in ways that contradict everything you product stands for.
18
+ Craftsman strives to be as unopinionated as possible, giving you the freedom to explore solutions that work best for you.<br />
19
+
20
+ When we are forced to assert an opinion, we seek to be as flexible as possible and rely on the open-source community before re-inventing the wheel.
21
+
22
+ ## Let's just vibe code...Tokenmaxxing FTW!
23
+ You absolutely can if you want, but we think you'll have a much better starting point with code that is forged by human experience.<br />
24
+
25
+ The Craftsman Framework draws inspiration from <a href="https://en.wikipedia.org/wiki/American_Craftsman" target="_blank">Arts & Crafts movement of the late 19th century</a>
26
+
27
+ > The movement emphasized handwork over mass production. In some ways, it was just as much of a social movement as it was an aesthetic one, emphasizing the plight of the industrial worker and equating moral rectitude with the ability to create beautiful but simple things.
28
+
29
+ In the physical world, you can't throw a nailgun at a pile of wood and have a house, we believe you can't expect different of your coding tools. We use AI intelligently, deliberately, and we limit the scope in such a way that enhances our creativity, rather than use it as a crutch to save us the agony of thought.<br /><br />
@@ -0,0 +1,264 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Themes & Styles" />
4
+
5
+ # Themes & Styles
6
+
7
+ Craftsman themes are plain objects that conform to the `Theme` type. You pass them into `ThemeProvider` and the framework applies them globally via CSS variables and component selectors.
8
+
9
+ Theme cascade order is layered:
10
+
11
+ - Base defaults are emitted in the `craftsman-base` layer.
12
+ - Theme overrides are emitted in the `craftsman-theme` layer.
13
+ - `craftsman-theme` is declared after `craftsman-base`, so theme values win when specificity is equal.
14
+
15
+ Craftsman supports styles in **two different ways** — plain JS objects or raw CSS/Sass strings. They are interchangeable and can be mixed within the same theme object. We encourage you to use HTML5 and take advantage of css nesting wherever possible. When custom styles are required, we intend to make all options available to you, so that you can build the app however works best for your product. Yes, you can even use Failwind.
16
+
17
+ ## How CSS Layers Work
18
+
19
+ Craftsman relies on the native [`@layer`](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) at-rule to control the cascade instead of specificity hacks (`!important`, ID selectors, deeply nested overrides).
20
+
21
+ A `@layer` declares a named cascade layer. Layers are ordered by the position of their *first* declaration, not by where their rules physically live in the file — so declaring the layer order once up front lets every subsequent block, wherever it's authored, slot into that order:
22
+
23
+ ```css
24
+ /* declares the order once: craftsman-base loses to craftsman-theme on a tie */
25
+ @layer craftsman-base, craftsman-theme;
26
+ ```
27
+
28
+ Two rules make this predictable:
29
+
30
+ 1. **Unlayered styles always beat layered styles.** Any plain CSS you write with no `@layer` wrapper (your app's own stylesheets, CSS Modules, styled-components, etc.) sits *above* every named layer, regardless of selector specificity. This is what makes Craftsman trivially overridable — you don't need to fight specificity to override a Craftsman default.
31
+ 2. **Between layers, declaration order wins on a tie**, not specificity. That's why `craftsman-theme` is declared after `craftsman-base` — a `.button` rule in `craftsman-theme` beats a `.button` rule in `craftsman-base` even though the selectors are equally specific.
32
+
33
+ ### Everything Craftsman ships lives in `craftsman-base`
34
+
35
+ Every component stylesheet and the global reset are wrapped in `@layer craftsman-base { ... }`:
36
+
37
+ ```scss
38
+ /* src/components/Button/Button.scss (abbreviated) */
39
+ @layer craftsman-base {
40
+ .button {
41
+ border-radius: 6px;
42
+ padding: 0.5em 1em;
43
+ }
44
+ }
45
+ ```
46
+
47
+ This means all of Craftsman's built-in styling is intentionally low-priority in the cascade:
48
+
49
+ - `ThemeProvider` overrides win automatically because they're emitted in `craftsman-theme`, declared after `craftsman-base`.
50
+ - Your own app CSS wins automatically because it's unlayered, beating both Craftsman layers with zero specificity gymnastics.
51
+
52
+ You never need `!important`, extra class chains, or `:where()` tricks to override a Craftsman component — a plain, unlayered selector of any specificity is enough.
53
+
54
+ ## Setup
55
+
56
+ Render `ThemeProvider` once near your app root:
57
+
58
+ ```tsx
59
+ import { ThemeProvider } from "@stamcat/craftsman/styles";
60
+ import { myTheme } from "./themes";
61
+
62
+ export function App() {
63
+ return (
64
+ <>
65
+ <ThemeProvider theme={myTheme} />
66
+ {/* your app */}
67
+ </>
68
+ );
69
+ }
70
+ ```
71
+
72
+ The `Theme` type accepts three optional keys:
73
+
74
+ | Key | Purpose |
75
+ |---|---|
76
+ | `colors` | Override any named CSS color variable (e.g. `--blue500`) |
77
+ | `root` | `:root` overrides as an object, serialized style object, or raw CSS/Sass string |
78
+ | `components` | Per-component style overrides keyed by component name |
79
+
80
+ ---
81
+
82
+ ## 1. Plain JavaScript object
83
+
84
+ The simplest approach. Pass a `CSSObject` directly — identical to what you would write in an inline style object.
85
+
86
+ ```ts
87
+ import type { Theme } from "@stamcat/craftsman/styles";
88
+
89
+ export const myTheme: Theme = {
90
+ root: {
91
+ "--w-gutter": "14px",
92
+ },
93
+ components: {
94
+ button: {
95
+ backgroundColor: "#16a34a",
96
+ color: "#ffffff",
97
+ border: "2px solid green",
98
+ borderRadius: "8px",
99
+ },
100
+ },
101
+ };
102
+ ```
103
+
104
+ Use this when you want a zero-dependency, no-build-step definition that lives entirely in a `.ts` file.
105
+
106
+ ---
107
+
108
+ ## 2. Raw CSS / Sass Strings
109
+
110
+ Pass CSS text directly as strings. For larger themes, import Sass files as compiled inline strings with Vite's `?inline` suffix.
111
+
112
+ ```scss
113
+ /* green.root.scss */
114
+ :root {
115
+ --w-gutter: 18px;
116
+ --w-text: 15px;
117
+ }
118
+ ```
119
+
120
+ ```scss
121
+ /* green.button.scss */
122
+ button {
123
+ background-color: #16a34a;
124
+ color: #ffffff;
125
+ border: 2px solid green;
126
+ border-radius: 8px;
127
+
128
+ &.primary {
129
+ background-color: #14532d;
130
+ border-color: #14532d;
131
+ }
132
+ }
133
+ ```
134
+
135
+ ```ts
136
+ import type { Theme } from "@stamcat/craftsman/styles";
137
+ import greenRoot from "./green.root.scss?inline";
138
+ import greenButton from "./green.button.scss?inline";
139
+
140
+ export const myTheme: Theme = {
141
+ colors: {
142
+ "--blue500": "#31198a",
143
+ },
144
+ root: greenRoot,
145
+ components: {
146
+ button: greenButton,
147
+ },
148
+ };
149
+ ```
150
+
151
+ Use this when you want full Sass syntax highlighting, mixins, and file organization while keeping theme injection RSC-safe.
152
+
153
+ ### Component selector mapping
154
+
155
+ Theme component entries are written to these selectors:
156
+
157
+ | Component key | Selector target |
158
+ |---|---|
159
+ | `input` | `input:not([type='radio']):not([type='checkbox'])` |
160
+ | `checkbox` | `input[type='checkbox']` |
161
+ | `radioButton` | `input[type='radio']` |
162
+ | HTML-tag keys such as `button`, `select`, `textarea` | both the HTML tag and matching class selector, for example `button, .button` |
163
+ | Non-HTML component keys such as `modal` | component class selector, for example `.modal` |
164
+
165
+ This mapping comes from the exported component name. The theme key is the uncapitalized component name, for example `Button` -> `button`, `RadioButton` -> `radioButton`.
166
+
167
+ ---
168
+
169
+ ## Defining multiple themes
170
+
171
+ Export a record of themes and switch between them at runtime.
172
+
173
+ ```ts
174
+ import type { AppTheme } from "@stamcat/craftsman/styles";
175
+
176
+ export const appThemes: AppTheme = {
177
+ default: { root: { "--w-gutter": "14px" } },
178
+ green: { components: { button: { backgroundColor: "#16a34a" } } },
179
+ brand: { colors: { "--blue500": "#31198a" } },
180
+ };
181
+ ```
182
+
183
+ ```tsx
184
+ // app.tsx
185
+ import React from "react";
186
+ import ReactDOM from "react-dom/client";
187
+ import { ThemeProvider } from "@stamcat/craftsman/styles";
188
+ import { Button } from "@stamcat/craftsman/Button";
189
+ import { appTheme } from "./theme";
190
+
191
+ function App() {
192
+ return <Button variant="primary">Save</Button>;
193
+ }
194
+
195
+ ReactDOM.createRoot(document.getElementById("root")!).render(
196
+ <>
197
+ <ThemeProvider theme={appTheme} />
198
+ <App />
199
+ </>,
200
+ );
201
+ ```
202
+
203
+ Switch themes using the **Themes** icon in the Storybook toolbar to see each variant applied live across all stories.
204
+
205
+ ---
206
+
207
+ ## Utility Parity (TypeScript + Sass)
208
+
209
+ The `color`, `width`, and `breakpoint` utilities exist in both TypeScript and Sass and follow the same usage patterns.
210
+
211
+ ### Color utility
212
+
213
+ ```ts
214
+ import { color } from "@stamcat/craftsman/styles";
215
+
216
+ const border = color("green500");
217
+ const overlay = color("green500", "rgba", 0.24);
218
+ ```
219
+
220
+ ```scss
221
+ @use "../../styles/utilities/_functions" as u;
222
+
223
+ .example {
224
+ border-color: #{u.color(green500)};
225
+ background-color: #{u.color(green500, rgba, 0.24)};
226
+ }
227
+ ```
228
+
229
+ ### Width utility
230
+
231
+ ```ts
232
+ import { width } from "@stamcat/craftsman/styles";
233
+
234
+ const text = width("text");
235
+ const cols = width("column", 3);
236
+ const numeric = width("column", 3, false);
237
+ ```
238
+
239
+ ```scss
240
+ @use "../../styles/utilities/_functions" as u;
241
+
242
+ .example {
243
+ font-size: #{u.width(text)};
244
+ max-width: #{u.width(column, 3)};
245
+ --column-count: #{u.width(column, 3, false)};
246
+ }
247
+ ```
248
+
249
+ ### Breakpoint utility
250
+
251
+ ```ts
252
+ import { breakpoint } from "@stamcat/craftsman/styles";
253
+
254
+ const rules = breakpoint("mobileMax", "h4{font-size:14px;} p{font-size:12.25px;}");
255
+ ```
256
+
257
+ ```scss
258
+ @use "../../styles/utilities/_functions" as u;
259
+
260
+ @include u.breakpoint(mobileMax) {
261
+ :where(h4) { font-size: var(--w-text, 14px); }
262
+ :where(p) { font-size: calc(var(--w-text, 14px) * 0.875); }
263
+ }
264
+ ```
@@ -0,0 +1,15 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="To Do" />
4
+
5
+ # Global Styles
6
+ - video
7
+ - image
8
+ - radio button alignment to baseline
9
+ - implement dark mode @media (prefers-color-scheme: dark)
10
+ - Accordion
11
+ - Progress
12
+ - Skeleton
13
+ - Toast - enhance to show pile vs stacking
14
+ - Tabs
15
+ - sortable list
@@ -0,0 +1,21 @@
1
+
2
+ @use "../../styles/utilities/_functions" as u;
3
+
4
+ @layer craftsman-base {
5
+ .carouselWrapper {
6
+ width: 400px;
7
+ img {
8
+ width: 100%;
9
+ }
10
+ figcaption {
11
+ position: absolute;
12
+ bottom: 0;
13
+ width: 100%;
14
+ text-align: center;
15
+ font-weight: bold;
16
+ background-color: #{u.color("white", rgba, 0.75)};
17
+ padding: #{u.width("gutter", 0.5)} 0 #{u.width("gutter")};
18
+ }
19
+
20
+ }
21
+ }
@@ -0,0 +1,59 @@
1
+ import { Meta } from "@storybook/addon-docs/blocks";
2
+
3
+ <Meta title="Utilities/Device Detection" />
4
+
5
+ # Device Detection
6
+
7
+ Craftsman already depends on [`react-device-detect`](https://www.npmjs.com/package/react-device-detect) — it's what powers `TimePicker`'s mobile wheel-picker fallback. **Use it instead of writing custom user-agent sniffing or `window.innerWidth` checks** whenever a decision depends on the actual device, browser, or OS rather than pure viewport width.
8
+
9
+ ```tsx
10
+ // DO NOT — fragile, reinvents an already-solved problem
11
+ const isMobile = /Mobi|Android/i.test(navigator.userAgent);
12
+ const isMobile = window.innerWidth < 768;
13
+
14
+ // DO
15
+ import { isMobile } from "react-device-detect";
16
+ ```
17
+
18
+ Pure layout/visual breakpoints (font size, column count, spacing) still belong in CSS media queries — see the `width()`/`breakpoint()` style utilities. Reach for `react-device-detect` when the branch happens in JS/TS, or the check needs to distinguish device/browser/OS rather than just viewport size.
19
+
20
+ ## Boolean Flags
21
+
22
+ ```tsx
23
+ import { isMobile, isTablet, isDesktop, isBrowser, isSmartTV, isMobileOnly, isAndroid, isIOS } from "react-device-detect";
24
+
25
+ if (isMobile) {
26
+ // mobile-specific behavior
27
+ }
28
+ ```
29
+
30
+ `isMobileOnly` excludes tablets — use it instead of `isMobile` whenever tablets need to be treated like desktop/browser.
31
+
32
+ ## Declarative View Components
33
+
34
+ As an alternative to branching inside JSX, use the wrapper components — they render `children` only when the matching device is detected:
35
+
36
+ ```tsx
37
+ import { MobileView, BrowserView, TabletView } from "react-device-detect";
38
+
39
+ <MobileView>
40
+ <CompactNav />
41
+ </MobileView>
42
+ <BrowserView>
43
+ <FullNav />
44
+ </BrowserView>
45
+ ```
46
+
47
+ ## Orientation
48
+
49
+ Use the `useMobileOrientation` hook rather than comparing `window.innerWidth`/`innerHeight` for portrait/landscape checks:
50
+
51
+ ```tsx
52
+ import { useMobileOrientation } from "react-device-detect";
53
+
54
+ const { isPortrait, isLandscape } = useMobileOrientation();
55
+ ```
56
+
57
+ ## Informational Values
58
+
59
+ `browserName`, `osName`, and `deviceType` return strings meant for logging/analytics — prefer the boolean flags above when the result drives conditional logic.
@@ -0,0 +1,30 @@
1
+ /// Configurable Sass variables for @stamcat/craftsman.
2
+ ///
3
+ /// To override breakpoints in your application, load this module first with
4
+ /// your custom values before importing any other craftsman styles:
5
+ ///
6
+ /// @example scss
7
+ /// @use "@stamcat/craftsman/styles/config" with (
8
+ /// $bp-tablet: 768,
9
+ /// $bp-desktop: 1200,
10
+ /// $bp-mobileMax: 767.99999,
11
+ /// $bp-tabletMax: 1199.99999,
12
+ /// );
13
+ /// @use "@stamcat/craftsman/styles/global/globalStyles";
14
+
15
+ // All values are unitless numbers (px implied).
16
+ // Default values mirror src/styles/utilities/constants.ts.
17
+
18
+ // Width defaults
19
+ $w-text: 14 !default;
20
+ $w-gutter: 16 !default;
21
+ $w-column: 60 !default;
22
+
23
+ // Breakpoint values used in @media queries.
24
+ // CSS custom properties cannot be used in @media conditions — these must be static values.
25
+ $bp-mobileMax: 659.99999 !default;
26
+ $bp-tablet: 660 !default;
27
+ $bp-tabletMax: 1039.99999 !default;
28
+ $bp-desktop: 1040 !default;
29
+ $bp-desktopMax: 1319.99999 !default;
30
+ $bp-extDesktop: 1320 !default;
@@ -1,7 +1,7 @@
1
1
  import { themeBuilder as e } from "../theme/theme.esm.js";
2
2
  import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
3
3
  //#region src/styles/components/ThemeProvider.tsx
4
- function i({ theme: i, children: a, precedence: o = "default", href: s = "stamcat-craftsman-theme-provider" }) {
4
+ function i({ theme: i, children: a, precedence: o = "high", href: s = "stamcat-craftsman-theme-provider" }) {
5
5
  return /* @__PURE__ */ r(t, { children: [/* @__PURE__ */ n("style", {
6
6
  precedence: o,
7
7
  href: s,
@@ -1,64 +1,68 @@
1
- %text-link {
2
- padding: 0;
3
- border: none;
4
- background: none;
5
- color: var(--blue500);
1
+ @use "../../utilities/functions" as u;
6
2
 
7
- &:not(:disabled):not(.disabled):hover {
8
- color: var(--teal700);
9
- background-color: transparent;
10
- text-decoration: underline;
11
- cursor: pointer;
12
- }
13
- }
3
+ @layer craftsman-base {
4
+ %text-link {
5
+ padding: 0;
6
+ border: none;
7
+ background: none;
8
+ color: var(--blue500);
14
9
 
15
- %button-styles {
16
- --btn-pad-y: calc(var(--w-gutter, 16px) * 0.5);
17
- --btn-pad-x: calc(var(--w-gutter, 16px) * 0.75);
18
- --btn-border-radius: calc(var(--w-gutter, 16px) * 0.75);
19
- color: var(--blue600);
20
- border: none;
21
- cursor: pointer;
22
- display: inline-flex;
23
- flex-flow: row wrap;
24
- align-items: center;
25
- font-weight: 500;
26
- transition: 0.125s;
27
- padding: var(--btn-pad-y) var(--btn-pad-x);
28
- border-radius: var(--btn-border-radius);
29
- border: 1px solid var(--blue500);
30
- background-color: var(--white);
31
-
32
- &:not(:disabled):not(.disabled):hover {
33
- background-color: var(--teal200);
10
+ &:hover {
11
+ color: var(--teal700);
12
+ background-color: transparent;
13
+ text-decoration: underline;
14
+ cursor: pointer;
15
+ &.disabled, &:disabled {
16
+ cursor: not-allowed;
17
+ color: #{u.color("gray400")};
18
+ }
19
+ }
34
20
  }
35
21
 
36
- &.text,
37
- &[data-variant="text"] {
38
- @extend %text-link;
39
- }
22
+ %button-styles {
23
+ --btn-size: 1;
24
+ color: var(--blue600);
25
+ border: none;
26
+ cursor: pointer;
27
+ display: inline-flex;
28
+ flex-flow: row wrap;
29
+ align-items: center;
30
+ font-weight: 500;
31
+ transition: 0.125s;
32
+ padding: calc(#{u.width(gutter, 0.5)} * var(--btn-size)) calc(#{u.width(gutter, 0.75)} * var(--btn-size));
33
+ border-radius: calc(#{u.width(gutter, 0.75)} * var(--btn-size));
34
+ font-size: max(10px, calc(#{u.width(text)} * var(--btn-size)));
35
+ border: 1px solid var(--blue500);
36
+ background-color: var(--white);
37
+
38
+ &:hover {
39
+ background-color: var(--teal200);
40
+ }
40
41
 
41
- &:disabled,
42
- &.disabled {
43
- cursor: not-allowed;
44
- border-color: var(--gray200);
45
- color: var(--gray400);
42
+ &.primary {
43
+ color: var(--white);
44
+ background-color: var(--blue500);
46
45
 
47
- &.primary,
48
- &[data-variant="primary"] {
49
- border-color: var(--gray200);
50
- background-color: var(--gray400);
51
- color: var(--gray200);
46
+ &:hover {
47
+ background-color: var(--blue700);
48
+ }
49
+ }
50
+
51
+ &.text {
52
+ @extend %text-link;
52
53
  }
53
- }
54
54
 
55
- &.primary,
56
- &[data-variant="primary"] {
57
- color: var(--white);
58
- background-color: var(--blue500);
55
+ &:disabled,
56
+ &.disabled {
57
+ cursor: not-allowed;
58
+ border-color: #{u.color("gray200")};
59
+ color: #{u.color("gray400")};
59
60
 
60
- &:not(:disabled):not(.disabled):hover {
61
- background-color: var(--blue700);
61
+ &.primary {
62
+ border-color: #{u.color("gray200")};
63
+ background-color: #{u.color("gray400")};
64
+ color: #{u.color("gray200")};
65
+ }
62
66
  }
63
67
  }
64
68
  }