drab 2.6.1 → 2.7.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.
@@ -3,7 +3,7 @@
3
3
 
4
4
  ### Accordion
5
5
 
6
- Displays a list of `details` elements.
6
+ Displays a list of `details` elements with helpful defaults and transitions.
7
7
 
8
8
  @props
9
9
 
@@ -30,15 +30,18 @@ Displays a list of `details` elements.
30
30
  @example
31
31
 
32
32
  ```svelte
33
- <script>
33
+ <script lang="ts">
34
34
  import { Accordion } from "drab";
35
+ import { FullscreenButton } from "drab";
35
36
  import { Chevron } from "../../site/svg/Chevron.svelte";
36
37
  </script>
37
38
 
38
39
  <Accordion
39
40
  icon={Chevron}
41
+ class="mb-12"
40
42
  classDetails="border-b"
41
- classHeader="flex gap-8 cursor-pointer items-center justify-between py-4 font-bold hover:underline"
43
+ classHeader="flex gap-8 cursor-pointer items-center justify-between p-4 font-bold underline hover:decoration-dotted"
44
+ classContent="pb-4 px-4"
42
45
  items={[
43
46
  { summary: "Is it accessible?", content: "Yes." },
44
47
  {
@@ -51,12 +54,35 @@ Displays a list of `details` elements.
51
54
  },
52
55
  { summary: "Does it work without Javascript?", content: "Yes." },
53
56
  ]}
57
+ />
58
+
59
+ <Accordion
60
+ icon={Chevron}
61
+ classDetails="border-b"
62
+ classHeader="flex gap-8 cursor-pointer items-center justify-between p-4 font-bold underline hover:decoration-dotted"
63
+ classContent="pb-4 px-4"
64
+ autoClose={false}
65
+ items={[
66
+ { summary: "Summary", content: "Content" },
67
+ { summary: "Summary", content: "Content", data: { uppercase: true } },
68
+ {
69
+ summary: "Summary",
70
+ content: "Content",
71
+ data: { component: FullscreenButton },
72
+ },
73
+ ]}
54
74
  >
55
- <svelte:fragment slot="content" let:item let:index>
56
- <div class="pb-4">
57
- <span>{index + 1}.</span>
58
- <span>{item.content}</span>
59
- </div>
75
+ <svelte:fragment slot="summary" let:item let:index>
76
+ <span class:uppercase={item.data?.uppercase}>
77
+ {item.summary}
78
+ {index + 1}
79
+ </span>
80
+ </svelte:fragment>
81
+ <svelte:fragment slot="content" let:item>
82
+ <span>{item.content}</span>
83
+ {#if item.data?.component === FullscreenButton}
84
+ <div><svelte:component this={FullscreenButton} class="btn mt-4" /></div>
85
+ {/if}
60
86
  </svelte:fragment>
61
87
  </Accordion>
62
88
  ```
