@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.
Files changed (125) hide show
  1. package/dist/component/FluxActionStack.vue.d.ts +25 -19
  2. package/dist/component/FluxAspectRatio.vue.d.ts +4 -3
  3. package/dist/component/FluxBorderShine.vue.d.ts +1 -1
  4. package/dist/component/FluxCalendar.vue.d.ts +2 -6
  5. package/dist/component/FluxContainer.vue.d.ts +3 -2
  6. package/dist/component/FluxFilter.vue.d.ts +6 -7
  7. package/dist/component/FluxFilterBar.vue.d.ts +5 -4
  8. package/dist/component/FluxFilterBase.vue.d.ts +14 -11
  9. package/dist/component/FluxFilterDate.vue.d.ts +3 -6
  10. package/dist/component/FluxFilterDateRange.vue.d.ts +3 -6
  11. package/dist/component/FluxFilterOption.vue.d.ts +3 -6
  12. package/dist/component/FluxFilterOptionAsync.vue.d.ts +3 -6
  13. package/dist/component/FluxFilterOptions.vue.d.ts +3 -6
  14. package/dist/component/FluxFilterOptionsAsync.vue.d.ts +3 -6
  15. package/dist/component/FluxFilterRange.vue.d.ts +3 -7
  16. package/dist/component/FluxFilterWindow.vue.d.ts +3 -8
  17. package/dist/component/FluxFlex.vue.d.ts +30 -0
  18. package/dist/component/{FluxRow.vue.d.ts → FluxFlexItem.vue.d.ts} +5 -3
  19. package/dist/component/FluxGrid.vue.d.ts +3 -2
  20. package/dist/component/FluxGridColumn.vue.d.ts +3 -2
  21. package/dist/component/FluxKanbanColumn.vue.d.ts +3 -0
  22. package/dist/component/FluxScroller.vue.d.ts +32 -0
  23. package/dist/component/{FluxStack.vue.d.ts → FluxSplitView.vue.d.ts} +7 -6
  24. package/dist/component/{FluxColumn.vue.d.ts → FluxSplitViewPane.vue.d.ts} +4 -1
  25. package/dist/component/FluxSticky.vue.d.ts +34 -0
  26. package/dist/component/index.d.ts +6 -3
  27. package/dist/component/primitive/FilterBadge.vue.d.ts +2 -2
  28. package/dist/component/primitive/FilterItem.vue.d.ts +3 -2
  29. package/dist/component/primitive/SelectBase.vue.d.ts +4 -4
  30. package/dist/composable/private/index.d.ts +1 -0
  31. package/dist/composable/private/useSplitView.d.ts +23 -0
  32. package/dist/data/di.d.ts +19 -2
  33. package/dist/data/index.d.ts +0 -1
  34. package/dist/index.css +778 -526
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +10381 -9732
  37. package/dist/index.js.map +1 -1
  38. package/dist/util/defineFilter.d.ts +3 -0
  39. package/dist/util/filter.d.ts +7 -0
  40. package/dist/util/index.d.ts +2 -0
  41. package/dist/vite/defineFilterMacro.d.ts +3 -0
  42. package/dist/vite/index.d.ts +1 -0
  43. package/dist/vite.js +217 -0
  44. package/dist/vite.js.map +1 -0
  45. package/package.json +11 -7
  46. package/src/component/FluxActionBar.vue +3 -4
  47. package/src/component/FluxActionStack.vue +3 -3
  48. package/src/component/FluxAspectRatio.vue +5 -3
  49. package/src/component/FluxBadgeStack.vue +4 -4
  50. package/src/component/FluxButtonStack.vue +6 -4
  51. package/src/component/FluxCalendar.vue +160 -157
  52. package/src/component/FluxContainer.vue +4 -2
  53. package/src/component/FluxFilter.vue +10 -11
  54. package/src/component/FluxFilterBar.vue +71 -15
  55. package/src/component/FluxFilterBase.vue +65 -51
  56. package/src/component/FluxFilterDate.vue +24 -8
  57. package/src/component/FluxFilterDateRange.vue +27 -9
  58. package/src/component/FluxFilterOption.vue +20 -10
  59. package/src/component/FluxFilterOptionAsync.vue +19 -11
  60. package/src/component/FluxFilterOptions.vue +26 -11
  61. package/src/component/FluxFilterOptionsAsync.vue +28 -12
  62. package/src/component/FluxFilterRange.vue +25 -11
  63. package/src/component/FluxFilterWindow.vue +25 -11
  64. package/src/component/FluxFlex.vue +53 -0
  65. package/src/component/FluxFlexItem.vue +40 -0
  66. package/src/component/FluxFormDateTimeInput.vue +3 -4
  67. package/src/component/FluxGrid.vue +4 -2
  68. package/src/component/FluxGridColumn.vue +4 -2
  69. package/src/component/FluxInfoStack.vue +3 -3
  70. package/src/component/FluxItemStack.vue +4 -4
  71. package/src/component/FluxKanbanColumn.vue +16 -3
  72. package/src/component/FluxNoticeStack.vue +3 -3
  73. package/src/component/FluxPane.vue +10 -7
  74. package/src/component/FluxProgressBar.vue +4 -3
  75. package/src/component/FluxScroller.vue +63 -0
  76. package/src/component/FluxSplitView.vue +101 -0
  77. package/src/component/FluxSplitViewPane.vue +23 -0
  78. package/src/component/FluxSticky.vue +67 -0
  79. package/src/component/FluxTagStack.vue +4 -4
  80. package/src/component/FluxToolbar.vue +3 -4
  81. package/src/component/FluxToolbarGroup.vue +3 -4
  82. package/src/component/FluxTooltipProvider.vue +56 -25
  83. package/src/component/index.ts +6 -3
  84. package/src/component/primitive/FilterBadge.vue +2 -2
  85. package/src/component/primitive/FilterItem.vue +4 -2
  86. package/src/component/primitive/FilterMenuRenderer.ts +10 -5
  87. package/src/component/primitive/FilterOptionBase.vue +1 -1
  88. package/src/composable/private/index.ts +1 -0
  89. package/src/composable/private/useAsyncFilterOptions.ts +1 -1
  90. package/src/composable/private/useFilterOption.ts +1 -1
  91. package/src/composable/private/useSplitView.ts +249 -0
  92. package/src/composable/useFilterInjection.ts +3 -1
  93. package/src/css/component/Calendar.module.scss +11 -17
  94. package/src/css/component/Comment.module.scss +3 -11
  95. package/src/css/component/Filter.module.scss +6 -2
  96. package/src/css/component/Flex.module.scss +84 -0
  97. package/src/css/component/Flyout.module.scss +1 -0
  98. package/src/css/component/Kanban.module.scss +31 -28
  99. package/src/css/component/LayerPane.module.scss +5 -0
  100. package/src/css/component/Layout.module.scss +0 -41
  101. package/src/css/component/Legend.module.scss +3 -4
  102. package/src/css/component/Menu.module.scss +1 -0
  103. package/src/css/component/Notice.module.scss +1 -1
  104. package/src/css/component/Pagination.module.scss +1 -1
  105. package/src/css/component/Pane.module.scss +1 -1
  106. package/src/css/component/Progress.module.scss +2 -2
  107. package/src/css/component/Scroller.module.scss +109 -0
  108. package/src/css/component/SplitView.module.scss +78 -0
  109. package/src/css/component/Sticky.module.scss +35 -0
  110. package/src/css/component/Tab.module.scss +1 -0
  111. package/src/css/component/Table.module.scss +1 -0
  112. package/src/css/component/Tooltip.module.scss +14 -0
  113. package/src/data/di.ts +22 -2
  114. package/src/data/index.ts +0 -1
  115. package/src/index.ts +11 -0
  116. package/src/util/defineFilter.ts +10 -0
  117. package/src/util/filter.ts +63 -0
  118. package/src/util/index.ts +2 -0
  119. package/src/vite/defineFilterMacro.ts +335 -0
  120. package/src/vite/index.ts +1 -0
  121. package/dist/data/filter.d.ts +0 -7
  122. package/src/component/FluxColumn.vue +0 -24
  123. package/src/component/FluxRow.vue +0 -24
  124. package/src/component/FluxStack.vue +0 -41
  125. package/src/data/filter.ts +0 -165
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <Component
3
+ :is="tag ?? 'div'"
4
+ :class="clsx(
5
+ isInline ? $style.flexInline : $style.flex,
6
+ direction === 'horizontal' && $style.flexDirectionHorizontal,
7
+ direction === 'vertical' && $style.flexDirectionVertical,
8
+ align === 'start' && $style.flexAlignStart,
9
+ align === 'center' && $style.flexAlignCenter,
10
+ align === 'end' && $style.flexAlignEnd,
11
+ align === 'stretch' && $style.flexAlignStretch,
12
+ align === 'baseline' && $style.flexAlignBaseline,
13
+ justify === 'start' && $style.flexJustifyStart,
14
+ justify === 'center' && $style.flexJustifyCenter,
15
+ justify === 'end' && $style.flexJustifyEnd,
16
+ justify === 'between' && $style.flexJustifyBetween,
17
+ justify === 'around' && $style.flexJustifyAround,
18
+ justify === 'evenly' && $style.flexJustifyEvenly,
19
+ wrap === 'wrap' && $style.flexWrapWrap,
20
+ wrap === 'nowrap' && $style.flexWrapNowrap,
21
+ wrap === 'wrap-reverse' && $style.flexWrapWrapReverse
22
+ )"
23
+ :style="{
24
+ '--gap': gap != null ? `${gap}px` : undefined
25
+ }">
26
+ <slot/>
27
+ </Component>
28
+ </template>
29
+
30
+ <script
31
+ lang="ts"
32
+ setup>
33
+ import type { FluxAlign, FluxDirection, FluxFlexWrap, FluxJustify } from '@flux-ui/types';
34
+ import { clsx } from 'clsx';
35
+ import type { VNode } from 'vue';
36
+ import $style from '~flux/components/css/component/Flex.module.scss';
37
+
38
+ const {
39
+ direction = 'horizontal'
40
+ } = defineProps<{
41
+ readonly align?: FluxAlign;
42
+ readonly direction?: FluxDirection;
43
+ readonly gap?: number;
44
+ readonly isInline?: boolean;
45
+ readonly justify?: FluxJustify;
46
+ readonly tag?: keyof HTMLElementTagNameMap;
47
+ readonly wrap?: FluxFlexWrap;
48
+ }>();
49
+
50
+ defineSlots<{
51
+ default(): VNode[];
52
+ }>();
53
+ </script>
@@ -0,0 +1,40 @@
1
+ <template>
2
+ <component :is="rendered"/>
3
+ </template>
4
+
5
+ <script
6
+ lang="ts"
7
+ setup>
8
+ import { flattenVNodeTree } from '@flux-ui/internals';
9
+ import { cloneVNode, computed, h, useSlots, type VNode } from 'vue';
10
+ import $style from '~flux/components/css/component/Flex.module.scss';
11
+
12
+ const props = defineProps<{
13
+ readonly basis?: number | string;
14
+ readonly grow?: number;
15
+ readonly shrink?: number;
16
+ }>();
17
+
18
+ defineSlots<{
19
+ default(): VNode[];
20
+ }>();
21
+
22
+ const slots = useSlots();
23
+
24
+ const flexStyle = computed(() => ({
25
+ flexBasis: typeof props.basis === 'number' ? `${props.basis}px` : props.basis,
26
+ flexGrow: props.grow,
27
+ flexShrink: props.shrink
28
+ }));
29
+
30
+ const rendered = computed(() => {
31
+ const children = flattenVNodeTree(slots.default?.() ?? []);
32
+ const extra = {class: $style.flexItem, style: flexStyle.value};
33
+
34
+ if (children.length === 1) {
35
+ return cloneVNode(children[0], extra);
36
+ }
37
+
38
+ return h('div', extra, children);
39
+ });
40
+ </script>
@@ -1,7 +1,6 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  :class="$style.formDateTimeInput"
4
- direction="horizontal"
5
4
  :gap="15"
