Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
STAGED=$(git diff --cached --name-only --diff-filter=ACMR)
yarn format-changed
git diff --exit-code $STAGED || (echo "Files were reformatted, please stage them and commit again" && exit 1)
1 change: 1 addition & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 100,
"proseWrap": "always"
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"scripts": {
"test": "vitest --run",
"type-check": "tsc --noEmit",
"prettier": "yarn prettier -w ./src",
"format": "prettier -w ./src",
"format-changed": "prettier $(git diff --cached --name-only --diff-filter=ACMR | sed 's| |\\ |g') --write --ignore-unknown",
"bump-and-release": "yarn test && git pull --rebase origin main && yarn run release-patch",
"release-patch": "yarn version --patch && git push && git push --tags",
"dev": "vite",
Expand All @@ -16,7 +17,8 @@
"docs:dev": "vitepress dev docs --host",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs",
"docs:gen": "node docs/scripts/propsgen.ts --trace-uncaught"
"docs:gen": "node docs/scripts/propsgen.ts --trace-uncaught",
"prepare": "husky"
},
"exports": {
".": {
Expand Down Expand Up @@ -132,6 +134,7 @@
"devDependencies": {
"@vitejs/plugin-vue": "^4.0.0",
"autoprefixer": "^10.4.13",
"husky": "^9.1.7",
"jsdom": "^27.4.0",
"lint-staged": ">=10",
"msw": "^2.7.0",
Expand Down
43 changes: 19 additions & 24 deletions src/components/Alert/Alert.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<script setup lang="ts">
import { computed } from 'vue'

import type { AlertProps } from "./types";
import type { AlertProps } from './types'

import LucideX from "~icons/lucide/x";
import LucideInfo from "~icons/lucide/info";
import LucideCircleX from "~icons/lucide/circle-x";
import LucideCheck from "~icons/lucide/circle-check";
import LucideWarning from "~icons/lucide/triangle-alert";
import LucideX from '~icons/lucide/x'
import LucideInfo from '~icons/lucide/info'
import LucideCircleX from '~icons/lucide/circle-x'
import LucideCheck from '~icons/lucide/circle-check'
import LucideWarning from '~icons/lucide/triangle-alert'

/** Controls the visibility of the alert for dismissing or toggling it */
const visible = defineModel({ default: true });
const visible = defineModel({ default: true })

const emit = defineEmits(['dismiss'])

Expand All @@ -21,16 +21,16 @@ const dismissAlert = () => {

const classes = computed(() => {
const subtleBgs = {
yellow: "bg-surface-amber-2",
blue: "bg-surface-blue-2",
red: "bg-surface-red-2",
green: "bg-surface-green-2",
};
yellow: 'bg-surface-amber-2',
blue: 'bg-surface-blue-2',
red: 'bg-surface-red-2',
green: 'bg-surface-green-2',
}

if (props.variant == "outline") return "border border-outline-gray-3";
if (props.variant == 'outline') return 'border border-outline-gray-3'

return props.theme ? subtleBgs[props.theme] : "bg-surface-gray-2";
});
return props.theme ? subtleBgs[props.theme] : 'bg-surface-gray-2'
})

const icon = computed(() => {
const data = {
Expand All @@ -43,9 +43,9 @@ const icon = computed(() => {
})

const props = withDefaults(defineProps<AlertProps>(), {
variant: "subtle",
variant: 'subtle',
dismissable: true,
});
})

defineSlots<{
/** Custom icon shown before the content */
Expand All @@ -67,15 +67,10 @@ defineSlots<{
class="grid grid-cols-[auto_1fr_auto] gap-3 rounded-md px-4 py-3.5 text-base items-start"
>
<slot name="icon">
<component
:is="icon.component"
class="size-4"
v-if="icon"
:class="icon.css"
/>
<component :is="icon.component" class="size-4" v-if="icon" :class="icon.css" />
</slot>

<div class="grid gap-2" :class='{ "col-span-2": !$slots.icon && !icon }'>
<div class="grid gap-2" :class="{ 'col-span-2': !$slots.icon && !icon }">
<span class="text-ink-gray-9"> {{ props.title }} </span>

<slot name="description">
Expand Down
90 changes: 18 additions & 72 deletions src/components/Autocomplete/Autocomplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
:placement="placement"
:match-target-width="true"
>
<template
#target="{ open: openPopover, togglePopover, close: closePopover }"
>
<template #target="{ open: openPopover, togglePopover, close: closePopover }">
<slot
name="target"
v-bind="{
Expand All @@ -36,22 +34,15 @@
>
<div class="flex items-center overflow-hidden">
<slot name="prefix" />
<span
class="truncate text-base leading-5 text-ink-gray-8"
v-if="displayValue"
>
<span class="truncate text-base leading-5 text-ink-gray-8" v-if="displayValue">
{{ displayValue }}
</span>
<span class="text-base leading-5 text-ink-gray-4" v-else>
{{ placeholder || '' }}
</span>
<slot name="suffix" />
</div>
<FeatherIcon
name="chevron-down"
class="h-4 w-4 text-ink-gray-5"
aria-hidden="true"
/>
<FeatherIcon name="chevron-down" class="h-4 w-4 text-ink-gray-5" aria-hidden="true" />
</button>
</div>
</slot>
Expand Down Expand Up @@ -81,24 +72,15 @@
autocomplete="off"
placeholder="Search"
/>
<div
class="absolute right-0 inline-flex h-7 w-7 items-center justify-center"
>
<LoadingIndicator
v-if="props.loading"
class="h-4 w-4 text-ink-gray-5"
/>
<div class="absolute right-0 inline-flex h-7 w-7 items-center justify-center">
<LoadingIndicator v-if="props.loading" class="h-4 w-4 text-ink-gray-5" />
<button v-else @click="clearAll">
<FeatherIcon name="x" class="w-4 text-ink-gray-8" />
</button>
</div>
</div>
</div>
<div
v-for="group in groups"
:key="group.key"
v-show="group.items.length > 0"
>
<div v-for="group in groups" :key="group.key" v-show="group.items.length > 0">
<div
v-if="group.group && !group.hideLabel"
class="sticky top-10 truncate bg-surface-modal px-2.5 py-1.5 text-sm font-medium text-ink-gray-5"
Expand All @@ -107,10 +89,7 @@
</div>
<ComboboxOption
as="template"
v-for="(option, idx) in group.items.slice(
0,
props.maxOptions,
)"
v-for="(option, idx) in group.items.slice(0, props.maxOptions)"
:key="idx"
:value="option"
:disabled="option.disabled"
Expand All @@ -130,10 +109,7 @@
v-if="$slots['item-prefix'] || props.multiple"
class="flex flex-shrink-0"
>
<slot
name="item-prefix"
v-bind="{ active, selected, option }"
>
<slot name="item-prefix" v-bind="{ active, selected, option }">
<FeatherIcon
name="check"
v-if="isOptionSelected(option)"
Expand All @@ -151,14 +127,8 @@
v-if="$slots['item-suffix'] || option?.description"
class="ml-2 flex-shrink-0"
>
<slot
name="item-suffix"
v-bind="{ active, selected, option }"
>
<div
v-if="option?.description"
class="text-sm text-ink-gray-5"
>
<slot name="item-suffix" v-bind="{ active, selected, option }">
<div v-if="option?.description" class="text-sm text-ink-gray-5">
{{ option.description }}
</div>
</slot>
Expand All @@ -174,22 +144,15 @@
</li>
</ComboboxOptions>

<div
v-if="$slots.footer || props.showFooter || multiple"
class="border-t p-1"
>
<div v-if="$slots.footer || props.showFooter || multiple" class="border-t p-1">
<slot name="footer" v-bind="{ togglePopover }">
<div v-if="multiple" class="flex items-center justify-end">
<Button
v-if="!areAllOptionsSelected"
label="Select All"
@click.stop="selectAll"
/>
<Button
v-if="areAllOptionsSelected"
label="Clear All"
@click.stop="clearAll"
/>
<Button v-if="areAllOptionsSelected" label="Clear All" @click.stop="clearAll" />
</div>
<div v-else class="flex items-center justify-end">
<Button label="Clear" @click.stop="clearAll" />
Expand All @@ -204,12 +167,7 @@
</template>

<script setup lang="ts">
import {
Combobox,
ComboboxInput,
ComboboxOption,
ComboboxOptions,
} from '@headlessui/vue'
import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/vue'
import { computed, nextTick, ref, watch } from 'vue'
import { Popover } from '../Popover'
import { Button } from '../Button'
Expand Down Expand Up @@ -270,9 +228,7 @@ const sanitizeOptions = (options: AutocompleteOption[]) => {
if (!options) return []
// in case the options are just values, convert them to objects
return options.map((option) => {
return isOption(option)
? option
: { label: option.toString(), value: option }
return isOption(option) ? option : { label: option.toString(), value: option }
})
}

Expand All @@ -281,10 +237,7 @@ const filterOptions = (options: Option[]) => {
return options.filter((option) => {
return (
option.label.toLowerCase().includes(query.value.trim().toLowerCase()) ||
option.value
.toString()
.toLowerCase()
.includes(query.value.trim().toLowerCase())
option.value.toString().toLowerCase().includes(query.value.trim().toLowerCase())
)
})
}
Expand All @@ -302,9 +255,7 @@ const selectedValue = computed({
// in case of `multiple`, modelValue is an array of values
// if the modelValue is a list of values, convert them to options
const values = (props.modelValue || []) as AutocompleteOption[]
return isOption(values[0])
? values
: values.map((v) => findOption(v) || makeOption(v))
return isOption(values[0]) ? values : values.map((v) => findOption(v) || makeOption(v))
},
set(val) {
query.value = ''
Expand Down Expand Up @@ -336,9 +287,7 @@ const displayValue = computed(() => {
if (!props.multiple) {
return getLabel(selectedValue.value as AutocompleteOption)
}
return (selectedValue.value as AutocompleteOption[])
.map((v) => getLabel(v))
.join(', ')
return (selectedValue.value as AutocompleteOption[]).map((v) => getLabel(v)).join(', ')
})

const isOptionSelected = (option: AutocompleteOption) => {
Expand All @@ -354,10 +303,7 @@ const isOptionSelected = (option: AutocompleteOption) => {

const areAllOptionsSelected = computed(() => {
if (!props.multiple) return false
return (
allOptions.value.length ===
(selectedValue.value as AutocompleteOption[])?.length
)
return allOptions.value.length === (selectedValue.value as AutocompleteOption[])?.length
})

const selectAll = () => {
Expand Down
6 changes: 1 addition & 5 deletions src/components/Avatar/Avatar.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<template>
<div
class="relative inline-block shrink-0"
:class="[sizeClasses, shapeClasses]"
>
<div class="relative inline-block shrink-0" :class="[sizeClasses, shapeClasses]">
<img
v-if="image && !imgFetchError"
:src="image"
Expand Down Expand Up @@ -136,5 +133,4 @@ defineSlots<{
/** Small indicator shown at the bottom-right of the avatar */
indicator?: () => any
}>()

</script>
12 changes: 3 additions & 9 deletions src/components/Badge/Badge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,11 @@
class="inline-flex select-none items-center gap-1 rounded-full whitespace-nowrap"
:class="classes"
>
<div
:class="[props.size == 'lg' ? 'max-h-6' : 'max-h-4']"
v-if="$slots.prefix"
>
<div :class="[props.size == 'lg' ? 'max-h-6' : 'max-h-4']" v-if="$slots.prefix">
<slot name="prefix"></slot>
</div>
<slot>{{ props.label?.toString() }}</slot>
<div
:class="[props.size == 'lg' ? 'max-h-6' : 'max-h-4']"
v-if="$slots.suffix"
>
<div :class="[props.size == 'lg' ? 'max-h-6' : 'max-h-4']" v-if="$slots.suffix">
<slot name="suffix"></slot>
</div>
</div>
Expand Down Expand Up @@ -73,7 +67,7 @@ const classes = computed(() => {
sm: 'h-4 text-xs px-1.5',
md: 'h-5 text-xs px-1.5',
lg: 'h-6 text-sm px-2',
xl: 'h-7 text-base px-2',
xl: 'h-7 text-base px-2',
}[props.size]

return [variantClasses, sizeClasses]
Expand Down
8 changes: 4 additions & 4 deletions src/components/Badge/stories/Themes.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Badge } from 'frappe-ui'
</script>

<template>
<Badge theme="gray" size='lg'>Solid</Badge>
<Badge theme="blue" size='lg'>Subtle</Badge>
<Badge theme="green" size='lg'>Outline</Badge>
<Badge theme="orange" size='lg'>Ghost</Badge>
<Badge theme="gray" size="lg">Solid</Badge>
<Badge theme="blue" size="lg">Subtle</Badge>
<Badge theme="green" size="lg">Outline</Badge>
<Badge theme="orange" size="lg">Ghost</Badge>
</template>
1 change: 0 additions & 1 deletion src/components/Badge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ export interface BadgeProps {
/** Content displayed inside the badge */
label?: Label | string | number
}

Loading
Loading