@geoffcox/sterling-svelte 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lists/List.svelte CHANGED
@@ -1,4 +1,6 @@
1
1
  <script>import { createEventDispatcher } from "svelte";
2
+ import { v4 as uuid } from "uuid";
3
+ import Label from "../display/Label.svelte";
2
4
  export let disabled = false;
3
5
  export let items = [];
4
6
  export let horizontal = false;
@@ -7,6 +9,7 @@ export let selectedItem = void 0;
7
9
  $: {
8
10
  selectedItem = items[selectedIndex];
9
11
  }
12
+ const inputId = uuid();
10
13
  let listRef;
11
14
  let itemRefs = {};
12
15
  let focusVisible = false;
@@ -90,232 +93,158 @@ const onKeydown = (event) => {
90
93
  @component
91
94
  A list of items where a single item can be selected.
92
95
  -->
93
- {#if $$slots.label}
94
- <!-- svelte-ignore a11y-label-has-associated-control -->
95
- <label class="sterling-list-label" class:horizontal class:disabled>
96
- <div class="label-content" class:disabled>
97
- <slot name="label" />
98
- </div>
99
- <div
100
- bind:this={listRef}
101
- class="sterling-list labeled"
102
- class:disabled
103
- class:focus-visible={focusVisible}
104
- class:horizontal
105
- role="listbox"
106
- tabindex={!disabled ? 0 : undefined}
107
- on:blur
108
- on:click
109
- on:copy
110
- on:cut
111
- on:dblclick
112
- on:focus
113
- on:focusin
114
- on:focusout
115
- on:keydown={onKeydown}
116
- on:keydown
117
- on:keypress
118
- on:keyup
119
- on:mousedown
120
- on:mouseenter
121
- on:mouseleave
122
- on:mousemove
123
- on:mouseover
124
- on:mouseout
125
- on:mouseup
126
- on:scroll
127
- on:wheel
128
- on:paste
129
- {...$$restProps}
130
- >
131
- {#each items as item, index (item)}
132
- {@const selected = selectedIndex === index}
133
- <!-- svelte-ignore a11y-click-events-have-key-events -->
134
- <div
135
- bind:this={itemRefs[index]}
136
- aria-selected={disabled ? undefined : selected}
137
- class="list-item"
138
- class:selected
139
- class:disabled
140
- data-index={index + 1}
141
- role="option"
142
- on:click={() => onItemClick(index)}
143
- >
144
- <slot {disabled} {index} {item} {selected}>
145
- {item}
146
- </slot>
147
- </div>
148
- {/each}
149
- </div>
150
- </label>
151
- {:else}
152
- <div
153
- bind:this={listRef}
154
- class="sterling-list"
155
- class:disabled
156
- class:focus-visible={focusVisible}
157
- class:horizontal
158
- role="listbox"
159
- tabindex={!disabled ? 0 : undefined}
160
- on:blur
161
- on:click
162
- on:copy
163
- on:cut
164
- on:dblclick
165
- on:focus
166
- on:focusin
167
- on:focusout
168
- on:keydown={onKeydown}
169
- on:keydown
170
- on:keypress
171
- on:keyup
172
- on:mousedown
173
- on:mouseenter
174
- on:mouseleave
175
- on:mousemove
176
- on:mouseover
177
- on:mouseout
178
- on:mouseup
179
- on:scroll
180
- on:wheel
181
- on:paste
182
- {...$$restProps}
183
- >
184
- {#each items as item, index (item)}
185
- {@const selected = selectedIndex === index}
186
- <!-- svelte-ignore a11y-click-events-have-key-events -->
187
- <div
188
- bind:this={itemRefs[index]}
189
- aria-selected={disabled ? undefined : selected}
190
- class="list-item"
191
- class:selected
192
- class:disabled
193
- data-index={index + 1}
194
- role="option"
195
- on:click={() => onItemClick(index)}
196
- >
197
- <slot {disabled} {index} {item} {selected}>
198
- {item}
199
- </slot>
200
- </div>
201
- {/each}
202
- </div>
203
- {/if}
96
+ <div class="sterling-list" class:horizontal class:disabled>
97
+ {#if $$slots.label}
98
+ <div class="label">
99
+ <Label {disabled} for={inputId}>
100
+ <slot name="label" />
101
+ </Label>
102
+ </div>
103
+ {/if}
104
+ <div
105
+ bind:this={listRef}
106
+ class="list labeled"
107
+ class:disabled
108
+ class:focus-visible={focusVisible}
109
+ class:horizontal
110
+ role="listbox"
111
+ tabindex={!disabled ? 0 : undefined}
112
+ on:blur
113
+ on:click
114
+ on:copy
115
+ on:cut
116
+ on:dblclick
117
+ on:focus
118
+ on:focusin
119
+ on:focusout
120
+ on:keydown={onKeydown}
121
+ on:keydown
122
+ on:keypress
123
+ on:keyup
124
+ on:mousedown
125
+ on:mouseenter
126
+ on:mouseleave
127
+ on:mousemove
128
+ on:mouseover
129
+ on:mouseout
130
+ on:mouseup
131
+ on:scroll
132
+ on:wheel
133
+ on:paste
134
+ {...$$restProps}
135
+ >
136
+ {#each items as item, index (item)}
137
+ {@const selected = selectedIndex === index}
138
+ <!-- svelte-ignore a11y-click-events-have-key-events -->
139
+ <div
140
+ bind:this={itemRefs[index]}
141
+ aria-selected={disabled ? undefined : selected}
142
+ class="list-item"
143
+ class:selected
144
+ class:disabled
145
+ data-index={index + 1}
146
+ role="option"
147
+ on:click={() => onItemClick(index)}
148
+ >
149
+ <slot {disabled} {index} {item} {selected}>
150
+ {item}
151
+ </slot>
152
+ </div>
153
+ {/each}
154
+ </div>
155
+ </div>
204
156
 
205
157
  <style>
206
- .sterling-list-label,
207
- .sterling-list {
208
- background-color: var(--Common__background-color);
209
- border-color: var(--Common__border-color);
210
- border-radius: var(--Common__border-radius);
211
- border-style: var(--Common__border-style);
212
- border-width: var(--Common__border-width);
213
- box-sizing: border-box;
214
- color: var(--Common__color);
215
- display: flex;
216
- flex-direction: column;
217
- flex-wrap: nowrap;
218
- height: 100%;
219
- margin: 0;
220
- padding: 0;
221
- transition: background-color 250ms, color 250ms, border-color 250ms;
222
- }
223
-
224
- .sterling-list-label.horizontal,
225
- .sterling-list.horizontal {
226
- height: unset;
227
- width: 100%;
228
- }
158
+ .sterling-list {
159
+ background-color: var(--Common__background-color);
160
+ border-color: var(--Common__border-color);
161
+ border-radius: var(--Common__border-radius);
162
+ border-style: var(--Common__border-style);
163
+ border-width: var(--Common__border-width);
164
+ box-sizing: border-box;
165
+ color: var(--Common__color);
166
+ display: flex;
167
+ flex-direction: column;
168
+ flex-wrap: nowrap;
169
+ height: 100%;
170
+ margin: 0;
171
+ padding: 0;
172
+ transition: background-color 250ms, color 250ms, border-color 250ms;
173
+ }
229
174
 
230
- .sterling-list {
231
- overflow-x: hidden;
232
- overflow-y: scroll;
233
- position: relative;
234
- }
175
+ .sterling-list.horizontal {
176
+ height: unset;
177
+ width: 100%;
178
+ }
235
179
 
236
- .sterling-list.horizontal {
237
- flex-direction: row;
238
- overflow-x: scroll;
239
- overflow-y: hidden;
240
- }
180
+ .sterling-list:hover {
181
+ border-color: var(--Common__border-color--hover);
182
+ color: var(--Common__color--hover);
183
+ }
241
184
 
242
- .sterling-list-label:hover,
243
- .sterling-list:hover {
244
- border-color: var(--Common__border-color--hover);
245
- color: var(--Common__color--hover);
246
- }
185
+ .sterling-list:focus-visible,
186
+ .sterling-list.focus-visible {
187
+ border-color: var(--Common__border-color--focus);
188
+ color: var(--Common__color--focus);
189
+ outline-color: var(--Common__outline-color);
190
+ outline-offset: var(--Common__outline-offset);
191
+ outline-style: var(--Common__outline-style);
192
+ outline-width: var(--Common__outline-width);
193
+ }
247
194
 
248
- .sterling-list-label:focus-visible,
249
- .sterling-list-label.focus-visible,
250
- .sterling-list:focus-visible,
251
- .sterling-list.focus-visible {
252
- border-color: var(--Common__border-color--focus);
253
- color: var(--Common__color--focus);
254
- outline-color: var(--Common__outline-color);
255
- outline-offset: var(--Common__outline-offset);
256
- outline-style: var(--Common__outline-style);
257
- outline-width: var(--Common__outline-width);
258
- }
195
+ .sterling-list.disabled {
196
+ background-color: var(--Common__background-color--disabled);
197
+ border-color: var(---Common__border-color--disabled);
198
+ color: var(--Common__color--disabled);
199
+ cursor: not-allowed;
200
+ }
259
201
 
260
- .sterling-list-label.disabled,
261
- .sterling-list.disabled {
262
- background-color: var(--Common__background-color--disabled);
263
- border-color: var(---Common__border-color--disabled);
264
- color: var(--Common__color--disabled);
265
- cursor: not-allowed;
266
- }
202
+ .list {
203
+ overflow-x: hidden;
204
+ overflow-y: scroll;
205
+ position: relative;
206
+ }
267
207
 
268
- /* The background, border, and outline are removed when labeled as the label provides them */
269
- .sterling-list.labeled,
270
- .sterling-list.labeled:hover,
271
- .sterling-list.labeled:focus-visible,
272
- .sterling-list.labeled.focus-visible,
273
- .sterling-list.labeled:disabled {
274
- background-color: transparent;
275
- border: none;
276
- outline: none;
277
- }
278
- .label {
279
- display: flex;
280
- flex-direction: column;
281
- box-sizing: border-box;
282
- }
208
+ .list.horizontal {
209
+ flex-direction: row;
210
+ overflow-x: scroll;
211
+ overflow-y: hidden;
212
+ }
283
213
 
284
- .label-content {
285
- font-size: 0.7em;
286
- margin: 0.5em 0.7em;
287
- color: var(--Display__color--subtle);
288
- transition: background-color 250ms, color 250ms, border-color 250ms;
289
- }
214
+ .label {
215
+ font-size: 0.7em;
216
+ margin: 0.5em 0.7em;
217
+ }
290
218
 
291
- .label-content.disabled {
292
- font-size: 0.7em;
293
- margin: 0.5em 0.7em;
294
- color: var(--Display__color--disabled);
295
- }
219
+ .list-item {
220
+ box-sizing: border-box;
221
+ color: var(--Input__color);
222
+ margin: 0;
223
+ padding: 0.5em;
224
+ outline: none;
225
+ text-overflow: ellipsis;
226
+ transition: background-color 250ms, color 250ms, border-color 250ms;
227
+ white-space: nowrap;
228
+ }
296
229
 
297
- .list-item {
298
- box-sizing: border-box;
299
- color: var(--Input__color);
300
- margin: 0;
301
- padding: 0.5em;
302
- outline: none;
303
- text-overflow: ellipsis;
304
- transition: background-color 250ms, color 250ms, border-color 250ms;
305
- white-space: nowrap;
306
- }
230
+ .list-item:hover {
231
+ background-color: var(--Button__background-color--hover);
232
+ color: var(--Button__color--hover);
233
+ }
307
234
 
308
- .list-item:hover {
309
- background-color: var(--Button__background-color--hover);
310
- color: var(--Button__color--hover);
311
- }
235
+ .list-item.selected {
236
+ background-color: var(--Input__background-color--selected);
237
+ color: var(--Input__color--selected);
238
+ }
312
239
 
313
- .list-item.selected {
314
- background-color: var(--Input__background-color--selected);
315
- color: var(--Input__color--selected);
316
- }
240
+ .list-item.disabled {
241
+ color: var(--Input__color--disabled);
242
+ }
317
243
 
318
- .list-item.disabled {
319
- color: var(--Input__color--disabled);
320
- }
244
+ @media (prefers-reduced-motion) {
245
+ .sterling-list,
246
+ .list-item {
247
+ transition: none;
248
+ }
249
+ }
321
250
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoffcox/sterling-svelte",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "devDependencies": {
5
5
  "@fontsource/fira-mono": "^4.5.10",
6
6
  "@fontsource/overpass": "^4.5.10",
@@ -9,6 +9,7 @@
9
9
  "@sveltejs/adapter-static": "^1.0.0",
10
10
  "@sveltejs/kit": "^1.0.0",
11
11
  "@sveltejs/package": "^1.0.0",
12
+ "@types/lodash-es": "^4.17.6",
12
13
  "@types/uuid": "^9.0.0",
13
14
  "@typescript-eslint/eslint-plugin": "^5.45.0",
14
15
  "@typescript-eslint/parser": "^5.45.0",
@@ -36,6 +37,7 @@
36
37
  "./buttons/Button.svelte": "./buttons/Button.svelte",
37
38
  "./buttons/Button.types": "./buttons/Button.types.js",
38
39
  "./clickOutside": "./clickOutside.js",
40
+ "./display/Label.svelte": "./display/Label.svelte",
39
41
  "./display/Progress.svelte": "./display/Progress.svelte",
40
42
  "./display/Progress.types": "./display/Progress.types.js",
41
43
  ".": "./index.js",
@@ -45,6 +47,8 @@
45
47
  "./inputs/Select.svelte": "./inputs/Select.svelte",
46
48
  "./inputs/Slider.svelte": "./inputs/Slider.svelte",
47
49
  "./lists/List.svelte": "./lists/List.svelte",
50
+ "./surfaces/CloseX.svelte": "./surfaces/CloseX.svelte",
51
+ "./surfaces/Dialog.svelte": "./surfaces/Dialog.svelte",
48
52
  "./theme/applyDarkTheme": "./theme/applyDarkTheme.js",
49
53
  "./theme/applyLightTheme": "./theme/applyLightTheme.js",
50
54
  "./theme/applyTheme": "./theme/applyTheme.js",
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16" {...$$restProps}>
2
+ <path
3
+ d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"
4
+ />
5
+ </svg>
@@ -0,0 +1,23 @@
1
+ /** @typedef {typeof __propDef.props} CloseXProps */
2
+ /** @typedef {typeof __propDef.events} CloseXEvents */
3
+ /** @typedef {typeof __propDef.slots} CloseXSlots */
4
+ export default class CloseX extends SvelteComponentTyped<{
5
+ [x: string]: never;
6
+ }, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {}> {
9
+ }
10
+ export type CloseXProps = typeof __propDef.props;
11
+ export type CloseXEvents = typeof __propDef.events;
12
+ export type CloseXSlots = typeof __propDef.slots;
13
+ import { SvelteComponentTyped } from "svelte";
14
+ declare const __propDef: {
15
+ props: {
16
+ [x: string]: never;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ };
23
+ export {};
@@ -0,0 +1,241 @@
1
+ <script>import { createEventDispatcher, onMount, tick } from "svelte";
2
+ import Button from "../buttons/Button.svelte";
3
+ import CloseX from "./CloseX.svelte";
4
+ const dialogFadeDuration = 250;
5
+ export let open = false;
6
+ export let returnValue = "";
7
+ export let backdropCloses = false;
8
+ let dialogRef;
9
+ let contentRef;
10
+ let formRef;
11
+ let closing = false;
12
+ const dispatch = createEventDispatcher();
13
+ const onDocumentClick = (event) => {
14
+ const targetNode = event?.target;
15
+ if (targetNode && !contentRef.contains(targetNode) && backdropCloses) {
16
+ open = false;
17
+ }
18
+ };
19
+ const showDialog = () => {
20
+ if (dialogRef?.open === false) {
21
+ document.addEventListener("click", onDocumentClick, true);
22
+ dialogRef.showModal();
23
+ }
24
+ open = true;
25
+ };
26
+ const closeDialog = (returnValue2 = "") => {
27
+ if (dialogRef?.open === true) {
28
+ document.removeEventListener("click", onDocumentClick);
29
+ closing = true;
30
+ tick();
31
+ setTimeout(() => {
32
+ dialogRef.close(returnValue2);
33
+ open = false;
34
+ closing = false;
35
+ }, dialogFadeDuration);
36
+ } else {
37
+ open = false;
38
+ }
39
+ };
40
+ const updateDialog = (open2) => {
41
+ if (open2) {
42
+ showDialog();
43
+ } else {
44
+ closeDialog();
45
+ }
46
+ };
47
+ const onCancel = (event) => {
48
+ event.preventDefault();
49
+ event.stopPropagation();
50
+ closeDialog();
51
+ return false;
52
+ };
53
+ const onSubmit = (event) => {
54
+ console.log(event);
55
+ const anyEvent = event;
56
+ if (anyEvent?.submitter.type === "submit") {
57
+ if (dialogRef.open) {
58
+ closeDialog(anyEvent?.submitter.value ?? "");
59
+ setTimeout(() => {
60
+ formRef.requestSubmit(anyEvent?.submitter);
61
+ }, dialogFadeDuration);
62
+ event.preventDefault();
63
+ return false;
64
+ }
65
+ } else {
66
+ console.log("cancelling");
67
+ event.preventDefault();
68
+ return false;
69
+ }
70
+ };
71
+ const onClose = (event) => {
72
+ returnValue = dialogRef.returnValue;
73
+ };
74
+ $: {
75
+ updateDialog(open);
76
+ }
77
+ onMount(() => {
78
+ updateDialog(open);
79
+ dialogRef.addEventListener("cancel", onCancel);
80
+ dialogRef.addEventListener("close", onClose);
81
+ return () => {
82
+ dialogRef?.removeEventListener("cancel", onCancel);
83
+ dialogRef?.removeEventListener("close", onClose);
84
+ };
85
+ });
86
+ </script>
87
+
88
+ <!-- @component
89
+ A styled &lt;dialog&gt; element
90
+
91
+ - Slots for typical dialog content.
92
+ - Props and events to make using &lt;dialog&gt; easier
93
+ -->
94
+ <dialog
95
+ class="dialog"
96
+ class:open
97
+ class:closing
98
+ bind:this={dialogRef}
99
+ on:close
100
+ on:cancel
101
+ {...$$restProps}
102
+ >
103
+ <form method="dialog" bind:this={formRef} on:submit={onSubmit}>
104
+ <div class="content" bind:this={contentRef}>
105
+ <slot name="content">
106
+ <div class="header">
107
+ <slot name="header">
108
+ <div class="title">
109
+ <slot name="title" />
110
+ </div>
111
+ <div class="close">
112
+ <Button variant="ghost" shape="circular" on:click={() => closeDialog()}>
113
+ <div class="close-x">
114
+ <CloseX />
115
+ </div>
116
+ </Button>
117
+ </div>
118
+ </slot>
119
+ </div>
120
+ <div class="body">
121
+ <slot name="body" />
122
+ </div>
123
+ <div class="separator" />
124
+ <div class="footer">
125
+ <slot name="footer" />
126
+ </div>
127
+ </slot>
128
+ </div>
129
+ </form>
130
+ </dialog>
131
+
132
+ <style>
133
+ .dialog {
134
+ padding: 0;
135
+ border: none;
136
+ background: none;
137
+ }
138
+
139
+ .dialog::backdrop {
140
+ backdrop-filter: blur(2px);
141
+ background: rgba(0, 0, 0, 0.3);
142
+ transition: opacity 250ms;
143
+ opacity: 0;
144
+ }
145
+
146
+ .dialog.open::backdrop {
147
+ opacity: 1;
148
+ }
149
+
150
+ .dialog.closing::backdrop {
151
+ opacity: 0;
152
+ }
153
+
154
+ .header {
155
+ background-color: var(--Display__background-color);
156
+ }
157
+
158
+ .content {
159
+ background-color: var(--Common__background-color);
160
+ border-color: var(--Common__border-color);
161
+ border-radius: var(--Common__border-radius);
162
+ border-style: var(--Common__border-style);
163
+ border-width: var(--Common__border-width);
164
+ box-sizing: border-box;
165
+ color: var(--Common__color);
166
+ display: grid;
167
+ grid-template-columns: 1fr;
168
+ grid-template-rows: auto 1fr auto auto;
169
+ justify-content: stretch;
170
+ justify-items: stretch;
171
+ align-items: stretch;
172
+ transition: opacity 250ms;
173
+ opacity: 0;
174
+ }
175
+
176
+ .dialog.open .content {
177
+ opacity: 1;
178
+ }
179
+
180
+ .dialog.closing .content {
181
+ opacity: 0;
182
+ }
183
+
184
+ .header {
185
+ display: grid;
186
+ grid-template-columns: 1fr auto;
187
+ grid-template-rows: 1fr;
188
+ justify-items: stretch;
189
+ align-items: center;
190
+ padding: 0.25em 0.5em;
191
+ }
192
+
193
+ .title {
194
+ font-size: 1.4em;
195
+ }
196
+
197
+ .close {
198
+ justify-self: flex-end;
199
+ }
200
+
201
+ .close :global(button) {
202
+ width: 1.75em;
203
+ height: 1.75em;
204
+ padding: 0;
205
+ }
206
+
207
+ .close-x {
208
+ width: 1.5em;
209
+ height: 1.5em;
210
+ display: grid;
211
+ grid-template-columns: 1fr;
212
+ grid-template-rows: 1fr;
213
+ place-content: center;
214
+ align-content: center;
215
+ }
216
+
217
+ .body {
218
+ padding: 1em;
219
+ }
220
+
221
+ .separator {
222
+ background-color: var(--Display__background-color);
223
+ height: var(--Common__border-width);
224
+ margin: 0 0.25em;
225
+ }
226
+
227
+ .footer {
228
+ display: flex;
229
+ justify-content: flex-end;
230
+ justify-items: flex-end;
231
+ padding: 0.5em 1em;
232
+ gap: 5px;
233
+ }
234
+
235
+ @media (prefers-reduced-motion) {
236
+ .dialog::backdrop,
237
+ .content {
238
+ transition: none;
239
+ }
240
+ }
241
+ </style>