@fastkit/vui 0.7.46 → 0.7.49

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
  }, {
@@ -404,6 +404,248 @@ function useElevation(props, opts = {}) {
404
404
  };
405
405
  }
406
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
+
407
649
  function extractRawGridValueClasses(value, prefix, getter) {
408
650
  if (typeof value !== 'object')
409
651
  return `${prefix}${getter ? getter(value) : value}`;
@@ -629,6 +871,162 @@ const VPaper = defineComponent({
629
871
 
630
872
  });
631
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
+
632
1030
  function createCardProps() {
633
1031
  return { ...createPaperProps(),
634
1032
  ...navigationableInheritProps,
@@ -2419,7 +2817,10 @@ const VWysiwygEditor = defineComponent({
2419
2817
 
2420
2818
  watch(() => inputControl.canOperation, updateEditable);
2421
2819
  watch(() => props.modelValue, modelValue => {
2422
- editor.value && editor.value.commands.setContent(modelValue == null ? '' : modelValue);
2820
+ const $editor = editor.value;
2821
+ if (!$editor) return;
2822
+ $editor.commands.setContent(modelValue == null ? '' : modelValue);
2823
+ textRef.value = $editor.getText();
2423
2824
  });
2424
2825
  const editor = useEditor({
2425
2826
  onCreate: ({
@@ -2437,6 +2838,7 @@ const VWysiwygEditor = defineComponent({
2437
2838
  onUpdate: ev => {
2438
2839
  inputControl.value = ev.editor.getHTML();
2439
2840
  textRef.value = ev.editor.getText();
2841
+ console.log(textRef.value);
2440
2842
  },
2441
2843
  autofocus: props.autofocus,
2442
2844
  content: props.modelValue,
@@ -4510,4 +4912,4 @@ function installVuiPlugin(app, opts) {
4510
4912
  return app.use(VuiPlugin, opts);
4511
4913
  }
4512
4914
 
4513
- 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 };
4915
+ 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.46",
3
+ "version": "0.7.49",
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.46",
36
- "@fastkit/icon-font": "0.7.46",
37
- "@fastkit/tiny-logger": "0.7.46",
38
- "@fastkit/vite-kit": "0.7.46",
39
- "@fastkit/vue-kit": "0.7.46",
35
+ "@fastkit/color-scheme": "0.7.49",
36
+ "@fastkit/icon-font": "0.7.49",
37
+ "@fastkit/tiny-logger": "0.7.49",
38
+ "@fastkit/vite-kit": "0.7.49",
39
+ "@fastkit/vue-kit": "0.7.49",
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';