@@ -49,7 +49,7 @@ export type AccordionSlots = typeof __propDef.slots;
49
49
  /**
50
50
  * ### Accordion
51
51
  *
52
- * Displays a list of `details` elements.
52
+ * Displays a list of `details` elements with helpful defaults and transitions.
53
53
  *
54
54
  * @props
55
55
  *
@@ -76,15 +76,18 @@ export type AccordionSlots = typeof __propDef.slots;
76
76
  * @example
77
77
  *
78
78
  * ```svelte
79
- * <script>
79
+ * <script lang="ts">
80
80
  * import { Accordion } from "drab";
81
+ * import { FullscreenButton } from "drab";
81
82
  * import { Chevron } from "../../site/svg/Chevron.svelte";
82
83
  * </script>
83
84
  *
84
85
  * <Accordion
85
86
  * icon={Chevron}
87
+ * class="mb-12"
86
88
  * classDetails="border-b"
87
- * classHeader="flex gap-8 cursor-pointer items-center justify-between py-4 font-bold hover:underline"
89
+ * classHeader="flex gap-8 cursor-pointer items-center justify-between p-4 font-bold underline hover:decoration-dotted"
90
+ * classContent="pb-4 px-4"
88
91
  * items={[
89
92
  * { summary: "Is it accessible?", content: "Yes." },
90
93
  * {
@@ -97,12 +100,35 @@ export type AccordionSlots = typeof __propDef.slots;
97
100
  * },
98
101
  * { summary: "Does it work without Javascript?", content: "Yes." },
99
102
  * ]}
103
+ * />
104
+ *
105
+ * <Accordion
106
+ * icon={Chevron}
107
+ * classDetails="border-b"
108
+ * classHeader="flex gap-8 cursor-pointer items-center justify-between p-4 font-bold underline hover:decoration-dotted"
109
+ * classContent="pb-4 px-4"
110
+ * autoClose={false}
111
+ * items={[
112
+ * { summary: "Summary", content: "Content" },
113
+ * { summary: "Summary", content: "Content", data: { uppercase: true } },
114
+ * {
115
+ * summary: "Summary",
116
+ * content: "Content",
117
+ * data: { component: FullscreenButton },
118
+ * },
119
+ * ]}
100
120
  * >
101
- * <svelte:fragment slot="content" let:item let:index>
102
- * <div class="pb-4">
103
- * <span>{index + 1}.</span>
104
- * <span>{item.content}</span>
105
- * </div>
121
+ * <svelte:fragment slot="summary" let:item let:index>
122
+ * <span class:uppercase={item.data?.uppercase}>
123
+ * {item.summary}
124
+ * {index + 1}
125
+ * </span>
126
+ * </svelte:fragment>
127
+ * <svelte:fragment slot="content" let:item>
128
+ * <span>{item.content}</span>
129
+ * {#if item.data?.component === FullscreenButton}
130
+ * <div><svelte:component this={FullscreenButton} class="btn mt-4" /></div>
131
+ * {/if}
106
132
  * </svelte:fragment>
107
133
  * </Accordion>
108
134
  * ```
@@ -5,17 +5,7 @@
5
5
 
6
6
  Displays the current breakpoint and `window.innerWidth`, based on the `breakpoints` provided. Defaults to [TailwindCSS breakpoint sizes](https://tailwindcss.com/docs/responsive-design).
7
7
 
8
- ```svelte
9
- <script lang="ts">
10
- import { dev } from "$app/environment"; // SvelteKit Example
11
- </script>
12
-
13
- {#if dev}
14
- <Breakpoint
15
- class="fixed bottom-4 right-4 rounded border bg-white px-2 py-1 font-mono tabular-nums shadow"
16
- />
17
- {/if}
18
- ```
8
+ With SvelteKit, this component can be wrapped in an `{#if dev}` block that checks for the [dev module](https://kit.svelte.dev/docs/modules#$app-environment-dev), to show only during development.
19
9
 
20
10
  @props
21
11
 
@@ -21,17 +21,7 @@ export type BreakpointSlots = typeof __propDef.slots;
21
21
  *
22
22
  * Displays the current breakpoint and `window.innerWidth`, based on the `breakpoints` provided. Defaults to [TailwindCSS breakpoint sizes](https://tailwindcss.com/docs/responsive-design).
23
23
  *
24
- * ```svelte
25
- * <script lang="ts">
26
- * import { dev } from "$app/environment"; // SvelteKit Example
27
- * </script>
28
- *
29
- * {#if dev}
30
- * <Breakpoint
31
- * class="fixed bottom-4 right-4 rounded border bg-white px-2 py-1 font-mono tabular-nums shadow"
32
- * />
33
- * {/if}
34
- * ```
24
+ * With SvelteKit, this component can be wrapped in an `{#if dev}` block that checks for the [dev module](https://kit.svelte.dev/docs/modules#$app-environment-dev), to show only during development.
35
25
  *
36
26
  * @props
37
27
  *
@@ -7,7 +7,6 @@ Displays when the parent element is right clicked, or long pressed on mobile.
7
7
 
8
8
  @props
9
9
 
10
- - `classNoscript` - `noscript` class
11
10
  - `class`
12
11
  - `display` - controls `display` css property
13
12
  - `id`
@@ -50,7 +49,6 @@ let className = "";
50
49
  export { className as class };
51
50
  export let id = "";
52
51
  export let display = false;
53
- export let classNoscript = "";
54
52
  export let transition = { duration };
55
53
  let contextMenu;
56
54
  let base;
@@ -124,8 +122,6 @@ onMount(() => {
124
122
  </div>
125
123
  {/if}
126
124
 
127
- <noscript><div class={classNoscript}>{messageNoScript}</div></noscript>
128
-
129
125
  <style>
130
126
  span {
131
127
  width: 0;
@@ -5,7 +5,6 @@ declare const __propDef: {
5
5
  class?: string | undefined;
6
6
  id?: string | undefined;
7
7
  /** controls `display` css property */ display?: boolean | undefined;
8
- /** `noscript` class */ classNoscript?: string | undefined;
9
8
  /** fades the content, set to `false` to remove */ transition?: false | FadeParams | undefined;
10
9
  };
