@nexus-cross/design-system 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DESIGN.md ADDED
@@ -0,0 +1,185 @@
1
+ # NEXUS Design System
2
+
3
+ ## Overview
4
+
5
+ This document defines the visual identity and design principles for projects using `@nexus-cross/design-system`. AI agents should read this file to generate consistent, on-brand UI across the entire project.
6
+
7
+ ## Visual Theme & Atmosphere
8
+
9
+ The interface prioritizes **clarity, density, and efficiency**. It targets professional data-driven applications — trading platforms, dashboards, and enterprise tools — where information density matters but readability must not be sacrificed.
10
+
11
+ Design philosophy:
12
+ - **Functional minimalism**: Every visual element serves a purpose. No decorative flourishes.
13
+ - **High contrast hierarchy**: Clear distinction between primary, secondary, and tertiary information.
14
+ - **Calm neutrals with intentional accent**: The UI stays quiet until interaction or status demands attention.
15
+ - **Dark-mode first**: Designed for prolonged screen use. Light mode is equally supported but dark mode is the primary context.
16
+
17
+ ## Color Palette & Roles
18
+
19
+ ### Background layers (depth ordering)
20
+
21
+ | Token | Role | Light | Dark |
22
+ |---|---|---|---|
23
+ | `bg-default` | Page-level background | `#FFFFFF` | `#1E232E` |
24
+ | `bg-subtle` | Recessed areas, sidebar backgrounds | `#F3F6F8` | `#161A21` |
25
+ | `bg-strong` | Maximum depth contrast | `#ECF0F2` | `#000000` |
26
+
27
+ ### Surface layers (interactive containers)
28
+
29
+ | Token | Role | Light | Dark |
30
+ |---|---|---|---|
31
+ | `surface-default` | Cards, panels, modals | `#FFFFFF` | `#1E232E` |
32
+ | `surface-subtle` | Secondary panels, nested containers | `#F3F6F8` | `#252B39` |
33
+ | `surface-strong` | Emphasized containers, active sections | `#ECF0F2` | `#363B4C` |
34
+ | `surface-inverted` | High-contrast banners, tooltips | `#161A21` | `#F3F6F8` |
35
+
36
+ **Rule**: Always layer surfaces in order: `bg` → `surface-default` → `surface-subtle`. Never place `surface-subtle` directly on `bg-default` — use `surface-default` as an intermediate layer.
37
+
38
+ ### Text hierarchy
39
+
40
+ | Token | Role | When to use |
41
+ |---|---|---|
42
+ | `text-highlight` | Maximum emphasis | Titles, critical numbers, hero stats |
43
+ | `text-primary` | Default readable text | Body text, labels, headings |
44
+ | `text-secondary` | Supporting information | Descriptions, helper text, timestamps |
45
+ | `text-tertiary` | De-emphasized content | Placeholders, disabled labels |
46
+ | `text-muted` | Lowest priority | Watermarks, footnotes |
47
+
48
+ **Rule**: Never use `text-muted` for any content the user needs to read. It exists only for decorative or supplementary text.
49
+
50
+ ### Accent colors
51
+
52
+ | Token | Role |
53
+ |---|---|
54
+ | `accent-primary` (teal/green) | Primary CTA, links, active states, brand identity |
55
+ | `accent-secondary` (purple) | Secondary actions, premium features, alternate highlights |
56
+
57
+ **Rule**: Use `accent-primary` for the single most important action on screen. If there are multiple CTAs, only ONE gets `accent-primary` — the rest use `outline` or `ghost` variants.
58
+
59
+ ### Status colors
60
+
61
+ | Token | Role | Usage context |
62
+ |---|---|---|
63
+ | `status-success` | Positive outcomes | Completed actions, profit, online status |
64
+ | `status-warning` | Caution needed | Expiring items, approaching limits |
65
+ | `status-danger` | Errors or destructive | Failed actions, losses, delete confirmations |
66
+ | `status-info` | Neutral information | Tips, update notices, general alerts |
67
+
68
+ **Rule**: Status colors should only appear in context — on alerts, badges, inline messages, or status indicators. Never use status colors for decorative purposes or general theming.
69
+
70
+ ## Typography Rules
71
+
72
+ - **Font**: System font stack (inherits from the consuming project).
73
+ - **Scale**: 8 levels from `text-xs` (0.75rem) to `text-xl` (1.25rem) for body, plus heading scale `h7`–`h1` and display `sm`–`lg`.
74
+ - **Weight system**: Regular (400) for body, Medium (500) for labels, Semi-bold (600) for headings, Bold (700) for display and h1–h2.
75
+ - **Letter spacing**: `-0.01em` for body text (tighter for readability at small sizes), `0` for headings and labels.
76
+ - **Line height**: Built into each typography token — do not override.
77
+
78
+ **Rule**: Use typography tokens (`text-text-sm`, `text-heading-h4`, etc.) instead of raw Tailwind sizes. The tokens include coordinated font-size, font-weight, line-height, and letter-spacing.
79
+
80
+ ## Spacing & Layout
81
+
82
+ ### Spacing scale
83
+
84
+ - **Padding**: `none` (0), `2xs` (4px), `xs` (8px), `sm` (12px), `md` (16px), `lg` (24px), `xl` (32px), `2xl` (40px)
85
+ - **Gap**: `none` (0), `xs` (4px), `sm` (8px), `md` (16px), `lg` (24px), `xl` (32px)
86
+
87
+ ### Control sizes
88
+
89
+ | Size | Height | Use case |
90
+ |---|---|---|
91
+ | `xs` | 24px | Compact tables, inline actions |
92
+ | `sm` | 32px | Secondary actions, filters |
93
+ | `md` | 40px | Default inputs, buttons |
94
+ | `lg` | 48px | Primary CTAs, prominent inputs |
95
+
96
+ ### Border radius
97
+
98
+ | Token | Value | Use case |
99
+ |---|---|---|
100
+ | `corner-none` | 0px | Tables, full-width elements |
101
+ | `corner-sm` | 4px | Chips, badges, small elements |
102
+ | `corner-md` | 8px | Buttons, inputs, cards (default) |
103
+ | `corner-lg` | 12px | Modals, large cards |
104
+ | `corner-xl` | 16px | Hero sections, featured cards |
105
+ | `corner-full` | 9999px | Avatars, pills, circular buttons |
106
+
107
+ **Rule**: Be consistent within a feature. If a card uses `corner-md`, its internal buttons should also use `corner-md` or smaller — never larger than their container.
108
+
109
+ ### Breakpoints
110
+
111
+ | Token | Value | Context |
112
+ |---|---|---|
113
+ | `screen-xs` | 320px | Small mobile |
114
+ | `screen-sm` | 640px | Mobile |
115
+ | `screen-md` | 768px | Tablet |
116
+ | `screen-lg` | 1024px | Desktop |
117
+ | `screen-xl` | 1280px | Wide desktop |
118
+ | `screen-2xl` | 1440px | Ultra-wide |
119
+
120
+ ## Component Styling Principles
121
+
122
+ - **Buttons**: `corner-md` (8px) radius by default. Primary actions use `accent-primary` fill with white text. Ghost and outline variants for secondary actions.
123
+ - **Inputs**: `corner-md` radius, `border-default` border, `surface-default` background. Focus state uses `accent-primary` ring.
124
+ - **Cards/Panels**: `surface-default` background, `border-default` border (1px), `corner-md` or `corner-lg` radius. No drop shadows by default — use `shadow-sm` only on hover or elevated contexts.
125
+ - **Modals/Drawers**: `surface-default` background, `corner-lg` radius on visible corners. Overlay uses `opacity-overlay-dim` (0.5).
126
+ - **Chips/Tags**: `corner-sm` (4px) radius, compact padding. Use semantic variants (`accent`, `success`, `danger`) to convey meaning.
127
+ - **Tables**: No border-radius on the table itself. Use `surface-subtle` for alternating rows or header background. `border-default` for cell dividers.
128
+
129
+ ## Elevation & Shadows
130
+
131
+ | Token | Value | Use case |
132
+ |---|---|---|
133
+ | `shadow-none` | `none` | Default state for most elements |
134
+ | `shadow-sm` | `0 1px 2px 0 rgb(0 0 0 / 0.12)` | Hover states, subtle lift |
135
+ | `shadow-md` | `0 1px 3px 0 rgb(0 0 0 / 0.12)` | Dropdown menus, popovers |
136
+ | `shadow-lg` | `0 2px 8px -1px rgb(0 0 0 / 0.12)` | Modals, drawers |
137
+ | `shadow-xl` | `0 4px 15px -3px rgb(0 0 0 / 0.12)` | Toast notifications |
138
+
139
+ **Rule**: Prefer borders over shadows for static elements. Shadows should imply interactivity or overlay behavior. A card sitting on a page uses a border, not a shadow.
140
+
141
+ ## Animation & Motion
142
+
143
+ - **Transitions**: 150ms (fast), 200ms (normal), 300ms (slow). Use `cubic-bezier(0, 0, 0.2, 1)` (ease-out) for most transitions.
144
+ - **Enter animations**: 200ms with ease-out. Elements enter from the direction they were triggered (dropdown from top, drawer from side).
145
+ - **Exit animations**: 150ms with `cubic-bezier(0.4, 0, 1, 1)` (ease-in). Exits are faster than enters.
146
+
147
+ **Rule**: Only animate properties that benefit the user's understanding of state change (opacity, transform). Never animate color or background-color on large surfaces — it feels sluggish.
148
+
149
+ ## Do's and Don'ts
150
+
151
+ ### Colors
152
+
153
+ - **Do** use semantic token names (`bg-surface-default`, `text-text-primary`), not raw hex values.
154
+ - **Do** use `accent-primary` sparingly — one primary CTA per visible area.
155
+ - **Don't** use `status-danger` red for non-error purposes (e.g., decorative highlights).
156
+ - **Don't** mix `text-muted` with `bg-subtle` — the contrast ratio is too low for accessibility.
157
+ - **Don't** override dark mode colors manually. The token system handles light/dark switching automatically.
158
+
159
+ ### Typography
160
+
161
+ - **Do** use the typography token scale. Every text element should map to a token.
162
+ - **Don't** use more than 3 different text sizes in a single card or section.
163
+ - **Don't** use `font-bold` (700) for body text. Bold is reserved for headings and display text.
164
+
165
+ ### Layout
166
+
167
+ - **Do** use the spacing scale tokens for all padding, margin, and gap values.
168
+ - **Do** maintain consistent spacing within a component: if padding-x is `md`, padding-y should be `sm` or `md`, not `2xs`.
169
+ - **Don't** use arbitrary pixel values (e.g., `p-[13px]`). Snap to the nearest spacing token.
170
+ - **Don't** nest more than 3 surface layers deep. If you need more depth, reconsider the information architecture.
171
+
172
+ ### Components
173
+
174
+ - **Do** use `@nexus-cross/design-system` components for any matching UI element. Never re-implement buttons, inputs, modals, etc.
175
+ - **Do** use `className` prop for style overrides. The `cn()` utility resolves prefix conflicts automatically.
176
+ - **Don't** use `!important` in className overrides — it's unnecessary and breaks the override system.
177
+ - **Don't** wrap design system components in extra `<div>` elements for styling. Use `className` directly.
178
+ - **Don't** import Radix UI, Headless UI, or similar libraries to build components that already exist in the design system.
179
+
180
+ ### Interaction States
181
+
182
+ - **Do** provide visual feedback for all interactive elements: hover, focus, active, disabled.
183
+ - **Do** use `focus-visible` outlines (not `focus`) to avoid showing focus rings on click.
184
+ - **Don't** remove focus indicators entirely — they are required for keyboard accessibility.
185
+ - **Don't** use `opacity` below `0.4` for disabled states — it becomes invisible in some contexts.
@@ -945,21 +945,25 @@ Text ellipsis. Built-in show more/less toggle.
945
945
 