6
5
  :aria-disabled="disabled ? true : undefined">
7
6
  <FluxFlyout
@@ -40,7 +39,7 @@
40
39
  type="time"
41
40
  :model-value="localValue"
42
41
  @update:model-value="setTime"/>
43
- </FluxStack>
42
+ </FluxFlex>
44
43
  </template>
45
44
 
46
45
  <script
@@ -52,11 +51,11 @@
52
51
  import { useDisabled } from '~flux/components/composable';
53
52
  import { useDateFlyout } from '~flux/components/composable/private';
54
53
  import FluxDatePicker from './FluxDatePicker.vue';
54
+ import FluxFlex from './FluxFlex.vue';
55
55
  import FluxFlyout from './FluxFlyout.vue';
56
56
  import FluxFormInput from './FluxFormInput.vue';
57
57
  import FluxFormInputGroup from './FluxFormInputGroup.vue';
58
58
  import FluxSecondaryButton from './FluxSecondaryButton.vue';
59
- import FluxStack from './FluxStack.vue';
60
59
  import $style from '~flux/components/css/component/Form.module.scss';
61
60
 
62
61
  const modelValue = defineModel<DateTime | null>({
@@ -1,12 +1,13 @@
1
1
  <template>
2
- <div
2
+ <Component
3
+ :is="tag ?? 'div'"
3
4
  :class="$style.grid"
4
5
  :style="{
5
6
  '--gap': `${gap}px`,
6
7
  '--columns': columns
7
8
  }">
8
9
  <slot/>
9
- </div>
10
+ </Component>
10
11
  </template>
11
12
 
12
13
  <script
@@ -21,6 +22,7 @@
21
22
  } = defineProps<{
22
23
  readonly columns?: number;
23
24
  readonly gap?: number;
25
+ readonly tag?: keyof HTMLElementTagNameMap;
24
26
  }>();
