@handaotech-design/bom 0.0.40 → 0.0.42

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,420 @@
1
+ <script lang="ts" setup>
2
+ import { nextTick, onBeforeUnmount, onMounted, ref, toRefs, watch } from 'vue'
3
+ import type { TreeProps } from 'ant-design-vue'
4
+ import { Dropdown, Tree } from 'ant-design-vue'
5
+ import { watchDebounced } from '@vueuse/shared'
6
+ import * as _ from 'lodash-es'
7
+ import type { DataNode } from 'ant-design-vue/es/vc-tree-select/interface'
8
+ import type { EventDataNode } from 'ant-design-vue/es/tree'
9
+ import { MoreOutlined } from '@ant-design/icons-vue'
10
+ import HdGrayInput from '../gray-input'
11
+ import type { BomNode, BomTreeConfig } from '../../models'
12
+
13
+ const props = withDefaults(defineProps<Props>(), {
14
+ maintainable: false,
15
+ })
16
+ const emit = defineEmits(['select'])
17
+ const COMPONENT_NAME = 'HdBomTreeView'
18
+ defineOptions({
19
+ name: COMPONENT_NAME,
20
+ components: { ATree: Tree, ADropdown: Dropdown },
21
+ })
22
+
23
+ type TreeNodeWithMeta = DataNode & {
24
+ parentKeys: string[]
25
+ }
26
+
27
+ interface Props {
28
+ treeData: TreeProps['treeData']
29
+ config: BomTreeConfig
30
+ maintainable?: boolean
31
+ shouldSelect?: (node: DataNode) => Promise<boolean>
32
+ keyNodeMap: Map<string, BomNode>
33
+ firstSelectableKey?: string
34
+ }
35
+
36
+ const expandedKeys = ref<(string | number)[]>([])
37
+ const searchValue = ref<string>('')
38
+ const autoExpandParent = ref<boolean>(true)
39
+ const { treeData: _treeData } = toRefs(props)
40
+ const filteredTreeData = ref<TreeProps['treeData']>([])
41
+ const treeContainerHeight = ref<number>(0)
42
+ const treeContainerId = 'treeContainer'
43
+ let keyToNodeMap = new Map<string, TreeNodeWithMeta>()
44
+ const selectedKeys = ref<string[]>([])
45
+ const isPreservingTreeState = ref<boolean>(false)
46
+ const initTreeState = () => {
47
+ searchValue.value = ''
48
+ selectedKeys.value = []
49
+ expandedKeys.value = []
50
+ }
51
+
52
+ const onExpand = (keys: Key[]) => {
53
+ expandedKeys.value = keys
54
+ autoExpandParent.value = false
55
+ }
56
+
57
+ const updateTreeContainerHeight = () => {
58
+ const treeContainer = document.getElementById(treeContainerId)
59
+ if (treeContainer) {
60
+ treeContainerHeight.value = treeContainer.clientHeight
61
+ }
62
+ }
63
+
64
+ const buildKeyToNodeMap = (treeData: TreeProps['treeData']) => {
65
+ const keyMap = new Map<string, TreeNodeWithMeta>()
66
+ const traverse = (nodes: TreeProps['treeData'] = [], parentKeys: string[] = []) => {
67
+ for (const node of nodes) {
68
+ if (parentKeys) {
69
+ keyMap.set(node.key as string, {
70
+ ...node,
71
+ parentKeys: parentKeys || [],
72
+ } as any)
73
+ }
74
+ if (!_.isEmpty(node.children)) {
75
+ traverse(node.children, [...parentKeys, node.key as string])
76
+ }
77
+ }
78
+ }
79
+ traverse(treeData)
80
+ return keyMap
81
+ }
82
+
83
+ const filterTreeData = (data: TreeProps['treeData'], filteredKeys: string[]) => {
84
+ const getNodes = (result: any, node: any) => {
85
+ if (_.includes(filteredKeys, node.key)) {
86
+ result.push({ ...node })
87
+ return result
88
+ }
89
+ if (Array.isArray(node.children)) {
90
+ const children = node.children.reduce(getNodes, [])
91
+ if (!_.isEmpty(children)) {
92
+ result.push({ ...node, children })
93
+ }
94
+ }
95
+ return result
96
+ }
97
+ return (data || []).reduce(getNodes, [])
98
+ }
99
+
100
+ // 获取直接父节点的 key
101
+ const getParentKeys = (key: string): string[] | undefined => {
102
+ const treeNode = keyToNodeMap.get(key)
103
+ return treeNode?.parentKeys || []
104
+ }
105
+
106
+ const selectFirstSelectableNode = (preserveExpanded = false) => {
107
+ const firstNode: any = _.find(Array.from(keyToNodeMap.values()), node => (node as any)?.selectable)
108
+ if (!firstNode) {
109
+ return
110
+ }
111
+
112
+ nextTick(() => {
113
+ const parentKeys = getParentKeys(firstNode.key as string) as string[]
114
+ expandedKeys.value = preserveExpanded
115
+ ? Array.from(new Set([...expandedKeys.value, ...parentKeys])) // 取并集
116
+ : parentKeys
117
+ selectedKeys.value = [firstNode.key]
118
+ })
119
+ }
120
+
121
+ type Key = string | number
122
+ const onSelected = async (keys: Key[], { node }: { node: EventDataNode }) => {
123
+ if (_.isFunction(props.shouldSelect) && node?.dataRef && !(await props.shouldSelect(node.dataRef))) {
124
+ return
125
+ }
126
+ const key = node?.dataRef?.key
127
+ if (key) {
128
+ selectedKeys.value = [key as string]
129
+ }
130
+ else {
131
+ selectedKeys.value = []
132
+ }
133
+ }
134
+
135
+ onMounted(async () => {
136
+ window.addEventListener('resize', updateTreeContainerHeight)
137
+ await nextTick(() => {
138
+ updateTreeContainerHeight()
139
+ })
140
+ })
141
+
142
+ onBeforeUnmount(() => {
143
+ window.removeEventListener('resize', updateTreeContainerHeight)
144
+ })
145
+
146
+ watch(
147
+ () => _treeData.value,
148
+ async () => {
149
+ filteredTreeData.value = _treeData.value
150
+ keyToNodeMap = buildKeyToNodeMap(_treeData.value ?? [])
151
+ initTreeState()
152
+ // if (!isPreservingTreeState.value) {
153
+ // selectFirstSelectableNode(true)
154
+ // }
155
+ },
156
+ {
157
+ immediate: true,
158
+ },
159
+ )
160
+
161
+ watchDebounced(
162
+ searchValue, (value: string) => {
163
+ let expanded: any[]
164
+ if (_.isEmpty(value)) {
165
+ expanded = getParentKeys(selectedKeys.value[0]) || []
166
+ filteredTreeData.value = _treeData.value
167
+ }
168
+ else {
169
+ const filteredNodes: TreeProps['treeData'] = []
170
+ expanded = (Array.from(keyToNodeMap.values()))
171
+ .map((item: any) => {
172
+ if (hasSearchMatch(item.title)) {
173
+ filteredNodes.push(item)
174
+ return getParentKeys(item.key)
175
+ }
176
+ return null
177
+ })
178
+ .filter((item, i, self) => item && self.indexOf(item) === i)
179
+ const filteredKeys = filteredNodes.map(item => item.key)
180
+ filteredTreeData.value = _.isEmpty(filteredKeys) ? [] : filterTreeData(_treeData.value, filteredKeys as unknown as string[])
181
+ }
182
+ expandedKeys.value = expanded
183
+ nextTick(() => {
184
+ expandedKeys.value = _.uniq(expanded.flat(1)) as any as string[]
185
+ })
186
+ }, { debounce: 500 })
187
+
188
+ watch(
189
+ () => selectedKeys.value,
190
+ () => {
191
+ if (selectedKeys.value && selectedKeys.value.length) {
192
+ return emit('select', keyToNodeMap.get(selectedKeys.value[0]))
193
+ }
194
+ },
195
+ )
196
+
197
+ function getIconClass(icon: string, isSelected: boolean) {
198
+ return isSelected ? `i-icon-${icon}-selected` : `i-icon-${icon}`
199
+ }
200
+
201
+ function getTitlePart(title: string, partType: 'before' | 'after') {
202
+ const _searchValue = searchValue.value || ''
203
+ const index = title.indexOf(_searchValue)
204
+
205
+ return {
206
+ before: title.substring(0, index),
207
+ after: title.substring(index + _searchValue.length),
208
+ }[partType]
209
+ }
210
+
211
+ function hasSearchMatch(title: string) {
212
+ return searchValue.value && title.includes(searchValue.value)
213
+ }
214
+
215
+ async function updateTreeWithPreservedState(updateDataFn: () => Promise<void>) {
216
+ const prevSelected = selectedKeys.value?.[0]
217
+ const prevExpanded = [...expandedKeys.value]
218
+ isPreservingTreeState.value = true
219
+ await updateDataFn()
220
+ await nextTick(() => {
221
+ expandedKeys.value = prevExpanded.filter(key => keyToNodeMap.has(key as string))
222
+
223
+ if (prevSelected && keyToNodeMap.has(prevSelected)) {
224
+ selectedKeys.value = [prevSelected]
225
+ }
226
+ else {
227
+ selectFirstSelectableNode(true)
228
+ }
229
+ isPreservingTreeState.value = false
230
+ })
231
+ }
232
+
233
+ function getDepth(key: string): number {
234
+ const parentKeys = getParentKeys(key)
235
+ if (_.isEmpty(parentKeys)) {
236
+ return -1
237
+ }
238
+ return parentKeys!.length + 1
239
+ }
240
+
241
+ defineExpose({
242
+ updateTreeWithPreservedState,
243
+ getParentKeys,
244
+ getDepth,
245
+ })
246
+ </script>
247
+
248
+ <template>
249
+ <div class="flex flex-col h-100%">
250
+ <div class="search-box">
251
+ <HdGrayInput
252
+ v-model:value="searchValue"
253
+ :placeholder="props.config?.filter?.placeholder || '输入关键词进行筛选(如名称/编号)'"
254
+ class="search-input"
255
+ >
256
+ <template #prefix>
257
+ <div class="i-icon-search w-16px h-16px" />
258
+ </template>
259
+ </HdGrayInput>
260
+ </div>
261
+ <div :id="treeContainerId" class="flex-grow tree-wrapper mt-12px overflow-y-hidden">
262
+ <div v-if="!_.isEmpty(filteredTreeData)">
263
+ <a-tree
264
+ :height="treeContainerHeight"
265
+ :expanded-keys="expandedKeys"
266
+ :auto-expand-parent="autoExpandParent"
267
+ :tree-data="filteredTreeData"
268
+ :block-node="true"
269
+ :default-selected-keys="[props.firstSelectableKey]"
270
+ @expand="onExpand"
271
+ @select="onSelected"
272
+ >
273
+ <template #title="{ title, dataRef }">
274
+ <div :class="`tree-node-tittle flex items-center ${dataRef.selectable ? 'selectable' : 'not-selectable'}`">
275
+ <div
276
+ v-if="!!dataRef.icon"
277
+ class="icon w-20px h-20px mr-4px min-w-20px"
278
+ :class="[getIconClass(dataRef.icon, selectedKeys.includes(dataRef.key))]"
279
+ />
280
+ <div v-if="hasSearchMatch(title)" class="tree-node-text">
281
+ <span>{{ getTitlePart(title, 'before') }}</span>
282
+ <span class="highlight" style="background-color: #FFD499">{{ searchValue }}</span>
283
+ <span>{{ getTitlePart(title, 'after') }}</span>
284
+ </div>
285
+ <div v-else class="tree-node-text">
286
+ {{ title }}
287
+ </div>
288
+ <div v-if="props.maintainable" class="click-menu-wrapper">
289
+ <a-dropdown
290
+ :trigger="['hover', 'click']"
291
+ :destroy-popup-on-hide="true"
292
+ >
293
+ <MoreOutlined class="menu-trigger" @click.stop />
294
+ <template #overlay>
295
+ <slot name="node-menu" :tree-node="dataRef" />
296
+ </template>
297
+ </a-dropdown>
298
+ </div>
299
+ </div>
300
+ </template>
301
+ <template #switcherIcon="{ dataRef }">
302
+ <div
303
+ v-if="expandedKeys.includes(dataRef.key)" class="i-icon-remove-minus icon w-16px h-16px"
304
+ style="font-size: 20px;"
305
+ />
306
+ <div v-else class="i-icon-remove-plus icon w-16px h-16px" />
307
+ </template>
308
+ </a-tree>
309
+ </div>
310
+ <div v-show="_.isEmpty(filteredTreeData)" class="w-100% h-100% flex justify-center items-center">
311
+ <span>暂无数据</span>
312
+ </div>
313
+ </div>
314
+ </div>
315
+ </template>
316
+
317
+ <style scoped>
318
+ .tree-wrapper {
319
+ background-color: #fff;
320
+ min-height: 0;
321
+ }
322
+
323
+ .search-box {
324
+ padding: 0 16px;
325
+ }
326
+
327
+ :deep(.ant-tree-list) .ant-tree-treenode-motion {
328
+ width: 100%;
329
+ }
330
+ :deep(.ant-tree-list) .ant-tree-treenode {
331
+ width: 100%;
332
+ align-items: center;
333
+ color: #2C2C2C;
334
+ font-size: 16px;
335
+ display: flex;
336
+ justify-content: center;
337
+ padding: 4px 0 4px 12px;
338
+ }
339
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-indent-unit {
340
+ width: 10px;
341
+ }
342
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-switcher {
343
+ width: 16px;
344
+ height: 16px;
345
+ padding: 0;
346
+ margin: 0 10px 0 0;
347
+ align-self: center;
348
+ line-height: 16px;
349
+ }
350
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper {
351
+ transition: none;
352
+ white-space: nowrap;
353
+ text-overflow: ellipsis;
354
+ margin-bottom: 0;
355
+ display: inline-flex;
356
+ overflow: visible !important;
357
+ flex: 1;
358
+ min-width: 0;
359
+ }
360
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper:hover {
361
+ background-color: #E9EBED;
362
+ }
363
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title {
364
+ text-overflow: ellipsis;
365
+ white-space: nowrap;
366
+ flex: 1;
367
+ min-width: 0;
368
+ position: relative;
369
+ }
370
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle.selectable {
371
+ cursor: pointer;
372
+ }
373
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle.not-selectable {
374
+ cursor: auto;
375
+ }
376
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle .click-menu-wrapper {
377
+ display: none;
378
+ margin-left: auto;
379
+ margin-right: 4px;
380
+ }
381
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper .ant-tree-title .tree-node-tittle:hover .click-menu-wrapper {
382
+ display: block;
383
+ }
384
+ :deep(.ant-tree-list) .ant-tree-treenode:hover {
385
+ background-color: #E9EBED;
386
+ }
387
+ :deep(.ant-tree-list) .ant-tree-treenode .ant-tree-node-content-wrapper {
388
+ user-select: auto;
389
+ }
390
+ :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected {
391
+ background-color: #EDF4FF;
392
+ border-radius: 4px;
393
+ color: #1E3B9D;
394
+ font-weight: 700;
395
+ }
396
+ :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected .ant-tree-switcher, :deep(.ant-tree-list) .ant-tree-treenode.ant-tree-treenode-selected .ant-tree-node-content-wrapper {
397
+ background-color: #EDF4FF;
398
+ }
399
+ :deep(.ant-tree-list) .ant-tree-node-content-wrapper {
400
+ align-items: center;
401
+ padding: 0;
402
+ }
403
+ :deep(.ant-tree-list) .ant-tree-node-content-wrapper {
404
+ display: flex;
405
+ margin-bottom: -4px;
406
+ }
407
+ :deep(.ant-tree-list) .ant-tree-node-content-wrapper .ant-tree-title {
408
+ flex-grow: 1;
409
+ display: block;
410
+ }
411
+
412
+ .tree-node-text {
413
+ display: inline-block;
414
+ max-width: 100%;
415
+ overflow: hidden;
416
+ text-overflow: ellipsis;
417
+ white-space: nowrap;
418
+ vertical-align: middle;
419
+ }
420
+ </style>
@@ -2,6 +2,7 @@
2
2
  import { ref, watch } from 'vue'