946
946
  ## NumberInput
947
947
 
948
- Number input. Accelerated increment on long press. Exposes increment/decrement methods via ref. numberInputBind(ref, direction) binds same acceleration to external buttons.
948
+ Number input with two variants: basic (chevron arrows) and bind (+/- buttons). Supports label, description, max display, accelerated increment on long press. numberInputBind(ref, direction) binds acceleration to external buttons.
949
949
 
950
950
  | Prop | Type | Default | Description |
951
951
  |---|---|---|---|
952
+ | `variant` | `'basic'` \| `'bind'` | `"basic"` | Variant: basic (right chevron arrows) or bind (left/right +/- buttons) |
952
953
  | `value` | `number` \| `string` | - | Current value |
953
- | `size` | `'sm'` \| `'md'` \| `'lg'` \| `'xl'` | `"md"` | Size |
954
+ | `size` | `'lg'` \| `'xl'` | `"lg"` | Size |
954
955
  | `error` | `boolean` | - | Error state |
955
956
  | `min` | `number` | - | Minimum value |
956
- | `max` | `number` | - | Maximum value |
957
+ | `max` | `number` | - | Maximum value. When set, "Max {value}" is displayed in the header |
957
958
  | `step` | `number` | `1` | Step increment |
958
959
  | `digit` | `number` | `0` | Decimal places |