11
10
  events: {
@@ -25,7 +24,6 @@ export type ContextMenuSlots = typeof __propDef.slots;
25
24
  *
26
25
  * @props
27
26
  *
28
- * - `classNoscript` - `noscript` class
29
27
  * - `class`
30
28
  * - `display` - controls `display` css property
31
29
  * - `id`
@@ -3,7 +3,7 @@
3
3
 
4
4
  ### CopyButton
5
5
 
6
- Uses the navigator api to copy text to the clipboard.
6
+ Uses the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to copy text to the clipboard.
7
7
 
8
8
  @props
9
9
 
@@ -21,7 +21,7 @@ export type CopyButtonSlots = typeof __propDef.slots;
21
21
  /**
22
22
  * ### CopyButton
23
23
  *
24
- * Uses the navigator api to copy text to the clipboard.
24
+ * Uses the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText) to copy text to the clipboard.
25
25
  *
26
26
  * @props
27
27
  *
@@ -28,15 +28,18 @@ Data table to display an array of JS objects. Click a column header to sort.
28
28
  - `data` - a list of objects to render in the table
29
29
  - `idTable` - `table` id
30
30
  - `id`
31
- - `paginate` - number of rows to show on each page, defaults to `0` - no pagination
32
- - `sortBy` - column to sort by--defaults to first column
31
+ - `maxRows` - maximum number of rows to show on each page, defaults to `0` - no pagination
32
+ - `sortBy` - column to sort by, defaults to first column
33
33
 
34
34
  @slots
35
35
 
36
- | name | purpose | default value |
37
- | ---------- | ------------------------ | ------------- |
38
- | `previous` | previous button contents | `Previous` |
39
- | `next` | next button contents | `Next` |
36
+ | name | purpose | default value | slot props |
37
+ | ------------ | ------------------------ | -------------------------------- | ------------------------------ |
38
+ | `next` | next button contents | `Next` | `currentPage` |
39
+ | `pageNumber` | page numbers | `currentPage` / `numberOfPages` | `currentPage`, `numberOfPages` |
40
+ | `previous` | previous button contents | `Previous` | `currentPage` |
41
+ | `td` | td contents | `Previous` | `column`, `row` |
42
+ | `th` | th contents | `Previous` | `column` |
40
43
 
41
44
  @example
42
45
 
@@ -46,6 +49,7 @@ Data table to display an array of JS objects. Click a column header to sort.
46
49
  </script>
47
50
 
48
51
  <DataTable
52
+ class="mb-12"
49
53
  data={[
50
54
  { make: "Honda", model: "CR-V", year: 2011, awd: true },
51
55
  { make: "Volvo", model: "XC-40", year: 2024, awd: true },
@@ -57,15 +61,49 @@ Data table to display an array of JS objects. Click a column header to sort.
57
61
  { make: "GMC", model: "Acadia", year: 2008, awd: true },
58
62
  { make: "BMW", model: "X3", year: 2023, awd: true },
59
63
  ]}
60
- sortBy="make"
61
- paginate={4}
64
+ />
65
+
66
+ <DataTable
67
+ data={[
68
+ { make: "Honda", model: "CR-V", year: 2011, awd: true },
69
+ { make: "Volvo", model: "XC-40", year: 2024, awd: true },
70
+ { make: "Ferrari", model: "458 Italia", year: 2015, awd: false },
71
+ { make: "Chevrolet", model: "Silverado", year: 2022, awd: true },
72
+ { make: "Ford", model: "Model A", year: 1931, awd: false },
73
+ { make: "Subaru", model: "Outback", year: 2021, awd: true },
74
+ { make: "Ford", model: "Bronco", year: 1970, awd: true },
75
+ { make: "GMC", model: "Acadia", year: 2008, awd: true },
76
+ { make: "BMW", model: "X3", year: 2023, awd: true },
77
+ ]}
78
+ sortBy="year"
79
+ maxRows={4}
62
80
  class="tabular-nums"
63
- classTh="cursor-pointer uppercase"
81
+ classTh="cursor-pointer"
64
82
  classThSorted="underline"
65
83
  classTbodyTr="transition hover:bg-neutral-50"
66
84
  classFooter="flex justify-between items-center"
67
85
  classButton="btn"
68
- />
86
+ >
87
+ <svelte:fragment slot="th" let:column>
88
+ {#if column === "awd"}
89
+ <span class="uppercase">{column}</span>
90
+ {:else}
91
+ {column}
92
+ {/if}
93
+ </svelte:fragment>
94
+ <svelte:fragment slot="td" let:column let:row>
95
+ {@const item = row[column]}
96
+ {#if typeof item === "boolean"}
97
+ {#if item}
98
+ Yes
99
+ {:else}
100
+ No
101
+ {/if}
102
+ {:else}
103
+ {item}
104
+ {/if}
105
+ </svelte:fragment>
106
+ </DataTable>
69
107
  ```
70
108
  -->
71
109
 
@@ -97,12 +135,12 @@ export let classButton = "";
97
135
  export let classFooter = "";
98
136
  export let classPageNumber = "";
99
137
  export let classPageControls = "";
100
- export let paginate = 0;
138
+ export let maxRows = 0;
101
139
  export let currentPage = 1;
102
140
  export let classNoscript = "";
103
141
  let clientJs = false;
104
142
  $:
105
- numberOfPages = Math.floor(data.length / paginate) + 1;
143
+ numberOfPages = Math.floor(data.length / maxRows) + 1;
106
144
  const sort = (column, toggleAscending = true) => {
107
145
  if (column === sortBy && toggleAscending) {
108
146
  ascending = !ascending;
@@ -150,7 +188,7 @@ onMount(() => clientJs = true);
150
188
  class="{classTh} {sortBy === column ? classThSorted : ''}"
151
189
  on:click={() => sort(column)}
152
190
  >
153
- {column}
191
+ <slot name="th" {column}>{column}</slot>
154
192
  </th>
155
193
  {/each}
156
194
  </tr>
@@ -158,12 +196,12 @@ onMount(() => clientJs = true);
158
196
  <tbody class={classTbody}>
159
197
  {#each data as row, i}
160
198
  {@const showRow =
161
- i < paginate * currentPage && i >= paginate * (currentPage - 1)}
162
- {#if paginate ? showRow : true}
199
+ i < maxRows * currentPage && i >= maxRows * (currentPage - 1)}
200
+ {#if maxRows ? showRow : true}
163
201
  <tr class={classTbodyTr}>
164
202
  {#each columns as column}
165
203
  <td class="{classTd} {sortBy === column ? classTdSorted : ''}">
166
- {row[column]}
204
+ <slot name="td" {row} {column}>{row[column]}</slot>
167
205
  </td>
168
206
  {/each}
169
207
  </tr>
@@ -172,23 +210,29 @@ onMount(() => clientJs = true);
172
210
  </tbody>
173
211
  </table>
174
212
 
175
- {#if paginate}
213
+ {#if maxRows}
176
214
  <div class={classFooter}>
177
- <div class={classPageNumber}>{currentPage} / {numberOfPages}</div>
215
+ <div class={classPageNumber}>
216
+ <slot name="pageNumber" {currentPage} {numberOfPages}>
217
+ {currentPage} / {numberOfPages}
218
+ </slot>
219
+ </div>
178
220
  <div class={classPageControls}>
179
221
  <button
222
+ type="button"
180
223
  class={classButton}
181
224
  disabled={!clientJs || currentPage < 2}
182
225
  on:click={() => currentPage--}
183
226
  >
184
- <slot name="previous">Previous</slot>
227
+ <slot name="previous" {currentPage}>Previous</slot>
185
228
  </button>
186
229
  <button
230
+ type="button"
187
231
  class={classButton}
188
232
  disabled={!clientJs || currentPage >= numberOfPages}
189
233
  on:click={() => currentPage++}
190
234
  >
191
- <slot name="next">Next</slot>
235
+ <slot name="next" {currentPage}>Next</slot>
192
236
  </button>
193
237
  </div>
194
238
  </div>
@@ -8,7 +8,7 @@ declare const __propDef: {
8
8
  id?: string | undefined;
9
9
  /** a list of objects to render in the table */ data: DataTableRow<any>[];
10
10
  /** table columns, in order */ columns?: string[] | undefined;
11
- /** column to sort by--defaults to first column */ sortBy?: string | undefined;
11
+ /** column to sort by, defaults to first column */ sortBy?: string | undefined;
12
12
  /** default sort order */ ascending?: boolean | undefined;
13
13
  /** `table` class */ classTable?: string | undefined;
14
14
  /** `table` id */ idTable?: string | undefined;
@@ -24,7 +24,7 @@ declare const __propDef: {
24
24
  /** `footer` class */ classFooter?: string | undefined;
25
25
  /** class of `div` wrapping page numbers */ classPageNumber?: string | undefined;
26
26
  /** class of `div` that wraps the "Previous" and "Next" buttons */ classPageControls?: string | undefined;
27
- /** number of rows to show on each page, defaults to `0` - no pagination */ paginate?: number | undefined;
27
+ /** maximum number of rows to show on each page, defaults to `0` - no pagination */ maxRows?: number | undefined;
28
28
  /** current page, defaults to `1` */ currentPage?: number | undefined;
29
29
  /** `noscript` class */ classNoscript?: string | undefined;
30
30
  };
@@ -32,8 +32,23 @@ declare const __propDef: {
32
32
  [evt: string]: CustomEvent<any>;
33
33
  };
34
34
  slots: {
35
- previous: {};
36
- next: {};
35
+ th: {
36
+ column: string;
37
+ };
38
+ td: {
39
+ row: DataTableRow<any>;
40
+ column: string;
41
+ };
42
+ pageNumber: {
43
+ currentPage: number;
44
+ numberOfPages: number;
45
+ };
46
+ previous: {
47
+ currentPage: number;
48
+ };
49
+ next: {
50
+ currentPage: number;
51
+ };
37
52
  };
38
53
  };
