@recursica/mantine-adapter 0.13.0 → 0.14.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 (31) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/mantine-adapter.cjs +1 -1
  3. package/dist/mantine-adapter.cjs.map +1 -1
  4. package/dist/mantine-adapter.css +1 -1
  5. package/dist/mantine-adapter.js +1304 -1059
  6. package/dist/mantine-adapter.js.map +1 -1
  7. package/dist/src/components/HoverCard/HoverCard.d.ts +55 -3
  8. package/dist/src/components/NumberInput/NumberInput.d.ts +10 -2
  9. package/dist/src/components/Panel/Panel.d.ts +57 -3
  10. package/dist/src/components/Tooltip/Tooltip.d.ts +42 -3
  11. package/package.json +1 -1
  12. package/src/components/Dropdown/Dropdown.module.css +0 -3
  13. package/src/components/HoverCard/HOVERCARD_IMPLEMENTATION_NOTES.md +77 -0
  14. package/src/components/HoverCard/HoverCard.module.css +84 -0
  15. package/src/components/HoverCard/HoverCard.stories.tsx +160 -5
  16. package/src/components/HoverCard/HoverCard.tsx +153 -4
  17. package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +25 -0
  18. package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +18 -0
  19. package/src/components/NumberInput/NumberInput.module.css +250 -0
  20. package/src/components/NumberInput/NumberInput.stories.tsx +84 -4
  21. package/src/components/NumberInput/NumberInput.tsx +144 -5
  22. package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +106 -0
  23. package/src/components/Panel/Panel.module.css +143 -0
  24. package/src/components/Panel/Panel.stories.tsx +205 -6
  25. package/src/components/Panel/Panel.tsx +143 -4
  26. package/src/components/TextArea/TextArea.module.css +0 -3
  27. package/src/components/TextField/TextField.module.css +0 -3
  28. package/src/components/Tooltip/TOOLTIP_IMPLEMENTATION_NOTES.md +85 -0
  29. package/src/components/Tooltip/Tooltip.module.css +81 -0
  30. package/src/components/Tooltip/Tooltip.stories.tsx +154 -6
  31. package/src/components/Tooltip/Tooltip.tsx +114 -4
@@ -1,7 +1,156 @@
1
- import React from "react";
1
+ import {
2
+ HoverCard as MantineHoverCard,
3
+ type HoverCardProps as MantineHoverCardProps,
4
+ type HoverCardTargetProps as MantineHoverCardTargetProps,
5
+ type HoverCardDropdownProps as MantineHoverCardDropdownProps,
6
+ } from "@mantine/core";
7
+ import {
8
+ filterStylingProps,
9
+ type RecursicaOverStyled,
10
+ } from "../../utils/filterStylingProps";
11
+ import styles from "./HoverCard.module.css";
2
12
 
3
- export type HoverCardProps = React.HTMLAttributes<HTMLDivElement>;
13
+ // ============================================================
14
+ // HOVERCARD ROOT
15
+ // ============================================================
4
16
 
