svelte 4.0.0 → 4.0.2

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/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "svelte",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Cybernetically enhanced web apps",
5
5
  "type": "module",
6
6
  "module": "src/runtime/index.js",
7
7
  "main": "src/runtime/index.js",
8
8
  "files": [
9
9
  "src",
10
+ "!src/**/tsconfig.json",
10
11
  "types",
11
12
  "compiler.*",
12
13
  "register.js",
@@ -57,7 +58,7 @@
57
58
  "default": "./src/runtime/store/index.js"
58
59
  },
59
60
  "./internal/disclose-version": {
60
- "import": "./src/runtime/internal/disclose-version/index.js"
61
+ "default": "./src/runtime/internal/disclose-version/index.js"
61
62
  },
62
63
  "./transition": {
63
64
  "types": "./types/index.d.ts",
@@ -92,8 +93,8 @@
92
93
  "@ampproject/remapping": "^2.2.1",
93
94
  "@jridgewell/sourcemap-codec": "^1.4.15",
94
95
  "@jridgewell/trace-mapping": "^0.3.18",
95
- "acorn": "^8.8.2",
96
- "aria-query": "^5.2.1",
96
+ "acorn": "^8.9.0",
97
+ "aria-query": "^5.3.0",
97
98
  "axobject-query": "^3.2.1",
98
99
  "code-red": "^1.0.3",
99
100
  "css-tree": "^2.3.1",
@@ -104,35 +105,35 @@
104
105
  "periscopic": "^3.1.0"
105
106
  },
106
107
  "devDependencies": {
107
- "@playwright/test": "^1.34.3",
108
+ "@playwright/test": "^1.35.1",
108
109
  "@rollup/plugin-commonjs": "^24.1.0",
109
110
  "@rollup/plugin-json": "^6.0.0",
110
- "@rollup/plugin-node-resolve": "^15.0.2",
111
+ "@rollup/plugin-node-resolve": "^15.1.0",
111
112
  "@sveltejs/eslint-config": "^6.0.4",
112
113
  "@types/aria-query": "^5.0.1",
113
114
  "@types/estree": "^1.0.1",
114
- "@types/node": "^14.14.31",
115
+ "@types/node": "^14.18.51",
115
116
  "agadoo": "^3.0.0",
116
117
  "dts-buddy": "^0.1.7",
117
118
  "esbuild": "^0.17.19",
118
- "happy-dom": "^9.18.3",
119
- "jsdom": "^21.1.1",
119
+ "happy-dom": "^9.20.3",
120
+ "jsdom": "^21.1.2",
120
121
  "kleur": "^4.1.5",
121
- "rollup": "^3.20.2",
122
+ "rollup": "^3.25.1",
122
123
  "source-map": "^0.7.4",
123
124
  "tiny-glob": "^0.2.9",
124
- "typescript": "^5.0.4",
125
- "vitest": "^0.31.1"
125
+ "typescript": "^5.1.3",
126
+ "vitest": "^0.31.4"
126
127
  },
127
128
  "scripts": {
128
129
  "format": "prettier . --cache --plugin-search-dir=. --write",
129
- "check": "prettier . --cache --plugin-search-dir=. --check",
130
+ "check": "tsc --noEmit",
130
131
  "test": "vitest run && echo \"manually check that there are no type errors in test/types by opening the files in there\"",
131
132
  "build": "rollup -c && pnpm types",
132
133
  "generate:version": "node ./scripts/generate-version.js",
133
134
  "dev": "rollup -cw",
134
135
  "posttest": "agadoo src/internal/index.js",
135
136
  "types": "node ./scripts/generate-dts.js",
136
- "lint": "eslint \"{src,test}/**/*.{ts,js}\" --cache"
137
+ "lint": "prettier . --cache --plugin-search-dir=. --check && eslint \"{src,test}/**/*.{ts,js}\" --cache"
137
138
  }
138
139
  }
@@ -1,2 +1,2 @@
1
1
  // This file is automatically generated