3
3
  import * as _ from 'lodash-es'
4
4
  import type { DataNode } from 'ant-design-vue/es/vc-tree-select/interface'
5
+ import type { EventDataNode } from 'ant-design-vue/es/tree'
5
6
  import type { BomNode, BomTreeConfig, Optional, WorkBenchLayoutConfig } from '../../models'
6
7
  import { convertBomDataToTree } from '../../utils'
7
8
  import HdLeftRight from '../left-right/index'
@@ -21,8 +22,11 @@ interface Props {
21
22
  maintainable?: boolean
22
23
  treeConfig: BomTreeConfig
23
24
  treeShouldSelect?: (node: DataNode) => Promise<boolean>
25
+ loadData?: (node: BomNode, eventNode?: EventDataNode) => Promise<BomNode[]>
24
26
  }
25
27
  const bomDataForTree = ref<BomNode[]>()
28
+ const firstSelectableKey = ref<string | undefined>()
29
+ const keyNodeMap = ref<Map<string, BomNode>>(new Map())
26
30
  const selectedNode = ref<BomNode>()
27
31
 
28
32
  async function onSelected(data: BomNode) {
@@ -37,7 +41,10 @@ watch(
37
41
  bomDataForTree.value = undefined
38
42
  }
39
43
  else {
40
- bomDataForTree.value = convertBomDataToTree(props.bomData!, props.treeConfig.nodeConfig.rule)
44
+ const { treeData, nodeMap, firstSelectableNodeKey } = convertBomDataToTree(props.bomData!, props.treeConfig.nodeConfig.rule)
45
+ bomDataForTree.value = treeData
46
+ keyNodeMap.value = nodeMap
47
+ firstSelectableKey.value = firstSelectableNodeKey
41
48
  }
42
49
  },
