Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[next] feat: Add NcChip component #5689

Merged
merged 4 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions src/components/NcButton/NcButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -718,8 +718,8 @@ export default defineComponent({
padding: 0;
font-size: var(--default-font-size);
font-weight: bold;
min-height: $clickable-area;
min-width: $clickable-area;
min-height: var(--default-clickable-area);
min-width: var(--default-clickable-area);
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -730,7 +730,7 @@ export default defineComponent({
span {
cursor: pointer;
}
border-radius: var(--border-radius-element, math.div($clickable-area, 2));
border-radius: var(--border-radius-element, calc(var(--default-clickable-area) / 2));
transition-property: color, border-color, background-color;
transition-duration: 0.1s;
transition-timing-function: linear;
Expand Down Expand Up @@ -785,10 +785,10 @@ export default defineComponent({
}

&__icon {
height: $clickable-area;
width: $clickable-area;
min-height: $clickable-area;
min-width: $clickable-area;
height: var(--default-clickable-area);
width: var(--default-clickable-area);
min-height: var(--default-clickable-area);
min-width: var(--default-clickable-area);
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -805,7 +805,8 @@ export default defineComponent({

// Icon-only button
&--icon-only {
width: $clickable-area !important;
line-height: 1;
width: var(--default-clickable-area) !important;
}

// Text-only button
Expand Down
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 lang="ts">
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: string) => ['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
},
},

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.ts
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'
4 changes: 2 additions & 2 deletions src/components/NcIconSvgWrapper/NcIconSvgWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ export default {
display: flex;
justify-content: center;
align-items: center;
min-width: 44px;
min-height: 44px;
min-width: var(--default-clickable-area);
min-height: var(--default-clickable-area);
opacity: 1;

&--inline {
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export { default as NcBreadcrumb } from './NcBreadcrumb/index.js'
export { default as NcBreadcrumbs } from './NcBreadcrumbs/index.js'
export { default as NcButton } from './NcButton/index'
export { default as NcCheckboxRadioSwitch } from './NcCheckboxRadioSwitch/index.js'
export { default as NcChip } from './NcChip/index'
export { default as NcColorPicker } from './NcColorPicker/index.js'
export { default as NcContent } from './NcContent/index.js'
export { default as NcCounterBubble } from './NcCounterBubble/index.js'
Expand Down
3 changes: 3 additions & 0 deletions styleguide/global.requires.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ function chunkify(t) {
return tz
}

// Global variables
window._oc_webroot = ''

window.OC = {
debug: true,
getCurrentUser() {
Expand Down
Loading