@geoffcox/sterling-svelte 0.0.9 → 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.
@@ -1,8 +1,10 @@
1
1
  <script>import { createEventDispatcher, onMount, tick } from "svelte";
2
- import { v4 as uuidv4 } from "uuid";
2
+ import { v4 as uuid } from "uuid";
3
3
  import { computePosition, flip, offset, shift, autoUpdate } from "@floating-ui/dom";
4
4
  import { clickOutside } from "../clickOutside";
5
+ import Label from "../display/Label.svelte";
5
6
  import List from "../lists/List.svelte";
7
+ import Input from "./Input.svelte";
6
8
  export let disabled = false;
7
9
  export let items = [];
8
10
  export let open = false;
@@ -11,12 +13,13 @@ export let selectedItem = void 0;
11
13
  $: {
12
14
  selectedItem = items[selectedIndex];
13
15
  }
16
+ const inputId = uuid();
14
17
  let prevOpen = false;
15
18
  let pendingSelectedIndex = selectedIndex;
16
19
  let selectRef;
17
20
  let popupRef;
18
21
  let listRef;
19
- const popupId = uuidv4();
22
+ const popupId = uuid();
20
23
  let popupPosition = {
21
24
  x: void 0,
22
25
  y: void 0
@@ -139,184 +142,177 @@ const onPendingItemSelected = (event) => {
139
142
  A single item that can be selected from a popup list of items.
140
143
  -->
141
144
  <div
142
- bind:this={selectRef}
143
- use:clickOutside
144
- aria-controls={popupId}
145
- aria-haspopup="listbox"
146
- aria-expanded={open}
147
- class="sterling-select"
148
- class:disabled
149
- role="combobox"
150
- tabindex="0"
151
- on:click_outside={() => (open = false)}
152
- on:click={onSelectClick}
153
- on:blur
154
- on:click
155
- on:copy
156
- on:cut
157
- on:dblclick
158
- on:focus
159
- on:focusin
160
- on:focusout
161
- on:keydown={onSelectKeydown}
162
- on:keydown
163
- on:keypress
164
- on:keyup
165
- on:mousedown
166
- on:mouseenter
167
- on:mouseleave
168
- on:mousemove
169
- on:mouseover
170
- on:mouseout
171
- on:mouseup
172
- on:wheel
173
- on:paste
174
- {...$$restProps}
145
+ bind:this={selectRef}
146
+ use:clickOutside
147
+ aria-controls={popupId}
148
+ aria-haspopup="listbox"
149
+ aria-expanded={open}
150
+ class="sterling-select"
151
+ class:disabled
152
+ role="combobox"
153
+ tabindex="0"
154
+ on:click_outside={() => (open = false)}
155
+ on:click={onSelectClick}
156
+ on:blur
157
+ on:click
158
+ on:copy
159
+ on:cut
160
+ on:dblclick
161
+ on:focus
162
+ on:focusin
163
+ on:focusout
164
+ on:keydown={onSelectKeydown}
165
+ on:keydown
166
+ on:keypress
167
+ on:keyup
168
+ on:mousedown
169
+ on:mouseenter
170
+ on:mouseleave
171
+ on:mousemove
172
+ on:mouseover
173
+ on:mouseout
174
+ on:mouseup
175
+ on:wheel
176
+ on:paste
177
+ {...$$restProps}
175
178
  >
176
- <!-- svelte-ignore a11y-label-has-associated-control -->
177
- <label class="sterling-select-label">
178
- {#if $$slots.label}
179
- <div class="label-content" class:disabled>
180
- <slot name="label" />
181
- </div>
182
- {/if}
183
- <div class="input">
184
- <div class="value">
185
- <slot name="value">
186
- {items[selectedIndex]}
187
- </slot>
188
- </div>
189
- <div class="button">
190
- <slot name="button" {open}>
191
- <div class="chevron" />
192
- </slot>
193
- </div>
194
- </div>
195
- </label>
196
- <div
197
- bind:this={popupRef}
198
- class="popup"
199
- class:open
200
- id={popupId}
201
- style="left:{popupPosition.x}px; top:{popupPosition.y}px"
202
- >
203
- <div class="popup-content">
204
- <slot name="list">
205
- {#if $$slots.default === true}
206
- <List
207
- bind:this={listRef}
208
- selectedIndex={pendingSelectedIndex}
209
- {items}
210
- {disabled}
211
- let:disabled
212
- let:index
213
- let:item
214
- let:selected
215
- on:click={onListClick}
216
- on:keydown={onListKeydown}
217
- on:itemSelected={onPendingItemSelected}
218
- >
219
- <slot {disabled} {index} {item} {selected} />
220
- </List>
221
- {:else}
222
- <List
223
- bind:this={listRef}
224
- selectedIndex={pendingSelectedIndex}
225
- {items}
226
- {disabled}
227
- let:disabled
228
- let:index
229
- let:item
230
- let:selected
231
- on:click={onListClick}
232
- on:keydown={onListKeydown}
233
- on:itemSelected={onPendingItemSelected}
234
- />
235
- {/if}
236
- </slot>
237
- </div>
238
- </div>
179
+ {#if $$slots.label}
180
+ <div class="label">
181
+ <Label {disabled} for={inputId}>
182
+ <slot name="label" />
183
+ </Label>
184
+ </div>
185
+ {/if}
186
+ <div class="input" id={inputId}>
187
+ <div class="value">
188
+ <slot name="value">
189
+ {items[selectedIndex]}
190
+ </slot>
191
+ </div>
192
+ <div class="button">
193
+ <slot name="button" {open}>
194
+ <div class="chevron" />
195
+ </slot>
196
+ </div>
197
+ </div>
198
+ <div
199
+ bind:this={popupRef}
200
+ class="popup"
201
+ class:open
202
+ id={popupId}
203
+ style="left:{popupPosition.x}px; top:{popupPosition.y}px"
204
+ >
205
+ <div class="popup-content">
206
+ <slot name="list">
207
+ {#if $$slots.default === true}
208
+ <List
209
+ bind:this={listRef}
210
+ selectedIndex={pendingSelectedIndex}
211
+ {items}
212
+ {disabled}
213
+ let:disabled
214
+ let:index
215
+ let:item
216
+ let:selected
217
+ on:click={onListClick}
218
+ on:keydown={onListKeydown}
219
+ on:itemSelected={onPendingItemSelected}
220
+ >
221
+ <slot {disabled} {index} {item} {selected} />
222
+ </List>
223
+ {:else}
224
+ <List
225
+ bind:this={listRef}
226
+ selectedIndex={pendingSelectedIndex}
227
+ {items}
228
+ {disabled}
229
+ let:disabled
230
+ let:index
231
+ let:item
232
+ let:selected
233
+ on:click={onListClick}
234
+ on:keydown={onListKeydown}
235
+ on:itemSelected={onPendingItemSelected}
236
+ />
237
+ {/if}
238
+ </slot>
239
+ </div>
240
+ </div>
239
241
  </div>
240
242
 
241
243
  <style>
242
- .sterling-select {
243
- background-color: var(--Input__background-color);
244
- border-color: var(--Input__border-color);
245
- border-radius: var(--Input__border-radius);
246
- border-style: var(--Input__border-style);
247
- border-width: var(--Input__border-width);
248
- color: var(--Input__color);
249
- padding: 0;
250
- transition: background-color 250ms, color 250ms, border-color 250ms;
251
- }
252
-
253
- .sterling-select:hover {
254
- background-color: var(--Input__background-color--hover);
255
- border-color: var(--Input__border-color--hover);
256
- color: var(--Input__color--hover);
257
- }
244
+ .sterling-select {
245
+ background-color: var(--Input__background-color);
246
+ border-color: var(--Input__border-color);
247
+ border-radius: var(--Input__border-radius);
248
+ border-style: var(--Input__border-style);
249
+ border-width: var(--Input__border-width);
250
+ color: var(--Input__color);
251
+ padding: 0;
252
+ transition: background-color 250ms, color 250ms, border-color 250ms;
253
+ }
258
254
 
259
- .sterling-select:focus-within {
260
- background-color: var(--Input__background-color--focus);
261
- border-color: var(--Input__border-color--focus);
262
- color: var(--Input__color--focus);
263
- outline-color: var(--Common__outline-color);
264
- outline-offset: var(--Common__outline-offset);
265
- outline-style: var(--Common__outline-style);
266
- outline-width: var(--Common__outline-width);
267
- }
255
+ .sterling-select:hover {
256
+ background-color: var(--Input__background-color--hover);
257
+ border-color: var(--Input__border-color--hover);
258
+ color: var(--Input__color--hover);
259
+ }
268
260
 
269
- .sterling-select.disabled {
270
- background-color: var(--Input__background-color--disabled);
271
- border-color: var(---Input__border-color--disabled);
272
- color: var(--Input__color--disabled);
273
- cursor: not-allowed;
274
- outline: none;
275
- }
261
+ .sterling-select:focus-within {
262
+ background-color: var(--Input__background-color--focus);
263
+ border-color: var(--Input__border-color--focus);
264
+ color: var(--Input__color--focus);
265
+ outline-color: var(--Common__outline-color);
266
+ outline-offset: var(--Common__outline-offset);
267
+ outline-style: var(--Common__outline-style);
268
+ outline-width: var(--Common__outline-width);
269
+ }
276
270
 
277
- .label-content {
278
- font-size: 0.7em;
279
- margin: 0.5em 0.7em 0 0.7em;
280
- color: var(--Display__color--subtle);
281
- transition: background-color 250ms, color 250ms, border-color 250ms;
282
- }
271
+ .sterling-select.disabled {
272
+ background-color: var(--Input__background-color--disabled);
273
+ border-color: var(---Input__border-color--disabled);
274
+ color: var(--Input__color--disabled);
275
+ cursor: not-allowed;
276
+ outline: none;
277
+ }
283
278
 
284
- .label-content.disabled {
285
- color: var(--Display__color--disabled);
286
- }
279
+ .label {
280
+ font-size: 0.7em;
281
+ margin: 0.5em 0.7em 0 0.7em;
282
+ }
287
283
 
288
- .input {
289
- display: grid;
290
- grid-template-columns: 1fr auto;
291
- grid-template-rows: auto;
292
- align-content: center;
293
- align-items: center;
294
- }
284
+ .input {
285
+ display: grid;
286
+ grid-template-columns: 1fr auto;
287
+ grid-template-rows: auto;
288
+ align-content: center;
289
+ align-items: center;
290
+ }
295
291
 
296
- .value {
297
- padding: 0.5em;
298
- }
292
+ .value {
293
+ padding: 0.5em;
294
+ }
299
295
 
300
- .chevron {
301
- display: block;
302
- position: relative;
303
- border: none;
304
- background: none;
305
- margin: 0;
306
- height: 100%;
307
- width: 32px;
308
- }
296
+ .chevron {
297
+ display: block;
298
+ position: relative;
299
+ border: none;
300
+ background: none;
301
+ margin: 0;
302
+ height: 100%;
303
+ width: 32px;
304
+ }
309
305
 
310
- .chevron::after {
311
- position: absolute;
312
- content: '';
313
- top: 50%;
314
- left: 50%;
315
- width: 7px;
316
- height: 7px;
317
- border-right: 3px solid currentColor;
318
- border-top: 3px solid currentColor;
319
- /*
306
+ .chevron::after {
307
+ position: absolute;
308
+ content: '';
309
+ top: 50%;
310
+ left: 50%;
311
+ width: 7px;
312
+ height: 7px;
313
+ border-right: 3px solid currentColor;
314
+ border-top: 3px solid currentColor;
315
+ /*
320
316
  The chevron is a right triangle, rotated to face down.
321
317
  It should be moved up so it is centered vertically after rotation.
322
318
  The amount to move is the hypotenuse of the right triangle of the chevron.
@@ -329,35 +325,34 @@ A single item that can be selected from a popup list of items.
329
325
  a = sqrt(0.5)
330
326
  a = 0.707
331
327
  */
332
- transform: translate(-50%, calc(-50% / 0.707)) rotate(135deg);
333
- transform-origin: 50% 50%;
334
- }
328
+ transform: translate(-50%, calc(-50% / 0.707)) rotate(135deg);
329
+ transform-origin: 50% 50%;
330
+ }
335
331
 
336
- .popup {
337
- box-sizing: border-box;
338
- display: none;
339
- overflow: hidden;
340
- position: absolute;
341
- box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
342
- width: fit-content;
343
- height: fit-content;
344
- z-index: 1;
345
- }
332
+ .popup {
333
+ box-sizing: border-box;
334
+ display: none;
335
+ overflow: hidden;
336
+ position: absolute;
337
+ box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
338
+ width: fit-content;
339
+ height: fit-content;
340
+ z-index: 1;
341
+ }
346
342
 
347
- .popup.open {
348
- display: grid;
349
- grid-template-columns: 1fr;
350
- grid-template-rows: 1fr;
351
- }
343
+ .popup.open {
344
+ display: grid;
345
+ grid-template-columns: 1fr;
346
+ grid-template-rows: 1fr;
347
+ }
352
348
 
353
- .popup-content {
354
- max-height: 15em;
355
- }
349
+ .popup-content {
350
+ max-height: 15em;
351
+ }
356
352
 
357
- @media (prefers-reduced-motion) {
358
- .sterling-select,
359
- .label-content {
360
- transition: none;
361
- }
362
- }
353
+ @media (prefers-reduced-motion) {
354
+ .sterling-select {
355
+ transition: none;
356
+ }
357
+ }
363
358
  </style>
@@ -1,5 +1,7 @@
1
- <script>import { round } from "lodash-es";
2
- import { createEventDispatcher } from "svelte";
1
+ <script>import { createEventDispatcher } from "svelte";
2
+ import { round } from "lodash-es";
3
+ import { v4 as uuid } from "uuid";
4
+ import Label from "../display/Label.svelte";
3
5
  export let value = 0;
4
6
  export let min = 0;
5
7
  export let max = 100;
@@ -7,6 +9,7 @@ export let step = void 0;
7
9
  export let precision = 0;
8
10
  export let vertical = false;
9
11
  export let disabled = false;
12
+ const inputId = uuid();
10
13
  let sliderRef;
11
14
  const dispatch = createEventDispatcher();
12
15
  const raiseChange = (newValue) => {
@@ -121,51 +124,20 @@ const onKeyDown = (event) => {
121
124
  <!-- @component
122
125
  Slider lets the user chose a value within a min/max range by dragging a thumb button.
123
126
  -->
124
- {#if $$slots.label}
125
- <label class="sterling-slider-label" class:vertical>
126
- <div class="label-content" class:disabled>
127
- <slot name="label" />
127
+ <div class="sterling-slider" class:vertical>
128
+ {#if $$slots.label}
129
+ <div class="label">
130
+ <Label {disabled} for={inputId}>
131
+ <slot name="label" />
132
+ </Label>
128
133
  </div>
129
- <div
130
- class="sterling-slider labeled"
131
- class:disabled
132
- class:horizontal={!vertical}
133
- class:vertical
134
- role="slider"
135
- aria-valuemin={0}
136
- aria-valuenow={value}
137
- aria-valuemax={max}
138
- tabindex={!disabled ? 0 : undefined}
139
- {...$$restProps}
140
- on:keydown={onKeyDown}
141
- on:pointerdown={onPointerDown}
142
- on:pointermove={onPointerMove}
143
- on:pointerup={onPointerUp}
144
- >
145
- <div
146
- class="container"
147
- bind:this={sliderRef}
148
- bind:clientWidth={sliderWidth}
149
- bind:clientHeight={sliderHeight}
150
- >
151
- <div class="track" />
152
- <div
153
- class="fill"
154
- style={vertical ? `height: ${valueOffset}px` : `width: ${valueOffset}px`}
155
- />
156
- <div
157
- class="thumb"
158
- style={vertical ? `bottom: ${valueOffset}px` : `left: ${valueOffset}px`}
159
- />
160
- </div>
161
- </div>
162
- </label>
163
- {:else}
134
+ {/if}
164
135
  <div
165
- class="sterling-slider"
136
+ class="slider"
166
137
  class:disabled
167
138
  class:horizontal={!vertical}
168
139
  class:vertical
140
+ id={inputId}
169
141
  role="slider"
170
142
  aria-valuemin={0}
171
143
  aria-valuenow={value}
@@ -188,41 +160,31 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
188
160
  <div class="thumb" style={vertical ? `bottom: ${valueOffset}px` : `left: ${valueOffset}px`} />
189
161
  </div>
190
162
  </div>
191
- {/if}
163
+ </div>
192
164
 
193
165
  <style>
194
- .sterling-slider-label {
166
+ .sterling-slider {
195
167
  display: grid;
196
168
  grid-template-columns: 1fr;
197
169
  grid-template-rows: auto 1fr;
198
170
  }
199
171
 
200
- .sterling-slider-label.vertical {
172
+ .sterling-slider.vertical {
201
173
  justify-items: center;
202
174
  height: 100%;
203
175
  }
204
176
 
205
- .label-content {
177
+ .label {
206
178
  font-size: 0.7em;
207
- color: var(--Display__color--subtle);
208
- transition: background-color 250ms, color 250ms, border-color 250ms;
209
- }
210
-
211
- .label-content.disabled {
212
- color: var(--Display__color--disabled);
213
179
  }
214
180
 
215
- .sterling-slider {
181
+ .slider {
216
182
  box-sizing: border-box;
217
183
  outline: none;
218
184
  padding: 0;
219
185
  overflow: visible;
220
186
  display: grid;
221
- height: 100%;
222
- }
223
-
224
- .sterling-slider.labeled {
225
- height: unset;
187
+ transition: background-color 250ms, color 250ms, border-color 250ms;
226
188
  }
227
189
 
228
190
  .container {
@@ -232,11 +194,13 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
232
194
  .track {
233
195
  position: absolute;
234
196
  background: var(--Display__background-color);
197
+ transition: background-color 250ms, color 250ms, border-color 250ms;
235
198
  }
236
199
 
237
200
  .fill {
238
201
  background: var(--Display__color);
239
202
  position: absolute;
203
+ transition: background-color 250ms, color 250ms, border-color 250ms;
240
204
  }
241
205
 
242
206
  .thumb {
@@ -262,15 +226,15 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
262
226
 
263
227
  /* ----- horizontal ----- */
264
228
 
265
- .sterling-slider.horizontal {
229
+ .slider.horizontal {
266
230
  height: 2em;
267
231
  }
268
232
 
269
- .sterling-slider.horizontal .container {
233
+ .slider.horizontal .container {
270
234
  margin: 0 0.75em;
271
235
  }
272
236
 
273
- .sterling-slider.horizontal .track {
237
+ .slider.horizontal .track {
274
238
  left: 0;
275
239
  right: 0;
276
240
  top: 50%;
@@ -278,27 +242,27 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
278
242
  transform: translate(0, -50%);
279
243
  }
280
244
 
281
- .sterling-slider.horizontal .fill {
245
+ .slider.horizontal .fill {
282
246
  height: 3px;
283
247
  top: 50%;
284
248
  transform: translate(0, -50%);
285
249
  }
286
250
 
287
- .sterling-slider.horizontal .thumb {
251
+ .slider.horizontal .thumb {
288
252
  top: 50%;
289
253
  transform: translate(-50%, -50%);
290
254
  }
291
255
 
292
256
  /* ----- vertical ----- */
293
257
 
294
- .sterling-slider.vertical {
258
+ .slider.vertical {
295
259
  width: 2em;
296
260
  }
297
- .sterling-slider.vertical .container {
261
+ .slider.vertical .container {
298
262
  margin: 0.75em 0;
299
263
  }
300
264
 
301
- .sterling-slider.vertical .track {
265
+ .slider.vertical .track {
302
266
  bottom: 0;
303
267
  left: 50%;
304
268
  top: 0;
@@ -306,14 +270,14 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
306
270
  width: 3px;
307
271
  }
308
272
 
309
- .sterling-slider.vertical .fill {
273
+ .slider.vertical .fill {
310
274
  bottom: 0;
311
275
  left: 50%;
312
276
  transform: translate(-50%, 0);
313
277
  width: 3px;
314
278
  }
315
279
 
316
- .sterling-slider.vertical .thumb {
280
+ .slider.vertical .thumb {
317
281
  left: 50%;
318
282
  transform: translate(-50%, 50%);
319
283
  }
@@ -335,7 +299,7 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
335
299
  }
336
300
 
337
301
  /* ----- focus ----- */
338
- .sterling-slider:focus-visible {
302
+ .slider:focus-visible {
339
303
  outline-color: var(--Common__outline-color);
340
304
  outline-offset: var(--Common__outline-offset);
341
305
  outline-style: var(--Common__outline-style);
@@ -343,15 +307,15 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
343
307
  }
344
308
  /* ----- disabled ----- */
345
309
 
346
- .sterling-slider.disabled .track {
310
+ .slider.disabled .track {
347
311
  background: var(--Common__background-color--disabled);
348
312
  }
349
313
 
350
- .sterling-slider.disabled .fill {
314
+ .slider.disabled .fill {
351
315
  background: var(--Common__color--disabled);
352
316
  }
353
317
 
354
- .sterling-slider.disabled .thumb {
318
+ .slider.disabled .thumb {
355
319
  background-color: var(--Common__background-color--disabled);
356
320
  border-color: var(--Common__border-color--disabled);
357
321
  color: var(--Common__color--disabled);
@@ -359,8 +323,10 @@ Slider lets the user chose a value within a min/max range by dragging a thumb bu
359
323
  }
360
324
 
361
325
  @media (prefers-reduced-motion) {
362
- .thumb,
363
- .label-content {
326
+ .slider,
327
+ .track,
328
+ .fill,
329
+ .thumb {
364
330
  transition: none;
365
331
  }
366
332
  }