@fastkit/vui 0.7.43 → 0.7.47

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.cjs.js CHANGED
@@ -9,8 +9,8 @@ var vueUtils = require('@fastkit/vue-utils');
9
9
  var vueScroller = require('@fastkit/vue-scroller');
10
10
  var vueColorScheme = require('@fastkit/vue-color-scheme');
11
11
  var vueLoading = require('@fastkit/vue-loading');
12
- var iconFont = require('@fastkit/icon-font');
13
12
  var helpers = require('@fastkit/helpers');
13
+ var iconFont = require('@fastkit/icon-font');
14
14
  var vueAppLayout = require('@fastkit/vue-app-layout');
15
15
  var vueFormControl = require('@fastkit/vue-form-control');
16
16
  var vue3 = require('@tiptap/vue-3');
@@ -355,6 +355,9 @@ function defineFormSelectorComponent(opts) {
355
355
  },
356
356
 
357
357
  render() {
358
+ const {
359
+ selectorControl
360
+ } = this;
358
361
  return vue.createVNode(VFormControl, {
359
362
  "nodeControl": this.nodeControl,
360
363
  "focused": this.nodeControl.focused,
@@ -369,14 +372,20 @@ function defineFormSelectorComponent(opts) {
369
372
  }, { ...this.$slots,
370
373
  default: () => vue.createVNode("div", {
371
374
  "class": "v-form-selector__body"
372
- }, [this.propItems.map(attrs => itemRenderer({
373
- attrs: { ...attrs,
374
- key: attrs.value
375
- },
376
- slots: {
377
- default: () => attrs.label(this.selectorControl)
378
- }
379
- })), vueKit.renderSlotOrEmpty(this.$slots, 'default')])
375
+ }, [this.propItems.map(attrs => {
376
+ const selected = selectorControl.isSelected(attrs.value);
377
+ return itemRenderer({
378
+ selected,
379
+ control: selectorControl,
380
+ attrs: { ...attrs,
381
+ modelValue: selected,
382
+ key: attrs.value
383
+ },
384
+ slots: {
385
+ default: () => attrs.label(this.selectorControl)
386
+ }
387
+ });
388
+ }), vueKit.renderSlotOrEmpty(this.$slots, 'default')])
380
389
  });
381
390
  }
382
391
 
@@ -400,6 +409,248 @@ function useElevation(props, opts = {}) {
400
409
  };
401
410
  }
402
411
 
