@fastkit/vui 0.7.44 → 0.7.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vui.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  import { createPropsOptions, createFormControlSettings, defineSlotsProps, useFormControl, VTooltip, renderSlotOrEmpty, createFormSelectorSettings, createFormControlProps, useFormSelectorControl, createFormSelectorItemSettings, useFormSelectorItemControl, createFormSelectorItemGroupProps, useFormSelectorItemGroupControl, resolveVNodeChildOrSlots, useParentFormNode, VMenu, createTextInputSettings, useTextInputControl, createTextareaSettings, useTextareaControl, createFormSettings, useForm, getDocumentScroller, useVScrollerRef, VScroller, useInjectTheme, VStackRoot, resolveVStackDynamicInput, VueColorSchemePlugin, installVueStackPlugin } from '@fastkit/vue-kit';
2
2
  export * from '@fastkit/vue-kit';
3
3
  export { VDialog, VMenu, VSnackbar, VTooltip } from '@fastkit/vue-kit';
4
- import { inject, computed, provide, createVNode, mergeProps, defineComponent, isVNode, cloneVNode, ref, watch, withDirectives, createTextVNode, Fragment, vShow, onBeforeUpdate, vModelSelect, onMounted, onBeforeUnmount, Transition, reactive } from 'vue';
4
+ import { inject, computed, provide, createVNode, mergeProps, defineComponent, isVNode, ref, watch, onMounted, onBeforeUnmount, cloneVNode, withDirectives, createTextVNode, Fragment, vShow, onBeforeUpdate, vModelSelect, Transition, reactive } from 'vue';
5
5
  import { useRouter, RouterLink, useLink, useRoute } from 'vue-router';
6
- import { createPropsOptions as createPropsOptions$1, htmlAttributesPropOptions, defineSlotsProps as defineSlotsProps$1, renderSlotOrEmpty as renderSlotOrEmpty$1, navigationableInheritProps, VLink, isFragment, rawNumberPropType, resolveNumberish, resizeDirectiveArgument, VExpandTransition, LocationService, setDefaultRouterLink } from '@fastkit/vue-utils';
6
+ import { createPropsOptions as createPropsOptions$1, renderSlotOrEmpty as renderSlotOrEmpty$1, defineSlotsProps as defineSlotsProps$1, htmlAttributesPropOptions, navigationableInheritProps, useNavigationable, VLink, isFragment, rawNumberPropType, resolveNumberish, resizeDirectiveArgument, VExpandTransition, LocationService, setDefaultRouterLink } from '@fastkit/vue-utils';
7
7
  import { getDocumentScroller as getDocumentScroller$1 } from '@fastkit/vue-scroller';
8
8
  import { useScopeColorClass, colorSchemeProps, useColorClasses, toScopeColorClass } from '@fastkit/vue-color-scheme';
9
9
  import { VProgressCircular } from '@fastkit/vue-loading';
10
10
  export * from '@fastkit/vue-loading';
11
+ import { loadImage, IN_WINDOW, isPromise } from '@fastkit/helpers';
11
12
  export { ICON_NAMES } from '@fastkit/icon-font';
12
- import { isPromise } from '@fastkit/helpers';
13
13
  import { VAppContainer, VAppLayoutControl } from '@fastkit/vue-app-layout';
14
14
  import { createTextableProps, createTextableEmits, TextableControl } from '@fastkit/vue-form-control';
15
15
  import { useEditor, EditorContent, BubbleMenu } from '@tiptap/vue-3';
