@flux-ui/components 3.0.0-next.73 → 3.0.0-next.75

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.
Files changed (56) hide show
  1. package/dist/component/FluxKanbanColumn.vue.d.ts +1 -1
  2. package/dist/component/FluxSegmentedControl.vue.d.ts +18 -8
  3. package/dist/component/FluxSegmentedControlItem.vue.d.ts +20 -0
  4. package/dist/component/FluxSpacing.vue.d.ts +2 -1
  5. package/dist/component/index.d.ts +1 -4
  6. package/dist/component/primitive/FilterMenuRenderer.d.ts +3 -3
  7. package/dist/composable/index.d.ts +1 -0
  8. package/dist/composable/useSegmentedControlInjection.d.ts +2 -0
  9. package/dist/data/di.d.ts +10 -1
  10. package/dist/index.css +57 -158
  11. package/dist/index.js +321 -405
  12. package/dist/index.js.map +1 -1
  13. package/package.json +9 -9
  14. package/src/component/FluxBoxedIcon.vue +1 -1
  15. package/src/component/FluxCalendar.vue +6 -6
  16. package/src/component/FluxColorPicker.vue +5 -5
  17. package/src/component/FluxDropZone.vue +0 -1
  18. package/src/component/FluxDynamicView.vue +2 -2
  19. package/src/component/FluxExpandableGroup.vue +0 -1
  20. package/src/component/FluxFilterBase.vue +11 -11
  21. package/src/component/FluxFormFieldAddition.vue +2 -2
  22. package/src/component/FluxInfo.vue +2 -2
  23. package/src/component/FluxInfoStack.vue +2 -2
  24. package/src/component/FluxKanbanColumn.vue +2 -4
  25. package/src/component/FluxLayerPane.vue +1 -1
  26. package/src/component/FluxPagination.vue +4 -4
  27. package/src/component/FluxSegmentedControl.vue +64 -67
  28. package/src/component/FluxSegmentedControlItem.vue +98 -0
  29. package/src/component/FluxSpacing.vue +5 -1
  30. package/src/component/FluxSplitButton.vue +2 -2
  31. package/src/component/FluxTable.vue +3 -1
  32. package/src/component/FluxToolbar.vue +1 -1
  33. package/src/component/index.ts +1 -4
  34. package/src/component/primitive/FilterBadge.vue +11 -2
  35. package/src/component/primitive/FilterMenuRenderer.ts +4 -4
  36. package/src/composable/index.ts +1 -0
  37. package/src/composable/useSegmentedControlInjection.ts +13 -0
  38. package/src/css/component/Form.module.scss +2 -2
  39. package/src/css/component/SegmentedControl.module.scss +51 -23
  40. package/src/css/component/Spinner.module.scss +1 -0
  41. package/src/css/component/Visual.module.scss +1 -0
  42. package/src/css/mixin/tree-node.scss +3 -3
  43. package/src/data/di.ts +13 -1
  44. package/src/data/iconRegistry.ts +1 -1
  45. package/src/util/createDialogRenderer.ts +1 -1
  46. package/dist/component/FluxLegend.vue.d.ts +0 -8
  47. package/dist/component/FluxPercentageBar.vue.d.ts +0 -8
  48. package/dist/component/FluxSegmentedView.vue.d.ts +0 -9
  49. package/dist/component/FluxStatistic.vue.d.ts +0 -17
  50. package/src/component/FluxLegend.vue +0 -27
  51. package/src/component/FluxPercentageBar.vue +0 -47
  52. package/src/component/FluxSegmentedView.vue +0 -15
  53. package/src/component/FluxStatistic.vue +0 -82
  54. package/src/css/component/Legend.module.scss +0 -29
  55. package/src/css/component/PercentageBar.module.scss +0 -31
  56. package/src/css/component/Statistic.module.scss +0 -91
@@ -92,7 +92,6 @@ export { default as FluxItemMedia } from './FluxItemMedia.vue';
92
92
  export { default as FluxItemStack } from './FluxItemStack.vue';
93
93
  export { default as FluxLayerPane } from './FluxLayerPane.vue';
94
94
  export { default as FluxLayerPaneSecondary } from './FluxLayerPaneSecondary.vue';
