Skip to content

Commit

Permalink
Merge pull request #342 from vuelessjs/VL-29_UBreadcrumbs-new-compone…
Browse files Browse the repository at this point in the history
…nt_Vitalii-Dudnik

VL-29_UBreadcrumbs-new-component_Vitalii-Dudnik
  • Loading branch information
KinduD21 authored Jan 21, 2025
2 parents 6e29b19 + ca439c6 commit 58791fa
Show file tree
Hide file tree
Showing 12 changed files with 453 additions and 3 deletions.
10 changes: 10 additions & 0 deletions .storybook/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ body {
.light .sbdocs .sbdocs-content > h2,
.light .sbdocs .sbdocs-content > h3,
.light .sbdocs .sbdocs-content > .sb-anchor > h3,
.light .sbdocs .sbdocs-content > .sb-anchor > p,
.light .sbdocs .sbdocs-content > p,
.light .sbdocs .sbdocs-content > table th,
.light .sbdocs .sbdocs-content > table td {
Expand All @@ -25,6 +26,7 @@ body {
.dark .sbdocs .sbdocs-content > h2,
.dark .sbdocs .sbdocs-content > h3,
.dark .sbdocs .sbdocs-content > .sb-anchor > h3,
.dark .sbdocs .sbdocs-content > .sb-anchor > p,
.dark .sbdocs .sbdocs-content > p,
.dark .sbdocs .sbdocs-content > table th,
.dark .sbdocs .sbdocs-content > table td {
Expand Down Expand Up @@ -163,6 +165,14 @@ body {
@apply mt-2;
}

.dark .sb-anchor > p > a {
@apply text-green-400;
}

.light .sb-anchor > p > a {
@apply text-green-600;
}

.sb-bar,
.docs-story {
@apply bg-white;
Expand Down
1 change: 1 addition & 0 deletions src/assets/icons/vueless/arrow_right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export const COMPONENTS = {
UTabs: "ui.navigation-tabs",
UProgress: "ui.navigation-progress",
UPagination: "ui.navigation-pagination",
UBreadcrumbs: "ui.navigation-breadcrumbs",

/* Loaders and Skeletons */
ULoader: "ui.loader",
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import UPaginationConfig from "./ui.navigation-pagination/config.ts";
import UProgressConfig from "./ui.navigation-progress/config.ts";
import UTabConfig from "./ui.navigation-tab/config.ts";
import UTabsConfig from "./ui.navigation-tabs/config.ts";
import UBreadcrumbsConfig from "./ui.navigation-breadcrumbs/config.ts";
import UAvatarConfig from "./ui.image-avatar/config.ts";
import UIconConfig from "./ui.image-icon/config.ts";
import UCheckboxConfig from "./ui.form-checkbox/config.ts";
Expand Down Expand Up @@ -226,6 +227,7 @@ export interface Components {
UProgress: Partial<typeof UProgressConfig>;
UTab: Partial<typeof UTabConfig>;
UTabs: Partial<typeof UTabsConfig>;
UBreadcrumbs: Partial<typeof UBreadcrumbsConfig>;
UAvatar: Partial<typeof UAvatarConfig>;
UIcon: Partial<typeof UIconConfig>;
UCheckbox: Partial<typeof UCheckboxConfig>;
Expand Down
13 changes: 10 additions & 3 deletions src/ui.button-link/ULink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getDefaults } from "../utils/ui.ts";
import defaultConfig from "./config.ts";
import { COMPONENT_NAME } from "./constants.ts";
import type { Props, Config } from "./types.ts";
import type { Props, Config, ULinkSlotProps } from "./types.ts";
defineOptions({ inheritAttrs: false });
Expand Down Expand Up @@ -101,6 +101,7 @@ const { getDataTest, linkAttrs } = useUI<Config>(defaultConfig, mutatedProps);
<template>
<router-link
v-if="isPresentRoute"
v-slot="slotProps: ULinkSlotProps"
:to="safeTo"
:custom="custom"
:replace="replace"
Expand All @@ -118,8 +119,14 @@ const { getDataTest, linkAttrs } = useUI<Config>(defaultConfig, mutatedProps);
@keydown="onKeydown"
@mouseover="onMouseover"
>
<!-- @slot Use it replace the label. -->
<slot>{{ label }}</slot>
<!--
@slot Use it replace the label.
@binding {boolean} is-active
@binding {boolean} is-exact-active
-->
<slot :is-active="slotProps.isActive" :is-exact-active="slotProps.isExactActive">
{{ label }}
</slot>
</router-link>

<a
Expand Down
5 changes: 5 additions & 0 deletions src/ui.button-link/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import type { RouteLocationRaw } from "vue-router";

export type Config = typeof defaultConfig;

export interface ULinkSlotProps {
isActive: boolean;
isExactActive: boolean;
}

export interface Props {
/**
* Button label.
Expand Down
122 changes: 122 additions & 0 deletions src/ui.navigation-breadcrumbs/UBreadcrumbs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<script setup lang="ts">
import { computed } from "vue";
import useUI from "../composables/useUI.ts";
import { getDefaults } from "../utils/ui.ts";
import defaultConfig from "./config.ts";
import { COMPONENT_NAME } from "./constants.ts";
import ULink from "../ui.button-link/ULink.vue";
import UIcon from "../ui.image-icon/UIcon.vue";
import type { Props, Config, UBreadcrumb } from "./types.ts";
import type { ULinkSlotProps } from "../ui.button-link/types.ts";
defineOptions({ inheritAttrs: false });
const props = withDefaults(defineProps<Props>(), {
...getDefaults<Props, Config>(defaultConfig, COMPONENT_NAME),
links: () => [],
});
const emit = defineEmits([
/**
* Triggers on a link click.
* @property {object} link
*/
"clickLink",
]);
const getIconColor = computed(() => {
return (link: UBreadcrumb) => (link.disabled || (!link.to && !link.href) ? "gray" : props.color);
});
function onClickLink(link: UBreadcrumb) {
emit("clickLink", link);
}
/**
* Get element / nested component attributes for each config token ✨
* Applies: `class`, `config`, redefined default `props` and dev `vl-...` attributes.
*/
const { config, breadcrumbsAttrs, breadcrumbLinkAttrs, breadcrumbIconAttrs, dividerIconAttrs } =
useUI<Config>(defaultConfig);
</script>

<template>
<div v-bind="breadcrumbsAttrs">
<template v-for="(link, index) in links" :key="index">
<!--
@slot Use it to add something instead of a link icon.
@binding {string} icon-name
@binding {number} index
-->
<slot name="icon" :icon-name="link.icon" :index="index">
<UIcon
v-if="link.icon"
:name="link.icon"
:color="getIconColor(link)"
v-bind="breadcrumbIconAttrs"
/>
</slot>

<ULink
:label="link.label"
:href="link.href"
:to="link.to"
:size="size"
:color="color"
:target="link.target || target"
:custom="link.custom"
:replace="link.replace"
:active-class="link.activeClass"
:exact-active-class="link.exactActiveClass"
:aria-current-value="link.ariaCurrentValue"
:underlined="underlined"
:dashed="dashed"
:disabled="link.disabled || (!link.to && !link.href)"
:ring="false"
v-bind="breadcrumbLinkAttrs"
:data-test="dataTest"
@click="onClickLink(link)"
>
<template #default="slotProps">
<!--
@slot Use it to add something instead of a link label.
@binding {string} label
@binding {number} index
@binding {boolean} active
@binding {boolean} exact-active
-->
<slot
name="label"
:label="link.label"
:index="index"
:active="(slotProps as ULinkSlotProps).isActive"
:exact-active="(slotProps as ULinkSlotProps).isExactActive"
/>
</template>
</ULink>

<!--
@slot Use it to add something instead of the divider.
@binding {string} icon-name
@binding {number} index
-->
<slot
v-if="links.length !== index + 1"
name="divider"
:icon-name="config.defaults.dividerIcon"
:index="index"
>
<UIcon
v-if="links.length !== index + 1"
:name="config.defaults.dividerIcon"
:color="getIconColor(link)"
v-bind="dividerIconAttrs"
/>
</slot>
</template>
</div>
</template>
32 changes: 32 additions & 0 deletions src/ui.navigation-breadcrumbs/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export default /*tw*/ {
breadcrumbs: "flex items-center gap-1 py-2",
breadcrumbLink: "{ULink}",
breadcrumbIcon: {
base: "{UIcon}",
defaults: {
size: {
sm: "2xs",
md: "xs",
lg: "sm",
},
},
},
dividerIcon: {
base: "{UIcon}",
defaults: {
size: {
sm: "xs",
md: "sm",
lg: "md",
},
},
},
defaults: {
color: "grayscale",
size: "md",
underlined: undefined,
dashed: false,
target: "_self",
dividerIcon: "arrow_right",
},
};
5 changes: 5 additions & 0 deletions src/ui.navigation-breadcrumbs/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
This const is needed to prevent the issue in script setup:
`defineProps` is referencing locally declared variables. (vue/valid-define-props)
*/
export const COMPONENT_NAME = "UBreadcrumbs";
37 changes: 37 additions & 0 deletions src/ui.navigation-breadcrumbs/storybook/docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Markdown, Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
import { getSource } from "../../utils/storybook.ts";

import * as stories from "./stories.ts";
import defaultConfig from "../config.ts?raw"

<Meta of={stories} />
<Title of={stories} />
<Subtitle of={stories} />
<Description of={stories} />
<Primary of={stories} />
<Controls of={stories.Default} />
<Stories of={stories} />

## Breadcrumb Link Object Properties
Keys you may/have to provide to the component in a `link` object.

<Markdown>
{`
| Key name | Description | Type |
| ---------------------- | ----------------------------------------------------- | ----------------------- |
| label | Link label | String |
| route | Route object | Object |
| href | Link URL | String |
| disabled | Used to disable link | Boolean |
| icon | Icon name | String |
| target | Specifies where to open the linked page. | String |
| custom | Whether RouterLink should not wrap content in a tag | Boolean |
| replace | Whether to replace current history entry | Boolean |
| activeClass | Classes to apply when route is active | String |
| exactActiveClass | Classes to apply when route is exactly active | String |
| ariaCurrentValue | Value for aria-current when link is exact active | String |
`}
</Markdown>

## Default config
<Source code={getSource(defaultConfig)} language="jsx" dark />
Loading

0 comments on commit 58791fa

Please sign in to comment.