contain-css-svelte 1.5.0 → 1.6.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.
@@ -18,6 +18,9 @@ let observer;
18
18
  let resizeObserver;
19
19
  let targetWidth = $state("");
20
20
  let optionButtons = $state([]);
21
+ // The subset of optionButtons the resize observer is currently watching, so
22
+ // the $effect below can tell "nothing changed" from "rewire".
23
+ let observedButtons = [];
21
24
  onMount(() => {
22
25
  tick().then(() => updateOptions());
23
26
  /*
@@ -40,14 +43,37 @@ onMount(() => {
40
43
  attributeFilter: ["data-html", "value", "label", "selected"],
41
44
  });
42
45
  }
43
- // Observe size changes in option buttons
44
46
  resizeObserver = new ResizeObserver(() => updateTargetWidth());
45
- optionButtons.forEach((button) => resizeObserver.observe(button));
46
47
  return () => {
47
48
  observer.disconnect();
48
49
  resizeObserver.disconnect();
49
50
  };
50
51
  });
52
+ /*
53
+ optionButtons is populated by `bind:this` inside the {#each options}
54
+ block below, so it only ever reflects the CURRENT option list once Svelte
55
+ has reconciled the DOM -- which happens asynchronously relative to the
56
+ updateOptions() call that rebuilt `options`. Re-deriving the observed set
57
+ here, every time that binding changes, is what keeps the ResizeObserver
58
+ in sync in both directions: a button added once the list grows longer
59
+ gets observed, and one removed when the list shrinks is dropped instead
60
+ of lingering as a stale (and eventually null) target.
61
+
62
+ Guarded by reference comparison so an unrelated re-render that leaves the
63
+ same buttons in place doesn't thrash disconnect()/observe() every time.
64
+ */
65
+ $effect(() => {
66
+ if (!resizeObserver)
67
+ return;
68
+ const current = optionButtons.filter((button) => Boolean(button));
69
+ const unchanged = current.length === observedButtons.length &&
70
+ current.every((button, i) => button === observedButtons[i]);
71
+ if (unchanged)
72
+ return;
73
+ resizeObserver.disconnect();
74
+ current.forEach((button) => resizeObserver.observe(button));
75
+ observedButtons = current;
76
+ });
51
77
  let options = $state([]);
52
78
  let activeOption = $state(null);
53
79
  let updateQueued = false;
@@ -73,12 +99,29 @@ function updateOptions() {
73
99
  html: richHtml.trim(),
74
100
  });
75
101
  }
102
+ /*
103
+ optionButtons is bound by index from the {#each options} block below,
104
+ so when the option list shrinks, the array's tail is left holding
105
+ targets for <li>s that no longer render. (Svelte nulls each removed
106
+ binding's own slot as it tears the element down, but that happens once
107
+ the DOM catches up with this reassignment, not synchronously here --
108
+ so truncate now rather than leave the old length around in the
109
+ meantime.) Trimming it here, before the {#each} re-renders, keeps it
110
+ from ever describing more options than currently exist.
111
+ */
112
+ if (optionButtons.length > options.length) {
113
+ optionButtons.length = options.length;
114
+ }
76
115
  activeOption = options[selectElement.selectedIndex];
77
116
  updateTargetWidth();
78
117
  }
79
118
  function updateTargetWidth() {
80
119
  let maxWidth = 0;
81
120
  for (let button of optionButtons) {
121
+ // A stale or not-yet-bound slot (see updateOptions() above) -- skip it
122
+ // rather than crash on a null bind:this target.
123
+ if (!button)
124
+ continue;
82
125
  if (button.offsetWidth > maxWidth) {
83
126
  maxWidth = button.offsetWidth;
84
127
  }
package/dist/index.d.ts CHANGED
@@ -4,6 +4,9 @@ import Button from "./controls/Button.svelte";
4
4
  import ButtonLink from "./controls/ButtonLink.svelte";
5
5
  import Checkbox from "./controls/Checkbox.svelte";
6
6
  import CircleButton from "./controls/CircleButton.svelte";
7
+ import GroupedToggle from "./controls/GroupedToggle.svelte";
8
+ import GroupedToggleItem from "./controls/GroupedToggleItem.svelte";
9
+ import GroupedRadioItem from "./controls/GroupedRadioItem.svelte";
7
10
  import Input from "./controls/Input.svelte";
8
11
  import MiniButton from "./controls/MiniButton.svelte";
9
12
  import RadioButton from "./controls/RadioButton.svelte";
@@ -51,6 +54,7 @@ export type { BaseStyleProps, MarginStyleProps, ContainerStyleProps, BarStylePro
51
54
  export { Tag };
52
55
  export { Hero };
53
56
  export { TabItem };
57
+ export { GroupedToggle, GroupedToggleItem, GroupedRadioItem };
54
58
  export { Button, ButtonLink, CircleButton, Checkbox, Input, Slider, Toggle, RadioButton, MiniButton, Select, Option, };
55
59
  export { Bar, ColumnContainer, Container, GridLayout, GridRow, Inline, MenuList, Page, ResponsiveText, RowContainer, Stack, TabBar, };
56
60
  export { TextLayout, Code, Accordion };
package/dist/index.js CHANGED
@@ -5,6 +5,9 @@ import Button from "./controls/Button.svelte";
5
5
  import ButtonLink from "./controls/ButtonLink.svelte";
6
6
  import Checkbox from "./controls/Checkbox.svelte";
7
7
  import CircleButton from "./controls/CircleButton.svelte";
8
+ import GroupedToggle from "./controls/GroupedToggle.svelte";
9
+ import GroupedToggleItem from "./controls/GroupedToggleItem.svelte";
10
+ import GroupedRadioItem from "./controls/GroupedRadioItem.svelte";
8
11
  import Input from "./controls/Input.svelte";
9
12
  import MiniButton from "./controls/MiniButton.svelte";
10
13
  import RadioButton from "./controls/RadioButton.svelte";
@@ -51,6 +54,7 @@ import Text from "./typography/Text.svelte";
51
54
  export { Tag };
52
55
  export { Hero };
53
56
  export { TabItem };
57
+ export { GroupedToggle, GroupedToggleItem, GroupedRadioItem };
54
58
  export { Button, ButtonLink, CircleButton, Checkbox, Input, Slider, Toggle, RadioButton, MiniButton, Select, Option, };
55
59
  export { Bar, ColumnContainer, Container, GridLayout, GridRow, Inline, MenuList, Page, ResponsiveText, RowContainer, Stack, TabBar, };
56
60
  export { TextLayout, Code, Accordion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contain-css-svelte",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "capture:review": "node scripts/capture-review.mjs",