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