@bitrix24/b24ui-nuxt 2.1.17 → 2.2.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.
Files changed (38) hide show
  1. package/dist/meta.d.mts +632 -11
  2. package/dist/meta.mjs +632 -11
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +1 -1
  5. package/dist/runtime/components/ScrollArea.d.vue.ts +81 -0
  6. package/dist/runtime/components/ScrollArea.vue +187 -0
  7. package/dist/runtime/components/ScrollArea.vue.d.ts +81 -0
  8. package/dist/runtime/components/Table.d.vue.ts +1 -0
  9. package/dist/runtime/components/Table.vue.d.ts +1 -0
  10. package/dist/runtime/types/index.d.ts +1 -0
  11. package/dist/runtime/types/index.js +1 -0
  12. package/dist/runtime/{inertia/components → vue/overrides/inertia}/Link.d.vue.ts +1 -1
  13. package/dist/runtime/{inertia/components → vue/overrides/inertia}/Link.vue +3 -3
  14. package/dist/runtime/{inertia/components → vue/overrides/inertia}/Link.vue.d.ts +1 -1
  15. package/dist/runtime/{inertia/components → vue/overrides/inertia}/LinkBase.d.vue.ts +1 -1
  16. package/dist/runtime/{inertia/components → vue/overrides/inertia}/LinkBase.vue.d.ts +1 -1
  17. package/dist/runtime/vue/overrides/none/Link.d.vue.ts +73 -0
  18. package/dist/runtime/vue/overrides/none/Link.vue +128 -0
  19. package/dist/runtime/vue/overrides/none/Link.vue.d.ts +73 -0
  20. package/dist/runtime/vue/{components → overrides/vue-router}/Link.d.vue.ts +1 -1
  21. package/dist/runtime/vue/{components → overrides/vue-router}/Link.vue +4 -4
  22. package/dist/runtime/vue/{components → overrides/vue-router}/Link.vue.d.ts +1 -1
  23. package/dist/runtime/vue/{stubs.d.ts → stubs/base.d.ts} +6 -7
  24. package/dist/runtime/vue/{stubs.js → stubs/base.js} +6 -7
  25. package/dist/runtime/vue/stubs/inertia.d.ts +5 -0
  26. package/dist/runtime/vue/stubs/inertia.js +10 -0
  27. package/dist/runtime/vue/stubs/none.d.ts +56 -0
  28. package/dist/runtime/vue/stubs/none.js +48 -0
  29. package/dist/runtime/vue/stubs/vue-router.d.ts +2 -0
  30. package/dist/runtime/vue/stubs/vue-router.js +2 -0
  31. package/dist/shared/{b24ui-nuxt.BeTQIwtu.mjs → b24ui-nuxt.C-CS9MBp.mjs} +37 -8
  32. package/dist/unplugin.d.mts +13 -0
  33. package/dist/unplugin.mjs +83 -61
  34. package/dist/vite.mjs +1 -1
  35. package/package.json +4 -4
  36. package/dist/runtime/inertia/stubs.d.ts +0 -46
  37. package/dist/runtime/inertia/stubs.js +0 -93
  38. /package/dist/runtime/{inertia/components → vue/overrides/inertia}/LinkBase.vue +0 -0
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitrix24/b24ui-nuxt",
3
- "version": "2.1.17",
3
+ "version": "2.2.1",
4
4
  "docs": "https://bitrix24.github.io/b24ui/guide/installation-nuxt-app.html",
5
5
  "configKey": "b24ui",
6
6
  "compatibility": {
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defu } from 'defu';
2
2
  import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addComponentsDir, addImportsDir, installModule } from '@nuxt/kit';
3
- import { d as defaultOptions, v as version, n as name, a as getDefaultConfig, b as addTemplates } from './shared/b24ui-nuxt.BeTQIwtu.mjs';
3
+ import { d as defaultOptions, v as version, n as name, a as getDefaultConfig, b as addTemplates } from './shared/b24ui-nuxt.C-CS9MBp.mjs';
4
4
  import 'node:url';
