drab 2.2.1 → 2.4.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.
@@ -8,19 +8,24 @@ Displays a list of `details` elements.
8
8
  @props
9
9
 
10
10
  - `autoClose` - if `true`, other items close when a new one is opened
11
+ - `classContent` - class of all the `div`s that wrap the `content` slot
11
12
  - `classDetails` - class of the `div` around each `details` element
12
- - `classIcon` - class of the `div` around the icon
13
- - `classSlot` - class of all the `slot` elements
14
- - `classSummary` - class of all the `summary` elements
13
+ - `classHeader` - class of all the `summary` elements
14
+ - `classIcon` - class of the `div` that wrap the icon if displayed
15
+ - `classSummary` - class of all the `div`s that wrap the `summary` slot
15
16
  - `class`
16
- - `content` - array of `AccordionContent` elements
17
17
  - `icon`
18
18
  - `id`
19
+ - `items` - array of `AccordionItem` elements
19
20
  - `transition` - rotates the icon, slides the content, defaults to empty object, set to false to remove
20
21
 
21
22
  @slots
22
23
 
23
- Pass components into the `content` prop if needed. `AccordionContent` has `summary` and `slot` attributes of type `string | ComponentType`.
24
+ | name | purpose | default value | slot props |
25
+ | --------- | ----------------------------- | -------------- | --------------- |
26
+ | `summary` | summary element | `item.summary` | `item`, `index` |
27
+ | `icon` | icon element | `icon` prop | `item`, `index` |
28
+ | `content` | content of the accordion item | `item.content` | `item`, `index` |
24
29
 
25
30
  @example
26
31
 
@@ -29,20 +34,43 @@ Pass components into the `content` prop if needed. `AccordionContent` has `summa
29
34
  import { Accordion } from "drab";
30
35
  </script>
31
36
 
32
- <Accordion
33
- content={[
34
- { summary: "Is it accessible?", slot: "Yes." },
37
+ <Accordion
38
+ items={[
39
+ { summary: "Is it accessible?", content: "Yes." },
35
40
  {
36
41
  summary: "Is it styled?",
37
- slot: "Nope, style with global styles.",
42
+ content: "Nope, style with global styles.",
38
43
  },
39
44
  {
40
45
  summary: "Is it animated?",
41
- slot: "Yes, with the transition prop.",
46
+ content: "Yes, with the transition prop.",
47
+ },
48
+ { summary: "Does it work without Javascript?", content: "Yes." },
49
+ ]}
50
+ >
51
+ <div slot="content" let:item let:index>
52
+ <span>{index + 1}.</span>
53
+ <span>{item.content}</span>
54
+ </div>
55
+ </Accordion>
56
+
57
+ <Accordion
58
+ items={[
59
+ {
60
+ summary: "A Component",
61
+ content: "Rendered only on this item.",
62
+ data: { component: FullscreenButton },
42
63
  },
43
- { summary: "Does it work without Javascript?", slot: "Yes." },
64
+ { summary: "Summary", content: "Some other content" },
44
65
  ]}
45
- />
66
+ >
67
+ <svelte:fragment slot="content" let:item>
68
+ {item.content}
69
+ {#if item.data?.component}
70
+ <svelte:component this={item.data.component} />
71
+ {/if}
72
+ </svelte:fragment>
73
+ </Accordion>
46
74
  ```
47
75
  -->
48
76
 
@@ -54,28 +82,21 @@ import { prefersReducedMotion } from "../util/accessibility";
54
82
  let className = "";
55
83
  export { className as class };
56
84
  export let id = "";
57
- export let content;
85
+ export let items;
58
86
  export let icon = "";
59
87
  export let classDetails = "";
88
+ export let classHeader = "";
60
89
  export let classSummary = "";
61
- export let classSlot = "";
90
+ export let classContent = "";
62
91
  export let classIcon = "";
63
92
  export let transition = {};
64
93
  export let autoClose = true;
65
94
  let clientJs = false;