5
- export const HoverCard: React.FC<HoverCardProps> = (props) => {
6
- return <div {...props}>HoverCard</div>;
17
+ /**
18
+ * Recursica-specific props for HoverCard.
19
+ */
20
+ export interface RecursicaHoverCardProps {
21
+ /**
22
+ * Whether to display a beak (arrow) pointing from the dropdown to the target.
23
+ * This is the Recursica equivalent of Mantine's `withArrow`.
24
+ * When both `withBeak` and `withArrow` are provided, `withBeak` takes precedence.
25
+ */
26
+ withBeak?: boolean;
27
+ }
28
+
29
+ /**
30
+ * Recursica HoverCard component wrapping Mantine's composable HoverCard.
31
+ *
32
+ * Displays a dropdown panel when the user hovers over a target element.
33
+ * Uses the composable dot-notation pattern:
34
+ * ```tsx
35
+ * <HoverCard withBeak>
36
+ * <HoverCard.Target>
37
+ * <Button>Hover me</Button>
38
+ * </HoverCard.Target>
39
+ * <HoverCard.Dropdown>
40
+ * Content displayed on hover
41
+ * </HoverCard.Dropdown>
42
+ * </HoverCard>
43
+ * ```
44
+ */
45
+ export type HoverCardProps = RecursicaOverStyled<
46
+ MantineHoverCardProps & RecursicaHoverCardProps
47
+ >;
48
+
49
+ const HoverCardBase = function HoverCard({
50
+ overStyled = false,
51
+ withBeak = true,
52
+ ...rest
53
+ }: HoverCardProps) {
54
+ const sanitizedProps = filterStylingProps(rest, overStyled);
55
+
56
+ // Bind CSS module classes to Mantine's internal classNames API
57
+ const mergedClassNames: Partial<Record<string, string>> = {
58
+ dropdown: styles.dropdown,
59
+ arrow: styles.arrow,
60
+ };
61
+
62
+ const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
63
+ if (
64
+ classNamesProp &&
65
+ typeof classNamesProp === "object" &&
66
+ !Array.isArray(classNamesProp)
67
+ ) {
68
+ const o = classNamesProp as Record<string, string>;
69
+ Object.keys(o).forEach((key) => {
70
+ if (mergedClassNames[key]) {
71
+ mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
72
+ } else {
73
+ mergedClassNames[key] = o[key];
74
+ }
75
+ });
76
+ }
77
+
78
+ // arrowSize must be a JS number prop — Mantine uses it for inline width/height
79
+ // and positioning offset (-arrowSize/2) calculations that cannot be CSS-driven.
80
+ // Default to 16 to match the Recursica beak-size token (16px).
81
+ const arrowSize =
82
+ ((sanitizedProps as Record<string, unknown>).arrowSize as
83
+ | number
84
+ | undefined) ?? 16;
85
+
86
+ // Resolve withBeak (Recursica) vs withArrow (Mantine).
87
+ // withBeak takes precedence when both are provided.
88
+ const withArrow = (sanitizedProps as Record<string, unknown>).withArrow as
89
+ | boolean
90
+ | undefined;
91
+ const resolvedWithArrow = withBeak ?? withArrow;
92
+
93
+ return (
94
+ <MantineHoverCard
95
+ position="top" /* Recursica default; Mantine defaults to "bottom" */
96
+ arrowSize={arrowSize}
97
+ withArrow={resolvedWithArrow}
98
+ classNames={mergedClassNames}
99
+ {...(sanitizedProps as unknown as MantineHoverCardProps)}
100
+ />
101
+ );
102
+ };
103
+ HoverCardBase.displayName = "HoverCard";
104
+
105
+ // ============================================================
106
+ // HOVERCARD TARGET
107
+ // ============================================================
108
+
109
+ /**
110
+ * Wrapper for the element that triggers the hover card.
111
+ * Requires a single child element that supports ref forwarding.
112
+ */
113
+ export type HoverCardTargetProps = MantineHoverCardTargetProps;
114
+
115
+ const HoverCardTarget = function HoverCardTarget(props: HoverCardTargetProps) {
116
+ return <MantineHoverCard.Target {...props} />;
117
+ };
118
+ HoverCardTarget.displayName = "HoverCardTarget";
119
+
120
+ // ============================================================
121
+ // HOVERCARD DROPDOWN
122
+ // ============================================================
123
+
124
+ /** The dropdown panel displayed when hovering over the target. */
125
+ export type HoverCardDropdownProps =
126
+ RecursicaOverStyled<MantineHoverCardDropdownProps>;
127
+
128
+ const HoverCardDropdown = function HoverCardDropdown({
129
+ overStyled = false,
130
+ ...rest
131
+ }: HoverCardDropdownProps) {
132
+ const sanitizedProps = filterStylingProps(rest, overStyled);
133
+ const classNameProp = (sanitizedProps as Record<string, unknown>)
134
+ .className as string | undefined;
135
+
136
+ return (
137
+ <MantineHoverCard.Dropdown
138
+ className={classNameProp}
139
+ {...(sanitizedProps as unknown as MantineHoverCardDropdownProps)}
140
+ />
141
+ );
7
142
  };
143
+ HoverCardDropdown.displayName = "HoverCardDropdown";
144
+
145
+ // ============================================================
146
+ // DOT NOTATION EXPORT
147
+ // ============================================================
148
+
149
+ type HoverCardComponent = typeof HoverCardBase & {
150
+ Target: typeof HoverCardTarget;
151
+ Dropdown: typeof HoverCardDropdown;
152
+ };
153
+
154
+ export const HoverCard = HoverCardBase as HoverCardComponent;
155
+ HoverCard.Target = HoverCardTarget;
156
+ HoverCard.Dropdown = HoverCardDropdown;
@@ -0,0 +1,25 @@
1
+ # Loader Implementation Notes
2
+
3
+ ## Architecture & Integration
4
+
5
+ The `Loader` component acts as a strictly tokenized wrapper bridging the Recursica UI-Kit `loader` variables to the generic Mantine `@mantine/core` `Loader` primitive.
6
+
7
+ ### Key Decisions:
8
+
9
+ - **Variant Mapping:** Recursica's `variant` directly proxies to Mantine's `type` prop for `"oval" | "bars" | "dots"`.
10
+ - **Property Overrides Disabled:** Natively overriding specific structural variants directly on the JSX interface like `thickness` and `borderRadius` has been intentionally omitted. Component rendering relies entirely on variables exposed by the underlying UI Kit mappings tied to the size prop.
11
+
12
+ ### Token Mapping:
13
+
14
+ Sizes are bound through `data-size` attributes (`sm`, `md`, `lg` parsing to target `<div data-size="small">`, etc.).
15
+
16
+ Mantine natively sets sizing dynamically at the component root and parses thickness/variants differently natively (e.g., `oval` styles its geometry strictly via CSS `border`, while `bars` and `dots` utilize specific DOM inner spans `span.dot` / `span.bar`).
17
+
18
+ #### Specific CSS Targeting Hacks Used
19
+
20
+ - `border-width` structurally styles the `thickness` configuration of the `oval` variant by resolving `--recursica_ui-kit_components_loader_variants_sizes_..._properties_thickness`.
21
+ - For non-oval variants, `border-radius` natively maps downwards to targeting component `span` children within the wrapper to capture `<span className="mantine-Loader-dot" />` geometries safely without polluting the flex wrapper natively.
22
+
23
+ ### Unsupported Properties
24
+
25
+ - **xs and xl Sizing:** These sizes are explicitly unsupported in the Recursica standard logic (as surfaced in `filterStylingProps` and UI Kit mappings). Attempting to use them will safely default back or fallthrough statically unless defined later. See `COMPONENT_ISSUES.md`.
@@ -0,0 +1,18 @@
1
+ # NumberInput Implementation Notes
2
+
3
+ This document contains specific design decisions, architectural constraints, and hacks required to bridge the Recursica design system with Mantine's underlying `NumberInput` primitive.
4
+
5
+ ## 1. Native Macro Wrapper Bypass
6
+
7
+ **Decision:** The `<NumberInput>` component explicitly bypasses Mantine's native `Input.Wrapper` DOM injections.
8
+ **Implementation:** We pass `label={undefined}`, `description={undefined}`, and `error={undefined}` directly into the primitive `<MantineNumberInput>`. All visual form control geometry is delegated exclusively to our unified `<FormControlWrapper>`, ensuring 100% token adherence for label spacing and assistive text styling without duplicate DOM rendering.
9
+
10
+ ## 2. Right Section & Controls Override
11
+
12
+ **Decision:** Passing a `rightSection` element will natively remove the increment/decrement arrow controls.
13
+ **Implementation:** Mantine inherently renders its stepper controls inside the `rightSection` DOM slot. Providing a custom right-aligned icon or text element intentionally overwrites this slot. If a layout strictly requires both a custom right-aligned element and the stepper controls simultaneously, the integrator must manually rebuild the arrows using Mantine's `handlersRef` within a custom right-section wrapper.
14
+
15
+ ## 3. Controls Styling
16
+
17
+ **Decision:** The increment/decrement control arrows rely partially on native Mantine CSS inheritance.
18
+ **Implementation:** The current Recursica design system tokens do not provide explicit UI styling parameters (`background`, `border`, `hover` states) for the inner number-input arrows. We have explicitly removed Mantine's default borders to cleanly nest them inside the unified input box, and mapped the icon colors to the generic `trailing-icon` token variable, but further visual configurations currently fall back to Mantine defaults.
@@ -0,0 +1,250 @@
1
+ /* HARDCODED VALUES:
2
+ - border-width: 1px. Native geometric boundary for the input box.
3
+ - border-style: solid. Native structural rendering rule.
4
+ - outline: none. Bypassing browser focus rings to rely strictly on Recursica focus states natively.
5
+ - flex/layout: display: flex on the root wrapper safely encapsulating internal section rendering.
6
+ - Controls: Hardcoded to bypass Mantine's default borders and backgrounds on the increment/decrement arrows.
7
+ */
8
+
9
+ .root {
10
+ display: flex;
11
+ position: relative;
12
+ width: 100%;
13
+ min-height: var(
14
+ --recursica_ui-kit_components_number-input_properties_min-height
15
+ );
16
+
17
+ /* Override Mantine native Input variables governing section spacing padding mathematics safely */
18
+ --input-left-section-size: calc(
19
+ var(--recursica_ui-kit_components_number-input_properties_icon-size) +
20
+ (
21
+ var(
22
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
23
+ ) *
24
+ 2
25
+ )
26
+ );
27
+ --input-right-section-size: calc(
28
+ var(--recursica_ui-kit_components_number-input_properties_icon-size) +
29
+ (
30
+ var(
31
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
32
+ ) *
33
+ 2
34
+ )
35
+ );
36
+ }
37
+
38
+ .input {
39
+ /* Structural Overrides */
40
+ width: 100%;
41
+ box-sizing: border-box;
42
+ margin: 0;
43
+
44
+ /* Box Geometry */
45
+ min-height: var(
46
+ --recursica_ui-kit_components_number-input_properties_min-height
47
+ );
48
+ padding-top: var(
49
+ --recursica_ui-kit_components_number-input_properties_vertical-padding
50
+ );
51
+ padding-bottom: var(
52
+ --recursica_ui-kit_components_number-input_properties_vertical-padding
53
+ );
54
+ padding-left: var(
55
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
56
+ );
57
+ padding-right: var(
58
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
59
+ );
60
+ border-radius: var(
61
+ --recursica_ui-kit_components_number-input_properties_border-radius
62
+ );
63
+ border-width: 1px;
64
+ border-style: solid;
65
+
66
+ /* Strict Typography Unification */
67
+ font-family: var(
68
+ --recursica_ui-kit_components_number-input_properties_text_font-family
69
+ );
70
+ font-size: var(
71
+ --recursica_ui-kit_components_number-input_properties_text_font-size
72
+ );
73
+ font-style: var(
74
+ --recursica_ui-kit_components_number-input_properties_text_font-style
75
+ );
76
+ font-weight: var(
77
+ --recursica_ui-kit_components_number-input_properties_text_font-weight
78
+ );
79
+ letter-spacing: var(
80
+ --recursica_ui-kit_components_number-input_properties_text_letter-spacing
81
+ );
82
+ line-height: var(
83
+ --recursica_ui-kit_components_number-input_properties_text_line-height
84
+ );
85
+ text-decoration: var(
86
+ --recursica_ui-kit_components_number-input_properties_text_text-decoration
87
+ );
88
+ text-transform: var(
89
+ --recursica_ui-kit_components_number-input_properties_text_text-transform
90
+ );
91
+
92
+ /* Base State Default Execution */
93
+ background-color: var(
94
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_background
95
+ );
96
+ border-color: var(
97
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_border-color
98
+ );
99
+ color: var(
100
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_text
101
+ );
102
+
103
+ outline: none;
104
+ }
105
+
106
+ .input::placeholder {
107
+ opacity: var(
108
+ --recursica_ui-kit_components_number-input_properties_placeholder-opacity
109
+ );
110
+ color: inherit;
111
+ }
112
+
113
+ /* Dynamic Padding Overrides */
114
+ .root[data-with-left-section] .input {
115
+ padding-left: var(--input-left-section-size);
116
+ }
117
+
118
+ .root[data-with-right-section] .input {
119
+ padding-right: var(--input-right-section-size);
120
+ }
121
+
122
+ /* Flexible End-Caps (Icons, actions) */
123
+ .section {
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ height: 100%;
128
+ }
129
+
130
+ .section :global(svg) {
131
+ width: var(--recursica_ui-kit_components_number-input_properties_icon-size);
132
+ height: var(--recursica_ui-kit_components_number-input_properties_icon-size);
133
+ color: var(
134
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_leading-icon
135
+ );
136
+ }
137
+
138
+ .section[data-position="right"] :global(svg) {
139
+ color: var(
140
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_trailing-icon
141
+ );
142
+ }
143
+
144
+ /* -------------------------------------
145
+ CONTROLS (Mantine Specific Up/Down Arrows)
146
+ -------------------------------------- */
147
+
148
+ .controls {
149
+ /* Adjust right padding so controls do not overlap borders */
150
+ padding-right: var(
151
+ --recursica_ui-kit_components_number-input_properties_horizontal-padding
152
+ );
153
+ }
154
+
155
+ .control {
156
+ /* Override Mantine borders for the inner controls */
157
+ border: none;
158
+ background: transparent;
159
+ color: var(
160
+ --recursica_ui-kit_components_number-input_variants_states_default_properties_colors_trailing-icon
161
+ );
162
+ }
163
+
164
+ .control:hover {
165
+ background: transparent;
166
+ }
167
+
168
+ /* -------------------------------------
169
+ STATE CASCADE ARCHITECTURE
170
+ -------------------------------------- */
171
+
172
+ /* Focus State Mapping (Triggered internally via browser pseudo-pseudo-class) */
173
+ .input:focus-within,
174
+ .input:focus {
175
+ border-color: var(
176
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_border-color
177
+ );
178
+ background-color: var(
179
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_background
180
+ );
181
+ color: var(
182
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_text
183
+ );
184
+ }
185
+
186
+ .root:focus-within .section[data-position="left"] :global(svg) {
187
+ color: var(
188
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_leading-icon
189
+ );
190
+ }
191
+
192
+ .root:focus-within .section[data-position="right"] :global(svg),
193
+ .root:focus-within .control {
194
+ color: var(
195
+ --recursica_ui-kit_components_number-input_variants_states_focus_properties_colors_trailing-icon
196
+ );
197
+ }
198
+
199
+ /* Error State Mapping (Propagated strictly down from the wrapper DOM context) */
200
+ .root[data-error] .input {
201
+ border-color: var(
202
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_border-color
203
+ ) !important;
204
+ background-color: var(
205
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_background
206
+ ) !important;
207
+ color: var(
208
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_text
209
+ ) !important;
210
+ }
211
+
212
+ .root[data-error] .section[data-position="left"] :global(svg) {
213
+ color: var(
214
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_leading-icon
215
+ ) !important;
216
+ }
217
+
218
+ .root[data-error] .section[data-position="right"] :global(svg),
219
+ .root[data-error] .control {
220
+ color: var(
221
+ --recursica_ui-kit_components_number-input_variants_states_error_properties_colors_trailing-icon
222
+ ) !important;
223
+ }
224
+
225
+ /* Disabled State Mapping (Propagated strictly down from the wrapper DOM context) */
226
+ .root[data-disabled] .input {
227
+ border-color: var(
228
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_border-color
229
+ ) !important;
230
+ background-color: var(
231
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_background
232
+ ) !important;
233
+ color: var(
234
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_text
235
+ ) !important;
236
+ cursor: not-allowed;
237
+ }
238
+
239
+ .root[data-disabled] .section[data-position="left"] :global(svg) {
240
+ color: var(
241
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_leading-icon
242
+ ) !important;
243
+ }
244
+
245
+ .root[data-disabled] .section[data-position="right"] :global(svg),
246
+ .root[data-disabled] .control {
247
+ color: var(
248
+ --recursica_ui-kit_components_number-input_variants_states_disabled_properties_colors_trailing-icon
249
+ ) !important;
250
+ }
@@ -1,12 +1,34 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { NumberInput } from "./NumberInput";
3
- import { ComingSoon } from "@recursica/storybook-template";
4
3
 
5
4
  const meta: Meta<typeof NumberInput> = {
6
- title: "UI-Kit/🚧 NumberInput",
5
+ title: "UI-Kit/NumberInput",
7
6
  component: NumberInput,
8
7
  tags: ["autodocs"],
9
- argTypes: {},
8
+ argTypes: {
9
+ label: { control: "text" },
10
+ assistiveText: { control: "text" },
11
+ disabled: { control: "boolean" },
12
+ error: { control: "boolean" },
13
+ readOnly: { control: "boolean" },
14
+ required: { control: "boolean" },
15
+ hideControls: { control: "boolean" },
16
+ formLayout: {
17
+ control: "select",
18
+ options: ["stacked", "side-by-side"],
19
+ },
20
+ labelSize: {
21
+ control: "select",
22
+ options: ["small", "default", "large"],
23
+ },
24
+ checked: { table: { disable: true } },
25
+ defaultChecked: { table: { disable: true } },
26
+ assistiveWithIcon: { table: { disable: true } },
27
+ labelOptionalText: { table: { disable: true } },
28
+ labelWithEditIcon: { table: { disable: true } },
29
+ onLabelEditClick: { table: { disable: true } },
30
+ emptyValueComponent: { table: { disable: true } },
31
+ },
10
32
  };
11
33
 
12
34
  export default meta;
@@ -14,5 +36,63 @@ export default meta;
14
36
  type Story = StoryObj<typeof NumberInput>;
15
37
 
16
38
  export const Default: Story = {
17
- render: () => <ComingSoon componentName="NumberInput" />,
39
+ args: {
40
+ label: "Amount",
41
+ placeholder: "Enter an amount",
42
+ assistiveText: "Must be greater than 0",
43
+ defaultValue: 10,
44
+ min: 0,
45
+ max: 100,
46
+ },
47
+ };
48
+
49
+ export const SideBySideLayout: Story = {
50
+ args: {
51
+ ...Default.args,
52
+ formLayout: "side-by-side",
53
+ },
54
+ };
55
+
56
+ export const States: Story = {
57
+ render: () => (
58
+ <div
59
+ style={{
60
+ display: "flex",
61
+ flexDirection: "column",
62
+ gap: "1rem",
63
+ maxWidth: 400,
64
+ }}
65
+ >
66
+ <NumberInput label="Default" placeholder="Enter a number" />
67
+ <NumberInput label="Disabled" placeholder="Disabled input" disabled />
68
+ <NumberInput label="Error" placeholder="Error state" error />
69
+ <NumberInput label="Read Only" value={42} readOnly />
70
+ <NumberInput label="Required" required />
71
+ </div>
72
+ ),
73
+ };
74
+
75
+ export const WithLeftIcon: Story = {
76
+ args: {
77
+ label: "Price",
78
+ placeholder: "0.00",
79
+ leftSection: <span>$</span>,
80
+ },
81
+ };
82
+
83
+ export const WithRightIcon: Story = {
84
+ args: {
85
+ label: "Percentage",
86
+ placeholder: "0",
87
+ rightSection: <span>%</span>,
88
+ hideControls: true, // Typically hiding controls if rightSection is occupied
89
+ },
90
+ };
91
+
92
+ export const HiddenControls: Story = {
93
+ args: {
94
+ label: "Zip Code",
95
+ placeholder: "Enter zip code",
96
+ hideControls: true,
97
+ },
18
98
  };