diff --git a/.gitignore b/.gitignore index 31fe48f6..20eea3e4 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ coverage .npmrc storybook-static + +.claude/* \ No newline at end of file diff --git a/figma-console-mcp b/figma-console-mcp deleted file mode 160000 index 61942b0a..00000000 --- a/figma-console-mcp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 61942b0a0f5c57687820cd8b5d43caa5ddee1c4f diff --git a/package.json b/package.json index 97f39612..0a3e454b 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@mdx-js/react": "^3.1.1", "@primevue/auto-import-resolver": "4.3.6", "@primevue/themes": "4.3.6", + "@tabler/icons-vue": "^3.41.1", "@tabler/icons-webfont": "^3.22.0", "@vee-validate/rules": "^4.7.3", "lodash": "^4.17.21", diff --git a/src/plugins/prime/stories/Form/InputText/InputText.mdx b/src/plugins/prime/stories/Form/InputText/InputText.mdx index fa5dbbb5..ca715b4f 100644 --- a/src/plugins/prime/stories/Form/InputText/InputText.mdx +++ b/src/plugins/prime/stories/Form/InputText/InputText.mdx @@ -1,42 +1,45 @@ -import { Meta, Story } from '@storybook/addon-docs/blocks'; +import { Meta, Canvas, Controls, Title, Description } from '@storybook/addon-docs/blocks'; import * as InputTextStories from './InputText.stories'; -import { Template, TemplateWithIcons } from './InputText.template'; - -# InputText + +<Description /> -[PrimeVue InputText](https://primevue.org/inputtext), [Макет](https://www.figma.com/design/4TYeki0MDLhfPGJstbIicf/UI-kit-PrimeFace-\(DS\)?node-id=484-5470\&node-type=section\&t=2PSg63p2UfJ4cUzB-0) +## Варианты использования -```html dark -<PrimeInputText v-model="value" placeholder="InputText" /> -``` +### Default +Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов. +<Canvas of={InputTextStories.Default} /> -<Story of={InputTextStories.Primary} /> +#### Список параметров +<Controls of={InputTextStories.Default} /> -# С иконками +### Disabled +Отключённое состояние. +<Canvas of={InputTextStories.Disabled} /> -Логика на работу крестика не прописана в ui-ките, на данный момент должна быть прописана на стороне приложения +### Readonly +Режим только для чтения. +<Canvas of={InputTextStories.Readonly} /> -```html dark -<script setup> - const inputValue = ref(''); +### Invalid +Невалидное состояние. +<Canvas of={InputTextStories.Invalid} /> - const onClickDelete = () => { - inputValue.value = ''; - }; -</script> +### FloatLabel +Интеграция с `FloatLabel` — плавающая метка внутри поля. +<Canvas of={InputTextStories.FloatLabel} /> -<template> - <PrimeIconField> - <PrimeInputText v-model=inputValue placeholder="Normal" /> - <PrimeInputIcon @click="onClickDelete"> - <i class="ti ti-x" /> - </PrimeInputIcon> - </PrimeIconField> -</template> +Возможно использование `FloatLabel` и `PBlockInputText` напрямую: +```vue +<FloatLabel variant="in"> + <PBlockInputText id="name" v-model="value" variant="filled" /> + <label for="name">Имя<span class="text-red-500">*</span></label> +</FloatLabel> ``` -<Story of={InputTextStories.WithIcons} /> +### FloatLabel + Invalid +FloatLabel с невалидным состоянием. +<Canvas of={InputTextStories.FloatLabelInvalid} /> diff --git a/src/plugins/prime/stories/Form/InputText/InputText.stories.js b/src/plugins/prime/stories/Form/InputText/InputText.stories.js index bb9fd373..69bfb999 100644 --- a/src/plugins/prime/stories/Form/InputText/InputText.stories.js +++ b/src/plugins/prime/stories/Form/InputText/InputText.stories.js @@ -1,14 +1,400 @@ -import { Template, TemplateWithIcons } from './InputText.template'; +import PBlockInputText from '@/primeBlocks/PBlockInputText/PBlockInputText.vue'; +import { ref } from 'vue'; +import { Template } from './InputText.template'; -export default { +/** + * Компонент текстового ввода. + */ +const meta = { title: 'Prime/Form/InputText', + component: PBlockInputText, + tags: ['autodocs'], + parameters: { + docs: { + description: { + component: `Обёртка над PrimeVue InputText с поддержкой очистки, размеров и кастомной иконки. + +\`\`\`js +import { PBlockInputText } from '@cdek-it/vue-ui-kit'; +\`\`\``, + }, + }, + designToken: { disable: false }, + designTokens: { prefix: '--p-inputtext' }, + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'large', 'xlarge'], + description: + 'Размер поля. `xlarge` — кастомный размер, реализован через CSS-класс `p-inputtext-xlg`.', + table: { + category: 'Props', + type: { summary: "'small' | 'large' | 'xlarge'" }, + }, + }, + showClear: { + control: 'boolean', + description: 'Показывает иконку очистки при наличии значения', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + invalid: { + control: 'boolean', + description: 'Невалидное состояние', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + disabled: { + control: 'boolean', + description: 'Отключает взаимодействие', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + readonly: { + control: 'boolean', + description: 'Только для чтения', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + placeholder: { + control: 'text', + description: 'Подсказка при пустом поле', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + hasFloatlabel: { + control: 'boolean', + description: 'Включает режим плавающей метки (FloatLabel)', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + label: { + control: 'text', + description: 'Текст плавающей метки (при `hasFloatlabel`)', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + fluid: { + control: 'boolean', + description: 'Растягивает поле на всю ширину контейнера', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + }, + args: { + placeholder: 'Введите текст...', + showClear: true, + hasFloatlabel: false, + invalid: false, + disabled: false, + readonly: false, + fluid: false, + }, +}; + +export default meta; + +// ── Stories ────────────────────────────────────────────────────────────────── + +export const Default = { + render: Template, + parameters: { + docs: { + description: { + story: + 'Базовый пример компонента. Используйте Controls для интерактивного изменения пропсов.', + }, + }, + }, +}; + +export const Disabled = { + render: (args) => ({ + components: { PBlockInputText }, + setup() { + const value = ref(''); + return { args, value }; + }, + template: ` + <PBlockInputText + v-model="value" + :placeholder="args.placeholder" + disabled + /> + `, + }), + args: { + placeholder: 'Введите текст...', + }, + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Отключённое состояние.', + }, + source: { + code: ` +<template> + <PBlockInputText v-model="value" placeholder="Введите текст..." disabled /> +</template> + `, + }, + }, + }, }; -export const Primary = { - render: Template.bind({}), +export const Readonly = { + render: (args) => ({ + components: { PBlockInputText }, + setup() { + const value = ref(''); + return { args, value }; + }, + template: ` + <PBlockInputText + v-model="value" + :placeholder="args.placeholder" + readonly + /> + `, + }), + args: { + placeholder: 'Введите текст...', + }, + parameters: { + controls: { disable: true }, + docs: { + description: { + story: + 'Режим только для чтения — поле отображает значение, но недоступно для редактирования.', + }, + source: { + code: ` +<template> + <PBlockInputText v-model="value" placeholder="Введите текст..." readonly /> +</template> + `, + }, + }, + }, +}; + +export const Invalid = { + render: (args) => ({ + components: { PBlockInputText }, + setup() { + const value = ref(''); + return { args, value }; + }, + template: ` + <PBlockInputText + v-model="value" + placeholder="Обязательное поле" + invalid + /> + `, + }), + parameters: { + controls: { disable: true }, + docs: { + description: { + story: 'Невалидное состояние.', + }, + source: { + code: ` +<template> + <PBlockInputText v-model="value" placeholder="Обязательное поле" invalid /> +</template> + `, + }, + }, + }, +}; + +export const FloatLabel = { + render: (args) => ({ + components: { PBlockInputText }, + setup() { + const value = ref(''); + return { args, value }; + }, + template: ` + <PBlockInputText + v-model="value" + hasFloatlabel + :label="args.label" + :required="args.required" + :showClear="args.showClear" + /> + `, + }), + args: { + label: 'Имя', + required: true, + showClear: true, + }, + argTypes: { + label: { + control: 'text', + description: 'Текст плавающей метки', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + showClear: { + control: 'boolean', + description: 'Показывает иконку очистки при наличии значения', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + size: { table: { disable: true } }, + invalid: { table: { disable: true } }, + disabled: { table: { disable: true } }, + readonly: { table: { disable: true } }, + placeholder: { table: { disable: true } }, + fluid: { table: { disable: true } }, + }, + parameters: { + docs: { + description: { + story: `Интеграция с \`FloatLabel\` — плавающая метка внутри поля. + +Можно также использовать \`FloatLabel\` и \`PBlockInputText\` напрямую: + +\`\`\`vue +<FloatLabel variant="in"> + <PBlockInputText id="name" v-model="value" variant="filled" /> + <label for="name">Имя<span class="text-red-500">*</span></label> +</FloatLabel> +\`\`\``, + }, + source: { + code: ` +<template> + <PBlockInputText v-model="value" hasFloatlabel label="Имя" required /> +</template> + `, + }, + }, + }, }; -export const WithIcons = { - render: TemplateWithIcons.bind({}), - name: 'withIcons', +export const FloatLabelInvalid = { + name: 'FloatLabel + Invalid', + render: (args) => ({ + components: { PBlockInputText }, + setup() { + const value = ref(''); + return { args, value }; + }, + template: ` + <PBlockInputText + v-model="value" + hasFloatlabel + :label="args.label" + :required="args.required" + :showClear="args.showClear" + invalid + /> + `, + }), + args: { + label: 'Обязательное поле', + required: true, + showClear: true, + }, + argTypes: { + label: { + control: 'text', + description: 'Текст плавающей метки', + table: { + category: 'Props', + type: { summary: 'string' }, + }, + }, + required: { + control: 'boolean', + description: 'Показывает маркер обязательного поля `*` рядом с меткой', + table: { + category: 'Props', + defaultValue: { summary: 'false' }, + type: { summary: 'boolean' }, + }, + }, + showClear: { + control: 'boolean', + description: 'Показывает иконку очистки при наличии значения', + table: { + category: 'Props', + defaultValue: { summary: 'true' }, + type: { summary: 'boolean' }, + }, + }, + size: { table: { disable: true } }, + invalid: { table: { disable: true } }, + disabled: { table: { disable: true } }, + readonly: { table: { disable: true } }, + placeholder: { table: { disable: true } }, + fluid: { table: { disable: true } }, + }, + parameters: { + docs: { + description: { + story: + 'FloatLabel с невалидным состоянием — демонстрирует стилизацию ошибки в комбинации с плавающей меткой.', + }, + source: { + code: ` +<template> + <PBlockInputText v-model="value" hasFloatlabel label="Обязательное поле" required invalid /> +</template> + `, + }, + }, + }, }; diff --git a/src/plugins/prime/stories/Form/InputText/InputText.template.js b/src/plugins/prime/stories/Form/InputText/InputText.template.js index e3b35ab5..b2fca786 100644 --- a/src/plugins/prime/stories/Form/InputText/InputText.template.js +++ b/src/plugins/prime/stories/Form/InputText/InputText.template.js @@ -1,49 +1,25 @@ -import InputText from 'primevue/inputtext'; -import { IconField, InputIcon } from 'primevue'; +import PBlockInputText from '@/primeBlocks/PBlockInputText/PBlockInputText.vue'; import { ref } from 'vue'; export const Template = (args) => ({ - components: { InputText }, + components: { PBlockInputText }, setup() { - return { args }; + const value = ref(''); + return { args, value }; }, template: ` -<div :style="{ display: 'grid', gridTemplateColumns: 'repeat(4, max-content)', gap: '15px', alignItems: 'center', justifyItems: 'center' }"> - <span></span> - <span></span> - <span><code>invalid</code></span> - <span><code>disabled</code></span> - - <span :style="{ justifySelf: 'flex-start' }"></span> - <InputText placeholder="InputText" v-bind="args" /> - <InputText placeholder="InputText" invalid v-bind="args" /> - <InputText placeholder="InputText" disabled v-bind="args" /> - - <span :style="{ justifySelf: 'flex-start' }"><code>v-model="text input"</code></span> - <InputText :default-value="'text input'" placeholder="InputText" v-bind="args" /> - <InputText :default-value="'text input'" placeholder="InputText" invalid v-bind="args" /> - <InputText :default-value="'text input'" placeholder="InputText" disabled v-bind="args" /> -</div> -`, -}); - -export const TemplateWithIcons = (args) => ({ - components: { InputText, IconField, InputIcon }, - setup() { - const inputValue = ref(''); - - const onClickDelete = () => { - inputValue.value = ''; - }; - - return { args, inputValue, onClickDelete }; - }, - template: ` - <IconField> - <InputText v-model="inputValue" placeholder="Normal" /> - <InputIcon @click="onClickDelete"> - <i class="ti ti-x" /> - </InputIcon> - </IconField> + <PBlockInputText + v-model="value" + :size="args.size" + :showClear="args.showClear" + :hasFloatlabel="args.hasFloatlabel" + :label="args.label" + :required="args.required" + :invalid="args.invalid" + :disabled="args.disabled" + :readonly="args.readonly" + :placeholder="args.placeholder" + :fluid="args.fluid" + /> `, }); diff --git a/src/plugins/prime/theme3.0/components/css/inputtext.ts b/src/plugins/prime/theme3.0/components/css/inputtext.ts new file mode 100644 index 00000000..36e04d15 --- /dev/null +++ b/src/plugins/prime/theme3.0/components/css/inputtext.ts @@ -0,0 +1,58 @@ +const css = ({ dt }: { dt: (token: string) => string }) => ` + +/* ─── Базовые стили ─── */ +.p-inputtext { + border-width: ${dt('inputtext.extend.borderWidth')}; + line-height: ${dt('fonts.lineHeight.250')}; +} + +/* ─── Disabled ─── */ +.p-inputtext:disabled { + background: ${dt('inputtext.root.disabledBackground')}; + color: ${dt('inputtext.root.disabledColor')}; +} + +/* ─── Readonly ─── */ +.p-inputtext:enabled:read-only { + background: ${dt('inputtext.extend.readonlyBackground')}; + color: ${dt('inputtext.root.color')}; +} + +/* ─── Focus ─── */ +.p-inputtext:enabled:focus { + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt( + 'inputtext.focusRing.color' +)}; +} + +/* ─── Invalid + Focus ─── */ +.p-inputtext.p-invalid:focus { + border-color: ${dt('inputtext.root.invalidBorderColor')}; + box-shadow: 0 0 0 ${dt('inputtext.focusRing.width')} ${dt( + 'focusRing.extend.invalid' +)}; +} + +/* ─── Extra Large ─── */ +.p-inputtext.p-inputtext-xlg { + font-size: ${dt('inputtext.extend.extXlg.fontSize')}; + padding: ${dt('inputtext.extend.extXlg.paddingY')} ${dt( + 'inputtext.extend.extXlg.paddingX' +)}; +} + +/* ─── IconField ─── */ +.p-iconfield[data-pc-name="iconfield"] { + width: fit-content; +} + +.p-iconfield .p-inputicon { + font-size: ${dt('inputtext.extend.iconSize')}; + width: ${dt('inputtext.extend.iconSize')}; + height: ${dt('inputtext.extend.iconSize')}; + cursor: pointer; +} + +`; + +export default css; diff --git a/src/plugins/prime/theme3.0/css.ts b/src/plugins/prime/theme3.0/css.ts index 55362c06..0c964773 100644 --- a/src/plugins/prime/theme3.0/css.ts +++ b/src/plugins/prime/theme3.0/css.ts @@ -1,4 +1,3 @@ -// const css = ({ dt }: { dt: (token: string) => string }) => ` const css = () => ` .p-disabled, .p-component:disabled { mix-blend-mode: luminosity; diff --git a/src/plugins/prime/theme3.0/tokens.json b/src/plugins/prime/theme3.0/tokens.json index a7d0103e..5718d930 100644 --- a/src/plugins/prime/theme3.0/tokens.json +++ b/src/plugins/prime/theme3.0/tokens.json @@ -2699,6 +2699,7 @@ "positionX": "{form.padding.300}", "positionY": "{form.padding.300}", "fontWeight": "{fonts.fontWeight.regular}", + "fontSize": "{fonts.fontSize.300}", "active": { "fontSize": "{fonts.fontSize.100}", "fontWeight": "{fonts.fontWeight.regular}" @@ -2709,7 +2710,7 @@ "top": "{form.padding.400}" } }, - "inside": { + "in": { "input": { "paddingTop": "{form.padding.700}", "paddingBottom": "{form.padding.300}" @@ -2920,9 +2921,9 @@ "iconSize": "{form.icon.300}", "borderWidth": "{form.borderWidth}", "extXlg": { - "fontSize": "{form.fontSize}", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}" + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.600}" } }, "root": { @@ -2940,19 +2941,19 @@ "placeholderColor": "{form.placeholderColor}", "invalidPlaceholderColor": "{form.invalidPlaceholderColor}", "shadow": "0", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.300}", "borderRadius": "{form.borderRadius.200}", "transitionDuration": "{form.transitionDuration}", "sm": { - "fontSize": "{form.fontSize}", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}" + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.200}" }, "lg": { - "fontSize": "{form.fontSize}", - "paddingX": "{form.paddingX}", - "paddingY": "{form.paddingY}" + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{form.padding.300}", + "paddingY": "{form.padding.400}" }, "focusRing": { "width": "{form.focusRing.width}", @@ -4826,4 +4827,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/primeBlocks/PBlockInputText/PBlockInputText.vue b/src/primeBlocks/PBlockInputText/PBlockInputText.vue new file mode 100644 index 00000000..00cc13c9 --- /dev/null +++ b/src/primeBlocks/PBlockInputText/PBlockInputText.vue @@ -0,0 +1,69 @@ +<script setup lang="ts"> +import { type InputTextProps, FloatLabel } from 'primevue'; +import PBlockInputTextField from './PBlockInputTextField.vue'; + +interface PBlockInputTextProps extends /* @vue-ignore */ InputTextProps { + modelValue?: string; + showClear?: boolean; + hasFloatlabel?: boolean; + label?: string; + required?: boolean; + size?: 'small' | 'large' | 'xlarge'; + fluid?: boolean; +} + +withDefaults(defineProps<PBlockInputTextProps>(), { + showClear: true, +}); + +defineEmits<{ + (e: 'update:modelValue', value: string): void; + (e: 'value-change', value: string): void; +}>(); +</script> + +<template> + <FloatLabel v-if="hasFloatlabel" variant="in"> + <PBlockInputTextField + :id="label" + :modelValue="modelValue" + :showClear="showClear" + :size="size" + :fluid="fluid" + variant="filled" + v-bind="$attrs" + @update:modelValue="$emit('update:modelValue', $event)" + @value-change="$emit('value-change', $event)" + > + <template #clear-icon> + <slot name="clear-icon" /> + </template> + </PBlockInputTextField> + <label :for="label"> + {{ label + }}<span v-if="required" class="p-block-inputtext__required">*</span> + </label> + </FloatLabel> + + <PBlockInputTextField + v-else + :modelValue="modelValue" + :showClear="showClear" + :size="size" + :fluid="fluid" + v-bind="$attrs" + @update:modelValue="$emit('update:modelValue', $event)" + @value-change="$emit('value-change', $event)" + > + <template #clear-icon> + <slot name="clear-icon" /> + </template> + </PBlockInputTextField> +</template> + +<style scoped lang="scss"> +.p-block-inputtext__required { + color: var(--p-red-500); + margin-left: var(--p-spacing-1x); +} +</style> diff --git a/src/primeBlocks/PBlockInputText/PBlockInputTextField.vue b/src/primeBlocks/PBlockInputText/PBlockInputTextField.vue new file mode 100644 index 00000000..dbcf009e --- /dev/null +++ b/src/primeBlocks/PBlockInputText/PBlockInputTextField.vue @@ -0,0 +1,73 @@ +<script setup lang="ts"> +import { IconField, InputIcon, InputText } from 'primevue'; +import { IconX } from '@tabler/icons-vue'; +import { useAttrs } from 'vue'; + +defineProps<{ + modelValue?: string; + showClear?: boolean; + size?: 'small' | 'large' | 'xlarge'; + fluid?: boolean; +}>(); + +defineOptions({ inheritAttrs: false }); + +const attrs = useAttrs(); + +const emit = defineEmits<{ + (e: 'update:modelValue', value: string): void; + (e: 'value-change', value: string): void; +}>(); + +const onUpdateModelValue = (value: string) => { + emit('update:modelValue', value); + emit('value-change', value); +}; + +const onClear = () => { + emit('update:modelValue', ''); + emit('value-change', ''); +}; +</script> + +<template> + <IconField + class="p-block-inputtext" + :class="{ 'p-block-inputtext--fluid': fluid }" + > + <InputText + v-bind="attrs" + :modelValue="modelValue" + :fluid="fluid" + :size="size === 'xlarge' ? undefined : size" + :class="{ 'p-inputtext-xlg': size === 'xlarge' }" + @update:modelValue="onUpdateModelValue($event as string)" + /> + <InputIcon + v-show="showClear && modelValue" + class="p-block-inputtext__icon" + @click.stop="onClear" + > + <slot name="clear-icon"> + <IconX size="1rem" /> + </slot> + </InputIcon> + </IconField> +</template> + +<style scoped lang="scss"> +.p-block-inputtext { + :deep(.p-inputtext) { + width: 100%; + } + + &--fluid { + width: 100%; + } + + &__icon { + cursor: pointer; + z-index: 1; + } +} +</style> diff --git a/src/primeBlocks/index.ts b/src/primeBlocks/index.ts index d36572ae..76a9d2cc 100644 --- a/src/primeBlocks/index.ts +++ b/src/primeBlocks/index.ts @@ -1,4 +1,5 @@ import PBlockPassword from './PBlockExample/PBlockPassword.vue'; import PBlockToggleButton from './PBlockToggleButton/PBlockToggleButton.vue'; +import PBlockInputText from './PBlockInputText/PBlockInputText.vue'; -export { PBlockPassword, PBlockToggleButton }; +export { PBlockPassword, PBlockToggleButton, PBlockInputText }; diff --git a/yarn.lock b/yarn.lock index ec05e009..4c2b9078 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1294,6 +1294,13 @@ type-fest "~2.19" vue-component-type-helpers latest +"@tabler/icons-vue@^3.41.1": + version "3.41.1" + resolved "https://registry.yarnpkg.com/@tabler/icons-vue/-/icons-vue-3.41.1.tgz#c7c79984d8125e112556f114754227d8a70cefca" + integrity sha512-OLLWlyrx6HdQpdgnZ8dO8uBGIIZwQDPgE8Gl6tUuAD7AgtfnmtFz8vb7dTEvxddM5CMpPt21ogPpBhJfEjSY+Q== + dependencies: + "@tabler/icons" "3.41.1" + "@tabler/icons-webfont@^3.22.0": version "3.34.1" resolved "https://registry.npmjs.org/@tabler/icons-webfont/-/icons-webfont-3.34.1.tgz" @@ -1307,6 +1314,11 @@ resolved "https://registry.npmjs.org/@tabler/icons/-/icons-3.34.1.tgz" integrity sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A== +"@tabler/icons@3.41.1": + version "3.41.1" + resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-3.41.1.tgz#dff9c77af287c73c2fcab4074cfa9f2069f9b7ee" + integrity sha512-OaRnVbRmH2nHtFeg+RmMJ/7m2oBIF9XCJAUD5gQnMrpK9f05ydj8MZrAf3NZQqOXyxGN1UBL0D5IKLLEUfr74Q== + "@tanstack/virtual-core@3.13.12": version "3.13.12" resolved "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz"