@flux-ui/components 3.0.0-next.61 → 3.0.0-next.64
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/component/FluxActionStack.vue.d.ts +25 -19
- package/dist/component/FluxAspectRatio.vue.d.ts +4 -3
- package/dist/component/FluxBorderShine.vue.d.ts +1 -1
- package/dist/component/FluxCalendar.vue.d.ts +2 -6
- package/dist/component/FluxContainer.vue.d.ts +3 -2
- package/dist/component/FluxFilter.vue.d.ts +6 -7
- package/dist/component/FluxFilterBar.vue.d.ts +5 -4
- package/dist/component/FluxFilterBase.vue.d.ts +14 -11
- package/dist/component/FluxFilterDate.vue.d.ts +3 -6
- package/dist/component/FluxFilterDateRange.vue.d.ts +3 -6
- package/dist/component/FluxFilterOption.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptionAsync.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptions.vue.d.ts +3 -6
- package/dist/component/FluxFilterOptionsAsync.vue.d.ts +3 -6
- package/dist/component/FluxFilterRange.vue.d.ts +3 -7
- package/dist/component/FluxFilterWindow.vue.d.ts +3 -8
- package/dist/component/FluxFlex.vue.d.ts +30 -0
- package/dist/component/{FluxRow.vue.d.ts → FluxFlexItem.vue.d.ts} +5 -3
- package/dist/component/FluxGrid.vue.d.ts +3 -2
- package/dist/component/FluxGridColumn.vue.d.ts +3 -2
- package/dist/component/FluxKanbanColumn.vue.d.ts +3 -0
- package/dist/component/FluxScroller.vue.d.ts +32 -0
- package/dist/component/{FluxStack.vue.d.ts → FluxSplitView.vue.d.ts} +7 -6
- package/dist/component/{FluxColumn.vue.d.ts → FluxSplitViewPane.vue.d.ts} +4 -1
- package/dist/component/FluxSticky.vue.d.ts +34 -0
- package/dist/component/index.d.ts +6 -3
- package/dist/component/primitive/FilterBadge.vue.d.ts +2 -2
- package/dist/component/primitive/FilterItem.vue.d.ts +3 -2
- package/dist/component/primitive/SelectBase.vue.d.ts +4 -4
- package/dist/composable/private/index.d.ts +1 -0
- package/dist/composable/private/useSplitView.d.ts +23 -0
- package/dist/data/di.d.ts +19 -2
- package/dist/data/index.d.ts +0 -1
- package/dist/index.css +778 -526
- package/dist/index.d.ts +2 -0
- package/dist/index.js +10381 -9732
- package/dist/index.js.map +1 -1
- package/dist/util/defineFilter.d.ts +3 -0
- package/dist/util/filter.d.ts +7 -0
- package/dist/util/index.d.ts +2 -0
- package/dist/vite/defineFilterMacro.d.ts +3 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite.js +217 -0
- package/dist/vite.js.map +1 -0
- package/package.json +11 -7
- package/src/component/FluxActionBar.vue +3 -4
- package/src/component/FluxActionStack.vue +3 -3
- package/src/component/FluxAspectRatio.vue +5 -3
- package/src/component/FluxBadgeStack.vue +4 -4
- package/src/component/FluxButtonStack.vue +6 -4
- package/src/component/FluxCalendar.vue +160 -157
- package/src/component/FluxContainer.vue +4 -2
- package/src/component/FluxFilter.vue +10 -11
- package/src/component/FluxFilterBar.vue +71 -15
- package/src/component/FluxFilterBase.vue +65 -51
- package/src/component/FluxFilterDate.vue +24 -8
- package/src/component/FluxFilterDateRange.vue +27 -9
- package/src/component/FluxFilterOption.vue +20 -10
- package/src/component/FluxFilterOptionAsync.vue +19 -11
- package/src/component/FluxFilterOptions.vue +26 -11
- package/src/component/FluxFilterOptionsAsync.vue +28 -12
- package/src/component/FluxFilterRange.vue +25 -11
- package/src/component/FluxFilterWindow.vue +25 -11
- package/src/component/FluxFlex.vue +53 -0
- package/src/component/FluxFlexItem.vue +40 -0
- package/src/component/FluxFormDateTimeInput.vue +3 -4
- package/src/component/FluxGrid.vue +4 -2
- package/src/component/FluxGridColumn.vue +4 -2
- package/src/component/FluxInfoStack.vue +3 -3
- package/src/component/FluxItemStack.vue +4 -4
- package/src/component/FluxKanbanColumn.vue +16 -3
- package/src/component/FluxNoticeStack.vue +3 -3
- package/src/component/FluxPane.vue +10 -7
- package/src/component/FluxProgressBar.vue +4 -3
- package/src/component/FluxScroller.vue +63 -0
- package/src/component/FluxSplitView.vue +101 -0
- package/src/component/FluxSplitViewPane.vue +23 -0
- package/src/component/FluxSticky.vue +67 -0
- package/src/component/FluxTagStack.vue +4 -4
- package/src/component/FluxToolbar.vue +3 -4
- package/src/component/FluxToolbarGroup.vue +3 -4
- package/src/component/FluxTooltipProvider.vue +56 -25
- package/src/component/index.ts +6 -3
- package/src/component/primitive/FilterBadge.vue +2 -2
- package/src/component/primitive/FilterItem.vue +4 -2
- package/src/component/primitive/FilterMenuRenderer.ts +10 -5
- package/src/component/primitive/FilterOptionBase.vue +1 -1
- package/src/composable/private/index.ts +1 -0
- package/src/composable/private/useAsyncFilterOptions.ts +1 -1
- package/src/composable/private/useFilterOption.ts +1 -1
- package/src/composable/private/useSplitView.ts +249 -0
- package/src/composable/useFilterInjection.ts +3 -1
- package/src/css/component/Calendar.module.scss +11 -17
- package/src/css/component/Comment.module.scss +3 -11
- package/src/css/component/Filter.module.scss +6 -2
- package/src/css/component/Flex.module.scss +84 -0
- package/src/css/component/Flyout.module.scss +1 -0
- package/src/css/component/Kanban.module.scss +31 -28
- package/src/css/component/LayerPane.module.scss +5 -0
- package/src/css/component/Layout.module.scss +0 -41
- package/src/css/component/Legend.module.scss +3 -4
- package/src/css/component/Menu.module.scss +1 -0
- package/src/css/component/Notice.module.scss +1 -1
- package/src/css/component/Pagination.module.scss +1 -1
- package/src/css/component/Pane.module.scss +1 -1
- package/src/css/component/Progress.module.scss +2 -2
- package/src/css/component/Scroller.module.scss +109 -0
- package/src/css/component/SplitView.module.scss +78 -0
- package/src/css/component/Sticky.module.scss +35 -0
- package/src/css/component/Tab.module.scss +1 -0
- package/src/css/component/Table.module.scss +1 -0
- package/src/css/component/Tooltip.module.scss +14 -0
- package/src/data/di.ts +22 -2
- package/src/data/index.ts +0 -1
- package/src/index.ts +11 -0
- package/src/util/defineFilter.ts +10 -0
- package/src/util/filter.ts +63 -0
- package/src/util/index.ts +2 -0
- package/src/vite/defineFilterMacro.ts +335 -0
- package/src/vite/index.ts +1 -0
- package/dist/data/filter.d.ts +0 -7
- package/src/component/FluxColumn.vue +0 -24
- package/src/component/FluxRow.vue +0 -24
- package/src/component/FluxStack.vue +0 -41
- package/src/data/filter.ts +0 -165
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
const {tooltip} = useFluxStore();
|
|
22
22
|
|
|
23
23
|
const elementRef = ref<HTMLElement | null>(null);
|
|
24
|
+
const hostRef = ref<HTMLElement | null>(null);
|
|
24
25
|
const position = ref<PositionData | null>(null);
|
|
25
26
|
|
|
26
27
|
const content = computed(() => unref(tooltip) ? unref(tooltip)!.contentSlot?.() ?? [unref(tooltip)!.content] : null);
|
|
@@ -66,34 +67,64 @@
|
|
|
66
67
|
|
|
67
68
|
watch(content, () => requestAnimationFrame(calculate));
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
70
|
+
watch(has, isVisible => {
|
|
71
|
+
if (!isVisible) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class: pos
|
|
80
|
-
? clsx(
|
|
81
|
-
pos.transition === 'above' && $style.tooltipAbove,
|
|
82
|
-
pos.transition === 'below' && $style.tooltipBelow,
|
|
83
|
-
pos.transition === 'end' && $style.tooltipEnd,
|
|
84
|
-
pos.transition === 'start' && $style.tooltipStart
|
|
85
|
-
)
|
|
86
|
-
: $style.tooltip,
|
|
87
|
-
style: {
|
|
88
|
-
'--x': pos?.x ?? undefined,
|
|
89
|
-
'--y': pos?.y ?? undefined,
|
|
90
|
-
'--arrowAngle': pos?.arrowAngle ?? undefined,
|
|
91
|
-
'--arrowX': pos?.arrowX ?? undefined,
|
|
92
|
-
'--arrowY': pos?.arrowY ?? undefined
|
|
93
|
-
}
|
|
94
|
-
}, unref(content));
|
|
75
|
+
const host = unrefTemplateElement(hostRef);
|
|
76
|
+
|
|
77
|
+
if (host && !host.matches(':popover-open')) {
|
|
78
|
+
host.showPopover();
|
|
95
79
|
}
|
|
96
80
|
});
|
|
81
|
+
|
|
82
|
+
return () => h('div', {
|
|
83
|
+
ref: hostRef,
|
|
84
|
+
popover: 'manual',
|
|
85
|
+
class: $style.tooltipHost
|
|
86
|
+
}, [
|
|
87
|
+
h(FluxTooltipTransition, {
|
|
88
|
+
onAfterLeave: () => {
|
|
89
|
+
if (unref(has)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const host = unrefTemplateElement(hostRef);
|
|
94
|
+
|
|
95
|
+
if (host && host.matches(':popover-open')) {
|
|
96
|
+
host.hidePopover();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
default: () => {
|
|
101
|
+
if (!unref(has)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const pos = unref(position);
|
|
106
|
+
|
|
107
|
+
return h('div', {
|
|
108
|
+
ref: elementRef,
|
|
109
|
+
class: pos
|
|
110
|
+
? clsx(
|
|
111
|
+
pos.transition === 'above' && $style.tooltipAbove,
|
|
112
|
+
pos.transition === 'below' && $style.tooltipBelow,
|
|
113
|
+
pos.transition === 'end' && $style.tooltipEnd,
|
|
114
|
+
pos.transition === 'start' && $style.tooltipStart
|
|
115
|
+
)
|
|
116
|
+
: $style.tooltip,
|
|
117
|
+
style: {
|
|
118
|
+
'--x': pos?.x ?? undefined,
|
|
119
|
+
'--y': pos?.y ?? undefined,
|
|
120
|
+
'--arrowAngle': pos?.arrowAngle ?? undefined,
|
|
121
|
+
'--arrowX': pos?.arrowX ?? undefined,
|
|
122
|
+
'--arrowY': pos?.arrowY ?? undefined
|
|
123
|
+
}
|
|
124
|
+
}, unref(content));
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
]);
|
|
97
128
|
});
|
|
98
129
|
|
|
99
130
|
function calculateHorizontalPosition(top: number, left: number, width: number, height: number, originWidth: number, originHeight: number, margin: number, safeZone: number): PositionData {
|
package/src/component/index.ts
CHANGED
|
@@ -25,7 +25,6 @@ export { default as FluxCommandPaletteItem } from './FluxCommandPaletteItem.vue'
|
|
|
25
25
|
export { default as FluxComment } from './FluxComment.vue';
|
|
26
26
|
export { default as FluxColorPicker } from './FluxColorPicker.vue';
|
|
27
27
|
export { default as FluxColorSelect } from './FluxColorSelect.vue';
|
|
28
|
-
export { default as FluxColumn } from './FluxColumn.vue';
|
|
29
28
|
export { default as FluxContainer } from './FluxContainer.vue';
|
|
30
29
|
export { default as FluxDataTable } from './FluxDataTable.vue';
|
|
31
30
|
export { default as FluxDatePicker } from './FluxDatePicker.vue';
|
|
@@ -48,6 +47,8 @@ export { default as FluxFilterOptionAsync } from './FluxFilterOptionAsync.vue';
|
|
|
48
47
|
export { default as FluxFilterOptions } from './FluxFilterOptions.vue';
|
|
49
48
|
export { default as FluxFilterOptionsAsync } from './FluxFilterOptionsAsync.vue';
|
|
50
49
|
export { default as FluxFilterRange } from './FluxFilterRange.vue';
|
|
50
|
+
export { default as FluxFlex } from './FluxFlex.vue';
|
|
51
|
+
export { default as FluxFlexItem } from './FluxFlexItem.vue';
|
|
51
52
|
export { default as FluxFlickeringGrid } from './FluxFlickeringGrid.vue';
|
|
52
53
|
export { default as FluxFlyout } from './FluxFlyout.vue';
|
|
53
54
|
export { default as FluxFocalPointEditor } from './FluxFocalPointEditor.vue';
|
|
@@ -125,7 +126,7 @@ export { default as FluxPublishButton } from './FluxPublishButton.vue';
|
|
|
125
126
|
export { default as FluxQuantitySelector } from './FluxQuantitySelector.vue';
|
|
126
127
|
export { default as FluxRemove } from './FluxRemove.vue';
|
|
127
128
|
export { default as FluxRoot } from './FluxRoot.vue';
|
|
128
|
-
export { default as
|
|
129
|
+
export { default as FluxScroller } from './FluxScroller.vue';
|
|
129
130
|
export { default as FluxSecondaryButton } from './FluxSecondaryButton.vue';
|
|
130
131
|
export { default as FluxSecondaryLinkButton } from './FluxSecondaryLinkButton.vue';
|
|
131
132
|
export { default as FluxSegmentedControl } from './FluxSegmentedControl.vue';
|
|
@@ -138,11 +139,13 @@ export { default as FluxSpacer } from './FluxSpacer.vue';
|
|
|
138
139
|
export { default as FluxSpacing } from './FluxSpacing.vue';
|
|
139
140
|
export { default as FluxSpinner } from './FluxSpinner.vue';
|
|
140
141
|
export { default as FluxSplitButton } from './FluxSplitButton.vue';
|
|
141
|
-
export { default as
|
|
142
|
+
export { default as FluxSplitView } from './FluxSplitView.vue';
|
|
143
|
+
export { default as FluxSplitViewPane } from './FluxSplitViewPane.vue';
|
|
142
144
|
export { default as FluxStatistic } from './FluxStatistic.vue';
|
|
143
145
|
export { default as FluxStepper } from './FluxStepper.vue';
|
|
144
146
|
export { default as FluxStepperStep } from './FluxStepperStep.vue';
|
|
145
147
|
export { default as FluxStepperSteps } from './FluxStepperSteps.vue';
|
|
148
|
+
export { default as FluxSticky } from './FluxSticky.vue';
|
|
146
149
|
export { default as FluxTab } from './FluxTab.vue';
|
|
147
150
|
export { default as FluxTabBar } from './FluxTabBar.vue';
|
|
148
151
|
export { default as FluxTabBarItem } from './FluxTabBarItem.vue';
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
lang="ts"
|
|
12
12
|
setup>
|
|
13
13
|
import { useLoaded } from '@basmilius/common';
|
|
14
|
-
import type {
|
|
14
|
+
import type { FluxFilterDefinition, FluxFilterValue } from '@flux-ui/types';
|
|
15
15
|
import { computed, ref, unref, watch } from 'vue';
|
|
16
16
|
import FluxBadge from '../FluxBadge.vue';
|
|
17
17
|
import $style from '~flux/components/css/component/Filter.module.scss';
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
item,
|
|
25
25
|
value
|
|
26
26
|
} = defineProps<{
|
|
27
|
-
readonly item:
|
|
27
|
+
readonly item: FluxFilterDefinition;
|
|
28
28
|
readonly value: FluxFilterValue;
|
|
29
29
|
}>();
|
|
30
30
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
:command="valueLabel"
|
|
4
4
|
command-icon="angle-right"
|
|
5
5
|
:command-loading="isLoading"
|
|
6
|
+
:disabled="disabled"
|
|
6
7
|
:icon-leading="item.icon"
|
|
7
8
|
:label="item.label"
|
|
8
9
|
type="button"
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
lang="ts"
|
|
14
15
|
setup>
|
|
15
16
|
import { useLoaded } from '@basmilius/common';
|
|
16
|
-
import type {
|
|
17
|
+
import type { FluxFilterDefinition, FluxFilterValue } from '@flux-ui/types';
|
|
17
18
|
import { computed, ref, unref, watch } from 'vue';
|
|
18
19
|
import FluxMenuItem from '../FluxMenuItem.vue';
|
|
19
20
|
|
|
@@ -25,8 +26,9 @@
|
|
|
25
26
|
item,
|
|
26
27
|
value
|
|
27
28
|
} = defineProps<{
|
|
28
|
-
readonly item:
|
|
29
|
+
readonly item: FluxFilterDefinition;
|
|
29
30
|
readonly value: FluxFilterValue;
|
|
31
|
+
readonly disabled?: boolean;
|
|
30
32
|
}>();
|
|
31
33
|
|
|
32
34
|
const {isLoading, loaded} = useLoaded();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FluxFilterDefinition, FluxFilterValue } from '@flux-ui/types';
|
|
2
2
|
import { defineComponent, h, isVNode, type VNode, unref } from 'vue';
|
|
3
3
|
import { useFilterInjection } from '~flux/components/composable';
|
|
4
4
|
import FluxMenuGroup from '../FluxMenuGroup.vue';
|
|
@@ -14,11 +14,11 @@ export const FilterMenuRenderer = defineComponent({
|
|
|
14
14
|
setup(props) {
|
|
15
15
|
const {state} = useFilterInjection();
|
|
16
16
|
|
|
17
|
-
return () => props.menuItems.map((group, index) => renderFilterGroup(group as (
|
|
17
|
+
return () => props.menuItems.map((group, index) => renderFilterGroup(group as (FluxFilterDefinition | VNode)[], index, props.navigate, unref(state) as Record<string, FluxFilterValue>));
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
function renderFilterGroup(group: (
|
|
21
|
+
function renderFilterGroup(group: (FluxFilterDefinition | VNode)[], index: number, navigate: Function, state: Record<string, FluxFilterValue>): VNode[] {
|
|
22
22
|
const slot: VNode[] = [];
|
|
23
23
|
|
|
24
24
|
if (index > 0) {
|
|
@@ -32,7 +32,7 @@ function renderFilterGroup(group: (FluxFilterItem | VNode)[], index: number, nav
|
|
|
32
32
|
return slot;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function renderFilterItem(item:
|
|
35
|
+
function renderFilterItem(item: FluxFilterDefinition | VNode, navigate: Function, state: Record<string, FluxFilterValue>): VNode {
|
|
36
36
|
if (isVNode(item)) {
|
|
37
37
|
return item;
|
|
38
38
|
}
|
|
@@ -40,6 +40,11 @@ function renderFilterItem(item: FluxFilterItem | VNode, navigate: Function, stat
|
|
|
40
40
|
return h(FilterItem, {
|
|
41
41
|
item,
|
|
42
42
|
value: state[item.name] ?? null,
|
|
43
|
-
|
|
43
|
+
disabled: item.disabled,
|
|
44
|
+
onClick: () => {
|
|
45
|
+
if (!item.disabled) {
|
|
46
|
+
navigate(item.name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
44
49
|
});
|
|
45
50
|
}
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
lang="ts"
|
|
39
39
|
setup>
|
|
40
40
|
import type { FluxFilterOptionItem, FluxFilterOptionRow, FluxFilterValueSingle } from '@flux-ui/types';
|
|
41
|
-
import { isFluxFilterOptionHeader, isFluxFilterOptionItem } from '~flux/components/
|
|
41
|
+
import { isFluxFilterOptionHeader, isFluxFilterOptionItem } from '~flux/components/util';
|
|
42
42
|
import FluxFormInput from '../FluxFormInput.vue';
|
|
43
43
|
import FluxMenuGroup from '../FluxMenuGroup.vue';
|
|
44
44
|
import FluxMenuItem from '../FluxMenuItem.vue';
|
|
@@ -3,6 +3,7 @@ export { default as useDateFlyout } from './useDateFlyout';
|
|
|
3
3
|
export { default as useDropdownPopup, type UseDropdownPopupOptions, type UseDropdownPopupReturn } from './useDropdownPopup';
|
|
4
4
|
export { default as useFormSelect } from './useFormSelect';
|
|
5
5
|
export { useKanban } from './useKanban';
|
|
6
|
+
export { useSplitView, type SplitViewPane, type UseSplitViewOptions, type UseSplitViewReturn } from './useSplitView';
|
|
6
7
|
export { default as useTranslate } from './useTranslate';
|
|
7
8
|
export { useCommandPalette, type CommandPaletteGroup, type CommandPaletteResultItem } from './useCommandPalette';
|
|
8
9
|
export { useFilterOptionMulti, useFilterOptionSingle, type FilterOptionMulti, type FilterOptionSingle } from './useFilterOption';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useDebouncedRef, useLoaded } from '@basmilius/common';
|
|
2
2
|
import type { FluxFilterOptionRow, FluxFilterValue } from '@flux-ui/types';
|
|
3
3
|
import { computed, ref, unref, watch, type ComputedRef, type ModelRef, type Ref } from 'vue';
|
|
4
|
-
import { isFluxFilterOptionItem } from '~flux/components/
|
|
4
|
+
import { isFluxFilterOptionItem } from '~flux/components/util';
|
|
5
5
|
|
|
6
6
|
type UseAsyncFilterOptionsParams = {
|
|
7
7
|
readonly currentValueIds: ComputedRef<FluxFilterValue[]>;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { useRemembered } from '@flux-ui/internals';
|
|
2
|
+
import type { FluxDirection } from '@flux-ui/types';
|
|
3
|
+
import { computed, type ComputedRef, nextTick, onMounted, ref, type Ref, watch } from 'vue';
|
|
4
|
+
|
|
5
|
+
export type SplitViewPane = {
|
|
6
|
+
readonly id: number;
|
|
7
|
+
readonly defaultSize: number | string | undefined;
|
|
8
|
+
readonly minSize: number;
|
|
9
|
+
readonly maxSize: number | undefined;
|
|
10
|
+
readonly isResizable: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type UseSplitViewOptions = {
|
|
14
|
+
readonly containerRef: Readonly<Ref<HTMLElement | null>>;
|
|
15
|
+
readonly direction: Readonly<Ref<FluxDirection>>;
|
|
16
|
+
readonly panes: Readonly<Ref<readonly SplitViewPane[]>>;
|
|
17
|
+
readonly rememberKey: string | undefined;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type UseSplitViewReturn = {
|
|
21
|
+
readonly sizes: Readonly<Ref<readonly number[]>>;
|
|
22
|
+
readonly templateStyle: ComputedRef<Record<string, string>>;
|
|
23
|
+
readonly isDragging: Readonly<Ref<boolean>>;
|
|
24
|
+
|
|
25
|
+
onHandleKeyDown(evt: KeyboardEvent, handleIndex: number): void;
|
|
26
|
+
onHandlePointerDown(evt: PointerEvent, handleIndex: number): void;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const HANDLE_SIZE = 6;
|
|
30
|
+
const KEY_STEP = 16;
|
|
31
|
+
const KEY_STEP_LARGE = 64;
|
|
32
|
+
|
|
33
|
+
export function useSplitView(options: UseSplitViewOptions): UseSplitViewReturn {
|
|
34
|
+
const sizes = ref<number[]>([]);
|
|
35
|
+
const isDragging = ref(false);
|
|
36
|
+
const persisted = options.rememberKey
|
|
37
|
+
? useRemembered<number[] | null>(`split-view/${options.rememberKey}`, null)
|
|
38
|
+
: null;
|
|
39
|
+
|
|
40
|
+
const containerSize = (): number => {
|
|
41
|
+
const el = options.containerRef.value;
|
|
42
|
+
|
|
43
|
+
if (!el) {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return options.direction.value === 'horizontal' ? el.clientWidth : el.clientHeight;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const computeInitialSizes = (): number[] => {
|
|
51
|
+
const persistedValue = persisted?.value;
|
|
52
|
+
|
|
53
|
+
if (persistedValue && persistedValue.length === options.panes.value.length) {
|
|
54
|
+
return [...persistedValue];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const total = containerSize();
|
|
58
|
+
const handleSpace = Math.max(0, options.panes.value.length - 1) * HANDLE_SIZE;
|
|
59
|
+
const available = Math.max(0, total - handleSpace);
|
|
60
|
+
const result: number[] = [];
|
|
61
|
+
|
|
62
|
+
let claimed = 0;
|
|
63
|
+
let flexCount = 0;
|
|
64
|
+
|
|
65
|
+
for (const pane of options.panes.value) {
|
|
66
|
+
if (typeof pane.defaultSize === 'number') {
|
|
67
|
+
result.push(pane.defaultSize);
|
|
68
|
+
claimed += pane.defaultSize;
|
|
69
|
+
} else if (typeof pane.defaultSize === 'string' && pane.defaultSize.endsWith('%')) {
|
|
70
|
+
const percentage = parseFloat(pane.defaultSize) / 100;
|
|
71
|
+
const size = available * percentage;
|
|
72
|
+
result.push(size);
|
|
73
|
+
claimed += size;
|
|
74
|
+
} else {
|
|
75
|
+
result.push(-1);
|
|
76
|
+
flexCount++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const flexShare = flexCount > 0 ? Math.max(0, (available - claimed) / flexCount) : 0;
|
|
81
|
+
|
|
82
|
+
return result.map(size => size === -1 ? flexShare : size);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const clampSizes = (next: number[]): number[] => {
|
|
86
|
+
return next.map((size, i) => {
|
|
87
|
+
const pane = options.panes.value[i];
|
|
88
|
+
const min = pane.minSize;
|
|
89
|
+
const max = pane.maxSize ?? Infinity;
|
|
90
|
+
return Math.min(Math.max(size, min), max);
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
onMounted(async () => {
|
|
95
|
+
await nextTick();
|
|
96
|
+
sizes.value = computeInitialSizes();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
watch(() => options.panes.value.length, () => {
|
|
100
|
+
sizes.value = computeInitialSizes();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
watch(sizes, value => {
|
|
104
|
+
if (persisted && !isDragging.value) {
|
|
105
|
+
persisted.value = [...value];
|
|
106
|
+
}
|
|
107
|
+
}, {deep: true});
|
|
108
|
+
|
|
109
|
+
const templateStyle = computed(() => {
|
|
110
|
+
const direction = options.direction.value;
|
|
111
|
+
const property = direction === 'horizontal' ? 'gridTemplateColumns' : 'gridTemplateRows';
|
|
112
|
+
const tracks: string[] = [];
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < sizes.value.length; i++) {
|
|
115
|
+
tracks.push(`${sizes.value[i]}px`);
|
|
116
|
+
|
|
117
|
+
if (i < sizes.value.length - 1) {
|
|
118
|
+
tracks.push(`${HANDLE_SIZE}px`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {[property]: tracks.join(' ')};
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
function applyDelta(handleIndex: number, delta: number): void {
|
|
126
|
+
const next = [...sizes.value];
|
|
127
|
+
const leftIndex = handleIndex;
|
|
128
|
+
const rightIndex = handleIndex + 1;
|
|
129
|
+
const leftPane = options.panes.value[leftIndex];
|
|
130
|
+
const rightPane = options.panes.value[rightIndex];
|
|
131
|
+
|
|
132
|
+
const leftMin = leftPane.minSize;
|
|
133
|
+
const leftMax = leftPane.maxSize ?? Infinity;
|
|
134
|
+
const rightMin = rightPane.minSize;
|
|
135
|
+
const rightMax = rightPane.maxSize ?? Infinity;
|
|
136
|
+
|
|
137
|
+
let newLeft = next[leftIndex] + delta;
|
|
138
|
+
let newRight = next[rightIndex] - delta;
|
|
139
|
+
|
|
140
|
+
if (newLeft < leftMin) {
|
|
141
|
+
const overshoot = leftMin - newLeft;
|
|
142
|
+
newLeft = leftMin;
|
|
143
|
+
newRight -= overshoot;
|
|
144
|
+
} else if (newLeft > leftMax) {
|
|
145
|
+
const overshoot = newLeft - leftMax;
|
|
146
|
+
newLeft = leftMax;
|
|
147
|
+
newRight += overshoot;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (newRight < rightMin) {
|
|
151
|
+
const overshoot = rightMin - newRight;
|
|
152
|
+
newRight = rightMin;
|
|
153
|
+
newLeft -= overshoot;
|
|
154
|
+
} else if (newRight > rightMax) {
|
|
155
|
+
const overshoot = newRight - rightMax;
|
|
156
|
+
newRight = rightMax;
|
|
157
|
+
newLeft += overshoot;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
next[leftIndex] = newLeft;
|
|
161
|
+
next[rightIndex] = newRight;
|
|
162
|
+
|
|
163
|
+
sizes.value = clampSizes(next);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function onHandlePointerDown(evt: PointerEvent, handleIndex: number): void {
|
|
167
|
+
if (evt.button !== 0) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
evt.preventDefault();
|
|
172
|
+
const target = evt.currentTarget as HTMLElement;
|
|
173
|
+
target.setPointerCapture(evt.pointerId);
|
|
174
|
+
|
|
175
|
+
isDragging.value = true;
|
|
176
|
+
|
|
177
|
+
const isHorizontal = options.direction.value === 'horizontal';
|
|
178
|
+
const startCoord = isHorizontal ? evt.clientX : evt.clientY;
|
|
179
|
+
const startSizes = [...sizes.value];
|
|
180
|
+
|
|
181
|
+
const onMove = (moveEvt: PointerEvent): void => {
|
|
182
|
+
const currentCoord = isHorizontal ? moveEvt.clientX : moveEvt.clientY;
|
|
183
|
+
const delta = currentCoord - startCoord;
|
|
184
|
+
|
|
185
|
+
sizes.value = clampSizes(startSizes.map((size, i) => {
|
|
186
|
+
if (i === handleIndex) {
|
|
187
|
+
return size + delta;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (i === handleIndex + 1) {
|
|
191
|
+
return size - delta;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return size;
|
|
195
|
+
}));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const onUp = (upEvt: PointerEvent): void => {
|
|
199
|
+
target.releasePointerCapture(upEvt.pointerId);
|
|
200
|
+
target.removeEventListener('pointermove', onMove);
|
|
201
|
+
target.removeEventListener('pointerup', onUp);
|
|
202
|
+
target.removeEventListener('pointercancel', onUp);
|
|
203
|
+
|
|
204
|
+
isDragging.value = false;
|
|
205
|
+
|
|
206
|
+
if (persisted) {
|
|
207
|
+
persisted.value = [...sizes.value];
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
target.addEventListener('pointermove', onMove);
|
|
212
|
+
target.addEventListener('pointerup', onUp);
|
|
213
|
+
target.addEventListener('pointercancel', onUp);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function onHandleKeyDown(evt: KeyboardEvent, handleIndex: number): void {
|
|
217
|
+
const isHorizontal = options.direction.value === 'horizontal';
|
|
218
|
+
const decreaseKey = isHorizontal ? 'ArrowLeft' : 'ArrowUp';
|
|
219
|
+
const increaseKey = isHorizontal ? 'ArrowRight' : 'ArrowDown';
|
|
220
|
+
const step = evt.shiftKey ? KEY_STEP_LARGE : KEY_STEP;
|
|
221
|
+
|
|
222
|
+
if (evt.key === decreaseKey) {
|
|
223
|
+
evt.preventDefault();
|
|
224
|
+
applyDelta(handleIndex, -step);
|
|
225
|
+
} else if (evt.key === increaseKey) {
|
|
226
|
+
evt.preventDefault();
|
|
227
|
+
applyDelta(handleIndex, step);
|
|
228
|
+
} else if (evt.key === 'Home') {
|
|
229
|
+
evt.preventDefault();
|
|
230
|
+
const leftPane = options.panes.value[handleIndex];
|
|
231
|
+
const delta = leftPane.minSize - sizes.value[handleIndex];
|
|
232
|
+
applyDelta(handleIndex, delta);
|
|
233
|
+
} else if (evt.key === 'End') {
|
|
234
|
+
evt.preventDefault();
|
|
235
|
+
const leftPane = options.panes.value[handleIndex];
|
|
236
|
+
const max = leftPane.maxSize ?? sizes.value[handleIndex] + sizes.value[handleIndex + 1] - options.panes.value[handleIndex + 1].minSize;
|
|
237
|
+
const delta = max - sizes.value[handleIndex];
|
|
238
|
+
applyDelta(handleIndex, delta);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
sizes,
|
|
244
|
+
templateStyle,
|
|
245
|
+
isDragging,
|
|
246
|
+
onHandleKeyDown,
|
|
247
|
+
onHandlePointerDown
|
|
248
|
+
};
|
|
249
|
+
}
|
|
@@ -7,9 +7,11 @@ export default function () {
|
|
|
7
7
|
// Vue, so that explains the empty getter and function below.
|
|
8
8
|
state: ref({}),
|
|
9
9
|
back: () => void 0,
|
|
10
|
-
|
|
10
|
+
clear: () => void 0,
|
|
11
|
+
getDefinition: () => undefined,
|
|
11
12
|
getValue: () => void 0,
|
|
12
13
|
hasValue: () => false,
|
|
14
|
+
reset: () => void 0,
|
|
13
15
|
setValue: () => void 0
|
|
14
16
|
});
|
|
15
17
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
@use '~flux/components/css/mixin';
|
|
2
2
|
|
|
3
3
|
.calendar {
|
|
4
|
-
|
|
4
|
+
flex-grow: 1;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.calendarView {
|
|
8
|
+
contain: paint;
|
|
5
9
|
|
|
6
10
|
display: flex;
|
|
7
11
|
flex-flow: column;
|
|
8
12
|
flex-grow: 1;
|
|
9
|
-
box-shadow: var(--shadow-sm);
|
|
10
|
-
contain: paint;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
.calendarItemRegistry {
|
|
@@ -90,16 +92,14 @@
|
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
/* region Month view */
|
|
94
|
-
|
|
95
95
|
.calendarCells {
|
|
96
96
|
display: grid;
|
|
97
97
|
flex-grow: 1;
|
|
98
98
|
gap: 1px;
|
|
99
99
|
grid-template-columns: repeat(7, minmax(180px, 1fr));
|
|
100
|
-
grid-
|
|
101
|
-
overflow-x: auto;
|
|
100
|
+
grid-template-rows: min-content repeat(6, auto);
|
|
102
101
|
background: var(--gray-100);
|
|
102
|
+
overflow-x: auto;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
.calendarCell {
|
|
@@ -113,9 +113,9 @@
|
|
|
113
113
|
padding-left: 0;
|
|
114
114
|
padding-right: 0;
|
|
115
115
|
color: var(--foreground-secondary);
|
|
116
|
-
font-size:
|
|
117
|
-
font-weight:
|
|
118
|
-
line-height:
|
|
116
|
+
font-size: 13px;
|
|
117
|
+
font-weight: 500;
|
|
118
|
+
line-height: 30px;
|
|
119
119
|
text-align: center;
|
|
120
120
|
text-transform: capitalize;
|
|
121
121
|
}
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
min-height: 90px;
|
|
128
128
|
padding-top: 33px;
|
|
129
129
|
outline: 2px dashed transparent;
|
|
130
|
-
outline-offset: 2px;
|
|
130
|
+
outline-offset: -2px;
|
|
131
131
|
transition: 210ms var(--swift-out);
|
|
132
132
|
transition-property: background, outline-color, z-index;
|
|
133
133
|
z-index: 0;
|
|
@@ -181,10 +181,6 @@
|
|
|
181
181
|
gap: 3px;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/* endregion */
|
|
185
|
-
|
|
186
|
-
/* region Time-grid view */
|
|
187
|
-
|
|
188
184
|
.timeGrid {
|
|
189
185
|
display: flex;
|
|
190
186
|
flex-flow: column;
|
|
@@ -393,5 +389,3 @@
|
|
|
393
389
|
z-index: 5;
|
|
394
390
|
pointer-events: none;
|
|
395
391
|
}
|
|
396
|
-
|
|
397
|
-
/* endregion */
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
.commentContent {
|
|
42
42
|
min-width: 0;
|
|
43
43
|
padding: 12px 18px;
|
|
44
|
-
background:
|
|
45
|
-
border: 1px solid var(--
|
|
44
|
+
background: var(--primary-50);
|
|
45
|
+
border: 1px solid var(--primary-200);
|
|
46
46
|
border-radius: calc(var(--radius) * 2);
|
|
47
47
|
box-shadow: var(--shadow-xs);
|
|
48
48
|
}
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
.comment.isReceived .commentContent {
|
|
55
|
-
background:
|
|
55
|
+
background: var(--gray-50);
|
|
56
56
|
border-color: var(--gray-200);
|
|
57
57
|
border-bottom-left-radius: var(--radius);
|
|
58
58
|
}
|
|
@@ -87,14 +87,6 @@
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
[dark] .commentContent {
|
|
91
|
-
background: linear-gradient(to bottom, var(--gray-50), var(--gray-25));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
[dark] .comment.isReceived .commentContent {
|
|
95
|
-
background: linear-gradient(to bottom, var(--gray-100), var(--gray-50));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
90
|
@keyframes commentTyping {
|
|
99
91
|
0%,
|
|
100
92
|
80%,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
max-height: 50dvh;
|
|
3
3
|
max-width: 100%;
|
|
4
4
|
padding: 9px;
|
|
5
|
-
width:
|
|
5
|
+
width: 300px;
|
|
6
6
|
overflow: auto;
|
|
7
7
|
scrollbar-width: none;
|
|
8
8
|
transition: height 150ms var(--deceleration-curve);
|
|
@@ -85,11 +85,15 @@
|
|
|
85
85
|
flex-grow: 1;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
.
|
|
88
|
+
.filterAction {
|
|
89
89
|
width: 42px;
|
|
90
90
|
justify-content: center;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
.filterHeaderActions {
|
|
94
|
+
justify-content: flex-end;
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
.filterDatePicker {
|
|
94
98
|
margin: -9px;
|
|
95
99
|
}
|