678 lines
22 KiB
Markdown
678 lines
22 KiB
Markdown
# Tabs
|
|
|
|
Tabs component for organizing content into separate panels with tab navigation.
|
|
|
|
## Tag
|
|
|
|
`Tabs`
|
|
|
|
## Props
|
|
|
|
| Prop | Type | Default | Description |
|
|
| :----------- | :-------------------------------------- | :---------- | :----------------------------------------------- |
|
|
| `items` | `Array<TabItem> \| Signal<Array>` | `[]` | Array of tab items |
|
|
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
|
|
|
|
### TabItem Structure
|
|
|
|
| Property | Type | Description |
|
|
| :---------- | :--------------------------- | :----------------------------------------------- |
|
|
| `label` | `string \| VNode` | Tab button label |
|
|
| `content` | `VNode \| function` | Content to display when tab is active |
|
|
| `active` | `boolean \| Signal<boolean>` | Whether this tab is active (only one per group) |
|
|
| `disabled` | `boolean` | Whether tab is disabled |
|
|
| `tip` | `string` | Tooltip text for the tab |
|
|
| `onclick` | `function` | Click handler (optional, overrides default) |
|
|
|
|
## Live Examples
|
|
|
|
### Basic Tabs
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const BasicDemo = () => {
|
|
const activeTab = $('tab1');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Tab 1',
|
|
active: () => activeTab() === 'tab1',
|
|
onclick: () => activeTab('tab1'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 1')
|
|
},
|
|
{
|
|
label: 'Tab 2',
|
|
active: () => activeTab() === 'tab2',
|
|
onclick: () => activeTab('tab2'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 2')
|
|
},
|
|
{
|
|
label: 'Tab 3',
|
|
active: () => activeTab() === 'tab3',
|
|
onclick: () => activeTab('tab3'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 3')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(BasicDemo, '#demo-basic');
|
|
```
|
|
|
|
### With Icons
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-icons" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const IconsDemo = () => {
|
|
const activeTab = $('home');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['🏠', 'Home']),
|
|
active: () => activeTab() === 'home',
|
|
onclick: () => activeTab('home'),
|
|
content: Div({ class: 'p-4' }, 'Welcome to the Home tab!')
|
|
},
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['⭐', 'Favorites']),
|
|
active: () => activeTab() === 'favorites',
|
|
onclick: () => activeTab('favorites'),
|
|
content: Div({ class: 'p-4' }, 'Your favorite items appear here.')
|
|
},
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['⚙️', 'Settings']),
|
|
active: () => activeTab() === 'settings',
|
|
onclick: () => activeTab('settings'),
|
|
content: Div({ class: 'p-4' }, 'Configure your preferences.')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(IconsDemo, '#demo-icons');
|
|
```
|
|
|
|
### With Tooltips
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-tooltips" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const TooltipsDemo = () => {
|
|
const activeTab = $('profile');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Profile',
|
|
tip: 'View your profile information',
|
|
active: () => activeTab() === 'profile',
|
|
onclick: () => activeTab('profile'),
|
|
content: Div({ class: 'p-4' }, 'Profile information here.')
|
|
},
|
|
{
|
|
label: 'Settings',
|
|
tip: 'Adjust your preferences',
|
|
active: () => activeTab() === 'settings',
|
|
onclick: () => activeTab('settings'),
|
|
content: Div({ class: 'p-4' }, 'Settings configuration.')
|
|
},
|
|
{
|
|
label: 'Notifications',
|
|
tip: 'Manage notifications',
|
|
active: () => activeTab() === 'notifications',
|
|
onclick: () => activeTab('notifications'),
|
|
content: Div({ class: 'p-4' }, 'Notification settings.')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(TooltipsDemo, '#demo-tooltips');
|
|
```
|
|
|
|
### Disabled Tab
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-disabled" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const DisabledDemo = () => {
|
|
const activeTab = $('basic');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Basic',
|
|
active: () => activeTab() === 'basic',
|
|
onclick: () => activeTab('basic'),
|
|
content: Div({ class: 'p-4' }, 'Basic features available.')
|
|
},
|
|
{
|
|
label: 'Premium',
|
|
disabled: true,
|
|
tip: 'Upgrade to access',
|
|
content: Div({ class: 'p-4' }, 'Premium content (locked)')
|
|
},
|
|
{
|
|
label: 'Pro',
|
|
disabled: true,
|
|
tip: 'Coming soon',
|
|
content: Div({ class: 'p-4' }, 'Pro features (coming soon)')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(DisabledDemo, '#demo-disabled');
|
|
```
|
|
|
|
### Reactive Content
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-reactive" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const ReactiveDemo = () => {
|
|
const activeTab = $('counter');
|
|
const count = $(0);
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Counter',
|
|
active: () => activeTab() === 'counter',
|
|
onclick: () => activeTab('counter'),
|
|
content: Div({ class: 'p-4 text-center' }, [
|
|
Div({ class: 'text-4xl font-bold mb-4' }, () => count()),
|
|
Button({
|
|
class: 'btn btn-primary',
|
|
onclick: () => count(count() + 1)
|
|
}, 'Increment')
|
|
])
|
|
},
|
|
{
|
|
label: 'Timer',
|
|
active: () => activeTab() === 'timer',
|
|
onclick: () => activeTab('timer'),
|
|
content: Div({ class: 'p-4' }, () => `Current time: ${new Date().toLocaleTimeString()}`)
|
|
},
|
|
{
|
|
label: 'Status',
|
|
active: () => activeTab() === 'status',
|
|
onclick: () => activeTab('status'),
|
|
content: Div({ class: 'p-4' }, () => `Counter value: ${count()}, Last updated: ${new Date().toLocaleTimeString()}`)
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(ReactiveDemo, '#demo-reactive');
|
|
```
|
|
|
|
### Form Tabs
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-form" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const FormTabs = () => {
|
|
const activeTab = $('personal');
|
|
const formData = $({
|
|
name: '',
|
|
email: '',
|
|
address: '',
|
|
city: '',
|
|
notifications: true,
|
|
newsletter: false
|
|
});
|
|
|
|
const updateField = (field, value) => {
|
|
formData({ ...formData(), [field]: value });
|
|
};
|
|
|
|
const handleSubmit = () => {
|
|
Toast('Form submitted!', 'alert-success', 2000);
|
|
console.log(formData());
|
|
};
|
|
|
|
return Div({ class: 'flex flex-col gap-4' }, [
|
|
Tabs({
|
|
items: [
|
|
{
|
|
label: 'Personal Info',
|
|
active: () => activeTab() === 'personal',
|
|
onclick: () => activeTab('personal'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Input({
|
|
label: 'Name',
|
|
value: () => formData().name,
|
|
placeholder: 'Enter your name',
|
|
oninput: (e) => updateField('name', e.target.value)
|
|
}),
|
|
Input({
|
|
label: 'Email',
|
|
type: 'email',
|
|
value: () => formData().email,
|
|
placeholder: 'email@example.com',
|
|
oninput: (e) => updateField('email', e.target.value)
|
|
})
|
|
])
|
|
},
|
|
{
|
|
label: 'Address',
|
|
active: () => activeTab() === 'address',
|
|
onclick: () => activeTab('address'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Input({
|
|
label: 'Address',
|
|
value: () => formData().address,
|
|
placeholder: 'Street address',
|
|
oninput: (e) => updateField('address', e.target.value)
|
|
}),
|
|
Input({
|
|
label: 'City',
|
|
value: () => formData().city,
|
|
placeholder: 'City',
|
|
oninput: (e) => updateField('city', e.target.value)
|
|
})
|
|
])
|
|
},
|
|
{
|
|
label: 'Preferences',
|
|
active: () => activeTab() === 'prefs',
|
|
onclick: () => activeTab('prefs'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Checkbox({
|
|
label: 'Email notifications',
|
|
value: () => formData().notifications,
|
|
onclick: () => updateField('notifications', !formData().notifications)
|
|
}),
|
|
Checkbox({
|
|
label: 'Newsletter subscription',
|
|
value: () => formData().newsletter,
|
|
onclick: () => updateField('newsletter', !formData().newsletter)
|
|
})
|
|
])
|
|
}
|
|
]
|
|
}),
|
|
Div({ class: 'flex justify-end mt-4' }, [
|
|
Button({
|
|
class: 'btn btn-primary',
|
|
onclick: handleSubmit
|
|
}, 'Submit')
|
|
])
|
|
]);
|
|
};
|
|
$mount(FormTabs, '#demo-form');
|
|
```
|
|
|
|
### All Variants
|
|
|
|
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
|
<div class="card-body">
|
|
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
|
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-6"></div>
|
|
</div>
|
|
</div>
|
|
|
|
```javascript
|
|
const VariantsDemo = () => {
|
|
const items = [
|
|
{ label: 'Tab 1', content: 'Content 1' },
|
|
{ label: 'Tab 2', content: 'Content 2' },
|
|
{ label: 'Tab 3', content: 'Content 3' }
|
|
].map((tab, idx) => ({
|
|
...tab,
|
|
active: () => idx === 0,
|
|
content: Div({ class: 'p-4' }, tab.content)
|
|
}));
|
|
|
|
return Div({ class: 'flex flex-col gap-6' }, [
|
|
Div({ class: 'text-sm font-bold' }, 'Default Tabs'),
|
|
Tabs({ items }),
|
|
|
|
Div({ class: 'text-sm font-bold mt-4' }, 'Boxed Tabs'),
|
|
Tabs({ items, class: 'tabs-box' }),
|
|
|
|
Div({ class: 'text-sm font-bold mt-4' }, 'Lifted Tabs'),
|
|
Tabs({ items, class: 'tabs-lifted' })
|
|
]);
|
|
};
|
|
$mount(VariantsDemo, '#demo-variants');
|
|
```
|
|
|
|
<script>
|
|
(function() {
|
|
const initTabsExamples = () => {
|
|
|
|
// 1. Basic Tabs
|
|
const basicTarget = document.querySelector('#demo-basic');
|
|
if (basicTarget && !basicTarget.hasChildNodes()) {
|
|
const BasicDemo = () => {
|
|
const activeTab = $('tab1');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Tab 1',
|
|
active: () => activeTab() === 'tab1',
|
|
onclick: () => activeTab('tab1'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 1')
|
|
},
|
|
{
|
|
label: 'Tab 2',
|
|
active: () => activeTab() === 'tab2',
|
|
onclick: () => activeTab('tab2'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 2')
|
|
},
|
|
{
|
|
label: 'Tab 3',
|
|
active: () => activeTab() === 'tab3',
|
|
onclick: () => activeTab('tab3'),
|
|
content: Div({ class: 'p-4' }, 'Content for Tab 3')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(BasicDemo, basicTarget);
|
|
}
|
|
|
|
// 2. With Icons
|
|
const iconsTarget = document.querySelector('#demo-icons');
|
|
if (iconsTarget && !iconsTarget.hasChildNodes()) {
|
|
const IconsDemo = () => {
|
|
const activeTab = $('home');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['🏠', 'Home']),
|
|
active: () => activeTab() === 'home',
|
|
onclick: () => activeTab('home'),
|
|
content: Div({ class: 'p-4' }, 'Welcome to the Home tab!')
|
|
},
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['⭐', 'Favorites']),
|
|
active: () => activeTab() === 'favorites',
|
|
onclick: () => activeTab('favorites'),
|
|
content: Div({ class: 'p-4' }, 'Your favorite items appear here.')
|
|
},
|
|
{
|
|
label: Span({ class: 'flex items-center gap-2' }, ['⚙️', 'Settings']),
|
|
active: () => activeTab() === 'settings',
|
|
onclick: () => activeTab('settings'),
|
|
content: Div({ class: 'p-4' }, 'Configure your preferences.')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(IconsDemo, iconsTarget);
|
|
}
|
|
|
|
// 3. With Tooltips
|
|
const tooltipsTarget = document.querySelector('#demo-tooltips');
|
|
if (tooltipsTarget && !tooltipsTarget.hasChildNodes()) {
|
|
const TooltipsDemo = () => {
|
|
const activeTab = $('profile');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Profile',
|
|
tip: 'View your profile information',
|
|
active: () => activeTab() === 'profile',
|
|
onclick: () => activeTab('profile'),
|
|
content: Div({ class: 'p-4' }, 'Profile information here.')
|
|
},
|
|
{
|
|
label: 'Settings',
|
|
tip: 'Adjust your preferences',
|
|
active: () => activeTab() === 'settings',
|
|
onclick: () => activeTab('settings'),
|
|
content: Div({ class: 'p-4' }, 'Settings configuration.')
|
|
},
|
|
{
|
|
label: 'Notifications',
|
|
tip: 'Manage notifications',
|
|
active: () => activeTab() === 'notifications',
|
|
onclick: () => activeTab('notifications'),
|
|
content: Div({ class: 'p-4' }, 'Notification settings.')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(TooltipsDemo, tooltipsTarget);
|
|
}
|
|
|
|
// 4. Disabled Tab
|
|
const disabledTarget = document.querySelector('#demo-disabled');
|
|
if (disabledTarget && !disabledTarget.hasChildNodes()) {
|
|
const DisabledDemo = () => {
|
|
const activeTab = $('basic');
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Basic',
|
|
active: () => activeTab() === 'basic',
|
|
onclick: () => activeTab('basic'),
|
|
content: Div({ class: 'p-4' }, 'Basic features available.')
|
|
},
|
|
{
|
|
label: 'Premium',
|
|
disabled: true,
|
|
tip: 'Upgrade to access',
|
|
content: Div({ class: 'p-4' }, 'Premium content (locked)')
|
|
},
|
|
{
|
|
label: 'Pro',
|
|
disabled: true,
|
|
tip: 'Coming soon',
|
|
content: Div({ class: 'p-4' }, 'Pro features (coming soon)')
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(DisabledDemo, disabledTarget);
|
|
}
|
|
|
|
// 5. Reactive Content
|
|
const reactiveTarget = document.querySelector('#demo-reactive');
|
|
if (reactiveTarget && !reactiveTarget.hasChildNodes()) {
|
|
const ReactiveDemo = () => {
|
|
const activeTab = $('counter');
|
|
const count = $(0);
|
|
|
|
return Tabs({
|
|
items: [
|
|
{
|
|
label: 'Counter',
|
|
active: () => activeTab() === 'counter',
|
|
onclick: () => activeTab('counter'),
|
|
content: Div({ class: 'p-4 text-center' }, [
|
|
Div({ class: 'text-4xl font-bold mb-4' }, () => count()),
|
|
Button({
|
|
class: 'btn btn-primary',
|
|
onclick: () => count(count() + 1)
|
|
}, 'Increment')
|
|
])
|
|
},
|
|
{
|
|
label: 'Timer',
|
|
active: () => activeTab() === 'timer',
|
|
onclick: () => activeTab('timer'),
|
|
content: Div({ class: 'p-4' }, () => `Current time: ${new Date().toLocaleTimeString()}`)
|
|
},
|
|
{
|
|
label: 'Status',
|
|
active: () => activeTab() === 'status',
|
|
onclick: () => activeTab('status'),
|
|
content: Div({ class: 'p-4' }, () => `Counter value: ${count()}, Last updated: ${new Date().toLocaleTimeString()}`)
|
|
}
|
|
]
|
|
});
|
|
};
|
|
$mount(ReactiveDemo, reactiveTarget);
|
|
}
|
|
|
|
// 6. Form Tabs
|
|
const formTarget = document.querySelector('#demo-form');
|
|
if (formTarget && !formTarget.hasChildNodes()) {
|
|
const FormTabs = () => {
|
|
const activeTab = $('personal');
|
|
const formData = $({
|
|
name: '',
|
|
email: '',
|
|
address: '',
|
|
city: '',
|
|
notifications: true,
|
|
newsletter: false
|
|
});
|
|
|
|
const updateField = (field, value) => {
|
|
formData({ ...formData(), [field]: value });
|
|
};
|
|
|
|
const handleSubmit = () => {
|
|
Toast('Form submitted!', 'alert-success', 2000);
|
|
console.log(formData());
|
|
};
|
|
|
|
return Div({ class: 'flex flex-col gap-4' }, [
|
|
Tabs({
|
|
items: [
|
|
{
|
|
label: 'Personal Info',
|
|
active: () => activeTab() === 'personal',
|
|
onclick: () => activeTab('personal'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Input({
|
|
label: 'Name',
|
|
value: () => formData().name,
|
|
placeholder: 'Enter your name',
|
|
oninput: (e) => updateField('name', e.target.value)
|
|
}),
|
|
Input({
|
|
label: 'Email',
|
|
type: 'email',
|
|
value: () => formData().email,
|
|
placeholder: 'email@example.com',
|
|
oninput: (e) => updateField('email', e.target.value)
|
|
})
|
|
])
|
|
},
|
|
{
|
|
label: 'Address',
|
|
active: () => activeTab() === 'address',
|
|
onclick: () => activeTab('address'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Input({
|
|
label: 'Address',
|
|
value: () => formData().address,
|
|
placeholder: 'Street address',
|
|
oninput: (e) => updateField('address', e.target.value)
|
|
}),
|
|
Input({
|
|
label: 'City',
|
|
value: () => formData().city,
|
|
placeholder: 'City',
|
|
oninput: (e) => updateField('city', e.target.value)
|
|
})
|
|
])
|
|
},
|
|
{
|
|
label: 'Preferences',
|
|
active: () => activeTab() === 'prefs',
|
|
onclick: () => activeTab('prefs'),
|
|
content: Div({ class: 'p-4 space-y-4' }, [
|
|
Checkbox({
|
|
label: 'Email notifications',
|
|
value: () => formData().notifications,
|
|
onclick: () => updateField('notifications', !formData().notifications)
|
|
}),
|
|
Checkbox({
|
|
label: 'Newsletter subscription',
|
|
value: () => formData().newsletter,
|
|
onclick: () => updateField('newsletter', !formData().newsletter)
|
|
})
|
|
])
|
|
}
|
|
]
|
|
}),
|
|
Div({ class: 'flex justify-end mt-4' }, [
|
|
Button({
|
|
class: 'btn btn-primary',
|
|
onclick: handleSubmit
|
|
}, 'Submit')
|
|
])
|
|
]);
|
|
};
|
|
$mount(FormTabs, formTarget);
|
|
}
|
|
|
|
// 7. All Variants
|
|
const variantsTarget = document.querySelector('#demo-variants');
|
|
if (variantsTarget && !variantsTarget.hasChildNodes()) {
|
|
const VariantsDemo = () => {
|
|
const items = [
|
|
{ label: 'Tab 1', content: 'Content 1' },
|
|
{ label: 'Tab 2', content: 'Content 2' },
|
|
{ label: 'Tab 3', content: 'Content 3' }
|
|
].map((tab, idx) => ({
|
|
...tab,
|
|
active: () => idx === 0,
|
|
content: Div({ class: 'p-4' }, tab.content)
|
|
}));
|
|
|
|
return Div({ class: 'flex flex-col gap-6' }, [
|
|
Div({ class: 'text-sm font-bold' }, 'Default Tabs'),
|
|
Tabs({ items }),
|
|
|
|
Div({ class: 'text-sm font-bold mt-4' }, 'Boxed Tabs'),
|
|
Tabs({ items, class: 'tabs-box' }),
|
|
|
|
Div({ class: 'text-sm font-bold mt-4' }, 'Lifted Tabs'),
|
|
Tabs({ items, class: 'tabs-lifted' })
|
|
]);
|
|
};
|
|
$mount(VariantsDemo, variantsTarget);
|
|
}
|
|
};
|
|
|
|
initTabsExamples();
|
|
|
|
if (window.$docsify) {
|
|
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
|
|
hook.doneEach(initTabsExamples);
|
|
});
|
|
}
|
|
})();
|
|
</script>
|