@nuxt/ui 4.6.1 → 4.7.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.
Files changed (168) hide show
  1. package/README.md +7 -4
  2. package/cli/package.json +1 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +3 -2
  5. package/dist/runtime/components/Accordion.d.vue.ts +6 -1
  6. package/dist/runtime/components/Accordion.vue +1 -1
  7. package/dist/runtime/components/Accordion.vue.d.ts +6 -1
  8. package/dist/runtime/components/AuthForm.d.vue.ts +22 -29
  9. package/dist/runtime/components/AuthForm.vue +8 -6
  10. package/dist/runtime/components/AuthForm.vue.d.ts +22 -29
  11. package/dist/runtime/components/Calendar.vue +4 -4
  12. package/dist/runtime/components/Card.d.vue.ts +4 -0
  13. package/dist/runtime/components/Card.vue +16 -2
  14. package/dist/runtime/components/Card.vue.d.ts +4 -0
  15. package/dist/runtime/components/ChatMessage.d.vue.ts +27 -17
  16. package/dist/runtime/components/ChatMessage.vue +10 -16
  17. package/dist/runtime/components/ChatMessage.vue.d.ts +27 -17
  18. package/dist/runtime/components/ChatMessages.d.vue.ts +27 -21
  19. package/dist/runtime/components/ChatMessages.vue +22 -23
  20. package/dist/runtime/components/ChatMessages.vue.d.ts +27 -21
  21. package/dist/runtime/components/ChatPromptSubmit.vue +3 -1
  22. package/dist/runtime/components/Checkbox.vue +5 -3
  23. package/dist/runtime/components/CommandPalette.d.vue.ts +18 -3
  24. package/dist/runtime/components/CommandPalette.vue +11 -7
  25. package/dist/runtime/components/CommandPalette.vue.d.ts +18 -3
  26. package/dist/runtime/components/ContextMenuContent.vue +68 -65
  27. package/dist/runtime/components/DashboardSearch.d.vue.ts +8 -37
  28. package/dist/runtime/components/DashboardSearch.vue +11 -10
  29. package/dist/runtime/components/DashboardSearch.vue.d.ts +8 -37
  30. package/dist/runtime/components/DashboardSidebar.vue +1 -5
  31. package/dist/runtime/components/Drawer.vue +44 -41
  32. package/dist/runtime/components/DropdownMenuContent.vue +90 -87
  33. package/dist/runtime/components/EditorEmojiMenu.d.vue.ts +1 -1
  34. package/dist/runtime/components/EditorEmojiMenu.vue +2 -0
  35. package/dist/runtime/components/EditorEmojiMenu.vue.d.ts +1 -1
  36. package/dist/runtime/components/EditorMentionMenu.d.vue.ts +1 -1
  37. package/dist/runtime/components/EditorMentionMenu.vue +2 -0
  38. package/dist/runtime/components/EditorMentionMenu.vue.d.ts +1 -1
  39. package/dist/runtime/components/EditorSuggestionMenu.d.vue.ts +1 -1
  40. package/dist/runtime/components/EditorSuggestionMenu.vue +2 -0
  41. package/dist/runtime/components/EditorSuggestionMenu.vue.d.ts +1 -1
  42. package/dist/runtime/components/FileUpload.vue +7 -5
  43. package/dist/runtime/components/Header.vue +1 -5
  44. package/dist/runtime/components/Input.vue +2 -2
  45. package/dist/runtime/components/InputDate.vue +6 -6
  46. package/dist/runtime/components/InputMenu.d.vue.ts +3 -3
  47. package/dist/runtime/components/InputMenu.vue +40 -38
  48. package/dist/runtime/components/InputMenu.vue.d.ts +3 -3
  49. package/dist/runtime/components/InputNumber.vue +2 -2
  50. package/dist/runtime/components/InputTags.vue +2 -2
  51. package/dist/runtime/components/InputTime.vue +2 -2
  52. package/dist/runtime/components/Link.vue +64 -8
  53. package/dist/runtime/components/Listbox.d.vue.ts +228 -0
  54. package/dist/runtime/components/Listbox.vue +242 -0
  55. package/dist/runtime/components/Listbox.vue.d.ts +228 -0
  56. package/dist/runtime/components/Modal.vue +13 -10
  57. package/dist/runtime/components/Popover.vue +7 -4
  58. package/dist/runtime/components/PricingTable.vue +60 -58
  59. package/dist/runtime/components/RadioGroup.vue +5 -3
  60. package/dist/runtime/components/Select.d.vue.ts +1 -1
  61. package/dist/runtime/components/Select.vue +84 -73
  62. package/dist/runtime/components/Select.vue.d.ts +1 -1
  63. package/dist/runtime/components/SelectMenu.d.vue.ts +3 -3
  64. package/dist/runtime/components/SelectMenu.vue +54 -52
  65. package/dist/runtime/components/SelectMenu.vue.d.ts +3 -3
  66. package/dist/runtime/components/Sidebar.vue +1 -4
  67. package/dist/runtime/components/Slideover.vue +67 -64
  68. package/dist/runtime/components/Table.d.vue.ts +1 -2
  69. package/dist/runtime/components/Table.vue +17 -29
  70. package/dist/runtime/components/Table.vue.d.ts +1 -2
  71. package/dist/runtime/components/Tabs.d.vue.ts +5 -1
  72. package/dist/runtime/components/Tabs.vue +2 -2
  73. package/dist/runtime/components/Tabs.vue.d.ts +5 -1
  74. package/dist/runtime/components/Textarea.d.vue.ts +1 -0
  75. package/dist/runtime/components/Textarea.vue +2 -1
  76. package/dist/runtime/components/Textarea.vue.d.ts +1 -0
  77. package/dist/runtime/components/Tooltip.vue +12 -9
  78. package/dist/runtime/components/content/ContentSearch.d.vue.ts +19 -35
  79. package/dist/runtime/components/content/ContentSearch.vue +10 -9
  80. package/dist/runtime/components/content/ContentSearch.vue.d.ts +19 -35
  81. package/dist/runtime/components/content/ContentToc.vue +19 -9
  82. package/dist/runtime/components/prose/Img.vue +2 -1
  83. package/dist/runtime/components/prose/Pre.vue +8 -3
  84. package/dist/runtime/components/prose/Prompt.d.vue.ts +32 -0
  85. package/dist/runtime/components/prose/Prompt.vue +88 -0
  86. package/dist/runtime/components/prose/Prompt.vue.d.ts +32 -0
  87. package/dist/runtime/composables/index.d.ts +1 -0
  88. package/dist/runtime/composables/index.js +1 -0
  89. package/dist/runtime/composables/useContentSearch.js +19 -5
  90. package/dist/runtime/composables/useEditorMenu.d.ts +5 -0
  91. package/dist/runtime/composables/useEditorMenu.js +3 -1
  92. package/dist/runtime/composables/useFieldGroup.d.ts +3 -0
  93. package/dist/runtime/composables/useFieldGroup.js +11 -1
  94. package/dist/runtime/composables/useResolvedVariants.d.ts +21 -0
  95. package/dist/runtime/composables/useResolvedVariants.js +14 -0
  96. package/dist/runtime/locale/ar.js +9 -0
  97. package/dist/runtime/locale/az.js +9 -0
  98. package/dist/runtime/locale/be.js +9 -0
  99. package/dist/runtime/locale/bg.js +9 -0
  100. package/dist/runtime/locale/bn.js +9 -0
  101. package/dist/runtime/locale/ca.js +9 -0
  102. package/dist/runtime/locale/ckb.js +10 -1
  103. package/dist/runtime/locale/cs.js +9 -0
  104. package/dist/runtime/locale/da.js +9 -0
  105. package/dist/runtime/locale/de.js +9 -0
  106. package/dist/runtime/locale/de_ch.js +9 -0
  107. package/dist/runtime/locale/el.js +9 -0
  108. package/dist/runtime/locale/en.js +10 -1
  109. package/dist/runtime/locale/es.js +9 -0
  110. package/dist/runtime/locale/et.js +9 -0
  111. package/dist/runtime/locale/eu.js +11 -2
  112. package/dist/runtime/locale/fa_ir.js +9 -0
  113. package/dist/runtime/locale/fi.js +9 -0
  114. package/dist/runtime/locale/fr.js +9 -0
  115. package/dist/runtime/locale/gl.js +9 -0
  116. package/dist/runtime/locale/he.js +9 -0
  117. package/dist/runtime/locale/hi.js +9 -0
  118. package/dist/runtime/locale/hr.js +9 -0
  119. package/dist/runtime/locale/hu.js +9 -0
  120. package/dist/runtime/locale/hy.js +9 -0
  121. package/dist/runtime/locale/id.js +9 -0
  122. package/dist/runtime/locale/is.js +9 -0
  123. package/dist/runtime/locale/it.js +9 -0
  124. package/dist/runtime/locale/ja.js +9 -0
  125. package/dist/runtime/locale/ka.js +9 -0
  126. package/dist/runtime/locale/kk.js +9 -0
  127. package/dist/runtime/locale/km.js +9 -0
  128. package/dist/runtime/locale/ko.js +9 -0
  129. package/dist/runtime/locale/ky.js +9 -0
  130. package/dist/runtime/locale/lb.js +11 -2
  131. package/dist/runtime/locale/lo.js +15 -6
  132. package/dist/runtime/locale/lt.js +9 -0
  133. package/dist/runtime/locale/mn.js +9 -0
  134. package/dist/runtime/locale/ms.js +9 -0
  135. package/dist/runtime/locale/nb_no.js +9 -0
  136. package/dist/runtime/locale/nl.js +9 -0
  137. package/dist/runtime/locale/pl.js +9 -0
  138. package/dist/runtime/locale/pt.js +9 -0
  139. package/dist/runtime/locale/pt_br.js +9 -0
  140. package/dist/runtime/locale/ro.js +9 -0
  141. package/dist/runtime/locale/ru.js +9 -0
  142. package/dist/runtime/locale/sk.js +9 -0
  143. package/dist/runtime/locale/sl.js +9 -0
  144. package/dist/runtime/locale/sq.js +9 -0
  145. package/dist/runtime/locale/sv.js +9 -0
  146. package/dist/runtime/locale/th.js +9 -0
  147. package/dist/runtime/locale/tj.js +9 -0
  148. package/dist/runtime/locale/tr.js +9 -0
  149. package/dist/runtime/locale/ug_cn.js +9 -0
  150. package/dist/runtime/locale/uk.js +9 -0
  151. package/dist/runtime/locale/ur.js +9 -0
  152. package/dist/runtime/locale/uz.js +9 -0
  153. package/dist/runtime/locale/vi.js +9 -0
  154. package/dist/runtime/locale/zh_cn.js +9 -0
  155. package/dist/runtime/locale/zh_tw.js +9 -0
  156. package/dist/runtime/plugins/colors.js +1 -1
  157. package/dist/runtime/types/index.d.ts +1 -0
  158. package/dist/runtime/types/index.js +1 -0
  159. package/dist/runtime/types/locale.d.ts +9 -0
  160. package/dist/runtime/types/prose.d.ts +1 -0
  161. package/dist/runtime/types/prose.js +1 -0
  162. package/dist/runtime/vue/overrides/inertia/Link.vue +3 -3
  163. package/dist/runtime/vue/overrides/none/Link.vue +3 -2
  164. package/dist/runtime/vue/overrides/vue-router/Link.vue +27 -31
  165. package/dist/shared/{ui.DJUbBpE2.mjs → ui.BIQuJqNV.mjs} +186 -34
  166. package/dist/unplugin.mjs +1 -1
  167. package/dist/vite.mjs +1 -1
  168. package/package.json +48 -39
