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.
@@ -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 Javascript?", content: "Yes." },
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
- item.open = false;
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 Javascript?", content: "Yes." },
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 { messageNoScript } from "../util/messages";
113
- import { onMount } from "svelte";
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(() => clientJs = true);
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
- {@const showRow =
199
- i < maxRows * currentPage && i >= maxRows * (currentPage - 1)}
200
- {#if maxRows ? showRow : true}
201
- <tr class={classTbodyTr}>
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) or the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to share or copy a url link depending on browser support.
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
- - `text` - prefixed text in share message
14
- - `title` - title of share message and `button` attribute, defaults to end of url
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
- <ShareButton
33
- class="btn"
34
- text="Check out this page: "
35
- title="drab"
36
- url="https://drab.robino.dev"
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 text = "";
48
- export let url;
49
- export let title = url.split("/").splice(-1)[0];
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
- try {
55
- if (navigator.canShare) {
56
- await navigator.share({ text, url, title });
57
- } else {
58
- await navigator.clipboard.writeText(url);
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
- } catch (error) {
63
- console.log(error);
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
- <noscript><span class={classNoscript}>{url}</span></noscript>
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
- /** prefixed text in share message */ text?: string | undefined;
7
- /** url to be shared */ url: string;
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) or the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to share or copy a url link depending on browser support.
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
- * - `text` - prefixed text in share message
33
- * - `title` - title of share message and `button` attribute, defaults to end of url
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
- * class="btn"
53
- * text="Check out this page: "
54
- * title="drab"
55
- * url="https://drab.robino.dev"
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` - fades the entire component, set to `false` to remove
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
- fade,
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 = "right";
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:fade={transition ? transition : { duration: 0 }}
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="d-sheet {classSheet}"
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 FadeParams, type FlyParams } from "svelte/transition";
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
- /** fades the entire component, set to `false` to remove */ transition?: false | FadeParams | undefined;
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` - fades the entire component, set to `false` to remove
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 rounded-sm p-1"
41
- classTabActive="bg-white text-neutral-950"
42
- classTabInactive="bg-neutral-200 text-neutral-500"
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 rounded-sm p-1"
53
- classTabActive="bg-white text-neutral-950"
54
- classTabInactive="bg-neutral-200 text-neutral-500"
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="tabpanel"
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
- class={classTabPanel}
130
- role="tabpanel"
131
- id="tabpanel"
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 rounded-sm p-1"
80
- * classTabActive="bg-white text-neutral-950"
81
- * classTabInactive="bg-neutral-200 text-neutral-500"
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 rounded-sm p-1"
92
- * classTabActive="bg-white text-neutral-950"
93
- * classTabInactive="bg-neutral-200 text-neutral-500"
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" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drab",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "An unstyled Svelte component library",
5
5
  "keywords": [
6
6
  "components",