aravint-ui-navigation 1.0.21 → 1.0.24
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/Readme.md +71 -218
- package/dist/navigation.css +1 -1
- package/dist/navigation.es.js +0 -2
- package/dist/types/components/CustomTabs.d.ts +1 -20
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types/tabs.d.ts +21 -0
- package/package.json +1 -1
package/Readme.md
CHANGED
|
@@ -1,249 +1,102 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CustomTabs
|
|
2
2
|
|
|
3
|
-
A reusable,
|
|
3
|
+
A reusable, dependency-free React + TypeScript tabs component with numbered badges, sticky tab bar, and mobile-responsive sizing — while preserving the original desktop/tablet look exactly.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
https://github.com/digitus-git/AFCI_OffAuto/tree/develop_rel_phase1/packages
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
## Features
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
- Controlled or uncontrolled usage (`value`/`onValueChange` or `defaultValue`)
|
|
8
|
+
- Numbered badges per tab (optional)
|
|
9
|
+
- Optional icons per tab
|
|
10
|
+
- Disabled tab support
|
|
11
|
+
- Sticky tab bar (`position: sticky; top: 0`)
|
|
12
|
+
- Active-tab underline-hiding trick (`marginBottom: -1`) to visually merge the active tab with its content panel
|
|
13
|
+
- Responsive breakpoints for tablet (`≤768px`) and phone (`≤480px`) that only affect sizing (padding, font-size, gap, badge size) — colors, borders, and desktop layout are untouched
|
|
14
|
+
- On phones, tabs wrap to a new row instead of overflowing or forcing horizontal scroll
|
|
12
15
|
|
|
13
16
|
## Installation
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
npm install @digitus-fci-oa/button
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
---
|
|
18
|
+
Copy `CustomTabs.tsx` into your project (e.g. `src/components/CustomTabs.tsx`). No extra dependencies — just React.
|
|
20
19
|
|
|
21
|
-
## Usage
|
|
20
|
+
## Basic Usage
|
|
22
21
|
|
|
23
22
|
```tsx
|
|
24
|
-
import {
|
|
25
|
-
import { Save, Trash2, X, Pencil } from 'lucide-react';
|
|
26
|
-
|
|
27
|
-
export function TestButton() {
|
|
28
|
-
return (
|
|
29
|
-
<div style={{ display: "flex", gap: "10px", padding: "20px" }}>
|
|
30
|
-
|
|
31
|
-
<Button variant="save" leftIcon={<Save size={14} />} loading={saveLoading}>
|
|
32
|
-
Save
|
|
33
|
-
</Button>
|
|
34
|
-
|
|
35
|
-
<Button variant="update" rightIcon={<Save size={14} />}>
|
|
36
|
-
Update
|
|
37
|
-
</Button>
|
|
38
|
-
|
|
39
|
-
<Button variant="delete" leftIcon={<Trash2 size={14} />}>
|
|
40
|
-
Delete
|
|
41
|
-
</Button>
|
|
42
|
-
|
|
43
|
-
<Button variant="cancel" leftIcon={<X size={14} />}>
|
|
44
|
-
Cancel
|
|
45
|
-
</Button>
|
|
46
|
-
|
|
47
|
-
{/* Icon-only button with tooltip */}
|
|
48
|
-
<Button
|
|
49
|
-
variant="update"
|
|
50
|
-
size="icon"
|
|
51
|
-
iconButton
|
|
52
|
-
tooltipLabel="Edit record"
|
|
53
|
-
>
|
|
54
|
-
<Pencil size={16} />
|
|
55
|
-
</Button>
|
|
23
|
+
import CustomTabs, { TabItem } from "@digitus-fci-oa/navigation";
|
|
56
24
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const [open, setOpen] = useState(false);
|
|
25
|
+
const tabs: TabItem[] = [
|
|
26
|
+
{ id: "overview", label: "Overview", content: <OverviewPanel /> },
|
|
27
|
+
{ id: "details", label: "Details", content: <DetailsPanel /> },
|
|
28
|
+
{ id: "history", label: "History", content: <HistoryPanel />, disabled: true },
|
|
29
|
+
];
|
|
63
30
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
) => {
|
|
67
|
-
console.log(type);
|
|
68
|
-
};
|
|
31
|
+
function App() {
|
|
32
|
+
const [activeTab, setActiveTab] = useState("overview");
|
|
69
33
|
|
|
70
34
|
return (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
text-xs
|
|
84
|
-
font-medium
|
|
85
|
-
"
|
|
86
|
-
buttonIcon={
|
|
87
|
-
<>
|
|
88
|
-
<Download className="w-4 h-4 text-white" />
|
|
89
|
-
<span className="text-white">Export</span>
|
|
90
|
-
</>
|
|
91
|
-
}
|
|
92
|
-
items={{
|
|
93
|
-
xlsx: {
|
|
94
|
-
label: "XLSX",
|
|
95
|
-
icon: <FileSpreadsheet />,
|
|
96
|
-
iconClassName: "text-green-600",
|
|
97
|
-
textClassName: "text-green-600",
|
|
98
|
-
iconWidth: "w-5",
|
|
99
|
-
iconHeight: "h-5",
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
csv: {
|
|
103
|
-
label: "CSV",
|
|
104
|
-
icon: <FileText />,
|
|
105
|
-
iconClassName: "text-blue-600",
|
|
106
|
-
textClassName: "text-blue-600",
|
|
107
|
-
iconWidth: "w-5",
|
|
108
|
-
iconHeight: "h-5",
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
pdf: {
|
|
112
|
-
label: "PDF",
|
|
113
|
-
icon: <FileText />,
|
|
114
|
-
iconClassName: "text-red-600",
|
|
115
|
-
textClassName: "text-red-600",
|
|
116
|
-
iconWidth: "w-5",
|
|
117
|
-
iconHeight: "h-5",
|
|
118
|
-
},
|
|
119
|
-
}}
|
|
120
|
-
/>
|
|
35
|
+
<div className="h-screen bg-gray-50 flex flex-col">
|
|
36
|
+
<div className="flex-1 min-h-0">
|
|
37
|
+
<CustomTabs
|
|
38
|
+
tabs={tabs}
|
|
39
|
+
value={activeTab}
|
|
40
|
+
onValueChange={setActiveTab}
|
|
41
|
+
showTabNumbers
|
|
42
|
+
className="h-full"
|
|
43
|
+
tabListClassName="bg-white"
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
121
47
|
);
|
|
122
48
|
}
|
|
123
49
|
```
|
|
124
50
|
|
|
125
|
-
---
|
|
126
|
-
---
|
|
127
|
-
|
|
128
51
|
## Props
|
|
129
52
|
|
|
130
|
-
| Prop
|
|
131
|
-
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `style` | `CSSProperties` | `undefined` | Inline styles (merged on top of variant styles) |
|
|
144
|
-
|
|
145
|
-
| `open` | `boolean` | |Controls dropdown visibility |
|
|
146
|
-
| `setOpen` | `Dispatch<SetStateAction<boolean>>` | Updates dropdown state |
|
|
147
|
-
| `onExport` | `(type) => void` | Export callback |
|
|
148
|
-
| `buttonLabel` | `string` | | Button label |
|
|
149
|
-
| `buttonIcon` | `ReactNode` | | Optional button icon |
|
|
150
|
-
| `items` | `Record` | | Export menu items |
|
|
151
|
-
| `className` | `string` | | Additional classes |
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
## Variants
|
|
156
|
-
|
|
157
|
-
| Variant | Color | Description |
|
|
158
|
-
|-----------|------------------|----------------------------------|
|
|
159
|
-
| `default` | Blue (`#3B82F6`) | General-purpose action |
|
|
160
|
-
| `save` | Navy (`#003B71`) | Primary save / create action |
|
|
161
|
-
| `update` | Navy (`#003B71`) | Edit / update action |
|
|
162
|
-
| `delete` | Red (`#FF6070`) | Destructive / remove action |
|
|
163
|
-
| `cancel` | White / bordered | Dismiss / abort action |
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## Sizes
|
|
168
|
-
|
|
169
|
-
| Size | Height | Description |
|
|
170
|
-
|-----------|--------|------------------------------------|
|
|
171
|
-
| `default` | 40px | Standard button |
|
|
172
|
-
| `sm` | 36px | Compact button |
|
|
173
|
-
| `lg` | 44px | Large button |
|
|
174
|
-
| `icon` | 40×40px| Square icon-only button |
|
|
175
|
-
| `xs` | 20px | Extra-small button (e.g. in tables)|
|
|
176
|
-
|
|
177
|
-
---
|
|
178
|
-
|
|
179
|
-
## Icon Support
|
|
180
|
-
|
|
181
|
-
Icons can be placed on the **left** or **right** side of the button label using `leftIcon` and `rightIcon` props. Works with any icon library (e.g. [lucide-react](https://lucide.dev/)).
|
|
53
|
+
| Prop | Type | Default | Description |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `tabs` | `TabItem[]` | — | **Required.** Array of tab definitions. |
|
|
56
|
+
| `defaultValue` | `string` | first tab's `id` | Initial active tab (uncontrolled mode). |
|
|
57
|
+
| `value` | `string` | — | Active tab id (controlled mode). Providing this switches the component to controlled. |
|
|
58
|
+
| `onValueChange` | `(value: string) => void` | — | Called when the user selects a tab. |
|
|
59
|
+
| `className` | `string` | `""` | Class on the outer wrapper. |
|
|
60
|
+
| `tabListClassName` | `string` | `""` | Class on the tab bar container. |
|
|
61
|
+
| `tabButtonClassName` | `string` | `""` | Class on each tab button. |
|
|
62
|
+
| `contentClassName` | `string` | `""` | Class on the content panel. |
|
|
63
|
+
| `showTabNumbers` | `boolean` | `true` | Show/hide the numbered badge on each tab. |
|
|
64
|
+
| `showContent` | `boolean` | `true` | Show/hide the content panel entirely (render tab bar only). |
|
|
65
|
+
| `animated` | `boolean` | `true` | Enables the opacity transition on the content panel. |
|
|
182
66
|
|
|
183
|
-
|
|
184
|
-
import { Pencil } from 'lucide-react';
|
|
185
|
-
|
|
186
|
-
<Button variant="update" leftIcon={<Pencil size={14} />}>
|
|
187
|
-
Edit
|
|
188
|
-
</Button>
|
|
189
|
-
```
|
|
67
|
+
### `TabItem`
|
|
190
68
|
|
|
191
|
-
|
|
69
|
+
| Field | Type | Description |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `id` | `string` | **Required.** Unique tab identifier. |
|
|
72
|
+
| `label` | `string` | **Required.** Tab display text. |
|
|
73
|
+
| `content` | `React.ReactNode` | Content rendered when this tab is active. |
|
|
74
|
+
| `disabled` | `boolean` | Disables selection of this tab. |
|
|
75
|
+
| `icon` | `React.ReactNode` | Optional icon rendered before the label. |
|
|
192
76
|
|
|
193
|
-
##
|
|
77
|
+
## Controlled vs Uncontrolled
|
|
194
78
|
|
|
195
|
-
|
|
79
|
+
- **Uncontrolled:** omit `value`. The component manages its own active tab internally, seeded by `defaultValue` (or the first tab).
|
|
80
|
+
- **Controlled:** pass `value` + `onValueChange`. You own the active-tab state; the component only reports selection events.
|
|
196
81
|
|
|
197
|
-
|
|
198
|
-
const [saving, setSaving] = useState(false);
|
|
199
|
-
|
|
200
|
-
<Button
|
|
201
|
-
variant="save"
|
|
202
|
-
loading={saving}
|
|
203
|
-
onClick={() => setSaving(true)}
|
|
204
|
-
leftIcon={<Save size={14} />}
|
|
205
|
-
>
|
|
206
|
-
Save
|
|
207
|
-
</Button>
|
|
208
|
-
```
|
|
82
|
+
## Styling Approach
|
|
209
83
|
|
|
210
|
-
|
|
84
|
+
Colors, borders, radii, and the sticky/active-tab layout tricks are set as **inline styles** and are the same across all screen sizes — this is what keeps the desktop/tablet appearance unchanged.
|
|
211
85
|
|
|
212
|
-
-
|
|
213
|
-
- CSV
|
|
214
|
-
- PDF
|
|
215
|
-
---
|
|
216
|
-
## Features
|
|
86
|
+
Only size-related properties (`padding`, `font-size`, `gap`, badge `width`/`height`) live in an injected `<style>` block using CSS classes (`.ctabs-list`, `.ctabs-btn`, `.ctabs-badge`, `.ctabs-label`), because inline styles can't respond to `@media` queries. This block ships inside the component, so no external CSS file is required.
|
|
217
87
|
|
|
218
|
-
|
|
219
|
-
- TailwindCSS support
|
|
220
|
-
- Custom icons
|
|
221
|
-
- Controlled open state
|
|
222
|
-
- Lightweight and reusable
|
|
223
|
-
|
|
224
|
-
---
|
|
225
|
-
## Icon Button with Tooltip
|
|
226
|
-
|
|
227
|
-
Set `iconButton={true}` to wrap the button in a tooltip. Pass `tooltipLabel` to set the tooltip text. Pair with `size="icon"` for a square icon-only button.
|
|
228
|
-
|
|
229
|
-
```tsx
|
|
230
|
-
import { Trash2 } from 'lucide-react';
|
|
231
|
-
|
|
232
|
-
<Button
|
|
233
|
-
variant="delete"
|
|
234
|
-
size="icon"
|
|
235
|
-
iconButton
|
|
236
|
-
tooltipLabel="Delete record"
|
|
237
|
-
onClick={handleDelete}
|
|
238
|
-
>
|
|
239
|
-
<Trash2 size={16} />
|
|
240
|
-
</Button>
|
|
241
|
-
```
|
|
88
|
+
### Breakpoints
|
|
242
89
|
|
|
243
|
-
|
|
90
|
+
| Breakpoint | Behavior |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Desktop (default) | Original sizing: `8px 20px` padding, `14px` font, `20px` badges. |
|
|
93
|
+
| Tablet (`≤768px`) | Slightly reduced padding/font/badge size. Tab bar scrolls horizontally if tabs overflow. |
|
|
94
|
+
| Phone (`≤480px`) | Further reduced padding/font/badge size. Tab bar **wraps** to a new row instead of scrolling, so every label stays fully visible. |
|
|
244
95
|
|
|
245
|
-
|
|
96
|
+
To customize breakpoint values, edit the `@media` blocks inside the component's `<style>` tag directly.
|
|
246
97
|
|
|
247
|
-
##
|
|
98
|
+
## Notes / Gotchas
|
|
248
99
|
|
|
249
|
-
|
|
100
|
+
- `marginBottom: -1` on the active tab intentionally overlaps the tab bar's bottom border so the active tab visually "merges" into its content panel. This depends on `alignItems: "flex-end"` on the tab list — don't remove that when customizing.
|
|
101
|
+
- The phone-only `flex-wrap: wrap` sets `overflow-x: visible` to explicitly undo the tablet breakpoint's `overflow-x: auto`, since media query rules don't reset each other automatically.
|
|
102
|
+
- If you have a large number of tabs, consider whether wrapping (phone behavior) or horizontal scroll suits your use case better, and adjust the `480px` block accordingly.
|
package/dist/navigation.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-
|
|
1
|
+
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-outline-style:solid;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-gray-50:oklch(98.5% .002 247.839);--color-white:#fff;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.sticky{position:sticky}.block{display:block}.flex{display:flex}.hidden{display:none}.inline{display:inline}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:0}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.border{border-style:var(--tw-border-style);border-width:1px}.bg-gray-50{background-color:var(--color-gray-50)}.bg-white{background-color:var(--color-white)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-ease{syntax:"*";inherits:false}
|
package/dist/navigation.es.js
CHANGED
|
@@ -26,7 +26,6 @@ const E = ({
|
|
|
26
26
|
top: 0,
|
|
27
27
|
zIndex: 100,
|
|
28
28
|
flexShrink: 0
|
|
29
|
-
// padding + gap now come from .ctabs-list (responsive)
|
|
30
29
|
}, T = {
|
|
31
30
|
display: "flex",
|
|
32
31
|
alignItems: "center",
|
|
@@ -36,7 +35,6 @@ const E = ({
|
|
|
36
35
|
outline: "none",
|
|
37
36
|
transition: "all .2s ease",
|
|
38
37
|
position: "relative"
|
|
39
|
-
// padding + font-size + gap now come from .ctabs-btn (responsive)
|
|
40
38
|
}, k = {
|
|
41
39
|
background: "#E8F7F1",
|
|
42
40
|
color: "#059669",
|
|
@@ -1,23 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
|
|
3
|
-
id: string;
|
|
4
|
-
label: string;
|
|
5
|
-
content?: React.ReactNode;
|
|
6
|
-
disabled?: boolean;
|
|
7
|
-
icon?: React.ReactNode;
|
|
8
|
-
}
|
|
9
|
-
export interface CustomTabsProps {
|
|
10
|
-
tabs: TabItem[];
|
|
11
|
-
defaultValue?: string;
|
|
12
|
-
value?: string;
|
|
13
|
-
onValueChange?: (value: string) => void;
|
|
14
|
-
className?: string;
|
|
15
|
-
tabListClassName?: string;
|
|
16
|
-
tabButtonClassName?: string;
|
|
17
|
-
contentClassName?: string;
|
|
18
|
-
showTabNumbers?: boolean;
|
|
19
|
-
showContent?: boolean;
|
|
20
|
-
animated?: boolean;
|
|
21
|
-
}
|
|
2
|
+
import type { CustomTabsProps } from "../types/tabs";
|
|
22
3
|
declare const CustomTabs: React.FC<CustomTabsProps>;
|
|
23
4
|
export default CustomTabs;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface TabItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
content?: React.ReactNode;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
icon?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export interface CustomTabsProps {
|
|
10
|
+
tabs: TabItem[];
|
|
11
|
+
defaultValue?: string;
|
|
12
|
+
value?: string;
|
|
13
|
+
onValueChange?: (value: string) => void;
|
|
14
|
+
className?: string;
|
|
15
|
+
tabListClassName?: string;
|
|
16
|
+
tabButtonClassName?: string;
|
|
17
|
+
contentClassName?: string;
|
|
18
|
+
showTabNumbers?: boolean;
|
|
19
|
+
showContent?: boolean;
|
|
20
|
+
animated?: boolean;
|
|
21
|
+
}
|