43
50
  { immediate: true },
@@ -64,6 +71,9 @@ defineExpose({
64
71
  :config="props.treeConfig"
65
72
  :maintainable="props.maintainable"
66
73
  :should-select="props.treeShouldSelect"
74
+ :first-selectable-key="firstSelectableKey"
75
+ :key-node-map="keyNodeMap"
76
+ :load-data="props.loadData"
67
77
  @select="(data: BomNode) => onSelected(data)"
68
78
  >
69
79
  <template #node-menu="{ treeNode }">
@@ -1,3 +1,7 @@
1
1
  import type { BomNode, BomTreeNodeConfig } from '../models';
2
2
  import type { BaseRule } from './rule-engine';
3
- export declare const convertBomDataToTree: (treeData: BomNode[], nodeConfigRule: BaseRule<BomTreeNodeConfig>) => BomNode[];
3
+ export declare function convertBomDataToTree(treeData: BomNode[], nodeConfigRule: BaseRule<BomTreeNodeConfig>): {
4
+ treeData: any[];
5
+ nodeMap: Map<string, any>;
6
+ firstSelectableNodeKey: string | undefined;
7
+ };
@@ -3,11 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.convertBomDataToTree = void 0;
6
+ exports.convertBomDataToTree = convertBomDataToTree;
7
7
  var _ = _interopRequireWildcard(require("lodash-es"));
8
8
  var _models = require("../models");
9
9
  var _ruleEngine = require("./rule-engine");
10
- var _template = require("./template");
11
10
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
12
11
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
13
12
  const defaultTreeNodeConfig = {
@@ -15,33 +14,75 @@ const defaultTreeNodeConfig = {
15
14
  template: _models.defaultTitleTemplate
16
15
  }
17
16
  };
18
- const convertBomDataToTree = (treeData, nodeConfigRule) => {
17
+ function convertBomDataToTree(treeData, nodeConfigRule) {
19
18
  const ruleEngine = new _ruleEngine.RuleEngine(nodeConfigRule);
20
- const traverse = (nodes = []) => {
21
- for (const node of nodes) {
22
- const nodeConfig = ruleEngine.matchOne({
19
+ const nodeMap = /* @__PURE__ */new Map();
20
+ const compileCache = /* @__PURE__ */new Map();
21
+ let firstSelectableNodeKey;
22
+ const getCompiledTemplate = tpl => {
23
+ if (!compileCache.has(tpl)) {
24
+ compileCache.set(tpl, _.template(tpl));
25
+ }
26
+ return compileCache.get(tpl);
27
+ };
28
+ const configCache = /* @__PURE__ */new Map();
29
+ const getConfig = node => {
30
+ const key = node.businessType || "default";
31
+ if (!configCache.has(key)) {
32
+ configCache.set(key, ruleEngine.matchOne({
23
33
  bomNode: node
24
- }, defaultTreeNodeConfig);
34
+ }, defaultTreeNodeConfig));
35
+ }
36
+ return configCache.get(key);
37
+ };
38
+ const traverse = (nodes = [], parentKeys = []) => {
39
+ for (const node of nodes) {
40
+ const nodeConfig = getConfig(node);
25
41
  const {
26
42
  title,
27
43
  selectable,
28
44
  icon,
29
45
  ...rest
30
- } = nodeConfig || {};
46
+ } = nodeConfig;
31
47
  const titleTemplate = title?.template ?? _models.defaultTitleTemplate;
48
+ let finalTitle = "--";
49
+ try {
50
+ const compiled = getCompiledTemplate(titleTemplate);
51
+ finalTitle = compiled(node);
52
+ } catch {}
53
+ const boolSelectable = selectable === _models.YesNo.YES;
54
+ if (boolSelectable && !firstSelectableNodeKey) {
55
+ firstSelectableNodeKey = node.key;
56
+ }
57
+ const isLeafObj = {
58
+ PROCESS_PLAN: false,
59
+ OPERATION: true
60
+ };
32
61
  Object.assign(node, {
33
62
  key: node.key,
34
- title: (0, _template.genText)(node, titleTemplate),
35
- selectable: selectable === _models.YesNo.YES,
63
+ title: finalTitle,
64
+ selectable: boolSelectable,
36
65
  icon,
66
+ isLeaf: !node?.children?.length || isLeafObj[node.businessType],
37
67
  ...rest
38
68
  });
69
+ const {
70
+ children,
71
+ ...restProps
72
+ } = node;
73
+ nodeMap.set(node.key, {
74
+ ...restProps,
75
+ parentKeys
76
+ });
39
77
  if (!_.isEmpty(node.children)) {
40
- traverse(node.children);
78
+ traverse(node.children, [...parentKeys, node.key]);
41
79
  }
42
80
  }
43
81
  };
44
82
  traverse(treeData);
45
- return treeData;
46
- };
47
- exports.convertBomDataToTree = convertBomDataToTree;
83
+ return {
84
+ treeData,
85
+ nodeMap,
86
+ firstSelectableNodeKey
87
+ };
88
+ }
package/dist/style.css CHANGED
@@ -42,6 +42,7 @@
42
42
  [grid=""]{display:grid;}
43
43
  .m-20px{margin:20px;}
44
44
  .mr-4px{margin-right:4px;}
45
+ .mr-8px{margin-right:8px;}
45
46
  .ms{margin-inline-start:1rem;}
46
47
  .mt-12px{margin-top:12px;}
47
48
  .inline{display:inline;}
@@ -84,4 +85,6 @@
84
85
  .filter{filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
85
86
  .transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);transition-duration:150ms;}
86
87
  .ease,
87
- [ease=""]{transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);}
88
+ [ease=""]{transition-timing-function:cubic-bezier(0.4, 0, 0.2, 1);}
89
+ .ease-out,
90
+ [ease-out=""]{transition-timing-function:cubic-bezier(0, 0, 0.2, 1);}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@handaotech-design/bom",
3
- "version": "0.0.40",
3
+ "version": "0.0.42",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "exports": {