@soleil-se/config-svelte 1.24.0 → 1.25.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,21 @@ All notable changes to this project will be documented in this file.
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
9
 
10
+ ## [1.25.0] - 2024-04-29
11
+
12
+ - Add `createConfigApp` function for creating a config app with Svelte 5.
13
+ - Rewrite of `CustomList` edit modal handling to work with Svelte 5.
14
+ - Remove all self closing tags in components.
15
+ - Remove `focus-visible` polyfill.
16
+
17
+ ## [1.24.1] - 2024-04-29
18
+
19
+ - Add Svelte 5 as a peer dependency.
20
+
21
+ ## [1.24.0] - 2024-04-18
22
+
23
+ - Add label slot for most components.
24
+
10
25
  ## [1.23.0] - 2024-03-07
11
26
 
12
27
  - List item templating in `CustomList` with [CustomListItemTemplate](/packages/soleil/svelte-config/components/customlist/#list-item-template).
@@ -65,7 +65,7 @@
65
65
  border-radius: 3px;
66
66
  }
67
67
 
68
- :global(.focus-visible) + &::before {
68
+ input:focus-visible + &::before {
69
69
  box-shadow: 0 0 0 0.2rem rgb(66 139 202 / 40%);
70
70
  }
71
71
 
@@ -97,7 +97,7 @@
97
97
  border-radius: 3px;
98
98
  }
99
99
 
100
- :global(.focus-visible) + &::before {
100
+ input:focus-visible + &::before {
101
101
  box-shadow: 0 0 0 0.2rem rgb(66 139 202 / 40%);
102
102
  }
103
103
 
@@ -26,9 +26,8 @@
26
26
  addGeneratedIds(value);
27
27
 
28
28
  const domId = generateId();
29
- let modals = value;
29
+ let modals = value.reduce((acc, id) => ({ ...acc, [id]: false }), {}) || [];
30
30
  let items = [];
31
- let editId;
32
31
  let dragDisabled = disabled;
33
32
  let addModalOpen = false;
34
33
 
@@ -36,10 +35,6 @@
36
35
  addModalOpen = true;
37
36
  }
38
37
 
39
- function onAddClose() {
40
- addModalOpen = false;
41
- }
42
-
43
38
  async function updateItems() {
44
39
  await tick();
45
40
  items = value.map((id) => ({
@@ -48,6 +43,7 @@
48
43
  document.querySelector(`#modal_${id} .custom-list-item-template`)?.innerHTML ||
49
44
  document.querySelector(`#modal_${id} input:not([type=radio],[type=checkbox])`)?.value ||
50
45
  id,
46
+ open: false,
51
47
  }));
52
48
  }
53
49
 
@@ -59,30 +55,26 @@
59
55
 
60
56
  function onAddSave({ detail }) {
61
57
  items = items.concat(detail);
62
- modals = modals.concat(detail.id);
58
+ modals[detail.id] = false;
63
59
  onChange();
64
60
  }
65
61
 
66
62
  function onEdit({ detail }) {
67
- editId = detail;
63
+ modals[detail] = true;
68
64
  }
69
65
 
70
66
  function onRemove({ detail }) {
71
67
  items = items.filter((item) => item.id !== detail);
72
- modals = modals.filter((id) => id !== detail);
68
+ delete modals[detail];
69
+ modals = modals;
73
70
  onChange();
74
71
  }
75
72
 
76
73
  function onEditSave() {
77
- editId = undefined;
78
74
  updateItems();
79
75
  onChange();
80
76
  }
81
77
 