@@ -52,7 +52,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
52
52
  meta?: TableMeta<T>;
53
53
  /**
54
54
  * Enable virtualization for large datasets.
55
- * Note: when enabled, the divider between rows, sticky and row pinning properties are not supported.
55
+ * Note: row pinning is not supported when virtualization is enabled.
56
56
  * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
57
57
  * @defaultValue false
58
58
  */
@@ -75,7 +75,6 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
75
75
  empty?: string;
76
76
  /**
77
77
  * Whether the table should have a sticky header or footer. True for both, 'header' for header only, 'footer' for footer only.
78
- * Note: this prop is not supported when `virtualize` is true.
79
78
  * @defaultValue false
80
79
  */
81
80
  sticky?: boolean | 'header' | 'footer';
@@ -90,11 +90,10 @@ function processColumns(columns2) {
90
90
  });
91
91
  }
92
92
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.table || {} })({
93
- sticky: props.virtualize ? false : props.sticky,
93
+ sticky: props.sticky,
94
94
  loading: props.loading,
95
95
  loadingColor: props.loadingColor,
96
- loadingAnimation: props.loadingAnimation,
97
- virtualize: !!props.virtualize
96
+ loadingAnimation: props.loadingAnimation
98
97
  }));
99
98
  const [DefineTableTemplate, ReuseTableTemplate] = createReusableTemplate();