95
- export { default as FluxLegend } from './FluxLegend.vue';
96
95
  export { default as FluxLink } from './FluxLink.vue';
97
96
  export { default as FluxMenu } from './FluxMenu.vue';
98
97
  export { default as FluxMenuCollapsible } from './FluxMenuCollapsible.vue';
@@ -115,7 +114,6 @@ export { default as FluxPaneGroup } from './FluxPaneGroup.vue';
115
114
  export { default as FluxPaneHeader } from './FluxPaneHeader.vue';
116
115
  export { default as FluxPaneIllustration } from './FluxPaneIllustration.vue';
117
116
  export { default as FluxPaneMedia } from './FluxPaneMedia.vue';
118
- export { default as FluxPercentageBar } from './FluxPercentageBar.vue';
119
117
  export { default as FluxPersona } from './FluxPersona.vue';
120
118
  export { default as FluxPlaceholder } from './FluxPlaceholder.vue';
121
119
  export { default as FluxPressable } from './FluxPressable.vue';
@@ -130,7 +128,7 @@ export { default as FluxScroller } from './FluxScroller.vue';
130
128
  export { default as FluxSecondaryButton } from './FluxSecondaryButton.vue';
131
129
  export { default as FluxSecondaryLinkButton } from './FluxSecondaryLinkButton.vue';
132
130
  export { default as FluxSegmentedControl } from './FluxSegmentedControl.vue';
133
- export { default as FluxSegmentedView } from './FluxSegmentedView.vue';
131
+ export { default as FluxSegmentedControlItem } from './FluxSegmentedControlItem.vue';
134
132
  export { default as FluxSeparator } from './FluxSeparator.vue';
135
133
  export { default as FluxSlideOver } from './FluxSlideOver.vue';
136
134
  export { default as FluxSnackbar } from './FluxSnackbar.vue';
@@ -141,7 +139,6 @@ export { default as FluxSpinner } from './FluxSpinner.vue';
141
139
  export { default as FluxSplitButton } from './FluxSplitButton.vue';
142
140
  export { default as FluxSplitView } from './FluxSplitView.vue';
143
141
  export { default as FluxSplitViewPane } from './FluxSplitViewPane.vue';
144
- export { default as FluxStatistic } from './FluxStatistic.vue';
145
142
  export { default as FluxStepper } from './FluxStepper.vue';
146
143
  export { default as FluxStepperStep } from './FluxStepperStep.vue';
147
144
  export { default as FluxStepperSteps } from './FluxStepperSteps.vue';
@@ -37,7 +37,16 @@
37
37
  emit('click', evt);
38
38
  }
39
39
 