39
54
  export type DataTableProps = typeof __propDef.props;
@@ -67,15 +82,18 @@ export type DataTableSlots = typeof __propDef.slots;
67
82
  * - `data` - a list of objects to render in the table
68
83
  * - `idTable` - `table` id
69
84
  * - `id`
70
- * - `paginate` - number of rows to show on each page, defaults to `0` - no pagination
71
- * - `sortBy` - column to sort by--defaults to first column
85
+ * - `maxRows` - maximum number of rows to show on each page, defaults to `0` - no pagination
86
+ * - `sortBy` - column to sort by, defaults to first column
72
87
  *
73
88
  * @slots
74
89
  *
75
- * | name | purpose | default value |
76
- * | ---------- | ------------------------ | ------------- |
77
- * | `previous` | previous button contents | `Previous` |
78
- * | `next` | next button contents | `Next` |
90
+ * | name | purpose | default value | slot props |
91
+ * | ------------ | ------------------------ | -------------------------------- | ------------------------------ |
92
+ * | `next` | next button contents | `Next` | `currentPage` |
93
+ * | `pageNumber` | page numbers | `currentPage` / `numberOfPages` | `currentPage`, `numberOfPages` |
94
+ * | `previous` | previous button contents | `Previous` | `currentPage` |
95
+ * | `td` | td contents | `Previous` | `column`, `row` |
96
+ * | `th` | th contents | `Previous` | `column` |
79
97
  *
80
98
  * @example
81
99
  *
@@ -85,6 +103,7 @@ export type DataTableSlots = typeof __propDef.slots;
85
103
  * </script>
86
104
  *
87
105
  * <DataTable
106
+ * class="mb-12"
88
107
  * data={[
89
108
  * { make: "Honda", model: "CR-V", year: 2011, awd: true },
90
109
  * { make: "Volvo", model: "XC-40", year: 2024, awd: true },
@@ -96,15 +115,49 @@ export type DataTableSlots = typeof __propDef.slots;
96
115
  * { make: "GMC", model: "Acadia", year: 2008, awd: true },
97
116
  * { make: "BMW", model: "X3", year: 2023, awd: true },
98
117
  * ]}