959
- | `hideButtons` | `boolean` | `false` | Hide default spin buttons. Use with numberInputBind for external button event binding |
960
+ | `label` | `string` | - | Label text displayed above input |
961
+ | `description` | `string` | - | Description text displayed below input |
962
+ | `showMax` | `boolean` | - | Show "Max {value}" in header (defaults to true when max is set) |
963
+ | `hideButtons` | `boolean` | `false` | Hide built-in buttons. Use with numberInputBind for external button event binding |
960
964
  | `disabled` | `boolean` | - | Disabled |
961
- | `readOnly` | `boolean` | - | Read-only (includes hiding spin buttons) |
962
- | `placeholder` | `string` | - | Placeholder |
965
+ | `readOnly` | `boolean` | - | Read-only (includes hiding buttons) |
966
+ | `placeholder` | `string` | - | Placeholder (default: "0") |
963
967
  | `name` | `string` | - | Form field name |
964
968
  | `id` | `string` | - | Element ID |
965
969
  | `autoFocus` | `boolean` | - | Auto focus |
@@ -27,21 +27,62 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
27
27
 
28
28
  var numberInputVariants = classVarianceAuthority.cva("nexus-number-input", {
29
29
  variants: {
30
+ variant: {
31
+ basic: "nexus-number-input--basic",
32
+ bind: "nexus-number-input--bind"
33
+ },
30
34
  size: {
31
- sm: "nexus-number-input--sm",
32
- md: "nexus-number-input--md",
33
35
  lg: "nexus-number-input--lg",
34
36
  xl: "nexus-number-input--xl"
35
- },
36
- state: {
37
- default: "nexus-number-input--default",
38
- error: "nexus-number-input--error"
39
37
  }
40
38
  },
41
- defaultVariants: { size: "md", state: "default" }
39
+ defaultVariants: { variant: "basic", size: "lg" }
42
40
  });