412
+ function _isSlot$e(s) {
413
+ return typeof s === 'function' || Object.prototype.toString.call(s) === '[object Object]' && !vue.isVNode(s);
414
+ }
415
+
416
+ const VSkeltonLoaderBone = vue.defineComponent({
417
+ name: 'VSkeltonLoaderBone',
418
+ inheritAttrs: false,
419
+ props: {
420
+ tag: {
421
+ type: String,
422
+ default: 'div'
423
+ }
424
+ },
425
+
426
+ setup(props, ctx) {
427
+ return () => {
428
+ let _slot;
429
+
430
+ const TagName = props.tag;
431
+ return vue.createVNode(TagName, vue.mergeProps(ctx.attrs, {
432
+ "class": "v-skelton-loader-bone"
433
+ }), _isSlot$e(_slot = vueUtils.renderSlotOrEmpty(ctx.slots)) ? _slot : {
434
+ default: () => [_slot]
435
+ });
436
+ };
437
+ }
438
+
439
+ });
440
+
441
+ const IMAGE_ATTRS = ['alt', 'crossorigin', 'decoding', 'sizes', 'src', 'srcset', 'usemap'];
442
+ function splitAttrs(attrs) {
443
+ const el = { ...attrs
444
+ };
445
+ const img = {};
446
+
447
+ for (const ATTR of IMAGE_ATTRS) {
448
+ const value = attrs[ATTR];
449
+
450
+ if (value != null) {
451
+ img[ATTR] = value;
452
+ }
453
+ }
454
+
455
+ return {
456
+ el,
457
+ img
458
+ };
459
+ }
460
+ const NUMBERISH_PROP = [Number, String];
461
+ const DEFAULT_HEIGHT = 150;
462
+
463
+ const resolveBusyImageSizeValue = source => {
464
+ if (source == null) return;
465
+ return isNaN(source) ? String(source) : `${source}px`;
466
+ };
467
+ /**
468
+ * 画像表示用コンポーネント
469
+ * <img /> タグのように振る舞うが、ローディング表示や、表示サイズの調整など、ちょっといい感じにやるためのコンポーネント
470
+ */
471
+
472
+
473
+ const VBusyImage = vue.defineComponent({
474
+ name: 'VBusyImage',
475
+ props: { ...undefined,
476
+ aspectRatio: String,
477
+ width: NUMBERISH_PROP,
478
+ height: NUMBERISH_PROP,
479
+ cover: Boolean,
480
+ ...vueUtils.defineSlotsProps()
481
+ },
482
+ emits: {
483
+ load: ev => true,
484
+ error: ev => true
485
+ },
486
+
487
+ setup(props, ctx) {
488
+ const loadStateRef = vue.ref(props.cover && isAvairableSrc(ctx.attrs.src) ? 'loading' : 'pending');
489
+ const attrsRef = vue.computed(() => splitAttrs(ctx.attrs));
490
+ const isPendingRef = vue.computed(() => loadStateRef.value === 'pending');
491
+ const isLoadingRef = vue.computed(() => loadStateRef.value === 'loading');
492
+ const isLoadedRef = vue.computed(() => loadStateRef.value === 'loaded');
493
+ const isErrorRef = vue.computed(() => loadStateRef.value === 'error');
494
+ const classesRef = vue.computed(() => [`v-busy-image--${loadStateRef.value}`, {
495
+ 'v-busy-image--cover': props.cover,
496
+ 'v-busy-image--clickable': typeof ctx.attrs.onClick === 'function'
497
+ }]);
498
+ const nodeRef = vue.ref();
499
+ const coverImageRef = vue.ref();
500
+ const rectsRef = vue.computed(() => {
501
+ const placeholder = {};
502
+ const main = {};
503
+ const {
504
+ cover
505
+ } = props;
506
+ let {
507
+ width,
508
+ height
509
+ } = props;
510
+
511
+ if (height == null && cover) {
512
+ height = DEFAULT_HEIGHT;
513
+ }
514
+
515
+ if (width == null && cover) {
516
+ width = height;
517
+ }
518
+
519
+ width = resolveBusyImageSizeValue(width);
520
+ height = resolveBusyImageSizeValue(height);
521
+ main.width = width;
522
+ main.height = height;
523
+ placeholder.width = width;
524
+ placeholder.height = height;
525
+
526
+ if (placeholder.height == null) {
527
+ placeholder.height = resolveBusyImageSizeValue(DEFAULT_HEIGHT);
528
+ }
529
+
530
+ if (placeholder.width == null) {
531
+ placeholder.width = placeholder.height;
532
+ }
533
+
534
+ return {
535
+ placeholder,
536
+ main
537
+ };
538
+ });
539
+ const currentRectRef = vue.computed(() => isLoadedRef.value ? rectsRef.value.main : rectsRef.value.placeholder);
540
+ const stylesRef = vue.computed(() => {
541
+ const {
542
+ value: coverImage
543
+ } = coverImageRef;
544
+ const coverSrc = coverImage && coverImage.src;
545
+ const styles = { ...currentRectRef.value
546
+ };
547
+
548
+ if (coverSrc) {
549
+ styles.backgroundImage = `url(${coverSrc})`;
550
+ }
551
+
552
+ return styles;
553
+ });
554
+ let booted = false;
555
+ vue.watch(() => ctx.attrs.src, value => {
556
+ coverImageRef.value = undefined;
557
+
558
+ if (isAvairableSrc(value)) {
559
+ loadStateRef.value = 'loading';
560
+
561
+ if (props.cover) {
562
+ helpers.loadImage(value).then(image => {
563
+ coverImageRef.value = image;
564
+ setManualState('load');
565
+ }).catch(err => {
566
+ setManualState('error');
567
+ });
568
+ }
569
+ } else {
570
+ loadStateRef.value = 'pending';
571
+ }
572
+ }, {
573
+ immediate: helpers.IN_WINDOW
574
+ });
575
+
576
+ const setManualState = loadType => {
577
+ loadStateRef.value = loadType === 'load' ? 'loaded' : 'error';
578
+ const ev = new Event(loadType, {
579
+ bubbles: false,
580
+ cancelable: false,
581
+ composed: false
582
+ });
583
+ ctx.emit(loadType, ev);
584
+ };
585
+
586
+ vue.onMounted(() => {
587
+ if (booted || props.cover) return;
588
+ const image = nodeRef.value;
589
+ if (!image) return;
590
+ const loadType = imageIsReady(image);
591
+
592
+ if (loadType) {
593
+ setManualState(loadType);
594
+ }
595
+ });
596
+ vue.onBeforeUnmount(() => {
597
+ coverImageRef.value = undefined;
598
+ });
599
+
600
+ const handleLoad = ev => {
601
+ booted = true;
602
+ loadStateRef.value = 'loaded';
603
+ ctx.emit('load', ev);
604
+ };
605
+
606
+ const handleError = ev => {
607
+ booted = true;
608
+ loadStateRef.value = 'error';
609
+ ctx.emit('error', ev);
610
+ };
611
+
612
+ ctx.expose({
613
+ state: loadStateRef,
614
+ isPending: isPendingRef,
615
+ isLoading: isLoadingRef,
616
+ isLoaded: isLoadedRef,
617
+ isError: isErrorRef
618
+ });
619
+ return () => {
620
+ const {
621
+ el: elAttrs,
622
+ img: imgAttrs
623
+ } = attrsRef.value;
624
+ const styles = stylesRef.value;
625
+ const children = ctx.slots.default && ctx.slots.default();
626
+ return vue.createVNode("span", vue.mergeProps({
627
+ "class": ['v-busy-image', classesRef.value]
628
+ }, elAttrs, {
629
+ "style": styles
630
+ }), [!props.cover && vue.createVNode("img", vue.mergeProps({
631
+ "key": "img",
632
+ "ref": nodeRef,
633
+ "class": "v-busy-image__node"
634
+ }, imgAttrs, {
635
+ "onLoad": handleLoad,
636
+ "onError": handleError
637
+ }), null), !!children && vue.createVNode("span", {
638
+ "class": "v-busy-image__slot"
639
+ }, [children])]);
640
+ };
641
+ }
642
+
643
+ });
644
+
645
+ function imageIsReady(image) {
646
+ if (!image.complete) return false;
647
+ return image.naturalWidth + image.naturalHeight > 0 ? 'load' : 'error';
648
+ }
649
+
650
+ function isAvairableSrc(src) {
651
+ return typeof src === 'string' && src !== '';
652
+ }
653
+
403
654
  function extractRawGridValueClasses(value, prefix, getter) {
404
655
  if (typeof value !== 'object')
405
656
  return `${prefix}${getter ? getter(value) : value}`;
@@ -625,6 +876,162 @@ const VPaper = vue.defineComponent({
625
876
 
626
877
  });
627
878
 
879
+ const AVATAR_SIZES = ['sm', 'md', 'lg'];
880
+ function createAvatarProps() {
881
+ return { ...vueColorScheme.colorSchemeProps(),
882
+ ...vueUtils.navigationableInheritProps,
883
+ size: {
884
+ type: [String, Number],
885
+ default: 'md'
886
+ },
887
+ tile: Boolean,
888
+ rounded: Boolean,
889
+ disabled: Boolean,
890
+ src: String
891
+ };
892
+ }
893
+ const VAvatar = vue.defineComponent({
894
+ name: 'VAvatar',
895
+ inheritAttrs: false,
896
+ props: createAvatarProps(),
897
+
898
+ setup(props, ctx) {
899
+ const vui = useVui();
900
+ const defaults = vui.setting('buttonDefault');
901
+ const color = vueColorScheme.useColorClasses({
902
+ color: () => props.color || defaults.color,
903
+ variant: () => props.variant || defaults.variant
904
+ });
905
+ const navigationable = vueUtils.useNavigationable(ctx, {
906
+ clickableClassName: () => 'v-avatar--clickable',
907
+ linkFallbackTag: 'div'
908
+ });
909
+ const classes = vue.computed(() => {
910
+ const {
911
+ size
912
+ } = props;
913
+ return [{
914
+ 'v-avatar--tile': props.tile,
915
+ 'v-avatar--rounded': props.rounded
916
+ }, typeof size === 'string' && `v-avatar--${size}`];
917
+ });
918
+ const styles = vue.computed(() => {
919
+ const {
920
+ size
921
+ } = props;
922
+ if (typeof size !== 'number') return;
923
+ return {
924
+ '--avatar-size': `${size}px`
925
+ };
926
+ });
927
+ return () => {
928
+ const {
929
+ src
930
+ } = props;
931
+ const {
932
+ Tag,
933
+ attrs
934
+ } = navigationable.value;
935
+ return vue.createVNode(Tag, vue.mergeProps(attrs, {
936
+ "class": ['v-avatar', classes.value, color.colorClasses.value],
937
+ "style": styles.value
938
+ }), {
939
+ default: () => [!!src && vue.createVNode(VBusyImage, {
940
+ "class": "v-avatar__image",
941
+ "src": src,
942
+ "cover": true
943
+ }, null) || vueUtils.renderSlotOrEmpty(ctx.slots)]
944
+ });
945
+ };
946
+ }
947
+
948
+ });
949
+
950
+ const CHIP_SIZES = ['xs', 'sm', 'md', 'lg', 'xl'];
951
+ function createChipProps() {
952
+ return { ...vueColorScheme.colorSchemeProps(),
953
+ ...vueUtils.navigationableInheritProps,
954
+ size: {
955
+ type: String,
956
+ default: 'md'
957
+ },
958
+ startIcon: [String, Function],
959
+ endIcon: [String, Function],
960
+ label: Boolean,
961
+ disabled: Boolean
962
+ };
963
+ }
964
+
965
+ function resolveRawVChipIcon(raw, type) {
966
+ if (!raw) return;
967
+
968
+ if (typeof raw === 'function') {
969
+ return () => {
970
+ const child = raw();
971
+ if (child == null) return;
972
+ return vue.createVNode("span", {
973
+ "class": ['v-chip__icon', `v-chip__icon--${type}`]
974
+ }, [child]);
975
+ };
976
+ }
977
+
978
+ return () => vue.createVNode(VIcon, {
979
+ "class": ['v-chip__icon', `v-chip__icon--${type}`],
980
+ "name": raw
981
+ }, null);
982
+ }
983
+
984
+ const VChip = vue.defineComponent({
985
+ name: 'VChip',
986
+ inheritAttrs: false,
987
+ props: createChipProps(),
988
+
989
+ setup(props, ctx) {
990
+ const vui = useVui();
991
+ const defaults = vui.setting('buttonDefault');
992
+ const color = vueColorScheme.useColorClasses({
993
+ color: () => props.color || defaults.color,
994
+ variant: () => props.variant || defaults.variant
995
+ });
996
+ const startIcon = vue.computed(() => {
997
+ const _icon = resolveRawVChipIcon(props.startIcon, 'start');
998
+
999
+ return _icon && _icon();
1000
+ });
1001
+ const endIcon = vue.computed(() => {
1002
+ const _icon = resolveRawVChipIcon(props.endIcon, 'end');
1003
+
1004
+ return _icon && _icon();
1005
+ });
1006
+ const navigationable = vueUtils.useNavigationable(ctx, {
1007
+ clickableClassName: () => 'v-chip--clickable',
1008
+ linkFallbackTag: 'div'
1009
+ });
1010
+ const classes = vue.computed(() => {
1011
+ const {
1012
+ size
1013
+ } = props;
1014
+ return [{
1015
+ 'v-chip--label': props.label
1016
+ }, typeof size === 'string' && `v-chip--${size}`];
1017
+ });
1018
+ return () => {
1019
+ const {
1020
+ Tag,
1021
+ attrs
1022
+ } = navigationable.value;
1023
+ return vue.createVNode(Tag, vue.mergeProps(attrs, {
1024
+ "class": ['v-chip', classes.value, color.colorClasses.value]
1025
+ }), {
1026
+ default: () => [startIcon.value, vue.createVNode("span", {
1027
+ "class": "v-chip__content"
1028
+ }, [vueUtils.renderSlotOrEmpty(ctx.slots)]), endIcon.value]
1029
+ });
1030
+ };
1031
+ }
1032
+
1033
+ });
1034
+
628
1035
  function createCardProps() {
629
1036
  return { ...createPaperProps(),
630
1037
  ...vueUtils.navigationableInheritProps,
@@ -2753,8 +3160,8 @@ const VForm = vue.defineComponent({
2753
3160
  name: 'VForm',
2754
3161
  props: { ...props,
2755
3162
  ...createControlProps(),
2756
- ...vueKit.defineSlotsProps(),
2757
- disableAutoScroll: Boolean
3163
+ ...vueKit.defineSlotsProps() // disableAutoScroll: Boolean,
3164
+
2758
3165
  },
2759
3166
  emits,
2760
3167
 
@@ -2762,13 +3169,9 @@ const VForm = vue.defineComponent({
2762
3169
  const vui = useVui();
2763
3170
  const nodeControl = vueKit.useForm(props, ctx, {
2764
3171
  nodeType: VUI_FORM_SYMBOL,
2765
- onAutoValidateError: () => {
2766
- if (props.disableAutoScroll) return;
3172
+ scrollToElement: el => {
2767
3173
  const scroller = vueKit.getDocumentScroller();
2768
- const {
2769
- firstInvalidEl
2770
- } = nodeControl;
2771
- firstInvalidEl && scroller.toElement(firstInvalidEl, {
3174
+ return scroller.toElement(el, {
2772
3175
  offset: vui.getAutoScrollToElementOffsetTop()
2773
3176
  });
2774
3177
  }
@@ -2906,7 +3309,8 @@ const VTabs = vue.defineComponent({
2906
3309
  */
2907
3310
  withQuery: Boolean,
2908
3311
  ...vueUtils.defineSlotsProps(),
2909
- color: String
3312
+ color: String,
3313
+ onBeforeChange: Function
2910
3314
  },
2911
3315
  emits: {
2912
3316
  'update:modelValue': newValue => true,
@@ -3003,7 +3407,33 @@ const VTabs = vue.defineComponent({
3003
3407
  }
3004
3408
  }
3005
3409
 
3006
- function to(value) {
3410
+ async function to(value) {
3411
+ const {
3412
+ value: currentValue
3413
+ } = currentRef;
3414
+
3415
+ if (currentValue === value) {
3416
+ return;
3417
+ }
3418
+
3419
+ const {
3420
+ onBeforeChange
3421
+ } = props;
3422
+
3423
+ if (onBeforeChange) {
3424
+ let result = onBeforeChange(value, currentRef.value);
3425
+
3426
+ if (helpers.isPromise(result)) {
3427
+ result = await result;
3428
+ }
3429
+
3430
+ console.log(result);
3431
+
3432
+ if (result === false) {
3433
+ return;
3434
+ }
3435
+ }
3436
+
3007
3437
  currentRef.value = value;
3008
3438
  }
3009
3439
 
@@ -4488,11 +4918,15 @@ exports.VMenu = vueKit.VMenu;
4488
4918
  exports.VSnackbar = vueKit.VSnackbar;
4489
4919
  exports.VTooltip = vueKit.VTooltip;
4490
4920
  exports.ICON_NAMES = iconFont.ICON_NAMES;
4921
+ exports.AVATAR_SIZES = AVATAR_SIZES;
4922
+ exports.CHIP_SIZES = CHIP_SIZES;
4491
4923
  exports.CONTROL_FIELD_VARIANTS = CONTROL_FIELD_VARIANTS;
4492
4924
  exports.CONTROL_SIZES = CONTROL_SIZES;
4493
4925
  exports.PAGINATION_ALIGNS = PAGINATION_ALIGNS;
4494
4926
  exports.VApp = VApp;
4927
+ exports.VAvatar = VAvatar;
4495
4928
  exports.VBreadcrumbs = VBreadcrumbs;
4929
+ exports.VBusyImage = VBusyImage;
4496
4930
  exports.VButton = VButton;
4497
4931
  exports.VButtonGroup = VButtonGroup;
4498
4932
  exports.VCard = VCard;
@@ -4500,6 +4934,7 @@ exports.VCardActions = VCardActions;
4500
4934
  exports.VCardContent = VCardContent;
4501
4935
  exports.VCheckbox = VCheckbox;
4502
4936
  exports.VCheckboxGroup = VCheckboxGroup;
4937
+ exports.VChip = VChip;
4503
4938
  exports.VContentSwitcher = VContentSwitcher;
4504
4939
  exports.VDataTable = VDataTable;
4505
4940
  exports.VDrawerLayout = VDrawerLayout;
@@ -4519,6 +4954,7 @@ exports.VPaper = VPaper;
4519
4954
  exports.VRadio = VRadio;
4520
4955
  exports.VRadioGroup = VRadioGroup;
4521
4956
  exports.VSelect = VSelect;
4957
+ exports.VSkeltonLoaderBone = VSkeltonLoaderBone;
4522
4958
  exports.VSwitch = VSwitch;
4523
4959
  exports.VSwitchGroup = VSwitchGroup;
4524
4960
  exports.VTabs = VTabs;
@@ -4556,7 +4992,9 @@ exports.WysiwygLinkTool = WysiwygLinkTool;
4556
4992
  exports.WysiwygOrderedListTool = WysiwygOrderedListTool;
4557
4993
  exports.WysiwygTextColorTool = WysiwygTextColorTool;
4558
4994
  exports.configureDataTableDefaults = configureDataTableDefaults;
4995
+ exports.createAvatarProps = createAvatarProps;
4559
4996
  exports.createCardProps = createCardProps;
4997
+ exports.createChipProps = createChipProps;
4560
4998
  exports.createControlFieldProviderProps = createControlFieldProviderProps;
4561
4999
  exports.createControlProps = createControlProps;
4562
5000
  exports.createElevationProps = createElevationProps;
@@ -4579,6 +5017,7 @@ exports.renderNavigationItemInput = renderNavigationItemInput;
4579
5017
  exports.resolveNavigationItemInput = resolveNavigationItemInput;
4580
5018
  exports.resolveRawIconProp = resolveRawIconProp;
4581
5019
  exports.resolveRawWysiwygEditorTools = resolveRawWysiwygEditorTools;
5020
+ exports.splitAttrs = splitAttrs;
4582
5021
  exports.useControl = useControl;
4583
5022
  exports.useControlField = useControlField;
4584
5023
  exports.useElevation = useElevation;