@recursica/mantine-adapter 0.5.0 → 0.7.0

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 (160) hide show
  1. package/.storybook/commonArgTypes.ts +148 -0
  2. package/CHANGELOG.md +69 -0
  3. package/dist/mantine-adapter.cjs +1 -1
  4. package/dist/mantine-adapter.cjs.map +1 -1
  5. package/dist/mantine-adapter.css +1 -1
  6. package/dist/mantine-adapter.js +1076 -266
  7. package/dist/mantine-adapter.js.map +1 -1
  8. package/dist/src/components/Accordion/Accordion.d.ts +13 -28
  9. package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +10 -0
  10. package/dist/src/components/Avatar/Avatar.d.ts +1 -1
  11. package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +6 -3
  12. package/dist/src/components/Button/Button.d.ts +1 -1
  13. package/dist/src/components/Card/Card.d.ts +38 -3
  14. package/dist/src/components/Checkbox/Checkbox.d.ts +11 -3
  15. package/dist/src/components/Checkbox/CheckboxGroup.d.ts +9 -0
  16. package/dist/src/components/Chip/Chip.d.ts +14 -2
  17. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +18 -0
  18. package/dist/src/components/Label/Label.d.ts +21 -0
  19. package/dist/src/components/Label/index.d.ts +1 -0
  20. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +19 -2
  21. package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
  22. package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +22 -0
  23. package/dist/src/components/ReadOnlyField/index.d.ts +3 -0
  24. package/dist/src/components/Text/Text.d.ts +17 -0
  25. package/dist/src/components/TextField/TextField.d.ts +8 -2
  26. package/dist/src/components/Title/Title.d.ts +13 -0
  27. package/dist/src/components/index.d.ts +3 -1
  28. package/dist/src/utils/ColorSchemeWrapper.d.ts +3 -0
  29. package/dist/src/utils/filterStylingProps.d.ts +6 -2
  30. package/package.json +9 -5
  31. package/src/OverStyling.stories.tsx +174 -0
  32. package/src/Version.stories.tsx +56 -0
  33. package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +48 -0
  34. package/src/components/Accordion/Accordion.module.css +261 -0
  35. package/src/components/Accordion/Accordion.stories.tsx +145 -0
  36. package/src/components/Accordion/Accordion.tsx +200 -0
  37. package/src/components/Accordion/index.ts +1 -0
  38. package/src/components/AssistiveElement/AssistiveElement.module.css +111 -0
  39. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +73 -0
  40. package/src/components/AssistiveElement/AssistiveElement.tsx +91 -0
  41. package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +24 -0
  42. package/src/components/Avatar/Avatar.module.css +340 -0
  43. package/src/components/Avatar/Avatar.stories.tsx +102 -0
  44. package/src/components/Avatar/Avatar.tsx +100 -0
  45. package/src/components/Avatar/index.ts +1 -0
  46. package/src/components/Badge/BADGE_IMPLEMENTATION_NOTES.md +18 -0
  47. package/src/components/Badge/Badge.module.css +124 -0
  48. package/src/components/Badge/Badge.stories.tsx +77 -0
  49. package/src/components/Badge/Badge.tsx +66 -0
  50. package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +14 -0
  51. package/src/components/Breadcrumb/Breadcrumb.module.css +26 -0
  52. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +77 -0
  53. package/src/components/Breadcrumb/Breadcrumb.tsx +64 -0
  54. package/src/components/Button/Button.module.css +275 -0
  55. package/src/components/Button/Button.stories.tsx +105 -0
  56. package/src/components/Button/Button.tsx +122 -0
  57. package/src/components/Button/IMPLEMENTATION_NOTES.md +45 -0
  58. package/src/components/Button/index.ts +1 -0
  59. package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +10 -0
  60. package/src/components/Card/Card.module.css +60 -0
  61. package/src/components/Card/Card.stories.tsx +141 -0
  62. package/src/components/Card/Card.tsx +176 -0
  63. package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +25 -0
  64. package/src/components/Checkbox/Checkbox.module.css +204 -0
  65. package/src/components/Checkbox/Checkbox.stories.tsx +73 -0
  66. package/src/components/Checkbox/Checkbox.tsx +111 -0
  67. package/src/components/Checkbox/CheckboxGroup.stories.tsx +138 -0
  68. package/src/components/Checkbox/CheckboxGroup.tsx +140 -0
  69. package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +35 -0
  70. package/src/components/Chip/Chip.module.css +218 -0
  71. package/src/components/Chip/Chip.stories.tsx +115 -0
  72. package/src/components/Chip/Chip.tsx +143 -0
  73. package/src/components/DatePicker/DatePicker.stories.tsx +22 -0
  74. package/src/components/DatePicker/DatePicker.tsx +7 -0
  75. package/src/components/Dropdown/Dropdown.stories.tsx +22 -0
  76. package/src/components/Dropdown/Dropdown.tsx +7 -0
  77. package/src/components/FileInput/FileInput.stories.tsx +22 -0
  78. package/src/components/FileInput/FileInput.tsx +7 -0
  79. package/src/components/FileUpload/FileUpload.stories.tsx +22 -0
  80. package/src/components/FileUpload/FileUpload.tsx +7 -0
  81. package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +32 -0
  82. package/src/components/FormControlWrapper/FormControlWrapper.module.css +46 -0
  83. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -0
  84. package/src/components/FormControlWrapper/FormControlWrapper.tsx +170 -0
  85. package/src/components/HoverCard/HoverCard.stories.tsx +17 -0
  86. package/src/components/HoverCard/HoverCard.tsx +7 -0
  87. package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +48 -0
  88. package/src/components/Label/Label.module.css +177 -0
  89. package/src/components/Label/Label.stories.tsx +123 -0
  90. package/src/components/Label/Label.tsx +132 -0
  91. package/src/components/Label/index.ts +1 -0
  92. package/src/components/Link/Link.stories.tsx +17 -0
  93. package/src/components/Link/Link.tsx +7 -0
  94. package/src/components/Loader/Loader.stories.tsx +17 -0
  95. package/src/components/Loader/Loader.tsx +7 -0
  96. package/src/components/Menu/Menu.stories.tsx +17 -0
  97. package/src/components/Menu/Menu.tsx +7 -0
  98. package/src/components/Modal/Modal.stories.tsx +17 -0
  99. package/src/components/Modal/Modal.tsx +7 -0
  100. package/src/components/NumberInput/NumberInput.stories.tsx +22 -0
  101. package/src/components/NumberInput/NumberInput.tsx +7 -0
  102. package/src/components/Pagination/Pagination.stories.tsx +17 -0
  103. package/src/components/Pagination/Pagination.tsx +7 -0
  104. package/src/components/Panel/Panel.stories.tsx +17 -0
  105. package/src/components/Panel/Panel.tsx +7 -0
  106. package/src/components/Popover/Popover.stories.tsx +17 -0
  107. package/src/components/Popover/Popover.tsx +7 -0
  108. package/src/components/Radio/Radio.stories.tsx +22 -0
  109. package/src/components/Radio/Radio.tsx +7 -0
  110. package/src/components/ReadOnlyField/READ_ONLY_FIELD_IMPLEMENTATION_NOTES.md +15 -0
  111. package/src/components/ReadOnlyField/ReadOnlyField.module.css +49 -0
  112. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +120 -0
  113. package/src/components/ReadOnlyField/ReadOnlyField.tsx +75 -0
  114. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +46 -0
  115. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +85 -0
  116. package/src/components/ReadOnlyField/index.ts +3 -0
  117. package/src/components/Search/Search.stories.tsx +17 -0
  118. package/src/components/Search/Search.tsx +7 -0
  119. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +22 -0
  120. package/src/components/SegmentedControl/SegmentedControl.tsx +7 -0
  121. package/src/components/Slider/Slider.stories.tsx +22 -0
  122. package/src/components/Slider/Slider.tsx +7 -0
  123. package/src/components/Stepper/Stepper.stories.tsx +17 -0
  124. package/src/components/Stepper/Stepper.tsx +7 -0
  125. package/src/components/Switch/Switch.stories.tsx +22 -0
  126. package/src/components/Switch/Switch.tsx +7 -0
  127. package/src/components/Table/Table.stories.tsx +17 -0
  128. package/src/components/Table/Table.tsx +7 -0
  129. package/src/components/Tabs/Tabs.stories.tsx +17 -0
  130. package/src/components/Tabs/Tabs.tsx +7 -0
  131. package/src/components/Text/Text.stories.tsx +88 -0
  132. package/src/components/Text/Text.tsx +54 -0
  133. package/src/components/TextArea/TextArea.stories.tsx +22 -0
  134. package/src/components/TextArea/TextArea.tsx +7 -0
  135. package/src/components/TextField/TEXTFIELD_IMPLEMENTATION_NOTES.md +19 -0
  136. package/src/components/TextField/TextField.module.css +225 -0
  137. package/src/components/TextField/TextField.stories.tsx +162 -0
  138. package/src/components/TextField/TextField.tsx +138 -0
  139. package/src/components/TimePicker/TimePicker.stories.tsx +22 -0
  140. package/src/components/TimePicker/TimePicker.tsx +7 -0
  141. package/src/components/Timeline/Timeline.stories.tsx +17 -0
  142. package/src/components/Timeline/Timeline.tsx +7 -0
  143. package/src/components/Title/Title.stories.tsx +63 -0
  144. package/src/components/Title/Title.tsx +45 -0
  145. package/src/components/Toast/Toast.stories.tsx +17 -0
  146. package/src/components/Toast/Toast.tsx +7 -0
  147. package/src/components/Tooltip/Tooltip.stories.tsx +17 -0
  148. package/src/components/Tooltip/Tooltip.tsx +7 -0
  149. package/src/components/TransferList/TransferList.stories.tsx +17 -0
  150. package/src/components/TransferList/TransferList.tsx +7 -0
  151. package/src/components/index.ts +39 -0
  152. package/src/env.d.ts +7 -0
  153. package/src/index.ts +3 -0
  154. package/src/types/index.ts +9 -0
  155. package/src/types/mantine.d.ts +7 -0
  156. package/src/types/scss-modules.d.ts +9 -0
  157. package/src/utils/ColorSchemeWrapper.tsx +27 -0
  158. package/src/utils/copyToClipboard.ts +36 -0
  159. package/src/utils/filterStylingProps.ts +139 -0
  160. package/src/utils/index.ts +1 -0