2
- export default new Set(["HtmlTag","HtmlTagHydration","ResizeObserverSingleton","SvelteComponent","SvelteComponentDev","SvelteComponentTyped","SvelteElement","action_destroyer","add_attribute","add_classes","add_flush_callback","add_iframe_resize_listener","add_location","add_render_callback","add_styles","add_transform","afterUpdate","append","append_dev","append_empty_stylesheet","append_hydration","append_hydration_dev","append_styles","assign","attr","attr_dev","attribute_to_object","beforeUpdate","bind","binding_callbacks","blank_object","bubble","check_outros","children","claim_comment","claim_component","claim_element","claim_html_tag","claim_space","claim_svg_element","claim_text","clear_loops","comment","component_subscribe","compute_rest_props","compute_slots","construct_svelte_component","construct_svelte_component_dev","contenteditable_truthy_values","createEventDispatcher","create_animation","create_bidirectional_transition","create_component","create_custom_element","create_in_transition","create_out_transition","create_slot","create_ssr_component","current_component","custom_event","dataset_dev","debug","destroy_block","destroy_component","destroy_each","detach","detach_after_dev","detach_before_dev","detach_between_dev","detach_dev","dirty_components","dispatch_dev","each","element","element_is","empty","end_hydrating","ensure_array_like","ensure_array_like_dev","escape","escape_attribute_value","escape_object","exclude_internal_props","fix_and_destroy_block","fix_and_outro_and_destroy_block","fix_position","flush","flush_render_callbacks","getAllContexts","getContext","get_all_dirty_from_scope","get_binding_group_value","get_current_component","get_custom_elements_slots","get_root_for_style","get_slot_changes","get_spread_object","get_spread_update","get_store_value","get_svelte_dataset","globals","group_outros","handle_promise","hasContext","has_prop","head_selector","identity","init","init_binding_group","init_binding_group_dynamic","insert","insert_dev","insert_hydration","insert_hydration_dev","intros","invalid_attribute_name_character","is_client","is_crossorigin","is_empty","is_function","is_promise","is_void","listen","listen_dev","loop","loop_guard","merge_ssr_styles","missing_component","mount_component","noop","not_equal","now","null_to_empty","object_without_properties","onDestroy","onMount","once","outro_and_destroy_block","prevent_default","prop_dev","query_selector_all","raf","resize_observer_border_box","resize_observer_content_box","resize_observer_device_pixel_content_box","run","run_all","safe_not_equal","schedule_update","select_multiple_value","select_option","select_options","select_value","self","setContext","set_attributes","set_current_component","set_custom_element_data","set_custom_element_data_map","set_data","set_data_contenteditable","set_data_contenteditable_dev","set_data_dev","set_data_maybe_contenteditable","set_data_maybe_contenteditable_dev","set_dynamic_element_data","set_input_type","set_input_value","set_now","set_raf","set_store_value","set_style","set_svg_attributes","space","split_css_unit","spread","src_url_equal","start_hydrating","stop_immediate_propagation","stop_propagation","subscribe","svg_element","text","tick","time_ranges_to_array","to_number","toggle_class","transition_in","transition_out","trusted","update_await_block_branch","update_keyed_each","update_slot","update_slot_base","validate_component","validate_dynamic_element","validate_each_keys","validate_slots","validate_store","validate_void_dynamic_element","xlink_attr"]);
2
+ export default new Set(["HtmlTag","HtmlTagHydration","ResizeObserverSingleton","SvelteComponent","SvelteComponentDev","SvelteComponentTyped","SvelteElement","action_destroyer","add_attribute","add_classes","add_flush_callback","add_iframe_resize_listener","add_location","add_render_callback","add_styles","add_transform","afterUpdate","append","append_dev","append_empty_stylesheet","append_hydration","append_hydration_dev","append_styles","assign","attr","attr_dev","attribute_to_object","beforeUpdate","bind","binding_callbacks","blank_object","bubble","check_outros","children","claim_comment","claim_component","claim_element","claim_html_tag","claim_space","claim_svg_element","claim_text","clear_loops","comment","component_subscribe","compute_rest_props","compute_slots","construct_svelte_component","construct_svelte_component_dev","contenteditable_truthy_values","createEventDispatcher","create_animation","create_bidirectional_transition","create_component","create_custom_element","create_in_transition","create_out_transition","create_slot","create_ssr_component","current_component","custom_event","dataset_dev","debug","destroy_block","destroy_component","destroy_each","detach","detach_after_dev","detach_before_dev","detach_between_dev","detach_dev","dirty_components","dispatch_dev","each","element","element_is","empty","end_hydrating","ensure_array_like","ensure_array_like_dev","escape","escape_attribute_value","escape_object","exclude_internal_props","fix_and_destroy_block","fix_and_outro_and_destroy_block","fix_position","flush","flush_render_callbacks","getAllContexts","getContext","get_all_dirty_from_scope","get_binding_group_value","get_current_component","get_custom_elements_slots","get_root_for_style","get_slot_changes","get_spread_object","get_spread_update","get_store_value","get_svelte_dataset","globals","group_outros","handle_promise","hasContext","has_prop","head_selector","identity","init","init_binding_group","init_binding_group_dynamic","insert","insert_dev","insert_hydration","insert_hydration_dev","intros","invalid_attribute_name_character","is_client","is_crossorigin","is_empty","is_function","is_promise","is_void","listen","listen_dev","loop","loop_guard","merge_ssr_styles","missing_component","mount_component","noop","not_equal","now","null_to_empty","object_without_properties","onDestroy","onMount","once","outro_and_destroy_block","prevent_default","prop_dev","query_selector_all","raf","resize_observer_border_box","resize_observer_content_box","resize_observer_device_pixel_content_box","run","run_all","safe_not_equal","schedule_update","select_multiple_value","select_option","select_options","select_value","self","setContext","set_attributes","set_current_component","set_custom_element_data","set_custom_element_data_map","set_data","set_data_contenteditable","set_data_contenteditable_dev","set_data_dev","set_data_maybe_contenteditable","set_data_maybe_contenteditable_dev","set_dynamic_element_data","set_input_type","set_input_value","set_now","set_raf","set_store_value","set_style","set_svg_attributes","space","split_css_unit","spread","src_url_equal","srcset_url_equal","start_hydrating","stop_immediate_propagation","stop_propagation","subscribe","svg_element","text","tick","time_ranges_to_array","to_number","toggle_class","transition_in","transition_out","trusted","update_await_block_branch","update_keyed_each","update_slot","update_slot_base","validate_component","validate_dynamic_element","validate_each_keys","validate_slots","validate_store","validate_void_dynamic_element","xlink_attr"]);
@@ -694,7 +694,11 @@ export default class Element extends Node {
694
694
  );
