@burger-editor/client 4.0.0-alpha.7 → 4.0.0-alpha.8

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/dist/client.css CHANGED
@@ -504,6 +504,7 @@
504
504
  --bge-dialog-background-color: var(--bge-ui-background-color);
505
505
  --bge-focus-outline-width: 2px;
506
506
  --bge-tooltip-background-color: rgb(0 0 0 / 60%);
507
+ --bge-font-family-monospace: "Courier New", monospace;
507
508
  }
508
509
 
509
510
  :where(body:has(dialog[open])) {
@@ -523,6 +524,7 @@
523
524
  padding: 0;
524
525
  padding-block: 1em;
525
526
  overscroll-behavior: contain;
527
+ font-size: 16px;
526
528
  color: var(--bge-dialog-font-color);
527
529
  resize: both;
528
530
  background: var(--bge-dialog-background-color);
@@ -596,16 +598,16 @@ select,
596
598
  textarea) {
597
599
  inline-size: 100%;
598
600
  padding: 0.5em 0.7em;
599
- font-size: inherit;
601
+ font-size: 1em;
600
602
  line-height: 1.1;
601
- border: 1px solid var(--bge-border-color);
602
- border-radius: var(--border-radius);
603
603
  }
604
604
  :where(dialog[open], [data-bge-component=block-menu]) :where(input:not([type=radio], [type=checkbox], [type=range]),
605
605
  select,
606
606
  textarea,
607
607
  [contenteditable]) {
608
608
  background: var(--bge-lightest-color);
609
+ border: 1px solid var(--bge-border-color);
610
+ border-radius: var(--border-radius);
609
611
  }
610
612
  :where(dialog[open], [data-bge-component=block-menu]) :where(input:not([type=radio], [type=checkbox], [type=range]),
611
613
  select,
@@ -762,28 +764,33 @@ textarea,
762
764
  display: none;
763
765
  }
764
766
 