@@ -287,7 +287,7 @@ const VFormControl = defineComponent({
287
287
  ctx.emit('clickLabel', ev, control);
288
288
  }
289
289
  }, [label, getRequiredChip(), hinttip && createVNode(VTooltip, {
290
- "top": true,
290
+ "y": "top",
291
291
  "openOnHover": _hinttipDelay !== 'click',
292
292
  "openDelay": typeof _hinttipDelay === 'number' ? _hinttipDelay : undefined
293
293
  }, {
@@ -350,6 +350,9 @@ function defineFormSelectorComponent(opts) {
350
350
  },
351
351
 
352
352
  render() {
353
+ const {
354
+ selectorControl
355
+ } = this;
353
356
  return createVNode(VFormControl, {
354
357
  "nodeControl": this.nodeControl,
355
358
  "focused": this.nodeControl.focused,
@@ -364,14 +367,20 @@ function defineFormSelectorComponent(opts) {
364
367
  }, { ...this.$slots,
365
368
  default: () => createVNode("div", {
366
369
  "class": "v-form-selector__body"
367
- }, [this.propItems.map(attrs => itemRenderer({
368
- attrs: { ...attrs,
369
- key: attrs.value
370
- },
371
- slots: {
372
- default: () => attrs.label(this.selectorControl)
373
- }
374
- })), renderSlotOrEmpty(this.$slots, 'default')])
370
+ }, [this.propItems.map(attrs => {
371
+ const selected = selectorControl.isSelected(attrs.value);
372
+ return itemRenderer({
373
+ selected,
374
+ control: selectorControl,
375
+ attrs: { ...attrs,
376
+ modelValue: selected,
377
+ key: attrs.value
378
+ },
379
+ slots: {
380
+ default: () => attrs.label(this.selectorControl)
381
+ }
382
+ });
383
+ }), renderSlotOrEmpty(this.$slots, 'default')])
375
384
  });
376
385
  }
377
386
 
@@ -395,6 +404,248 @@ function useElevation(props, opts = {}) {
395
404
  };
396
405
  }
397
406
 
407
+ function _isSlot$e(s) {
408
+ return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !isVNode(s);
409
+ }
410
+
411
+ const VSkeltonLoaderBone = defineComponent({
412
+ name: 'VSkeltonLoaderBone',
413
+ inheritAttrs: false,
414
+ props: {
415
+ tag: {
416
+ type: String,
417
+ default: 'div'
418
+ }
419
+ },
420
+
421
+ setup(props, ctx) {
422
+ return () => {
423
+ let _slot;
424
+
425
+ const TagName = props.tag;
426
+ return createVNode(TagName, mergeProps(ctx.attrs, {
427
+ "class": "v-skelton-loader-bone"
428
+ }), _isSlot$e(_slot = renderSlotOrEmpty$1(ctx.slots)) ? _slot : {
429
+ default: () => [_slot]
430
+ });
431
+ };
432
+ }
433
+
434
+ });
435
+
436
+ const IMAGE_ATTRS = ['alt', 'crossorigin', 'decoding', 'sizes', 'src', 'srcset', 'usemap'];
437
+ function splitAttrs(attrs) {
438
+ const el = { ...attrs
439
+ };
440
+ const img = {};
441
+
442
+ for (const ATTR of IMAGE_ATTRS) {
443
+ const value = attrs[ATTR];
444
+
445
+ if (value != null) {
446
+ img[ATTR] = value;
447
+ }
448
+ }
449
+
450
+ return {
451
+ el,
452
+ img
453
+ };
454
+ }
455
+ const NUMBERISH_PROP = [Number, String];
456
+ const DEFAULT_HEIGHT = 150;
457
+
458
+ const resolveBusyImageSizeValue = source => {
459
+ if (source == null) return;
460
+ return isNaN(source) ? String(source) : `${source}px`;
461
+ };
462
+ /**
463
+ * 画像表示用コンポーネント
464
+ * <img /> タグのように振る舞うが、ローディング表示や、表示サイズの調整など、ちょっといい感じにやるためのコンポーネント
465
+ */
466
+
467
+
468
+ const VBusyImage = defineComponent({
469
+ name: 'VBusyImage',
470
+ props: { ...undefined,
471
+ aspectRatio: String,
472
+ width: NUMBERISH_PROP,
473
+ height: NUMBERISH_PROP,
474
+ cover: Boolean,
475
+ ...defineSlotsProps$1()
476
+ },
477
+ emits: {
478
+ load: ev => true,
479
+ error: ev => true
480
+ },
481
+
482
+ setup(props, ctx) {
483
+ const loadStateRef = ref(props.cover && isAvairableSrc(ctx.attrs.src) ? 'loading' : 'pending');
484
+ const attrsRef = computed(() => splitAttrs(ctx.attrs));
485
+ const isPendingRef = computed(() => loadStateRef.value === 'pending');
486
+ const isLoadingRef = computed(() => loadStateRef.value === 'loading');
487
+ const isLoadedRef = computed(() => loadStateRef.value === 'loaded');
488
+ const isErrorRef = computed(() => loadStateRef.value === 'error');
489
+ const classesRef = computed(() => [`v-busy-image--${loadStateRef.value}`, {
490
+ 'v-busy-image--cover': props.cover,
491
+ 'v-busy-image--clickable': typeof ctx.attrs.onClick === 'function'
492
+ }]);
493
+ const nodeRef = ref();
494
+ const coverImageRef = ref();
495
+ const rectsRef = computed(() => {
496
+ const placeholder = {};
497
+ const main = {};
498
+ const {
499
+ cover
500
+ } = props;
501
+ let {
502
+ width,
503
+ height
504
+ } = props;
505
+
506
+ if (height == null && cover) {
507
+ height = DEFAULT_HEIGHT;
508
+ }
509
+
510
+ if (width == null && cover) {
511
+ width = height;
512
+ }
513
+
514
+ width = resolveBusyImageSizeValue(width);
515
+ height = resolveBusyImageSizeValue(height);
516
+ main.width = width;
517
+ main.height = height;
518
+ placeholder.width = width;
519
+ placeholder.height = height;
520
+
521
+ if (placeholder.height == null) {
522
+ placeholder.height = resolveBusyImageSizeValue(DEFAULT_HEIGHT);
523
+ }
524
+
525
+ if (placeholder.width == null) {
526
+ placeholder.width = placeholder.height;
527
+ }
528
+
529
+ return {
530
+ placeholder,
531
+ main
532
+ };
533
+ });
534
+ const currentRectRef = computed(() => isLoadedRef.value ? rectsRef.value.main : rectsRef.value.placeholder);
535
+ const stylesRef = computed(() => {
536
+ const {
537
+ value: coverImage
538
+ } = coverImageRef;
539
+ const coverSrc = coverImage && coverImage.src;
540
+ const styles = { ...currentRectRef.value
541
+ };
542
+
543
+ if (coverSrc) {
544
+ styles.backgroundImage = `url(${coverSrc})`;
545
+ }
546
+
547
+ return styles;
548
+ });
549
+ let booted = false;
550
+ watch(() => ctx.attrs.src, value => {
551
+ coverImageRef.value = undefined;
552
+
553
+ if (isAvairableSrc(value)) {
554
+ loadStateRef.value = 'loading';
555
+
556
+ if (props.cover) {
557
+ loadImage(value).then(image => {
558
+ coverImageRef.value = image;
559
+ setManualState('load');
560
+ }).catch(err => {
561
+ setManualState('error');
562
+ });
563
+ }
564
+ } else {
565
+ loadStateRef.value = 'pending';
566
+ }
567
+ }, {
568
+ immediate: IN_WINDOW
569
+ });
570
+
571
+ const setManualState = loadType => {
572
+ loadStateRef.value = loadType === 'load' ? 'loaded' : 'error';
573
+ const ev = new Event(loadType, {
574
+ bubbles: false,
575
+ cancelable: false,
576
+ composed: false
577
+ });
578
+ ctx.emit(loadType, ev);
579
+ };
580
+
581
+ onMounted(() => {
582
+ if (booted || props.cover) return;
583
+ const image = nodeRef.value;
584
+ if (!image) return;
585
+ const loadType = imageIsReady(image);
586
+
587
+ if (loadType) {
588
+ setManualState(loadType);
589
+ }
590
+ });
591
+ onBeforeUnmount(() => {
592
+ coverImageRef.value = undefined;
593
+ });
594
+
595
+ const handleLoad = ev => {
596
+ booted = true;
597
+ loadStateRef.value = 'loaded';
598
+ ctx.emit('load', ev);
599
+ };
600
+
601
+ const handleError = ev => {
602
+ booted = true;
603
+ loadStateRef.value = 'error';
604
+ ctx.emit('error', ev);
605
+ };
606
+
607
+ ctx.expose({
608
+ state: loadStateRef,
609
+ isPending: isPendingRef,
610
+ isLoading: isLoadingRef,
611
+ isLoaded: isLoadedRef,
612
+ isError: isErrorRef
613
+ });
614
+ return () => {
615
+ const {
616
+ el: elAttrs,
617
+ img: imgAttrs
618
+ } = attrsRef.value;
619
+ const styles = stylesRef.value;
620
+ const children = ctx.slots.default && ctx.slots.default();
621
+ return createVNode("span", mergeProps({
622
+ "class": ['v-busy-image', classesRef.value]
623
+ }, elAttrs, {
624
+ "style": styles
625
+ }), [!props.cover && createVNode("img", mergeProps({
626
+ "key": "img",
627
+ "ref": nodeRef,
628
+ "class": "v-busy-image__node"
629
+ }, imgAttrs, {
630
+ "onLoad": handleLoad,
631
+ "onError": handleError
632
+ }), null), !!children && createVNode("span", {
633
+ "class": "v-busy-image__slot"
634
+ }, [children])]);
635
+ };
636
+ }
637
+
638
+ });
639
+
640
+ function imageIsReady(image) {
641
+ if (!image.complete) return false;
642
+ return image.naturalWidth + image.naturalHeight > 0 ? 'load' : 'error';
643
+ }
644
+
645
+ function isAvairableSrc(src) {
646
+ return typeof src === 'string' && src !== '';
647
+ }
648
+
398
649
  function extractRawGridValueClasses(value, prefix, getter) {
399
650
  if (typeof value !== 'object')
400
651
  return `${prefix}${getter ? getter(value) : value}`;
@@ -620,6 +871,162 @@ const VPaper = defineComponent({
620
871
 
621
872
  });
622
873
 
874
+ const AVATAR_SIZES = ['sm', 'md', 'lg'];
875
+ function createAvatarProps() {
876
+ return { ...colorSchemeProps(),
877
+ ...navigationableInheritProps,
878
+ size: {
879
+ type: [String, Number],
880
+ default: 'md'
881
+ },
882
+ tile: Boolean,
883
+ rounded: Boolean,
884
+ disabled: Boolean,
885
+ src: String
886
+ };
887
+ }
888
+ const VAvatar = defineComponent({
889
+ name: 'VAvatar',
890
+ inheritAttrs: false,
891
+ props: createAvatarProps(),
892
+
893
+ setup(props, ctx) {
894
+ const vui = useVui();
895
+ const defaults = vui.setting('buttonDefault');
896
+ const color = useColorClasses({
897
+ color: () => props.color || defaults.color,
898
+ variant: () => props.variant || defaults.variant
899
+ });
900
+ const navigationable = useNavigationable(ctx, {
901
+ clickableClassName: () => 'v-avatar--clickable',
902
+ linkFallbackTag: 'div'
903
+ });
904
+ const classes = computed(() => {
905
+ const {
906
+ size
907
+ } = props;
908
+ return [{
909
+ 'v-avatar--tile': props.tile,
910
+ 'v-avatar--rounded': props.rounded
911
+ }, typeof size === 'string' && `v-avatar--${size}`];
912
+ });
913
+ const styles = computed(() => {
914
+ const {
915
+ size
916
+ } = props;
917
+ if (typeof size !== 'number') return;
918
+ return {
919
+ '--avatar-size': `${size}px`
920
+ };
921
+ });
922
+ return () => {
923
+ const {
924
+ src
925
+ } = props;
926
+ const {
927
+ Tag,
928
+ attrs
929
+ } = navigationable.value;
930
+ return createVNode(Tag, mergeProps(attrs, {
931
+ "class": ['v-avatar', classes.value, color.colorClasses.value],
932
+ "style": styles.value
933
+ }), {
934
+ default: () => [!!src && createVNode(VBusyImage, {
935
+ "class": "v-avatar__image",
936
+ "src": src,
937
+ "cover": true
938
+ }, null) || renderSlotOrEmpty$1(ctx.slots)]
939
+ });
940
+ };
941
+ }
942
+
943
+ });
944
+
945
+ const CHIP_SIZES = ['xs', 'sm', 'md', 'lg', 'xl'];
946
+ function createChipProps() {
947
+ return { ...colorSchemeProps(),
948
+ ...navigationableInheritProps,
949
+ size: {
950
+ type: String,
951
+ default: 'md'
952
+ },
953
+ startIcon: [String, Function],
954
+ endIcon: [String, Function],
955
+ label: Boolean,
956
+ disabled: Boolean
957
+ };
958
+ }
959
+
960
+ function resolveRawVChipIcon(raw, type) {
961
+ if (!raw) return;
962
+
963
+ if (typeof raw === 'function') {
964
+ return () => {
965
+ const child = raw();
966
+ if (child == null) return;
967
+ return createVNode("span", {
968
+ "class": ['v-chip__icon', `v-chip__icon--${type}`]
969
+ }, [child]);
970
+ };
971
+ }
972
+
973
+ return () => createVNode(VIcon, {
974
+ "class": ['v-chip__icon', `v-chip__icon--${type}`],
975
+ "name": raw
976
+ }, null);
977
+ }
978
+
979
+ const VChip = defineComponent({
980
+ name: 'VChip',
981
+ inheritAttrs: false,
982
+ props: createChipProps(),
983
+
984
+ setup(props, ctx) {
985
+ const vui = useVui();
986
+ const defaults = vui.setting('buttonDefault');
987
+ const color = useColorClasses({
988
+ color: () => props.color || defaults.color,
989
+ variant: () => props.variant || defaults.variant
990
+ });
991
+ const startIcon = computed(() => {
992
+ const _icon = resolveRawVChipIcon(props.startIcon, 'start');
993
+
994
+ return _icon && _icon();
995
+ });
996
+ const endIcon = computed(() => {
997
+ const _icon = resolveRawVChipIcon(props.endIcon, 'end');
998
+
999
+ return _icon && _icon();
1000
+ });
1001
+ const navigationable = useNavigationable(ctx, {
1002
+ clickableClassName: () => 'v-chip--clickable',
1003
+ linkFallbackTag: 'div'
1004
+ });
1005
+ const classes = computed(() => {
1006
+ const {
1007
+ size
1008
+ } = props;
1009
+ return [{
1010
+ 'v-chip--label': props.label
1011
+ }, typeof size === 'string' && `v-chip--${size}`];
1012
+ });
1013
+ return () => {
1014
+ const {
1015
+ Tag,
1016
+ attrs
1017
+ } = navigationable.value;
1018
+ return createVNode(Tag, mergeProps(attrs, {
1019
+ "class": ['v-chip', classes.value, color.colorClasses.value]
1020
+ }), {
1021
+ default: () => [startIcon.value, createVNode("span", {
1022
+ "class": "v-chip__content"
1023
+ }, [renderSlotOrEmpty$1(ctx.slots)]), endIcon.value]
1024
+ });
1025
+ };
1026
+ }
1027
+
1028
+ });
1029
+
623
1030
  function createCardProps() {
624
1031
  return { ...createPaperProps(),
625
1032
  ...navigationableInheritProps,
@@ -4501,4 +4908,4 @@ function installVuiPlugin(app, opts) {
4501
4908
  return app.use(VuiPlugin, opts);
4502
4909
  }
4503
4910
 
4504
- export { CONTROL_FIELD_VARIANTS, CONTROL_SIZES, PAGINATION_ALIGNS, VApp, VBreadcrumbs, VButton, VButtonGroup, VCard, VCardActions, VCardContent, VCheckbox, VCheckboxGroup, VContentSwitcher, VDataTable, VDrawerLayout, VForm, VFormControl, VGridContainer, VGridItem, VHero, VIcon, VListTile, VNavigation, VNavigationItem, VOption, VOptionGroup, VPagination, VPaper, VRadio, VRadioGroup, VSelect, VSwitch, VSwitchGroup, VTabs, VTextField, VTextarea, VToolbar, VToolbarEdge, VToolbarMenu, VToolbarTitle, VUI_CHECKBOX_GROUP_SYMBOL, VUI_CHECKBOX_SYMBOL, VUI_FORM_SYMBOL, VUI_OPTION_SYMBOL, VUI_RADIO_GROUP_SYMBOL, VUI_RADIO_SYMBOL, VUI_SELECT_SYMBOL, VUI_SWITCH_GROUP_SYMBOL, VUI_SWITCH_SYMBOL, VUI_TEXTAREA_SYMBOL, VUI_TEXT_FIELD_SYMBOL, VUI_WYSIWYG_EDITOR_SYMBOL, VWysiwygEditor, VuiColorProviderInjectionKey, VuiControlFieldInjectionKey, VuiControlInjectionKey, VuiInjectionKey, VuiPlugin, VuiService, WysiwygBulletListTool, WysiwygFormatBoldTool, WysiwygFormatItalicTool, WysiwygFormatUnderlineTool, WysiwygHistoryTool, WysiwygLinkTool, WysiwygOrderedListTool, WysiwygTextColorTool, configureDataTableDefaults, createCardProps, createControlFieldProviderProps, createControlProps, createElevationProps, createListTileProps, createNavigationItemProps, createPaperBaseProps, createPaperProps, createRequiredChipRenderer, defineFormSelectorComponent, iconProps, installVuiPlugin, listTileEmits, mergeVuiPluginOptions, mergeVuiServiceIconSettings, mergeVuiServiceOptions, mergeVuiServiceUISettings, paginationProps, rawIconProp, renderNavigationItemInput, resolveNavigationItemInput, resolveRawIconProp, resolveRawWysiwygEditorTools, useControl, useControlField, useElevation, useVui, useVuiColorProvider, vueButtonProps };
4911
+ export { AVATAR_SIZES, CHIP_SIZES, CONTROL_FIELD_VARIANTS, CONTROL_SIZES, PAGINATION_ALIGNS, VApp, VAvatar, VBreadcrumbs, VBusyImage, VButton, VButtonGroup, VCard, VCardActions, VCardContent, VCheckbox, VCheckboxGroup, VChip, VContentSwitcher, VDataTable, VDrawerLayout, VForm, VFormControl, VGridContainer, VGridItem, VHero, VIcon, VListTile, VNavigation, VNavigationItem, VOption, VOptionGroup, VPagination, VPaper, VRadio, VRadioGroup, VSelect, VSkeltonLoaderBone, VSwitch, VSwitchGroup, VTabs, VTextField, VTextarea, VToolbar, VToolbarEdge, VToolbarMenu, VToolbarTitle, VUI_CHECKBOX_GROUP_SYMBOL, VUI_CHECKBOX_SYMBOL, VUI_FORM_SYMBOL, VUI_OPTION_SYMBOL, VUI_RADIO_GROUP_SYMBOL, VUI_RADIO_SYMBOL, VUI_SELECT_SYMBOL, VUI_SWITCH_GROUP_SYMBOL, VUI_SWITCH_SYMBOL, VUI_TEXTAREA_SYMBOL, VUI_TEXT_FIELD_SYMBOL, VUI_WYSIWYG_EDITOR_SYMBOL, VWysiwygEditor, VuiColorProviderInjectionKey, VuiControlFieldInjectionKey, VuiControlInjectionKey, VuiInjectionKey, VuiPlugin, VuiService, WysiwygBulletListTool, WysiwygFormatBoldTool, WysiwygFormatItalicTool, WysiwygFormatUnderlineTool, WysiwygHistoryTool, WysiwygLinkTool, WysiwygOrderedListTool, WysiwygTextColorTool, configureDataTableDefaults, createAvatarProps, createCardProps, createChipProps, createControlFieldProviderProps, createControlProps, createElevationProps, createListTileProps, createNavigationItemProps, createPaperBaseProps, createPaperProps, createRequiredChipRenderer, defineFormSelectorComponent, iconProps, installVuiPlugin, listTileEmits, mergeVuiPluginOptions, mergeVuiServiceIconSettings, mergeVuiServiceOptions, mergeVuiServiceUISettings, paginationProps, rawIconProp, renderNavigationItemInput, resolveNavigationItemInput, resolveRawIconProp, resolveRawWysiwygEditorTools, splitAttrs, useControl, useControlField, useElevation, useVui, useVuiColorProvider, vueButtonProps };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastkit/vui",
3
- "version": "0.7.44",
3
+ "version": "0.7.48",
4
4
  "description": "@fastkit/vui",
5
5
  "buildOptions": {
6
6
  "name": "Vui",
@@ -32,11 +32,11 @@
32
32
  "vue": "^3.2.26"
33
33
  },
34
34
  "dependencies": {
35
- "@fastkit/color-scheme": "0.7.44",
36
- "@fastkit/icon-font": "0.7.44",
37
- "@fastkit/tiny-logger": "0.7.44",
38
- "@fastkit/vite-kit": "0.7.44",
39
- "@fastkit/vue-kit": "0.7.44",
35
+ "@fastkit/color-scheme": "0.7.48",
36
+ "@fastkit/icon-font": "0.7.48",
37
+ "@fastkit/tiny-logger": "0.7.48",
38
+ "@fastkit/vite-kit": "0.7.48",
39
+ "@fastkit/vue-kit": "0.7.48",
40
40
  "@tiptap/extension-link": "^2.0.0-beta.36",
41
41
  "@tiptap/extension-underline": "^2.0.0-beta.23",
42
42
  "@tiptap/starter-kit": "^2.0.0-beta.183",
Binary file
Binary file
@@ -0,0 +1,76 @@
1
+ @use '../../styles/core.scss';
2
+
3
+ .v-avatar {
4
+ @include core.button-reset();
5
+
6
+ --avatar-radius: 50%;
7
+ --avatar-font-weight: var(--typo-medium-weight);
8
+ --avatar-base-font-size: var(--typo-base-size);
9
+ --avatar-font-size: var(--avatar-base-font-size);
10
+
11
+ display: inline-flex;
12
+ flex-basis: var(--avatar-size);
13
+ align-items: center;
14
+ justify-content: center;
15
+ width: var(--avatar-size);
16
+ min-width: var(--avatar-size);
17
+ height: var(--avatar-size);
18
+ overflow: hidden;
19
+ font-size: var(--avatar-font-size);
20
+ font-weight: var(--avatar-font-weight);
21
+ line-height: 1;
22
+ text-align: center;
23
+ vertical-align: bottom;
24
+ cursor: default;
25
+ border-style: solid;
26
+ border-width: 1px;
27
+ border-radius: var(--avatar-radius);
28
+ // border-radius: var(--control-field-radius);
29
+
30
+ --shadow-color: rgba(0, 0, 0, 0) !important; // @TODO layer supports
31
+ --focusShadow-color: rgba(0, 0, 0, 0) !important; // @TODO layer supports
32
+
33
+ &--clickable {
34
+ cursor: pointer;
35
+ }
36
+
37
+ &--sm {
38
+ --avatar-size: 36px;
39
+ --avatar-font-size: calc(var(--avatar-base-font-size) * 0.75);
40
+ }
41
+
42
+ &--md {
43
+ --avatar-size: 48px;
44
+ }
45
+
46
+ &--lg {
47
+ --avatar-size: 62px;
48
+ --avatar-font-size: calc(var(--avatar-base-font-size) * 1.25);
49
+ }
50
+
51
+ &--rounded {
52
+ --avatar-radius: 4px;
53
+ }
54
+
55
+ &--tile {
56
+ --avatar-radius: 0;
57
+ }
58
+
59
+ // &[disabled] {
60
+ // pointer-events: none;
61
+
62
+ // &::before {
63
+ // content: none;
64
+ // }
65
+ // }
66
+ // // noop
67
+
68
+ img,
69
+ &__image {
70
+ display: inline-flex;
71
+ width: inherit !important;
72
+ height: inherit !important;
73
+ border-radius: inherit;
74
+ object-fit: cover;
75
+ }
76
+ }
@@ -0,0 +1,81 @@
1
+ import './VAvatar.scss';
2
+ import { defineComponent, computed, PropType } from 'vue';
3
+ import {
4
+ navigationableInheritProps,
5
+ useNavigationable,
6
+ renderSlotOrEmpty,
7
+ } from '@fastkit/vue-utils';
8
+ import { colorSchemeProps, useColorClasses } from '@fastkit/vue-color-scheme';
9
+ import { useVui } from '../../injections';
10
+ import { VBusyImage } from '../VBusyImage';
11
+
12
+ export const AVATAR_SIZES = ['sm', 'md', 'lg'] as const;
13
+
14
+ export type AvatarSize = typeof AVATAR_SIZES[number];
15
+
16
+ export function createAvatarProps() {
17
+ return {
18
+ ...colorSchemeProps(),
19
+ ...navigationableInheritProps,
20
+ size: {
21
+ type: [String, Number] as PropType<AvatarSize | number>,
22
+ default: 'md',
23
+ },
24
+ tile: Boolean,
25
+ rounded: Boolean,
26
+ disabled: Boolean,
27
+ src: String,
28
+ };
29
+ }
30
+
31
+ export const VAvatar = defineComponent({
32
+ name: 'VAvatar',
33
+ inheritAttrs: false,
34
+ props: createAvatarProps(),
35
+ setup(props, ctx) {
36
+ const vui = useVui();
37
+ const defaults = vui.setting('buttonDefault');
38
+ const color = useColorClasses({
39
+ color: () => props.color || defaults.color,
40
+ variant: () => props.variant || defaults.variant,
41
+ });
42
+ const navigationable = useNavigationable(ctx, {
43
+ clickableClassName: () => 'v-avatar--clickable',
44
+ linkFallbackTag: 'div',
45
+ });
46
+
47
+ const classes = computed(() => {
48
+ const { size } = props;
49
+ return [
50
+ {
51
+ 'v-avatar--tile': props.tile,
52
+ 'v-avatar--rounded': props.rounded,
53
+ },
54
+ typeof size === 'string' && `v-avatar--${size}`,
55
+ ];
56
+ });
57
+
58
+ const styles = computed(() => {
59
+ const { size } = props;
60
+ if (typeof size !== 'number') return;
61
+
62
+ return {
63
+ '--avatar-size': `${size}px`,
64
+ };
65
+ });
66
+
67
+ return () => {
68
+ const { src } = props;
69
+ const { Tag, attrs } = navigationable.value;
70
+ return (
71
+ <Tag
72
+ {...attrs}
73
+ class={['v-avatar', classes.value, color.colorClasses.value]}
74
+ style={styles.value}>
75
+ {(!!src && <VBusyImage class="v-avatar__image" src={src} cover />) ||
76
+ renderSlotOrEmpty(ctx.slots)}
77
+ </Tag>
78
+ );
79
+ };
80
+ },
81
+ });
@@ -0,0 +1 @@
1
+ export * from './VAvatar';