@flux-ui/application 3.0.0-next.39

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 (59) hide show
  1. package/README.md +16 -0
  2. package/dist/component/FluxApplication.vue.d.ts +28 -0
  3. package/dist/component/FluxApplicationContent.vue.d.ts +24 -0
  4. package/dist/component/FluxApplicationHero.vue.d.ts +26 -0
  5. package/dist/component/FluxApplicationMenu.vue.d.ts +29 -0
  6. package/dist/component/FluxApplicationMenuAccount.vue.d.ts +29 -0
  7. package/dist/component/FluxApplicationMenuContext.vue.d.ts +15 -0
  8. package/dist/component/FluxApplicationMenuContextStack.vue.d.ts +6 -0
  9. package/dist/component/FluxApplicationMenuPromo.vue.d.ts +22 -0
  10. package/dist/component/FluxApplicationMenuToggle.vue.d.ts +3 -0
  11. package/dist/component/FluxApplicationSection.vue.d.ts +26 -0
  12. package/dist/component/FluxApplicationSide.vue.d.ts +20 -0
  13. package/dist/component/FluxApplicationTop.vue.d.ts +29 -0
  14. package/dist/component/index.d.ts +12 -0
  15. package/dist/composable/index.d.ts +3 -0
  16. package/dist/composable/useApplicationContextMenu.d.ts +7 -0
  17. package/dist/composable/useApplicationContextRegistration.d.ts +2 -0
  18. package/dist/composable/useApplicationInjection.d.ts +2 -0
  19. package/dist/composable/useApplicationMenu.d.ts +26 -0
  20. package/dist/data/index.d.ts +29 -0
  21. package/dist/index.css +746 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.js +4331 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/routing/useNamedRoutes.d.ts +14 -0
  26. package/dist/routing/useRoute.d.ts +8 -0
  27. package/dist/types.d.ts +13 -0
  28. package/package.json +71 -0
  29. package/src/component/FluxApplication.vue +144 -0
  30. package/src/component/FluxApplicationContent.vue +37 -0
  31. package/src/component/FluxApplicationHero.vue +34 -0
  32. package/src/component/FluxApplicationMenu.vue +73 -0
  33. package/src/component/FluxApplicationMenuAccount.vue +47 -0
  34. package/src/component/FluxApplicationMenuContext.vue +78 -0
  35. package/src/component/FluxApplicationMenuContextStack.vue +53 -0
  36. package/src/component/FluxApplicationMenuPromo.vue +23 -0
  37. package/src/component/FluxApplicationMenuToggle.vue +30 -0
  38. package/src/component/FluxApplicationSection.vue +40 -0
  39. package/src/component/FluxApplicationSide.vue +16 -0
  40. package/src/component/FluxApplicationTop.vue +74 -0
  41. package/src/component/index.ts +12 -0
  42. package/src/composable/index.ts +3 -0
  43. package/src/composable/useApplicationContextMenu.ts +19 -0
  44. package/src/composable/useApplicationContextRegistration.ts +25 -0
  45. package/src/composable/useApplicationInjection.ts +12 -0
  46. package/src/composable/useApplicationMenu.ts +79 -0
  47. package/src/css/component/Application.module.scss +88 -0
  48. package/src/css/component/ApplicationContent.module.scss +119 -0
  49. package/src/css/component/ApplicationHero.module.scss +17 -0
  50. package/src/css/component/ApplicationMenu.module.scss +421 -0
  51. package/src/css/component/ApplicationSection.module.scss +43 -0
  52. package/src/css/component/ApplicationSide.module.scss +21 -0
  53. package/src/css/component/ApplicationTop.module.scss +111 -0
  54. package/src/data/index.ts +38 -0
  55. package/src/index.ts +3 -0
  56. package/src/routing/useNamedRoutes.ts +34 -0
  57. package/src/routing/useRoute.ts +11 -0
  58. package/src/types.d.ts +13 -0
  59. package/tsconfig.json +7 -0
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <aside :class="$style.applicationSide">
3
+ <slot/>
4
+ </aside>
5
+ </template>
6
+
7
+ <script
8
+ lang="ts"
9
+ setup>
10
+ import type { VNode } from 'vue';
11
+ import $style from '../css/component/ApplicationSide.module.scss';
12
+
13
+ defineSlots<{
14
+ default(): VNode;
15
+ }>();
16
+ </script>
@@ -0,0 +1,74 @@
1
+ <template>
2
+ <header :class="y > 1 ? $style.applicationTopScrolled : $style.applicationTop">
3
+ <div :class="$style.applicationTopBar">
4
+ <FluxApplicationMenuToggle :class="!showDesktopMenuToggle && $style.applicationTopMenuToggleHidden"/>
5
+
6
+ <slot name="start"/>
7
+
8
+ <FluxFadeTransition>
9
+ <FluxIcon
10
+ v-if="icon"
11
+ :key="icon"
12
+ :name="icon"/>
13
+ </FluxFadeTransition>
14
+
15
+ <FluxFadeTransition>
16
+ <span
17
+ v-if="title"
18
+ :key="title"
19
+ :class="$style.applicationTopBarTitle">
20
+ {{ title }}
21
+ </span>
22
+ </FluxFadeTransition>
23
+
24
+ <FluxSpacer/>
25
+
26
+ <slot name="end"/>
27
+ </div>
28
+
29
+ <FluxRouteTransition>
30
+ <div
31
+ v-if="slots.tabs"
32
+ :class="clsx(
33
+ layout === 'default' && $style.applicationTopTabsDefault,
34
+ layout === 'dashboard' && $style.applicationTopTabsDashboard,
35
+ layout === 'full' && $style.applicationTopTabsFull,
36
+ layout === 'medium' && $style.applicationTopTabsMedium,
37
+ layout === 'narrow' && $style.applicationTopTabsNarrow
38
+ )">
39
+ <FluxTabBar>
40
+ <slot name="tabs"/>
41
+ </FluxTabBar>
42
+ </div>
43
+
44
+ <div v-else/>
45
+ </FluxRouteTransition>
46
+ </header>
47
+ </template>
48
+
49
+ <script
50
+ lang="ts"
51
+ setup>
52
+ import { FluxFadeTransition, FluxIcon, FluxRouteTransition, FluxSpacer, FluxTabBar } from '@flux-ui/components';
53
+ import { useScrollPosition } from '@flux-ui/internals';
54
+ import type { FluxIconName } from '@flux-ui/types';
55
+ import clsx from 'clsx';
56
+ import type { VNode } from 'vue';
57
+ import { useApplicationInjection } from '../composable';
58
+ import FluxApplicationMenuToggle from './FluxApplicationMenuToggle.vue';
59
+ import $style from '../css/component/ApplicationTop.module.scss';
60
+
61
+ defineProps<{
62
+ readonly icon?: FluxIconName;
63
+ readonly title?: string;
64
+ }>();
65
+
66
+ const slots = defineSlots<{
67
+ end?(): VNode;
68
+ start?(): VNode;
69
+ tabs?(): VNode;
70
+ }>();
71
+
72
+ const {layout, showDesktopMenuToggle} = useApplicationInjection();
73
+ const {y} = useScrollPosition();
74
+ </script>
@@ -0,0 +1,12 @@
1
+ export { default as FluxApplication } from './FluxApplication.vue';
2
+ export { default as FluxApplicationContent } from './FluxApplicationContent.vue';
3
+ export { default as FluxApplicationHero } from './FluxApplicationHero.vue';
4
+ export { default as FluxApplicationMenu } from './FluxApplicationMenu.vue';
5
+ export { default as FluxApplicationMenuAccount } from './FluxApplicationMenuAccount.vue';
6
+ export { default as FluxApplicationMenuContext } from './FluxApplicationMenuContext.vue';
7
+ export { default as FluxApplicationMenuContextStack } from './FluxApplicationMenuContextStack.vue';
8
+ export { default as FluxApplicationMenuPromo } from './FluxApplicationMenuPromo.vue';
9
+ export { default as FluxApplicationMenuToggle } from './FluxApplicationMenuToggle.vue';
10
+ export { default as FluxApplicationSection } from './FluxApplicationSection.vue';
11
+ export { default as FluxApplicationSide } from './FluxApplicationSide.vue';
12
+ export { default as FluxApplicationTop } from './FluxApplicationTop.vue';
@@ -0,0 +1,3 @@
1
+ export { default as useApplicationContextMenu } from './useApplicationContextMenu';
2
+ export { default as useApplicationInjection } from './useApplicationInjection';
3
+ export { default as useApplicationMenu } from './useApplicationMenu';
@@ -0,0 +1,19 @@
1
+ import { computed, type ComputedRef, toRef } from 'vue';
2
+ import useNamedRoutes from '../routing/useNamedRoutes';
3
+
4
+ export default function (name: string = 'menu'): UseApplicationContextMenu {
5
+ const matches = useNamedRoutes(toRef(() => name));
6
+
7
+ const hasContextMenu = computed(() => matches.value.length > 0);
8
+ const contextMenuKey = computed(() => matches.value.map(m => m.record.path).join('|') || undefined);
9
+
10
+ return {
11
+ contextMenuKey,
12
+ hasContextMenu
13
+ };
14
+ }
15
+
16
+ type UseApplicationContextMenu = {
17
+ readonly contextMenuKey: ComputedRef<string | undefined>;
18
+ readonly hasContextMenu: ComputedRef<boolean>;
19
+ };
@@ -0,0 +1,25 @@
1
+ import { inject, onBeforeUnmount, onMounted, watch } from 'vue';
2
+ import { type FluxApplicationContextInfo, FluxApplicationInjectionKey } from '../data';
3
+
4
+ export default function (info: () => Omit<FluxApplicationContextInfo, 'id'>): void {
5
+ const injection = inject(FluxApplicationInjectionKey, null);
6
+
7
+ if (!injection) {
8
+ return;
9
+ }
10
+
11
+ const id = Symbol('application-context');
12
+
13
+ onMounted(() => {
14
+ injection.pushContext({id, ...info()});
15
+ });
16
+
17
+ watch(info, next => {
18
+ injection.removeContext(id);
19
+ injection.pushContext({id, ...next});
20
+ });
21
+
22
+ onBeforeUnmount(() => {
23
+ injection.removeContext(id);
24
+ });
25
+ }
@@ -0,0 +1,12 @@
1
+ import { inject } from 'vue';
2
+ import { type FluxApplicationInjection, FluxApplicationInjectionKey } from '../data';
3
+
4
+ export default function (): FluxApplicationInjection {
5
+ const injection = inject(FluxApplicationInjectionKey);
6
+
7
+ if (!injection) {
8
+ throw new Error('[Flux] useApplicationInjection() was used outside a FluxApplication component.');
9
+ }
10
+
11
+ return injection;
12
+ }
@@ -0,0 +1,79 @@
1
+ import { computed, type ComputedRef, type Ref } from 'vue';
2
+ import type { FluxApplicationContextInfo, FluxApplicationLayout } from '../data';
3
+ import useApplicationInjection from './useApplicationInjection';
4
+
5
+ export default function (): UseApplicationMenu {
6
+ const {
7
+ activeContext,
8
+ contexts,
9
+ isMenuCollapsed,
10
+ layout,
11
+ totalLevels,
12
+ viewIndex,
13
+ goToChild,
14
+ goToCurrent,
15
+ goToLevel,
16
+ goToMain,
17
+ goToParent
18
+ } = useApplicationInjection();
19
+
20
+ const isMainMenuVisible = computed(() => viewIndex.value === 0);
21
+ const canGoBack = computed(() => viewIndex.value > 0);
22
+ const canGoForward = computed(() => viewIndex.value < totalLevels.value - 1);
23
+
24
+ return {
25
+ activeContext,
26
+ canGoBack,
27
+ canGoForward,
28
+ contexts,
29
+ isMainMenuVisible,
30
+ isMenuCollapsed,
31
+ layout,
32
+ totalLevels,
33
+ viewIndex,
34
+
35
+ goToChild,
36
+ goToCurrent,
37
+ goToLevel,
38
+ goToMain,
39
+ goToParent,
40
+
41
+ close: () => isMenuCollapsed.value = true,
42
+ open: () => isMenuCollapsed.value = false,
43
+ toggle: () => isMenuCollapsed.value = !isMenuCollapsed.value,
44
+
45
+ // Convenience aliases mapping onto the viewIndex model.
46
+ showMainMenu: goToMain,
47
+ showContextMenu: goToCurrent,
48
+ toggleMainMenu: () => {
49
+ if (viewIndex.value === 0) {
50
+ goToCurrent();
51
+ } else {
52
+ goToMain();
53
+ }
54
+ }
55
+ };
56
+ }
57
+
58
+ type UseApplicationMenu = {
59
+ readonly activeContext: ComputedRef<FluxApplicationContextInfo | undefined>;
60
+ readonly canGoBack: ComputedRef<boolean>;
61
+ readonly canGoForward: ComputedRef<boolean>;
62
+ readonly contexts: ComputedRef<readonly FluxApplicationContextInfo[]>;
63
+ readonly isMainMenuVisible: ComputedRef<boolean>;
64
+ readonly isMenuCollapsed: Ref<boolean>;
65
+ readonly layout: Ref<FluxApplicationLayout>;
66
+ readonly totalLevels: ComputedRef<number>;
67
+ readonly viewIndex: Ref<number>;
68
+ close(): void;
69
+ goToChild(): void;
70
+ goToCurrent(): void;
71
+ goToLevel(index: number): void;
72
+ goToMain(): void;
73
+ goToParent(): void;
74
+ open(): void;
75
+ showContextMenu(): void;
76
+ showMainMenu(): void;
77
+ toggle(): void;
78
+ toggleMainMenu(): void;
79
+ };
@@ -0,0 +1,88 @@
1
+ @use '$flux/css/mixin';
2
+
3
+ :root {
4
+ --application-duration: 360ms;
5
+ --application-menu-surface: var(--gray-100);
6
+ --application-menu-surface-stroke: var(--gray-200);
7
+ --application-menu-width: 300px;
8
+ --application-menu-width-collapsed: 69px;
9
+ --application-side-width: 300px;
10
+ --application-top-height: 66px;
11
+ }
12
+
13
+ [dark] {
14
+ --application-menu-surface: color-mix(in srgb, var(--gray-25), black 25%);
15
+ --application-menu-surface-stroke: var(--gray-100);
16
+ }
17
+
18
+ .application {
19
+ position: relative;
20
+ display: flex;
21
+ transition: padding var(--application-duration) var(--swift-out);
22
+ transition-property: padding-left, padding-right;
23
+
24
+ &:has(> .applicationSide) {
25
+ padding-right: var(--application-side-width);
26
+ }
27
+ }
28
+
29
+ .applicationBody {
30
+ position: relative;
31
+ display: flex;
32
+ min-width: 0;
33
+ min-height: 100dvh;
34
+ flex-flow: column;
35
+ flex-grow: 1;
36
+
37
+ &:has(> .applicationContentFull > :is(.calendar, .table)) {
38
+ max-height: 100dvh;
39
+ }
40
+ }
41
+
42
+ .applicationMenuBackdrop {
43
+ position: fixed;
44
+ display: none;
45
+ inset: 0;
46
+ width: 100dvw;
47
+ height: 100dvh;
48
+ padding: 0;
49
+ border: 0;
50
+ background: rgb(from var(--gray-200) r g b / .5);
51
+ backdrop-filter: blur(3px) saturate(180%);
52
+ transition: var(--application-duration) var(--swift-out);
53
+ transition-property: background, backdrop-filter, opacity;
54
+ z-index: 1900;
55
+ }
56
+
57
+ @include mixin.breakpoint-up(lg) {
58
+ .application:has(> .applicationMenu) {
59
+ padding-left: var(--application-menu-width);
60
+ }
61
+
62
+ .application:has(> .applicationMenu[data-collapsed][data-collapsible]) {
63
+ padding-left: var(--application-menu-width-collapsed);
64
+ }
65
+ }
66
+
67
+ @include mixin.breakpoint-down(md) {
68
+ .application {
69
+ &:has(> .applicationSide) {
70
+ padding-right: 0;
71
+ }
72
+ }
73
+
74
+ .applicationMenuBackdrop {
75
+ display: block;
76
+ }
77
+
78
+ .application:has(> .applicationMenu[data-collapsed]) .applicationMenuBackdrop {
79
+ pointer-events: none;
80
+ opacity: 0;
81
+ }
82
+
83
+ html[data-application-menu-open],
84
+ html[data-application-menu-open] body {
85
+ overflow: hidden;
86
+ overscroll-behavior: contain;
87
+ }
88
+ }
@@ -0,0 +1,119 @@
1
+ @use '$flux/css/mixin';
2
+
3
+ .applicationContent {
4
+ position: relative;
5
+ display: flex;
6
+ container: applicationContent / inline-size;
7
+ margin-left: auto;
8
+ margin-right: auto;
9
+ padding-top: 21px;
10
+ padding-bottom: 21px;
11
+ flex-flow: column;
12
+ flex-grow: 1;
13
+ gap: 21px;
14
+ }
15
+
16
+ .applicationContentDefault,
17
+ .applicationContentDashboard {
18
+ composes: applicationContent;
19
+
20
+ width: min(1620px, 100% - 42px);
21
+ }
22
+
23
+ .applicationContentDashboard {
24
+ gap: 45px;
25
+ }
26
+
27
+ .applicationContentFull {
28
+ composes: applicationContent;
29
+
30
+ padding-top: 0;
31
+ padding-bottom: 0;
32
+ width: calc(100% - 42px);
33
+ }
34
+
35
+ .applicationContentMedium {
36
+ composes: applicationContent;
37
+
38
+ width: min(1280px, 100% - 42px);
39
+ }
40
+
41
+ .applicationContentNarrow {
42
+ composes: applicationContent;
43
+
44
+ width: min(840px, 100% - 42px);
45
+ }
46
+
47
+ .applicationContentFull {
48
+ &:has(> :is(:local(.calendar), :local(.table))) {
49
+ min-height: 0;
50
+ width: 100%;
51
+ contain: paint;
52
+ overflow: hidden;
53
+ }
54
+
55
+ > :is(:local(.calendar), :local(.table)) {
56
+ max-height: 100%;
57
+ flex-grow: 1;
58
+ }
59
+
60
+ > :local(.calendar) {
61
+ border-left: 0;
62
+ border-right: 0;
63
+ border-radius: 0;
64
+
65
+ :local(.calendarActions) {
66
+ padding-left: 21px;
67
+ padding-right: 21px;
68
+ }
69
+ }
70
+
71
+ > :local(.table) {
72
+ :local(.tableCell):first-child :local(.tableCellContent) {
73
+ padding-left: 21px;
74
+ }
75
+
76
+ :local(.tableCell):last-child :local(.tableCellContent) {
77
+ padding-right: 21px;
78
+ }
79
+ }
80
+ }
81
+
82
+ @include mixin.breakpoint-down(md) {
83
+ .applicationContentDefault,
84
+ .applicationContentMedium,
85
+ .applicationContentNarrow {
86
+ gap: 15px;
87
+ }
88
+
89
+ .applicationContentDashboard {
90
+ gap: 30px;
91
+ }
92
+
93
+ .applicationContentFull {
94
+ width: 100%;
95
+ }
96
+
97
+ .applicationContentFull {
98
+ > :is(.calendar, .table) {
99
+ margin-left: 0;
100
+ margin-right: 0;
101
+ height: auto;
102
+ }
103
+
104
+ > .calendar .calendarActions {
105
+ padding-left: 12px;
106
+ padding-right: 12px;
107
+ }
108
+
109
+ > .table {
110
+ .tableCell:first-child .tableCellContent {
111
+ padding-left: 12px;
112
+ }
113
+
114
+ .tableCell:last-child .tableCellContent {
115
+ padding-right: 12px;
116
+ }
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,17 @@
1
+ .applicationHero {
2
+ display: flex;
3
+ align-items: center;
4
+ flex-flow: row;
5
+ gap: 21px;
6
+ }
7
+
8
+ .applicationHeroBody {
9
+ display: flex;
10
+ flex-flow: column;
11
+ flex-grow: 1;
12
+ gap: 6px;
13
+ }
14
+
15
+ .applicationHeroSubtitle {
16
+ color: var(--foreground-secondary);
17
+ }