25
27
 
26
28
  defineSlots<{
@@ -1,5 +1,6 @@
1
1
  <template>
2
- <div
2
+ <Component
3
+ :is="tag ?? 'div'"
3
4
  :class="$style.gridColumn"
4
5
  :style="{
5
6
  '--xs': xs ?? 12,
@@ -9,7 +10,7 @@
9
10
  '--xl': xl ?? lg ?? md ?? sm ?? xs ?? 12
10
11
  }">
11
12
  <slot/>
12
- </div>
13
+ </Component>
13
14
  </template>
14
15
 
15
16
  <script
@@ -24,6 +25,7 @@
24
25
  readonly md?: number;
25
26
  readonly lg?: number;
26
27
  readonly xl?: number;
28
+ readonly tag?: keyof HTMLElementTagNameMap;
27
29
  }>();
28
30
 
29
31
  defineSlots<{
@@ -1,16 +1,16 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  direction="vertical"
4
4
  :gap="18">
5
5
  <slot/>
6
- </FluxStack>
6
+ </FluxFlex>
7
7
  </template>
8
8
 
9
9
  <script
10
10
  setup
11
11
  lang="ts">
12
12
  import type { VNode } from 'vue';
13
- import FluxStack from './FluxStack.vue';
13
+ import FluxFlex from './FluxFlex.vue';
14
14
 
15
15
  defineSlots<{
16
16
  default(): VNode[];
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  :class="$style.itemStack"
4
- :gap="0">
4
+ direction="vertical">
5
5
  <slot/>
6
- </FluxStack>
6
+ </FluxFlex>
7
7
  </template>
8
8
 
9
9
  <script
10
10
  lang="ts"
11
11
  setup>
12
- import FluxStack from './FluxStack.vue';
12
+ import FluxFlex from './FluxFlex.vue';
13
13
  import $style from '~flux/components/css/component/Item.module.scss';
14
14
  </script>
@@ -22,9 +22,17 @@
22
22
  @dragend="onColumnDragEnd"
23
23
  @dragover="onColumnDragOver"
24
24
  @drop="onColumnDrop">
25
- <slot name="header">
26
- <span :class="$style.kanbanColumnLabel">{{ label }}</span>
27
- </slot>
25
+ <div :class="$style.kanbanColumnHeaderCaption">
26
+ <FluxIcon
27
+ v-if="icon"
28
+ :name="icon"/>
29
+
30
+ <span>{{ label }}</span>
31
+
32
+ <FluxBadge
33
+ v-if="count"
34
+ :label="String(count)"/>
35
+ </div>
28
36
 
29
37
  <slot name="actions"/>
30
38
  </header>
@@ -68,10 +76,13 @@
68
76
  lang="ts"
69
77
  setup>
70
78
  import { flattenVNodeTree } from '@flux-ui/internals';
79
+ import type { FluxIconName } from '@flux-ui/types';
71
80
  import { Comment, computed, onBeforeUnmount, onMounted, provide, Text, toRef, unref, useSlots, useTemplateRef, watch } from 'vue';
72
81
  import { useDisabled, useKanbanInjection } from '~flux/components/composable';
73
82
  import { FluxDisabledInjectionKey } from '~flux/components/data';
74
83
  import $style from '~flux/components/css/component/Kanban.module.scss';
84
+ import FluxBadge from './FluxBadge.vue';
85
+ import FluxIcon from './FluxIcon.vue';
75
86
 
76
87
  const {
77
88
  columnId,
@@ -79,7 +90,9 @@
79
90
  label
80
91
  } = defineProps<{
81
92
  readonly columnId: string | number;
93
+ readonly count: string | number;
82
94
  readonly disabled?: boolean;
95
+ readonly icon?: FluxIconName;
83
96
  readonly label: string;
84
97
  }>();
85
98
 
@@ -1,16 +1,16 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  direction="vertical"
4
4
  :gap="6">
5
5
  <slot/>
6
- </FluxStack>
6
+ </FluxFlex>
7
7
  </template>
8
8
 
9
9
  <script
10
10
  lang="ts"
11
11
  setup>
12
12
  import type { VNode } from 'vue';
13
- import FluxStack from './FluxStack.vue';
13
+ import FluxFlex from './FluxFlex.vue';
14
14
 
15
15
  defineSlots<{
16
16
  default(): VNode[];
@@ -2,13 +2,15 @@
2
2
  <div :class="CLASS_MAP[variant]">
3
3
  <slot/>
4
4
 
5
- <slot
6
- v-if="isLoading"
7
- name="loader">
8
- <div :class="$style.paneLoader">
9
- <FluxSpinner/>
10
- </div>
11
- </slot>
5
+ <FluxFadeTransition>
6
+ <slot
7
+ v-if="isLoading"
8
+ name="loader">
9
+ <div :class="$style.paneLoader">
10
+ <FluxSpinner/>
11
+ </div>
12
+ </slot>
13
+ </FluxFadeTransition>
12
14
 
13
15
  <div
14
16
  v-if="tag"
@@ -22,6 +24,7 @@
22
24
  lang="ts"
23
25
  setup>
24
26
  import type { VNode } from 'vue';
27
+ import { FluxFadeTransition } from '~flux/components/transition';
25
28
  import FluxSpinner from './FluxSpinner.vue';
26
29
  import $style from '~flux/components/css/component/Pane.module.scss';
27
30
 
@@ -1,6 +1,7 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  :class="$style.progressBar"
4
+ direction="vertical"
4
5
  :gap="6"
5
6
  role="progressbar"
6
7
  :aria-valuenow="value"
@@ -34,7 +35,7 @@
34
35
  </span>
35
36
  </FluxFadeTransition>
36
37
  </div>
37
- </FluxStack>
38
+ </FluxFlex>
38
39
  </template>
39
40
 
40
41
  <script
@@ -42,7 +43,7 @@
42
43
  setup>
43
44
  import { computed, unref } from 'vue';
44
45
  import { FluxFadeTransition } from '~flux/components/transition';
45
- import FluxStack from './FluxStack.vue';
46
+ import FluxFlex from './FluxFlex.vue';
46
47
  import $style from '~flux/components/css/component/Progress.module.scss';
47
48
 
48
49
  const {
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <Component
3
+ :is="tag ?? 'div'"
4
+ ref="element"
5
+ :class="clsx(
6
+ $style.scroller,
7
+ direction === 'vertical' && $style.scrollerDirectionVertical,
8
+ direction === 'horizontal' && $style.scrollerDirectionHorizontal,
9
+ direction === 'both' && $style.scrollerDirectionBoth,
10
+ snap && direction === 'vertical' && (snap === 'mandatory' ? $style.scrollerSnapMandatoryVertical : $style.scrollerSnapProximityVertical),
11
+ snap && direction === 'horizontal' && (snap === 'mandatory' ? $style.scrollerSnapMandatoryHorizontal : $style.scrollerSnapProximityHorizontal),
12
+ snap && direction === 'both' && (snap === 'mandatory' ? $style.scrollerSnapMandatoryBoth : $style.scrollerSnapProximityBoth),
13
+ snapAlign === 'start' && $style.scrollerSnapAlignStart,
14
+ snapAlign === 'center' && $style.scrollerSnapAlignCenter,
15
+ snapAlign === 'end' && $style.scrollerSnapAlignEnd,
16
+ hasFade && direction === 'horizontal' && $style.scrollerFadeHorizontal,
17
+ hasFade && direction !== 'horizontal' && $style.scrollerFadeVertical
18
+ )"
19
+ :style="hasFade ? fadeStyle : undefined">
20
+ <slot/>
21
+ </Component>
22
+ </template>
23
+
24
+ <script
25
+ lang="ts"
26
+ setup>
27
+ import { useScrollEdges } from '@flux-ui/internals';
28
+ import type { FluxAlignment, FluxDirection } from '@flux-ui/types';
29
+ import { clsx } from 'clsx';
30
+ import { computed, useTemplateRef, type VNode } from 'vue';
31
+ import $style from '~flux/components/css/component/Scroller.module.scss';
32
+
33
+ const FADE_DISTANCE = 24;
34
+
35
+ const {
36
+ direction = 'vertical',
37
+ hasFade = false
38
+ } = defineProps<{
39
+ readonly direction?: FluxDirection | 'both';
40
+ readonly hasFade?: boolean;
41
+ readonly snap?: 'mandatory' | 'proximity';
42
+ readonly snapAlign?: FluxAlignment;
43
+ readonly tag?: keyof HTMLElementTagNameMap;
44
+ }>();
45
+
46
+ defineSlots<{
47
+ default(): VNode[];
48
+ }>();
49
+
50
+ const elementRef = useTemplateRef<HTMLElement>('element');
51
+ const {isAtStart, isAtEnd, isAtLeft, isAtRight} = useScrollEdges(elementRef);
52
+
53
+ const fadeStyle = computed(() => {
54
+ const isHorizontal = direction === 'horizontal';
55
+ const startEdge = isHorizontal ? isAtLeft.value : isAtStart.value;
56
+ const endEdge = isHorizontal ? isAtRight.value : isAtEnd.value;
57
+
58
+ return {
59
+ '--fade-start': startEdge ? '0px' : `${FADE_DISTANCE}px`,
60
+ '--fade-end': endEdge ? '0px' : `${FADE_DISTANCE}px`
61
+ };
62
+ });
63
+ </script>
@@ -0,0 +1,101 @@
1
+ <template>
2
+ <Component
3
+ :is="tag ?? 'div'"
4
+ ref="container"
5
+ :class="clsx(
6
+ direction === 'horizontal' && $style.splitViewHorizontal,
7
+ direction === 'vertical' && $style.splitViewVertical,
8
+ isDragging && $style.splitViewDragging
9
+ )"
10
+ :style="templateStyle">
11
+ <template v-for="(pane, index) in panes" :key="pane.id">
12
+ <component :is="pane.vnode"/>
13
+
14
+ <button
15
+ v-if="index < panes.length - 1"
16
+ :class="direction === 'horizontal' ? $style.splitViewHandle : $style.splitViewHandleVertical"
17
+ type="button"
18
+ role="separator"
19
+ :aria-orientation="direction === 'horizontal' ? 'vertical' : 'horizontal'"
20
+ :aria-valuemin="0"
21
+ :aria-valuenow="Math.round(sizes[index] ?? 0)"
22
+ :tabindex="pane.isResizable ? 0 : -1"
23
+ @pointerdown="onHandlePointerDown($event, index)"
24
+ @keydown="onHandleKeyDown($event, index)"/>
25
+ </template>
26
+ </Component>
27
+ </template>
28
+
29
+ <script
30
+ lang="ts"
31
+ setup>
32
+ import { flattenVNodeTree } from '@flux-ui/internals';
33
+ import type { FluxDirection } from '@flux-ui/types';
34
+ import { clsx } from 'clsx';
35
+ import { computed, toRef, useTemplateRef, type VNode } from 'vue';
36
+ import { type SplitViewPane, useSplitView } from '~flux/components/composable/private';
37
+ import FluxSplitViewPane from './FluxSplitViewPane.vue';
38
+ import $style from '~flux/components/css/component/SplitView.module.scss';
39
+
40
+ type ParsedPane = SplitViewPane & {
41
+ readonly vnode: VNode;
42
+ };
43
+
44
+ const {
45
+ direction = 'horizontal',
46
+ rememberKey
47
+ } = defineProps<{
48
+ readonly direction?: FluxDirection;
49
+ readonly rememberKey?: string;
50
+ readonly tag?: keyof HTMLElementTagNameMap;
51
+ }>();
52
+
53
+ const slots = defineSlots<{
54
+ default(): VNode[];
55
+ }>();
56
+
57
+ const containerRef = useTemplateRef<HTMLElement>('container');
58
+
59
+ const panes = computed<readonly ParsedPane[]>(() => {
60
+ const vnodes = flattenVNodeTree(slots.default?.() ?? []);
61
+ const out: ParsedPane[] = [];
62
+
63
+ for (const vnode of vnodes) {
64
+ if (vnode.type !== FluxSplitViewPane) {
65
+ continue;
66
+ }
67
+
68
+ const props = vnode.props ?? {};
69
+ const defaultSize = props.defaultSize ?? props['default-size'];
70
+ const minSize = props.minSize ?? props['min-size'];
71
+ const maxSize = props.maxSize ?? props['max-size'];
72
+ const isResizable = props.isResizable ?? props['is-resizable'];
73
+
74
+ out.push({
75
+ id: out.length,
76
+ vnode,
77
+ defaultSize: defaultSize as number | string | undefined,
78
+ minSize: typeof minSize === 'number' ? minSize : 64,
79
+ maxSize: typeof maxSize === 'number' ? maxSize : undefined,
80
+ isResizable: isResizable !== false && isResizable !== 'false'
81
+ });
82
+ }
83
+
84
+ return out;
85
+ });
86
+
87
+ const paneSpecs = computed<readonly SplitViewPane[]>(() => panes.value);
88
+
89
+ const {
90
+ sizes,
91
+ templateStyle,
92
+ isDragging,
93
+ onHandlePointerDown,
94
+ onHandleKeyDown
95
+ } = useSplitView({
96
+ containerRef,
97
+ direction: toRef(() => direction),
98
+ panes: paneSpecs,
99
+ rememberKey
100
+ });
101
+ </script>
@@ -0,0 +1,23 @@
1
+ <template>
2
+ <div :class="$style.splitViewPane">
3
+ <slot/>
4
+ </div>
5
+ </template>
6
+
7
+ <script
8
+ lang="ts"
9
+ setup>
10
+ import type { VNode } from 'vue';
11
+ import $style from '~flux/components/css/component/SplitView.module.scss';
12
+
13
+ defineProps<{
14
+ readonly defaultSize?: number | string;
15
+ readonly minSize?: number;
16
+ readonly maxSize?: number;
17
+ readonly isResizable?: boolean;
18
+ }>();
19
+
20
+ defineSlots<{
21
+ default(): VNode[];
22
+ }>();
23
+ </script>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <div
3
+ v-if="position === 'top'"
4
+ ref="sentinel"
5
+ :class="$style.stickySentinel"
6
+ aria-hidden="true"/>
7
+
8
+ <Component
9
+ :is="tag ?? 'div'"
10
+ :class="clsx(
11
+ position === 'top' ? $style.stickyTop : $style.stickyBottom,
12
+ hasShadowOnStick && $style.hasShadow
13
+ )"
14
+ :data-stuck="isStuck"
15
+ :style="{'--offset': `${offset}px`}">
16
+ <slot v-bind="{isStuck}"/>
17
+ </Component>
18
+
19
+ <div
20
+ v-if="position === 'bottom'"
21
+ ref="sentinel"
22
+ :class="$style.stickySentinel"
23
+ aria-hidden="true"/>
24
+ </template>
25
+
26
+ <script
27
+ lang="ts"
28
+ setup>
29
+ import { clsx } from 'clsx';
30
+ import { ref, useTemplateRef, type VNode, watch } from 'vue';
31
+ import $style from '~flux/components/css/component/Sticky.module.scss';
32
+
33
+ const {
34
+ offset = 0,
35
+ position = 'top'
36
+ } = defineProps<{
37
+ readonly hasShadowOnStick?: boolean;
38
+ readonly offset?: number;
39
+ readonly position?: 'top' | 'bottom';
40
+ readonly tag?: keyof HTMLElementTagNameMap;
41
+ }>();
42
+
43
+ defineSlots<{
44
+ default(props: { isStuck: boolean }): VNode[];
45
+ }>();
46
+
47
+ const sentinelRef = useTemplateRef<HTMLElement>('sentinel');
48
+ const isStuck = ref(false);
49
+
50
+ watch(sentinelRef, (sentinel, _, onCleanup) => {
51
+ if (!sentinel) {
52
+ return;
53
+ }
54
+
55
+ const observer = new IntersectionObserver(([entry]) => {
56
+ isStuck.value = !entry.isIntersecting;
57
+ }, {
58
+ threshold: 0
59
+ });
60
+
61
+ observer.observe(sentinel);
62
+
63
+ onCleanup(() => {
64
+ observer.disconnect();
65
+ });
66
+ }, {immediate: true});
67
+ </script>
@@ -1,17 +1,17 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  direction="horizontal"
4
4
  :gap="6"
5
- is-wrapping>
5
+ wrap="wrap">
6
6
  <slot/>
7
- </FluxStack>
7
+ </FluxFlex>
8
8
  </template>
9
9
 
10
10
  <script
11
11
  lang="ts"
12
12
  setup>
13
13
  import type { VNode } from 'vue';
14
- import FluxStack from './FluxStack.vue';
14
+ import FluxFlex from './FluxFlex.vue';
15
15
 
16
16
  defineSlots<{
17
17
  default(): VNode[];
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <FluxStack
2
+ <FluxFlex
3
3
  :class="clsx(
4
4
  !!floatingMode ? $style.toolbarFloating : $style.toolbarFlat,
5
5
  floatingMode === 'free' && $style.isFree,
@@ -8,11 +8,10 @@
8
8
  floatingMode === 'bottom-end' && $style.isBottomEnd,
9
9
  floatingMode === 'bottom-start' && $style.isBottomStart,
10
10
  )"
11
- direction="horizontal"
12
11
  :gap="6"
13
12
  tag="nav">
14
13
  <slot/>
15
- </FluxStack>
14
+ </FluxFlex>
16
15
  </template>
17
16
 
18
17
  <script
@@ -20,7 +19,7 @@
20
19
  setup>
21
20
  import { clsx } from 'clsx';
22
21
  import type { VNode } from 'vue';
23
- import FluxStack from './FluxStack.vue';
22
+ import FluxFlex from './FluxFlex.vue';
24
23
  import $style from '~flux/components/css/component/Toolbar.module.scss';
25
24
 
26
25
  defineProps<{
@@ -1,17 +1,16 @@
1
1
  <template>
2
- <FluxStack
3
- direction="horizontal"
2
+ <FluxFlex
4
3
  :gap="3"
5
4
  tag="nav">
6
5
  <slot/>
7
- </FluxStack>
6
+ </FluxFlex>
8
7
  </template>
9
8
 
10
9
  <script
11
10
  lang="ts"
12
11
  setup>
13
12
  import type { VNode } from 'vue';
14
- import FluxStack from './FluxStack.vue';
13
+ import FluxFlex from './FluxFlex.vue';
15
14
 
16
15
  defineSlots<{
17
16
  default(): VNode[];