82
- function onEditClose() {
83
- editId = undefined;
84
- }
85
-
86
78
  function tempDisableDrag() {
87
79
  dragDisabled = true;
88
80
  setTimeout(() => {
@@ -110,13 +102,13 @@
110
102
  [README](https://docs.soleilit.se/03.packages/@soleil&svelte-config/components/CustomList/)
111
103
  -->
112
104
 
113
- {#each modals as id, index (id)}
114
- <EditModal {id} open={editId === id} on:save={onEditSave} on:close={onEditClose}>
115
- <slot {id} {index} {triggerUpdate} />
105
+ {#each Object.keys(modals) as id (id)}
106
+ <EditModal {id} bind:open={modals[id]} on:save={onEditSave}>
107
+ <slot {id} {triggerUpdate} />
116
108
  </EditModal>
117
109
  {/each}
118
- <AddModal {name} open={addModalOpen} on:save={onAddSave} on:close={onAddClose} let:id>
119
- <slot {id} index={items.length} {triggerUpdate} />
110
+ <AddModal {name} bind:open={addModalOpen} on:save={onAddSave} let:id>
111
+ <slot {id} {triggerUpdate} />
120
112
  </AddModal>
121
113
 
122
114
  <div class="form-group" class:hidden={!show}>
@@ -134,18 +126,19 @@
134
126
  on:remove={onRemove}
135
127
  on:click={tempDisableDrag}
136
128
  >
129
+ <!-- eslint-disable-next-line svelte/no-at-html-tags -->
137
130
  {@html item.name}
138
131
  </SortableItem>
139
132
  </Sortable>
140
- <div class="ui-resizable-handle ui-resizable-s" use:resizer />
133
+ <div class="ui-resizable-handle ui-resizable-s" use:resizer></div>
141
134
  </div>
142
135
  <button class="list-component__add-item btn btn-link" {disabled} on:click={onAddOpen}>
143
- <i class="glyphicons plus" aria-hidden="true" />
136
+ <i class="glyphicons plus" aria-hidden="true"></i>
144
137
  {i18n('add')}
145
138
  </button>
146
139
 
147
140
  {#if disabled}
148
- <div class="disabled-overlay" />
141
+ <div class="disabled-overlay"></div>
149
142
  {/if}
150
143
  </div>
151
144
 
@@ -181,7 +174,7 @@
181
174
  }
182
175
 
183
176
  &:focus-visible {
184
- outline: 2px solid #66afe9;
177
+ outline: 2px solid #428bca;
185
178
  }
186
179
  }
187
180
  </style>
@@ -31,7 +31,7 @@
31
31
  };
32
32
  </script>
33
33
 
34
- <Modal {open} title={i18n('add')} on:save={onSave} on:close={onClose} bind:element>
34
+ <Modal title={i18n('add')} bind:open on:save={onSave} on:close={onClose} bind:element>
35
35
  {#if id}
36
36
  <slot {id} />
37
37
  {/if}
@@ -11,14 +11,12 @@
11
11
  let selectElement;
12
12
  $: noValue = value.length === 0;
13
13
 
14
- $: {
15
- if (selectElement) {
16
- selectElement.setCustomValidity('');
17
- setTimeout(() => triggerInput(selectElement, value));
18
- }
14
+ $: if (selectElement) {
15
+ selectElement.setCustomValidity('');
16
+ setTimeout(() => triggerInput(selectElement, value));
19
17
  }
20
18
 
21
- const setValidationMessage = () => {
19
+ function setValidationMessage() {
22
20
  if (required && noValue) {
23
21
  selectElement.setCustomValidity(i18n('validation'));
24
22
  }
@@ -26,16 +24,16 @@
26
24
  </script>
27
25
 
28
26
  <select
27
+ bind:this={selectElement}
29
28
  id={domId}
30
- {value}
31
- multiple
32
29
  {name}
33
30
  class="sr-only"
34
31
  aria-hidden="true"
35
- bind:this={selectElement}
32
+ multiple
36
33
  required={noValue && required}
37
- on:invalid={setValidationMessage}
38
34
  tabindex="-1"
35
+ {value}
36
+ on:invalid={setValidationMessage}
39
37
  >
40
38
  {#each value as option}
41
39
  <option>{option}</option>
@@ -8,9 +8,9 @@
8
8
  let name = '';
9
9
  let element;
10
10
 
11
- const onOpen = () => {
11
+ function onOpen() {
12
12
  name = element.querySelector('input')?.value || id;
13
- };
13
+ }
14
14
  </script>
15
15
 
16
16
  <div id="modal_{id}" style:display="contents">
@@ -9,19 +9,19 @@
9
9
 
10
10
  const dispatch = createEventDispatcher();
11
11
 
12
- const onConsider = (e) => {
12
+ function onConsider(e) {
13
13
  items = e.detail.items;
14
- };
14
+ }
15
15
 
16
- const onFinalize = (e) => {
16
+ function onFinalize(e) {
17
17
  items = e.detail.items;
18
18
  dispatch('finalize', items);
19
- };
19
+ }
20
20
 
21
- const transformDraggedElement = (el) => {
21
+ function transformDraggedElement(el) {
22
22
  // eslint-disable-next-line no-param-reassign
23
23
  el.style.backgroundColor = '#f5f5f5';
24
- };
24
+ }
25
25
  </script>
26
26
 
27
27
  <ul
@@ -56,10 +56,10 @@
56
56
  padding: 0;
57
57
  }
58
58
 
59
- ul:focus,
60
- ul :global(li.focus-visible) {
59
+ ul:focus-visible,
60
+ ul li:focus-visible {
61
61
  position: relative;
62
62
  z-index: 1;
63
- outline: 2px solid #66afe9;
63
+ outline: 2px solid #428bca;
64
64
  }
65
65
  </style>
@@ -7,32 +7,32 @@
7
7
 
8
8
  const dispatch = createEventDispatcher();
9
9
 
10
- const editItem = async () => {
10
+ function editItem() {
11
11
  dispatch('edit', id);
12
- };
12
+ }
13
13
 
14
- const removeItem = () => {
14
+ function removeItem() {
15
15
  dispatch('remove', id);
16
- };
16
+ }
17
17
  </script>
18
18
 
19
19
  <!-- This is handled by the click event on the edit button -->
20
20
  <!-- svelte-ignore a11y-click-events-have-key-events a11y-no-static-element-interactions -->
21
21
  <div class="list-component__item" on:dblclick={editItem} on:click>
22
22
  {#if icon}
23
- <i class="sv-list-icon {icon}" aria-hidden="true" />
23
+ <i class="sv-list-icon {icon}" aria-hidden="true"></i>
24
24
  {/if}
25
25
  <span class="item-name">
26
26
  <slot />
27
27
  </span>
28
28
  <div class="list-component__item-actions">
29
29
  <button {disabled} on:click={editItem}>
30
- <i class="glyphicons edit" aria-hidden="true" />
30
+ <i class="glyphicons edit" aria-hidden="true"></i>
31
31
  </button>
32
32
  <button {disabled} on:click={removeItem}>
33
- <i class="glyphicons remove-2" aria-hidden="true" />
33
+ <i class="glyphicons remove-2" aria-hidden="true"></i>
34
34
  </button>
35
- <i class="glyphicons move" aria-hidden="true" />
35
+ <i class="glyphicons move" aria-hidden="true"></i>
36
36
  </div>
37
37
  </div>
38
38
 
@@ -50,7 +50,7 @@
50
50
  }
51
51
 
52
52
  &:focus-visible {
53
- outline: 2px solid #66afe9;
53
+ outline: 2px solid #428bca;
54
54
  }
55
55
  }
56
56
 
@@ -43,6 +43,7 @@
43
43
 
44
44
  onMount(() => {
45
45
  // Instansiate select2 ourselves to be able to use more options.
46
+ if (multiple) element.setAttribute('multiple', '');
46
47
  jQuery(element)
47
48
  .select2({
48
49
  placeholder,
@@ -84,15 +85,8 @@
84
85
  {label}
85
86
  </slot>
86
87
  </label>
87
- <select
88
- bind:this={element}
89
- {id}
90
- name={!multiple ? name : undefined}
91
- {disabled}
92
- {multiple}
93
- {required}
94
- >
95
- <option />
88
+ <select bind:this={element} {id} name={!multiple ? name : undefined} {disabled} {required}>
89
+ <option></option>
96
90
  {#each options as option}
97
91
  <option value={option.value ?? option}>
98
92
  {option.label ?? option}
@@ -103,7 +97,7 @@
103
97
  {#if multiple}
104
98
  <select {name} hidden multiple {value}>
105
99
  {#each options as option}
106
- <option value={option.value ?? option} />
100
+ <option value={option.value ?? option}></option>
107
101
  {/each}
108
102
  </select>
109
103
  {/if}
@@ -70,6 +70,6 @@
70
70
  data-types={selectable}
71
71
  {disabled}
72
72
  {required}
73
- />
73
+ ></select>
74
74
  <slot />
75
75
  </div>
@@ -69,7 +69,7 @@
69
69
  {value}
70
70
  {...$$restProps}
71
71
  on:input={onInput}
72
- />
72
+ ></textarea>
73
73
  {:else}
74
74
  <input
75
75
  {id}
@@ -64,7 +64,7 @@
64
64
  value={value.join(',')}
65
65
  />
66
66
  {#if disabled}
67
- <div class="disabled-overlay" />
67
+ <div class="disabled-overlay"></div>
68
68
  {/if}
69
69
  <slot />
70
70
  </div>
@@ -143,7 +143,7 @@
143
143
  >
144
144
  <!-- This is handled by the keydown event on svelte:window -->
145
145
  <!-- svelte-ignore a11y-no-static-element-interactions a11y-click-events-have-key-events -->
146
- <div class="overlay" on:click={close} />
146
+ <div class="overlay" on:click={close}></div>
147
147
  <div class="modal-dialog" role="document">
148
148
  <div class="modal-content">
149
149
  <div class="modal-header">
@@ -80,7 +80,7 @@
80
80
  value={displayName}
81
81
  />
82
82
  {#if disabled}
83
- <div class="disabled-overlay" />
83
+ <div class="disabled-overlay"></div>
84
84
  {/if}
85
85
  <slot />
86
86
  </div>
@@ -65,7 +65,7 @@
65
65
  {value}
66
66
  />
67
67
  {#if disabled}
68
- <div class="disabled-overlay" />
68
+ <div class="disabled-overlay"></div>
69
69
  {/if}
70
70
  <slot />
71
71
  </div>
@@ -44,7 +44,6 @@
44
44
  <input
45
45
  id={`${id}_${index}`}
46
46
  class="sr-only"
47
- checked={option.value || option}
48
47
  disabled={isDisabled(option, disabled)}
49
48
  type="radio"
50
49
  value={option.value || option}
@@ -91,10 +90,6 @@
91
90
  border-radius: 50%;
92
91
  }
93
92
 
94
- :global(.focus-visible) + &::before {
95
- box-shadow: 0 0 0 0.2rem rgb(66 139 202 / 40%);
96
- }
97
-
98
93
  input:checked + &::before {
99
94
  background-color: #428bca;
100
95
  border-color: transparent;
@@ -111,6 +106,10 @@
111
106
  border-radius: 50%;
112
107
  }
113
108
 
109
+ input:focus-visible + &::before {
110
+ box-shadow: 0 0 0 0.2rem rgb(66 139 202 / 40%);
111
+ }
112
+
114
113
  &.disabled {
115
114
  cursor: not-allowed;
116
115
  opacity: 0.7;
@@ -65,7 +65,7 @@
65
65
  {value}
66
66
  />
67
67
  {#if disabled}
68
- <div class="disabled-overlay" />
68
+ <div class="disabled-overlay"></div>
69
69
  {/if}
70
70
  <slot />
71
71
  </div>
@@ -91,19 +91,19 @@
91
91
  on:enter={() => addButtonElement.focus()}
92
92
  />
93
93
  </Sortable>
94
- <div class="ui-resizable-handle ui-resizable-s" use:resizer />
94
+ <div class="ui-resizable-handle ui-resizable-s" use:resizer></div>
95
95
  </div>
96
96
  <button
97
97
  bind:this={addButtonElement}
98
98
  class="list-component__add-item btn btn-link"
99
99
  on:click={addItem}
100
100
  >
101
- <i class="glyphicons plus" aria-hidden="true" />
101
+ <i class="glyphicons plus" aria-hidden="true"></i>
102
102
  {i18n('add')}
103
103
  </button>
104
104
  </div>
105
105
  {#if disabled}
106
- <div class="disabled-overlay" />
106
+ <div class="disabled-overlay"></div>
107
107
  {/if}
108
108
  <DataHolder {id} {name} {required} {value} />
109
109
  </div>
@@ -68,10 +68,10 @@
68
68
 
69
69
  <span class="input-group-btn">
70
70
  <button class="btn btn-default" type="button" on:click={updateItem}>
71
- <i class="glyphicons ok-2" />
71
+ <i class="glyphicons ok-2"></i>
72
72
  </button>
73
73
  <button class="btn btn-default" type="button" on:click={abortEdit}>
74
- <i class="glyphicons remove-2" />
74
+ <i class="glyphicons remove-2"></i>
75
75
  </button>
76
76
  </span>
77
77
  </div>
@@ -82,12 +82,12 @@
82
82
  <span class="item-name">{value}</span>
83
83
  <div class="list-component__item-actions">
84
84
  <button on:click={editItem}>
85
- <i class="glyphicons edit" aria-hidden="true" />
85
+ <i class="glyphicons edit" aria-hidden="true"></i>
86
86
  </button>
87
87
  <button on:click={removeItem}>
88
- <i class="glyphicons remove-2" aria-hidden="true" />
88
+ <i class="glyphicons remove-2" aria-hidden="true"></i>
89
89
  </button>
90
- <i class="glyphicons move" aria-hidden="true" />
90
+ <i class="glyphicons move" aria-hidden="true"></i>
91
91
  </div>
92
92
  </div>
93
93
  {/if}
@@ -99,17 +99,16 @@
99
99
  }
100
100
 
101
101
  &:focus-visible {
102
- outline: 2px solid #66afe9;
102
+ outline: 2px solid #428bca;
103
103
  }
104
104
  }
105
105
 
106
106
  .list-component__item-actions {
107
107
  button {
108
108
  padding: 0;
109
+ appearance: none;
109
110
  background: none;
110
111
  border: none;
111
- appearance: none;
112
- appearance: none;
113
112
  }
114
113
 
115
114
  :global(li:focus-within) & i {
@@ -24,6 +24,9 @@
24
24
  </script>
25
25
 
26
26
  <ul
27
+ class="list-component__list"
28
+ on:consider={onConsider}
29
+ on:finalize={onFinalize}
27
30
  use:dndzone={{
28
31
  items,
29
32
  flipDurationMs: 100,
@@ -33,9 +36,6 @@
33
36
  autoAriaDisabled: true,
34
37
  dragDisabled,
35
38
  }}
36
- on:consider={onConsider}
37
- on:finalize={onFinalize}
38
- class="list-component__list"
39
39
  >
40
40
  {#each items as item (item.id)}
41
41
  <li class="list-component__item" animate:flip={{ duration: 100 }}>
@@ -46,10 +46,9 @@
46
46
 
47
47
  <style>
48
48
  ul:focus,
49
- ul :global(li.focus-visible) {
49
+ ul li:focus-visible {
50
50
  position: relative;
51
51
  z-index: 1;
52
- outline: 2px solid #66afe9;
52
+ outline: 2px solid #428bca;
53
53
  }
54
-
55
54
  </style>
@@ -1,22 +1,22 @@
1
- import 'focus-visible';
2
-
3
- export default function createConfigApp(App) {
1
+ export default function createConfigApp(callback) {
4
2
  window.setValues = (values) => {
5
3
  // window?.sv?.setValues(values);
6
4
  window.CONFIG_VALUES = values;
7
5
 
6
+ const props = {
7
+ ...window.CONFIG_APP_PROPS,
8
+ values,
9
+ };
10
+
8
11
  const target = document.querySelector('#app_root') || document.querySelector('body');
9
12
  target.innerHTML = '';
10
13
 
11
- const app = new App({
12
- target,
13
- props: {
14
- ...window.CONFIG_APP_PROPS,
15
- values,
16
- },
17
- });
18
-
19
- return app;
14
+ if (callback?.toString()?.startsWith('class')) {
15
+ // Legacy support for class components
16
+ // eslint-disable-next-line no-new, new-cap
17
+ return new callback({ target, props });
18
+ }
19
+ return callback({ target, props });
20
20
  };
21
21
 
22
22
  window.getValues = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soleil-se/config-svelte",
3
- "version": "1.24.0",
3
+ "version": "1.25.0",
4
4
  "main": "./index.js",
5
5
  "module": "./index.js",
6
6
  "svelte": "./index.js",
@@ -8,26 +8,25 @@
8
8
  "license": "UNLICENSED",
9
9
  "sideEffects": false,
10
10
  "peerDependencies": {
11
- "@sitevision/api": "*",
12
- "svelte": "^3.46.0 || ^4.0.0"
11
+ "@sitevision/api": "^2024.4.2",
12
+ "svelte": "^3.46.0 || ^4.0.0 || ^5.0.0-next || ^5.0.0"
13
13
  },
14
14
  "devDependencies": {
15
- "@soleil-se/eslint-config": "^5.1.1",
15
+ "@soleil-se/eslint-config": "^5.1.2",
16
16
  "@soleil-se/stylelint-config": "^3.1.1",
17
- "eslint": "^8.51.0",
17
+ "eslint": "^8.57.0",
18
18
  "eslint-config-airbnb-base": "^15.0.0",
19
- "eslint-config-prettier": "^9.0.0",
20
- "eslint-plugin-import": "^2.28.1",
21
- "eslint-plugin-svelte": "^2.34.0",
22
- "stylelint": "^15.10.3",
19
+ "eslint-config-prettier": "^9.1.0",
20
+ "eslint-plugin-import": "^2.29.1",
21
+ "eslint-plugin-svelte": "^2.38.0",
22
+ "stylelint": "^15.11.0",
23
23
  "svelte": "^4.2.1",
24
- "svelte-preprocess": "^5.0.4"
24
+ "svelte-preprocess": "^5.1.4"
25
25
  },
26
26
  "dependencies": {
27
27
  "@soleil-se/config-validate": "^1.1.2",
28
28
  "a11y-dialog": "7.5.2",
29
- "focus-visible": "^5.2.0",
30
- "svelte-dnd-action": "^0.9.31"
29
+ "svelte-dnd-action": "^0.9.44"
31
30
  },
32
31
  "homepage": "https://docs.soleil.se/packages/config-svelte",
33
32
  "description": "A collection of Svelte components and utilities for WebApp, RESTApp and Widget configurations.",