@threadlabs/looma 0.18.0 → 0.18.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.
@@ -307,7 +307,7 @@
307
307
  border-color: transparent;
308
308
  }
309
309
 
310
- :host-state([variant="ghost"]):active:not(:disabled, [aria-disabled="true"]) {
310
+ :host-state([variant="ghost"]):is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]) {
311
311
  background-color: var(--ui-button-ghost-active-surface, oklch(from var(--_tone) l c h / 16%));
312
312
  border-color: transparent;
313
313
  box-shadow: var(--ui-pressed);
@@ -35,6 +35,10 @@
35
35
  syntax: "*";
36
36
  inherits: false;
37
37
  }
38
+ @property --ui-icon-button-active-surface {
39
+ syntax: "*";
40
+ inherits: false;
41
+ }
38
42
  @property --ui-icon-button-border {
39
43
  syntax: "*";
40
44
  inherits: false;
@@ -277,6 +281,12 @@
277
281
  background-color: var(--ui-icon-button-solid-hover-surface, var(--ui-accent-hover));
278
282
  }
279
283
 
284
+ :host-state([variant="ghost"])[aria-expanded="true"]:enabled:not([aria-disabled="true"]) {
285
+ background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 16%, transparent));
286
+ color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
287
+ box-shadow: var(--ui-pressed);
288
+ }
289
+
280
290
  :host:active:enabled:not([aria-disabled="true"]) {
281
291
  transform: scale(var(--ui-icon-button-active-scale, 0.96));
282
292
  }
@@ -17,6 +17,7 @@ export default function controller(host) {
17
17
  const overlayId = `ui-menu-${Math.random().toString(36).slice(2, 11)}`;
18
18
  const items = () => menuItems(element);
19
19
  let anchor = null;
20
+ let anchorAria = null;
20
21
  let surface = null;
21
22
  let lastFor;
22
23
  let lastPlacement;
@@ -39,6 +40,16 @@ export default function controller(host) {
39
40
  if (reason === "escape") anchor?.focus();
40
41
  };
41
42
  const ids = createIdResolver(document, () => apply());
43
+ const releaseAnchor = () => {
44
+ if (!anchor) return;
45
+ anchor.removeEventListener("click", onAnchorClick);
46
+ for (const [name, value] of Object.entries(anchorAria ?? {})) {
47
+ if (value === null) anchor.removeAttribute(name);
48
+ else anchor.setAttribute(name, value);
49
+ }
50
+ anchor = null;
51
+ anchorAria = null;
52
+ };
42
53
  const setup = () => {
43
54
  const nextFor = host.state.inline ? "" : String(host.state.for ?? "");
44
55
  const nextPlacement = String(host.state.placement ?? "bottom-start");
@@ -46,8 +57,9 @@ export default function controller(host) {
46
57
  lastFor = nextFor;
47
58
  lastPlacement = nextPlacement;
48
59
  surface?.destroy();
49
- anchor?.removeEventListener("click", onAnchorClick);
60
+ releaseAnchor();
50
61
  anchor = ids.get(nextFor);
62
+ if (anchor) anchorAria = { "aria-haspopup": anchor.getAttribute("aria-haspopup"), "aria-expanded": anchor.getAttribute("aria-expanded") };
51
63
  anchor?.addEventListener("click", onAnchorClick);
52
64
  surface = anchor ? createAnchoredSurface(element, { anchor, placement: nextPlacement }) : null;
53
65
  };
@@ -119,8 +131,8 @@ export default function controller(host) {
119
131
  ids.stop();
120
132
  element.removeEventListener("click", onClick);
121
133
  element.removeEventListener("keydown", onKeydown);
122
- anchor?.removeEventListener("click", onAnchorClick);
123
134
  surface?.destroy();
124
135
  closeOverlay(document, overlayId);
136
+ releaseAnchor();
125
137
  };
126
138
  }
@@ -87,6 +87,9 @@
87
87
  }
88
88
 
89
89
  .label {
90
+ display: flex;
91
+ align-items: center;
92
+ gap: var(--ui-space-2);
90
93
  flex: 1;
91
94
  min-inline-size: 0;
92
95
  }
@@ -13,6 +13,7 @@ export default function controller(host) {
13
13
  };
14
14
  const overlayId = `ui-popover-${Math.random().toString(36).slice(2, 11)}`;
15
15
  let anchor = null;
16
+ let anchorExpanded = null;
16
17
  let surface = null;
17
18
  let lastFor;
18
19
  let lastPlacement;
@@ -37,6 +38,14 @@ export default function controller(host) {
37
38
  host.dispatch("open", { open: true, reason: "action", trigger });
38
39
  };
39
40
  const ids = createIdResolver(document, () => apply());
41
+ const releaseAnchor = () => {
42
+ if (!anchor) return;
43
+ anchor.removeEventListener("click", onAnchorClick);
44
+ if (anchorExpanded === null) anchor.removeAttribute("aria-expanded");
45
+ else anchor.setAttribute("aria-expanded", anchorExpanded);
46
+ anchor = null;
47
+ anchorExpanded = null;
48
+ };
40
49
  const setup = () => {
41
50
  const nextFor = String(host.state.for ?? "");
42
51
  const nextPlacement = String(host.state.placement ?? "bottom-start");
@@ -44,8 +53,9 @@ export default function controller(host) {
44
53
  lastFor = nextFor;
45
54
  lastPlacement = nextPlacement;
46
55
  surface?.destroy();
47
- anchor?.removeEventListener("click", onAnchorClick);
56
+ releaseAnchor();
48
57
  anchor = ids.get(nextFor);
58
+ if (anchor) anchorExpanded = anchor.getAttribute("aria-expanded");
49
59
  anchor?.addEventListener("click", onAnchorClick);
50
60
  surface = anchor ? createAnchoredSurface(element, { anchor, placement: nextPlacement, gap: offset }) : null;
51
61
  };
@@ -57,6 +67,7 @@ export default function controller(host) {
57
67
  }
58
68
  setup();
59
69
  const open = Boolean(host.state.internalOpen);
70
+ if (anchor) anchor.setAttribute("aria-expanded", String(open));
60
71
  if (open) {
61
72
  surface?.show();
62
73
  openOverlay({ id: overlayId, modal: false, element, relatedElements: anchor ? [anchor] : [], dismissible: true, requestClose: close });
@@ -79,8 +90,8 @@ export default function controller(host) {
79
90
  stop();
80
91
  ids.stop();
81
92
  element.removeEventListener("keydown", onKeydown);
82
- anchor?.removeEventListener("click", onAnchorClick);
83
93
  surface?.destroy();
84
94
  closeOverlay(document, overlayId);
95
+ releaseAnchor();
85
96
  };
86
97
  }