765
- [data-bgi] {
767
+ [data-bge-component=editable-area] [data-bgi] {
768
+ --outline: none;
766
769
  min-inline-size: 20px;
767
770
  min-block-size: 20px;
768
- outline: 1px #a6a6a6 dotted;
771
+ outline: var(--outline);
772
+ }
773
+ [data-bge-component=editable-area] [data-bgi]:where([data-bge-container]:hover [data-bge-component=editable-area] [data-bgi]) {
774
+ --outline: 1px #a6a6a6 dotted;
769
775
  }
770
- [data-bgi]:hover {
776
+ [data-bge-component=editable-area] [data-bgi]:hover {
777
+ --outline: 1px solid var(--bge-ui-primary-color);
771
778
  cursor: pointer;
772
- outline: 1px solid var(--bge-ui-primary-color);
773
- background-color: var(--bge-ui-background-color);
779
+ background-color: oklch(from currentcolor l c h/5%);
780
+ background-blend-mode: darken;
774
781
  }
775
- [data-bgi]:hover img {
782
+ [data-bge-component=editable-area] [data-bgi]:hover img {
776
783
  filter: brightness(90%);
777
784
  }
778
- [data-bgi] a,
779
- [data-bgi] area,
780
- [data-bgi] button,
781
- [data-bgi] input,
782
- [data-bgi] label,
783
- [data-bgi] select,
784
- [data-bgi] summary,
785
- [data-bgi] textarea,
786
- [data-bgi] iframe {
785
+ [data-bge-component=editable-area] [data-bgi] a,
786
+ [data-bge-component=editable-area] [data-bgi] area,
787
+ [data-bge-component=editable-area] [data-bgi] button,
788
+ [data-bge-component=editable-area] [data-bgi] input,
789
+ [data-bge-component=editable-area] [data-bgi] label,
790
+ [data-bge-component=editable-area] [data-bgi] select,
791
+ [data-bge-component=editable-area] [data-bgi] summary,
792
+ [data-bge-component=editable-area] [data-bgi] textarea,
793
+ [data-bge-component=editable-area] [data-bgi] iframe {
787
794
  pointer-events: none;
788
795
  }
789
796
 
package/dist/client.js CHANGED
@@ -2928,6 +2928,12 @@ function requireSemver () {
2928
2928
  var semverExports = requireSemver();
2929
2929
  const semver = /*@__PURE__*/getDefaultExportFromCjs(semverExports);
2930
2930
 
2931
+ const CSS_LAYER = {
2932
+ base: 'bge-component-bases',
2933
+ components: 'bge-components',
2934
+ ui: 'bge-ui',
2935
+ };
2936
+
2931
2937
  /**
2932
2938
  *
2933
2939
  * @param doc
@@ -2941,6 +2947,18 @@ function appendStylesheetTo(doc, url) {
2941
2947
  doc.head.append(link);
2942
2948
  }
2943
2949
 
2950
+ /**
2951
+ *
2952
+ * @param cssContents
2953
+ * @param layer
2954
+ */
2955
+ function createStylesheet(cssContents, layer) {
2956
+ const css = layer ? `@layer ${layer} {${cssContents}}` : cssContents;
2957
+ const blob = new Blob([css], { type: 'text/css' });
2958
+ const url = URL.createObjectURL(blob);
2959
+ return url;
2960
+ }
2961
+
2944
2962
  class ElementNotFoundError extends Error {
2945
2963
  static {
2946
2964
  this.prototype.name = 'ElementNotFoundError';
@@ -2989,9 +3007,7 @@ class EditorUI {
2989
3007
  this.#el = typeof elOrSelector === 'string' ? getElement(elOrSelector) : elOrSelector;
2990
3008
  this.#el.dataset.bgeComponent = name;
2991
3009
  if (options?.stylesheet) {
2992
- const css = options.stylesheet;
2993
- const blob = new Blob([css], { type: 'text/css' });
2994
- const url = URL.createObjectURL(blob);
3010
+ const url = createStylesheet(options.stylesheet, CSS_LAYER.ui);
2995
3011
  appendStylesheetTo(this.el.ownerDocument, url);
2996
3012
  }
2997
3013
  }
@@ -3280,35 +3296,43 @@ class ComponentObserver {
3280
3296
  *
3281
3297
  * @param items
3282
3298
  * @param generalCSS
3299
+ * @param layer
3283
3300
  */
3284
- function createComponentStylesheet(items, generalCSS) {
3301
+ function createComponentStylesheet(items, generalCSS, layer) {
3285
3302
  const itemStyles = Object.values(items)
3286
3303
  .map((item) => item.style)
3287
3304
  .filter(Boolean)
3288
3305
  .join('\n');
3289
- const css = `${itemStyles}\n${generalCSS}`;
3306
+ return createStylesheet(itemStyles + '\n' + generalCSS, layer);
3307
+ }
3308
+
3309
+ /**
3310
+ *
3311
+ * @param url
3312
+ * @param layer
3313
+ */
3314
+ async function createStylesheetFromUrl(url, layer) {
3315
+ const response = await fetch(url);
3316
+ const cssContents = await response.text();
3317
+ const css = layer ? `@layer ${layer} {${cssContents}}` : cssContents;
3290
3318
  const blob = new Blob([css], { type: 'text/css' });
3291
- const url = URL.createObjectURL(blob);
3292
- return url;
3319
+ const blobUrl = URL.createObjectURL(blob);
3320
+ return blobUrl;
3293
3321
  }
3294
3322
 
3295
3323
  const PREFIX = '--bge-options-';
3296
3324
  /**
3297
- *
3325
+ * Get all custom properties from editorArea
3298
3326
  * @param editorArea
3299
3327
  */
3300
3328
  function getCustomProperties(editorArea) {
3301
3329
  const categories = new Map();
3302
3330
  const defaultValues = new Map();
3303
- // From iframe scope
3304
- const CSSStyleRule = editorArea.containerElement.ownerDocument.defaultView?.CSSStyleRule;
3305
- if (CSSStyleRule === undefined) {
3306
- throw new Error('CSSStyleRule is not available');
3307
- }
3308
3331
  for (const styleSheet of editorArea.containerElement.ownerDocument.styleSheets) {
3309
3332
  try {
3310
- for (const cssRule of styleSheet.cssRules) {
3311
- if (cssRule instanceof CSSStyleRule && cssRule.selectorText === ':root') {
3333
+ const styleRules = getStyleRules(styleSheet.cssRules, editorArea);
3334
+ for (const cssRule of styleRules) {
3335
+ if (cssRule.selectorText === ':root') {
3312
3336
  for (const cssProperty of cssRule.style) {
3313
3337
  if (cssProperty.startsWith(PREFIX)) {
3314
3338
  const [type, key] = cssProperty.slice(PREFIX.length).split('-');
@@ -3337,6 +3361,13 @@ function getCustomProperties(editorArea) {
3337
3361
  throw error;
3338
3362
  }
3339
3363
  }
3364
+ for (const propList of categories.values()) {
3365
+ for (const [key, customProperty] of propList.entries()) {
3366
+ if (customProperty.value.trim().toLowerCase() === 'null') {
3367
+ propList.delete(key);
3368
+ }
3369
+ }
3370
+ }
3340
3371
  for (const [category, value] of defaultValues.entries()) {
3341
3372
  const currentMap = categories.get(category);
3342
3373
  if (!currentMap) {
@@ -3350,6 +3381,34 @@ function getCustomProperties(editorArea) {
3350
3381
  }
3351
3382
  return categories;
3352
3383
  }
3384
+ /**
3385
+ * Get all CSSStyleRule from CSSRule array recursively
3386
+ * @param rules - CSSRule array
3387
+ * @param scope - EditableArea
3388
+ * @returns CSSStyleRule array
3389
+ */
3390
+ function getStyleRules(rules, scope) {
3391
+ const CSSStyleRule = scope.containerElement.ownerDocument.defaultView?.CSSStyleRule;
3392
+ if (CSSStyleRule === undefined) {
3393
+ throw new Error('CSSStyleRule is not available');
3394
+ }
3395
+ const CSSGroupingRule = scope.containerElement.ownerDocument.defaultView?.CSSGroupingRule;
3396
+ if (CSSGroupingRule === undefined) {
3397
+ throw new Error('CSSGroupingRule is not available');
3398
+ }
3399
+ const styleRules = [];
3400
+ for (const rule of rules) {
3401
+ if (rule instanceof CSSStyleRule) {
3402
+ styleRules.push(rule);
3403
+ continue;
3404
+ }
3405
+ if (rule instanceof CSSGroupingRule) {
3406
+ styleRules.push(...getStyleRules(rule.cssRules, scope));
3407
+ continue;
3408
+ }
3409
+ }
3410
+ return styleRules;
3411
+ }
3353
3412
 
3354
3413
  const getCSSPropertyAsNumberCache = new Map();
3355
3414
  /**
@@ -3384,10 +3443,6 @@ class BlockMenu extends EditorUI {
3384
3443
  position: absolute;
3385
3444
  z-index: 2147483647;
3386
3445
  pointer-events: none;
3387
-
3388
- > * {
3389
- pointer-events: auto;
3390
- }
3391
3446
  }
3392
3447
  `,
3393
3448
  });
@@ -5296,8 +5351,12 @@ class BurgerEditorEngine {
5296
5351
  static #itemSeeds = new Map();
5297
5352
  static async new(options) {
5298
5353
  const engine = new BurgerEditorEngine(options);
5299
- const componentStylesheet = createComponentStylesheet(options.items, options.generalCSS);
5300
- const stylesheets = [componentStylesheet, ...(options.config.stylesheets ?? [])];
5354
+ const layers = createStylesheet(`@layer ${CSS_LAYER.base}, ${CSS_LAYER.components}, ${CSS_LAYER.ui};`);
5355
+ const baseStylesheet = createComponentStylesheet(options.items, options.generalCSS, CSS_LAYER.base);
5356
+ const componentStylesheets = await Promise.all(options.config.stylesheets.map(async (stylesheet) => {
5357
+ return createStylesheetFromUrl(stylesheet.path, stylesheet.layer ?? CSS_LAYER.components);
5358
+ }));
5359
+ const stylesheets = [layers, baseStylesheet, ...componentStylesheets];
5301
5360
  const mainInitialContent = typeof options.initialContents === 'string'
5302
5361
  ? options.initialContents
5303
5362
  : options.initialContents.main;
@@ -6553,6 +6612,7 @@ const INSPECT_EFFECT = 1 << 17;
6553
6612
  const HEAD_EFFECT = 1 << 18;
6554
6613
  const EFFECT_PRESERVED = 1 << 19;
6555
6614
  const EFFECT_IS_UPDATING = 1 << 20;
6615
+ const USER_EFFECT = 1 << 21;
6556
6616
 
6557
6617
  const STATE_SYMBOL = Symbol('$state');
6558
6618
  const LEGACY_PROPS = Symbol('legacy props');
@@ -6748,7 +6808,7 @@ function pop(component) {
6748
6808
  var component_effect = component_effects[i];
6749
6809
  set_active_effect(component_effect.effect);
6750
6810
  set_active_reaction(component_effect.reaction);
6751
- effect(component_effect.fn);
6811
+ create_user_effect(component_effect.fn);
6752
6812
  }
6753
6813
  } finally {
6754
6814
  set_active_effect(previous_effect);
@@ -7111,7 +7171,7 @@ function derived(fn) {
7111
7171
  fn,
7112
7172
  reactions: null,
7113
7173
  rv: 0,
7114
- v: /** @type {V} */ (null),
7174
+ v: /** @type {V} */ (UNINITIALIZED),
7115
7175
  wv: 0,
7116
7176
  parent: parent_derived ?? active_effect,
7117
7177
  ac: null
@@ -7312,7 +7372,7 @@ function set(source, value, should_proxy = false) {
7312
7372
  (!untracking || (active_reaction.f & INSPECT_EFFECT) !== 0) &&
7313
7373
  is_runes() &&
7314
7374
  (active_reaction.f & (DERIVED | BLOCK_EFFECT | INSPECT_EFFECT)) !== 0 &&
7315
- !(reaction_sources?.[1].includes(source) && reaction_sources[0] === active_reaction)
7375
+ !(source_ownership?.reaction === active_reaction && source_ownership.sources.includes(source))
7316
7376
  ) {
7317
7377
  state_unsafe_mutation();
7318
7378
  }
@@ -7721,11 +7781,17 @@ function user_effect(fn) {
7721
7781
  reaction: active_reaction
7722
7782
  });
7723
7783
  } else {
7724
- var signal = effect(fn);
7725
- return signal;
7784
+ return create_user_effect(fn);
7726
7785
  }
7727
7786
  }
7728
7787
 
7788
+ /**
7789
+ * @param {() => void | (() => void)} fn
7790
+ */
7791
+ function create_user_effect(fn) {
7792
+ return create_effect(EFFECT | USER_EFFECT, fn, false);
7793
+ }
7794
+
7729
7795
  /**
7730
7796
  * Internal representation of `$effect.pre(...)`
7731
7797
  * @param {() => void | (() => void)} fn
@@ -7733,7 +7799,7 @@ function user_effect(fn) {
7733
7799
  */
7734
7800
  function user_pre_effect(fn) {
7735
7801
  validate_effect();
7736
- return render_effect(fn);
7802
+ return create_effect(RENDER_EFFECT | USER_EFFECT, fn, true);
7737
7803
  }
7738
7804
 
7739
7805
  /**
@@ -8216,17 +8282,17 @@ function set_active_effect(effect) {
8216
8282
  /**
8217
8283
  * When sources are created within a reaction, reading and writing
8218
8284
  * them within that reaction should not cause a re-run
8219
- * @type {null | [active_reaction: Reaction, sources: Source[]]}
8285
+ * @type {null | { reaction: Reaction, sources: Source[] }}
8220
8286
  */
8221
- let reaction_sources = null;
8287
+ let source_ownership = null;
8222
8288
 
8223
8289
  /** @param {Value} value */
8224
8290
  function push_reaction_value(value) {
8225
8291
  if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) {
8226
- if (reaction_sources === null) {
8227
- reaction_sources = [active_reaction, [value]];
8292
+ if (source_ownership === null) {
8293
+ source_ownership = { reaction: active_reaction, sources: [value] };
8228
8294
  } else {
8229
- reaction_sources[1].push(value);
8295
+ source_ownership.sources.push(value);
8230
8296
  }
8231
8297
  }
8232
8298
  }
@@ -8360,7 +8426,12 @@ function schedule_possible_effect_self_invalidation(signal, effect, root = true)
8360
8426
  for (var i = 0; i < reactions.length; i++) {
8361
8427
  var reaction = reactions[i];
8362
8428
 
8363
- if (reaction_sources?.[1].includes(signal) && reaction_sources[0] === active_reaction) continue;
8429
+ if (
8430
+ source_ownership?.reaction === active_reaction &&
8431
+ source_ownership.sources.includes(signal)
8432
+ ) {
8433
+ continue;
8434
+ }
8364
8435
 
8365
8436
  if ((reaction.f & DERIVED) !== 0) {
8366
8437
  schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false);
@@ -8382,7 +8453,7 @@ function update_reaction(reaction) {
8382
8453
  var previous_untracked_writes = untracked_writes;
8383
8454
  var previous_reaction = active_reaction;
8384
8455
  var previous_skip_reaction = skip_reaction;
8385
- var previous_reaction_sources = reaction_sources;
8456
+ var previous_reaction_sources = source_ownership;
8386
8457
  var previous_component_context = component_context;
8387
8458
  var previous_untracking = untracking;
8388
8459
 
@@ -8395,10 +8466,10 @@ function update_reaction(reaction) {
8395
8466
  (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null);
8396
8467
  active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null;
8397
8468
 
8398
- reaction_sources = null;
8469
+ source_ownership = null;
8399
8470
  set_component_context(reaction.ctx);
8400
8471
  untracking = false;
8401
- read_version++;
8472
+ ++read_version;
8402
8473
 
8403
8474
  reaction.f |= EFFECT_IS_UPDATING;
8404
8475
 
@@ -8483,7 +8554,7 @@ function update_reaction(reaction) {
8483
8554
  untracked_writes = previous_untracked_writes;
8484
8555
  active_reaction = previous_reaction;
8485
8556
  skip_reaction = previous_skip_reaction;
8486
- reaction_sources = previous_reaction_sources;
8557
+ source_ownership = previous_reaction_sources;
8487
8558
  set_component_context(previous_component_context);
8488
8559
  untracking = previous_untracking;
8489
8560
 
@@ -8650,6 +8721,8 @@ function flush_queued_effects(effects) {
8650
8721
 
8651
8722
  if ((effect.f & (DESTROYED | INERT)) === 0) {
8652
8723
  if (check_dirtiness(effect)) {
8724
+ var wv = write_version;
8725
+
8653
8726
  update_effect(effect);
8654
8727
 
8655
8728
  // Effects with no dependencies or teardown do not get added to the effect tree.
@@ -8666,9 +8739,19 @@ function flush_queued_effects(effects) {
8666
8739
  effect.fn = null;
8667
8740
  }
8668
8741
  }
8742
+
8743
+ // if state is written in a user effect, abort and re-schedule, lest we run
8744
+ // effects that should be removed as a result of the state change
8745
+ if (write_version > wv && (effect.f & USER_EFFECT) !== 0) {
8746
+ break;
8747
+ }
8669
8748
  }
8670
8749
  }
8671
8750
  }
8751
+
8752
+ for (; i < length; i += 1) {
8753
+ schedule_effect(effects[i]);
8754
+ }
8672
8755
  }
8673
8756
 
8674
8757
  /**
@@ -8765,7 +8848,10 @@ function get(signal) {
8765
8848
 
8766
8849
  // Register the dependency on the current reaction signal.
8767
8850
  if (active_reaction !== null && !untracking) {
8768
- if (!reaction_sources?.[1].includes(signal) || reaction_sources[0] !== active_reaction) {
8851
+ if (
8852
+ source_ownership?.reaction !== active_reaction ||
8853
+ !source_ownership?.sources.includes(signal)
8854
+ ) {
8769
8855
  var deps = active_reaction.deps;
8770
8856
  if (signal.rv < read_version) {
8771
8857
  signal.rv = read_version;
@@ -8800,7 +8886,7 @@ function get(signal) {
8800
8886
  }
8801
8887
  }
8802
8888
 
8803
- if (is_derived) {
8889
+ if (is_derived && !is_destroying_effect) {
8804
8890
  derived = /** @type {Derived} */ (signal);
8805
8891
 
8806
8892
  if (check_dirtiness(derived)) {
@@ -8808,13 +8894,48 @@ function get(signal) {
8808
8894
  }
8809
8895
  }
8810
8896
 
8811
- if (is_destroying_effect && old_values.has(signal)) {
8812
- return old_values.get(signal);
8897
+ if (is_destroying_effect) {
8898
+ if (old_values.has(signal)) {
8899
+ return old_values.get(signal);
8900
+ }
8901
+
8902
+ if (is_derived) {
8903
+ derived = /** @type {Derived} */ (signal);
8904
+
8905
+ var value = derived.v;
8906
+
8907
+ // if the derived is dirty, or depends on the values that just changed, re-execute
8908
+ if ((derived.f & CLEAN) !== 0 || depends_on_old_values(derived)) {
8909
+ value = execute_derived(derived);
8910
+ }
8911
+
8912
+ old_values.set(derived, value);
8913
+
8914
+ return value;
8915
+ }
8813
8916
  }
8814
8917
 
8815
8918
  return signal.v;
8816
8919
  }
8817
8920
 
8921
+ /** @param {Derived} derived */
8922
+ function depends_on_old_values(derived) {
8923
+ if (derived.v === UNINITIALIZED) return true; // we don't know, so assume the worst
8924
+ if (derived.deps === null) return false;
8925
+
8926
+ for (const dep of derived.deps) {
8927
+ if (old_values.has(dep)) {
8928
+ return true;
8929
+ }
8930
+
8931
+ if ((dep.f & DERIVED) !== 0 && depends_on_old_values(/** @type {Derived} */ (dep))) {
8932
+ return true;
8933
+ }
8934
+ }
8935
+
8936
+ return false;
8937
+ }
8938
+
8818
8939
  /**
8819
8940
  * Capture an array of all the signals that are read when `fn` is called
8820
8941
  * @template T
@@ -10821,9 +10942,9 @@ function set_style(dom, value, prev_styles, next_styles) {
10821
10942
  * @template V
10822
10943
  * @param {HTMLSelectElement} select
10823
10944
  * @param {V} value
10824
- * @param {boolean} [mounting]
10945
+ * @param {boolean} mounting
10825
10946
  */
10826
- function select_option(select, value, mounting) {
10947
+ function select_option(select, value, mounting = false) {
10827
10948
  if (select.multiple) {
10828
10949
  // If value is null or undefined, keep the selection as is
10829
10950
  if (value == undefined) {
@@ -11192,7 +11313,7 @@ function attribute_effect(
11192
11313
  var current = set_attributes(element, prev, next, css_hash, skip_warning);
11193
11314
 
11194
11315
  if (inited && is_select && 'value' in next) {
11195
- select_option(/** @type {HTMLSelectElement} */ (element), next.value, false);
11316
+ select_option(/** @type {HTMLSelectElement} */ (element), next.value);
11196
11317
  }
11197
11318
 
11198
11319
  for (let symbol of Object.getOwnPropertySymbols(effects)) {
@@ -11217,7 +11338,7 @@ function attribute_effect(
11217
11338
  var select = /** @type {HTMLSelectElement} */ (element);
11218
11339
 
11219
11340
  effect(() => {
11220
- select_option(select, /** @type {Record<string | symbol, any>} */ (prev).value);
11341
+ select_option(select, /** @type {Record<string | symbol, any>} */ (prev).value, true);
11221
11342
  init_select(select);
11222
11343
  });
11223
11344
  }
@@ -11515,11 +11636,12 @@ function capture_store_binding(fn) {
11515
11636
  }
11516
11637
  }
11517
11638
 
11518
- /** @import { Derived, Source } from './types.js' */
11639
+ /** @import { ComponentContext } from '#client' */
11640
+ /** @import { Derived, Effect, Source } from './types.js' */
11519
11641
 
11520
11642
  /**
11521
11643
  * The proxy handler for legacy $$restProps and $$props
11522
- * @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number> }>}}
11644
+ * @type {ProxyHandler<{ props: Record<string | symbol, unknown>, exclude: Array<string | symbol>, special: Record<string | symbol, (v?: unknown) => unknown>, version: Source<number>, parent_effect: Effect }>}}
11523
11645
  */
11524
11646
  const legacy_rest_props_handler = {
11525
11647
  get(target, key) {
@@ -11529,17 +11651,25 @@ const legacy_rest_props_handler = {
11529
11651
  },
11530
11652
  set(target, key, value) {
11531
11653
  if (!(key in target.special)) {
11532
- // Handle props that can temporarily get out of sync with the parent
11533
- /** @type {Record<string, (v?: unknown) => unknown>} */
11534
- target.special[key] = prop(
11535
- {
11536
- get [key]() {
11537
- return target.props[key];
11538
- }
11539
- },
11540
- /** @type {string} */ (key),
11541
- PROPS_IS_UPDATED
11542
- );
11654
+ var previous_effect = active_effect;
11655
+
11656
+ try {
11657
+ set_active_effect(target.parent_effect);
11658
+
11659
+ // Handle props that can temporarily get out of sync with the parent
11660
+ /** @type {Record<string, (v?: unknown) => unknown>} */
11661
+ target.special[key] = prop(
11662
+ {
11663
+ get [key]() {
11664
+ return target.props[key];
11665
+ }
11666
+ },
11667
+ /** @type {string} */ (key),
11668
+ PROPS_IS_UPDATED
11669
+ );
11670
+ } finally {
11671
+ set_active_effect(previous_effect);
11672
+ }
11543
11673
  }
11544
11674
 
11545
11675
  target.special[key](value);
@@ -11578,7 +11708,19 @@ const legacy_rest_props_handler = {
11578
11708
  * @returns {Record<string, unknown>}
11579
11709
  */
11580
11710
  function legacy_rest_props(props, exclude) {
11581
- return new Proxy({ props, exclude, special: {}, version: source(0) }, legacy_rest_props_handler);
11711
+ return new Proxy(
11712
+ {
11713
+ props,
11714
+ exclude,
11715
+ special: {},
11716
+ version: source(0),
11717
+ // TODO this is only necessary because we need to track component
11718
+ // destruction inside `prop`, because of `bind:this`, but it
11719
+ // seems likely that we can simplify `bind:this` instead
11720
+ parent_effect: /** @type {Effect} */ (active_effect)
11721
+ },
11722
+ legacy_rest_props_handler
11723
+ );
11582
11724
  }
11583
11725
 
11584
11726
  /**
@@ -11667,14 +11809,6 @@ function spread_props(...props) {
11667
11809
  return new Proxy({ props }, spread_props_handler);
11668
11810
  }
11669
11811
 
11670
- /**
11671
- * @param {Derived} current_value
11672
- * @returns {boolean}
11673
- */
11674
- function has_destroyed_component_ctx(current_value) {
11675
- return current_value.ctx?.d ?? false;
11676
- }
11677
-
11678
11812
  /**
11679
11813
  * This function is responsible for synchronizing a possibly bound prop with the inner component state.
11680
11814
  * It is used whenever the compiler sees that the component writes to the prop, or when it has a default prop_value.
@@ -11793,16 +11927,24 @@ function prop(props, key, flags, fallback) {
11793
11927
  // create a derived that we can write to locally.
11794
11928
  // Or we are in legacy mode where we always create a derived to replicate that
11795
11929
  // Svelte 4 did not trigger updates when a primitive value was updated to the same value.
11796
- var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(getter);
11930
+ var overridden = false;
11931
+
11932
+ var d = ((flags & PROPS_IS_IMMUTABLE) !== 0 ? derived : derived_safe_equal)(() => {
11933
+ overridden = false;
11934
+ return getter();
11935
+ });
11797
11936
 
11798
11937
  // Capture the initial value if it's bindable
11799
11938
  if (bindable) get(d);
11800
11939
 
11940
+ var parent_effect = /** @type {Effect} */ (active_effect);
11941
+
11801
11942
  return function (/** @type {any} */ value, /** @type {boolean} */ mutation) {
11802
11943
  if (arguments.length > 0) {
11803
11944
  const new_value = mutation ? get(d) : runes && bindable ? proxy(value) : value;
11804
11945
 
11805
11946
  set(d, new_value);
11947
+ overridden = true;
11806
11948
 
11807
11949
  if (fallback_value !== undefined) {
11808
11950
  fallback_value = new_value;
@@ -11811,8 +11953,12 @@ function prop(props, key, flags, fallback) {
11811
11953
  return value;
11812
11954
  }
11813
11955
 
11814
- // TODO is this still necessary post-#16263?
11815
- if (has_destroyed_component_ctx(d)) {
11956
+ // special case avoid recalculating the derived if we're in a
11957
+ // teardown function and the prop was overridden locally, or the
11958
+ // component was already destroyed (this latter part is necessary
11959
+ // because `bind:this` can read props after the component has
11960
+ // been destroyed. TODO simplify `bind:this`
11961
+ if ((is_destroying_effect && overridden) || (parent_effect.f & DESTROYED) !== 0) {
11816
11962
  return d.v;
11817
11963
  }
11818
11964
 
@@ -14591,7 +14737,7 @@ function parseConfig(config) {
14591
14737
  }
14592
14738
  }
14593
14739
 
14594
- const version = "4.0.0-alpha.6";
14740
+ const version = "4.0.0-alpha.7";
14595
14741
  function attachDraftSwitcher(engine) {
14596
14742
  if (engine.hasDraft()) {
14597
14743
  const container = document.createElement("div");