5
5
  import 'scule';
6
6
  import 'knitwork';
@@ -0,0 +1,81 @@
1
+ import type { AppConfig } from '@nuxt/schema';
2
+ import type { VirtualItem, VirtualizerOptions } from '@tanstack/vue-virtual';
3
+ import theme from '#build/b24ui/scroll-area';
4
+ import type { ComponentConfig } from '../types/tv';
5
+ type ScrollArea = ComponentConfig<typeof theme, AppConfig, 'scrollArea'>;
6
+ export interface ScrollAreaVirtualizeOptions extends Partial<Omit<VirtualizerOptions<Element, Element>, 'count' | 'getScrollElement' | 'horizontal' | 'isRtl' | 'estimateSize' | 'lanes' | 'enabled'>> {
7
+ /**
8
+ * Estimated size (in px) of each item along the scroll axis. Can be a number or a function.
9
+ * @defaultValue 100
10
+ */
11
+ estimateSize?: number | ((index: number) => number);
12
+ /**
13
+ * Number of lanes for multi-column/row layouts.
14
+ * For responsive lane counts, use a computed property with viewport/container size:
15
+ * @example
16
+ * ```ts
17
+ * const { width } = useWindowSize()
18
+ * const lanes = computed(() => Math.floor(width.value / 300))
19
+ * ```
20
+ * @defaultValue undefined
21
+ */
22
+ lanes?: number;
23
+ }
24
+ export type ScrollAreaItem = any;
25
+ export interface ScrollAreaProps<T extends ScrollAreaItem = ScrollAreaItem> {
26
+ /**
27
+ * The element or component this component should render as.
28
+ * @defaultValue 'div'
29
+ */
30
+ as?: any;
31
+ /**
32
+ * The scroll direction.
33
+ * @defaultValue 'vertical'
34
+ */
35
+ orientation?: ScrollArea['variants']['orientation'];
36
+ /**
37
+ * Array of items to render.
38
+ */
39
+ items?: T[];
40
+ /**
41
+ * Enable virtualization for large lists.
42
+ * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
43
+ * @defaultValue false
44
+ */
45
+ virtualize?: boolean | ScrollAreaVirtualizeOptions;
46
+ class?: any;
47
+ b24ui?: ScrollArea['slots'];
48
+ }
49
+ export interface ScrollAreaSlots<T extends ScrollAreaItem = ScrollAreaItem> {
50
+ default(props: {
51
+ item: T;
52
+ index: number;
53
+ virtualItem?: VirtualItem;
54
+ } | Record<string, never>): any;
55
+ }
56
+ export interface ScrollAreaEmits {
57
+ /**
58
+ * Emitted when scroll state changes
59
+ * @param isScrolling - Whether the list is currently being scrolled
60
+ */
61
+ scroll: [isScrolling: boolean];
62
+ }
63
+ declare const __VLS_export: <T extends ScrollAreaItem>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
64
+ props: __VLS_PrettifyLocal<ScrollAreaProps<T> & __VLS_EmitsToProps<__VLS_NormalizeEmits<(evt: "scroll", isScrolling: boolean) => void>>> & import("vue").PublicProps & (typeof globalThis extends {
65
+ __VLS_PROPS_FALLBACK: infer P;
66
+ } ? P : {});
67
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
68
+ readonly $el: HTMLElement;
69
+ virtualizer: import("vue").Ref<import("@tanstack/vue-virtual").Virtualizer<Element, Element>, import("@tanstack/vue-virtual").Virtualizer<Element, Element>> | undefined;
70
+ }>) => void;
71
+ attrs: any;
72
+ slots: ScrollAreaSlots<T>;
73
+ emit: (evt: "scroll", isScrolling: boolean) => void;
74
+ }>) => import("vue").VNode & {
75
+ __ctx?: Awaited<typeof __VLS_setup>;
76
+ };
77
+ declare const _default: typeof __VLS_export;
78
+ export default _default;
79
+ type __VLS_PrettifyLocal<T> = {
80
+ [K in keyof T as K]: T[K];
81
+ } & {};
@@ -0,0 +1,187 @@
1
+ <script>
2
+ import theme from "#build/b24ui/scroll-area";
3
+ </script>
4
+
5
+ <script setup>
6
+ import { computed, toRef, useTemplateRef, watch } from "vue";
7
+ import { Primitive } from "reka-ui";
8
+ import { defu } from "defu";
9
+ import { useVirtualizer } from "@tanstack/vue-virtual";
10
+ import { useAppConfig } from "#imports";
11
+ import { tv } from "../utils/tv";
12
+ import { useLocale } from "../composables/useLocale";
13
+ const props = defineProps({
14
+ as: { type: null, required: false },
15
+ orientation: { type: null, required: false, default: "vertical" },
16
+ items: { type: Array, required: false },
17
+ virtualize: { type: [Boolean, Object], required: false, default: false },
18
+ class: { type: null, required: false },
19
+ b24ui: { type: null, required: false }
20
+ });
21
+ defineSlots();
22
+ const emits = defineEmits(["scroll"]);
23
+ const { dir } = useLocale();
24
+ const appConfig = useAppConfig();
25
+ const b24ui = computed(() => tv({ extend: tv(theme), ...appConfig.b24ui?.scrollArea || {} })({
26
+ orientation: props.orientation
27
+ }));
28
+ const rootRef = useTemplateRef("rootRef");
29
+ const isRtl = computed(() => dir.value === "rtl");
30
+ const isHorizontal = computed(() => props.orientation === "horizontal");
31
+ const isVertical = computed(() => !isHorizontal.value);
32
+ const virtualizerProps = toRef(() => {
33
+ const options = typeof props.virtualize === "boolean" ? {} : props.virtualize;
34
+ return defu(options, {
35
+ estimateSize: 100,
36
+ overscan: 12,
37
+ gap: 0,
38
+ paddingStart: 0,
39
+ paddingEnd: 0,
40
+ scrollMargin: 0
41
+ });
42
+ });
43
+ const lanes = computed(() => {
44
+ const value = virtualizerProps.value.lanes;
45
+ return typeof value === "number" ? value : void 0;
46
+ });
47
+ const virtualizer = !!props.virtualize && useVirtualizer({
48
+ ...virtualizerProps.value,
49
+ get overscan() {
50
+ return virtualizerProps.value.overscan;
51
+ },
52
+ get gap() {
53
+ return virtualizerProps.value.gap;
54
+ },
55
+ get paddingStart() {
56
+ return virtualizerProps.value.paddingStart;
57
+ },
58
+ get paddingEnd() {
59
+ return virtualizerProps.value.paddingEnd;
60
+ },
61
+ get scrollMargin() {
62
+ return virtualizerProps.value.scrollMargin;
63
+ },
64
+ get lanes() {
65
+ return lanes.value;
66
+ },
67
+ get isRtl() {
68
+ return isRtl.value;
69
+ },
70
+ get count() {
71
+ return props.items?.length || 0;
72
+ },
73
+ getScrollElement: () => rootRef.value?.$el,
74
+ get horizontal() {
75
+ return isHorizontal.value;
76
+ },
77
+ estimateSize: (index) => {
78
+ const estimate = virtualizerProps.value.estimateSize;
79
+ return typeof estimate === "function" ? estimate(index) : estimate;
80
+ }
81
+ });
82
+ const virtualItems = computed(() => virtualizer ? virtualizer.value.getVirtualItems() : []);
83
+ const totalSize = computed(() => virtualizer ? virtualizer.value.getTotalSize() : 0);
84
+ const virtualViewportStyle = computed(() => ({
85
+ position: "relative",
86
+ inlineSize: isHorizontal.value ? `${totalSize.value}px` : "100%",
87
+ blockSize: isVertical.value ? `${totalSize.value}px` : "100%"
88
+ }));
89
+ function getVirtualItemStyle(virtualItem) {
90
+ const hasLanes = lanes.value !== void 0 && lanes.value > 1;
91
+ const lane = virtualItem.lane;
92
+ const gap = virtualizerProps.value.gap ?? 0;
93
+ const laneSize = hasLanes ? `calc((100% - ${(lanes.value - 1) * gap}px) / ${lanes.value})` : "100%";
94
+ const lanePosition = hasLanes && lane !== void 0 ? `calc(${lane} * ((100% - ${(lanes.value - 1) * gap}px) / ${lanes.value} + ${gap}px))` : 0;
95
+ return {
96
+ position: "absolute",
97
+ insetBlockStart: isHorizontal.value && hasLanes ? lanePosition : 0,
98
+ insetInlineStart: isVertical.value && hasLanes ? lanePosition : 0,
99
+ blockSize: isHorizontal.value ? hasLanes ? laneSize : "100%" : void 0,
100
+ inlineSize: isVertical.value ? hasLanes ? laneSize : "100%" : void 0,
101
+ transform: isHorizontal.value ? `translateX(${isRtl.value ? -virtualItem.start : virtualItem.start}px)` : `translateY(${virtualItem.start}px)`
102
+ };
103
+ }
104
+ watch(lanes, () => {
105
+ if (virtualizer) {
106
+ virtualizer.value.measure();
107
+ }
108
+ }, { flush: "sync" });
109
+ function measureElement(el) {
110
+ if (el && virtualizer) {
111
+ const element = el instanceof Element ? el : el.$el;
112
+ virtualizer.value.measureElement(element);
113
+ }
114
+ }
115
+ watch(
116
+ () => virtualizer ? virtualizer.value.isScrolling : false,
117
+ (isScrolling) => emits("scroll", isScrolling)
118
+ );
119
+ function getItemKey(item, index) {
120
+ if (virtualizerProps.value.getItemKey) {
121
+ return virtualizerProps.value.getItemKey(index);
122
+ }
123
+ if (item && typeof item === "object" && "id" in item) {
124
+ return item.id;
125
+ }
126
+ return index;
127
+ }
128
+ defineExpose({
129
+ get $el() {
130
+ return rootRef.value?.$el;
131
+ },
132
+ virtualizer: virtualizer || void 0
133
+ });
134
+ </script>
135
+
136
+ <template>
137
+ <Primitive
138
+ ref="rootRef"
139
+ :as="as"
140
+ data-slot="root"
141
+ :data-orientation="orientation"
142
+ :class="b24ui.root({ class: [props.b24ui?.root, props.class] })"
143
+ >
144
+ <template v-if="virtualizer">
145
+ <div
146
+ data-slot="viewport"
147
+ :class="b24ui.viewport({ class: props.b24ui?.viewport })"
148
+ :style="virtualViewportStyle"
149
+ >
150
+ <div
151
+ v-for="virtualItem in virtualItems"
152
+ :key="String(virtualItem.key)"
153
+ :ref="measureElement"
154
+ :data-index="virtualItem.index"
155
+ data-slot="item"
156
+ :class="b24ui.item({ class: props.b24ui?.item })"
157
+ :style="getVirtualItemStyle(virtualItem)"
158
+ >
159
+ <slot
160
+ :item="items?.[virtualItem.index]"
161
+ :index="virtualItem.index"
162
+ :virtual-item="virtualItem"
163
+ />
164
+ </div>
165
+ </div>
166
+ </template>
167
+
168
+ <template v-else>
169
+ <div data-slot="viewport" :class="b24ui.viewport({ class: props.b24ui?.viewport })">
170
+ <template v-if="items?.length">
171
+ <div
172
+ v-for="(item, index) in items"
173
+ :key="getItemKey(item, index)"
174
+ data-slot="item"
175
+ :class="b24ui.item({ class: props.b24ui?.item })"
176
+ >
177
+ <slot :item="item" :index="index" />
178
+ </div>
179
+ </template>
180
+
181
+ <template v-else>
182
+ <slot />
183
+ </template>
184
+ </div>
185
+ </template>
186
+ </Primitive>
187
+ </template>
@@ -0,0 +1,81 @@
1
+ import type { AppConfig } from '@nuxt/schema';
2
+ import type { VirtualItem, VirtualizerOptions } from '@tanstack/vue-virtual';
3
+ import theme from '#build/b24ui/scroll-area';
4
+ import type { ComponentConfig } from '../types/tv';
5
+ type ScrollArea = ComponentConfig<typeof theme, AppConfig, 'scrollArea'>;
6
+ export interface ScrollAreaVirtualizeOptions extends Partial<Omit<VirtualizerOptions<Element, Element>, 'count' | 'getScrollElement' | 'horizontal' | 'isRtl' | 'estimateSize' | 'lanes' | 'enabled'>> {
7
+ /**
8
+ * Estimated size (in px) of each item along the scroll axis. Can be a number or a function.
9
+ * @defaultValue 100
10
+ */
11
+ estimateSize?: number | ((index: number) => number);
12
+ /**
13
+ * Number of lanes for multi-column/row layouts.
14
+ * For responsive lane counts, use a computed property with viewport/container size:
15
+ * @example
16
+ * ```ts
17
+ * const { width } = useWindowSize()
18
+ * const lanes = computed(() => Math.floor(width.value / 300))
19
+ * ```
20
+ * @defaultValue undefined
21
+ */
22
+ lanes?: number;
23
+ }
24
+ export type ScrollAreaItem = any;
25
+ export interface ScrollAreaProps<T extends ScrollAreaItem = ScrollAreaItem> {
26
+ /**
27
+ * The element or component this component should render as.
28
+ * @defaultValue 'div'
29
+ */
30
+ as?: any;
31
+ /**
32
+ * The scroll direction.
33
+ * @defaultValue 'vertical'
34
+ */
35
+ orientation?: ScrollArea['variants']['orientation'];
36
+ /**
37
+ * Array of items to render.
38
+ */
39
+ items?: T[];
40
+ /**
41
+ * Enable virtualization for large lists.
42
+ * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
43
+ * @defaultValue false
44
+ */
45
+ virtualize?: boolean | ScrollAreaVirtualizeOptions;
46
+ class?: any;
47
+ b24ui?: ScrollArea['slots'];
48
+ }
49
+ export interface ScrollAreaSlots<T extends ScrollAreaItem = ScrollAreaItem> {
50
+ default(props: {
51
+ item: T;
52
+ index: number;
53
+ virtualItem?: VirtualItem;
54
+ } | Record<string, never>): any;
55
+ }
56
+ export interface ScrollAreaEmits {
57
+ /**
58
+ * Emitted when scroll state changes
59
+ * @param isScrolling - Whether the list is currently being scrolled
60
+ */
61
+ scroll: [isScrolling: boolean];
62
+ }
63
+ declare const __VLS_export: <T extends ScrollAreaItem>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
64
+ props: __VLS_PrettifyLocal<ScrollAreaProps<T> & __VLS_EmitsToProps<__VLS_NormalizeEmits<(evt: "scroll", isScrolling: boolean) => void>>> & import("vue").PublicProps & (typeof globalThis extends {
65
+ __VLS_PROPS_FALLBACK: infer P;
66
+ } ? P : {});
67
+ expose: (exposed: import("vue").ShallowUnwrapRef<{
68
+ readonly $el: HTMLElement;
69
+ virtualizer: import("vue").Ref<import("@tanstack/vue-virtual").Virtualizer<Element, Element>, import("@tanstack/vue-virtual").Virtualizer<Element, Element>> | undefined;
70
+ }>) => void;
71
+ attrs: any;
72
+ slots: ScrollAreaSlots<T>;
73
+ emit: (evt: "scroll", isScrolling: boolean) => void;
74
+ }>) => import("vue").VNode & {
75
+ __ctx?: Awaited<typeof __VLS_setup>;
76
+ };
77
+ declare const _default: typeof __VLS_export;
78
+ export default _default;
79
+ type __VLS_PrettifyLocal<T> = {
80
+ [K in keyof T as K]: T[K];
81
+ } & {};
@@ -54,6 +54,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
54
54
  /**
55
55
  * Enable virtualization for large datasets.
56
56
  * Note: when enabled, the divider between rows and sticky properties are not supported.
57
+ * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
57
58
  * @defaultValue false
58
59
  */
