@flowgram-vue/fixed-semi-materials 0.2.0

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.
@@ -0,0 +1,124 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ import { ref, computed } from 'vue';
7
+ import {
8
+ FlowNodeEntity,
9
+ FlowNodeRenderData,
10
+ FlowNodeTransformData,
11
+ } from '@flowgram-vue/document';
12
+ import { FlowRendererRegistry, FlowTextKey, useBaseColor } from '@flowgram-vue/renderer';
13
+ import { usePlayground } from '@flowgram-vue/core';
14
+
15
+ import { IconChevronLeft } from '../assets';
16
+
17
+ defineOptions({ name: 'TryCatchCollapse' });
18
+
19
+ const props = defineProps<{
20
+ node: FlowNodeEntity;
21
+ }>();
22
+
23
+ const { baseColor, baseActivatedColor } = useBaseColor();
24
+ const playground = usePlayground();
25
+ const activateData = props.node.getData(FlowNodeRenderData)!;
26
+ const transform = props.node.getData(FlowNodeTransformData)!;
27
+ const hoverActivated = ref(false);
28
+
29
+ const width = transform?.parent
30
+ ? transform.inputPoint.x - transform.parent.inputPoint.x
31
+ : 0;
32
+
33
+ const catchText = computed(() =>
34
+ props.node.getService(FlowRendererRegistry).getText(FlowTextKey.CATCH_TEXT)
35
+ );
36
+
37
+ const scrollToActivateNode = () => {
38
+ setTimeout(() => {
39
+ playground.config.scrollToView({
40
+ position: props.node?.getData(FlowNodeTransformData)?.inputPoint,
41
+ scrollToCenter: true,
42
+ });
43
+ }, 100);
44
+ };
45
+
46
+ const collapseBlock = () => {
47
+ transform.collapsed = true;
48
+ activateData.activated = false;
49
+ scrollToActivateNode();
50
+ };
51
+
52
+ const openBlock = () => {
53
+ transform.collapsed = false;
54
+ scrollToActivateNode();
55
+ };
56
+
57
+ const handleMouseEnter = () => {
58
+ hoverActivated.value = true;
59
+ activateData.activated = true;
60
+ };
61
+
62
+ const handleMouseLeave = () => {
63
+ hoverActivated.value = false;
64
+ activateData.activated = false;
65
+ };
66
+
67
+ const childCount = computed(
68
+ () =>
69
+ props.node.allCollapsedChildren.filter((child) => !child.hidden && child !== props.node)
70
+ .length
71
+ );
72
+
73
+ const badgeBg = computed(() =>
74
+ hoverActivated.value || activateData.lineActivated ? baseActivatedColor : baseColor
75
+ );
76
+ </script>
77
+
78
+ <template>
79
+ <div
80
+ v-if="transform && transform.parent"
81
+ :style="{
82
+ width: `${width}px`,
83
+ height: '40px',
84
+ display: 'flex',
85
+ alignItems: 'center',
86
+ justifyContent: 'center',
87
+ gap: '6px',
88
+ }"
89
+ @mouseenter="handleMouseEnter"
90
+ @mouseleave="handleMouseLeave"
91
+ >
92
+ <div
93
+ :data-label-id="props.labelId"
94
+ :style="{
95
+ fontSize: '12px',
96
+ color: hoverActivated || activateData.lineActivated ? baseActivatedColor : baseColor,
97
+ textAlign: 'center',
98
+ whiteSpace: 'nowrap',
99
+ backgroundColor: 'var(--g-editor-background)',
100
+ lineHeight: '20px',
101
+ }"
102
+ >
103
+ {{ catchText }}
104
+ </div>
105
+ <div
106
+ v-if="transform.collapsed"
107
+ class="fg-collapse is-hovered"
108
+ :style="{ background: badgeBg }"
109
+ aria-hidden="true"
110
+ @click="openBlock"
111
+ >
112
+ {{ childCount }}
113
+ </div>
114
+ <div
115
+ v-else-if="hoverActivated"
116
+ class="fg-collapse is-hovered"
117
+ :style="{ background: baseActivatedColor }"
118
+ aria-hidden="true"
119
+ @click="collapseBlock"
120
+ >
121
+ <IconChevronLeft />
122
+ </div>
123
+ </div>
124
+ </template>
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import {
7
+ EditorState,
8
+ type PlaygroundInteractiveType,
9
+ usePlayground,
10
+ usePlaygroundContainer,
11
+ useService,
12
+ } from '@flowgram-vue/core';
13
+ import {
14
+ FlowDocument,
15
+ FlowLayoutDefault,
16
+ FlowNodeRenderData,
17
+ } from '@flowgram-vue/document';
18
+ import { HistoryService } from '@flowgram-vue/history';
19
+ import { DisposableCollection } from '@flowgram-vue/utils';
20
+ import { computed, onBeforeUnmount, reactive, ref } from 'vue';
21
+
22
+ export interface FixedPlaygroundTools {
23
+ zoom: number;
24
+ zoomin: (easing?: boolean) => void;
25
+ zoomout: (easing?: boolean) => void;
26
+ updateZoom: (newZoom: number, easing?: boolean, easingDuration?: number) => void;
27
+ fitView: (easing?: boolean, easingDuration?: number, padding?: number) => Promise<void>;
28
+ isVertical: boolean;
29
+ changeLayout: (layout?: FlowLayoutDefault) => void;
30
+ interactiveType: PlaygroundInteractiveType;
31
+ setInteractiveType: (type: PlaygroundInteractiveType) => void;
32
+ canRedo: boolean;
33
+ canUndo: boolean;
34
+ redo: () => void;
35
+ undo: () => void;
36
+ }
37
+
38
+ export function useFixedPlaygroundTools(): FixedPlaygroundTools {
39
+ const playground = usePlayground();
40
+ const container = usePlaygroundContainer();
41
+ const historyService = container?.isBound?.(HistoryService)
42
+ ? container.get(HistoryService)
43
+ : undefined;
44
+ const doc = useService<FlowDocument>(FlowDocument);
45
+
46
+ const zoom = ref(1);
47
+ const layoutName = ref(doc.layout.name);
48
+ const canUndo = ref(false);
49
+ const canRedo = ref(false);
50
+
51
+ const handleFitView = (easing?: boolean, easingDuration?: number, padding?: number) => {
52
+ padding = padding || 30;
53
+ return playground.config.fitView(doc.root.bounds, easing, padding, easingDuration);
54
+ };
55
+
56
+ const changeLayout = (newLayout?: FlowLayoutDefault) => {
57
+ const allNodes = doc.getAllNodes();
58
+ newLayout =
59
+ newLayout ||
60
+ (doc.layout.name === FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT
61
+ ? FlowLayoutDefault.VERTICAL_FIXED_LAYOUT
62
+ : FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT);
63
+ allNodes.forEach((node) => {
64
+ const renderData = node.getData(FlowNodeRenderData);
65
+ renderData.node.classList.add('gedit-transition-ease');
66
+ });
67
+ setTimeout(() => {
68
+ handleFitView();
69
+ }, 10);
70
+ setTimeout(() => {
71
+ allNodes.forEach((node) => {
72
+ const renderData = node.getData(FlowNodeRenderData);
73
+ renderData.node.classList.remove('gedit-transition-ease');
74
+ });
75
+ }, 500);
76
+ doc.setLayout(newLayout);
77
+ layoutName.value = doc.layout.name;
78
+ };
79
+
80
+ const dispose = new DisposableCollection();
81
+ dispose.push(playground.onZoom((z) => (zoom.value = z)));
82
+ if (historyService) {
83
+ dispose.push(
84
+ historyService.undoRedoService.onChange(() => {
85
+ canUndo.value = historyService.canUndo();
86
+ canRedo.value = historyService.canRedo();
87
+ })
88
+ );
89
+ }
90
+ onBeforeUnmount(() => dispose.dispose());
91
+
92
+ const interactiveType = computed<PlaygroundInteractiveType>(() =>
93
+ playground.editorState.isMouseFriendlyMode() ? 'MOUSE' : 'PAD'
94
+ );
95
+
96
+ return reactive({
97
+ zoomin: (easing?: boolean) => playground.config.zoomin(easing),
98
+ zoomout: (easing?: boolean) => playground.config.zoomout(easing),
99
+ updateZoom: (value: number, easing?: boolean, easingDuration?: number) =>
100
+ playground.config.updateZoom(value, easing, easingDuration),
101
+ zoom,
102
+ fitView: handleFitView,
103
+ isVertical: computed(() => layoutName.value === FlowLayoutDefault.VERTICAL_FIXED_LAYOUT),
104
+ changeLayout,
105
+ canRedo,
106
+ canUndo,
107
+ undo: () => historyService?.undo(),
108
+ redo: () => historyService?.redo(),
109
+ interactiveType,
110
+ setInteractiveType: (type: PlaygroundInteractiveType) => {
111
+ if (type === 'MOUSE') {
112
+ playground.editorState.changeState(EditorState.STATE_MOUSE_FRIENDLY_SELECT.id);
113
+ } else {
114
+ playground.editorState.changeState(EditorState.STATE_SELECT.id);
115
+ }
116
+ },
117
+ }) as FixedPlaygroundTools;
118
+ }
package/src/env.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ declare module '*.vue' {
7
+ import type { DefineComponent } from 'vue';
8
+ const component: DefineComponent<object, object, unknown>;
9
+ export default component;
10
+ }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import './styles.css';
7
+
8
+ export { defaultFixedSemiMaterials, PlaygroundTools } from './components';
9
+ export { useFixedPlaygroundTools } from './composables/use-fixed-playground-tools';
package/src/styles.css ADDED
@@ -0,0 +1,225 @@
1
+ .fg-fixed-chrome {
2
+ --fg-primary: hsl(252 62% 54.9%);
3
+ --fg-primary-09: hsl(252deg 62% 55% / 9%);
4
+ --fg-adder: rgb(143, 149, 158);
5
+ --fg-collapse: #bbbfc4;
6
+ --fg-collapse-active: #82a7fc;
7
+ --fg-line: #3370ff;
8
+ }
9
+
10
+ .fg-adder-wrap {
11
+ width: 6px;
12
+ height: 6px;
13
+ background-color: var(--fg-adder);
14
+ color: #fff;
15
+ border-radius: 50%;
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ cursor: pointer;
20
+ }
21
+
22
+ .fg-adder-wrap.is-hovered {
23
+ width: 15px;
24
+ height: 15px;
25
+ }
26
+
27
+ .fg-icon-plus {
28
+ width: 14px;
29
+ height: 14px;
30
+ color: #3370ff;
31
+ background: #fff;
32
+ border-radius: 15px;
33
+ }
34
+
35
+ .fg-popover {
36
+ position: absolute;
37
+ z-index: 20;
38
+ left: 18px;
39
+ top: 50%;
40
+ transform: translateY(-50%);
41
+ background: #fff;
42
+ border: 1px solid #e5e6eb;
43
+ border-radius: 8px;
44
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
45
+ padding: 8px;
46
+ }
47
+
48
+ .fg-collapse {
49
+ width: 16px;
50
+ height: 16px;
51
+ font-size: 10px;
52
+ border-radius: 9px;
53
+ display: flex;
54
+ color: #fff;
55
+ cursor: pointer;
56
+ justify-content: center;
57
+ align-items: center;
58
+ background: var(--fg-collapse);
59
+ }
60
+
61
+ .fg-collapse.is-hovered {
62
+ background: var(--fg-collapse-active);
63
+ }
64
+
65
+ .fg-collapse.is-horizontal-collapse {
66
+ transform: rotate(-90deg);
67
+ }
68
+
69
+ .fg-branch-adder {
70
+ width: 28px;
71
+ height: 18px;
72
+ background: rgb(187, 191, 196);
73
+ display: flex;
74
+ border-radius: 9px;
75
+ justify-content: space-evenly;
76
+ align-items: center;
77
+ color: #fff;
78
+ font-size: 10px;
79
+ font-weight: bold;
80
+ }
81
+
82
+ .fg-branch-adder.is-activated {
83
+ background: #82a7fc;
84
+ }
85
+
86
+ .fg-branch-adder.is-horizontal {
87
+ transform: rotate(90deg);
88
+ }
89
+
90
+ .fg-branch-adder .fg-branch-hit {
91
+ flex-grow: 1;
92
+ text-align: center;
93
+ cursor: pointer;
94
+ display: flex;
95
+ justify-content: center;
96
+ align-items: center;
97
+ }
98
+
99
+ .fg-branch-adder svg {
100
+ width: 12px;
101
+ height: 12px;
102
+ }
103
+
104
+ .fg-slot-adder {
105
+ display: flex;
106
+ background: #fff;
107
+ }
108
+
109
+ .fg-native-btn {
110
+ display: inline-flex;
111
+ align-items: center;
112
+ justify-content: center;
113
+ border: 1px solid #d9d9d9;
114
+ background: #fff;
115
+ border-radius: 4px;
116
+ height: 24px;
117
+ min-width: 24px;
118
+ padding: 0 6px;
119
+ cursor: pointer;
120
+ }
121
+
122
+ .fg-native-btn:hover {
123
+ border-color: #3370ff;
124
+ color: #3370ff;
125
+ }
126
+
127
+ .fg-drag-node {
128
+ position: relative;
129
+ height: 32px;
130
+ border-radius: 5px;
131
+ display: flex;
132
+ align-items: center;
133
+ cursor: pointer;
134
+ font-size: 19px;
135
+ border: 1px solid var(--fg-primary);
136
+ padding: 0 15px;
137
+ background: #fff;
138
+ }
139
+
140
+ .fg-drag-node:hover {
141
+ background-color: var(--fg-primary-09);
142
+ color: var(--fg-primary);
143
+ }
144
+
145
+ .fg-drag-counts {
146
+ position: absolute;
147
+ top: -8px;
148
+ right: -8px;
149
+ text-align: center;
150
+ line-height: 16px;
151
+ width: 16px;
152
+ height: 16px;
153
+ border-radius: 8px;
154
+ font-size: 12px;
155
+ color: #fff;
156
+ background-color: var(--fg-primary);
157
+ }
158
+
159
+ .fg-dragging-adder {
160
+ width: 16px;
161
+ height: 16px;
162
+ border-radius: 100px;
163
+ background-color: white;
164
+ border: 1px dashed #b8bcc1;
165
+ }
166
+
167
+ .fg-highlight-line {
168
+ display: flex;
169
+ align-items: center;
170
+ }
171
+
172
+ .fg-highlight-bar {
173
+ background: #3370ff;
174
+ }
175
+
176
+ .fg-node-wrap {
177
+ width: 100%;
178
+ height: 32px;
179
+ border-radius: 5px;
180
+ display: flex;
181
+ align-items: center;
182
+ cursor: pointer;
183
+ font-size: 19px;
184
+ padding: 0 15px;
185
+ }
186
+
187
+ .fg-node-wrap:hover {
188
+ background-color: var(--fg-primary-09);
189
+ color: var(--fg-primary);
190
+ }
191
+
192
+ .fg-node-label {
193
+ font-size: 12px;
194
+ margin-left: 10px;
195
+ }
196
+
197
+ .fg-nodes-wrap {
198
+ max-height: 500px;
199
+ overflow: auto;
200
+ }
201
+
202
+ .fg-nodes-wrap::-webkit-scrollbar {
203
+ display: none;
204
+ }
205
+
206
+ .fg-tools {
207
+ display: flex;
208
+ align-items: center;
209
+ gap: 8px;
210
+ }
211
+
212
+ .fg-tools button,
213
+ .fg-tools label {
214
+ border: 1px solid #d9d9d9;
215
+ background: #fff;
216
+ border-radius: 4px;
217
+ height: 28px;
218
+ padding: 0 8px;
219
+ cursor: pointer;
220
+ }
221
+
222
+ .fg-tools button:disabled {
223
+ opacity: 0.45;
224
+ cursor: not-allowed;
225
+ }