100
99
  const [DefineRowTemplate, ReuseRowTemplate] = createReusableTemplate({
@@ -238,15 +237,11 @@ const virtualizer = !!props.virtualize && useVirtualizer({
238
237
  return typeof estimate === "function" ? estimate(index) : estimate;
239
238
  }
240
239
  });
241
- const renderedSize = computed(() => {
242
- if (!virtualizer) {
243
- return 0;
244
- }
245
- const virtualItems = virtualizer.value.getVirtualItems();
246
- if (!virtualItems?.length) {
247
- return 0;
248
- }
249
- return virtualItems.reduce((sum, item) => sum + item.size, 0);
240
+ const virtualItems = computed(() => virtualizer ? virtualizer.value.getVirtualItems() : []);
241
+ const virtualPaddingTop = computed(() => virtualItems.value[0]?.start ?? 0);
242
+ const virtualPaddingBottom = computed(() => {
243
+ if (!virtualizer || !virtualItems.value.length) return 0;
244
+ return virtualizer.value.getTotalSize() - (virtualItems.value[virtualItems.value.length - 1]?.end ?? 0);
250
245
  });
251
246
  function valueUpdater(updaterOrValue, ref) {
252
247
  ref.value = typeof updaterOrValue === "function" ? updaterOrValue(ref.value) : updaterOrValue;
@@ -408,15 +403,19 @@ defineExpose({
408
403
  <ReuseRowTemplate v-for="row in topRows" :key="row.id" :row="row" />
409
404
 
410
405
  <template v-if="virtualizer">
411
- <template v-for="(virtualRow, index) in virtualizer.getVirtualItems()" :key="centerRows[virtualRow.index]?.id">
406
+ <tr v-if="virtualPaddingTop > 0" :style="{ height: `${virtualPaddingTop}px` }" aria-hidden="true">
407
+ <td :colspan="tableApi.getAllLeafColumns().length" />
408
+ </tr>
409
+ <template v-for="virtualRow in virtualItems" :key="centerRows[virtualRow.index]?.id ?? `virtual-${virtualRow.index}`">
412
410
  <ReuseRowTemplate
411
+ v-if="centerRows[virtualRow.index]"
413
412
  :row="centerRows[virtualRow.index]"
414
- :style="{
415
- height: `${virtualRow.size}px`,
416
- transform: `translateY(${virtualRow.start - index * virtualRow.size}px)`
417
- }"
413
+ :style="{ height: `${virtualRow.size}px` }"
418
414
  />
419
415
  </template>
416
+ <tr v-if="virtualPaddingBottom > 0" :style="{ height: `${virtualPaddingBottom}px` }" aria-hidden="true">
417
+ <td :colspan="tableApi.getAllLeafColumns().length" />
418
+ </tr>
420
419
  </template>
421
420
 
422
421
  <template v-else>
@@ -447,9 +446,6 @@ defineExpose({
447
446
  v-if="hasFooter"
448
447
  data-slot="tfoot"
449
448
  :class="ui.tfoot({ class: [uiProp?.tfoot] })"
450
- :style="virtualizer ? {
451
- transform: `translateY(${virtualizer.getTotalSize() - renderedSize}px)`
452
- } : void 0"
453
449
  >
454
450
  <tr data-slot="separator" :class="ui.separator({ class: [uiProp?.separator] })" />
455
451
 
@@ -483,14 +479,6 @@ defineExpose({
483
479
  </DefineTableTemplate>
484
480
 
485
481
  <Primitive ref="rootRef" :as="as" v-bind="$attrs" data-slot="root" :class="ui.root({ class: [uiProp?.root, props.class] })">
486
- <div
487
- v-if="virtualizer"
488
- :style="{
489
- height: `${virtualizer.getTotalSize()}px`
490
- }"
491
- >
492
- <ReuseTableTemplate />
493
- </div>
494
- <ReuseTableTemplate v-else />
482
+ <ReuseTableTemplate />
495
483
  </Primitive>
496
484
  </template>
@@ -52,7 +52,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
52
52
  meta?: TableMeta<T>;
53
53
  /**
54
54
  * Enable virtualization for large datasets.
55
- * Note: when enabled, the divider between rows, sticky and row pinning properties are not supported.
55
+ * Note: row pinning is not supported when virtualization is enabled.
56
56
  * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
57
57
  * @defaultValue false
58
58
  */
@@ -75,7 +75,6 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
75
75
  empty?: string;
76
76
  /**
77
77
  * Whether the table should have a sticky header or footer. True for both, 'header' for header only, 'footer' for footer only.
78
- * Note: this prop is not supported when `virtualize` is true.
79
78
  * @defaultValue false
80
79
  */
81
80
  sticky?: boolean | 'header' | 'footer';
@@ -20,7 +20,11 @@ export interface TabsItem {
20
20
  badge?: string | number | BadgeProps;
21
21
  slot?: string;
22
22
  content?: string;
23
- /** A unique value for the tab item. Defaults to the index. */
23
+ /**
24
+ * A unique value for the tab item. Defaults to the index.
25
+ * Also used as the Vue `key` for this item, so providing a stable value prevents tab
26
+ * content (and its local state) from remounting when items are added, removed, or reordered.
27
+ */
24
28
  value?: string | number;
25
29
  disabled?: boolean;
26
30
  class?: any;
@@ -67,7 +67,7 @@ defineExpose({
67
67
 
68
68
  <TabsTrigger
69
69
  v-for="(item, index) of items"
70
- :key="index"
70
+ :key="get(item, props.valueKey) ?? index"
71
71
  :ref="(el) => setTriggerRef(index, el)"
72
72
  :value="get(item, props.valueKey) ?? String(index)"
73
73
  :disabled="item.disabled"
@@ -100,7 +100,7 @@ defineExpose({
100
100
  </TabsList>
101
101
 
102
102
  <template v-if="!!content">
103
- <TabsContent v-for="(item, index) of items" :key="index" :value="get(item, props.valueKey) ?? String(index)" data-slot="content" :class="ui.content({ class: [uiProp?.content, item.ui?.content, item.class] })">
103
+ <TabsContent v-for="(item, index) of items" :key="get(item, props.valueKey) ?? index" :value="get(item, props.valueKey) ?? String(index)" data-slot="content" :class="ui.content({ class: [uiProp?.content, item.ui?.content, item.class] })">
104
104
  <slot :name="item.slot || 'content'" :item="item" :index="index" :ui="ui">
105
105
  {{ item.content }}
106
106
  </slot>
@@ -20,7 +20,11 @@ export interface TabsItem {
20
20
  badge?: string | number | BadgeProps;
21
21
  slot?: string;
22
22
  content?: string;
23
- /** A unique value for the tab item. Defaults to the index. */
23
+ /**
24
+ * A unique value for the tab item. Defaults to the index.
25
+ * Also used as the Vue `key` for this item, so providing a stable value prevents tab
26
+ * content (and its local state) from remounting when items are added, removed, or reordered.
27
+ */
24
28
  value?: string | number;
25
29
  disabled?: boolean;
26
30
  class?: any;
@@ -95,6 +95,7 @@ declare const __VLS_export: <T extends TextareaValue, Mod extends ModelModifiers
95
95
  } ? P : {});
96
96
  expose: (exposed: import("vue").ShallowUnwrapRef<{
97
97
  textareaRef: Readonly<import("vue").ShallowRef<HTMLTextAreaElement | null, HTMLTextAreaElement | null>>;
98
+ autoResize: () => void;
98
99
  }>) => void;
99
100
  attrs: any;
100
101
  slots: TextareaSlots;
@@ -138,7 +138,8 @@ onMounted(() => {
138
138
  }, props.autoresizeDelay);
139
139
  });
140
140
  defineExpose({
141
- textareaRef
141
+ textareaRef,
142
+ autoResize
142
143
  });
143
144
  </script>
144
145
 
@@ -95,6 +95,7 @@ declare const __VLS_export: <T extends TextareaValue, Mod extends ModelModifiers
95
95
  } ? P : {});
96
96
  expose: (exposed: import("vue").ShallowUnwrapRef<{
97
97
  textareaRef: Readonly<import("vue").ShallowRef<HTMLTextAreaElement | null, HTMLTextAreaElement | null>>;
98
+ autoResize: () => void;
98
99
  }>) => void;
99
100
  attrs: any;
100
101
  slots: TextareaSlots;
@@ -9,6 +9,7 @@ import { TooltipRoot, TooltipTrigger, TooltipPortal, TooltipContent, TooltipArro
9
9
  import { reactivePick } from "@vueuse/core";
10
10
  import { useAppConfig } from "#imports";
11
11
  import { useComponentUI } from "../composables/useComponentUI";
12
+ import { FieldGroupReset } from "../composables/useFieldGroup";
12
13
  import { usePortal } from "../composables/usePortal";
13
14
  import { tv } from "../utils/tv";
14
15
  import UKbd from "./Kbd.vue";
@@ -50,17 +51,19 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.tooltip || {}
50
51
  </TooltipTrigger>
51
52
 
52
53
  <TooltipPortal v-bind="portalProps">
53
- <TooltipContent v-bind="contentProps" data-slot="content" :class="ui.content({ class: [!slots.default && props.class, uiProp?.content] })">
54
- <slot name="content" :ui="ui">
55
- <span v-if="text" data-slot="text" :class="ui.text({ class: uiProp?.text })">{{ text }}</span>
54
+ <FieldGroupReset>
55
+ <TooltipContent v-bind="contentProps" data-slot="content" :class="ui.content({ class: [!slots.default && props.class, uiProp?.content] })">
56
+ <slot name="content" :ui="ui">
57
+ <span v-if="text" data-slot="text" :class="ui.text({ class: uiProp?.text })">{{ text }}</span>
56
58
 
57
- <span v-if="kbds?.length" data-slot="kbds" :class="ui.kbds({ class: uiProp?.kbds })">
58
- <UKbd v-for="(kbd, index) in kbds" :key="index" :size="uiProp?.kbdsSize || ui.kbdsSize()" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
59
- </span>
60
- </slot>
59
+ <span v-if="kbds?.length" data-slot="kbds" :class="ui.kbds({ class: uiProp?.kbds })">
60
+ <UKbd v-for="(kbd, index) in kbds" :key="index" :size="uiProp?.kbdsSize || ui.kbdsSize()" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
61
+ </span>
62
+ </slot>
61
63
 
62
- <TooltipArrow v-if="!!arrow" v-bind="arrowProps" data-slot="arrow" :class="ui.arrow({ class: uiProp?.arrow })" />
63
- </TooltipContent>
64
+ <TooltipArrow v-if="!!arrow" v-bind="arrowProps" data-slot="arrow" :class="ui.arrow({ class: uiProp?.arrow })" />
65
+ </TooltipContent>
66
+ </FieldGroupReset>
64
67
  </TooltipPortal>
65
68
  </TooltipRoot>
66
69
  </template>
@@ -3,7 +3,7 @@ import type { ContentNavigationItem } from '@nuxt/content';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import type { UseFuseOptions } from '@vueuse/integrations/useFuse';
5
5
  import theme from '#build/ui/content/content-search';
6
- import type { ButtonProps, InputProps, LinkProps, ModalProps, CommandPaletteProps, CommandPaletteSlots, CommandPaletteGroup, CommandPaletteItem, IconProps, LinkPropsKeys } from '../../types';
6
+ import type { ButtonProps, LinkProps, ModalProps, CommandPaletteProps, CommandPaletteSlots, CommandPaletteGroup, CommandPaletteItem, IconProps, LinkPropsKeys } from '../../types';
7
7
  import type { ComponentConfig } from '../../types/tv';
8
8
  type ContentSearch = ComponentConfig<typeof theme, AppConfig, 'contentSearch'>;
9
9
  export interface ContentSearchLink extends Omit<LinkProps, 'custom'> {
@@ -29,35 +29,11 @@ export interface ContentSearchItem extends Omit<LinkProps, 'custom'>, CommandPal
29
29
  */
30
30
  icon?: IconProps['name'];
31
31
  }
32
- export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchLink> extends Pick<ModalProps, 'title' | 'description' | 'overlay' | 'transition' | 'content' | 'dismissible' | 'fullscreen' | 'modal' | 'portal'> {
32
+ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchLink> extends Pick<ModalProps, 'title' | 'description' | 'overlay' | 'transition' | 'content' | 'dismissible' | 'fullscreen' | 'modal' | 'portal'>, Pick<CommandPaletteProps<CommandPaletteGroup<ContentSearchItem>, ContentSearchItem>, 'icon' | 'placeholder' | 'autofocus' | 'loading' | 'loadingIcon' | 'closeIcon' | 'groups'> {
33
33
  /**
34
34
  * @defaultValue 'md'
35
35
  */
36
36
  size?: ContentSearch['variants']['size'];
37
- /**
38
- * The icon displayed in the input.
39
- * @defaultValue appConfig.ui.icons.search
40
- * @IconifyIcon
41
- */
42
- icon?: IconProps['name'];
43
- /**
44
- * The placeholder text for the input.
45
- * @defaultValue t('commandPalette.placeholder')
46
- */
47
- placeholder?: InputProps['placeholder'];
48
- /**
49
- * Automatically focus the input when component is mounted.
50
- * @defaultValue true
51
- */
52
- autofocus?: boolean;
53
- /** When `true`, the loading icon will be displayed. */
54
- loading?: boolean;
55
- /**
56
- * The icon when the `loading` prop is `true`.
57
- * @defaultValue appConfig.ui.icons.loading
58
- * @IconifyIcon
59
- */
60
- loadingIcon?: IconProps['name'];
61
37
  /**
62
38
  * Display a close button in the input (useful when inside a Modal for example).
63
39
  * `{ size: 'md', color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
@@ -65,12 +41,6 @@ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchL
65
41
  * @defaultValue true
66
42
  */
67
43
  close?: boolean | Omit<ButtonProps, LinkPropsKeys>;
68
- /**
69
- * The icon displayed in the close button.
70
- * @defaultValue appConfig.ui.icons.close
71
- * @IconifyIcon
72
- */
73
- closeIcon?: IconProps['name'];
74
44
  /**
75
45
  * Keyboard shortcut to open the search (used by [`defineShortcuts`](https://ui.nuxt.com/docs/composables/define-shortcuts))
76
46
  * @defaultValue 'meta_k'
@@ -79,14 +49,28 @@ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchL
79
49
  /** Links group displayed as the first group in the command palette. */
80
50
  links?: T[];
81
51
  navigation?: ContentNavigationItem[];
82
- /** Custom groups displayed between navigation and color mode group. */
83
- groups?: CommandPaletteGroup<ContentSearchItem>[];
84
52
  files?: ContentSearchFile[];
85
53
  /**
86
54
  * Options for [useFuse](https://vueuse.org/integrations/useFuse) passed to the [CommandPalette](https://ui.nuxt.com/docs/components/command-palette).
87
- * @defaultValue { fuseOptions: { includeMatches: true } }
55
+ * @defaultValue {
56
+ fuseOptions: {
57
+ ignoreLocation: true,
58
+ includeMatches: true,
59
+ threshold: 0.1,
60
+ keys: ['label', 'suffix']
61
+ },
62
+ resultLimit: 12,
63
+ matchAllWhenSearchEmpty: true
64
+ }
88
65
  */
89
66
  fuse?: UseFuseOptions<T>;
67
+ /**
68
+ * Delay (in milliseconds) before the search term is passed to Fuse (debounced).
69
+ * Useful for large doc sets where running fuzzy search on every keystroke is the bottleneck — the input stays responsive while Fuse only re-runs after typing settles.
70
+ * Set to `0` to disable.
71
+ * @defaultValue 100
72
+ */
73
+ searchDelay?: number;
90
74
  /**
91
75
  * When `true`, the theme command will be added to the groups.
92
76
  * @defaultValue true
@@ -17,19 +17,13 @@ import UModal from "../Modal.vue";
17
17
  import UCommandPalette from "../CommandPalette.vue";
18
18
  const props = defineProps({
19
19
  size: { type: null, required: false },
20
- icon: { type: null, required: false },
21
- placeholder: { type: String, required: false },
22
- autofocus: { type: Boolean, required: false },
23
- loading: { type: Boolean, required: false },
24
- loadingIcon: { type: null, required: false },
25
20
  close: { type: [Boolean, Object], required: false, default: true },
26
- closeIcon: { type: null, required: false },
27
21
  shortcut: { type: String, required: false, default: "meta_k" },
28
22
  links: { type: Array, required: false },
29
23
  navigation: { type: Array, required: false },
30
- groups: { type: Array, required: false },
31
24
  files: { type: Array, required: false },
32
25
  fuse: { type: Object, required: false },
26
+ searchDelay: { type: Number, required: false, default: 100 },
33
27
  colorMode: { type: Boolean, required: false, default: true },
34
28
  class: { type: null, required: false },
35
29
  ui: { type: Object, required: false },
@@ -41,7 +35,14 @@ const props = defineProps({
41
35
  dismissible: { type: Boolean, required: false },
42
36
  fullscreen: { type: Boolean, required: false, default: false },
43
37
  modal: { type: Boolean, required: false },
44
- portal: { type: [Boolean, String], required: false, skipCheck: true }
38
+ portal: { type: [Boolean, String], required: false, skipCheck: true },
39
+ icon: { type: null, required: false },
40
+ placeholder: { type: String, required: false },
41
+ autofocus: { type: Boolean, required: false },
42
+ loading: { type: Boolean, required: false },
43
+ loadingIcon: { type: null, required: false },
44
+ closeIcon: { type: null, required: false },
45
+ groups: { type: Array, required: false }
45
46
  });
46
47
  const slots = defineSlots();
47
48
  const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
@@ -50,7 +51,7 @@ const { open, mapNavigationItems, postFilter } = useContentSearch();
50
51
  const colorMode = useColorMode();
51
52
  const appConfig = useAppConfig();
52
53
  const uiProp = useComponentUI("contentSearch", props);
53
- const commandPaletteProps = useForwardProps(reactivePick(props, "size", "icon", "placeholder", "autofocus", "loading", "loadingIcon", "close", "closeIcon"));
54
+ const commandPaletteProps = useForwardProps(reactivePick(props, "size", "icon", "placeholder", "autofocus", "loading", "loadingIcon", "close", "closeIcon", "searchDelay"));
54
55
  const modalProps = useForwardProps(reactivePick(props, "overlay", "transition", "content", "dismissible", "fullscreen", "modal", "portal"));
55
56
  const getProxySlots = () => omit(slots, ["content"]);
56
57
  const fuse = computed(() => defu({}, props.fuse, {
@@ -3,7 +3,7 @@ import type { ContentNavigationItem } from '@nuxt/content';
3
3
  import type { AppConfig } from '@nuxt/schema';
4
4
  import type { UseFuseOptions } from '@vueuse/integrations/useFuse';
5
5
  import theme from '#build/ui/content/content-search';
6
- import type { ButtonProps, InputProps, LinkProps, ModalProps, CommandPaletteProps, CommandPaletteSlots, CommandPaletteGroup, CommandPaletteItem, IconProps, LinkPropsKeys } from '../../types';
6
+ import type { ButtonProps, LinkProps, ModalProps, CommandPaletteProps, CommandPaletteSlots, CommandPaletteGroup, CommandPaletteItem, IconProps, LinkPropsKeys } from '../../types';
7
7
  import type { ComponentConfig } from '../../types/tv';
8
8
  type ContentSearch = ComponentConfig<typeof theme, AppConfig, 'contentSearch'>;
9
9
  export interface ContentSearchLink extends Omit<LinkProps, 'custom'> {
@@ -29,35 +29,11 @@ export interface ContentSearchItem extends Omit<LinkProps, 'custom'>, CommandPal
29
29
  */
30
30
  icon?: IconProps['name'];
31
31
  }
32
- export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchLink> extends Pick<ModalProps, 'title' | 'description' | 'overlay' | 'transition' | 'content' | 'dismissible' | 'fullscreen' | 'modal' | 'portal'> {
32
+ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchLink> extends Pick<ModalProps, 'title' | 'description' | 'overlay' | 'transition' | 'content' | 'dismissible' | 'fullscreen' | 'modal' | 'portal'>, Pick<CommandPaletteProps<CommandPaletteGroup<ContentSearchItem>, ContentSearchItem>, 'icon' | 'placeholder' | 'autofocus' | 'loading' | 'loadingIcon' | 'closeIcon' | 'groups'> {
33
33
  /**
34
34
  * @defaultValue 'md'
35
35
  */
36
36
  size?: ContentSearch['variants']['size'];
37
- /**
38
- * The icon displayed in the input.
39
- * @defaultValue appConfig.ui.icons.search
40
- * @IconifyIcon
41
- */
42
- icon?: IconProps['name'];
43
- /**
44
- * The placeholder text for the input.
45
- * @defaultValue t('commandPalette.placeholder')
46
- */
47
- placeholder?: InputProps['placeholder'];
48
- /**
49
- * Automatically focus the input when component is mounted.
50
- * @defaultValue true
51
- */
52
- autofocus?: boolean;
53
- /** When `true`, the loading icon will be displayed. */
54
- loading?: boolean;
55
- /**
56
- * The icon when the `loading` prop is `true`.
57
- * @defaultValue appConfig.ui.icons.loading
58
- * @IconifyIcon
59
- */
60
- loadingIcon?: IconProps['name'];
61
37
  /**
62
38
  * Display a close button in the input (useful when inside a Modal for example).
63
39
  * `{ size: 'md', color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
@@ -65,12 +41,6 @@ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchL
65
41
  * @defaultValue true
66
42
  */
67
43
  close?: boolean | Omit<ButtonProps, LinkPropsKeys>;
68
- /**
69
- * The icon displayed in the close button.
70
- * @defaultValue appConfig.ui.icons.close
71
- * @IconifyIcon
72
- */
73
- closeIcon?: IconProps['name'];
74
44
  /**
75
45
  * Keyboard shortcut to open the search (used by [`defineShortcuts`](https://ui.nuxt.com/docs/composables/define-shortcuts))
76
46
  * @defaultValue 'meta_k'
@@ -79,14 +49,28 @@ export interface ContentSearchProps<T extends ContentSearchLink = ContentSearchL
79
49
  /** Links group displayed as the first group in the command palette. */
80
50
  links?: T[];
81
51
  navigation?: ContentNavigationItem[];
82
- /** Custom groups displayed between navigation and color mode group. */
83
- groups?: CommandPaletteGroup<ContentSearchItem>[];
84
52
  files?: ContentSearchFile[];
85
53
  /**
86
54
  * Options for [useFuse](https://vueuse.org/integrations/useFuse) passed to the [CommandPalette](https://ui.nuxt.com/docs/components/command-palette).
87
- * @defaultValue { fuseOptions: { includeMatches: true } }
55
+ * @defaultValue {
56
+ fuseOptions: {
57
+ ignoreLocation: true,
58
+ includeMatches: true,
59
+ threshold: 0.1,
60
+ keys: ['label', 'suffix']
61
+ },
62
+ resultLimit: 12,
63
+ matchAllWhenSearchEmpty: true
64
+ }
88
65
  */
89
66
  fuse?: UseFuseOptions<T>;
67
+ /**
68
+ * Delay (in milliseconds) before the search term is passed to Fuse (debounced).
69
+ * Useful for large doc sets where running fuzzy search on every keystroke is the bottleneck — the input stays responsive while Fuse only re-runs after typing settles.
70
+ * Set to `0` to disable.
71
+ * @defaultValue 100
72
+ */
73
+ searchDelay?: number;
90
74
  /**
91
75
  * When `true`, the theme command will be added to the groups.
92
76
  * @defaultValue true
@@ -3,11 +3,12 @@ import theme from "#build/ui/content/content-toc";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed } from "vue";
6
+ import { computed, onUnmounted } from "vue";
7
7
  import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent, useForwardPropsEmits } from "reka-ui";
8
8
  import { reactivePick, createReusableTemplate } from "@vueuse/core";
9
9
  import { useRouter, useAppConfig, useNuxtApp } from "#imports";
10
10
  import { useComponentUI } from "../../composables/useComponentUI";
11
+ import { useResolvedVariants } from "../../composables/useResolvedVariants";
11
12
  import { useScrollspy } from "../../composables/useScrollspy";
12
13
  import { useLocale } from "../../composables/useLocale";
13
14
  import { tv } from "../../utils/tv";
@@ -34,6 +35,7 @@ const { t } = useLocale();
34
35
  const router = useRouter();
35
36
  const appConfig = useAppConfig();
36
37
  const uiProp = useComponentUI("contentToc", props);
38
+ const { highlightVariant } = useResolvedVariants("contentToc", props, theme, ["highlightVariant"]);
37
39
  const { activeHeadings, updateHeadings } = useScrollspy();
38
40
  const [DefineListTemplate, ReuseListTemplate] = createReusableTemplate({
39
41
  props: {
@@ -46,7 +48,7 @@ const [DefineContentTemplate, ReuseContentTemplate] = createReusableTemplate();
46
48
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.contentToc || {} })({
47
49
  color: props.color,
48
50
  highlight: props.highlight,
49
- highlightVariant: props.highlightVariant,
51
+ highlightVariant: highlightVariant.value,
50
52
  highlightColor: props.highlightColor || props.color
51
53
  }));
52
54
  function scrollToHeading(id) {
@@ -76,7 +78,7 @@ const indicatorStyle = computed(() => {
76
78
  };
77
79
  });
78
80
  const circuitMaskStyle = computed(() => {
79
- if (!props.highlight || props.highlightVariant !== "circuit" || !props.links?.length) {
81
+ if (!props.highlight || highlightVariant.value !== "circuit" || !props.links?.length) {
80
82
  return;
81
83
  }
82
84
  const flatLinks = flattenLinksWithLevel(props.links);
@@ -110,13 +112,21 @@ const circuitMaskStyle = computed(() => {
110
112
  };
111
113
  });
112
114
  const nuxtApp = useNuxtApp();
113
- nuxtApp.hooks.hook("page:loading:end", () => {
114
- const headings = Array.from(document.querySelectorAll("h2, h3"));
115
- updateHeadings(headings);
116
- });
117
- nuxtApp.hooks.hook("page:transition:finish", () => {
118
- const headings = Array.from(document.querySelectorAll("h2, h3"));
115
+ function refreshHeadings() {
116
+ const flatLinks = flattenLinks(props.links || []);
117
+ if (!flatLinks.length) {
118
+ updateHeadings([]);
119
+ return;
120
+ }
121
+ const selector = flatLinks.map((l) => `#${CSS.escape(l.id)}`).join(", ");
122
+ const headings = Array.from(document.querySelectorAll(selector));
119
123
  updateHeadings(headings);
124
+ }
125
+ const offLoadingEnd = nuxtApp.hooks.hook("page:loading:end", refreshHeadings);
126
+ const offTransitionFinish = nuxtApp.hooks.hook("page:transition:finish", refreshHeadings);
127
+ onUnmounted(() => {
128
+ offLoadingEnd();
129
+ offTransitionFinish();
120
130
  });
121
131
  </script>
122
132
 
@@ -29,7 +29,8 @@ const [DefineZoomedImageTemplate, ReuseZoomedImageTemplate] = createReusableTemp
29
29
  const open = ref(false);
30
30
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.prose?.img || {} })({
31
31
  zoom: props.zoom,
32
- open: open.value
32
+ open: open.value,
33
+ width: !!props.width
33
34
  }));
34
35
  const refinedSrc = computed(() => resolveBaseURL(props.src, useRuntimeConfig().app.baseURL));
35
36
  const layoutId = computed(() => `${refinedSrc.value}::${useId()}`);
@@ -3,7 +3,7 @@ import theme from "#build/ui/prose/pre";
3
3
  </script>
4
4
 
5
5
  <script setup>
6
- import { computed } from "vue";
6
+ import { computed, useTemplateRef } from "vue";
7
7
  import { useClipboard } from "@vueuse/core";
8
8
  import { useAppConfig } from "#imports";
9
9
  import { useComponentUI } from "../../composables/useComponentUI";
@@ -27,7 +27,12 @@ const { t } = useLocale();
27
27
  const { copy, copied } = useClipboard();
28
28
  const appConfig = useAppConfig();
29
29
  const uiProp = useComponentUI("prose.pre", props);
30
+ const baseRef = useTemplateRef("baseRef");
30
31
  const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.prose?.pre || {} })());
32
+ function copyCode() {
33
+ const code = props.code ?? baseRef.value?.textContent ?? "";
34
+ copy(code);
35
+ }
31
36
  </script>
32
37
 
33
38
  <template>
@@ -46,9 +51,9 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.prose?.pre ||
46
51
  :aria-label="t('prose.pre.copy')"
47
52
  :class="ui.copy({ class: uiProp?.copy })"
48
53
  tabindex="-1"
49
- @click="copy(props.code || '')"
54
+ @click="copyCode"
50
55
  />
51
56
 
52
- <pre :class="ui.base({ class: [uiProp?.base, props.class] })" v-bind="$attrs"><slot /></pre>
57
+ <pre ref="baseRef" :class="ui.base({ class: [uiProp?.base, props.class] })" v-bind="$attrs"><slot /></pre>
53
58
  </div>
54
59
  </template>
@@ -0,0 +1,32 @@
1
+ import type { VNode } from 'vue';
2
+ import type { AppConfig } from '@nuxt/schema';
3
+ import theme from '#build/ui/prose/prompt';
4
+ import type { IconProps } from '../../types';
5
+ import type { ComponentConfig } from '../../types/tv';
6
+ type ProsePrompt = ComponentConfig<typeof theme, AppConfig, 'prompt', 'ui.prose'>;
7
+ export interface ProsePromptProps {
8
+ description?: string;
9
+ /**
10
+ * @IconifyIcon
11
+ */
12
+ icon?: IconProps['name'];
13
+ /**
14
+ * @defaultValue ['copy']
15
+ */
16
+ actions?: ('copy' | 'cursor' | 'windsurf')[];
17
+ class?: any;
18
+ ui?: ProsePrompt['slots'];
19
+ }
20
+ export interface ProsePromptSlots {
21
+ default(props?: {}): VNode[];
22
+ }
23
+ declare const _default: typeof __VLS_export;
24
+ export default _default;
25
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ProsePromptProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ProsePromptProps> & Readonly<{}>, {
26
+ actions: ("copy" | "cursor" | "windsurf")[];
27
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ProsePromptSlots>;
28
+ type __VLS_WithSlots<T, S> = T & {
29
+ new (): {
30
+ $slots: S;
31
+ };
32
+ };