99
- * sortBy="make"
100
- * paginate={4}
118
+ * />
119
+ *
120
+ * <DataTable
121
+ * data={[
122
+ * { make: "Honda", model: "CR-V", year: 2011, awd: true },
123
+ * { make: "Volvo", model: "XC-40", year: 2024, awd: true },
124
+ * { make: "Ferrari", model: "458 Italia", year: 2015, awd: false },
125
+ * { make: "Chevrolet", model: "Silverado", year: 2022, awd: true },
126
+ * { make: "Ford", model: "Model A", year: 1931, awd: false },
127
+ * { make: "Subaru", model: "Outback", year: 2021, awd: true },
128
+ * { make: "Ford", model: "Bronco", year: 1970, awd: true },
129
+ * { make: "GMC", model: "Acadia", year: 2008, awd: true },
130
+ * { make: "BMW", model: "X3", year: 2023, awd: true },
131
+ * ]}
132
+ * sortBy="year"
133
+ * maxRows={4}
101
134
  * class="tabular-nums"
102
- * classTh="cursor-pointer uppercase"
135
+ * classTh="cursor-pointer"
103
136
  * classThSorted="underline"
104
137
  * classTbodyTr="transition hover:bg-neutral-50"
105
138
  * classFooter="flex justify-between items-center"
106
139
  * classButton="btn"