695
695
  }
696
696
  // no-redundant-roles
697
- if (current_role === get_implicit_role(this.name, attribute_map)) {
697
+ if (
698
+ current_role === get_implicit_role(this.name, attribute_map) &&
699
+ // <ul role="list"> is ok because CSS list-style:none removes the semantics and this is a way to bring them back
700
+ !['ul', 'ol', 'li'].includes(this.name)
701
+ ) {
698
702
  component.warn(
699
703
  attribute,
700
704
  compiler_warnings.a11y_no_redundant_roles(current_role)
@@ -36,6 +36,7 @@ export function unpack_destructuring({
36
36
  if (in_rest_element) {
37
37
  context_rest_properties.set(node.name, node);
38
38
  }
39
+ component.used_names.add(node.name);
39
40
  } else if (node.type === 'ArrayPattern') {
40
41
  node.elements.forEach((element, i) => {
41
42
  if (!element) {
@@ -64,6 +64,9 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
64
64
  /** @type {boolean} */
65
65
  is_src;
66
66
 
67
+ /** @type {boolean} */
68
+ is_srcset;
69
+
67
70
  /** @type {boolean} */
68
71
  is_select_value_attribute;
69
72
 
@@ -120,6 +123,9 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
120
123
  this.is_src =
121
124
  this.name === 'src' &&
122
125
  (!this.parent.node.namespace || this.parent.node.namespace === namespaces.html);
126
+ this.is_srcset =
127
+ this.name === 'srcset' &&
128
+ (!this.parent.node.namespace || this.parent.node.namespace === namespaces.html);
123
129
  this.should_cache = should_cache(this);
124
130
  }
125
131
 
@@ -164,6 +170,11 @@ export default class AttributeWrapper extends BaseAttributeWrapper {
164
170
  b`if (!@src_url_equal(${element.var}.src, ${init})) ${method}(${element.var}, "${name}", ${this.last});`
165
171
  );
166
172
  updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
173
+ } else if (this.is_srcset) {
174
+ block.chunks.hydrate.push(
175
+ b`if (!@srcset_url_equal(${element.var}, ${init})) ${method}(${element.var}, "${name}", ${this.last});`
176
+ );
177
+ updater = b`${method}(${element.var}, "${name}", ${should_cache ? this.last : value});`;
167
178
  } else if (property_name) {
168
179
  block.chunks.hydrate.push(b`${element.var}.${property_name} = ${init};`);
169
180
  updater = block.renderer.options.dev
@@ -403,7 +414,7 @@ Object.keys(attribute_lookup).forEach((name) => {
403
414
 
404
415
  /** @param {AttributeWrapper} attribute */
405
416
  function should_cache(attribute) {
406
- return attribute.is_src || attribute.node.should_cache();
417
+ return attribute.is_src || attribute.is_srcset || attribute.node.should_cache();
407
418
  }
408
419
  const regex_contains_checked_or_group = /checked|group/;
409
420
 
@@ -233,6 +233,14 @@ export default class ElementWrapper extends Wrapper {
233
233
  strip_whitespace,
234
234
  next_sibling
235
235
  );
236
+
237
+ // in the case of `parent_block -> child_dynamic_element_block -> child_dynamic_element`
238
+ // `child_dynamic_element_block.add_intro/outro` is called inside `new ElementWrapper()`
239
+ // but when `is_local === true` it does not bubble to parent_block
240
+ // we manually add transitions back to the parent_block (#8233)
241
+ if (node.intro) block.add_intro(node.intro.is_local);
242
+ if (node.outro) block.add_outro(node.outro.is_local);
243
+
236
244
  // the original svelte:element is never used for rendering, because
237
245
  // it gets assigned a child_dynamic_element which is used in all rendering logic.
238
246
  // so doing all of this on the original svelte:element will just cause double
@@ -266,10 +274,10 @@ export default class ElementWrapper extends Wrapper {
266
274
  this.event_handlers = this.node.handlers.map(
267
275
  (event_handler) => new EventHandler(event_handler, this)
268
276
  );
269
- if (node.intro || node.outro) {
270
- if (node.intro) block.add_intro(node.intro.is_local);
271
- if (node.outro) block.add_outro(node.outro.is_local);
272
- }
277
+
278
+ if (node.intro) block.add_intro(node.intro.is_local);
279
+ if (node.outro) block.add_outro(node.outro.is_local);
280
+
273
281
  if (node.animation) {
274
282
  block.add_animation();
275
283
  }
@@ -26,7 +26,7 @@ export default class RawMustacheTagWrapper extends Tag {
26
26
  render(block, parent_node, _parent_nodes) {
27
27
  const in_head = is_head(parent_node);
28
28
  const can_use_innerhtml = !in_head && parent_node && !this.prev && !this.next;
29
- if (can_use_innerhtml) {
29
+ if (can_use_innerhtml && !this.renderer.options.hydratable) {
30
30
  /** @param {import('estree').Node} content */
31
31
  const insert = (content) => b`${parent_node}.innerHTML = ${content};`[0];
32
32
  const { init } = this.rename_this_method(block, (content) => insert(content));
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Actions can return an object containing the two properties defined in this interface. Both are optional.
3
3
  * - update: An action can have a parameter. This method will be called whenever that parameter changes,
4
- * immediately after Svelte has applied updates to the markup. `ActionReturn` and `ActionReturn<never>` both
5
- * mean that the action accepts no parameters, which makes it illegal to set the `update` method.
4
+ * immediately after Svelte has applied updates to the markup. `ActionReturn` and `ActionReturn<undefined>` both
5
+ * mean that the action accepts no parameters.
6
6
  * - destroy: Method that is called after the element is unmounted
7
7
  *
8
8
  * Additionally, you can specify which additional attributes and events the action enables on the applied element.
@@ -27,10 +27,10 @@
27
27
  * Docs: https://svelte.dev/docs/svelte-action
28
28
  */
29
29
  export interface ActionReturn<
30
- Parameter = never,
30
+ Parameter = undefined,
31
31
  Attributes extends Record<string, any> = Record<never, any>
32
32
  > {
33
- update?: [Parameter] extends [never] ? never : (parameter: Parameter) => void;
33
+ update?: (parameter: Parameter) => void;
34
34
  destroy?: () => void;
35
35
  /**
36
36
  * ### DO NOT USE THIS
@@ -50,7 +50,7 @@ export interface ActionReturn<
50
50
  * // ...
51
51
  * }
52
52
  * ```
53
- * `Action<HTMLDivElement>` and `Action<HTMLDiveElement, never>` both signal that the action accepts no parameters.
53
+ * `Action<HTMLDivElement>` and `Action<HTMLDiveElement, undefined>` both signal that the action accepts no parameters.
54
54
  *
55
55
  * You can return an object with methods `update` and `destroy` from the function and type which additional attributes and events it has.
56
56
  * See interface `ActionReturn` for more details.
@@ -59,13 +59,11 @@ export interface ActionReturn<
59
59
  */
60
60
  export interface Action<
61
61
  Element = HTMLElement,
62
- Parameter = never,
62
+ Parameter = undefined,
63
63
  Attributes extends Record<string, any> = Record<never, any>
64
64
  > {
65
65
  <Node extends Element>(
66
- ...args: [Parameter] extends [never]
67
- ? [node: Node]
68
- : undefined extends Parameter
66
+ ...args: undefined extends Parameter
69
67
  ? [node: Node, parameter?: Parameter]
70
68
  : [node: Node, parameter: Parameter]
71
69
  ): void | ActionReturn<Parameter, Attributes>;
@@ -73,4 +71,3 @@ export interface Action<
73
71
 
74
72
  // Implementation notes:
75
73
  // - undefined extends X instead of X extends undefined makes this work better with both strict and nonstrict mode
76
- // - [X] extends [never] is needed, X extends never would reduce the whole resulting type to never and not to one of the condition outcomes
@@ -13,7 +13,9 @@ import {
13
13
  start_hydrating,
14
14
  end_hydrating,
15
15
  get_custom_elements_slots,
16
- insert
16
+ insert,
17
+ element,
18
+ attr
17
19
  } from './dom.js';
18
20
  import { transition_in } from './transitions.js';
19
21
 
@@ -157,23 +159,29 @@ export let SvelteElement;
157
159
 
158
160
  if (typeof HTMLElement === 'function') {
159
161
  SvelteElement = class extends HTMLElement {
160
- $$componentCtor;
161
- $$slots;
162
- $$component;
163
- $$connected = false;
164
- $$data = {};
165
- $$reflecting = false;
166
- /** @type {Record<string, CustomElementPropDefinition>} */
167
- $$props_definition = {};
168
- /** @type {Record<string, Function[]>} */
169
- $$listeners = {};
170
- /** @type {Map<Function, Function>} */
171
- $$listener_unsubscribe_fns = new Map();
162
+ /** The Svelte component constructor */
163
+ $$ctor;
164
+ /** Slots */
165
+ $$s;
166
+ /** The Svelte component instance */
167
+ $$c;
168
+ /** Whether or not the custom element is connected */
169
+ $$cn = false;
170
+ /** Component props data */
171
+ $$d = {};
172
+ /** `true` if currently in the process of reflecting component props back to attributes */
173
+ $$r = false;
174
+ /** @type {Record<string, CustomElementPropDefinition>} Props definition (name, reflected, type etc) */
175
+ $$p_d = {};
176
+ /** @type {Record<string, Function[]>} Event listeners */
177
+ $$l = {};
178
+ /** @type {Map<Function, Function>} Event listener unsubscribe functions */
179
+ $$l_u = new Map();
172
180
 
173
181
  constructor($$componentCtor, $$slots, use_shadow_dom) {
174
182
  super();
175
- this.$$componentCtor = $$componentCtor;
176
- this.$$slots = $$slots;
183
+ this.$$ctor = $$componentCtor;
184
+ this.$$s = $$slots;
177
185
  if (use_shadow_dom) {
178
186
  this.attachShadow({ mode: 'open' });
179
187
  }
@@ -183,32 +191,32 @@ if (typeof HTMLElement === 'function') {
183
191
  // We can't determine upfront if the event is a custom event or not, so we have to
184
192
  // listen to both. If someone uses a custom event with the same name as a regular
185
193
  // browser event, this fires twice - we can't avoid that.
186
- this.$$listeners[type] = this.$$listeners[type] || [];
187
- this.$$listeners[type].push(listener);
188
- if (this.$$component) {
189
- const unsub = this.$$component.$on(type, listener);
190
- this.$$listener_unsubscribe_fns.set(listener, unsub);
194
+ this.$$l[type] = this.$$l[type] || [];
195
+ this.$$l[type].push(listener);
196
+ if (this.$$c) {
197
+ const unsub = this.$$c.$on(type, listener);
198
+ this.$$l_u.set(listener, unsub);
191
199
  }
192
200
  super.addEventListener(type, listener, options);
193
201
  }
194
202
 
195
203
  removeEventListener(type, listener, options) {
196
204
  super.removeEventListener(type, listener, options);
197
- if (this.$$component) {
198
- const unsub = this.$$listener_unsubscribe_fns.get(listener);
205
+ if (this.$$c) {
206
+ const unsub = this.$$l_u.get(listener);
199
207
  if (unsub) {
200
208
  unsub();
201
- this.$$listener_unsubscribe_fns.delete(listener);
209
+ this.$$l_u.delete(listener);
202
210
  }
203
211
  }
204
212
  }
205
213
 
206
214
  async connectedCallback() {
207
- this.$$connected = true;
208
- if (!this.$$component) {
215
+ this.$$cn = true;
216
+ if (!this.$$c) {
209
217
  // We wait one tick to let possible child slot elements be created/mounted
210
218
  await Promise.resolve();
211
- if (!this.$$connected) {
219
+ if (!this.$$cn) {
212
220
  return;
213
221
  }
214
222
  function create_slot(name) {
@@ -216,9 +224,9 @@ if (typeof HTMLElement === 'function') {
216
224
  let node;
217
225
  const obj = {
218
226
  c: function create() {
219
- node = document.createElement('slot');
227
+ node = element('slot');
220
228
  if (name !== 'default') {
221
- node.setAttribute('name', name);
229
+ attr(node, 'name', name);
222
230
  }
223
231
  },
224
232
  /**
@@ -239,74 +247,89 @@ if (typeof HTMLElement === 'function') {
239
247
  }
240
248
  const $$slots = {};
241
249
  const existing_slots = get_custom_elements_slots(this);
242
- for (const name of this.$$slots) {
250
+ for (const name of this.$$s) {
243
251
  if (name in existing_slots) {
244
252
  $$slots[name] = [create_slot(name)];
245
253
  }
246
254
  }
247
255
  for (const attribute of this.attributes) {
248
256
  // this.$$data takes precedence over this.attributes
249
- const name = this.$$get_prop_name(attribute.name);
250
- if (!(name in this.$$data)) {
251
- this.$$data[name] = get_custom_element_value(
252
- name,
253
- attribute.value,
254
- this.$$props_definition,
255
- 'toProp'
256
- );
257
+ const name = this.$$g_p(attribute.name);
258
+ if (!(name in this.$$d)) {
259
+ this.$$d[name] = get_custom_element_value(name, attribute.value, this.$$p_d, 'toProp');
257
260
  }
258
261
  }
259
- this.$$component = new this.$$componentCtor({
262
+ this.$$c = new this.$$ctor({
260
263
  target: this.shadowRoot || this,
261
264
  props: {
262
- ...this.$$data,
265
+ ...this.$$d,
263
266
  $$slots,
264
267
  $$scope: {
265
268
  ctx: []
266
269
  }
267
270
  }
268
271
  });
269
- for (const type in this.$$listeners) {
270
- for (const listener of this.$$listeners[type]) {
271
- const unsub = this.$$component.$on(type, listener);
272
- this.$$listener_unsubscribe_fns.set(listener, unsub);
272
+
273
+ // Reflect component props as attributes
274
+ const reflect_attributes = () => {
275
+ this.$$r = true;
276
+ for (const key in this.$$p_d) {
277
+ this.$$d[key] = this.$$c.$$.ctx[this.$$c.$$.props[key]];
278
+ if (this.$$p_d[key].reflect) {
279
+ const attribute_value = get_custom_element_value(
280
+ key,
281
+ this.$$d[key],
282
+ this.$$p_d,
283
+ 'toAttribute'
284
+ );
285
+ if (attribute_value == null) {
286
+ this.removeAttribute(key);
287
+ } else {
288
+ this.setAttribute(this.$$p_d[key].attribute || key, attribute_value);
289
+ }
290
+ }
291
+ }
292
+ this.$$r = false;
293
+ };
294
+ this.$$c.$$.after_update.push(reflect_attributes);
295
+ reflect_attributes(); // once initially because after_update is added too late for first render
296
+
297
+ for (const type in this.$$l) {
298
+ for (const listener of this.$$l[type]) {
299
+ const unsub = this.$$c.$on(type, listener);
300
+ this.$$l_u.set(listener, unsub);
273
301
  }
274
302
  }
275
- this.$$listeners = {};
303
+ this.$$l = {};
276
304
  }
277
305
  }
278
306
 
279
307
  // We don't need this when working within Svelte code, but for compatibility of people using this outside of Svelte
280
308
  // and setting attributes through setAttribute etc, this is helpful
281
309
  attributeChangedCallback(attr, _oldValue, newValue) {
282
- if (this.$$reflecting) return;
283
- attr = this.$$get_prop_name(attr);
284
- this.$$data[attr] = get_custom_element_value(
285
- attr,
286
- newValue,
287
- this.$$props_definition,
288
- 'toProp'
289
- );
290
- this.$$component?.$set({ [attr]: this.$$data[attr] });
310
+ if (this.$$r) return;
311
+ attr = this.$$g_p(attr);
312
+ this.$$d[attr] = get_custom_element_value(attr, newValue, this.$$p_d, 'toProp');
313
+ this.$$c?.$set({ [attr]: this.$$d[attr] });
291
314
  }
292
315
 
293
316
  disconnectedCallback() {
294
- this.$$connected = false;
317
+ this.$$cn = false;
295
318
  // In a microtask, because this could be a move within the DOM
296
319
  Promise.resolve().then(() => {
297
- if (!this.$$connected) {
298
- this.$$component.$destroy();
299
- this.$$component = undefined;
320
+ if (!this.$$cn) {
321
+ this.$$c.$destroy();
322
+ this.$$c = undefined;
300
323
  }
301
324
  });
302
325
  }
303
326
 
304
- $$get_prop_name(attribute_name) {
327
+ $$g_p(attribute_name) {
305
328
  return (
306
- Object.keys(this.$$props_definition).find(
329
+ Object.keys(this.$$p_d).find(
307
330
  (key) =>
308
- this.$$props_definition[key].attribute === attribute_name ||
309
- (!this.$$props_definition[key].attribute && key.toLowerCase() === attribute_name)
331
+ this.$$p_d[key].attribute === attribute_name ||
332
+ (!this.$$p_d[key].attribute && key.toLowerCase() === attribute_name)
310
333
  ) || attribute_name
311
334
  );
312
335
  }
@@ -371,7 +394,7 @@ export function create_custom_element(
371
394
  const Class = class extends SvelteElement {
372
395
  constructor() {
373
396
  super(Component, slots, use_shadow_dom);
374
- this.$$props_definition = props_definition;
397
+ this.$$p_d = props_definition;
375
398
  }
376
399
  static get observedAttributes() {
377
400
  return Object.keys(props_definition).map((key) =>
@@ -382,36 +405,19 @@ export function create_custom_element(
382
405
  Object.keys(props_definition).forEach((prop) => {
383
406
  Object.defineProperty(Class.prototype, prop, {
384
407
  get() {
385
- return this.$$component && prop in this.$$component
386
- ? this.$$component[prop]
387
- : this.$$data[prop];
408
+ return this.$$c && prop in this.$$c ? this.$$c[prop] : this.$$d[prop];
388
409
  },
389
410
  set(value) {
390
411
  value = get_custom_element_value(prop, value, props_definition);
391
- this.$$data[prop] = value;
392
- this.$$component?.$set({ [prop]: value });
393
- if (props_definition[prop].reflect) {
394
- this.$$reflecting = true;
395
- const attribute_value = get_custom_element_value(
396
- prop,
397
- value,
398
- props_definition,
399
- 'toAttribute'
400
- );
401
- if (attribute_value == null) {
402
- this.removeAttribute(prop);
403
- } else {
404
- this.setAttribute(props_definition[prop].attribute || prop, attribute_value);
405
- }
406
- this.$$reflecting = false;
407
- }
412
+ this.$$d[prop] = value;
413
+ this.$$c?.$set({ [prop]: value });
408
414
  }
409
415
  });
410
416
  });
411
417
  accessors.forEach((accessor) => {
412
418
  Object.defineProperty(Class.prototype, accessor, {
413
419
  get() {
414
- return this.$$component?.[accessor];
420
+ return this.$$c?.[accessor];
415
421
  }
416
422
  });
417
423
  });
@@ -80,14 +80,12 @@ export interface DispatchOptions {
80
80
  export interface EventDispatcher<EventMap extends Record<string, any>> {
81
81
  // Implementation notes:
82
82
  // - undefined extends X instead of X extends undefined makes this work better with both strict and nonstrict mode
83
- // - [X] extends [never] is needed, X extends never would reduce the whole resulting type to never and not to one of the condition outcomes
83
+ // - | null | undefined is added for convenience, as they are equivalent for the custom event constructor (both result in a null detail)
84
84
  <Type extends keyof EventMap>(
85
- ...args: [EventMap[Type]] extends [never]
86
- ? [type: Type, parameter?: null | undefined, options?: DispatchOptions]
87
- : null extends EventMap[Type]
88
- ? [type: Type, parameter?: EventMap[Type], options?: DispatchOptions]
85
+ ...args: null extends EventMap[Type]
86
+ ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
89
87
  : undefined extends EventMap[Type]
90
- ? [type: Type, parameter?: EventMap[Type], options?: DispatchOptions]
88
+ ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
91
89
  : [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
92
90
  ): boolean;
93
91
  }
@@ -68,15 +68,50 @@ export function safe_not_equal(a, b) {
68
68
 
69
69
  let src_url_equal_anchor;
70
70
 
71
- /** @returns {boolean} */
71
+ /**
72
+ * @param {string} element_src
73
+ * @param {string} url
74
+ * @returns {boolean}
75
+ */
72
76
  export function src_url_equal(element_src, url) {
77
+ if (element_src === url) return true;
73
78
  if (!src_url_equal_anchor) {
74
79
  src_url_equal_anchor = document.createElement('a');
75
80
  }
81
+ // This is actually faster than doing URL(..).href
76
82
  src_url_equal_anchor.href = url;
77
83
  return element_src === src_url_equal_anchor.href;
78
84
  }
79
85
 
86
+ /** @param {string} srcset */
87
+ function split_srcset(srcset) {
88
+ return srcset.split(',').map((src) => src.trim().split(' ').filter(Boolean));
89
+ }
90
+
91
+ /**
92
+ * @param {HTMLSourceElement | HTMLImageElement} element_srcset
93
+ * @param {string} srcset
94
+ * @returns {boolean}
95
+ */
96
+ export function srcset_url_equal(element_srcset, srcset) {
97
+ const element_urls = split_srcset(element_srcset.srcset);
98
+ const urls = split_srcset(srcset);
99
+
100
+ return (
101
+ urls.length === element_urls.length &&
102
+ urls.every(
103
+ ([url, width], i) =>
104
+ width === element_urls[i][1] &&
105
+ // We need to test both ways because Vite will create an a full URL with
106
+ // `new URL(asset, import.meta.url).href` for the client when `base: './'`, and the
107
+ // relative URLs inside srcset are not automatically resolved to absolute URLs by
108
+ // browsers (in contrast to img.src). This means both SSR and DOM code could
109
+ // contain relative or absolute URLs.
110
+ (src_url_equal(element_urls[i][0], url) || src_url_equal(url, element_urls[i][0]))
111
+ )
112
+ );
113
+ }
114
+
80
115
  /** @returns {boolean} */
81
116
  export function not_equal(a, b) {
82
117
  return a != a ? b == b : a !== b;
@@ -6,5 +6,5 @@
6
6
  * https://svelte.dev/docs/svelte-compiler#svelte-version
7
7
  * @type {string}
8
8
  */
9
- export const VERSION = '4.0.0';
9
+ export const VERSION = '4.0.2';
10
10
  export const PUBLIC_VERSION = '4';