@@ -0,0 +1,141 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Card } from "./Card";
3
+ import { Layer } from "@recursica/adapter-common";
4
+ import { Button } from "../Button/Button";
5
+
6
+ const meta: Meta<typeof Card> = {
7
+ title: "UI-Kit/Card",
8
+ component: Card,
9
+ subcomponents: {
10
+ "Card.Header": Card.Header,
11
+ "Card.Content": Card.Content,
12
+ "Card.Footer": Card.Footer,
13
+ "Card.Section": Card.Section,
14
+ } as Record<string, React.ComponentType<unknown>>,
15
+ tags: ["autodocs"],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component:
20
+ "The Card component acts as the foundational padded surface for grouping related information. It relies on standard internal compositional nodes (`Card.Header`, `Card.Content`, `Card.Footer`) mapped directly to the active Recursica design tokens to enforce layout gaps and margins seamlessly. Use the provided dot-notation wrappers rather than building ad-hoc generic sections.",
21
+ },
22
+ },
23
+ },
24
+ argTypes: {},
25
+ };
26
+
27
+ export default meta;
28
+
29
+ type Story = StoryObj<typeof Card>;
30
+
31
+ export const Default: Story = {
32
+ args: {},
33
+ render: ({ ...args }) => {
34
+ return (
35
+ <Layer
36
+ layer={0}
37
+ style={{
38
+ padding: "48px",
39
+ backgroundColor: "var(--recursica_brand_palettes_neutral_050)",
40
+ }}
41
+ >
42
+ <Card {...args}>
43
+ <Card.Header>
44
+ <span style={{ fontWeight: 500, fontSize: "1.125rem" }}>
45
+ Customer Activity Report
46
+ </span>
47
+ </Card.Header>
48
+ <Card.Content>
49
+ <p>
50
+ Card inner section content body. Notice how this acts as padded
51
+ content natively based on the overarching properties. Recursica's
52
+ vertical gutter governs vertical spacing between siblings in the
53
+ flex container.
54
+ </p>
55
+ <p>Another section showing the vertical gutter spacing.</p>
56
+ </Card.Content>
57
+ <Card.Footer>
58
+ <div
59
+ style={{
60
+ display: "flex",
61
+ justifyContent: "space-between",
62
+ alignItems: "center",
63
+ marginTop: "16px",
64
+ marginBottom: "8px",
65
+ }}
66
+ >
67
+ <span style={{ color: "#868e96", fontSize: "0.75rem" }}>
68
+ Generated today
69
+ </span>
70
+ <Button variant="solid">View Details</Button>
71
+ </div>
72
+ </Card.Footer>
73
+ </Card>
74
+ </Layer>
75
+ );
76
+ },
77
+ };
78
+
79
+ export const HeaderlessAndFooterless: Story = {
80
+ args: {},
81
+ render: ({ ...args }) => {
82
+ return (
83
+ <Layer
84
+ layer={0}
85
+ style={{
86
+ padding: "48px",
87
+ backgroundColor: "var(--recursica_brand_palettes_neutral_050)",
88
+ }}
89
+ >
90
+ <Card {...args}>
91
+ <Card.Content>
92
+ <span style={{ fontWeight: 500, fontSize: "1.125rem" }}>
93
+ Notice
94
+ </span>
95
+ <p>
96
+ This is a completely generic card payload dropping the Header and
97
+ Footer specific elements, simply acting as a padded elevation
98
+ boundary box directly mirroring native composability!
99
+ </p>
100
+ <Button variant="solid" mt="rec-md">
101
+ Acknowledge
102
+ </Button>
103
+ </Card.Content>
104
+ </Card>
105
+ </Layer>
106
+ );
107
+ },
108
+ };
109
+
110
+ export const LayerDemonstration: Story = {
111
+ args: {},
112
+ render: ({ ...args }) => {
113
+ return (
114
+ <div
115
+ style={{
116
+ display: "flex",
117
+ gap: "32px",
118
+ backgroundColor: "#e9ecef",
119
+ padding: "32px",
120
+ }}
121
+ >
122
+ <Layer layer={1}>
123
+ <Card {...args}>
124
+ <Card.Header>Layer 1 Wrapper</Card.Header>
125
+ <p>Content inside layer 1 card.</p>
126
+ </Card>
127
+ </Layer>
128
+
129
+ <Layer layer={2}>
130
+ <Card {...args}>
131
+ <Card.Header>Layer 2 Wrapper</Card.Header>
132
+ <p>
133
+ Content inside layer 2 card exposing a higher elevation drop
134
+ shadow inherently cascaded.
135
+ </p>
136
+ </Card>
137
+ </Layer>
138
+ </div>
139
+ );
140
+ },
141
+ };
@@ -0,0 +1,176 @@
1
+ import { forwardRef } from "react";
2
+ import {
3
+ Card as MantineCard,
4
+ type CardProps as MantineCardProps,
5
+ type CardSectionProps as MantineCardSectionProps,
6
+ } from "@mantine/core";
7
+ import {
8
+ filterStylingProps,
9
+ type RecursicaOverStyled,
10
+ } from "../../utils/filterStylingProps";
11
+ import styles from "./Card.module.css";
12
+
13
+ // ==== CARD CONTAINER ====
14
+ export type CardProps = RecursicaOverStyled<MantineCardProps>;
15
+
16
+ /**
17
+ * The root Card elevation box. It establishes the global background color, border radius, nested component gap, and outer shadow governed by the current `Layer` context.
18
+ */
19
+ const CardBase = forwardRef<HTMLDivElement, CardProps>(function Card(
20
+ { overStyled = false, ...rest },
21
+ ref,
22
+ ) {
23
+ const sanitizedProps = filterStylingProps(rest, overStyled);
24
+
25
+ const mergedClassNames: Partial<Record<string, string>> = {
26
+ root: styles.root,
27
+ };
28
+
29
+ const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
30
+ if (
31
+ classNamesProp &&
32
+ typeof classNamesProp === "object" &&
33
+ !Array.isArray(classNamesProp)
34
+ ) {
35
+ const o = classNamesProp as Record<string, string>;
36
+ Object.keys(o).forEach((key) => {
37
+ if (mergedClassNames[key]) {
38
+ mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
39
+ } else {
40
+ mergedClassNames[key] = o[key];
41
+ }
42
+ });
43
+ }
44
+
45
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
46
+ .className as string | undefined;
47
+
48
+ return (
49
+ <MantineCard
50
+ ref={ref}
51
+ className={classNameProp}
52
+ classNames={mergedClassNames}
53
+ {...(sanitizedProps as unknown as MantineCardProps)}
54
+ />
55
+ );
56
+ });
57
+ CardBase.displayName = "Card";
58
+
59
+ // ==== NATIVE MANTINE CARD.SECTION ====
60
+ export type RecursicaCardSectionProps = MantineCardSectionProps & {
61
+ children?: React.ReactNode;
62
+ };
63
+ export type CardSectionProps = RecursicaOverStyled<RecursicaCardSectionProps>;
64
+
65
+ /**
66
+ * A generalized edge-to-edge structural wrapper native to Mantine. Strips typical boundary padding via negative margins to allow content (like maps or header images) to touch the border seamlessly.
67
+ */
68
+ export const CardSection = forwardRef<HTMLDivElement, CardSectionProps>(
69
+ function CardSection({ overStyled = false, ...rest }, ref) {
70
+ const sanitizedProps = filterStylingProps(rest, overStyled);
71
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
72
+ .className as string | undefined;
73
+
74
+ return (
75
+ <MantineCard.Section
76
+ ref={ref}
77
+ className={
78
+ classNameProp ? `${styles.section} ${classNameProp}` : styles.section
79
+ }
80
+ {...(sanitizedProps as unknown as MantineCardSectionProps)}
81
+ />
82
+ );
83
+ },
84
+ );
85
+ CardSection.displayName = "CardSection";
86
+
87
+ // ==== EXPLICIT CARD.HEADER ====
88
+ export type CardHeaderProps = RecursicaOverStyled<RecursicaCardSectionProps>;
89
+
90
+ /**
91
+ * Replaces standard generic Mantine `<Card.Section>` wrappers by directly injecting the strict Recursica design tokens for header sizing, background drops, and intrinsic padding limits.
92
+ */
93
+ export const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
94
+ function CardHeader({ overStyled = false, ...rest }, ref) {
95
+ const sanitizedProps = filterStylingProps(rest, overStyled);
96
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
97
+ .className as string | undefined;
98
+
99
+ return (
100
+ <MantineCard.Section
101
+ ref={ref}
102
+ className={
103
+ classNameProp ? `${styles.header} ${classNameProp}` : styles.header
104
+ }
105
+ {...(sanitizedProps as unknown as MantineCardSectionProps)}
106
+ />
107
+ );
108
+ },
109
+ );
110
+ CardHeader.displayName = "CardHeader";
111
+
112
+ // ==== EXPLICIT CARD.FOOTER ====
113
+ export type CardFooterProps = RecursicaOverStyled<RecursicaCardSectionProps>;
114
+
115
+ /**
116
+ * Counterpart to `Card.Header`, applying specific footer elevation margins, sizes, and padding natively.
117
+ */
118
+ export const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
119
+ function CardFooter({ overStyled = false, ...rest }, ref) {
120
+ const sanitizedProps = filterStylingProps(rest, overStyled);
121
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
122
+ .className as string | undefined;
123
+
124
+ return (
125
+ <MantineCard.Section
126
+ ref={ref}
127
+ className={
128
+ classNameProp ? `${styles.footer} ${classNameProp}` : styles.footer
129
+ }
130
+ {...(sanitizedProps as unknown as MantineCardSectionProps)}
131
+ />
132
+ );
133
+ },
134
+ );
135
+ CardFooter.displayName = "CardFooter";
136
+
137
+ // ==== EXPLICIT CARD.CONTENT ====
138
+ export type CardContentProps = RecursicaOverStyled<
139
+ React.HTMLAttributes<HTMLDivElement>
140
+ >;
141
+
142
+ /**
143
+ * Internal container that safely binds typography and structural flex gaps driven by the active UI kit tokens natively, preserving correct padding blocks compared to rigid `Card.Section` edges.
144
+ */
145
+ export const CardContent = forwardRef<HTMLDivElement, CardContentProps>(
146
+ function CardContent({ overStyled = false, ...rest }, ref) {
147
+ const sanitizedProps = filterStylingProps(rest, overStyled);
148
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
149
+ .className as string | undefined;
150
+
151
+ return (
152
+ <div
153
+ ref={ref}
154
+ className={
155
+ classNameProp ? `${styles.content} ${classNameProp}` : styles.content
156
+ }
157
+ {...sanitizedProps}
158
+ />
159
+ );
160
+ },
161
+ );
162
+ CardContent.displayName = "CardContent";
163
+
164
+ // ==== DOT NOTATION EXPORT ====
165
+ type CardComponent = typeof CardBase & {
166
+ Section: typeof CardSection;
167
+ Header: typeof CardHeader;
168
+ Footer: typeof CardFooter;
169
+ Content: typeof CardContent;
170
+ };
171
+
172
+ export const Card = CardBase as CardComponent;
173
+ Card.Section = CardSection;
174
+ Card.Header = CardHeader;
175
+ Card.Footer = CardFooter;
176
+ Card.Content = CardContent;
@@ -0,0 +1,25 @@
1
+ # Checkbox Implementation Notes
2
+
3
+ ## Architectural Philosophy
4
+
5
+ The `Checkbox` primitive requires aggressive structural modifications to decouple Mantine's built-in arrays (`<Checkbox.Group>`) tying the raw DOM nodes seamlessly back into Recursica's unified form definitions flawlessly.
6
+
7
+ ### Checkbox Alignment Anchoring (gap overflow hack)
8
+
9
+ By default, placing a Checkbox alongside a deeply wrapping multi-line label causes native geometric drifts natively. Because Mantine aligns the Checkbox graphic to the top of standard `display: flex` boxes, its optical center will appear natively skewed slightly _too high_ against the very first typographic text-line.
10
+
11
+ We mathematically fix this alignment within `Checkbox.module.css` using explicit design variable arithmetic natively.
12
+ \`\`\`css
13
+ margin-top: calc(
14
+ (
15
+ var(--recursica_ui-kit_components_checkbox-item_properties_text_line-height) \*
16
+ var(--recursica_ui-kit_components_checkbox-item_properties_text_font-size) -
17
+ var(--recursica_ui-kit_components_checkbox_properties_size)
18
+ ) / 2
19
+ ) !important;
20
+ \`\`\`
21
+ This calculation ensures that the optical center of the `.inner` checkmark vector perfectly snaps onto the relative center of the text's line-height, permanently solving pixel-drifts natively!
22
+
23
+ ### Checkbox.Group Overrides
24
+
25
+ To decouple `<CheckboxGroup>` away from `<Input.Wrapper>`, we explicitly extract the raw array execution mapped correctly against our identical `RecursicaFormControlWrapperProps` schema structurally!
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Checkbox.module.css
3
+ *
4
+ * HARDCODED VALUES:
5
+ * - margin / padding: 0 — Structural resets; consider token if spacing needed.
6
+ * - cursor: pointer / not-allowed — Baseline interactive indications.
7
+ * - appearance / box-sizing / border-style — necessary normalization for inputs.
8
+ * - transition: all 0.2s ease — Animation curve; consider a transition token.
9
+ * - min-width: 0 — Forces text wrap boundary in flex children.
10
+ */
11
+
12
+ /* --- GROUP STYLES --- */
13
+ .groupRoot {
14
+ padding: var(
15
+ --recursica_ui-kit_components_checkbox-group_properties_padding,
16
+ 0
17
+ );
18
+ margin: 0; /* HARDCODE: structural reset; consider token if layout needs change */
19
+ display: flex !important;
20
+ flex-direction: column;
21
+ gap: var(
22
+ --recursica_ui-kit_components_checkbox-group_properties_item-gap,
23
+ 16px
24
+ );
25
+ }
26
+
27
+ /* SideBySide Variant */
28
+ .groupRoot[data-layout="side-by-side"] {
29
+ flex-direction: column;
30
+ flex-wrap: wrap;
31
+ padding-top: var(
32
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_vertical-padding
33
+ );
34
+ padding-bottom: var(
35
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_vertical-padding
36
+ );
37
+ margin-top: var(
38
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_top-bottom-margin
39
+ );
40
+ margin-bottom: var(
41
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_side-by-side_properties_top-bottom-margin
42
+ );
43
+ }
44
+
45
+ /* Stacked Variant */
46
+ .groupRoot[data-layout="stacked"] {
47
+ flex-direction: column;
48
+ margin-top: var(
49
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_stacked_properties_top-bottom-margin
50
+ );
51
+ margin-bottom: var(
52
+ --recursica_ui-kit_components_checkbox-group_variants_layouts_stacked_properties_top-bottom-margin
53
+ );
54
+ }
55
+
56
+ /* --- PRIMITIVE CHECKBOX STYLES --- */
57
+
58
+ .root {
59
+ max-width: var(
60
+ --recursica_ui-kit_components_checkbox-item_properties_max-width
61
+ );
62
+ }
63
+
64
+ .body {
65
+ display: flex;
66
+ align-items: flex-start;
67
+ gap: var(--recursica_ui-kit_components_checkbox-item_properties_label-gap);
68
+ }
69
+
70
+ .inner {
71
+ display: flex !important;
72
+ align-items: center !important;
73
+ justify-content: center !important;
74
+ margin: 0 !important; /* HARDCODE: structural reset */
75
+ width: var(--recursica_ui-kit_components_checkbox_properties_size) !important;
76
+ height: var(
77
+ --recursica_ui-kit_components_checkbox_properties_size
78
+ ) !important;
79
+ /* Mathematically syncs the physical input checkbox bounding block visually with the center of the text's first line natively. */
80
+ margin-top: calc(
81
+ (
82
+ var(
83
+ --recursica_ui-kit_components_checkbox-item_properties_text_line-height
84
+ ) *
85
+ var(
86
+ --recursica_ui-kit_components_checkbox-item_properties_text_font-size
87
+ ) -
88
+ var(--recursica_ui-kit_components_checkbox_properties_size)
89
+ ) /
90
+ 2
91
+ ) !important;
92
+ }
93
+
94
+ /* Base explicit reset masking underlying framework defaults */
95
+ .input {
96
+ cursor: pointer; /* HARDCODE: core interaction behavior */
97
+ appearance: none; /* HARDCODE: reset native widget */
98
+ box-sizing: border-box !important; /* HARDCODE: ensures size includes borders */
99
+ width: var(--recursica_ui-kit_components_checkbox_properties_size) !important;
100
+ height: var(
101
+ --recursica_ui-kit_components_checkbox_properties_size
102
+ ) !important;
103
+ border-radius: var(
104
+ --recursica_ui-kit_components_checkbox_properties_border-radius
105
+ ) !important;
106
+ border-width: var(
107
+ --recursica_ui-kit_components_checkbox_properties_border-size
108
+ ) !important;
109
+ border-style: solid; /* HARDCODE: normalize primitive border-style */
110
+
111
+ /* Standard unchecked state */
112
+ background-color: var(
113
+ --recursica_ui-kit_components_checkbox_properties_colors_background-unchecked
114
+ ) !important;
115
+ border-color: var(
116
+ --recursica_ui-kit_components_checkbox_properties_colors_border-unchecked
117
+ ) !important;
118
+ transition: all 0.2s ease; /* HARDCODE: consider global transition token */
119
+ }
120
+
121
+ /* Checked/Indeterminate State */
122
+ .input:checked {
123
+ background-color: var(
124
+ --recursica_ui-kit_components_checkbox_properties_colors_background-checked
125
+ ) !important;
126
+ border-color: var(
127
+ --recursica_ui-kit_components_checkbox_properties_colors_border-checked
128
+ ) !important;
129
+ }
130
+ .input[data-indeterminate] {
131
+ background-color: var(
132
+ --recursica_ui-kit_components_checkbox_properties_colors_background-indeterminate
133
+ ) !important;
134
+ border-color: var(
135
+ --recursica_ui-kit_components_checkbox_properties_colors_border-indeterminate
136
+ ) !important;
137
+ }
138
+
139
+ /* Disabled State */
140
+ .input:disabled {
141
+ cursor: not-allowed; /* HARDCODE: disabled state default */
142
+ opacity: var(
143
+ --recursica_ui-kit_components_checkbox_properties_disabled-opacity
144
+ ) !important;
145
+ background-color: var(
146
+ --recursica_ui-kit_components_checkbox_properties_colors_disabled-background
147
+ ) !important;
148
+ border-color: var(
149
+ --recursica_ui-kit_components_checkbox_properties_colors_disabled-border
150
+ ) !important;
151
+ }
152
+
153
+ .icon {
154
+ width: var(
155
+ --recursica_ui-kit_components_checkbox_properties_icon-size
156
+ ) !important;
157
+ height: var(
158
+ --recursica_ui-kit_components_checkbox_properties_icon-size
159
+ ) !important;
160
+ color: var(
161
+ --recursica_ui-kit_components_checkbox_properties_colors_icon-color
162
+ ) !important;
163
+ }
164
+ .input:disabled + .iconWrapper .icon {
165
+ color: var(
166
+ --recursica_ui-kit_components_checkbox_properties_colors_disabled-icon
167
+ ) !important;
168
+ }
169
+
170
+ .labelWrapper {
171
+ padding: 0 !important; /* HARDCODE: structural layout reset */
172
+ margin: 0 !important; /* HARDCODE: structural layout reset */
173
+ flex: 1;
174
+ min-width: 0; /* HARDCODE: forces text wrap boundary in flex child */
175
+ }
176
+
177
+ .label {
178
+ cursor: pointer; /* HARDCODE: interactive affordance */
179
+ padding: 0 !important; /* HARDCODE: reset layout */
180
+ margin: 0 !important; /* HARDCODE: reset layout */
181
+ word-wrap: break-word;
182
+ white-space: normal;
183
+ color: var(
184
+ --recursica_ui-kit_components_checkbox-item_properties_text_color
185
+ ) !important;
186
+ font-family: var(
187
+ --recursica_ui-kit_components_checkbox-item_properties_text_font-family
188
+ );
189
+ font-size: var(
190
+ --recursica_ui-kit_components_checkbox-item_properties_text_font-size
191
+ );
192
+ font-weight: var(
193
+ --recursica_ui-kit_components_checkbox-item_properties_text_font-weight
194
+ );
195
+ line-height: var(
196
+ --recursica_ui-kit_components_checkbox-item_properties_text_line-height
197
+ );
198
+ }
199
+ .root[data-disabled] .label {
200
+ cursor: not-allowed; /* HARDCODE: disabled interaction */
201
+ opacity: var(
202
+ --recursica_ui-kit_components_checkbox_properties_disabled-opacity
203
+ );
204
+ }
@@ -0,0 +1,73 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Checkbox } from "./Checkbox";
3
+
4
+ const meta: Meta<typeof Checkbox> = {
5
+ title: "UI-Kit/Checkbox",
6
+ component: Checkbox,
7
+ tags: ["autodocs"],
8
+ parameters: {
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ The \`Checkbox\` component is a precisely engineered, atomic form primitive representing boolean states natively aligned to the Recursica design system. It overrides Mantine's standard properties explicitly enforcing our variables natively across all structural boundaries.
13
+
14
+ > [!IMPORTANT]
15
+ > The atomic \`Checkbox\` is intended primarily as an internal primitive. **When wrapping multiple Checkbox elements together or rendering form controls, always utilize the \`<Checkbox.Group>\` component.** \`Checkbox.Group\` inherits the global \`FormControlWrapper\`, granting instantaneous access to macroscopic layout structuring, assistive descriptions, validation errors, and strict flex arrays.
16
+
17
+ ### Usage
18
+ To render a solitary component natively:
19
+ \`\`\`tsx
20
+ <Checkbox label="Acknowledge Terms" defaultChecked />
21
+ \`\`\`
22
+ `,
23
+ },
24
+ },
25
+ },
26
+ argTypes: {
27
+ disabled: {
28
+ control: "boolean",
29
+ },
30
+ readOnly: {
31
+ control: "boolean",
32
+ description:
33
+ "Toggles structural read-only data presentation bypassing interaction boundaries completely.",
34
+ },
35
+ },
36
+ };
37
+
38
+ export default meta;
39
+
40
+ type Story = StoryObj<typeof Checkbox>;
41
+
42
+ export const Default: Story = {
43
+ args: {
44
+ disabled: false,
45
+ label: "Standard Unchecked Property",
46
+ },
47
+ };
48
+
49
+ export const LongLabelWrap: Story = {
50
+ args: {
51
+ label:
52
+ "A meticulously long Checkbox label property demonstrating the absolute maximum 400px wrapper constraints actively snapping the text engine down onto a secondary wrapping line automatically without blowing out the visual boundaries.",
53
+ },
54
+ };
55
+
56
+ export const StaticVariations: Story = {
57
+ args: {},
58
+ render: () => (
59
+ <div
60
+ style={{
61
+ display: "flex",
62
+ flexDirection: "column",
63
+ gap: "24px",
64
+ }}
65
+ >
66
+ <Checkbox label="Default Unchecked State" />
67
+ <Checkbox label="Acknowledge Configuration" defaultChecked />
68
+ <Checkbox label="Indeterminate Master" indeterminate />
69
+ <Checkbox label="Disabled Variant" disabled />
70
+ <Checkbox label="Disabled Checked Variant" checked disabled />
71
+ </div>
72
+ ),
73
+ };