40
- watch([() => item, () => value], async () => {
41
- valueLabel.value = await unref(getValueLabel)(value) ?? undefined;
40
+ watch([() => item, () => value], async ([, nextValue], _prev, onCleanup) => {
41
+ let cancelled = false;
42
+ onCleanup(() => {
43
+ cancelled = true;
44
+ });
45
+
46
+ const nextLabel = await unref(getValueLabel)(nextValue);
47
+
48
+ if (!cancelled) {
49
+ valueLabel.value = nextLabel ?? undefined;
50
+ }
42
51
  }, {deep: true, immediate: true});
43
52
  </script>
@@ -1,5 +1,5 @@
1
1
  import type { FluxFilterDefinition, FluxFilterValue } from '@flux-ui/types';
2
- import { defineComponent, h, isVNode, type VNode, unref } from 'vue';
2
+ import { defineComponent, h, isVNode, type PropType, unref, type VNode } from 'vue';
3
3
  import { useFilterInjection } from '~flux/components/composable';
4
4
  import FluxMenuGroup from '../FluxMenuGroup.vue';
5
5
  import FluxSeparator from '../FluxSeparator.vue';
@@ -8,7 +8,7 @@ import FilterItem from './FilterItem.vue';
8
8
  export const FilterMenuRenderer = defineComponent({
9
9
  props: {
10
10
  menuItems: {required: true, type: Array},
11
- navigate: {required: true, type: Function}
11
+ navigate: {required: true, type: Function as PropType<(name: string) => void>}
12
12
  },
13
13
 
14
14
  setup(props) {
@@ -18,7 +18,7 @@ export const FilterMenuRenderer = defineComponent({
18
18
  }
19
19
  });
20
20
 
21
- function renderFilterGroup(group: (FluxFilterDefinition | VNode)[], index: number, navigate: Function, state: Record<string, FluxFilterValue>): VNode[] {
21
+ function renderFilterGroup(group: (FluxFilterDefinition | VNode)[], index: number, navigate: (name: string) => void, state: Record<string, FluxFilterValue>): VNode[] {
22
22
  const slot: VNode[] = [];
23
23
 
24
24
  if (index > 0) {
@@ -32,7 +32,7 @@ function renderFilterGroup(group: (FluxFilterDefinition | VNode)[], index: numbe
32
32
  return slot;
33
33
  }
34
34
 
35
- function renderFilterItem(item: FluxFilterDefinition | VNode, navigate: Function, state: Record<string, FluxFilterValue>): VNode {
35
+ function renderFilterItem(item: FluxFilterDefinition | VNode, navigate: (name: string) => void, state: Record<string, FluxFilterValue>): VNode {
36
36
  if (isVNode(item)) {
37
37
  return item;
38
38
  }
@@ -9,6 +9,7 @@ export { default as useFilterInjection } from './useFilterInjection';
9
9
  export { default as useFlyoutInjection } from './useFlyoutInjection';
10
10
  export { default as useFormFieldInjection } from './useFormFieldInjection';
11
11
  export { default as useKanbanInjection } from './useKanbanInjection';
12
+ export { default as useSegmentedControlInjection } from './useSegmentedControlInjection';
12
13
  export { default as useTabBarInjection } from './useTabBarInjection';
13
14
  export { default as useTableInjection } from './useTableInjection';
14
15
  export { default as useTooltipInjection } from './useTooltipInjection';
@@ -0,0 +1,13 @@
1
+ import type { FluxSize } from '@flux-ui/types';
2
+ import { inject, ref } from 'vue';
3
+ import { FluxSegmentedControlInjectionKey, type FluxSegmentedControlValue } from '~flux/components/data';
4
+
5
+ export default function () {
6
+ return inject(FluxSegmentedControlInjectionKey, {
7
+ modelValue: ref<FluxSegmentedControlValue | undefined>(undefined),
8
+ size: ref<FluxSize>('medium'),
9
+ select: () => undefined,
10
+ registerItem: () => undefined,
11
+ unregisterItem: () => undefined
12
+ });
13
+ }
@@ -90,8 +90,8 @@
90
90
 
91
91
  .formFieldHeader {
92
92
  display: flex;
93
- margin-bottom: 0;
94
93
  width: 100%;
94
+ margin-bottom: 0;
95
95
  align-items: center;
96
96
  align-self: flex-start;
97
97
  gap: 6px;
@@ -274,9 +274,9 @@
274
274
  }
275
275
 
276
276
  &::-webkit-color-swatch-wrapper {
277
+ width: calc(100% + 24px);
277
278
  margin: 0 -12px;
278
279
  padding: 3px;
279
- width: calc(100% + 24px);
280
280
  }
281
281
  }
282
282
 
@@ -3,7 +3,8 @@
3
3
  .segmentedControl {
4
4
  position: relative;
5
5
  align-items: center;
6
- gap: 1px;
6
+ gap: 3px;
7
+ padding: 3px;
7
8
  background: var(--gray-50);
8
9
  border: 1px solid var(--surface-stroke);
9
10
  border-radius: var(--radius);
@@ -24,60 +25,87 @@
24
25
 
25
26
  .segmentedControlHighlight {
26
27
  position: absolute;
27
- top: 0;
28
- bottom: 0;
28
+ top: 3px;
29
+ bottom: 3px;
29
30
  background: var(--surface);
30
- border-radius: calc(var(--radius) - 2px);
31
- box-shadow: var(--shadow-sm);
31
+ border-radius: calc(var(--radius) - 3px);
32
+ box-shadow: var(--shadow-md);
32
33
  outline: 1px solid var(--surface-stroke);
33
34
  pointer-events: none;
34
35
  transition: 300ms var(--swift-out);
35
36
  transition-property: left, width;
36
- translate: -1px 0;
37
37
  }
38
38
 
39
39
  .segmentedControlItem {
40
+ position: relative;
40
41
  display: flex;
41
- height: 36px;
42
- padding-left: 12px;
43
- padding-right: 12px;
44
42
  align-items: center;
45
43
  flex: 1 1 0;
46
- gap: 9px;
47
44
  justify-content: center;
48
45
  background: none;
49
46
  border: 0;
50
- border-radius: var(--radius);
47
+ border-radius: var(--radius-full);
51
48
  color: var(--foreground);
52
49
  cursor: pointer;
53
50
  font-weight: 500;
54
51
  text-align: center;
55
- transition: 300ms var(--swift-out);
56
- transition-property: background, color;
52
+ transition: color 300ms var(--swift-out);
53
+ white-space: nowrap;
57
54
 
58
55
  @include mixin.hover {
59
- background: var(--gray-100);
56
+ color: var(--foreground-prominent);
60
57
  }
61
58
 
59
+ @include mixin.focus-ring(3px);
60
+
62
61
  &.isActive {
63
- background: none;
64
62
  color: var(--foreground-prominent);
65
63
  cursor: default;
66
64
  }
67
65
 
66
+ &:disabled {
67
+ opacity: .5;
68
+ pointer-events: none;
69
+ }
70
+
68
71
  > * {
69
72
  position: relative;
73
+ z-index: 1;
70
74
  }
71
- }
72
75
 
73
- .segmentedControlSeparator {
74
- height: 15px;
75
- width: 1px;
76
- flex-shrink: 0;
77
- background: var(--surface-stroke);
78
- transition: opacity 300ms var(--swift-out);
76
+ & + &::before {
77
+ content: '';
78
+ position: absolute;
79
+ top: 50%;
80
+ left: -2px;
81
+ height: 15px;
82
+ width: 2px;
83
+ background: var(--gray-100);
84
+ border-radius: 1px;
85
+ transition: opacity 300ms var(--swift-out);
86
+ translate: 0 -50%;
87
+ }
79
88
 
80
- &.isActive {
89
+ &.isActive::before,
90
+ &.isActive + &::before {
81
91
  opacity: 0;
82
92
  }
83
93
  }
94
+
95
+ .isSmall {
96
+ height: 30px;
97
+ padding: 0 12px;
98
+ gap: 9px;
99
+ }
100
+
101
+ .isMedium {
102
+ height: 36px;
103
+ padding: 0 15px;
104
+ gap: 9px;
105
+ }
106
+
107
+ .isLarge {
108
+ height: 48px;
109
+ padding: 0 21px;
110
+ gap: 12px;
111
+ }
@@ -30,6 +30,7 @@
30
30
  from {
31
31
  transform: rotate(0deg);
32
32
  }
33
+
33
34
  to {
34
35
  transform: rotate(1turn);
35
36
  }
@@ -64,6 +64,7 @@
64
64
  from {
65
65
  --shine-degrees: 0deg;
66
66
  }
67
+
67
68
  to {
68
69
  --shine-degrees: 360deg;
69
70
  }
@@ -15,12 +15,12 @@
15
15
  pointer-events: none;
16
16
 
17
17
  &.hasLine::before {
18
- content: '';
19
18
  position: absolute;
20
19
  top: 0;
21
20
  bottom: 0;
22
21
  left: 9px;
23
22
  width: 1px;
23
+ content: '';
24
24
  background: var(--surface-stroke);
25
25
  }
26
26
  }
@@ -35,24 +35,24 @@
35
35
 
36
36
  // Non-last siblings: full-height vertical continuation line
37
37
  &:not(.isLast)::before {
38
- content: '';
39
38
  position: absolute;
40
39
  top: 0;
41
40
  bottom: 0;
42
41
  left: 9px;
43
42
  width: 1px;
43
+ content: '';
44
44
  background: var(--surface-stroke);
45
45
  }
46
46
 
47
47
  // Rounded elbow: vertical segment from top to midpoint, curves right to expand area
48
48
  // Overlaps the ::before vertical line for non-last nodes (same position, same color)
49
49
  &::after {
50
- content: '';
51
50
  position: absolute;
52
51
  top: 0;
53
52
  bottom: 50%;
54
53
  left: 9px;
55
54
  right: 0;
55
+ content: '';
56
56
  border-left: 1px solid var(--surface-stroke);
57
57
  border-bottom: 1px solid var(--surface-stroke);
58
58
  border-bottom-left-radius: 6px;
package/src/data/di.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { FluxFilterDefinition, FluxFilterState, FluxFilterValue } from '@flux-ui/types';
1
+ import type { FluxFilterDefinition, FluxFilterState, FluxFilterValue, FluxSize } from '@flux-ui/types';
2
2
  import type { DateTime } from 'luxon';
3
3
  import type { ComponentInternalInstance, ComputedRef, InjectionKey, Ref, VNode } from 'vue';
4
4
 
@@ -10,6 +10,7 @@ export const FluxExpandableGroupInjectionKey: InjectionKey<FluxExpandableGroupIn
10
10
  export const FluxFlyoutInjectionKey: InjectionKey<FluxFlyoutInjection> = Symbol();
11
11
  export const FluxFilterInjectionKey: InjectionKey<FluxFilterInjection> = Symbol();
12
12
  export const FluxFormFieldInjectionKey: InjectionKey<FluxFormFieldInjection> = Symbol();
13
+ export const FluxSegmentedControlInjectionKey: InjectionKey<FluxSegmentedControlInjection> = Symbol();
13
14
  export const FluxSplitViewInjectionKey: InjectionKey<FluxSplitViewInjection> = Symbol();
14
15
  export const FluxTabBarInjectionKey: InjectionKey<FluxTabBarInjection> = Symbol();
15
16
  export const FluxTableInjectionKey: InjectionKey<FluxTableInjection> = Symbol();
@@ -168,6 +169,17 @@ export type FluxSplitViewInjection = {
168
169
  getPaneIndex(id: number): number;
169
170
  };
170
171
 
172
+ export type FluxSegmentedControlValue = string | number;
173
+
174
+ export type FluxSegmentedControlInjection = {
175
+ readonly modelValue: Ref<FluxSegmentedControlValue | undefined>;
176
+ readonly size: Ref<FluxSize>;
177
+
178
+ select(value: FluxSegmentedControlValue): void;
179
+ registerItem(element: HTMLElement, value: FluxSegmentedControlValue): void;
180
+ unregisterItem(element: HTMLElement): void;
181
+ };
182
+
171
183
  export type FluxTabBarInjection = {
172
184
  readonly isPills: Ref<boolean>;
173
185
 
@@ -17,7 +17,7 @@ export function fluxRegisterIcons(icons: Icons): void {
17
17
  acc[iconName as FluxIconName] = icon;
18
18
 
19
19
  if (Array.isArray(icon[2])) {
20
- icon[2].forEach((iconName: string) => acc[iconName as FluxIconName] = icon);
20
+ icon[2].forEach((alias: string) => acc[alias as FluxIconName] = icon);
21
21
  }
22
22
 
23
23
  return acc;
@@ -14,7 +14,7 @@ let DIALOG_ID = 0;
14
14
 
15
15
  export default function (attrs: object, props: Props, emit: Emit, slots: Slots, className: string, transition: Component): RenderFunction {
16
16
  const dialogId = `flux-dialog:${DIALOG_ID++}`;
17
- let unregister: Function | null = null;
17
+ let unregister: VoidFunction | null = null;
18
18
  let zIndex = 0;
19
19
 
20
20
  const dialogRef = ref<HTMLElement>();
@@ -1,8 +0,0 @@
1
- import { FluxDirection, FluxLegendObject } from '@flux-ui/types';
2
- import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
- type __VLS_Props = {
4
- readonly direction?: FluxDirection;
5
- readonly items: FluxLegendObject[];
6
- };
7
- declare const _default: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
8
- export default _default;
@@ -1,8 +0,0 @@
1
- import { FluxPercentageBarItemObject } from '@flux-ui/types';
2
- import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
- type __VLS_Props = {
4
- readonly isLegendVisible?: boolean;
5
- readonly items: FluxPercentageBarItemObject[];
6
- };
7
- declare const _default: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
8
- export default _default;
@@ -1,9 +0,0 @@
1
- import { DefineComponent, ExtractPropTypes, VNode, RendererNode, RendererElement, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
- declare const _default: DefineComponent<ExtractPropTypes<{
3
- index: NumberConstructor;
4
- }>, () => VNode<RendererNode, RendererElement, {
5
- [key: string]: any;
6
- }>, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly< ExtractPropTypes<{
7
- index: NumberConstructor;
8
- }>> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
9
- export default _default;
@@ -1,17 +0,0 @@
1
- import { FluxColor, FluxDirection, FluxIconName } from '@flux-ui/types';
2
- import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
- type __VLS_Props = {
4
- readonly changeColor?: FluxColor;
5
- readonly changeIcon?: FluxIconName;
6
- readonly changeValue?: string | number | null;
7
- readonly color?: FluxColor;
8
- readonly direction?: FluxDirection;
9
- readonly icon?: FluxIconName;
10
- readonly imageSrc?: string;
11
- readonly imageAlt?: string;
12
- readonly isLoading?: boolean;
13
- readonly label: string;
14
- readonly value?: string | number | null;
15
- };
16
- declare const _default: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, any>;
17
- export default _default;
@@ -1,27 +0,0 @@
1
- <template>
2
- <div :class="direction === 'horizontal' ? $style.legendHorizontal : $style.legendVertical">
3
- <span
4
- v-for="(item, index) of items"
5
- :key="index"
6
- :class="$style.legendItem"
7
- :style="{
8
- '--color': item.color
9
- }">
10
- {{ item.label }}
11
- </span>
12
- </div>
13
- </template>
14
-
15
- <script
16
- lang="ts"
17
- setup>
18
- import type { FluxDirection, FluxLegendObject } from '@flux-ui/types';
19
- import $style from '~flux/components/css/component/Legend.module.scss';
20
-
21
- const {
22
- direction = 'horizontal'
23
- } = defineProps<{
24
- readonly direction?: FluxDirection;
25
- readonly items: FluxLegendObject[];
26
- }>();
27
- </script>
@@ -1,47 +0,0 @@
1
- <template>
2
- <div :class="$style.percentageBar">
3
- <div :class="$style.percentageBarTrack">
4
- <FluxTooltip
5
- v-for="(item, index) of items"
6
- :key="index">
7
- <template #content>
8
- <div :class="$style.percentageBarTooltip">
9
- <FluxIcon
10
- v-if="item.icon"
11
- :name="item.icon"
12
- :size="16"/>
13
-
14
- <span>{{ formatPercentage(item.value) }} {{ item.label }}</span>
15
- </div>
16
- </template>
17
-
18
- <div
19
- :class="$style.percentageBarSegment"
20
- :style="{
21
- backgroundColor: item.color,
22
- flexGrow: item.value
23
- }"/>
24
- </FluxTooltip>
25
- </div>
26
-
27
- <FluxLegend
28
- v-if="isLegendVisible"
29
- :items="items"/>
30
- </div>
31
- </template>
32
-
33
- <script
34
- lang="ts"
35
- setup>
36
- import { formatPercentage } from '@basmilius/utils';
37
- import type { FluxPercentageBarItemObject } from '@flux-ui/types';
38
- import FluxIcon from './FluxIcon.vue';
39
- import FluxLegend from './FluxLegend.vue';
40
- import FluxTooltip from './FluxTooltip.vue';
41
- import $style from '~flux/components/css/component/PercentageBar.module.scss';
42
-
43
- defineProps<{
44
- readonly isLegendVisible?: boolean;
45
- readonly items: FluxPercentageBarItemObject[];
46
- }>();
47
- </script>
@@ -1,15 +0,0 @@
1
- <script lang="ts">
2
- import { defineComponent } from 'vue';
3
-
4
- export default defineComponent({
5
- props: {
6
- index: Number
7
- },
8
- setup(props, {slots}) {
9
- return () => {
10
- const items = slots.default!();
11
- return items[props.index!];
12
- };
13
- }
14
- });
15
- </script>
@@ -1,82 +0,0 @@
1
- <template>
2
- <FluxPane
3
- :class="clsx(
4
- direction === 'horizontal' && $style.statisticHorizontal,
5
- direction === 'vertical' && $style.statisticVertical,
6
- color === 'gray' && $style.isGray,
7
- color === 'primary' && $style.isPrimary,
8
- color === 'danger' && $style.isDanger,
9
- color === 'info' && $style.isInfo,
10
- color === 'success' && $style.isSuccess,
11
- color === 'warning' && $style.isWarning
12
- )"
13
- :is-loading="isLoading">
14
- <FluxBoxedIcon
15
- v-if="icon"
16
- :class="$style.statisticIcon"
17
- :color="color"
18
- :name="icon"
19
- :size="48"/>
20
-
21
- <div v-else-if="imageSrc">
22
- <img
23
- :class="$style.statisticImage"
24
- :src="imageSrc"
25
- :alt="imageAlt"/>
26
- </div>
27
-
28
- <div :class="$style.statisticData">
29
- <span>{{ label }}</span>
30
- <strong>{{ value ?? MDASH }}</strong>
31
- </div>
32
-
33
- <div
34
- v-if="changeIcon || changeValue"
35
- :class="clsx(
36
- $style.statisticChange,
37
- changeColor === 'gray' && $style.isGray,
38
- changeColor === 'primary' && $style.isPrimary,
39
- changeColor === 'danger' && $style.isDanger,
40
- changeColor === 'info' && $style.isInfo,
41
- changeColor === 'success' && $style.isSuccess,
42
- changeColor === 'warning' && $style.isWarning
43
- )">
44
- <span v-if="changeValue">{{ changeValue }}</span>
45
-
46
- <FluxIcon
47
- v-if="changeIcon"
48
- :name="changeIcon"
49
- :size="14"/>
50
- </div>
51
- </FluxPane>
52
- </template>
53
-
54
- <script
55
- lang="ts"
56
- setup>
57
- import { MDASH } from '@basmilius/utils';
58
- import type { FluxColor, FluxDirection, FluxIconName } from '@flux-ui/types';
59
- import { clsx } from 'clsx';
60
- import FluxBoxedIcon from './FluxBoxedIcon.vue';
61
- import FluxIcon from './FluxIcon.vue';
62
- import FluxPane from './FluxPane.vue';
63
- import $style from '~flux/components/css/component/Statistic.module.scss';
64
-
65
- const {
66
- changeColor = 'gray',
67
- color = 'gray',
68
- direction = 'horizontal'
69
- } = defineProps<{
70
- readonly changeColor?: FluxColor;
71
- readonly changeIcon?: FluxIconName;
72
- readonly changeValue?: string | number | null;
73
- readonly color?: FluxColor;
74
- readonly direction?: FluxDirection;
75
- readonly icon?: FluxIconName;
76
- readonly imageSrc?: string;
77
- readonly imageAlt?: string;
78
- readonly isLoading?: boolean;
79
- readonly label: string;
80
- readonly value?: string | number | null;
81
- }>();
82
- </script>
@@ -1,29 +0,0 @@
1
- .legendHorizontal {
2
- display: flex;
3
- gap: 12px 18px;
4
- }
5
-
6
- .legendVertical {
7
- display: flex;
8
- flex-flow: column;
9
- gap: 12px;
10
- }
11
-
12
- .legendItem {
13
- display: flex;
14
- flex-flow: row nowrap;
15
- gap: 6px;
16
- font-size: 14px;
17
- line-height: 1;
18
-
19
- &::before {
20
- display: block;
21
- margin-top: 1px;
22
- height: 12px;
23
- width: 12px;
24
- content: '';
25
- flex: 0 0 12px;
26
- background: var(--color);
27
- border-radius: var(--radius-full);
28
- }
29
- }
@@ -1,31 +0,0 @@
1
- .percentageBar {
2
- display: flex;
3
- flex-flow: column;
4
- gap: 12px;
5
- }
6
-
7
- .percentageBarSegment {
8
- height: 12px;
9
- border-radius: calc(var(--radius) / 3);
10
- transition: var(--transition-default);
11
- transition-property: height, margin, flex-grow;
12
-
13
- &:hover {
14
- height: 16px;
15
- margin-top: -2px;
16
- margin-bottom: -2px;
17
- }
18
- }
19
-
20
- .percentageBarTooltip {
21
- display: flex;
22
- align-items: center;
23
- flex-flow: row nowrap;
24
- gap: 9px;
25
- }
26
-
27
- .percentageBarTrack {
28
- display: flex;
29
- flex-flow: row nowrap;
30
- gap: 3px;
31
- }