@knime/kds-components 0.29.3 → 0.30.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @knime/kds-components
2
2
 
3
+ ## 0.30.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e0a3ce6: Add submenu capability to `KdsMenuContainer` component
8
+ - Can now render children items up to 3 levels (root + 2 nested submenus)
9
+ - Items with children cannot have a shortcut assigned, nor a badge or a trailing icon since that space
10
+ is reserved for the icon that hints at a nested submenu
11
+
12
+ ### Patch Changes
13
+
14
+ - @knime/kds-styles@0.30.0
15
+
3
16
  ## 0.29.3
4
17
 
5
18
  ### Patch Changes
package/dist/index.css CHANGED
@@ -1210,7 +1210,7 @@ html.kds-legacy {
1210
1210
  }
1211
1211
  }
1212
1212
 
1213
- .kds-menu-item-link[data-v-677d6ca6] {
1213
+ .kds-menu-item-link[data-v-96d9cfba] {
1214
1214
  display: block;
1215
1215
  color: inherit;
1216
1216
  text-decoration: none;
@@ -1227,7 +1227,7 @@ html.kds-legacy {
1227
1227
  }
1228
1228
 
1229
1229
  .kds-menu-container {
1230
- &[data-v-cce3fc40] {
1230
+ &[data-v-9dc6d3f6] {
1231
1231
  display: flex;
1232
1232
  flex-direction: column;
1233
1233
  gap: var(--kds-spacing-container-0-10x);
@@ -1239,11 +1239,46 @@ html.kds-legacy {
1239
1239
  border-radius: var(--kds-border-radius-container-0-50x);
1240
1240
  box-shadow: var(--kds-elevation-level-3);
1241
1241
  }
1242
- &[data-v-cce3fc40]:focus-visible {
1242
+ &[data-v-9dc6d3f6]:focus-visible {
1243
1243
  outline: var(--kds-border-action-focused);
1244
1244
  outline-offset: var(--kds-spacing-offset-focus);
1245
1245
  }
1246
1246
  }
1247
+ .submenu-popover[data-v-9dc6d3f6] {
1248
+ inset: anchor(top) auto auto anchor(right);
1249
+ padding: 0 var(--kds-spacing-container-0-25x);
1250
+ margin: 0;
1251
+ position-try-fallbacks:
1252
+ --kds-popover-try-right-dropdown, --kds-popover-try-left-dropdown,
1253
+ --kds-popover-try-right-dropup, --kds-popover-try-left-dropup;
1254
+ overflow: visible;
1255
+ font: inherit;
1256
+ color: inherit;
1257
+ background-color: transparent;
1258
+ border: none;
1259
+ border-radius: 0;
1260
+ box-shadow: none;
1261
+ }
1262
+
1263
+ /* noinspection CssInvalidFunction,CssInvalidAtRule */
1264
+ @position-try --kds-popover-try-right-dropdown {
1265
+ inset: anchor(top) auto auto anchor(right);
1266
+ }
1267
+
1268
+ /* noinspection CssInvalidFunction,CssInvalidAtRule */
1269
+ @position-try --kds-popover-try-left-dropdown {
1270
+ inset: anchor(top) anchor(left) auto auto;
1271
+ }
1272
+
1273
+ /* noinspection CssInvalidFunction,CssInvalidAtRule */
1274
+ @position-try --kds-popover-try-right-dropup {
1275
+ inset: auto auto anchor(bottom) anchor(right);
1276
+ }
1277
+
1278
+ /* noinspection CssInvalidFunction,CssInvalidAtRule */
1279
+ @position-try --kds-popover-try-left-dropup {
1280
+ inset: auto anchor(left) anchor(bottom) auto;
1281
+ }
1247
1282
 
1248
1283
  .kds-popover {
1249
1284
  &[data-v-1e5f9d24] {
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { defineComponent, createPropsRestProxy, ref, watch, computed, openBlock, createElementBlock, normalizeClass, createElementVNode, toDisplayString, Fragment, renderList, createBlock, normalizeStyle, createCommentVNode, shallowRef, markRaw, readonly, toRef, unref, resolveDynamicComponent, mergeProps, useTemplateRef, createVNode, withCtx, renderSlot, h as h$1, useSlots, getCurrentInstance, useModel, mergeModels, onMounted, onUnmounted, nextTick, useId, withModifiers, watchEffect, useAttrs, withKeys, isRef, getCurrentScope, onScopeDispose, defineAsyncComponent, toRefs, useCssVars, createSlots, normalizeProps, withDirectives, vShow, onBeforeUpdate, onBeforeUnmount, vModelText, createTextVNode, guardReactiveProps } from 'vue';
1
+ import { defineComponent, createPropsRestProxy, ref, watch, computed, openBlock, createElementBlock, normalizeClass, createElementVNode, toDisplayString, Fragment, renderList, createBlock, normalizeStyle, createCommentVNode, shallowRef, markRaw, readonly, toRef, unref, resolveDynamicComponent, mergeProps, useTemplateRef, createVNode, withCtx, renderSlot, h as h$1, useSlots, getCurrentInstance, useModel, mergeModels, onMounted, onUnmounted, nextTick, useId, withModifiers, inject, provide, resolveComponent, withKeys, watchEffect, useAttrs, isRef, getCurrentScope, onScopeDispose, defineAsyncComponent, toRefs, useCssVars, createSlots, normalizeProps, withDirectives, vShow, onBeforeUpdate, onBeforeUnmount, vModelText, createTextVNode, guardReactiveProps } from 'vue';
2
2
  import { useLocalStorage, useDark, usePreferredDark, useResizeObserver, useMutationObserver, onClickOutside, useElementSize, useMousePressed, useVirtualList, useTemplateRefsList } from '@vueuse/core';
3
3
 
4
4
  import './index.css';const kdsAvatarSize = {
@@ -10,7 +10,7 @@ import './index.css';const kdsAvatarSize = {
10
10
  const kdsAvatarSizes = Object.values(kdsAvatarSize);
11
11
 
12
12
  const _hoisted_1$15 = ["role", "title", "aria-hidden", "aria-label", "data-color"];
13
- const _hoisted_2$G = ["src"];
13
+ const _hoisted_2$H = ["src"];
14
14
  const _hoisted_3$u = {
15
15
  key: 1,
16
16
  class: "kds-avatar-initials",
@@ -80,7 +80,7 @@ const _sfc_main$1G = /* @__PURE__ */ defineComponent({
80
80
  alt: "",
81
81
  "aria-hidden": "true",
82
82
  onError: onImageError
83
- }, null, 40, _hoisted_2$G)) : (openBlock(), createElementBlock("div", _hoisted_3$u, [
83
+ }, null, 40, _hoisted_2$H)) : (openBlock(), createElementBlock("div", _hoisted_3$u, [
84
84
  createElementVNode("span", null, toDisplayString(displayedInitials.value), 1)
85
85
  ]))
86
86
  ], 10, _hoisted_1$15);
@@ -99,7 +99,7 @@ const _export_sfc = (sfc, props) => {
99
99
  const KdsAvatar = /* @__PURE__ */ _export_sfc(_sfc_main$1G, [["__scopeId", "data-v-9e1a5abe"]]);
100
100
 
101
101
  const _hoisted_1$14 = ["aria-label"];
102
- const _hoisted_2$F = { class: "avatars" };
102
+ const _hoisted_2$G = { class: "avatars" };
103
103
  const _hoisted_3$t = {
104
104
  key: 0,
105
105
  class: "more-count",
@@ -125,7 +125,7 @@ const _sfc_main$1F = /* @__PURE__ */ defineComponent({
125
125
  role: "group",
126
126
  "aria-label": ariaLabel.value
127
127
  }, [
128
- createElementVNode("div", _hoisted_2$F, [
128
+ createElementVNode("div", _hoisted_2$G, [
129
129
  (openBlock(true), createElementBlock(Fragment, null, renderList(__props.avatars, (avatar, index) => {
130
130
  return openBlock(), createBlock(KdsAvatar, {
131
131
  key: index,
@@ -686,7 +686,7 @@ const kdsProgressBarSize = {
686
686
  const kdsProgressBarSizes = Object.values(kdsProgressBarSize);
687
687
 
688
688
  const _hoisted_1$11 = ["title", "aria-label"];
689
- const _hoisted_2$E = {
689
+ const _hoisted_2$F = {
690
690
  key: 0,
691
691
  class: "indeterminate-bar",
692
692
  "aria-hidden": "true"
@@ -728,7 +728,7 @@ const _sfc_main$1B = /* @__PURE__ */ defineComponent({
728
728
  "aria-label": title.value,
729
729
  class: "progress"
730
730
  }, __props.indeterminate ? {} : { value: progressValue.value, max: 100 }), null, 16, _hoisted_1$11),
731
- __props.indeterminate ? (openBlock(), createElementBlock("span", _hoisted_2$E)) : createCommentVNode("", true)
731
+ __props.indeterminate ? (openBlock(), createElementBlock("span", _hoisted_2$F)) : createCommentVNode("", true)
732
732
  ], 2);
733
733
  };
734
734
  }
@@ -961,7 +961,7 @@ function useKdsIsTruncated(elementRef) {
961
961
  }
962
962
 
963
963
  const _hoisted_1$$ = ["title", "aria-label"];
964
- const _hoisted_2$D = ["title"];
964
+ const _hoisted_2$E = ["title"];
965
965
  const _sfc_main$1z = /* @__PURE__ */ defineComponent({
966
966
  __name: "KdsLiveStatus",
967
967
  props: {
@@ -991,7 +991,7 @@ const _sfc_main$1z = /* @__PURE__ */ defineComponent({
991
991
  ref: labelEl,
992
992
  class: "label",
993
993
  title: unref(isTruncated) ? __props.label : void 0
994
- }, toDisplayString(__props.label), 9, _hoisted_2$D)) : createCommentVNode("", true)
994
+ }, toDisplayString(__props.label), 9, _hoisted_2$E)) : createCommentVNode("", true)
995
995
  ], 10, _hoisted_1$$);
996
996
  };
997
997
  }
@@ -1055,7 +1055,7 @@ const kdsLoadingSpinnerVariants = Object.values(
1055
1055
  );
1056
1056
 
1057
1057
  const _hoisted_1$Z = ["role"];
1058
- const _hoisted_2$C = { class: "header" };
1058
+ const _hoisted_2$D = { class: "header" };
1059
1059
  const _hoisted_3$s = { class: "headline" };
1060
1060
  const _hoisted_4$o = {
1061
1061
  key: 0,
@@ -1092,7 +1092,7 @@ const _sfc_main$1x = /* @__PURE__ */ defineComponent({
1092
1092
  class: normalizeClass(classes.value),
1093
1093
  role: role.value
1094
1094
  }, [
1095
- createElementVNode("div", _hoisted_2$C, [
1095
+ createElementVNode("div", _hoisted_2$D, [
1096
1096
  createVNode(KdsIcon, {
1097
1097
  class: "icon",
1098
1098
  name: iconName.value,
@@ -1135,7 +1135,7 @@ const _sfc_main$1w = /* @__PURE__ */ defineComponent({
1135
1135
  const KdsMissingValueIcon = /* @__PURE__ */ _export_sfc(_sfc_main$1w, [["__scopeId", "data-v-df682150"]]);
1136
1136
 
1137
1137
  const _hoisted_1$Y = { class: "donut-container" };
1138
- const _hoisted_2$B = ["height", "width", "viewBox"];
1138
+ const _hoisted_2$C = ["height", "width", "viewBox"];
1139
1139
  const _hoisted_3$r = ["r", "stroke-width"];
1140
1140
  const _hoisted_4$n = ["r", "stroke-width", "stroke-dasharray", "stroke-dashoffset", "transform"];
1141
1141
  const _hoisted_5$d = ["r", "stroke-width", "stroke-dasharray", "stroke-dashoffset", "transform"];
@@ -1233,7 +1233,7 @@ const _sfc_main$1v = /* @__PURE__ */ defineComponent({
1233
1233
  fill: "transparent",
1234
1234
  transform: transformWedge.value
1235
1235
  }, null, 10, _hoisted_5$d)) : createCommentVNode("", true)
1236
- ], 8, _hoisted_2$B)),
1236
+ ], 8, _hoisted_2$C)),
1237
1237
  __props.title ? (openBlock(), createElementBlock("div", _hoisted_6$b, [
1238
1238
  createElementVNode("div", _hoisted_7$4, toDisplayString(__props.title), 1),
1239
1239
  __props.subText ? (openBlock(), createElementBlock("div", _hoisted_8$3, toDisplayString(__props.subText), 1)) : createCommentVNode("", true)
@@ -1634,7 +1634,7 @@ function prettyBytes(number, options) {
1634
1634
  }
1635
1635
 
1636
1636
  const _hoisted_1$V = { class: "label" };
1637
- const _hoisted_2$A = {
1637
+ const _hoisted_2$B = {
1638
1638
  key: 1,
1639
1639
  class: "file-size"
1640
1640
  };
@@ -1734,7 +1734,7 @@ const _sfc_main$1q = /* @__PURE__ */ defineComponent({
1734
1734
  name: "external-link",
1735
1735
  size: "xsmall"
1736
1736
  })) : createCommentVNode("", true),
1737
- normalizedFileSize.value ? (openBlock(), createElementBlock("span", _hoisted_2$A, toDisplayString(normalizedFileSize.value), 1)) : createCommentVNode("", true)
1737
+ normalizedFileSize.value ? (openBlock(), createElementBlock("span", _hoisted_2$B, toDisplayString(normalizedFileSize.value), 1)) : createCommentVNode("", true)
1738
1738
  ]),
1739
1739
  _: 1
1740
1740
  }, 8, ["class", "to", "download", "target", "rel", "title", "aria-disabled"]);
@@ -1782,7 +1782,7 @@ const kdsToggleButtonVariant = {
1782
1782
  const kdsToggleButtonVariants = Object.values(kdsToggleButtonVariant);
1783
1783
 
1784
1784
  const _hoisted_1$U = ["data-visible"];
1785
- const _hoisted_2$z = ["data-visible"];
1785
+ const _hoisted_2$A = ["data-visible"];
1786
1786
  const _sfc_main$1o = /* @__PURE__ */ defineComponent({
1787
1787
  __name: "KdsProgressButton",
1788
1788
  props: /* @__PURE__ */ mergeModels({
@@ -1854,7 +1854,7 @@ const _sfc_main$1o = /* @__PURE__ */ defineComponent({
1854
1854
  size: iconSize.value,
1855
1855
  variant: __props.variant === "filled" ? "onPrimary" : "onSurface"
1856
1856
  }, null, 8, ["size", "variant"])
1857
- ], 8, _hoisted_2$z)
1857
+ ], 8, _hoisted_2$A)
1858
1858
  ], 2)
1859
1859
  ]),
1860
1860
  _: 1
@@ -1885,7 +1885,8 @@ const useListItemKeyboardNav = (options) => {
1885
1885
  containerEl,
1886
1886
  selectableItems,
1887
1887
  enabledItems,
1888
- itemFocusStrategy = "persistent"
1888
+ itemFocusStrategy = "persistent",
1889
+ shouldNavigate = () => true
1889
1890
  } = options;
1890
1891
  const activeId = ref(void 0);
1891
1892
  function scrollToView() {
@@ -1914,6 +1915,9 @@ const useListItemKeyboardNav = (options) => {
1914
1915
  return enabledItems.value[currentIndex - 1].id;
1915
1916
  };
1916
1917
  const handleKeydown = (event) => {
1918
+ if (!shouldNavigate(event)) {
1919
+ return;
1920
+ }
1917
1921
  if (enabledItems.value.length === 0) {
1918
1922
  activeId.value = selectableItems.value.length === 0 ? options.emptyOptionId : void 0;
1919
1923
  return;
@@ -1933,6 +1937,14 @@ const useListItemKeyboardNav = (options) => {
1933
1937
  scrollToView();
1934
1938
  event.preventDefault();
1935
1939
  break;
1940
+ case "ArrowLeft":
1941
+ options.triggers?.onArrowLeft?.(activeId.value, targetItem);
1942
+ event.preventDefault();
1943
+ break;
1944
+ case "ArrowRight":
1945
+ options.triggers?.onArrowRight?.(activeId.value, targetItem);
1946
+ event.preventDefault();
1947
+ break;
1936
1948
  case "Enter":
1937
1949
  options.triggers?.onEnter?.(activeId.value, targetItem, event);
1938
1950
  event.preventDefault();
@@ -2134,7 +2146,7 @@ const kdsListItemAccessorySize = {
2134
2146
  };
2135
2147
 
2136
2148
  const _hoisted_1$T = ["id", "role", "aria-selected", "aria-disabled"];
2137
- const _hoisted_2$y = {
2149
+ const _hoisted_2$z = {
2138
2150
  key: 0,
2139
2151
  class: "accessory"
2140
2152
  };
@@ -2212,7 +2224,7 @@ const _sfc_main$1m = /* @__PURE__ */ defineComponent({
2212
2224
  ]),
2213
2225
  onClick
2214
2226
  }, [
2215
- props.accessory ? (openBlock(), createElementBlock("span", _hoisted_2$y, [
2227
+ props.accessory ? (openBlock(), createElementBlock("span", _hoisted_2$z, [
2216
2228
  createVNode(_sfc_main$1n, {
2217
2229
  accessory: props.accessory,
2218
2230
  size: accessorySize.value,
@@ -2261,7 +2273,7 @@ const _sfc_main$1m = /* @__PURE__ */ defineComponent({
2261
2273
  const KdsListItem = /* @__PURE__ */ _export_sfc(_sfc_main$1m, [["__scopeId", "data-v-a3d6c86f"]]);
2262
2274
 
2263
2275
  const _hoisted_1$S = { class: "kds-list-item-section-title" };
2264
- const _hoisted_2$x = {
2276
+ const _hoisted_2$y = {
2265
2277
  key: 0,
2266
2278
  class: "icon"
2267
2279
  };
@@ -2278,7 +2290,7 @@ const _sfc_main$1l = /* @__PURE__ */ defineComponent({
2278
2290
  const { isTruncated } = useKdsIsTruncated(labelEl);
2279
2291
  return (_ctx, _cache) => {
2280
2292
  return openBlock(), createElementBlock("div", _hoisted_1$S, [
2281
- props.leadingIcon ? (openBlock(), createElementBlock("span", _hoisted_2$x, [
2293
+ props.leadingIcon ? (openBlock(), createElementBlock("span", _hoisted_2$y, [
2282
2294
  createVNode(KdsIcon, {
2283
2295
  name: props.leadingIcon,
2284
2296
  size: "small"
@@ -2305,7 +2317,7 @@ const _sfc_main$1k = /* @__PURE__ */ defineComponent({
2305
2317
  isLast: { type: Boolean },
2306
2318
  variant: {}
2307
2319
  },
2308
- emits: ["click"],
2320
+ emits: ["click", "mouseenter"],
2309
2321
  setup(__props, { expose: __expose }) {
2310
2322
  const props = __props;
2311
2323
  const linkEl = useTemplateRef(
@@ -2370,6 +2382,14 @@ const _sfc_main$1k = /* @__PURE__ */ defineComponent({
2370
2382
  const effectiveTo = computed(
2371
2383
  () => props.item.disabled ? void 0 : props.item.to
2372
2384
  );
2385
+ const hasChildren = computed(
2386
+ () => props.item.children && props.item.children.length > 0
2387
+ );
2388
+ const anchorId = useId();
2389
+ const anchorName = `--anchor-${anchorId}`;
2390
+ const anchorRootStyle = computed(
2391
+ () => hasChildren.value ? { anchorName } : {}
2392
+ );
2373
2393
  return (_ctx, _cache) => {
2374
2394
  return openBlock(), createElementBlock(Fragment, null, [
2375
2395
  __props.item.sectionHeadline ? (openBlock(), createBlock(unref(ListItemSectionTitle), mergeProps({
@@ -2393,7 +2413,8 @@ const _sfc_main$1k = /* @__PURE__ */ defineComponent({
2393
2413
  class: "kds-menu-item-link",
2394
2414
  onMousedown: _cache[0] || (_cache[0] = withModifiers(() => {
2395
2415
  }, ["prevent"])),
2396
- onClick: _cache[1] || (_cache[1] = ($event) => !__props.item.disabled && _ctx.$emit("click", $event))
2416
+ onClick: _cache[1] || (_cache[1] = ($event) => !__props.item.disabled && _ctx.$emit("click", $event)),
2417
+ onMouseenter: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("mouseenter", $event))
2397
2418
  }, {
2398
2419
  default: withCtx(() => [
2399
2420
  createVNode(unref(KdsListItem), mergeProps({
@@ -2411,7 +2432,7 @@ const _sfc_main$1k = /* @__PURE__ */ defineComponent({
2411
2432
  }, _ctx.$attrs), null, 16, ["id", "accessory", "text", "sub-text", "disabled", "active", "variant", "badge", "shortcut", "trailing-icon"])
2412
2433
  ]),
2413
2434
  _: 1
2414
- }, 40, ["id", "to", "download", "target", "rel", "aria-disabled"])) : (openBlock(), createBlock(unref(KdsListItem), mergeProps({
2435
+ }, 40, ["id", "to", "download", "target", "rel", "aria-disabled"])) : !hasChildren.value ? (openBlock(), createBlock(unref(KdsListItem), mergeProps({
2415
2436
  key: 2,
2416
2437
  id: __props.item.id,
2417
2438
  accessory: __props.item.accessory,
@@ -2425,22 +2446,46 @@ const _sfc_main$1k = /* @__PURE__ */ defineComponent({
2425
2446
  shortcut: __props.item.shortcut,
2426
2447
  role: "menuitem"
2427
2448
  }, _ctx.$attrs, {
2428
- onClick: _cache[2] || (_cache[2] = ($event) => !__props.item.disabled && _ctx.$emit("click", $event))
2429
- }), null, 16, ["id", "accessory", "text", "sub-text", "disabled", "active", "variant", "badge", "trailing-icon", "shortcut"])),
2430
- __props.item.separator && !__props.isLast ? (openBlock(), createBlock(unref(KdsDivider), {
2449
+ onClick: _cache[3] || (_cache[3] = ($event) => !__props.item.disabled && _ctx.$emit("click", $event)),
2450
+ onMouseenter: _cache[4] || (_cache[4] = ($event) => _ctx.$emit("mouseenter", $event))
2451
+ }), null, 16, ["id", "accessory", "text", "sub-text", "disabled", "active", "variant", "badge", "trailing-icon", "shortcut"])) : (openBlock(), createBlock(unref(KdsListItem), mergeProps({
2431
2452
  key: 3,
2453
+ id: __props.item.id,
2454
+ accessory: __props.item.accessory,
2455
+ text: __props.item.text,
2456
+ "sub-text": __props.item.subText,
2457
+ disabled: __props.item.disabled,
2458
+ active: __props.activeId === __props.item.id,
2459
+ variant: __props.variant,
2460
+ "trailing-icon": "chevron-right",
2461
+ style: anchorRootStyle.value,
2462
+ role: "menuitem",
2463
+ "aria-haspopup": "menu"
2464
+ }, _ctx.$attrs, {
2465
+ onMouseenter: _cache[5] || (_cache[5] = ($event) => _ctx.$emit("mouseenter", $event))
2466
+ }), null, 16, ["id", "accessory", "text", "sub-text", "disabled", "active", "variant", "style"])),
2467
+ __props.item.separator && !__props.isLast ? (openBlock(), createBlock(unref(KdsDivider), {
2468
+ key: 4,
2432
2469
  class: "kds-list-item-divider",
2433
2470
  role: "presentation",
2434
2471
  "aria-hidden": "true"
2435
- })) : createCommentVNode("", true)
2472
+ })) : createCommentVNode("", true),
2473
+ hasChildren.value ? renderSlot(_ctx.$slots, "children", {
2474
+ key: 5,
2475
+ anchor: { id: unref(anchorId), name: anchorName }
2476
+ }, void 0, true) : createCommentVNode("", true)
2436
2477
  ], 64);
2437
2478
  };
2438
2479
  }
2439
2480
  });
2440
2481
 
2441
- const KdsMenuItem = /* @__PURE__ */ _export_sfc(_sfc_main$1k, [["__scopeId", "data-v-677d6ca6"]]);
2482
+ const KdsMenuItem = /* @__PURE__ */ _export_sfc(_sfc_main$1k, [["__scopeId", "data-v-96d9cfba"]]);
2483
+
2484
+ const ContainerDepthKey = /* @__PURE__ */ Symbol("ContainerDepth");
2485
+ const ChildItemKey = /* @__PURE__ */ Symbol("ChildItem");
2442
2486
 
2443
2487
  const _hoisted_1$R = ["id", "aria-label", "aria-activedescendant"];
2488
+ const _hoisted_2$x = ["id"];
2444
2489
  const _sfc_main$1j = /* @__PURE__ */ defineComponent({
2445
2490
  __name: "KdsMenuContainer",
2446
2491
  props: {
@@ -2497,20 +2542,95 @@ const _sfc_main$1j = /* @__PURE__ */ defineComponent({
2497
2542
  }
2498
2543
  handleItemInteraction(item, event);
2499
2544
  };
2500
- const { activeId } = useListItemKeyboardNav({
2545
+ const activePopoverId = ref();
2546
+ const popovers = shallowRef({});
2547
+ const showPopover = (itemId) => {
2548
+ if (!itemId) {
2549
+ return void 0;
2550
+ }
2551
+ if (popovers.value[itemId]) {
2552
+ activePopoverId.value = itemId;
2553
+ popovers.value[itemId].showPopover?.();
2554
+ return popovers.value[itemId];
2555
+ }
2556
+ return void 0;
2557
+ };
2558
+ const closePopover = () => {
2559
+ if (activePopoverId.value) {
2560
+ popovers.value[activePopoverId.value]?.hidePopover?.();
2561
+ activePopoverId.value = void 0;
2562
+ }
2563
+ };
2564
+ const depth = inject(ContainerDepthKey, 0);
2565
+ const providedDepth = computed(() => depth + 1);
2566
+ const canRenderSubmenus = computed(() => depth < 2);
2567
+ provide(ContainerDepthKey, providedDepth.value);
2568
+ const parentList = inject(ChildItemKey, null);
2569
+ const validateItemChildren = (item) => {
2570
+ if (item.children) {
2571
+ return canRenderSubmenus.value ? item : { ...item, children: [] };
2572
+ }
2573
+ return item;
2574
+ };
2575
+ const hasChildren = (item) => {
2576
+ return item.children && item.children.length > 0;
2577
+ };
2578
+ const showPopoverByKeyboard = (activeId2) => {
2579
+ if (activeId2) {
2580
+ const activePopover = showPopover(activeId2);
2581
+ const containerComponent = activePopover?.querySelector(
2582
+ "[data-submenu-container]"
2583
+ );
2584
+ containerComponent?.focus();
2585
+ }
2586
+ };
2587
+ const { activeId, setActiveId } = useListItemKeyboardNav({
2501
2588
  containerEl,
2502
2589
  enabledItems,
2503
2590
  selectableItems,
2504
2591
  itemFocusStrategy: __props.itemFocusStrategy,
2592
+ // only allow navigation when the current menu has the focus
2593
+ shouldNavigate: (event) => {
2594
+ const rootNode = containerEl.value?.getRootNode();
2595
+ if (!rootNode) {
2596
+ return false;
2597
+ }
2598
+ const activeElement = rootNode.activeElement;
2599
+ return activeElement === event.target && activeElement === containerEl.value;
2600
+ },
2505
2601
  triggers: {
2506
- onEnter: (_activeId, item, event) => {
2507
- onKeyboardActivate(item, event);
2602
+ onEnter: (activeId2, item, event) => {
2603
+ if (item && hasChildren(validateItemChildren(item))) {
2604
+ showPopoverByKeyboard(activeId2);
2605
+ } else {
2606
+ onKeyboardActivate(item, event);
2607
+ }
2508
2608
  },
2509
2609
  onSpace: (_activeId, item, event) => {
2510
2610
  onKeyboardActivate(item, event);
2611
+ },
2612
+ // In this type of navigation
2613
+ // LEFT is treated as -> CLOSE
2614
+ onArrowLeft: () => {
2615
+ parentList?.closeActiveSubmenu({ requester: props.id });
2616
+ },
2617
+ // RIGHT is treated as -> OPEN
2618
+ onArrowRight: (activeId2, item) => {
2619
+ if (item && !hasChildren(validateItemChildren(item))) {
2620
+ return;
2621
+ }
2622
+ showPopoverByKeyboard(activeId2);
2511
2623
  }
2512
2624
  }
2513
2625
  });
2626
+ provide(ChildItemKey, {
2627
+ closeActiveSubmenu: () => {
2628
+ const lastActiveId = activePopoverId.value;
2629
+ closePopover();
2630
+ containerEl.value?.focus();
2631
+ setActiveId(lastActiveId);
2632
+ }
2633
+ });
2514
2634
  __expose({
2515
2635
  /**
2516
2636
  * Function to focus the outer container of the menu.
@@ -2520,7 +2640,18 @@ const _sfc_main$1j = /* @__PURE__ */ defineComponent({
2520
2640
  containerEl.value?.focus();
2521
2641
  }
2522
2642
  });
2643
+ const handleFocusOut = (event) => {
2644
+ if (event.relatedTarget && containerEl.value?.contains(event.relatedTarget)) {
2645
+ event.stopPropagation();
2646
+ if (containerEl.value === event.relatedTarget) {
2647
+ const lastActiveId = activePopoverId.value;
2648
+ closePopover();
2649
+ setActiveId(lastActiveId);
2650
+ }
2651
+ }
2652
+ };
2523
2653
  return (_ctx, _cache) => {
2654
+ const _component_KdsMenuContainer = resolveComponent("KdsMenuContainer", true);
2524
2655
  return openBlock(), createElementBlock("div", {
2525
2656
  id: props.id,
2526
2657
  ref_key: "containerEl",
@@ -2530,26 +2661,68 @@ const _sfc_main$1j = /* @__PURE__ */ defineComponent({
2530
2661
  "aria-label": __props.ariaLabel,
2531
2662
  tabindex: 0,
2532
2663
  style: normalizeStyle({ maxHeight: __props.menuMaxHeight }),
2533
- "aria-activedescendant": unref(activeId)
2664
+ "aria-activedescendant": unref(activeId) ?? activePopoverId.value,
2665
+ onMouseleave: closePopover,
2666
+ onFocusin: _cache[3] || (_cache[3] = withModifiers(($event) => activePopoverId.value = void 0, ["stop"])),
2667
+ onFocusout: handleFocusOut,
2668
+ onKeydown: _cache[4] || (_cache[4] = withKeys(
2669
+ () => {
2670
+ unref(parentList)?.closeActiveSubmenu({ requester: props.id });
2671
+ },
2672
+ ["esc"]
2673
+ ))
2534
2674
  }, [
2535
2675
  (openBlock(true), createElementBlock(Fragment, null, renderList(unref(itemsWithPrefix), (item, index) => {
2536
2676
  return openBlock(), createBlock(KdsMenuItem, {
2537
2677
  key: item.id,
2538
2678
  ref_for: true,
2539
2679
  ref: (el) => setItemRef(el, index),
2540
- item,
2680
+ item: validateItemChildren(item),
2541
2681
  "is-last": index === unref(itemsWithPrefix).length - 1,
2542
- "active-id": unref(activeId),
2682
+ "active-id": unref(activeId) ?? activePopoverId.value,
2543
2683
  variant: __props.variant,
2544
- onClick: ($event) => handleItemInteraction(item, $event)
2545
- }, null, 8, ["item", "is-last", "active-id", "variant", "onClick"]);
2684
+ onClick: ($event) => handleItemInteraction(item, $event),
2685
+ onMouseenter: () => {
2686
+ if (activePopoverId.value) {
2687
+ closePopover();
2688
+ }
2689
+ if (!item.disabled && hasChildren(item)) {
2690
+ showPopover(item.id);
2691
+ }
2692
+ }
2693
+ }, {
2694
+ children: withCtx(({ anchor }) => [
2695
+ createElementVNode("div", {
2696
+ id: anchor.id,
2697
+ ref_for: true,
2698
+ ref: (el) => {
2699
+ popovers.value[item.id] = el;
2700
+ },
2701
+ popover: "",
2702
+ class: "submenu-popover",
2703
+ style: normalizeStyle({ positionAnchor: anchor.name }),
2704
+ onMouseleave: _cache[1] || (_cache[1] = ($event) => closePopover()),
2705
+ onKeydown: _cache[2] || (_cache[2] = withKeys(withModifiers(() => {
2706
+ }, ["stop", "prevent"]), ["esc"]))
2707
+ }, [
2708
+ createVNode(_component_KdsMenuContainer, {
2709
+ id: `${__props.id}:${item.id}`,
2710
+ "data-submenu-container": "",
2711
+ ariaLabel: `Submenu for item ${item.text}`,
2712
+ items: item.children ?? [],
2713
+ onItemClick: _cache[0] || (_cache[0] = ($event) => emit("itemClick", $event))
2714
+ }, null, 8, ["id", "ariaLabel", "items"])
2715
+ ], 44, _hoisted_2$x)
2716
+ ]),
2717
+ _: 2
2718
+ }, 1032, ["item", "is-last", "active-id", "variant", "onClick", "onMouseenter"]);
2546
2719
  }), 128))
2547
- ], 12, _hoisted_1$R);
2720
+ ], 44, _hoisted_1$R);
2548
2721
  };
2549
2722
  }
2550
2723
  });
2551
2724
 
2552
- const KdsMenuContainer = /* @__PURE__ */ _export_sfc(_sfc_main$1j, [["__scopeId", "data-v-cce3fc40"]]);
2725
+ const KdsMenuContainer = /* @__PURE__ */ _export_sfc(_sfc_main$1j, [["__scopeId", "data-v-9dc6d3f6"]]);
2553
2726
 
2554
2727
  const kdsPopoverPlacement = {
2555
2728
  TOP_LEFT: "top-left",