drab 2.7.0 → 2.8.0
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/dist/components/Accordion.svelte +3 -3
- package/dist/components/Accordion.svelte.d.ts +1 -1
- package/dist/components/DataTable.svelte +27 -12
- package/dist/components/DataTable.svelte.d.ts +3 -0
- package/dist/components/Popover.svelte +2 -2
- package/dist/components/ShareButton.svelte +72 -22
- package/dist/components/ShareButton.svelte.d.ts +44 -13
- package/dist/components/Sheet.svelte +5 -28
- package/dist/components/Sheet.svelte.d.ts +3 -3
- package/dist/components/Tabs.svelte +14 -16
- package/dist/components/Tabs.svelte.d.ts +8 -8
- package/package.json +1 -1
@@ -52,7 +52,7 @@ Displays a list of `details` elements with helpful defaults and transitions.
|
|
52
52
|
summary: "Is it animated?",
|
53
53
|
content: "Yes, with the transition prop.",
|
54
54
|
},
|
55
|
-
{ summary: "Does it work without
|
55
|
+
{ summary: "Does it work without JavaScript?", content: "Yes." },
|
56
56
|
]}
|
57
57
|
/>
|
58
58
|
|
@@ -112,9 +112,8 @@ const toggleOpen = (i) => {
|
|
112
112
|
items[i].open = !items[i].open;
|
113
113
|
if (autoClose) {
|
114
114
|
for (let j = 0; j < items.length; j++) {
|
115
|
-
const item = items[j];
|
116
115
|
if (j !== i)
|
117
|
-
|
116
|
+
items[j].open = false;
|
118
117
|
}
|
119
118
|
}
|
120
119
|
};
|
@@ -169,6 +168,7 @@ onMount(() => {
|
|
169
168
|
{/if}
|
170
169
|
</details>
|
171
170
|
{#if clientJs && item.open && transition}
|
171
|
+
<!-- outside the details for the transition -->
|
172
172
|
<div class={classContent} transition:slide={transition}>
|
173
173
|
<slot name="content" {item} {index}>{item.content}</slot>
|
174
174
|
</div>
|
@@ -98,7 +98,7 @@ export type AccordionSlots = typeof __propDef.slots;
|
|
98
98
|
* summary: "Is it animated?",
|
99
99
|
* content: "Yes, with the transition prop.",
|
100
100
|
* },
|
101
|
-
* { summary: "Does it work without
|
101
|
+
* { summary: "Does it work without JavaScript?", content: "Yes." },
|
102
102
|
* ]}
|
103
103
|
* />
|
104
104
|
*
|
@@ -30,6 +30,7 @@ Data table to display an array of JS objects. Click a column header to sort.
|
|
30
30
|
- `id`
|
31
31
|
- `maxRows` - maximum number of rows to show on each page, defaults to `0` - no pagination
|
32
32
|
- `sortBy` - column to sort by, defaults to first column
|
33
|
+
- `transition` - fades the rows in, set to `false` to disable
|
33
34
|
|
34
35
|
@slots
|
35
36
|
|
@@ -109,8 +110,11 @@ Data table to display an array of JS objects. Click a column header to sort.
|
|
109
110
|
|
110
111
|
<script context="module"></script>
|
111
112
|
|
112
|
-
<script>import {
|
113
|
-
import {
|
113
|
+
<script>import { onMount } from "svelte";
|
114
|
+
import { fade } from "svelte/transition";
|
115
|
+
import { duration } from "../util/transition";
|
116
|
+
import { prefersReducedMotion } from "../util/accessibility";
|
117
|
+
import { messageNoScript } from "../util/messages";
|
114
118
|
let className = "";
|
115
119
|
export { className as class };
|
116
120
|
export let id = "";
|
@@ -137,6 +141,7 @@ export let classPageNumber = "";
|
|
137
141
|
export let classPageControls = "";
|
138
142
|
export let maxRows = 0;
|
139
143
|
export let currentPage = 1;
|
144
|
+
export let transition = { duration };
|
140
145
|
export let classNoscript = "";
|
141
146
|
let clientJs = false;
|
142
147
|
$:
|
@@ -175,8 +180,21 @@ const sort = (column, toggleAscending = true) => {
|
|
175
180
|
data = data;
|
176
181
|
sortBy = column;
|
177
182
|
};
|
183
|
+
const showRow = (i, currentPage2) => {
|
184
|
+
if (!maxRows)
|
185
|
+
return true;
|
186
|
+
const overMin = i >= maxRows * (currentPage2 - 1);
|
187
|
+
const underMax = i < maxRows * currentPage2;
|
188
|
+
return overMin && underMax;
|
189
|
+
};
|
178
190
|
sort(sortBy, false);
|
179
|
-
onMount(() =>
|
191
|
+
onMount(() => {
|
192
|
+
if (prefersReducedMotion()) {
|
193
|
+
if (transition)
|
194
|
+
transition.duration = 0;
|
195
|
+
}
|
196
|
+
clientJs = true;
|
197
|
+
});
|
180
198
|
</script>
|
181
199
|
|
182
200
|
<div class={className} {id}>
|
@@ -195,10 +213,11 @@ onMount(() => clientJs = true);
|
|
195
213
|
</thead>
|
196
214
|
<tbody class={classTbody}>
|
197
215
|
{#each data as row, i}
|
198
|
-
{
|
199
|
-
|
200
|
-
|
201
|
-
|
216
|
+
{#if showRow(i, currentPage)}
|
217
|
+
<tr
|
218
|
+
in:fade={transition ? transition : { duration: 0 }}
|
219
|
+
class={classTbodyTr}
|
220
|
+
>
|
202
221
|
{#each columns as column}
|
203
222
|
<td class="{classTd} {sortBy === column ? classTdSorted : ''}">
|
204
223
|
<slot name="td" {row} {column}>{row[column]}</slot>
|
@@ -237,10 +256,6 @@ onMount(() => clientJs = true);
|
|
237
256
|
</div>
|
238
257
|
</div>
|
239
258
|
|
240
|
-
<noscript>
|
241
|
-
<div class={classNoscript}>
|
242
|
-
{messageNoScript}
|
243
|
-
</div>
|
244
|
-
</noscript>
|
259
|
+
<noscript><div class={classNoscript}>{messageNoScript}</div></noscript>
|
245
260
|
{/if}
|
246
261
|
</div>
|
@@ -2,6 +2,7 @@ import { SvelteComponent } from "svelte";
|
|
2
2
|
export type DataTableRow<T> = {
|
3
3
|
[K in keyof T]: T[K];
|
4
4
|
};
|
5
|
+
import { type FadeParams } from "svelte/transition";
|
5
6
|
declare const __propDef: {
|
6
7
|
props: {
|
7
8
|
class?: string | undefined;
|
@@ -26,6 +27,7 @@ declare const __propDef: {
|
|
26
27
|
/** class of `div` that wraps the "Previous" and "Next" buttons */ classPageControls?: string | undefined;
|
27
28
|
/** maximum number of rows to show on each page, defaults to `0` - no pagination */ maxRows?: number | undefined;
|
28
29
|
/** current page, defaults to `1` */ currentPage?: number | undefined;
|
30
|
+
/** fades the rows in, set to `false` to disable */ transition?: false | FadeParams | undefined;
|
29
31
|
/** `noscript` class */ classNoscript?: string | undefined;
|
30
32
|
};
|
31
33
|
events: {
|
@@ -84,6 +86,7 @@ export type DataTableSlots = typeof __propDef.slots;
|
|
84
86
|
* - `id`
|
85
87
|
* - `maxRows` - maximum number of rows to show on each page, defaults to `0` - no pagination
|
86
88
|
* - `sortBy` - column to sort by, defaults to first column
|
89
|
+
* - `transition` - fades the rows in, set to `false` to disable
|
87
90
|
*
|
88
91
|
* @slots
|
89
92
|
*
|
@@ -83,8 +83,8 @@ const setPosition = async () => {
|
|
83
83
|
}
|
84
84
|
}
|
85
85
|
const targetRect = target.getBoundingClientRect();
|
86
|
-
coordinates.x += targetRect.x;
|
87
|
-
coordinates.y += targetRect.y;
|
86
|
+
coordinates.x += targetRect.x + window.scrollX;
|
87
|
+
coordinates.y += targetRect.y + window.scrollY;
|
88
88
|
await tick();
|
89
89
|
const popoverRect = popover.getBoundingClientRect();
|
90
90
|
if (popoverRect.x < 0) {
|
@@ -3,16 +3,22 @@
|
|
3
3
|
|
4
4
|
### ShareButton
|
5
5
|
|
6
|
-
Uses the [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
6
|
+
Uses the [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) to share data. Progressively enhances according to browser support.
|
7
|
+
|
8
|
+
- If the browser cannot share the provided data:
|
9
|
+
- `url` - uses the the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to copy
|
10
|
+
- `files` - uses a hidden `anchor` element to download the first file in the `files` array
|
11
|
+
- If no JavaScript:
|
12
|
+
- `button` is disabled
|
13
|
+
- `url` - displayed after the button
|
7
14
|
|
8
15
|
@props
|
9
16
|
|
10
17
|
- `classNoscript` - `noscript` class
|
11
18
|
- `class`
|
12
19
|
- `id`
|
13
|
-
- `
|
14
|
-
- `title`
|
15
|
-
- `url` - url to be shared
|
20
|
+
- `shareData` - [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
21
|
+
- `title`
|
16
22
|
|
17
23
|
@slots
|
18
24
|
|
@@ -24,43 +30,81 @@ Uses the [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Naviga
|
|
24
30
|
@example
|
25
31
|
|
26
32
|
```svelte
|
27
|
-
<script>
|
33
|
+
<script lang="ts">
|
28
34
|
import { ShareButton } from "drab";
|
35
|
+
|
36
|
+
let fileInput: HTMLInputElement;
|
37
|
+
|
38
|
+
let fileShareData: ShareData;
|
39
|
+
|
40
|
+
const onInput = () => {
|
41
|
+
if (fileInput.files) {
|
42
|
+
fileShareData.files = [fileInput.files[0]];
|
43
|
+
}
|
44
|
+
};
|
29
45
|
</script>
|
30
46
|
|
47
|
+
<ShareButton
|
48
|
+
class="btn mb-8"
|
49
|
+
shareData={{
|
50
|
+
text: "Check out this page: ",
|
51
|
+
title: "drab",
|
52
|
+
url: "https://drab.robino.dev",
|
53
|
+
}}
|
54
|
+
>
|
55
|
+
Share URL
|
56
|
+
</ShareButton>
|
57
|
+
|
31
58
|
<div>
|
32
|
-
<
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
59
|
+
<label class="label" for="fileInput">Upload File</label>
|
60
|
+
<input
|
61
|
+
type="file"
|
62
|
+
id="fileInput"
|
63
|
+
class="input mb-4"
|
64
|
+
bind:this={fileInput}
|
65
|
+
on:input={onInput}
|
37
66
|
/>
|
67
|
+
<ShareButton class="btn" bind:shareData={fileShareData}>
|
68
|
+
Share File
|
69
|
+
</ShareButton>
|
38
70
|
</div>
|
39
71
|
```
|
40
72
|
-->
|
41
73
|
|
42
74
|
<script>import { onMount } from "svelte";
|
43
75
|
import { delay } from "../util/delay";
|
76
|
+
import { messageNoScript } from "../util/messages";
|
44
77
|
let className = "";
|
45
78
|
export { className as class };
|
46
79
|
export let id = "";
|
47
|
-
export let
|
48
|
-
export let
|
49
|
-
|
80
|
+
export let title = "";
|
81
|
+
export let shareData = {};
|
82
|
+
let downloadAnchor;
|
50
83
|
export let classNoscript = "";
|
51
84
|
let clientJs = false;
|
52
85
|
let complete = false;
|
53
86
|
const onClick = async () => {
|
54
|
-
|
55
|
-
|
56
|
-
await navigator.share(
|
57
|
-
}
|
58
|
-
|
87
|
+
if (navigator.canShare && navigator.canShare(shareData)) {
|
88
|
+
try {
|
89
|
+
await navigator.share(shareData);
|
90
|
+
} catch (error) {
|
91
|
+
if (error.name !== "AbortError") {
|
92
|
+
console.error(error);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
} else if (shareData.url) {
|
96
|
+
try {
|
97
|
+
await navigator.clipboard.writeText(shareData.url);
|
59
98
|
complete = true;
|
60
99
|
setTimeout(() => complete = false, delay);
|
100
|
+
} catch (error) {
|
101
|
+
console.error(error);
|
61
102
|
}
|
62
|
-
}
|
63
|
-
|
103
|
+
} else if (shareData.files) {
|
104
|
+
const file = shareData.files[0];
|
105
|
+
downloadAnchor.download = file.name;
|
106
|
+
downloadAnchor.href = URL.createObjectURL(file);
|
107
|
+
downloadAnchor.click();
|
64
108
|
}
|
65
109
|
};
|
66
110
|
onMount(() => clientJs = true);
|
@@ -68,7 +112,7 @@ onMount(() => clientJs = true);
|
|
68
112
|
|
69
113
|
<button
|
70
114
|
type="button"
|
71
|
-
disabled={!clientJs}
|
115
|
+
disabled={!clientJs || (!shareData.url && !shareData.files)}
|
72
116
|
on:click={onClick}
|
73
117
|
class={className}
|
74
118
|
{id}
|
@@ -81,4 +125,10 @@ onMount(() => clientJs = true);
|
|
81
125
|
{/if}
|
82
126
|
</button>
|
83
127
|
|
84
|
-
<
|
128
|
+
<a href="/" bind:this={downloadAnchor} style:display="none">Download</a>
|
129
|
+
|
130
|
+
<noscript>
|
131
|
+
<span class={classNoscript}>
|
132
|
+
{shareData.url ? shareData.url : messageNoScript}
|
133
|
+
</span>
|
134
|
+
</noscript>
|
@@ -3,9 +3,8 @@ declare const __propDef: {
|
|
3
3
|
props: {
|
4
4
|
class?: string | undefined;
|
5
5
|
id?: string | undefined;
|
6
|
-
|
7
|
-
/**
|
8
|
-
/** title of share message and `button` attribute, defaults to end of url */ title?: string | undefined;
|
6
|
+
title?: string | undefined;
|
7
|
+
/** [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) */ shareData?: ShareData | undefined;
|
9
8
|
/** `noscript` class */ classNoscript?: string | undefined;
|
10
9
|
};
|
11
10
|
events: {
|
@@ -22,16 +21,22 @@ export type ShareButtonSlots = typeof __propDef.slots;
|
|
22
21
|
/**
|
23
22
|
* ### ShareButton
|
24
23
|
*
|
25
|
-
* Uses the [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
24
|
+
* Uses the [Navigator API](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) to share data. Progressively enhances according to browser support.
|
25
|
+
*
|
26
|
+
* - If the browser cannot share the provided data:
|
27
|
+
* - `url` - uses the the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to copy
|
28
|
+
* - `files` - uses a hidden `anchor` element to download the first file in the `files` array
|
29
|
+
* - If no JavaScript:
|
30
|
+
* - `button` is disabled
|
31
|
+
* - `url` - displayed after the button
|
26
32
|
*
|
27
33
|
* @props
|
28
34
|
*
|
29
35
|
* - `classNoscript` - `noscript` class
|
30
36
|
* - `class`
|
31
37
|
* - `id`
|
32
|
-
* - `
|
33
|
-
* - `title`
|
34
|
-
* - `url` - url to be shared
|
38
|
+
* - `shareData` - [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
|
39
|
+
* - `title`
|
35
40
|
*
|
36
41
|
* @slots
|
37
42
|
*
|
@@ -43,17 +48,43 @@ export type ShareButtonSlots = typeof __propDef.slots;
|
|
43
48
|
* @example
|
44
49
|
*
|
45
50
|
* ```svelte
|
46
|
-
* <script>
|
51
|
+
* <script lang="ts">
|
47
52
|
* import { ShareButton } from "drab";
|
53
|
+
*
|
54
|
+
* let fileInput: HTMLInputElement;
|
55
|
+
*
|
56
|
+
* let fileShareData: ShareData;
|
57
|
+
*
|
58
|
+
* const onInput = () => {
|
59
|
+
* if (fileInput.files) {
|
60
|
+
* fileShareData.files = [fileInput.files[0]];
|
61
|
+
* }
|
62
|
+
* };
|
48
63
|
* </script>
|
49
64
|
*
|
50
|
-
* <div>
|
51
65
|
* <ShareButton
|
52
|
-
*
|
53
|
-
*
|
54
|
-
*
|
55
|
-
*
|
66
|
+
* class="btn mb-8"
|
67
|
+
* shareData={{
|
68
|
+
* text: "Check out this page: ",
|
69
|
+
* title: "drab",
|
70
|
+
* url: "https://drab.robino.dev",
|
71
|
+
* }}
|
72
|
+
* >
|
73
|
+
* Share URL
|
74
|
+
* </ShareButton>
|
75
|
+
*
|
76
|
+
* <div>
|
77
|
+
* <label class="label" for="fileInput">Upload File</label>
|
78
|
+
* <input
|
79
|
+
* type="file"
|
80
|
+
* id="fileInput"
|
81
|
+
* class="input mb-4"
|
82
|
+
* bind:this={fileInput}
|
83
|
+
* on:input={onInput}
|
56
84
|
* />
|
85
|
+
* <ShareButton class="btn" bind:shareData={fileShareData}>
|
86
|
+
* Share File
|
87
|
+
* </ShareButton>
|
57
88
|
* </div>
|
58
89
|
* ```
|
59
90
|
*/
|
@@ -14,7 +14,7 @@ Creates a sheet element based on the `position` provided.
|
|
14
14
|
- `maxSize` - max width/height of sheet based on the `side` - can also use css instead
|
15
15
|
- `position` - determines the position of sheet
|
16
16
|
- `transitionSheet` - slides the sheet, set to `false` to remove
|
17
|
-
- `transition` -
|
17
|
+
- `transition` - blurs the entire component, set to `false` to remove
|
18
18
|
|
19
19
|
@slots
|
20
20
|
|
@@ -61,7 +61,7 @@ Creates a sheet element based on the `position` provided.
|
|
61
61
|
|
62
62
|
<script>import { onMount } from "svelte";
|
63
63
|
import {
|
64
|
-
|
64
|
+
blur,
|
65
65
|
fly
|
66
66
|
} from "svelte/transition";
|
67
67
|
import { prefersReducedMotion } from "../util/accessibility";
|
@@ -72,7 +72,7 @@ export let id = "";
|
|
72
72
|
export let classSheet = "";
|
73
73
|
export let display = false;
|
74
74
|
export let transition = { duration };
|
75
|
-
export let position = "
|
75
|
+
export let position = "left";
|
76
76
|
export let maxSize = 488;
|
77
77
|
export let transitionSheet = { duration };
|
78
78
|
let sheet;
|
@@ -106,7 +106,7 @@ onMount(() => {
|
|
106
106
|
|
107
107
|
{#if display}
|
108
108
|
<div
|
109
|
-
transition:
|
109
|
+
transition:blur={transition ? transition : { duration: 0 }}
|
110
110
|
class="d-backdrop {className}"
|
111
111
|
class:d-backdrop-bottom={position === "bottom"}
|
112
112
|
class:d-backdrop-top={position === "top"}
|
@@ -120,11 +120,7 @@ onMount(() => {
|
|
120
120
|
style={position === "top" || position === "bottom"
|
121
121
|
? `max-height: ${maxSize}px;`
|
122
122
|
: `max-width: ${maxSize}px`}
|
123
|
-
class=
|
124
|
-
class:d-sheet-bottom={position === "bottom"}
|
125
|
-
class:d-sheet-top={position === "top"}
|
126
|
-
class:d-sheet-left={position === "left"}
|
127
|
-
class:d-sheet-right={position === "right"}
|
123
|
+
class={classSheet}
|
128
124
|
>
|
129
125
|
<slot>Content</slot>
|
130
126
|
</div>
|
@@ -155,23 +151,4 @@ onMount(() => {
|
|
155
151
|
.d-backdrop-right {
|
156
152
|
flex-direction: row-reverse;
|
157
153
|
}
|
158
|
-
.d-sheet {
|
159
|
-
margin: auto;
|
160
|
-
}
|
161
|
-
.d-sheet-bottom {
|
162
|
-
margin-bottom: 0;
|
163
|
-
width: 100%;
|
164
|
-
}
|
165
|
-
.d-sheet-top {
|
166
|
-
margin-top: 0;
|
167
|
-
width: 100%;
|
168
|
-
}
|
169
|
-
.d-sheet-right {
|
170
|
-
margin-right: 0;
|
171
|
-
height: 100%;
|
172
|
-
}
|
173
|
-
.d-sheet-left {
|
174
|
-
margin-left: 0;
|
175
|
-
height: 100%;
|
176
|
-
}
|
177
154
|
</style>
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
2
|
-
import { type
|
2
|
+
import { type BlurParams, type FlyParams } from "svelte/transition";
|
3
3
|
declare const __propDef: {
|
4
4
|
props: {
|
5
5
|
class?: string | undefined;
|
6
6
|
id?: string | undefined;
|
7
7
|
/** sheet class - not the backdrop */ classSheet?: string | undefined;
|
8
8
|
/** controls whether the sheet is displayed*/ display?: boolean | undefined;
|
9
|
-
/**
|
9
|
+
/** blurs the entire component, set to `false` to remove */ transition?: false | BlurParams | undefined;
|
10
10
|
/** determines the position of sheet */ position?: "top" | "bottom" | "left" | "right" | undefined;
|
11
11
|
/** max width/height of sheet based on the `side` - can also use css instead */ maxSize?: number | undefined;
|
12
12
|
/** slides the sheet, set to `false` to remove */ transitionSheet?: false | FlyParams | undefined;
|
@@ -35,7 +35,7 @@ export type SheetSlots = typeof __propDef.slots;
|
|
35
35
|
* - `maxSize` - max width/height of sheet based on the `side` - can also use css instead
|
36
36
|
* - `position` - determines the position of sheet
|
37
37
|
* - `transitionSheet` - slides the sheet, set to `false` to remove
|
38
|
-
* - `transition` -
|
38
|
+
* - `transition` - blurs the entire component, set to `false` to remove
|
39
39
|
*
|
40
40
|
* @slots
|
41
41
|
*
|
@@ -36,10 +36,10 @@ Displays tabs and the selected tab's content.
|
|
36
36
|
|
37
37
|
<Tabs
|
38
38
|
class="mb-4"
|
39
|
-
classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded bg-neutral-200 p-1"
|
40
|
-
classTab="btn btn-s
|
41
|
-
classTabActive="bg-white text-neutral-950"
|
42
|
-
classTabInactive="bg-neutral-200 text-neutral-
|
39
|
+
classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded-md bg-neutral-200 p-1"
|
40
|
+
classTab="btn btn-s p-2"
|
41
|
+
classTabActive="bg-white text-neutral-950 shadow"
|
42
|
+
classTabInactive="bg-neutral-200 text-neutral-600"
|
43
43
|
classTabPanel="py-2"
|
44
44
|
tabs={[
|
45
45
|
{ tab: "Tab", panel: "Content" },
|
@@ -48,10 +48,10 @@ Displays tabs and the selected tab's content.
|
|
48
48
|
/>
|
49
49
|
|
50
50
|
<Tabs
|
51
|
-
classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded bg-neutral-200 p-1"
|
52
|
-
classTab="btn btn-s
|
53
|
-
classTabActive="bg-white text-neutral-950"
|
54
|
-
classTabInactive="bg-neutral-200 text-neutral-
|
51
|
+
classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded-md bg-neutral-200 p-1"
|
52
|
+
classTab="btn btn-s p-2"
|
53
|
+
classTabActive="bg-white text-neutral-950 shadow"
|
54
|
+
classTabInactive="bg-neutral-200 text-neutral-600"
|
55
55
|
classTabPanel="py-2"
|
56
56
|
tabs={[
|
57
57
|
{ tab: "Tab", panel: "Generated indexes" },
|
@@ -103,6 +103,7 @@ onMount(() => {
|
|
103
103
|
}
|
104
104
|
clientJs = true;
|
105
105
|
});
|
106
|
+
const panelId = "tabPanel-" + Math.random().toString().substring(2, 8);
|
106
107
|
</script>
|
107
108
|
|
108
109
|
<div class={className} {id}>
|
@@ -112,7 +113,7 @@ onMount(() => {
|
|
112
113
|
role="tab"
|
113
114
|
tabindex={index === selectedIndex ? 0 : -1}
|
114
115
|
aria-selected={index === selectedIndex}
|
115
|
-
aria-controls=
|
116
|
+
aria-controls={panelId}
|
116
117
|
disabled={!clientJs}
|
117
118
|
class="{classTab} {selectedIndex === index
|
118
119
|
? classTabActive
|
@@ -125,13 +126,10 @@ onMount(() => {
|
|
125
126
|
</div>
|
126
127
|
{#each tabs as tab, index}
|
127
128
|
{#if index === selectedIndex}
|
128
|
-
<div
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
in:fade={transition ? transition : { duration: 0 }}
|
133
|
-
>
|
134
|
-
<slot name="panel" selectedTab={tab} {index}>{tab.panel}</slot>
|
129
|
+
<div class={classTabPanel} role="tabpanel" id={panelId}>
|
130
|
+
<div in:fade={transition ? transition : { duration: 0 }}>
|
131
|
+
<slot name="panel" selectedTab={tab} {index}>{tab.panel}</slot>
|
132
|
+
</div>
|
135
133
|
</div>
|
136
134
|
{/if}
|
137
135
|
{/each}
|
@@ -75,10 +75,10 @@ export type TabsSlots = typeof __propDef.slots;
|
|
75
75
|
*
|
76
76
|
* <Tabs
|
77
77
|
* class="mb-4"
|
78
|
-
* classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded bg-neutral-200 p-1"
|
79
|
-
* classTab="btn btn-s
|
80
|
-
* classTabActive="bg-white text-neutral-950"
|
81
|
-
* classTabInactive="bg-neutral-200 text-neutral-
|
78
|
+
* classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded-md bg-neutral-200 p-1"
|
79
|
+
* classTab="btn btn-s p-2"
|
80
|
+
* classTabActive="bg-white text-neutral-950 shadow"
|
81
|
+
* classTabInactive="bg-neutral-200 text-neutral-600"
|
82
82
|
* classTabPanel="py-2"
|
83
83
|
* tabs={[
|
84
84
|
* { tab: "Tab", panel: "Content" },
|
@@ -87,10 +87,10 @@ export type TabsSlots = typeof __propDef.slots;
|
|
87
87
|
* />
|
88
88
|
*
|
89
89
|
* <Tabs
|
90
|
-
* classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded bg-neutral-200 p-1"
|
91
|
-
* classTab="btn btn-s
|
92
|
-
* classTabActive="bg-white text-neutral-950"
|
93
|
-
* classTabInactive="bg-neutral-200 text-neutral-
|
90
|
+
* classTabList="grid grid-flow-col grid-rows-1 gap-1 rounded-md bg-neutral-200 p-1"
|
91
|
+
* classTab="btn btn-s p-2"
|
92
|
+
* classTabActive="bg-white text-neutral-950 shadow"
|
93
|
+
* classTabInactive="bg-neutral-200 text-neutral-600"
|
94
94
|
* classTabPanel="py-2"
|
95
95
|
* tabs={[
|
96
96
|
* { tab: "Tab", panel: "Generated indexes" },
|