@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 +185 -0
- package/cursor-rules/nexus-ui-api.mdc +10 -6
- package/dist/chunks/{chunk-AFSEYJZT.js → chunk-2T7RUYEK.js} +175 -50
- package/dist/chunks/chunk-BJM3NDT2.mjs +368 -0
- package/dist/chunks/chunk-PXBZEAZQ.mjs +5 -0
- package/dist/chunks/chunk-QRNHFOLG.js +7 -0
- package/dist/index.js +4 -4
- package/dist/index.mjs +1 -1
- package/dist/number-input.d.mts +5 -6
- package/dist/number-input.d.ts +5 -6
- package/dist/number-input.js +4 -4
- package/dist/number-input.mjs +1 -1
- package/dist/schemas/_all.json +27 -8
- package/dist/schemas/numberInput.json +27 -8
- package/dist/schemas.d.mts +15 -3
- package/dist/schemas.d.ts +15 -3
- package/dist/schemas.js +12 -6
- package/dist/schemas.mjs +12 -6
- package/dist/styles/layer.js +2 -2
- package/dist/styles/layer.mjs +1 -1
- package/dist/styles.css +191 -64
- package/dist/styles.js +2 -2
- package/dist/styles.layered.css +191 -64
- package/dist/styles.mjs +1 -1
- package/package.json +4 -3
- package/scripts/setup-cursor-rules.cjs +15 -1
- package/dist/chunks/chunk-ECVAVQUY.mjs +0 -243
- package/dist/chunks/chunk-KZ7S5VN2.js +0 -7
- package/dist/chunks/chunk-PI464222.mjs +0 -5
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
|
|
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` | `'
|
|
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
|
-
| `
|
|
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
|
|
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: {
|
|
39
|
+
defaultVariants: { variant: "basic", size: "lg" }
|
|
42
40
|
});
|
|
43
|
-
var
|
|
44
|
-
var
|
|
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
|
|
84
|
-
|
|
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
|
|
193
|
-
|
|
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({
|
|
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.
|
|
207
|
-
"
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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": "
|
|
240
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
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:
|
|
249
|
-
className: "nexus-number-
|
|
250
|
-
onPointerDown: (e) => startRepeat(
|
|
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": "
|
|
254
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
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
|
);
|