@dorsk/tsumikit 0.58.0 → 0.58.1

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.
@@ -103,16 +103,6 @@
103
103
 
104
104
  let listEl = $state<HTMLDivElement | null>(null);
105
105
 
106
- $effect(() => {
107
- const pop = listEl?.closest<HTMLElement>('[popover]');
108
- if (!pop) return;
109
- const isOpen = pop.matches(':popover-open');
110
- try {
111
- if (open && !isOpen) pop.showPopover();
112
- else if (!open && isOpen) pop.hidePopover();
113
- } catch {}
114
- });
115
-
116
106
  function buttons(): HTMLButtonElement[] {
117
107
  return listEl
118
108
  ? Array.from(listEl.querySelectorAll<HTMLButtonElement>('[role="menuitem"]:not(:disabled), [role="menuitemcheckbox"]:not(:disabled)'))
@@ -167,12 +157,9 @@
167
157
  {gap}
168
158
  role="menu"
169
159
  haspopup="menu"
170
- onclose={() => {
171
- open = false;
172
- onclose?.();
173
- }}
160
+ bind:open
161
+ {onclose}
174
162
  onopen={() => {
175
- open = true;
176
163
  queueMicrotask(() => focusAt(0));
177
164
  onopen?.();
178
165
  }}
@@ -76,6 +76,8 @@
76
76
  role?: PanelRole;
77
77
  /** `aria-haspopup` announced on the trigger. */
78
78
  haspopup?: HasPopup;
79
+ /** Bindable open state; setting it opens or closes the panel, even before its first open. */
80
+ open?: boolean;
79
81
  onopen?: () => void;
80
82
  onclose?: () => void;
81
83
  class?: string;
@@ -110,6 +112,7 @@
110
112
  href,
111
113
  role = 'dialog',
112
114
  haspopup = 'dialog',
115
+ open = $bindable(false),
113
116
  onopen,
114
117
  onclose,
115
118
  class: klass = '',
@@ -133,7 +136,14 @@
133
136
  // reopening is instant. The panel element itself always renders — the native
134
137
  // `popovertarget` wiring needs its id present in the DOM at all times.
135
138
  let opened = $state(false);
136
- let open = $state(false);
139
+
140
+ let shown = false;
141
+
142
+ $effect(() => {
143
+ if (!panelEl) return;
144
+ if (open && !shown) show();
145
+ else if (!open && shown) close();
146
+ });
137
147
 
138
148
  function close() {
139
149
  try {
@@ -210,6 +220,7 @@
210
220
  }
211
221
 
212
222
  async function onToggle(e: ToggleEvent) {
223
+ shown = e.newState === 'open';
213
224
  if (e.newState === 'open') {
214
225
  const firstOpen = !opened;
215
226
  opened = true;
@@ -62,6 +62,8 @@ type Own = {
62
62
  role?: PanelRole;
63
63
  /** `aria-haspopup` announced on the trigger. */
64
64
  haspopup?: HasPopup;
65
+ /** Bindable open state; setting it opens or closes the panel, even before its first open. */
66
+ open?: boolean;
65
67
  onopen?: () => void;
66
68
  onclose?: () => void;
67
69
  class?: string;
@@ -71,6 +73,6 @@ type Own = {
71
73
  panelStyle?: string;
72
74
  };
73
75
  type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own;
74
- declare const Popover: import("svelte").Component<$$ComponentProps, {}, "">;
76
+ declare const Popover: import("svelte").Component<$$ComponentProps, {}, "open">;
75
77
  type Popover = ReturnType<typeof Popover>;
76
78
  export default Popover;
@@ -78,16 +78,10 @@
78
78
  const height = $derived(control ? 'var(--control-height)' : HEIGHT[size]);
79
79
  const caretDisabled = $derived(disabled || menuDisabled);
80
80
 
81
- let caretEl = $state<HTMLSpanElement | null>(null);
82
-
83
- function openMenu() {
84
- caretEl?.querySelector<HTMLButtonElement>('[popovertarget]')?.click();
85
- }
86
-
87
81
  function onPrimaryKeydown(e: KeyboardEvent) {
88
82
  if (e.key !== 'ArrowDown' || caretDisabled) return;
89
83
  e.preventDefault();
90
- openMenu();
84
+ open = true;
91
85
  }
92
86
  </script>
93
87
 
@@ -114,7 +108,7 @@
114
108
  {@render children()}
115
109
  </Button>
116
110
  </span>
117
- <span class="split-caret" bind:this={caretEl}>
111
+ <span class="split-caret">
118
112
  <Menu
119
113
  {label}
120
114
  {items}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorsk/tsumikit",
3
- "version": "0.58.0",
3
+ "version": "0.58.1",
4
4
  "description": "Minimal, dependency-free Svelte 5 + pure-CSS UI kit. Token-driven atoms, molecules & layouts with theming out of the box.",
5
5
  "type": "module",
6
6
  "license": "MIT",