43
- var ChevronUp = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "nexus-number-input__step-icon", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 7.5L6 4.5l3 3" }) });
44
- var ChevronDown = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "nexus-number-input__step-icon", viewBox: "0 0 12 12", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 4.5L6 7.5l3-3" }) });
41
+ var CHEVRON_PATH = "M3.606.179C3.82-.06 4.18-.06 4.394.179L7.846 4.01C8.18 4.382 7.934 5 7.452 5H.548C.066 5-.18 4.382.154 4.01L3.606.179Z";
42
+ var ChevronUpIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
43
+ "svg",
44
+ {
45
+ className: "nexus-number-input__chevron-icon",
46
+ viewBox: "0 0 8 5",
47
+ fill: "currentColor",
48
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: CHEVRON_PATH })
49
+ }
50
+ );
51
+ var ChevronDownIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
52
+ "svg",
53
+ {
54
+ className: "nexus-number-input__chevron-icon nexus-number-input__chevron-icon--down",
55
+ viewBox: "0 0 8 5",
56
+ fill: "currentColor",
57
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: CHEVRON_PATH })
58
+ }
59
+ );
60
+ var MinusIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
61
+ "svg",
62
+ {
63
+ className: "nexus-number-input__bind-icon",
64
+ viewBox: "0 0 16 16",
65
+ fill: "none",
66
+ stroke: "currentColor",
67
+ strokeWidth: "1.33",
68
+ strokeLinecap: "round",
69
+ strokeLinejoin: "round",
70
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.333 8h9.334" })
71
+ }
72
+ );
73
+ var PlusIcon = () => /* @__PURE__ */ jsxRuntime.jsx(
74
+ "svg",
75
+ {
76
+ className: "nexus-number-input__bind-icon",
77
+ viewBox: "0 0 16 16",
78
+ fill: "none",
79
+ stroke: "currentColor",
80
+ strokeWidth: "1.33",
81
+ strokeLinecap: "round",
82
+ strokeLinejoin: "round",
83
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.333 8h9.334M8 3.333v9.334" })
84
+ }
85
+ );
45
86
  function clampValue(val, min, max) {
46
87
  let result = val;
47
88
  if (min !== void 0) result = Math.max(min, result);
@@ -65,6 +106,7 @@ function numberInputBind(ref, direction) {
65
106
  var NumberInput = React__namespace.forwardRef(
66
107
  ({
67
108
  className,
109
+ variant = "basic",
68
110
  size,
69
111
  error,
70
112
  value,
@@ -72,6 +114,9 @@ var NumberInput = React__namespace.forwardRef(
72
114
  max,
73
115
  step = 1,
74
116
  digit = 0,
117
+ label,
118
+ description,
119
+ showMax,
75
120
  hideButtons = false,
76
121
  disabled,
77
122
  readOnly,
@@ -80,8 +125,9 @@ var NumberInput = React__namespace.forwardRef(
80
125
  ...props
81
126
  }, ref) => {
82
127
  const inputRef = React__namespace.useRef(null);
83
- const state = error ? "error" : "default";
84
- const [internalValue, setInternalValue] = React__namespace.useState(value?.toString() ?? "");
128
+ const [internalValue, setInternalValue] = React__namespace.useState(
129
+ value?.toString() ?? ""
130
+ );
85
131
  const internalValueRef = React__namespace.useRef(internalValue);
86
132
  const timeoutRef = React__namespace.useRef(null);
87
133
  const pressCountRef = React__namespace.useRef(0);
@@ -189,72 +235,151 @@ var NumberInput = React__namespace.forwardRef(
189
235
  }),
190
236
  [step]
191
237
  );
192
- const padSize = size === "sm" ? "nexus-number-input__field--sm" : size === "xl" ? "nexus-number-input__field--xl" : size === "lg" ? "nexus-number-input__field--lg" : "nexus-number-input__field--md";
193
- const showButtons = !hideButtons && !readOnly && !disabled;
238
+ const handleMaxClick = React__namespace.useCallback(() => {
239
+ if (disabled || readOnly || max === void 0) return;
240
+ const maxStr = max.toString();
241
+ internalValueRef.current = maxStr;
242
+ setInternalValue(maxStr);
243
+ onValueChange?.(max);
244
+ inputRef.current?.focus();
245
+ }, [disabled, readOnly, max, onValueChange]);
194
246
  const numValue = parseFloat(internalValue) || 0;
195
247
  const isMinDisabled = min !== void 0 && numValue <= min;
196
248
  const isMaxDisabled = max !== void 0 && numValue >= max;
249
+ const isMaxExceeded = max !== void 0 && numValue > max;
250
+ const displayMax = showMax ?? max !== void 0;
251
+ const showHeader = !!label || displayMax;
252
+ const isError = error || isMaxExceeded;
253
+ const showBtns = !hideButtons && !readOnly;
254
+ const isBasic = variant !== "bind";
197
255
  return /* @__PURE__ */ jsxRuntime.jsxs(
198
256
  "div",
199
257
  {
200
258
  className: chunkCZC76ZD5_js.cn(
201
- numberInputVariants({ size, state }),
259
+ numberInputVariants({ variant, size }),
260
+ isError && "nexus-number-input--error",
202
261
  disabled && "nexus-number-input--disabled",
203
262
  className
204
263
  ),
205
264
  children: [
206
- /* @__PURE__ */ jsxRuntime.jsx(
207
- "input",
208
- {
209
- ref: inputRef,
210
- type: "text",
211
- inputMode: "decimal",
212
- role: "spinbutton",
213
- className: chunkCZC76ZD5_js.cn("nexus-number-input__field", padSize),
214
- value: internalValue,
215
- disabled,
216
- readOnly,
217
- placeholder,
218
- "aria-invalid": error || void 0,
219
- "aria-valuemin": min,
220
- "aria-valuemax": max,
221
- "aria-valuenow": internalValue ? parseFloat(internalValue) || void 0 : void 0,
222
- onChange: handleInputChange,
223
- onBlur: handleBlur,
224
- onKeyDown: handleKeyDown,
225
- ...props
226
- }
227
- ),
228
- showButtons && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nexus-number-input__buttons", children: [
229
- /* @__PURE__ */ jsxRuntime.jsx(
265
+ showHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nexus-number-input__header", children: [
266
+ label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nexus-number-input__label", children: label }),
267
+ displayMax && max !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs(
230
268
  "button",
231
269
  {
232
270
  type: "button",
271
+ className: "nexus-number-input__max",
272
+ onClick: handleMaxClick,
273
+ disabled: disabled || readOnly,
233
274
  tabIndex: -1,
234
- disabled: isMaxDisabled,
235
- className: "nexus-number-input__step nexus-number-input__step--up",
236
- onPointerDown: (e) => startRepeat(step, e),
275
+ children: [
276
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nexus-number-input__max-text", children: "Max" }),
277
+ /* @__PURE__ */ jsxRuntime.jsx(
278
+ "span",
279
+ {
280
+ className: chunkCZC76ZD5_js.cn(
281
+ "nexus-number-input__max-value",
282
+ isMaxExceeded && "nexus-number-input__max-value--exceeded"
283
+ ),
284
+ children: max
285
+ }
286
+ )
287
+ ]
288
+ }
289
+ )
290
+ ] }),
291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nexus-number-input__container", children: [
292
+ !isBasic && showBtns && /* @__PURE__ */ jsxRuntime.jsx(
293
+ "button",
294
+ {
295
+ type: "button",
296
+ tabIndex: -1,
297
+ disabled: disabled || isMinDisabled,
298
+ className: "nexus-number-input__bind-btn",
299
+ onPointerDown: (e) => startRepeat(-step, e),
237
300
  onPointerUp: stopRepeat,
238
301
  onPointerLeave: stopRepeat,
239
- "aria-label": "Increase",
240
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronUp, {})
302
+ "aria-label": "Decrease",
303
+ children: /* @__PURE__ */ jsxRuntime.jsx(MinusIcon, {})
241
304
  }
242
305
  ),
243
306
  /* @__PURE__ */ jsxRuntime.jsx(
307
+ "input",
308
+ {
309
+ ref: inputRef,
310
+ type: "text",
311
+ inputMode: "decimal",
312
+ role: "spinbutton",
313
+ className: "nexus-number-input__field",
314
+ value: internalValue,
315
+ disabled,
316
+ readOnly,
317
+ placeholder: placeholder ?? "0",
318
+ "aria-invalid": isError || void 0,
319
+ "aria-valuemin": min,
320
+ "aria-valuemax": max,
321
+ "aria-valuenow": internalValue ? parseFloat(internalValue) || void 0 : void 0,
322
+ onChange: handleInputChange,
323
+ onBlur: handleBlur,
324
+ onKeyDown: handleKeyDown,
325
+ ...props
326
+ }
327
+ ),
328
+ !isBasic && showBtns && /* @__PURE__ */ jsxRuntime.jsx(
244
329
  "button",
245
330
  {
246
331
  type: "button",
247
332
  tabIndex: -1,
248
- disabled: isMinDisabled,
249
- className: "nexus-number-input__step nexus-number-input__step--down",
250
- onPointerDown: (e) => startRepeat(-step, e),
333
+ disabled: disabled || isMaxDisabled,
334
+ className: "nexus-number-input__bind-btn",
335
+ onPointerDown: (e) => startRepeat(step, e),
251
336
  onPointerUp: stopRepeat,
252
337
  onPointerLeave: stopRepeat,
253
- "aria-label": "Decrease",
254
- children: /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
338
+ "aria-label": "Increase",
339
+ children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {})
255
340
  }
256
- )
257
- ] })
341
+ ),
342
+ isBasic && showBtns && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nexus-number-input__buttons", children: [
343
+ /* @__PURE__ */ jsxRuntime.jsx(
344
+ "button",
345
+ {
346
+ type: "button",
347
+ tabIndex: -1,
348
+ disabled: disabled || isMaxDisabled,
349
+ className: "nexus-number-input__step nexus-number-input__step--up",
350
+ onPointerDown: (e) => startRepeat(step, e),
351
+ onPointerUp: stopRepeat,
352
+ onPointerLeave: stopRepeat,
353
+ "aria-label": "Increase",
354
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronUpIcon, {})
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsxRuntime.jsx(
358
+ "button",
359
+ {
360
+ type: "button",
361
+ tabIndex: -1,
362
+ disabled: disabled || isMinDisabled,
363
+ className: "nexus-number-input__step nexus-number-input__step--down",
364
+ onPointerDown: (e) => startRepeat(-step, e),
365
+ onPointerUp: stopRepeat,
366
+ onPointerLeave: stopRepeat,
367
+ "aria-label": "Decrease",
368
+ children: /* @__PURE__ */ jsxRuntime.jsx(ChevronDownIcon, {})
369
+ }
370
+ )
371
+ ] })
372
+ ] }),
373
+ description && /* @__PURE__ */ jsxRuntime.jsx(
374
+ "p",
375
+ {
376
+ className: chunkCZC76ZD5_js.cn(
377
+ "nexus-number-input__description",
378
+ isError && "nexus-number-input__description--error"
379
+ ),
380
+ children: description
381
+ }
382
+ )
258
383
  ]
259
384
  }
260
385
  );