66
- for (const item of content) {
67
- if (!item.classContentDetails)
68
- item.classContentDetails = "";
69
- if (!item.classContentSlot)
70
- item.classContentSlot = "";
71
- if (!item.classContentSummary)
72
- item.classContentSummary = "";
73
- }
74
95
  const toggleOpen = (i) => {
75
- content[i].open = !content[i].open;
96
+ items[i].open = !items[i].open;
76
97
  if (autoClose) {
77
- for (let j = 0; j < content.length; j++) {
78
- const item = content[j];
98
+ for (let j = 0; j < items.length; j++) {
99
+ const item = items[j];
79
100
  if (j !== i)
80
101
  item.open = false;
81
102
  }
@@ -88,64 +109,51 @@ onMount(() => {
88
109
  });
89
110
  </script>
90
111
 
91
- <div class="transition"></div>
92
-
93
112
  <div class={className} {id}>
94
- {#each content as { classContentDetails, summary, classContentSummary, slot, classContentSlot, open }, i}
95
- <div class="{classDetails} {classContentDetails}">
96
- <details bind:open>
113
+ {#each items as item, index}
114
+ <div class={classDetails}>
115
+ <details bind:open={item.open}>
97
116
  <!-- svelte-ignore a11y-no-redundant-roles -->
98
117
  <summary
99
118
  role="button"
100
119
  tabindex="0"
101
- class={classSummary}
102
- on:click={(e) => {
103
- e.preventDefault();
104
- toggleOpen(i);
105
- }}
120
+ class={classHeader}
121
+ on:click|preventDefault={() => toggleOpen(index)}
106
122
  on:keydown={(e) => {
107
123
  if (e.key === "Enter") {
108
124
  e.preventDefault();
109
- toggleOpen(i);
125
+ toggleOpen(index);
110
126
  }
111
127
  }}
112
128
  >
113
- {#if typeof summary !== "string"}
114
- <svelte:component this={summary} class={classContentSummary} />
115
- {:else}
116
- <span class={classContentSummary}>{summary}</span>
117
- {/if}
118
- {#if icon}
119
- <div
120
- class={classIcon}
121
- class:db-rotate-180={open}
122
- class:db-transition={transition}
123
- >
124
- {#if typeof icon !== "string"}
125
- <svelte:component this={icon} />
126
- {:else}
127
- <span>{icon}</span>
128
- {/if}
129
- </div>
130
- {/if}
129
+ <div class={classSummary}>
130
+ <slot name="summary" {item} {index}>{item.summary}</slot>
131
+ </div>
132
+ <slot name="icon" {item} {index}>
133
+ {#if icon}
134
+ <div
135
+ class={classIcon}
136
+ class:d-rotate-180={item.open}
137
+ class:d-transition={transition}
138
+ >
139
+ {#if typeof icon !== "string"}
140
+ <svelte:component this={icon} />
141
+ {:else}
142
+ <span>{icon}</span>
143
+ {/if}
144
+ </div>
145
+ {/if}
146
+ </slot>
131
147
  </summary>
132
148
  {#if !clientJs || !transition}
133
- <div class={classSlot}>
134
- {#if typeof slot !== "string"}
135
- <svelte:component this={slot} class={classContentSlot} />
136
- {:else}
137
- <div class={classContentSlot}>{slot}</div>
138
- {/if}
149
+ <div class={classContent}>
150
+ <slot name="content" {item} {index}>{item.content}</slot>
139
151
  </div>
140
152
  {/if}
141
153
  </details>
142
- {#if clientJs && open && transition}
143
- <div transition:slide={transition} class={classSlot}>
144
- {#if typeof slot !== "string"}
145
- <svelte:component this={slot} class={classContentSlot} />
146
- {:else}
147
- <div class={classContentSlot}>{slot}</div>
148
- {/if}
154
+ {#if clientJs && item.open && transition}
155
+ <div class={classContent} transition:slide={transition}>
156
+ <slot name="content" {item} {index}>{item.content}</slot>
149
157
  </div>
150
158
  {/if}
151
159
  </div>
@@ -159,10 +167,10 @@ onMount(() => {
159
167
  summary::-webkit-details-marker {
160
168
  display: none;
161
169
  }
162
- .db-rotate-180 {
170
+ .d-rotate-180 {
163
171
  transform: rotate(180deg);
164
172
  }
165
- .db-transition {
173
+ .d-transition {
166
174
  transition-property: transform;
167
175
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
168
176
  transition-duration: 150ms;
@@ -1,37 +1,47 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import type { ComponentType } from "svelte";
3
- export interface AccordionContent {
4
- /** `details` element class */
5
- classContentDetails?: string;
6
- /** content of the `summary` element */
7
- summary: string | ComponentType;
8
- /** `summary` element class */
9
- classContentSummary?: string;
10
- /** content of the `slot` */
11
- slot: string | ComponentType;
12
- /** `slot` element class */
13
- classContentSlot?: string;
14
- /** controls whether the slotted content is displayed */
2
+ export interface AccordionItem<T = any> {
3
+ /** text summary of the item */
4
+ summary?: string;
5
+ /** text content of the item */
6
+ content?: string;
7
+ /** controls whether the content is displayed */
15
8
  open?: boolean;
9
+ /** any data to pass back to the parent */
10
+ data?: T;
16
11
  }
12
+ import { type ComponentType } from "svelte";
17
13
  import { type SlideParams } from "svelte/transition";
18
14
  declare const __propDef: {
19
15
  props: {
20
16
  class?: string | undefined;
21
17
  id?: string | undefined;
22
- /** array of `AccordionContent` elements */ content: AccordionContent[];
18
+ /** array of `AccordionItem` elements */ items: AccordionItem[];
23
19
  icon?: string | ComponentType | undefined;
24
20
  /** class of the `div` around each `details` element */ classDetails?: string | undefined;
25
- /** class of all the `summary` elements */ classSummary?: string | undefined;
26
- /** class of all the `slot` elements */ classSlot?: string | undefined;
27
- /** class of the `div` around the icon */ classIcon?: string | undefined;
21
+ /** class of all the `summary` elements */ classHeader?: string | undefined;
22
+ /** class of all the `div`s that wrap the `summary` slot */ classSummary?: string | undefined;
23
+ /** class of all the `div`s that wrap the `content` slot */ classContent?: string | undefined;
24
+ /** class of the `div` that wrap the icon if displayed */ classIcon?: string | undefined;
28
25
  /** rotates the icon, slides the content, defaults to empty object, set to false to remove */ transition?: false | SlideParams | undefined;
29
26
  /** if `true`, other items close when a new one is opened */ autoClose?: boolean | undefined;
30
27
  };
31
28
  events: {
32
29
  [evt: string]: CustomEvent<any>;
33
30
  };
34
- slots: {};
31
+ slots: {
32
+ summary: {
33
+ item: AccordionItem<any>;
34
+ index: any;
35
+ };
36
+ icon: {
37
+ item: AccordionItem<any>;
38
+ index: any;
39
+ };
40
+ content: {
41
+ item: AccordionItem<any>;
42
+ index: any;
43
+ };
44
+ };
35
45
  };
36
46
  export type AccordionProps = typeof __propDef.props;
37
47
  export type AccordionEvents = typeof __propDef.events;
@@ -44,19 +54,24 @@ export type AccordionSlots = typeof __propDef.slots;
44
54
  * @props
45
55
  *
46
56
  * - `autoClose` - if `true`, other items close when a new one is opened
57
+ * - `classContent` - class of all the `div`s that wrap the `content` slot
47
58
  * - `classDetails` - class of the `div` around each `details` element
48
- * - `classIcon` - class of the `div` around the icon
49
- * - `classSlot` - class of all the `slot` elements
50
- * - `classSummary` - class of all the `summary` elements
59
+ * - `classHeader` - class of all the `summary` elements
60
+ * - `classIcon` - class of the `div` that wrap the icon if displayed
61
+ * - `classSummary` - class of all the `div`s that wrap the `summary` slot
51
62
  * - `class`
52
- * - `content` - array of `AccordionContent` elements
53
63
  * - `icon`
54
64
  * - `id`
65
+ * - `items` - array of `AccordionItem` elements
55
66
  * - `transition` - rotates the icon, slides the content, defaults to empty object, set to false to remove
56
67
  *
57
68
  * @slots
58
69
  *
59
- * Pass components into the `content` prop if needed. `AccordionContent` has `summary` and `slot` attributes of type `string | ComponentType`.
70
+ * | name | purpose | default value | slot props |
71
+ * | --------- | ----------------------------- | -------------- | --------------- |
72
+ * | `summary` | summary element | `item.summary` | `item`, `index` |
73
+ * | `icon` | icon element | `icon` prop | `item`, `index` |
74
+ * | `content` | content of the accordion item | `item.content` | `item`, `index` |
60
75
  *
61
76
  * @example
62
77
  *
@@ -66,19 +81,42 @@ export type AccordionSlots = typeof __propDef.slots;
66
81
  * </script>
67
82
  *
68
83
  * <Accordion
69
- * content={[
70
- * { summary: "Is it accessible?", slot: "Yes." },
84
+ * items={[
85
+ * { summary: "Is it accessible?", content: "Yes." },
71
86
  * {
72
87
  * summary: "Is it styled?",
73
- * slot: "Nope, style with global styles.",
88
+ * content: "Nope, style with global styles.",
74
89
  * },
75
90
  * {
76
91
  * summary: "Is it animated?",
77
- * slot: "Yes, with the transition prop.",
92
+ * content: "Yes, with the transition prop.",
93
+ * },
94
+ * { summary: "Does it work without Javascript?", content: "Yes." },
95
+ * ]}
96
+ * >
97
+ * <div slot="content" let:item let:index>
98
+ * <span>{index + 1}.</span>
99
+ * <span>{item.content}</span>
100
+ * </div>
101
+ * </Accordion>
102
+ *
103
+ * <Accordion
104
+ * items={[
105
+ * {
106
+ * summary: "A Component",
107
+ * content: "Rendered only on this item.",
108
+ * data: { component: FullscreenButton },
78
109
  * },
79
- * { summary: "Does it work without Javascript?", slot: "Yes." },
110
+ * { summary: "Summary", content: "Some other content" },
80
111
  * ]}
81
- * />
112
+ * >
113
+ * <svelte:fragment slot="content" let:item>
114
+ * {item.content}
115
+ * {#if item.data?.component}
116
+ * <svelte:component this={item.data.component} />
117
+ * {/if}
118
+ * </svelte:fragment>
119
+ * </Accordion>
82
120
  * ```
83
121
  */
84
122
  export default class Accordion extends SvelteComponent<AccordionProps, AccordionEvents, AccordionSlots> {
@@ -3,100 +3,104 @@
3
3
 
4
4
  ### Tabs
5
5
 
6
- Displays tabs and slotted content.
6
+ Displays tabs and the active tab's content.
7
7
 
8
8
  @props
9
9
 
10
- - `classButtonActive` - class of the active tab's `button`
11
- - `classButtonInactive` - class of all the inactive tabs' `button`s
12
- - `classButton` - `button` class
10
+ - `activeIndex` - index of active tab, defaults to 0
11
+ - `classContent` - class of `div` that wraps the slotted content
13
12
  - `classHeader` - class of the `div` that wraps the `button`s
14
13
  - `classNoscript` - `noscript` class
15
- - `classSlot` - class of `div` that wraps the slotted content
14
+ - `classTitleActive` - class of the active tab's `button`
15
+ - `classTitleInactive` - class of all the inactive tabs' `button`s
16
+ - `classTitle` - class of all title `button`s
16
17
  - `class`
17
- - `content` - array of `TabContent` elements
18
18
  - `id`
19
- - `transition` - fades the content in, defaults to empty object, set to false to remove
19
+ - `tabs` - array of tabs
20
20
 
21
21
  @slots
22
22
 
23
- Pass components into the `content` prop if needed. `TabsContent` has a `slot` attribute of type `string | ComponentType`.
23
+ | name | purpose | default value | slot props |
24
+ | --------- | --------------------- | -------------------- | --------------- |
25
+ | `default` | active item's content | `activeItem.content` | `activeItem` |
26
+ | `title` | title of each tab | `item.title` | `item`, `index` |
24
27
 
25
28
  @example
26
29
 
27
30
  ```svelte
28
31
  <script>
29
32
  import { Tabs } from "drab";
30
- import { FullscreenButton } from "drab";
31
33
  </script>
32
34
 
33
- <Tabs content={[
34
- { name: "String", slot: "Slot" },
35
- { name: "Component", slot: FullscreenButton },
35
+ <Tabs
36
+ items={[
37
+ { name: "Tab 1", content: "Content 1" },
38
+ { name: "Tab 2", content: "Content 2" },
36
39
  ]}
37
40
  />
41
+
42
+ <Tabs
43
+ tabs={[
44
+ { title: "Tab", content: "Content 1" },
45
+ {
46
+ title: "Tab",
47
+ content: "A tab with a component",
48
+ data: { component: FullscreenButton },
49
+ },
50
+ ]}
51
+ let:activeTab
52
+ >
53
+ <svelte:fragment slot="title" let:item let:index>
54
+ {item.title}
55
+ {index + 1}
56
+ </svelte:fragment>
57
+ <div>{activeTab.content}</div>
58
+ {#if activeTab.data?.component}
59
+ <svelte:component this={activeTab.data.component} />
60
+ {/if}
61
+ </Tabs>
38
62
  ```
39
63
  -->
40
64
 
41
65
  <script context="module"></script>
42
66
 
43
67
  <script>import { onMount } from "svelte";
44
- import { fade } from "svelte/transition";
45
68
  import { messageNoScript } from "../util/messages";
46
69
  let className = "";
47
70
  export { className as class };
48
71
  export let id = "";
49
72
  export let classHeader = "";
50
- export let classButton = "";
51
- export let classButtonActive = "";
52
- export let classButtonInactive = "";
73
+ export let classTitle = "";
74
+ export let classTitleActive = "";
75
+ export let classTitleInactive = "";
53
76
  export let classNoscript = "";
54
- export let classSlot = "";
55
- export let content;
56
- export let transition = {};
57
- const fadeTransition = transition ? transition : { duration: 0 };
77
+ export let classContent = "";
78
+ export let tabs;
79
+ export let activeIndex = 0;
58
80
  let clientJs = false;
59
- let activeIndex = 0;
60
- for (const item of content) {
61
- if (!item.classContentSlot)
62
- item.classContentSlot = "";
63
- }
64
81
  $:
65
- activeTab = content[activeIndex];
82
+ activeTab = tabs[activeIndex];
66
83
  onMount(() => clientJs = true);
67
84
  </script>
68
85
 
69
86
  <div class={className} {id}>
70
87
  <div class={classHeader}>
71
- {#each content as { name }, i}
88
+ {#each tabs as item, index}
72
89
  <button
73
90
  disabled={!clientJs}
74
- class="{classButton} {activeIndex === i
75
- ? classButtonActive
76
- : ''} {activeIndex !== i ? classButtonInactive : ''}"
77
- on:click={() => (activeIndex = i)}
91
+ class="{classTitle} {activeIndex === index
92
+ ? classTitleActive
93
+ : ''} {activeIndex !== index ? classTitleInactive : ''}"
94
+ on:click={() => (activeIndex = index)}
78
95
  >
79
- {name}
96
+ <slot name="title" {item} {index}>{item.title}</slot>
80
97
  </button>
81
98
  {/each}
82
99
  </div>
83
- <div class={classSlot}>
84
- {#if typeof activeTab.slot !== "string"}
85
- <div in:fade={fadeTransition}>
86
- <svelte:component
87
- this={activeTab.slot}
88
- class={activeTab.classContentSlot}
89
- />
90
- </div>
91
- {:else}
92
- <div in:fade={fadeTransition} class={activeTab.classContentSlot}>
93
- {activeTab.slot}
94
- </div>
95
- {/if}
100
+ <div class={classContent}>
101
+ <slot {activeTab}>{activeTab.content}</slot>
96
102
  </div>
97
103
  <noscript>
98
- <div class={classNoscript}>
99
- {messageNoScript}
100
- </div>
104
+ <div class={classNoscript}>{messageNoScript}</div>
101
105
  </noscript>
102
106
  </div>
@@ -1,31 +1,37 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import type { ComponentType } from "svelte";
3
- export interface TabsContent {
4
- /** tab name, displayed in `button` element */
5
- name: string;
2
+ export interface TabsTab<T = any> {
3
+ /** tab title, displayed in `button` element */
4
+ title?: string;
6
5
  /** slotted content, displayed once tab is clicked */
7
- slot: string | ComponentType;
8
- /** class of the slotted content */
9
- classContentSlot?: string;
6
+ content?: string;
7
+ /** any data to pass back to the parent */
8
+ data?: T;
10
9
  }
11
- import { type FadeParams } from "svelte/transition";
12
10
  declare const __propDef: {
13
11
  props: {
14
12
  class?: string | undefined;
15
13
  id?: string | undefined;
16
14
  /** class of the `div` that wraps the `button`s */ classHeader?: string | undefined;
17
- /** `button` class */ classButton?: string | undefined;
18
- /** class of the active tab's `button` */ classButtonActive?: string | undefined;
19
- /** class of all the inactive tabs' `button`s */ classButtonInactive?: string | undefined;
15
+ /** class of all title `button`s */ classTitle?: string | undefined;
16
+ /** class of the active tab's `button` */ classTitleActive?: string | undefined;
17
+ /** class of all the inactive tabs' `button`s */ classTitleInactive?: string | undefined;
20
18
  /** `noscript` class */ classNoscript?: string | undefined;
21
- /** class of `div` that wraps the slotted content */ classSlot?: string | undefined;
22
- /** array of `TabContent` elements */ content: TabsContent[];
23
- /** fades the content in, defaults to empty object, set to false to remove */ transition?: false | FadeParams | undefined;
19
+ /** class of `div` that wraps the slotted content */ classContent?: string | undefined;
20
+ /** array of tabs */ tabs: TabsTab[];
21
+ /** index of active tab, defaults to 0 */ activeIndex?: number | undefined;
24
22
  };
25
23
  events: {
26
24
  [evt: string]: CustomEvent<any>;
27
25
  };
28
- slots: {};
26
+ slots: {
27
+ title: {
28
+ item: TabsTab<any>;
29
+ index: any;
30
+ };
31
+ default: {
32
+ activeTab: TabsTab<any>;
33
+ };
34
+ };
29
35
  };
30
36
  export type TabsProps = typeof __propDef.props;
31
37
  export type TabsEvents = typeof __propDef.events;
@@ -33,38 +39,62 @@ export type TabsSlots = typeof __propDef.slots;
33
39
  /**
34
40
  * ### Tabs
35
41
  *
36
- * Displays tabs and slotted content.
42
+ * Displays tabs and the active tab's content.
37
43
  *
38
44
  * @props
39
45
  *
40
- * - `classButtonActive` - class of the active tab's `button`
41
- * - `classButtonInactive` - class of all the inactive tabs' `button`s
42
- * - `classButton` - `button` class
46
+ * - `activeIndex` - index of active tab, defaults to 0
47
+ * - `classContent` - class of `div` that wraps the slotted content
43
48
  * - `classHeader` - class of the `div` that wraps the `button`s
44
49
  * - `classNoscript` - `noscript` class
45
- * - `classSlot` - class of `div` that wraps the slotted content
50
+ * - `classTitleActive` - class of the active tab's `button`
51
+ * - `classTitleInactive` - class of all the inactive tabs' `button`s
52
+ * - `classTitle` - class of all title `button`s
46
53
  * - `class`
47
- * - `content` - array of `TabContent` elements
48
54
  * - `id`
49
- * - `transition` - fades the content in, defaults to empty object, set to false to remove
55
+ * - `tabs` - array of tabs
50
56
  *
51
57
  * @slots
52
58
  *
53
- * Pass components into the `content` prop if needed. `TabsContent` has a `slot` attribute of type `string | ComponentType`.
59
+ * | name | purpose | default value | slot props |
60
+ * | --------- | --------------------- | -------------------- | --------------- |
61
+ * | `default` | active item's content | `activeItem.content` | `activeItem` |
62
+ * | `title` | title of each tab | `item.title` | `item`, `index` |
54
63
  *
55
64
  * @example
56
65
  *
57
66
  * ```svelte
58
67
  * <script>
59
68
  * import { Tabs } from "drab";
60
- * import { FullscreenButton } from "drab";
61
69
  * </script>
62
70
  *
63
- * <Tabs content={[
64
- * { name: "String", slot: "Slot" },
65
- * { name: "Component", slot: FullscreenButton },
71
+ * <Tabs
72
+ * items={[
73
+ * { name: "Tab 1", content: "Content 1" },
74
+ * { name: "Tab 2", content: "Content 2" },
66
75
  * ]}
67
76
  * />
77
+ *
78
+ * <Tabs
79
+ * tabs={[
80
+ * { title: "Tab", content: "Content 1" },
81
+ * {
82
+ * title: "Tab",
83
+ * content: "A tab with a component",
84
+ * data: { component: FullscreenButton },
85
+ * },
86
+ * ]}
87
+ * let:activeTab
88
+ * >
89
+ * <svelte:fragment slot="title" let:item let:index>
90
+ * {item.title}
91
+ * {index + 1}
92
+ * </svelte:fragment>
93
+ * <div>{activeTab.content}</div>
94
+ * {#if activeTab.data?.component}
95
+ * <svelte:component this={activeTab.data.component} />
96
+ * {/if}
97
+ * </Tabs>
68
98
  * ```
69
99
  */
70
100
  export default class Tabs extends SvelteComponent<TabsProps, TabsEvents, TabsSlots> {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Accordion from "./components/Accordion.svelte";
2
- import type { AccordionContent } from "./components/Accordion.svelte";
2
+ import type { AccordionItem } from "./components/Accordion.svelte";
3
3
  import Chord from "./components/Chord.svelte";
4
4
  import type { ChordNote } from "./components/Chord.svelte";
5
5
  import ContextMenu from "./components/ContextMenu.svelte";
@@ -11,5 +11,7 @@ import type { EditorContentElement } from "./components/Editor.svelte";
11
11
  import FullscreenButton from "./components/FullscreenButton.svelte";
12
12
  import Popover from "./components/Popover.svelte";
13
13
  import ShareButton from "./components/ShareButton.svelte";
14
+ import Tabs from "./components/Tabs.svelte";
15
+ import type { TabsTab } from "./components/Tabs.svelte";
14
16
  import YouTube from "./components/YouTube.svelte";
15
- export { Accordion, type AccordionContent, Chord, type ChordNote, ContextMenu, CopyButton, DataTable, type DataTableRow, Editor, type EditorContentElement, FullscreenButton, Popover, ShareButton, YouTube, };
17
+ export { Accordion, type AccordionItem, Chord, type ChordNote, ContextMenu, CopyButton, DataTable, type DataTableRow, Editor, type EditorContentElement, FullscreenButton, Popover, ShareButton, Tabs, type TabsTab, YouTube, };
package/dist/index.js CHANGED
@@ -7,5 +7,6 @@ import Editor from "./components/Editor.svelte";
7
7
  import FullscreenButton from "./components/FullscreenButton.svelte";
8
8
  import Popover from "./components/Popover.svelte";
9
9
  import ShareButton from "./components/ShareButton.svelte";
10
+ import Tabs from "./components/Tabs.svelte";
10
11
  import YouTube from "./components/YouTube.svelte";
11
- export { Accordion, Chord, ContextMenu, CopyButton, DataTable, Editor, FullscreenButton, Popover, ShareButton, YouTube, };
12
+ export { Accordion, Chord, ContextMenu, CopyButton, DataTable, Editor, FullscreenButton, Popover, ShareButton, Tabs, YouTube, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drab",
3
- "version": "2.2.1",
3
+ "version": "2.4.0",
4
4
  "description": "An unstyled Svelte component library",
5
5
  "keywords": [
6
6
  "components",
@@ -15,6 +15,7 @@
15
15
  "Fullscreen",
16
16
  "Popover",
17
17
  "Share",
18
+ "Tabs",
18
19
  "YouTube"
19
20
  ],
20
21
  "homepage": "https://drab.robino.dev",