107
- * />
140
+ * >
141
+ * <svelte:fragment slot="th" let:column>
142
+ * {#if column === "awd"}
143
+ * <span class="uppercase">{column}</span>
144
+ * {:else}
145
+ * {column}
146
+ * {/if}
147
+ * </svelte:fragment>
148
+ * <svelte:fragment slot="td" let:column let:row>
149
+ * {@const item = row[column]}
150
+ * {#if typeof item === "boolean"}
151
+ * {#if item}
152
+ * Yes
153
+ * {:else}
154
+ * No
155
+ * {/if}
156
+ * {:else}
157
+ * {item}
158
+ * {/if}
159
+ * </svelte:fragment>
160
+ * </DataTable>
108
161
  * ```
109
162
  */
110
163
  export default class DataTable extends SvelteComponent<DataTableProps, DataTableEvents, DataTableSlots> {
@@ -38,10 +38,9 @@ Make the document or a specific element fullscreen.
38
38
  bind:this={fullscreenDiv}
39
39
  class="mt-4 rounded bg-neutral-800 p-4 text-neutral-50"
40
40
  >
41
- <div class="mb-2">Target element fullscreen</div>
41
+ <div class="mb-2">Target element</div>
42
42
  <FullscreenButton target={fullscreenDiv} class="btn btn-s bg-neutral-50">
43
- <span>Enable Element Fullscreen</span>
44
- <span slot="enabled">Exit Element Fullscreen</span>
43
+ Enable Element Fullscreen
45
44
  </FullscreenButton>
46
45
  </div>
47
46
  ```
@@ -57,10 +57,9 @@ export type FullscreenButtonSlots = typeof __propDef.slots;
57
57
  * bind:this={fullscreenDiv}
58
58
  * class="mt-4 rounded bg-neutral-800 p-4 text-neutral-50"
59
59
  * >
60
- * <div class="mb-2">Target element fullscreen</div>
60
+ * <div class="mb-2">Target element</div>
61
61
  * <FullscreenButton target={fullscreenDiv} class="btn btn-s bg-neutral-50">
62
- * <span>Enable Element Fullscreen</span>
63
- * <span slot="enabled">Exit Element Fullscreen</span>
62
+ * Enable Element Fullscreen
64
63
  * </FullscreenButton>
65
64
  * </div>
66
65
  * ```
@@ -3,7 +3,7 @@
3
3
 
4
4
  ### Popover
5
5
 
6
- Displays a popover relatively positioned to the button.
6
+ Displays a popover relatively positioned to the target.
7
7
 
8
8
  @props
9
9
 
@@ -22,7 +22,7 @@ export type PopoverSlots = typeof __propDef.slots;
22
22
  /**
23
23
  * ### Popover
24
24
  *
25
- * Displays a popover relatively positioned to the button.
25
+ * Displays a popover relatively positioned to the target.
26
26
  *
27
27
  * @props
28
28
  *
@@ -3,7 +3,7 @@
3
3
 
4
4
  ### ShareButton
5
5
 
6
- Uses the navigator api 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) 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.
7
7
 
8
8
  @props
9
9
 
@@ -22,7 +22,7 @@ export type ShareButtonSlots = typeof __propDef.slots;
22
22
  /**
23
23
  * ### ShareButton
24
24
  *
25
- * Uses the navigator api to share or copy a url link depending on browser support.
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.
26
26
  *
27
27
  * @props
28
28
  *
@@ -11,9 +11,8 @@ Creates a sheet element based on the `position` provided.
11
11
  - `class`
12
12
  - `display` - controls whether the sheet is displayed
13
13
  - `id`
14
- - `onClickClose` - close on click, defaults to `false` - only closes if clicked outside
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
- - `size` - width/height of sheet based on the `side` - can also use css instead
17
16
  - `transitionSheet` - slides the sheet, set to `false` to remove
18
17
  - `transition` - fades the entire component, set to `false` to remove
19
18
 
@@ -28,7 +27,6 @@ Creates a sheet element based on the `position` provided.
28
27
  ```svelte
29
28
  <script lang="ts">
30
29
  import { Sheet } from "drab";
31
- import { X } from "../../site/svg/X.svelte";
32
30
 
33
31
  let display = false;
34
32
  </script>
@@ -46,13 +44,8 @@ Creates a sheet element based on the `position` provided.
46
44
  >
47
45
  <div class="mb-4 flex items-center justify-between">
48
46
  <h2 class="my-0">Sheet</h2>
49
- <button
50
- type="button"
51
- title="Close"
52
- class="btn btn-s"
53
- on:click={() => (display = false)}
54
- >
55
- <X />
47
+ <button type="button" class="btn btn-s" on:click={() => (display = false)}>
48
+ Close
56
49
  </button>
57
50
  </div>
58
51
  <div>
@@ -80,15 +73,9 @@ export let classSheet = "";
80
73
  export let display = false;
81
74
  export let transition = { duration };
82
75
  export let position = "right";
83
- export let size = 488;
76
+ export let maxSize = 488;
84
77
  export let transitionSheet = { duration };
85
- export let onClickClose = false;
86
78
  let sheet;
87
- const clickOutside = (e) => {
88
- if (e.target instanceof Node && !sheet.contains(e.target) || onClickClose) {
89
- display = false;
90
- }
91
- };
92
79
  const onKeyDown = (e) => {
93
80
  if (e.key === "Escape") {
94
81
  display = false;
@@ -96,13 +83,13 @@ const onKeyDown = (e) => {
96
83
  };
97
84
  if (transitionSheet && !transitionSheet.x && !transitionSheet.y) {
98
85
  if (position === "bottom") {
99
- transitionSheet.y = size;
86
+ transitionSheet.y = maxSize;
100
87
  } else if (position === "top") {
101
- transitionSheet.y = -size;
88
+ transitionSheet.y = -maxSize;
102
89
  } else if (position === "right") {
103
- transitionSheet.x = size;
90
+ transitionSheet.x = maxSize;
104
91
  } else {
105
- transitionSheet.x = -size;
92
+ transitionSheet.x = -maxSize;
106
93
  }
107
94
  }
108
95
  onMount(() => {
@@ -119,12 +106,11 @@ onMount(() => {
119
106
 
120
107
  {#if display}
121
108
  <div
122
- role="button"
123
- tabindex="0"
124
- on:click={clickOutside}
125
- on:keydown={onKeyDown}
126
109
  transition:fade={transition ? transition : { duration: 0 }}
127
110
  class="d-backdrop {className}"
111
+ class:d-backdrop-bottom={position === "bottom"}
112
+ class:d-backdrop-top={position === "top"}
113
+ class:d-backdrop-right={position === "right"}
128
114
  {id}
129
115
  >
130
116
  <div
@@ -132,47 +118,59 @@ onMount(() => {
132
118
  bind:this={sheet}
133
119
  transition:fly={transitionSheet ? transitionSheet : { duration: 0 }}
134
120
  style={position === "top" || position === "bottom"
135
- ? `max-height: ${size}px;`
136
- : `max-width: ${size}px`}
121
+ ? `max-height: ${maxSize}px;`
122
+ : `max-width: ${maxSize}px`}
137
123
  class="d-sheet {classSheet}"
138
- class:d-bottom={position === "bottom"}
139
- class:d-top={position === "top"}
140
- class:d-left={position === "left"}
141
- class:d-right={position === "right"}
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"}
142
128
  >
143
129
  <slot>Content</slot>
144
130
  </div>
131
+ <button title="Close" on:click={() => (display = false)}></button>
145
132
  </div>
146
133
  {/if}
147
134
 
148
135
  <style>
136
+ button {
137
+ flex-grow: 1;
138
+ }
149
139
  .d-backdrop {
150
140
  position: fixed;
151
- display: grid;
141
+ display: flex;
152
142
  z-index: 40;
153
143
  top: 0;
154
144
  bottom: 0;
155
145
  left: 0;
156
146
  right: 0;
157
147
  overflow: hidden;
158
- cursor: default;
148
+ }
149
+ .d-backdrop-bottom {
150
+ flex-direction: column-reverse;
151
+ }
152
+ .d-backdrop-top {
153
+ flex-direction: column;
154
+ }
155
+ .d-backdrop-right {
156
+ flex-direction: row-reverse;
159
157
  }
160
158
  .d-sheet {
161
159
  margin: auto;
162
160
  }
163
- .d-bottom {
161
+ .d-sheet-bottom {
164
162
  margin-bottom: 0;
165
163
  width: 100%;
166
164
  }
167
- .d-top {
165
+ .d-sheet-top {
168
166
  margin-top: 0;
169
167
  width: 100%;
170
168
  }
171
- .d-right {
169
+ .d-sheet-right {
172
170
  margin-right: 0;
173
171
  height: 100%;
174
172
  }
175
- .d-left {
173
+ .d-sheet-left {
176
174
  margin-left: 0;
177
175
  height: 100%;
178
176
  }
@@ -8,9 +8,8 @@ declare const __propDef: {
8
8
  /** controls whether the sheet is displayed*/ display?: boolean | undefined;
9
9
  /** fades the entire component, set to `false` to remove */ transition?: false | FadeParams | undefined;
10
10
  /** determines the position of sheet */ position?: "top" | "bottom" | "left" | "right" | undefined;
11
- /** width/height of sheet based on the `side` - can also use css instead */ size?: number | undefined;
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;
13
- /** close on click, defaults to `false` - only closes if clicked outside */ onClickClose?: boolean | undefined;
14
13
  };
15
14
  events: {
16
15
  [evt: string]: CustomEvent<any>;
@@ -33,9 +32,8 @@ export type SheetSlots = typeof __propDef.slots;
33
32
  * - `class`
34
33
  * - `display` - controls whether the sheet is displayed
35
34
  * - `id`
36
- * - `onClickClose` - close on click, defaults to `false` - only closes if clicked outside
35
+ * - `maxSize` - max width/height of sheet based on the `side` - can also use css instead
37
36
  * - `position` - determines the position of sheet
38
- * - `size` - width/height of sheet based on the `side` - can also use css instead
39
37
  * - `transitionSheet` - slides the sheet, set to `false` to remove
40
38
  * - `transition` - fades the entire component, set to `false` to remove
41
39
  *
@@ -50,7 +48,6 @@ export type SheetSlots = typeof __propDef.slots;
50
48
  * ```svelte
51
49
  * <script lang="ts">
52
50
  * import { Sheet } from "drab";
53
- * import { X } from "../../site/svg/X.svelte";
54
51
  *
55
52
  * let display = false;
56
53
  * </script>
@@ -68,13 +65,8 @@ export type SheetSlots = typeof __propDef.slots;
68
65
  * >
69
66
  * <div class="mb-4 flex items-center justify-between">
70
67
  * <h2 class="my-0">Sheet</h2>
71
- * <button
72
- * type="button"
73
- * title="Close"
74
- * class="btn btn-s"
75
- * on:click={() => (display = false)}
76
- * >
77
- * <X />
68
+ * <button type="button" class="btn btn-s" on:click={() => (display = false)}>
69
+ * Close
78
70
  * </button>
79
71
  * </div>
80
72
  * <div>
@@ -3,7 +3,7 @@
3
3
 
4
4
  ### Tabs
5
5
 
6
- Displays tabs and the active tab's content.
6
+ Displays tabs and the selected tab's content.
7
7
 
8
8
  @props
9
9
 
@@ -15,15 +15,16 @@ Displays tabs and the active tab's content.
15
15
  - `classTab` - class of all title `button`s
16
16
  - `class`
17
17
  - `id`
18
- - `selectedIndex` - index of selected tab, defaults to 0
19
- - `tabs` - array of tabs
18
+ - `selectedIndex` - index of selected tab, defaults to `0`
19
+ - `tabs` - array of `TabsTab` objects
20
+ - `transition` - fades the panel content, set to `false` to remove
20
21
 
21
22
  @slots
22
23
 
23
- | name | purpose | default value | slot props |
24
- | --------- | --------------------- | ------------------ | --------------- |
25
- | `default` | active item's content | `activeItem.panel` | `activeItem` |
26
- | `tab` | title of each tab | `item.tab` | `item`, `index` |
24
+ | name | purpose | default value | slot props |
25
+ | ------- | ------------------ | ------------------- | ---------------------- |
26
+ | `panel` | active tab's panel | `selectedTab.panel` | `selectedTab`, `index` |
27
+ | `tab` | title of each tab | `tab.tab` | `tab`, `index` |
27
28
 
28
29
  @example
29
30
 
@@ -60,16 +61,17 @@ Displays tabs and the active tab's content.
60
61
  data: { component: FullscreenButton },
61
62
  },
62
63
  ]}
63
- let:selectedTab
64
64
  >
65
- <svelte:fragment slot="tab" let:item let:index>
66
- {item.tab}
65
+ <svelte:fragment slot="tab" let:tab let:index>
66
+ {tab.tab}
67
67
  {index + 1}
68
68
  </svelte:fragment>
69
- <div class="mb-2">{selectedTab.panel}</div>
70
- {#if selectedTab.data?.component}
71
- <svelte:component this={selectedTab.data.component} class="btn" />
72
- {/if}
69
+ <svelte:fragment slot="panel" let:selectedTab>
70
+ <div class="mb-2">{selectedTab.panel}</div>
71
+ {#if selectedTab.data?.component}
72
+ <svelte:component this={selectedTab.data.component} class="btn" />
73
+ {/if}
74
+ </svelte:fragment>
73
75
  </Tabs>
74
76
  ```
75
77
  -->
@@ -78,6 +80,9 @@ Displays tabs and the active tab's content.
78
80
 
79
81
  <script>import { onMount } from "svelte";
80
82
  import { messageNoScript } from "../util/messages";
83
+ import { fade } from "svelte/transition";
84
+ import { duration } from "../util/transition";
85
+ import { prefersReducedMotion } from "../util/accessibility";
81
86
  let className = "";
82
87
  export { className as class };
83
88
  export let id = "";
@@ -89,15 +94,20 @@ export let classNoscript = "";
89
94
  export let classTabPanel = "";
90
95
  export let tabs;
91
96
  export let selectedIndex = 0;
97
+ export let transition = { duration };
92
98
  let clientJs = false;
93
- $:
94
- selectedTab = tabs[selectedIndex];
95
- onMount(() => clientJs = true);
99
+ onMount(() => {
100
+ if (prefersReducedMotion()) {
101
+ if (transition)
102
+ transition.duration = 0;
103
+ }
104
+ clientJs = true;
105
+ });
96
106
  </script>
97
107
 
98
108
  <div class={className} {id}>
99
109
  <div class={classTabList} role="tablist">
100
- {#each tabs as item, index}
110
+ {#each tabs as tab, index}
101
111
  <button
102
112
  role="tab"
103
113
  tabindex={index === selectedIndex ? 0 : -1}
@@ -109,13 +119,22 @@ onMount(() => clientJs = true);
109
119
  : ''} {selectedIndex !== index ? classTabInactive : ''}"
110
120
  on:click={() => (selectedIndex = index)}
111
121
  >
112
- <slot name="tab" {item} {index}>{item.tab}</slot>
122
+ <slot name="tab" {tab} {index}>{tab.tab}</slot>
113
123
  </button>
114
124
  {/each}
115
125
  </div>
116
- <div class={classTabPanel} role="tabpanel" id="tabpanel">
117
- <slot {selectedTab}>{selectedTab.panel}</slot>
118
- </div>
126
+ {#each tabs as tab, index}
127
+ {#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>
135
+ </div>
136
+ {/if}
137
+ {/each}
119
138
  <noscript>
120
139
  <div class={classNoscript}>{messageNoScript}</div>
121
140
  </noscript>
@@ -7,6 +7,7 @@ export interface TabsTab<T = any> {
7
7
  /** any data to pass back to the parent */
8
8
  data?: T;
9
9
  }
10
+ import { type FadeParams } from "svelte/transition";
10
11
  declare const __propDef: {
11
12
  props: {
12
13
  class?: string | undefined;
@@ -17,19 +18,21 @@ declare const __propDef: {
17
18
  /** class of all the inactive tabs' `button`s */ classTabInactive?: string | undefined;
18
19
  /** `noscript` class */ classNoscript?: string | undefined;
19
20
  /** class of `div` that wraps the slotted content */ classTabPanel?: string | undefined;
20
- /** array of tabs */ tabs: TabsTab[];
21
- /** index of selected tab, defaults to 0 */ selectedIndex?: number | undefined;
21
+ /** array of `TabsTab` objects */ tabs: TabsTab[];
22
+ /** index of selected tab, defaults to `0` */ selectedIndex?: number | undefined;
23
+ /** fades the panel content, set to `false` to remove */ transition?: false | FadeParams | undefined;
22
24
  };
23
25
  events: {
24
26
  [evt: string]: CustomEvent<any>;
25
27
  };
26
28
  slots: {
27
29
  tab: {
28
- item: TabsTab<any>;
30
+ tab: TabsTab<any>;
29
31
  index: any;
30
32
  };
31
- default: {
33
+ panel: {
32
34
  selectedTab: TabsTab<any>;
35
+ index: any;
33
36
  };
34
37
  };
35
38
  };
@@ -39,7 +42,7 @@ export type TabsSlots = typeof __propDef.slots;
39
42
  /**
40
43
  * ### Tabs
41
44
  *
42
- * Displays tabs and the active tab's content.
45
+ * Displays tabs and the selected tab's content.
43
46
  *
44
47
  * @props
45
48
  *
@@ -51,15 +54,16 @@ export type TabsSlots = typeof __propDef.slots;
51
54
  * - `classTab` - class of all title `button`s
52
55
  * - `class`
53
56
  * - `id`
54
- * - `selectedIndex` - index of selected tab, defaults to 0
55
- * - `tabs` - array of tabs
57
+ * - `selectedIndex` - index of selected tab, defaults to `0`
58
+ * - `tabs` - array of `TabsTab` objects
59
+ * - `transition` - fades the panel content, set to `false` to remove
56
60
  *
57
61
  * @slots
58
62
  *
59
- * | name | purpose | default value | slot props |
60
- * | --------- | --------------------- | ------------------ | --------------- |
61
- * | `default` | active item's content | `activeItem.panel` | `activeItem` |
62
- * | `tab` | title of each tab | `item.tab` | `item`, `index` |
63
+ * | name | purpose | default value | slot props |
64
+ * | ------- | ------------------ | ------------------- | ---------------------- |
65
+ * | `panel` | active tab's panel | `selectedTab.panel` | `selectedTab`, `index` |
66
+ * | `tab` | title of each tab | `tab.tab` | `tab`, `index` |
63
67
  *
64
68
  * @example
65
69
  *
@@ -96,16 +100,17 @@ export type TabsSlots = typeof __propDef.slots;
96
100
  * data: { component: FullscreenButton },
97
101
  * },
98
102
  * ]}
99
- * let:selectedTab
100
103
  * >
101
- * <svelte:fragment slot="tab" let:item let:index>
102
- * {item.tab}
104
+ * <svelte:fragment slot="tab" let:tab let:index>
105
+ * {tab.tab}
103
106
  * {index + 1}
104
107
  * </svelte:fragment>
105
- * <div class="mb-2">{selectedTab.panel}</div>
106
- * {#if selectedTab.data?.component}
107
- * <svelte:component this={selectedTab.data.component} class="btn" />
108
- * {/if}
108
+ * <svelte:fragment slot="panel" let:selectedTab>
109
+ * <div class="mb-2">{selectedTab.panel}</div>
110
+ * {#if selectedTab.data?.component}
111
+ * <svelte:component this={selectedTab.data.component} class="btn" />
112
+ * {/if}
113
+ * </svelte:fragment>
109
114
  * </Tabs>
110
115
  * ```
111
116
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drab",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "An unstyled Svelte component library",
5
5
  "keywords": [
6
6
  "components",