Skip to content

Commit

Permalink
feat(NcChip): Add NcChip component for a chip-linke element
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>

[skip ci]
  • Loading branch information
susnux authored and backportbot[bot] committed Jun 11, 2024
1 parent bf1c7fe commit 2e5c909
Show file tree
Hide file tree
Showing 2 changed files with 275 additions and 0 deletions.
270 changes: 270 additions & 0 deletions src/components/NcChip/NcChip.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<docs>
### Basic usage

```vue
<template>
<div style="display: flex; gap: 8px; flex-wrap: wrap;">
<NcChip text="Notes.txt" :icon-path="mdiFile" />
<NcChip text="Color" type="tertiary" :icon-path="mdiPalette" />
<NcChip text="Current time" type="primary" :icon-path="mdiClock" no-close />
</div>
</template>
<script>
import { mdiClock, mdiFile, mdiPalette } from '@mdi/js'
export default {
setup() {
return {
mdiClock,
mdiFile,
mdiPalette,
}
}
}
</script>
```

### Advanced usage

It is also possible to use custom components for the icon by using the `icon` slot.
In this example we are using the `NcAvatar` component to render the users avatar as the icon.

*Hint: If you use round icons like avatars you should set their size to `24px` (or use CSS variable `--chip-size`) to make then fully fill and align with the the chip*

Also it is possible to pass custom actions.

```vue
<template>
<NcChip>
<!-- The icon slot allow to use custom components as the chip icon -->
<template #icon>
<NcAvatar :size="24" user="jdoe" display-name="J. Doe" />
</template>
<!-- The actions slot allows to add custom actions -->
<template #actions>
<NcActionButton>
<template #icon>
<ContactsIcon :size="20" />
</template>
Add to contacts
</NcActionButton>
</template>
<!-- The default slot can be used for add content, just like the `text` prop -->
J. Doe
</NcChip>
</template>
<script>
import ContactsIcon from 'vue-material-design-icons/Contacts.vue'
export default {
components: {
ContactsIcon,
},
}
</script>
```
</docs>

<template>
<div class="nc-chip" :class="{ [`nc-chip--${type}`]: true, 'nc-chip--no-actions': !hasActions }">
<span class="nc-chip__icon">
<!-- @slot The icon slot can be used to set the chip icon. Make sure that the icon is not exceeding a height of `24px`. For round icons a exact size of `24px` is recommended. -->
<slot name="icon">
<!-- The default icon wrapper uses a size of 18px to ensure the icon is not clipped by the round chip style -->
<NcIconSvgWrapper v-if="iconPath || iconSvg"
inline
:path="iconPath"
:svg="iconPath ? undefined : iconSvg"
:size="18" />
</slot>
</span>
<span class="nc-chip__text">
<!-- @slot The default slot can be used to set the text that is shown -->
<slot>{{ text }}</slot>
</span>
<NcActions v-if="hasActions"
class="nc-chip__actions"
:force-menu="!canClose"
type="tertiary-no-background">
<NcActionButton v-if="canClose"
close-after-click
@click="onClose">
<template #icon>
<NcIconSvgWrapper :path="mdiClose" :size="20" />
</template>
{{ ariaLabelClose }}
</NcActionButton>
<!-- @slot The actions slot can be used to add custom actions to the chips actions -->
<slot name="actions" />
</NcActions>
</div>
</template>

<script>
import { mdiClose } from '@mdi/js'
import { defineComponent } from 'vue'
import { t } from '../../l10n.js'
import NcActions from '../NcActions/NcActions.vue'
import NcActionButton from '../NcActionButton/NcActionButton.vue'
import NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'
export default defineComponent({
name: 'NcChip',
components: {
NcActions,
NcActionButton,
NcIconSvgWrapper,
},
props: {
/**
* aria label to set on the close button
* @default 'Close'
*/
ariaLabelClose: {
type: String,
default: t('Close'),
},
/**
* Main text of the chip
*/
text: {
type: String,
default: '',
},
/**
* Chip style
* This sets the background style of the chip, similar to NcButton's `type`
*/
type: {
type: String,
default: 'secondary',
validator: (value) => ['primary', 'secondary', 'tertiary'].includes(value),
},
/**
* SVG path of the icon to use.
* For example icon paths from `@mdi/js` can be used.
*/
iconPath: {
type: String,
default: null,
},
/**
* Inline SVG to use as the icon
*/
iconSvg: {
type: String,
default: null,
},
/**
* Set to true to prevent the close button to be shown
*/
noClose: {
type: Boolean,
default: false,
},
},
emits: ['close'],
setup() {
return {
mdiClose,
}
},
computed: {
canClose() {
return !this.noClose
},
hasActions() {
return this.canClose || (this.$slots?.actions !== undefined) || (this.$scopedSlots.actions !== undefined)
},
},
methods: {
t,
onClose() {
/**
* Emitted when the close button is clicked
*/
this.$emit('close')
},
},
})
</script>
<style scoped lang="scss">
.nc-chip {
--chip-size: 24px;
--chip-radius: calc(var(--chip-size) / 2);
// Setup size of wrapper
height: var(--chip-size);
max-width: fit-content;
display: flex;
flex-direction: row;
align-items: center;
gap: var(--default-grid-baseline);
border-radius: var(--chip-radius);
background-color: var(--color-background-hover);
&--primary {
background-color: var(--color-primary-element);
color: var(--color-primary-text);
}
&--secondary {
background-color: var(--color-primary-element-light);
color: var(--color-primary-element-light-text);
}
&--no-actions &__text {
// If there are no actions we need to add some padding to ensure the text is not cut-off
padding-inline-end: calc(1.5 * var(--default-grid-baseline));
}
&__text {
// Allow to grow the text
// this is only used if an app forces a width of the chip
flex: 1 auto;
overflow: hidden;
text-overflow: ellipsis;
}
&__icon {
// Do neither grow nor shrink, size is fixed
flex: 0 0 var(--chip-size);
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
// Force size
overflow: hidden;
height: var(--chip-size);
width: var(--chip-size);
}
&__actions {
// Do neither grow nor shrink, size is fixed
flex: 0 0 var(--chip-size);
// Adjust action size to match chip size
--default-clickable-area: var(--chip-size);
--border-radius-element: var(--chip-radius);
}
}
</style>
5 changes: 5 additions & 0 deletions src/components/NcChip/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
export { default } from './NcChip.vue'

0 comments on commit 2e5c909

Please sign in to comment.