@nqlib/nqui 0.4.3 → 0.4.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/INSTALLATION.md +234 -0
- package/README.md +109 -151
- package/dist/button-CJHdCq9I.js +155 -0
- package/dist/button-R304rhsj.cjs +1 -0
- package/dist/calendar.cjs.js +1 -1
- package/dist/calendar.es.js +1 -1
- package/dist/carousel-D1FMVglR.cjs +1 -0
- package/dist/carousel-U7RZhYZj.js +179 -0
- package/dist/carousel.cjs.js +1 -1
- package/dist/carousel.es.js +1 -1
- package/dist/command-palette-DCtLpM3Q.js +694 -0
- package/dist/command-palette-MHc03bBf.cjs +5 -0
- package/dist/command.cjs.js +1 -1
- package/dist/command.es.js +1 -1
- package/dist/components/custom/color-picker.d.ts +1 -1
- package/dist/components/custom/color-picker.d.ts.map +1 -1
- package/dist/components/custom/color-slider.d.ts +4 -10
- package/dist/components/custom/color-slider.d.ts.map +1 -1
- package/dist/components/custom/enhanced-radio-group.d.ts +13 -4
- package/dist/components/custom/enhanced-radio-group.d.ts.map +1 -1
- package/dist/components/custom/enhanced-tabs.d.ts.map +1 -1
- package/dist/components/debug/debug-features.d.ts +29 -0
- package/dist/components/debug/debug-features.d.ts.map +1 -0
- package/dist/components/debug/debug-panel.d.ts.map +1 -1
- package/dist/components/error-boundary.d.ts +20 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/index.d.ts +103 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/badge.d.ts +16 -5
- package/dist/components/ui/badge.d.ts.map +1 -1
- package/dist/components/ui/button.d.ts +38 -4
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/checkbox.d.ts +16 -2
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/combobox.d.ts +2 -1
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/frosted-glass.d.ts.map +1 -1
- package/dist/components/ui/input-group.d.ts +1 -1
- package/dist/components/ui/input-group.d.ts.map +1 -1
- package/dist/components/ui/pagination.d.ts +3 -2
- package/dist/components/ui/pagination.d.ts.map +1 -1
- package/dist/components/ui/radio-group.d.ts +3 -1
- package/dist/components/ui/radio-group.d.ts.map +1 -1
- package/dist/components/ui/select.d.ts +6 -1
- package/dist/components/ui/select.d.ts.map +1 -1
- package/dist/components/ui/sidebar.d.ts +1 -1
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/slider.d.ts +10 -2
- package/dist/components/ui/slider.d.ts.map +1 -1
- package/dist/components/ui/sonner.d.ts +18 -2
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/spinner.d.ts +2 -1
- package/dist/components/ui/spinner.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +15 -2
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/tabs.d.ts +1 -1
- package/dist/components/ui/tabs.d.ts.map +1 -1
- package/dist/components/ui/toggle.d.ts +1 -1
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/debug-panel-CNKk-No5.cjs +75 -0
- package/dist/debug-panel-pg39-6xw.js +9011 -0
- package/dist/debug.cjs.js +1 -0
- package/dist/debug.es.js +7 -0
- package/dist/{drawer-CU4lkcz7.js → drawer-DO26uhym.js} +31 -31
- package/dist/drawer-DVarEy65.cjs +1 -0
- package/dist/drawer.cjs.js +1 -1
- package/dist/drawer.es.js +1 -1
- package/dist/{enhanced-calendar-BENbxw7_.js → enhanced-calendar-BGlsSYJd.js} +1 -1
- package/dist/{enhanced-calendar-5PA8CeF7.cjs → enhanced-calendar-C7EQIr6i.cjs} +1 -1
- package/dist/entries/debug.d.ts +14 -0
- package/dist/entries/debug.d.ts.map +1 -0
- package/dist/entries/sonner.d.ts +1 -2
- package/dist/entries/sonner.d.ts.map +1 -1
- package/dist/hooks/use-mobile.d.ts.map +1 -1
- package/dist/hooks/use-scroll-spy.d.ts.map +1 -1
- package/dist/index-CI756mSv.cjs +41 -0
- package/dist/index-CgfzsUO6.js +1069 -0
- package/dist/index.d.ts +2 -98
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/wrap-inline-label-text.d.ts +7 -0
- package/dist/lib/wrap-inline-label-text.d.ts.map +1 -0
- package/dist/nqui.cjs.js +49 -245
- package/dist/nqui.es.js +7402 -16735
- package/dist/sonner-CpmECDBk.js +179 -0
- package/dist/sonner-nE9hIalJ.cjs +48 -0
- package/dist/sonner.cjs.js +1 -1
- package/dist/sonner.es.js +3 -2
- package/dist/styles.css +237 -10
- package/docs/components/README.md +109 -10
- package/docs/components/nqui-badge.md +1 -0
- package/docs/components/nqui-button.md +3 -1
- package/docs/components/nqui-card.md +8 -0
- package/docs/components/nqui-carousel.md +6 -0
- package/docs/components/nqui-checkbox.md +38 -1
- package/docs/components/nqui-color-slider.md +5 -3
- package/docs/components/nqui-combobox.md +58 -37
- package/docs/components/nqui-drawer.md +1 -1
- package/docs/components/nqui-frosted-glass.md +83 -5
- package/docs/components/nqui-radio-group.md +47 -2
- package/docs/components/nqui-scroll-area.md +1 -1
- package/docs/components/nqui-select.md +2 -2
- package/docs/components/nqui-sheet.md +1 -1
- package/docs/components/nqui-slider.md +13 -0
- package/docs/components/nqui-spinner.md +6 -1
- package/docs/components/nqui-switch.md +23 -1
- package/docs/components/nqui-tabs.md +11 -1
- package/docs/components/nqui-toaster.md +5 -1
- package/docs/internal-notes/PUBLISHING.md +46 -4
- package/docs/nqui-skills/SKILL.md +106 -0
- package/docs/nqui-skills/design-system.md +143 -0
- package/docs/nqui-skills/rules/composition.md +183 -0
- package/docs/nqui-skills/rules/forms.md +190 -0
- package/docs/nqui-skills/rules/icons.md +158 -0
- package/docs/nqui-skills/rules/styling.md +192 -0
- package/package.json +23 -12
- package/scripts/build-styles.js +16 -0
- package/scripts/cli.js +1 -0
- package/scripts/download-skills.js +91 -0
- package/scripts/examples/nextjs-layout-sidebar.tsx +100 -0
- package/scripts/examples/nextjs-page-sidebar.tsx +81 -0
- package/scripts/examples/vite-app.tsx +135 -0
- package/scripts/examples/vite-main.tsx +17 -0
- package/scripts/examples.js +92 -6
- package/scripts/generate-docs.js +169 -0
- package/scripts/init-css.js +34 -14
- package/scripts/init-cursor.js +8 -0
- package/scripts/init-debug-css.js +4 -2
- package/scripts/post-install.js +41 -9
- package/scripts/publish-npmjs.js +17 -3
- package/scripts/resolve-target-dir.js +20 -1
- package/scripts/setup-helper.js +13 -1
- package/scripts/verify-build.js +1 -1
- package/scripts/wizard.js +12 -7
- package/dist/button-CYFTFDKe.cjs +0 -1
- package/dist/button-nJvDl3w8.js +0 -44
- package/dist/carousel-DEyyJi49.js +0 -179
- package/dist/carousel-Dhhz8m5V.cjs +0 -1
- package/dist/command-palette-UHk8zZOg.cjs +0 -45
- package/dist/command-palette-d-TrdBsM.js +0 -1778
- package/dist/components/custom/enhanced-badge.d.ts +0 -33
- package/dist/components/custom/enhanced-badge.d.ts.map +0 -1
- package/dist/components/custom/enhanced-button.d.ts +0 -34
- package/dist/components/custom/enhanced-button.d.ts.map +0 -1
- package/dist/components/custom/enhanced-checkbox.d.ts +0 -28
- package/dist/components/custom/enhanced-checkbox.d.ts.map +0 -1
- package/dist/components/custom/enhanced-combobox.d.ts +0 -35
- package/dist/components/custom/enhanced-combobox.d.ts.map +0 -1
- package/dist/components/custom/enhanced-select.d.ts +0 -30
- package/dist/components/custom/enhanced-select.d.ts.map +0 -1
- package/dist/components/custom/enhanced-sonner.d.ts +0 -16
- package/dist/components/custom/enhanced-sonner.d.ts.map +0 -1
- package/dist/drawer-BcIxWRN8.cjs +0 -1
- package/dist/sonner-Co6YpYVs.js +0 -546
- package/dist/sonner-DbQhVp8m.cjs +0 -330
|
@@ -17,7 +17,7 @@ Implementation guides for each component. **AI Skill:** Optimized for AI/LLM con
|
|
|
17
17
|
| Dependency | Version | Notes |
|
|
18
18
|
|------------|---------|-------|
|
|
19
19
|
| **React** | 18+ or 19 | nqui supports React 18 and 19 via `^18.0.0 \|\| ^19.0.0` peer. |
|
|
20
|
-
| **Tailwind CSS** | ^4.x | Required. Vite: `@tailwindcss/vite`. Next.js
|
|
20
|
+
| **Tailwind CSS** | ^4.x | Required. Vite: `@tailwindcss/vite`. Both Vite and Next.js need `@source` for `node_modules/@nqlib/nqui/dist` (Tailwind does not scan node_modules). |
|
|
21
21
|
| **tw-animate-css** | — | `@import "tw-animate-css"` in your CSS (added by init-css). |
|
|
22
22
|
| **Radix UI** | — | Bundled (Dialog, Select, etc.). |
|
|
23
23
|
| **Hugeicons** | @hugeicons/react, @hugeicons/core-free-icons | Required for icon display in components. |
|
|
@@ -28,16 +28,115 @@ Implementation guides for each component. **AI Skill:** Optimized for AI/LLM con
|
|
|
28
28
|
|
|
29
29
|
## Shared Conventions (AI Implementation Rules)
|
|
30
30
|
|
|
31
|
-
- **Control sizes:** `sm`=h-6, `default`=h-7, `lg`=h-8. Button, Toggle, ToggleGroup, Input, Select use this scale. See `.cursor/skills/nqui-design-system/SKILL.md`.
|
|
31
|
+
- **Control sizes:** `sm`=h-6, `default`=h-7, `lg`=h-8. Button, Toggle, ToggleGroup, Input, Select, Switch, Slider use this scale. See `packages/nqui/docs/nqui-skills/design-system.md` or `.cursor/skills/nqui-design-system/SKILL.md`.
|
|
32
32
|
- **CSS vars required:** nqui uses `--primary`, `--background`, `--foreground`, etc. Run `npx @nqlib/nqui init-css`.
|
|
33
|
-
- **Enhanced vs Core:** Button
|
|
34
|
-
- **Grouped controls:** ButtonGroup, ToggleGroup share border; ToggleGroup uses item dividers (`border-foreground/20`) or `ToggleGroupSeparator`.
|
|
33
|
+
- **Enhanced vs Core:** Default exports (`Button`, `Badge`, `Checkbox`, `Select`, etc.) are the polished/3D variants. Implementations live in **`packages/nqui/src/components/ui/*.tsx`** (single file per concern). Use `CoreButton`, `CoreBadge`, `CoreCheckbox`, etc. for base Radix/shadcn-style behavior. Separator: single component with `variant` prop (no CoreSeparator).
|
|
34
|
+
- **Grouped controls:** ButtonGroup, ToggleGroup share border; outer container uses **pill** radius (`rounded-full`). ToggleGroup uses item dividers (`border-foreground/20`) or `ToggleGroupSeparator`.
|
|
35
35
|
- **Toolbar context:** Always show Toggle/ToggleGroup in realistic context (document toolbar, chart settings, etc.). Reference: `src/pages/ComponentShowcase.tsx`.
|
|
36
|
-
- **Style injection:**
|
|
36
|
+
- **Style injection:** Some components inject `<style>` once at mount (e.g. **Combobox** input chrome in `ui/combobox.tsx`) → safe for SSR if the component is client-only (`"use client"`).
|
|
37
37
|
- **OKLCH:** ColorPicker expects OKLCH strings (`oklch(0.5 0.15 240)`), not hex.
|
|
38
38
|
- **SidebarProvider:** Must wrap entire layout (sidebar + content).
|
|
39
39
|
- **Z-index:** Use CSS vars from `styles/elevation.css` (e.g. `z-[var(--z-modal)]`). Never hardcode `z-10`, `z-50`, etc.
|
|
40
40
|
- **Keyboard:** Use `Keys`, `isMod`, `shouldIgnoreKeyboardShortcut` from `@/lib/keyboard` for custom shortcuts.
|
|
41
|
+
- **Bounded content:** Chips, pills, and inline controls should stay inside their box (ellipsis / line-clamp / scroll-by-design). See **Bounded content** in `packages/nqui/docs/nqui-skills/design-system.md`. Portals and tooltips are explicit exceptions.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Layout & Scroll Patterns
|
|
46
|
+
|
|
47
|
+
This section documents the CSS patterns used in the showcase app to ensure proper scroll behavior and prevent sticky element issues.
|
|
48
|
+
|
|
49
|
+
### Sticky Elements & Momentum Scroll
|
|
50
|
+
|
|
51
|
+
**The problem:** When using default body scroll, sticky elements can exhibit "momentum push" behavior during fast scrolling - they appear to float or lag before snapping back. This happens because sticky positioning is relative to the viewport, not the scroll container.
|
|
52
|
+
|
|
53
|
+
**The solution:** Use a custom scroll container instead of body/html scroll.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
// App layout structure - prevents momentum push on sticky elements
|
|
57
|
+
<div className="h-screen overflow-hidden">
|
|
58
|
+
<header className="sticky top-0 z-[var(--z-sticky-page)]">
|
|
59
|
+
{/* Page header */}
|
|
60
|
+
</header>
|
|
61
|
+
<main className="flex-1 min-h-0 overflow-y-auto">
|
|
62
|
+
{/* Scrollable content */}
|
|
63
|
+
</main>
|
|
64
|
+
</div>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Z-Index Layering for Sticky Elements
|
|
68
|
+
|
|
69
|
+
Use the correct z-index variables to prevent sticky element conflicts:
|
|
70
|
+
|
|
71
|
+
| Element | CSS Variable | Value |
|
|
72
|
+
|---------|-------------|-------|
|
|
73
|
+
| Page headers, navigation bars | `z-[var(--z-sticky-page)]` | 20 |
|
|
74
|
+
| Card headers, table headers | `z-[var(--z-sticky-content)]` | 15 |
|
|
75
|
+
|
|
76
|
+
**Rule:** Page-level sticky elements (20) must be above container-level sticky elements (15) to prevent scroll conflicts.
|
|
77
|
+
|
|
78
|
+
### Flex Scroll Pattern
|
|
79
|
+
|
|
80
|
+
For nested scrolling to work correctly, flex children must have `min-height: 0` (or `min-h-0` in Tailwind):
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// Correct - flex child can shrink and scroll
|
|
84
|
+
<div className="flex flex-col h-screen">
|
|
85
|
+
<header className="flex-shrink-0">...</header>
|
|
86
|
+
<main className="flex-1 min-h-0 overflow-y-auto">
|
|
87
|
+
{/* This will scroll */}
|
|
88
|
+
</main>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
// Wrong - flex child cannot shrink below content height
|
|
92
|
+
<div className="flex flex-col h-screen">
|
|
93
|
+
<header>...</header>
|
|
94
|
+
<main className="flex-1 overflow-y-auto">
|
|
95
|
+
{/* May not scroll - overflows instead */}
|
|
96
|
+
</main>
|
|
97
|
+
</div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Body Scroll Prevention
|
|
101
|
+
|
|
102
|
+
For app-like experiences, disable body/html scroll:
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
// Disable browser scroll restoration
|
|
107
|
+
if ('scrollRestoration' in history) {
|
|
108
|
+
history.scrollRestoration = 'manual'
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Prevent body/html from scrolling
|
|
112
|
+
document.body.style.overflow = 'hidden'
|
|
113
|
+
document.documentElement.style.overflow = 'hidden'
|
|
114
|
+
|
|
115
|
+
return () => {
|
|
116
|
+
document.body.style.overflow = ''
|
|
117
|
+
document.documentElement.style.overflow = ''
|
|
118
|
+
}
|
|
119
|
+
}, [])
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Sliding Indicator Containers
|
|
123
|
+
|
|
124
|
+
Components with sliding indicators (Tabs, RadioGroup `sliding` variant) need specific container styling:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
// Required CSS for sliding indicator containers
|
|
128
|
+
.sliding-indicator-container {
|
|
129
|
+
position: relative;
|
|
130
|
+
overflow: hidden;
|
|
131
|
+
min-width: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.sliding-indicator {
|
|
135
|
+
position: absolute;
|
|
136
|
+
overflow: visible;
|
|
137
|
+
/* transitions for smooth sliding */
|
|
138
|
+
}
|
|
139
|
+
```
|
|
41
140
|
|
|
42
141
|
---
|
|
43
142
|
|
|
@@ -67,7 +166,7 @@ Use these rules to choose the right component. **Selection** = user picks from o
|
|
|
67
166
|
|-------|-----|
|
|
68
167
|
| 2–5 options, inline (e.g. bold/italic/underline) | **ToggleGroup** `type="multiple"` |
|
|
69
168
|
| Form context, list of options | **Checkbox** (each option) |
|
|
70
|
-
| Many options, need search | **Combobox** `
|
|
169
|
+
| Many options, need search | **Combobox** with `multiple` (see `nqui-combobox.md`) |
|
|
71
170
|
|
|
72
171
|
### Actions (trigger, not select)
|
|
73
172
|
|
|
@@ -108,7 +207,7 @@ Use these rules to choose the right component. **Selection** = user picks from o
|
|
|
108
207
|
| Single choice, 5+ options or no space | **Select** |
|
|
109
208
|
| Single choice, need search | **Combobox** (single) |
|
|
110
209
|
| Single choice, form, small option set | **RadioGroup** |
|
|
111
|
-
| Multiple choice, need search | **Combobox** `
|
|
210
|
+
| Multiple choice, need search | **Combobox** with `multiple` (see `nqui-combobox.md`) |
|
|
112
211
|
| One boolean (agree, subscribe) | **Checkbox** |
|
|
113
212
|
| On/off setting (dark mode, notifications) | **Switch** |
|
|
114
213
|
| Numeric range (volume, opacity) | **Slider** |
|
|
@@ -135,7 +234,7 @@ Use these rules to choose the right component. **Selection** = user picks from o
|
|
|
135
234
|
| Rating | [nqui-rating.md](./nqui-rating.md) | Star/score (1–5). |
|
|
136
235
|
| InputOTP | [nqui-input-otp.md](./nqui-input-otp.md) | OTP/verification. |
|
|
137
236
|
| Field | [nqui-field.md](./nqui-field.md) | Label + description + error wrapper. |
|
|
138
|
-
| Combobox | [nqui-combobox.md](./nqui-combobox.md) | **Searchable** select. Single or `
|
|
237
|
+
| Combobox | [nqui-combobox.md](./nqui-combobox.md) | **Searchable** select. Single or `multiple`. Use when user types to filter. |
|
|
139
238
|
| ColorPicker | [nqui-color-picker.md](./nqui-color-picker.md) | Color selection. OKLCH. |
|
|
140
239
|
| ColorSlider | [nqui-color-slider.md](./nqui-color-slider.md) | Hue/saturation (used in ColorPicker). |
|
|
141
240
|
| Label | [nqui-label.md](./nqui-label.md) | Form label. |
|
|
@@ -158,7 +257,7 @@ Use these rules to choose the right component. **Selection** = user picks from o
|
|
|
158
257
|
| List row (avatar + title + actions) | **Item** |
|
|
159
258
|
| Show keyboard shortcut | **Kbd** |
|
|
160
259
|
| Activity blocks (e.g. heatmap) | **Tracker** |
|
|
161
|
-
| Glass effect | **FrostedGlass** |
|
|
260
|
+
| Glass effect (blur + tint row; scroll behind) | **FrostedGlass** |
|
|
162
261
|
|
|
163
262
|
---
|
|
164
263
|
|
|
@@ -178,7 +277,7 @@ Use these rules to choose the right component. **Selection** = user picks from o
|
|
|
178
277
|
| Item | [nqui-item.md](./nqui-item.md) | List row: media + title + description + actions. |
|
|
179
278
|
| Kbd | [nqui-kbd.md](./nqui-kbd.md) | Keyboard shortcut display. |
|
|
180
279
|
| Tracker | [nqui-tracker.md](./nqui-tracker.md) | Activity blocks (heatmap). |
|
|
181
|
-
| FrostedGlass | [nqui-frosted-glass.md](./nqui-frosted-glass.md) | Glass
|
|
280
|
+
| FrostedGlass | [nqui-frosted-glass.md](./nqui-frosted-glass.md) | Glass blur; use with second tint row + scroll behind (see doc). |
|
|
182
281
|
| NquiLogo | [nqui-logo.md](./nqui-logo.md) | Theme-aware logo. |
|
|
183
282
|
|
|
184
283
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# nqui Button
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Default **Button** is the enhanced variant (gradients, depth, active scale). Implemented in **`ui/button.tsx`** with **`CoreButton`** for the plain primitive.
|
|
4
4
|
|
|
5
5
|
## Import
|
|
6
6
|
|
|
@@ -52,5 +52,7 @@ Render as `<a>` or custom element:
|
|
|
52
52
|
|
|
53
53
|
## Notes
|
|
54
54
|
|
|
55
|
+
- **Shape:** full pill (`rounded-full`) for all sizes.
|
|
56
|
+
- **Bounded label:** string/number children are wrapped so **`truncate`** + **`min-w-0`** apply in narrow layouts. Same pattern is used across **Toggle**, **Tabs**, **Badge**, **Combobox** chips; **Select** value uses **line-clamp**. Custom markup with one long inner node may still need its own `min-w-0 truncate` or a **`title`**.
|
|
55
57
|
- Active state uses `scale-95`; avoid parent `transform` overrides.
|
|
56
58
|
- Use `CoreButton` from `@nqlib/nqui` for base shadcn style.
|
|
@@ -29,3 +29,11 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }
|
|
|
29
29
|
<CardContent>Scrollable content</CardContent>
|
|
30
30
|
</Card>
|
|
31
31
|
```
|
|
32
|
+
|
|
33
|
+
## Notes
|
|
34
|
+
|
|
35
|
+
- **Layout / bounds:** Root **Card**, **CardHeader**, **CardContent**, and **CardFooter** include **`min-w-0`** so nested flex/grid layouts can shrink and children are less likely to spill horizontally. **Card** stays **`overflow-visible`** on purpose so popovers, menus, and focus rings are not clipped—pair with bounded components (buttons, carousel insets, `truncate`, etc.) instead of `overflow-hidden` on the card by default.
|
|
36
|
+
- **stickyHeader:** Use `stickyHeader` prop on Card for scrollable content with sticky header. The header uses `--z-sticky-content` (z-index: 15).
|
|
37
|
+
- **Z-index layering:** Card sticky headers (15) are below page headers (20). If using in a page with sticky header, ensure proper z-index layering.
|
|
38
|
+
- **Height required:** Card needs a defined height (e.g., `h-[400px]` or `h-full`) for sticky behavior to work.
|
|
39
|
+
- **Content scroll:** The CardContent becomes scrollable when Card has `stickyHeader` and a defined height.
|
|
@@ -20,3 +20,9 @@ import { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext
|
|
|
20
20
|
<CarouselNext />
|
|
21
21
|
</Carousel>
|
|
22
22
|
```
|
|
23
|
+
|
|
24
|
+
## Notes
|
|
25
|
+
|
|
26
|
+
- **Prev/Next** are positioned **inside** the carousel region (`left-2` / `right-2`, or `top-2` / `bottom-2` when vertical) so arrows stay within parents like **Card** instead of using negative offsets that sat outside the viewport (`-left-12` / `-right-12` previously).
|
|
27
|
+
- **Visibility:** Arrows are **dim by default** (`opacity-35`), ramp up on **carousel hover** (`group-hover/carousel`), and go **full opacity** on **button** `:hover`, `:focus-visible`, and `:active` (tap). Disabled controls stay faint.
|
|
28
|
+
- Override with `className` on `CarouselPrevious` / `CarouselNext` if you need edge-aligned or external controls.
|
|
@@ -11,9 +11,31 @@ import { Checkbox } from "@nqlib/nqui"
|
|
|
11
11
|
## Basic
|
|
12
12
|
|
|
13
13
|
```tsx
|
|
14
|
-
|
|
14
|
+
const [checked, setChecked] = useState(false)
|
|
15
|
+
|
|
16
|
+
<Checkbox checked={checked} onCheckedChange={setChecked}>Accept terms</Checkbox>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## With Label
|
|
20
|
+
|
|
21
|
+
Checkbox automatically wraps in a label when children are provided:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
<Checkbox>Accept terms</Checkbox>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Gap
|
|
28
|
+
|
|
29
|
+
Control the gap between checkbox and label:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
<Checkbox gap={2}>Compact gap (8px)</Checkbox>
|
|
33
|
+
<Checkbox gap={3}>Default gap (12px)</Checkbox>
|
|
34
|
+
<Checkbox gap={4}>Loose gap (16px)</Checkbox>
|
|
15
35
|
```
|
|
16
36
|
|
|
37
|
+
Options: `0`, `1`, `2`, `3`, `4` (maps to Tailwind gap-0 through gap-4).
|
|
38
|
+
|
|
17
39
|
## Variants
|
|
18
40
|
|
|
19
41
|
```tsx
|
|
@@ -27,8 +49,23 @@ import { Checkbox } from "@nqlib/nqui"
|
|
|
27
49
|
<Checkbox checked="indeterminate" onCheckedChange={...} />
|
|
28
50
|
```
|
|
29
51
|
|
|
52
|
+
## Hit area (expanded pointer target)
|
|
53
|
+
|
|
54
|
+
nqui ships [Bazza **hit-area** utilities](https://bazza.dev/craft/2026/hit-area) in library CSS (`hit-area-*`, `hit-area-x-*`, `hit-area-debug`, etc.). They extend the clickable region with a `::before` layer without changing layout.
|
|
55
|
+
|
|
56
|
+
**Enhanced checkbox:** The checkmark is drawn with `::after` on the control root so `::before` stays free for `hit-area-*` on the **same** element. Add a class when you want a larger target (e.g. padded table cells):
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
<Checkbox className="hit-area-6" checked={rowSelected} onCheckedChange={...} aria-label="Select row" />
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Label hover pill:** `.checkbox-animated-label::before` is on the **label** wrapper only; it does not conflict with `hit-area-*` on the checkbox button.
|
|
63
|
+
|
|
64
|
+
**Without hit-area:** You can still wrap the control in `<span className="relative hit-area-6">` if you prefer the expanded area on a wrapper.
|
|
65
|
+
|
|
30
66
|
## Notes
|
|
31
67
|
|
|
68
|
+
- Implementation: **`packages/nqui/src/components/ui/checkbox.tsx`** (enhanced + core in one module).
|
|
32
69
|
- Injects `<style>` at mount. Use client-only guard for SSR.
|
|
33
70
|
- Square and round share the same animation (pulse + checkmark scale); round has no SVG filters.
|
|
34
71
|
- Use `CoreCheckbox` for plain Radix checkbox.
|
|
@@ -10,10 +10,12 @@ import { ColorSlider } from "@nqlib/nqui"
|
|
|
10
10
|
|
|
11
11
|
## Types
|
|
12
12
|
|
|
13
|
+
Built on **`Slider`** from `ui/slider` (white thumb + shadow). For **non-controlled** demos, prefer **`defaultValue`** so the thumb stays draggable.
|
|
14
|
+
|
|
13
15
|
```tsx
|
|
14
|
-
<ColorSlider sliderType="hue"
|
|
15
|
-
<ColorSlider sliderType="saturation"
|
|
16
|
-
<ColorSlider sliderType="lightness"
|
|
16
|
+
<ColorSlider sliderType="hue" defaultValue={[240]} onValueChange={setVal} min={0} max={360} />
|
|
17
|
+
<ColorSlider sliderType="saturation" defaultValue={[0.5]} onValueChange={setVal} min={0} max={1} step={0.01} />
|
|
18
|
+
<ColorSlider sliderType="lightness" defaultValue={[0.6]} onValueChange={setVal} min={0} max={1} step={0.01} />
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
## Custom
|
|
@@ -1,73 +1,94 @@
|
|
|
1
1
|
# nqui Combobox
|
|
2
2
|
|
|
3
|
-
> **Searchable** select
|
|
3
|
+
> **Searchable** select (Base UI). User types to filter options. Single or multiple selection.
|
|
4
4
|
|
|
5
5
|
## When to Use
|
|
6
6
|
|
|
7
|
-
- **Selection:** Single or multiple
|
|
8
|
-
- **Key feature:**
|
|
9
|
-
- **Options:** Many
|
|
7
|
+
- **Selection:** Single (default) or multiple (`multiple` on root)
|
|
8
|
+
- **Key feature:** Filter list by typing in the input
|
|
9
|
+
- **Options:** Many rows; use **`items`** on `Combobox` + render prop on `ComboboxList` for built-in filtering
|
|
10
10
|
|
|
11
|
-
**Choose Combobox when:**
|
|
11
|
+
**Choose Combobox when:** Users need search. Use **Select** when a plain dropdown is enough.
|
|
12
12
|
|
|
13
13
|
## Import
|
|
14
14
|
|
|
15
15
|
```tsx
|
|
16
16
|
import {
|
|
17
|
-
Combobox,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
Combobox,
|
|
18
|
+
ComboboxInput,
|
|
19
|
+
ComboboxContent,
|
|
20
|
+
ComboboxList,
|
|
21
|
+
ComboboxItem,
|
|
22
|
+
ComboboxEmpty,
|
|
23
|
+
ComboboxGroup,
|
|
24
|
+
ComboboxLabel,
|
|
25
|
+
ComboboxSeparator,
|
|
26
|
+
ComboboxCollection,
|
|
27
|
+
ComboboxChips,
|
|
28
|
+
ComboboxChip,
|
|
29
|
+
ComboboxChipsInput,
|
|
30
|
+
ComboboxTrigger,
|
|
31
|
+
ComboboxValue,
|
|
32
|
+
ComboboxClear,
|
|
33
|
+
useComboboxAnchor,
|
|
21
34
|
} from "@nqlib/nqui"
|
|
22
35
|
```
|
|
23
36
|
|
|
24
|
-
##
|
|
37
|
+
## Single selection + type-to-filter (recommended)
|
|
38
|
+
|
|
39
|
+
Pass **`items`** to `Combobox` and use a **render function** as the only child of `ComboboxList`. Place **`ComboboxEmpty`** next to `ComboboxList` (both under `ComboboxContent`), not inside `ComboboxList` alongside the function.
|
|
25
40
|
|
|
26
41
|
```tsx
|
|
27
|
-
|
|
42
|
+
const fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]
|
|
43
|
+
|
|
44
|
+
<Combobox items={fruits}>
|
|
28
45
|
<ComboboxInput placeholder="Search..." />
|
|
29
46
|
<ComboboxContent>
|
|
47
|
+
<ComboboxEmpty>No results found.</ComboboxEmpty>
|
|
30
48
|
<ComboboxList>
|
|
31
|
-
{
|
|
32
|
-
<ComboboxItem key={item
|
|
33
|
-
|
|
49
|
+
{(item) => (
|
|
50
|
+
<ComboboxItem key={item} value={item}>
|
|
51
|
+
{item}
|
|
52
|
+
</ComboboxItem>
|
|
53
|
+
)}
|
|
34
54
|
</ComboboxList>
|
|
35
|
-
<ComboboxEmpty>No results</ComboboxEmpty>
|
|
36
55
|
</ComboboxContent>
|
|
37
56
|
</Combobox>
|
|
38
57
|
```
|
|
39
58
|
|
|
40
|
-
##
|
|
59
|
+
## Static list (no `items` filter)
|
|
41
60
|
|
|
42
|
-
|
|
43
|
-
<Combobox showClear ... />
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Multi-select chips
|
|
61
|
+
You can still render `ComboboxItem` children manually when you control filtering yourself.
|
|
47
62
|
|
|
48
63
|
```tsx
|
|
49
|
-
<Combobox
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
<Combobox>
|
|
65
|
+
<ComboboxInput placeholder="Search..." />
|
|
66
|
+
<ComboboxContent>
|
|
67
|
+
<ComboboxList>
|
|
68
|
+
<ComboboxItem value="a">A</ComboboxItem>
|
|
69
|
+
<ComboboxItem value="b">B</ComboboxItem>
|
|
70
|
+
</ComboboxList>
|
|
71
|
+
</ComboboxContent>
|
|
54
72
|
</Combobox>
|
|
55
73
|
```
|
|
56
74
|
|
|
57
|
-
##
|
|
75
|
+
## Clear button
|
|
58
76
|
|
|
59
77
|
```tsx
|
|
60
|
-
<
|
|
61
|
-
<ComboboxGroup>
|
|
62
|
-
<ComboboxLabel>Group A</ComboboxLabel>
|
|
63
|
-
<ComboboxItem value="a">A</ComboboxItem>
|
|
64
|
-
</ComboboxGroup>
|
|
65
|
-
<ComboboxSeparator />
|
|
66
|
-
...
|
|
67
|
-
</ComboboxCollection>
|
|
78
|
+
<ComboboxInput showClear placeholder="Search..." />
|
|
68
79
|
```
|
|
69
80
|
|
|
81
|
+
## Multiple selection
|
|
82
|
+
|
|
83
|
+
Use **`multiple`** on `Combobox` (see [Base UI Combobox](https://base-ui.com/react/components/combobox)). Combine with **`ComboboxChips`**, **`ComboboxChip`**, **`ComboboxChipsInput`** as needed for chip UI.
|
|
84
|
+
|
|
85
|
+
## Implementation
|
|
86
|
+
|
|
87
|
+
- **Source:** `packages/nqui/src/components/ui/combobox.tsx`
|
|
88
|
+
- **Public API:** exported from `@nqlib/nqui` (same as `CoreCombobox*` aliases in the barrel if you need the unprefixed base re-exports)
|
|
89
|
+
- **Styling:** Input group uses injected CSS once per page (`nqui-combobox-styles-v1`) for trigger depth/shadow; component is `"use client"`.
|
|
90
|
+
|
|
70
91
|
## Notes
|
|
71
92
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
93
|
+
- **`useComboboxAnchor`:** ref for anchoring `ComboboxContent` when using chips / custom layout.
|
|
94
|
+
- **Dropdown items:** spacing/hover treatment aligns with **Select** (`SelectItem`-style density).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# nqui Drawer
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Vaul** drawer. **DrawerContent** keeps an **inset rounded card** (`before:bg-card`, `before:inset-2`, `before:rounded-xl`) so the panel does not read as a full-bleed slab—surface follows **`card`** tokens in both themes.
|
|
4
4
|
|
|
5
5
|
## Import
|
|
6
6
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# nqui FrostedGlass
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Apple-style frosted glass using `backdrop-filter`, extended backdrop, and masks. **Do not use `FrostedGlass` alone** in headers—pair it with a second row that carries the tint and controls stacking.
|
|
4
|
+
|
|
5
|
+
**Background:** [Josh Comeau — `backdrop-filter`](https://www.joshwcomeau.com/css/backdrop-filter/)
|
|
4
6
|
|
|
5
7
|
## Import
|
|
6
8
|
|
|
@@ -8,12 +10,88 @@
|
|
|
8
10
|
import { FrostedGlass } from "@nqlib/nqui"
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
##
|
|
13
|
+
## Props
|
|
14
|
+
|
|
15
|
+
| Prop | Type | Default | Notes |
|
|
16
|
+
|------|------|---------|--------|
|
|
17
|
+
| `blur` | `number` | `16` | Blur radius in pixels (`backdrop-filter`). |
|
|
18
|
+
| `borderRadius` | `number` | `0` | Pixels. `> 0` enables an SVG corner mask; `0` uses a linear gradient mask (flat header edge). |
|
|
19
|
+
| `className` | `string` | — | Extra classes on the backdrop layer (e.g. z-index). |
|
|
20
|
+
|
|
21
|
+
There is **no `opacity` prop**—tint comes from the sibling bar (see below). The backdrop layer uses a very light `bg-background/3` internally so the blur reads clearly.
|
|
22
|
+
|
|
23
|
+
## Why two layers?
|
|
24
|
+
|
|
25
|
+
`FrostedGlass` renders an **absolute** backdrop layer (`pointer-events-none`, extended height for sampling). Your **toolbar/title row** must be a **sibling** on top with:
|
|
26
|
+
|
|
27
|
+
- `relative z-[var(--z-content)]`
|
|
28
|
+
- A semi-opaque surface, e.g. `bg-background/40` (tint + readability)
|
|
29
|
+
- Optional `border-b`, transitions, flex layout
|
|
30
|
+
|
|
31
|
+
Without that second row, you only get blur with almost no “glass” read and no interactive chrome.
|
|
32
|
+
|
|
33
|
+
## Z-index (elevation)
|
|
34
|
+
|
|
35
|
+
Use variables from `styles/elevation.css` (never raw `z-10` / `z-50`).
|
|
36
|
+
|
|
37
|
+
| Layer | Typical class | Role |
|
|
38
|
+
|-------|----------------|------|
|
|
39
|
+
| Sticky container | `z-[var(--z-sticky-page)]` or `z-[var(--z-sticky-content)]` | Page header vs sticky **inside** a card/panel. |
|
|
40
|
+
| `FrostedGlass` | `className="z-[var(--z-background)]"` | Blur sits **below** the bar content. |
|
|
41
|
+
| Bar / controls | `relative z-[var(--z-content)]` | Text, buttons, borders. |
|
|
42
|
+
|
|
43
|
+
**Rule:** `--z-sticky-content` (15) < `--z-sticky-page` (20). Use `--z-sticky-page` for app chrome; `--z-sticky-content` for a **Card** with `stickyHeader` so page nav stays above card headers.
|
|
44
|
+
|
|
45
|
+
## Scroll requirement
|
|
46
|
+
|
|
47
|
+
`backdrop-filter` blurs **what is painted behind** the element. For a sticky header:
|
|
48
|
+
|
|
49
|
+
1. Put the header and the main content in the **same scroll container** (or ensure content scrolls under the sticky region).
|
|
50
|
+
2. Content must **move behind** the header while scrolling. If nothing scrolls behind the bar, you will see a flat tint with little or no visible blur.
|
|
51
|
+
|
|
52
|
+
Reference: `AppLayout` wraps header + main in `overflow-y-auto` so the main area scrolls under the sticky header.
|
|
53
|
+
|
|
54
|
+
## Page sticky header (canonical)
|
|
55
|
+
|
|
56
|
+
Same structure as `packages/nqui/src/components/AppLayout.tsx`:
|
|
12
57
|
|
|
13
58
|
```tsx
|
|
14
|
-
<
|
|
59
|
+
<div className="flex-1 min-h-0 flex flex-col overflow-y-auto overflow-x-hidden">
|
|
60
|
+
<header className="sticky top-0 z-[var(--z-sticky-page)] flex-shrink-0 relative">
|
|
61
|
+
<FrostedGlass blur={16} borderRadius={0} className="z-[var(--z-background)]" />
|
|
62
|
+
<div className="relative z-[var(--z-content)] border-b bg-background/40 flex h-12 items-center gap-2 px-4">
|
|
63
|
+
{/* title, nav, actions */}
|
|
64
|
+
</div>
|
|
65
|
+
</header>
|
|
66
|
+
<main>{/* scrolls behind header */}</main>
|
|
67
|
+
</div>
|
|
15
68
|
```
|
|
16
69
|
|
|
17
|
-
|
|
70
|
+
- Outer `header`: `sticky` + `relative` + page-level z-index.
|
|
71
|
+
- `FrostedGlass`: `borderRadius={0}` for a straight top edge; increase if the header has rounded corners.
|
|
72
|
+
- Inner bar: `bg-background/40` (adjust opacity to taste).
|
|
73
|
+
|
|
74
|
+
## Card with sticky header
|
|
75
|
+
|
|
76
|
+
**Card** `stickyHeader` wires this pattern for you: `FrostedGlass` with `borderRadius={8}` under **CardHeader**, scrollable **CardContent** below. See `ComponentShowcase` and `packages/nqui/src/components/ui/card.tsx`.
|
|
77
|
+
|
|
78
|
+
Use `--z-sticky-content` on the sticky region when the glass sits inside a card, not the full page.
|
|
79
|
+
|
|
80
|
+
## Troubleshooting
|
|
81
|
+
|
|
82
|
+
| Symptom | Likely cause |
|
|
83
|
+
|---------|----------------|
|
|
84
|
+
| Solid bar, almost no blur | No content scrolling behind the sticky region, or header not in the scrolling ancestor. |
|
|
85
|
+
| Blur but unreadable text | Add / raise `bg-background/40` (or similar) on the **content row**, not only on `FrostedGlass`. |
|
|
86
|
+
| Wrong stacking vs sidebar/modals | Check elevation: floating sidebars use `--z-floating`; modals/popovers sit above—see `elevation.css`. |
|
|
87
|
+
| Rounded header corners | Set `borderRadius` to match; `> 0` switches to the SVG mask path. |
|
|
88
|
+
|
|
89
|
+
## Vite / Tailwind
|
|
90
|
+
|
|
91
|
+
Consumer apps must import nqui styles **and** add Tailwind `@source` for the library (see **INSTALLATION.md** §2c). Missing sources can strip utilities used around the header (`bg-background/40`, z-index arbitrary values, etc.).
|
|
92
|
+
|
|
93
|
+
## Related
|
|
18
94
|
|
|
19
|
-
|
|
95
|
+
- **AppLayout** — full app shell with frosted page header.
|
|
96
|
+
- **Card** `stickyHeader` — frosted sticky card header.
|
|
97
|
+
- **Select** — popover row uses the same backdrop layering pattern.
|
|
@@ -18,13 +18,58 @@ import { RadioGroup, RadioGroupItem } from "@nqlib/nqui"
|
|
|
18
18
|
|
|
19
19
|
## Basic
|
|
20
20
|
|
|
21
|
+
RadioGroupItem now automatically wraps the radio button with a label when children are provided:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
const [value, setValue] = useState("a")
|
|
25
|
+
|
|
26
|
+
<RadioGroup value={value} onValueChange={setValue}>
|
|
27
|
+
<RadioGroupItem value="a">Option A</RadioGroupItem>
|
|
28
|
+
<RadioGroupItem value="b">Option B</RadioGroupItem>
|
|
29
|
+
</RadioGroup>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Do not** pair an empty `RadioGroupItem` with a separate `Label` in the same row: the item’s outer wrapper is meant to include the text (as children) or stand alone without a sibling label. Putting `Label` beside a control-only item can create a wide empty flex region and push the label to the far edge. Prefer the pattern above; if you must use a separate label, use `CoreRadioGroupItem` from `@nqlib/nqui` (see package exports) or ensure the item is not wrapped in a full-width row that fights the layout.
|
|
33
|
+
|
|
34
|
+
## With Complex Content
|
|
35
|
+
|
|
21
36
|
```tsx
|
|
22
37
|
<RadioGroup value={value} onValueChange={setValue}>
|
|
23
|
-
<RadioGroupItem value="
|
|
24
|
-
|
|
38
|
+
<RadioGroupItem value="email">
|
|
39
|
+
<div>
|
|
40
|
+
<div className="font-medium">Email</div>
|
|
41
|
+
<div className="text-sm text-muted-foreground">Receive notifications via email</div>
|
|
42
|
+
</div>
|
|
43
|
+
</RadioGroupItem>
|
|
44
|
+
<RadioGroupItem value="sms">
|
|
45
|
+
<div>
|
|
46
|
+
<div className="font-medium">SMS</div>
|
|
47
|
+
<div className="text-sm text-muted-foreground">Receive notifications via SMS</div>
|
|
48
|
+
</div>
|
|
49
|
+
</RadioGroupItem>
|
|
25
50
|
</RadioGroup>
|
|
26
51
|
```
|
|
27
52
|
|
|
53
|
+
## Spacing
|
|
54
|
+
|
|
55
|
+
Control the gap between radio items with the `gap` prop on RadioGroup:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
<RadioGroup gap={0}>No gap</RadioGroup>
|
|
59
|
+
<RadioGroup gap={1}>4px gap</RadioGroup>
|
|
60
|
+
<RadioGroup gap={2}>Compact (8px)</RadioGroup>
|
|
61
|
+
<RadioGroup gap={3}>Default (12px)</RadioGroup>
|
|
62
|
+
<RadioGroup gap={4}>Loose (16px)</RadioGroup>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Control the gap between radio button and label with the `spacing` prop on RadioGroupItem:
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
<RadioGroupItem value="a" spacing="compact">Tight spacing (8px)</RadioGroupItem>
|
|
69
|
+
<RadioGroupItem value="b" spacing="default">Default spacing (12px)</RadioGroupItem>
|
|
70
|
+
<RadioGroupItem value="c" spacing="comfortable">Loose spacing (16px)</RadioGroupItem>
|
|
71
|
+
```
|
|
72
|
+
|
|
28
73
|
## Variants
|
|
29
74
|
|
|
30
75
|
```tsx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# nqui ScrollArea
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Default export is **EnhancedScrollArea** (fade mask, orientation). Underlying primitive: **`CoreScrollArea`** / `ScrollBar` from **`ui/scroll-area`**. Core scrollbar uses a **thinner** track/thumb (drawer-like).
|
|
4
4
|
|
|
5
5
|
## Import
|
|
6
6
|
|
|
@@ -48,6 +48,6 @@ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SelectGr
|
|
|
48
48
|
|
|
49
49
|
## Notes
|
|
50
50
|
|
|
51
|
-
-
|
|
51
|
+
- **Content:** FrostedGlass + popover surface; **items** use relaxed row spacing (hover `accent`, margins) for dropdown parity with **Combobox** list items.
|
|
52
52
|
- Use `SelectScrollUpButton` / `SelectScrollDownButton` for long lists.
|
|
53
|
-
-
|
|
53
|
+
- **`CoreSelect*`** for the same primitives without the enhanced trigger chrome (re-exported from the same `ui/select` module).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# nqui Sheet
|
|
2
2
|
|
|
3
|
-
> Side panel.
|
|
3
|
+
> Side panel (Radix **Dialog** pattern). **SheetContent** uses an **inset card** panel: transparent outer shell + `before:bg-card` block inset with **rounded corners** (matches drawer-style “card floating in the viewport”). **No edge borders** on the sheet shell (divider lines removed in favor of the card shape).
|
|
4
4
|
|
|
5
5
|
## Import
|
|
6
6
|
|
|
@@ -14,3 +14,16 @@ import { Slider } from "@nqlib/nqui"
|
|
|
14
14
|
<Slider value={[50]} onValueChange={([v]) => setVal(v)} />
|
|
15
15
|
<Slider value={[20, 80]} onValueChange={setRange} />
|
|
16
16
|
```
|
|
17
|
+
|
|
18
|
+
## Sizes
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<Slider size="sm" defaultValue={[40]} />
|
|
22
|
+
<Slider size="default" defaultValue={[40]} />
|
|
23
|
+
<Slider size="lg" defaultValue={[40]} />
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Notes
|
|
27
|
+
|
|
28
|
+
- **Thumb:** white, rounded-full, subtle shadow (aligned with **Switch** thumb language).
|
|
29
|
+
- **`size`:** `sm` | `default` | `lg` (control scale heights).
|