59
60
  virtualize?: boolean | (Partial<Omit<VirtualizerOptions<Element, Element>, 'getScrollElement' | 'count' | 'estimateSize' | 'overscan'>> & {
@@ -54,6 +54,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
54
54
  /**
55
55
  * Enable virtualization for large datasets.
56
56
  * Note: when enabled, the divider between rows and sticky properties are not supported.
57
+ * @see https://tanstack.com/virtual/latest/docs/api/virtualizer#options
57
58
  * @defaultValue false
58
59
  */
59
60
  virtualize?: boolean | (Partial<Omit<VirtualizerOptions<Element, Element>, 'getScrollElement' | 'count' | 'estimateSize' | 'overscan'>> & {
@@ -63,6 +63,7 @@ export * from '../components/Popover.vue';
63
63
  export * from '../components/Progress.vue';
64
64
  export * from '../components/RadioGroup.vue';
65
65
  export * from '../components/Range.vue';
66
+ export * from '../components/ScrollArea.vue';
66
67
  export * from '../components/Select.vue';
67
68
  export * from '../components/SelectMenu.vue';
68
69
  export * from '../components/Separator.vue';
@@ -63,6 +63,7 @@ export * from "../components/Popover.vue";
63
63
  export * from "../components/Progress.vue";
64
64
  export * from "../components/RadioGroup.vue";
65
65
  export * from "../components/Range.vue";
66
+ export * from "../components/ScrollArea.vue";
66
67
  export * from "../components/Select.vue";
67
68
  export * from "../components/SelectMenu.vue";
68
69
  export * from "../components/Separator.vue";
@@ -1,5 +1,5 @@
1
1
  import type { InertiaLinkProps } from '@inertiajs/vue3';
2
- import type { ButtonHTMLAttributes, AnchorHTMLAttributes } from '../../types/html';
2
+ import type { ButtonHTMLAttributes, AnchorHTMLAttributes } from '../../../types/html';
3
3
  export interface LinkProps extends Partial<Omit<InertiaLinkProps, 'href' | 'onClick'>>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled'>, /** @vue-ignore */ Omit<AnchorHTMLAttributes, 'href' | 'target' | 'rel' | 'type'> {
4
4
  /**
5
5
  * The element or component this component should render as when not a link.
@@ -10,9 +10,9 @@ import { reactiveOmit } from "@vueuse/core";
10
10
  import { usePage } from "@inertiajs/vue3";
11
11
  import { hasProtocol } from "ufo";
12
12
  import { useAppConfig } from "#imports";
13
- import { tv } from "../../utils/tv";
14
- import { mergeClasses } from "../../utils";
15
- import B24LinkBase from "../../components/LinkBase.vue";
13
+ import { tv } from "../../../utils/tv";
14
+ import { mergeClasses } from "../../../utils";
15
+ import B24LinkBase from "./LinkBase.vue";
16
16
  defineOptions({ inheritAttrs: false });
17
17
  const props = defineProps({
18
18
  as: { type: null, required: false, default: "button" },
@@ -1,5 +1,5 @@
1
1
  import type { InertiaLinkProps } from '@inertiajs/vue3';
2
- import type { ButtonHTMLAttributes, AnchorHTMLAttributes } from '../../types/html';
2
+ import type { ButtonHTMLAttributes, AnchorHTMLAttributes } from '../../../types/html';
3
3
  export interface LinkProps extends Partial<Omit<InertiaLinkProps, 'href' | 'onClick'>>, /** @vue-ignore */ Omit<ButtonHTMLAttributes, 'type' | 'disabled'>, /** @vue-ignore */ Omit<AnchorHTMLAttributes, 'href' | 'target' | 'rel' | 'type'> {
4
4
  /**
5
5
  * The element or component this component should render as when not a link.
@@ -1,4 +1,4 @@
1
- import type { LinkProps } from '../../types';
1
+ import type { LinkProps } from '../../../types';
2
2
  export interface LinkBaseProps {
3
3
  as?: string;
4
4
  type?: string;
@@ -1,4 +1,4 @@
1
- import type { LinkProps } from '../../types';
1
+ import type { LinkProps } from '../../../types';
2
2
  export interface LinkBaseProps {
3
3
  as?: string;
4
4
  type?: string;
@@ -0,0 +1,73 @@
1
+ import type { ButtonHTMLAttributes } from 'vue';
2
+ interface BaseLinkProps {
3
+ /**
4
+ * Route Location the link should navigate to when clicked on.
5
+ */
6
+ to?: string;
7
+ /**
8
+ * An alias for `to`. If used with `to`, `href` will be ignored
9
+ */
10
+ href?: string;
11
+ /**
12
+ * Forces the link to be considered as external (true) or internal (false). This is helpful to handle edge-cases
13
+ */
14
+ external?: boolean;
15
+ /**
16
+ * Where to display the linked URL, as the name for a browsing context.
17
+ */
18
+ target?: '_blank' | '_parent' | '_self' | '_top' | (string & {}) | null;
19
+ /**
20
+ * A rel attribute value to apply on the link. Defaults to "noopener noreferrer" for external links.
21
+ */
22
+ rel?: 'noopener' | 'noreferrer' | 'nofollow' | 'sponsored' | 'ugc' | (string & {}) | null;
23
+ /**
24
+ * If set to true, no rel attribute will be added to the link
25
+ */
26
+ noRel?: boolean;
27
+ }
28
+ export interface LinkProps extends BaseLinkProps {
29
+ /**
30
+ * The element or component this component should render as when not a link.
31
+ * @defaultValue 'button'
32
+ */
33
+ as?: any;
34
+ /**
35
+ * The type of the button when not a link.
36
+ * @defaultValue 'button'
37
+ */
38
+ type?: ButtonHTMLAttributes['type'];
39
+ disabled?: boolean;
40
+ /** Force the link to be active independent of the current route. */
41
+ active?: boolean;
42
+ /** Will only be active if the current route is an exact match. */
43
+ exact?: boolean;
44
+ /** Allows controlling how the current route query sets the link as active. */
45
+ exactQuery?: boolean | 'partial';
46
+ /** Will only be active if the current route hash is an exact match. */
47
+ exactHash?: boolean;
48
+ /** The class to apply when the link is inactive. */
49
+ inactiveClass?: string;
50
+ /** The class to apply when the link is active. */
51
+ activeClass?: string;
52
+ /** The value of the `aria-current` attribute when the link is active. */
53
+ ariaCurrentValue?: string;
54
+ custom?: boolean;
55
+ /** When `true`, uses special underlined styling. */
56
+ isAction?: boolean;
57
+ /** When `true`, only styles from `class`, `activeClass`, and `inactiveClass` will be applied. */
58
+ raw?: boolean;
59
+ class?: any;
60
+ }
61
+ export interface LinkSlots {
62
+ default(props: {
63
+ active: boolean;
64
+ }): any;
65
+ }
66
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<LinkProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<LinkProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, LinkSlots>;
67
+ declare const _default: typeof __VLS_export;
68
+ export default _default;
69
+ type __VLS_WithSlots<T, S> = T & {
70
+ new (): {
71
+ $slots: S;
72
+ };
73
+ };
@@ -0,0 +1,128 @@
1
+ <script>
2
+ import theme from "#build/b24ui/link";
3
+ </script>
4
+
5
+ <script setup>
6
+ import { computed } from "vue";
7
+ import { defu } from "defu";
8
+ import { hasProtocol } from "ufo";
9
+ import { useAppConfig } from "#imports";
10
+ import { mergeClasses } from "../../../utils";
11
+ import { tv } from "../../../utils/tv";
12
+ import B24LinkBase from "../../../components/LinkBase.vue";
13
+ defineOptions({ inheritAttrs: false });
14
+ const props = defineProps({
15
+ as: { type: null, required: false, default: "button" },
16
+ type: { type: null, required: false, default: "button" },
17
+ disabled: { type: Boolean, required: false },
18
+ active: { type: Boolean, required: false, default: void 0 },
19
+ exact: { type: Boolean, required: false },
20
+ exactQuery: { type: [Boolean, String], required: false },
21
+ exactHash: { type: Boolean, required: false },
22
+ inactiveClass: { type: String, required: false },
23
+ activeClass: { type: String, required: false },
24
+ ariaCurrentValue: { type: String, required: false, default: "page" },
25
+ custom: { type: Boolean, required: false },
26
+ isAction: { type: Boolean, required: false, default: false },
27
+ raw: { type: Boolean, required: false },
28
+ class: { type: null, required: false },
29
+ to: { type: String, required: false },
30
+ href: { type: String, required: false },
31
+ external: { type: Boolean, required: false },
32
+ target: { type: [String, Object, null], required: false },
33
+ rel: { type: [String, Object, null], required: false },
34
+ noRel: { type: Boolean, required: false }
35
+ });
36
+ defineSlots();
37
+ const appConfig = useAppConfig();
38
+ const b24ui = computed(() => tv({
39
+ extend: tv(theme),
40
+ ...defu({
41
+ variants: {
42
+ active: {
43
+ true: mergeClasses(appConfig.b24ui?.link?.variants?.active?.true, props.activeClass),
44
+ false: mergeClasses(appConfig.b24ui?.link?.variants?.active?.false, props.inactiveClass)
45
+ }
46
+ }
47
+ }, appConfig.b24ui?.link || {})
48
+ }));
49
+ const href = computed(() => props.to ?? props.href);
50
+ const isExternal = computed(() => {
51
+ if (props.target === "_blank") {
52
+ return true;
53
+ }
54
+ if (props.external) {
55
+ return true;
56
+ }
57
+ if (!href.value) {
58
+ return false;
59
+ }
60
+ return hasProtocol(href.value, { acceptRelative: true });
61
+ });
62
+ const isLinkActive = computed(() => {
63
+ if (props.active !== void 0) {
64
+ return props.active;
65
+ }
66
+ return false;
67
+ });
68
+ const linkClass = computed(() => {
69
+ const active = isLinkActive.value;
70
+ if (props.raw) {
71
+ return [props.class, active ? props.activeClass : props.inactiveClass];
72
+ }
73
+ return b24ui.value({
74
+ class: props.class,
75
+ active,
76
+ disabled: props.disabled,
77
+ isAction: Boolean(props.isAction)
78
+ });
79
+ });
80
+ const linkRel = computed(() => {
81
+ if (props.noRel) {
82
+ return null;
83
+ }
84
+ if (props.rel) {
85
+ return props.rel;
86
+ }
87
+ if (isExternal.value) {
88
+ return "noopener noreferrer";
89
+ }
90
+ return null;
91
+ });
92
+ </script>
93
+
94
+ <template>
95
+ <template v-if="custom">
96
+ <slot
97
+ v-bind="{
98
+ ...$attrs,
99
+ as,
100
+ type,
101
+ disabled,
102
+ href,
103
+ navigate: void 0,
104
+ rel: linkRel,
105
+ target: target || (isExternal ? '_blank' : void 0),
106
+ isExternal,
107
+ active: isLinkActive
108
+ }"
109
+ />
110
+ </template>
111
+ <B24LinkBase
112
+ v-else
113
+ v-bind="{
114
+ ...$attrs,
115
+ as,
116
+ type,
117
+ disabled,
118
+ href,
119
+ navigate: void 0,
120
+ rel: linkRel,
121
+ target: target || (isExternal ? '_blank' : void 0),
122
+ isExternal
123
+ }"
124
+ :class="linkClass"
125
+ >
126
+ <slot :active="isLinkActive" />
127
+ </B24LinkBase>
128
+ </template>