@zeedhi/vuetify 3.0.0 → 3.0.2

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.
@@ -46,7 +46,7 @@ export const ZdTreeProps = buildProps({
46
46
  default: true,
47
47
  },
48
48
  afterTitleSlot: {
49
- type: Object as PropType<ITreeConditionComponent>,
49
+ type: [String, Object] as PropType<ITreeConditionComponent>,
50
50
  default: () => [],
51
51
  },
52
52
  toolbarSlot: {
@@ -164,34 +164,100 @@ export default defineComponent({
164
164
  });
165
165
  };
166
166
 
167
- const setAfterTitleMargin = () => {
168
- nextTick(() => {
169
- const els = Array.from((proxy?.$el as HTMLElement).querySelectorAll<HTMLElement>('.zd-tree-after-title'));
170
- const maxOffset = els.reduce((acc, el) => {
171
- const sib = el.previousElementSibling as HTMLElement;
172
- if (!sib) return acc;
173
- const offset =
174
- sib.offsetLeft +
175
- sib.offsetWidth +
176
- parseInt(sib.style.marginLeft || '0') +
177
- parseInt(sib.style.marginRight || '0');
178
- return Math.max(acc, offset);
179
- }, 0);
180
- els.forEach((el) => {
181
- el.style.left = `${maxOffset}px`;
182
- });
167
+ const refsMap = ref<{ [key: string]: HTMLElement | null }>({});
168
+
169
+ function getAfterTitleEls(rootEl: HTMLElement) {
170
+ return Array.from(rootEl.querySelectorAll<HTMLElement>('.zd-tree-after-title'));
171
+ }
172
+
173
+ function getMaxOffset(els: HTMLElement[]) {
174
+ const siblings = els.map((el) =>
175
+ el.previousElementSibling instanceof HTMLElement ? el.previousElementSibling : null,
176
+ );
177
+ return siblings.reduce((result, el) => {
178
+ if (!el) return result;
179
+ const style = getComputedStyle(el);
180
+ const offset =
181
+ el.offsetLeft + el.offsetWidth + parseFloat(style.marginLeft || '0') + parseFloat(style.marginRight || '0');
182
+ return offset > result ? offset : result;
183
+ }, 0);
184
+ }
185
+
186
+ function setAfterTitleMargin(rootEl: HTMLElement | null) {
187
+ if (!rootEl) return;
188
+ const els = getAfterTitleEls(rootEl);
189
+ const maxOffset = getMaxOffset(els);
190
+ els.forEach((el) => {
191
+ el.style.left = `${maxOffset}px`;
183
192
  });
184
- };
193
+ }
194
+
195
+ function addObserver(node: ITreeNode<IDictionary>) {
196
+ if (!node.pathStr) return;
197
+ const ref = refsMap.value[node.pathStr];
198
+ const el = ref as HTMLElement;
199
+
200
+ const observer = new ResizeObserver(() => {
201
+ const root = treeRef.value?.$el || treeRef.value;
202
+ if (root) setAfterTitleMargin(root);
203
+ });
204
+ if (el.parentElement) {
205
+ observer.observe(el.parentElement);
206
+ }
207
+ }
185
208
 
186
209
  onMounted(() => {
187
- instance.setTree(treeRef.value!);
188
- setAfterTitleMargin();
210
+ instance.setTree(treeRef.value as any);
189
211
  nodeChange();
190
- if (instance.fillHeight) {
191
- setFillHeight(proxy?.$el as HTMLElement);
192
- }
212
+
213
+ const rootEl = (treeRef.value?.$el || treeRef.value) as HTMLElement;
214
+ if (!rootEl) return;
215
+
216
+ const observeAfterTitleSlots = () => {
217
+ const afterTitleEls = rootEl.querySelectorAll<HTMLElement>('.zd-tree-after-title');
218
+ afterTitleEls.forEach((el) => {
219
+ if (!el.parentElement) return;
220
+ if (!(el as any)._hasObserver) {
221
+ const resizeObserver = new ResizeObserver(() => setAfterTitleMargin(rootEl));
222
+ resizeObserver.observe(el.parentElement);
223
+ (el as any)._hasObserver = true;
224
+ }
225
+ });
226
+ };
227
+
228
+ setAfterTitleMargin(rootEl);
229
+ observeAfterTitleSlots();
230
+
231
+ if (instance.fillHeight) setFillHeight(rootEl);
232
+
233
+ const mutationObserver = new MutationObserver(() => {
234
+ setAfterTitleMargin(rootEl);
235
+ observeAfterTitleSlots();
236
+ });
237
+ mutationObserver.observe(rootEl, { childList: true, subtree: true });
193
238
  });
194
239
 
240
+ watch(
241
+ () => instance.nodes,
242
+ () => {
243
+ nextTick(() => {
244
+ const rootEl = (treeRef.value?.$el || treeRef.value) as HTMLElement;
245
+ if (!rootEl) return;
246
+
247
+ setAfterTitleMargin(rootEl);
248
+
249
+ // registra ResizeObserver nos novos afterTitleSlots
250
+ const afterTitleEls = rootEl.querySelectorAll<HTMLElement>('.zd-tree-after-title');
251
+ afterTitleEls.forEach((el) => {
252
+ if (!el.parentElement) return;
253
+ const observer = new ResizeObserver(() => setAfterTitleMargin(rootEl));
254
+ observer.observe(el.parentElement);
255
+ });
256
+ });
257
+ },
258
+ { deep: true },
259
+ );
260
+
195
261
  watch(
196
262
  () => instance.datasource?.data?.length,
197
263
  () => {
@@ -237,14 +303,32 @@ export default defineComponent({
237
303
  instance.nodeCheck(node, event, proxy?.$el as HTMLElement);
238
304
  };
239
305
 
240
- // Adiciona método para expandir/colapsar nó
241
306
  const toggleNode = (node: any) => {
242
307
  if (treeRef.value && typeof treeRef.value.toggleNode === 'function') {
243
308
  treeRef.value.toggleNode(node);
244
309
  } else {
245
310
  node.isExpanded = !node.isExpanded;
246
311
  }
312
+ updateAfterTitlePositions();
247
313
  };
314
+ function updateAfterTitlePositions() {
315
+ nextTick(() => {
316
+ const rootEl = (treeRef.value?.$el || treeRef.value) as HTMLElement;
317
+ if (!rootEl) return;
318
+
319
+ setAfterTitleMargin(rootEl);
320
+
321
+ const afterTitleEls = rootEl.querySelectorAll<HTMLElement>('.zd-tree-after-title');
322
+ afterTitleEls.forEach((el) => {
323
+ if (!el.parentElement) return;
324
+ if (!(el as any)._hasObserver) {
325
+ const observer = new ResizeObserver(() => setAfterTitleMargin(rootEl));
326
+ observer.observe(el.parentElement);
327
+ (el as any)._hasObserver = true;
328
+ }
329
+ });
330
+ });
331
+ }
248
332
 
249
333
  return {
250
334
  root,
@@ -259,6 +343,7 @@ export default defineComponent({
259
343
  instanceNode,
260
344
  nodeCheck,
261
345
  toggleNode,
346
+ addObserver,
262
347
  };
263
348
  },
264
349
  });
@@ -2,7 +2,10 @@
2
2
  <div
3
3
  :id="instance.name"
4
4
  v-show="instance.isVisible"
5
- :class="[instance.cssClass, 'zd-tree', theme]"
5
+ :class="[
6
+ instance.cssClass, 'zd-tree',
7
+ theme,
8
+ ]"
6
9
  :style="[
7
10
  cssColorVars,
8
11
  ...$styleObject(instance.cssStyle),
@@ -27,7 +30,9 @@
27
30
  <slot name="toolbarSlot"></slot>
28
31
  </div>
29
32
 
30
- <div class="zd-tree-container">
33
+ <div
34
+ class="zd-tree-container"
35
+ >
31
36
  <sl-vue-tree
32
37
  :model-value="instance.nodes"
33
38
  ref="treeRef"
@@ -59,7 +64,6 @@
59
64
  </template>
60
65
 
61
66
  <template #title="{ node, gap }">
62
- <div style="display: flex; align-items: center;">
63
67
  <span v-if="!node.children || node.children.length === 0" class="align"></span>
64
68
  <span v-html="gap" />
65
69
  <zd-tree-checkbox
@@ -72,31 +76,37 @@
72
76
  <template v-if="!$slots.titleSlot">
73
77
  <span
74
78
  v-if="!instance.titleSlot || instance.titleSlot.length === 0"
75
- :class="['item-title', { 'has-children': node.children.length }]"
79
+ :class="[
80
+ 'item-title',
81
+ { 'has-children': node.children.length }
82
+ ]"
76
83
  >
77
84
  {{ node.title }}
78
85
  </span>
79
- <span v-else class="zd-display-inline-flex">
86
+ <span v-else class='zd-display-inline-flex'>
80
87
  <component
81
- v-for="(comp, index) in instance.getSlotComponent(instance.titleSlot || [], node)"
88
+ v-for="(comp, index) in instance.getSlotComponent(instance.titleSlot, node)"
89
+ :class="[
90
+ 'item-title',
91
+ { 'has-children': node.children.length }
92
+ ]"
82
93
  :key="index"
83
94
  :is="comp.component"
84
- :class="['item-title', { 'has-children': node.children.length }]"
85
95
  v-bind="comp"
86
96
  />
87
97
  </span>
88
98
  </template>
89
- <slot name="titleSlot" :node="node" />
99
+ <slot name="titleSlot" v-bind:node="node"/>
90
100
  <zd-tree-after-title
91
101
  :ref="node.pathStr"
92
102
  :afterTitleSlot="instance.getSlotComponent(instance.afterTitleSlot || [], node)[0]"
93
- >
94
- <slot name="afterTitleSlot" :node="node" />
103
+ @hook:mounted="addObserver(node)"
104
+ >
105
+ <slot name="afterTitleSlot" v-bind:node="node"/>
95
106
  </zd-tree-after-title>
96
- </div>
97
107
  </template>
98
108
 
99
- <template #draginfo>
109
+ <template v-slot:draginfo>
100
110
  {{ selectedNodesTitle }}
101
111
  </template>
102
112
  </sl-vue-tree>
@@ -109,109 +119,38 @@
109
119
  <style lang="scss">
110
120
  @import 'sl-vue-tree-next/sl-vue-tree-next-minimal.css';
111
121
 
112
- .zd-tree .sl-vue-tree-nodes-list .sl-vue-tree-node .sl-vue-tree-node-item {
113
- height: 30px;
114
- line-height: 30px;
115
- }
116
-
117
- .sl-vue-tree-node-item,
118
- .sl-vue-tree-node-list {
119
- position: relative;
120
- display: flex;
121
- flex-direction: row;
122
- }
123
-
124
122
  .zd-tree {
125
123
  color: var(--zd-font-color);
126
124
  font-size: var(--zd-font-body1-size);
127
- font-weight: normal;
128
125
  overflow: auto;
129
126
 
130
127
  &-toolbar {
131
128
  display: flex;
129
+ margin-bottom: 1rem;
132
130
  }
133
131
 
134
- &.theme--light .sl-vue-tree-title {
135
- color: var(--zd-font-color);
136
- }
137
-
138
- &.theme--light .sl-vue-tree-node-item:hover {
139
- background: #eee;
140
- }
141
-
142
- &.theme--dark .sl-vue-tree-title {
143
- color: #fff;
144
- }
145
-
146
- &.theme--dark .sl-vue-tree-node-item:hover {
147
- background: #616161;
148
- }
149
-
150
- .sl-vue-tree-title {
151
- display: flex;
152
- }
153
-
154
- .sl-vue-tree-nodes-list {
132
+ .sl-vue-tree-next-nodes-list {
155
133
  list-style: none;
156
134
  padding-left: 0;
157
135
  margin: 0;
158
136
 
159
- .sl-vue-tree-node {
160
- padding-top: 3px;
161
- padding-left: 1rem;
137
+ .sl-vue-tree-next-node {
162
138
  cursor: pointer;
163
139
  user-select: none;
164
140
 
165
- .sl-vue-tree-node-item {
166
- display: flex !important;
167
- align-items: center !important;
168
- height: 30px;
169
- line-height: 30px;
170
- padding: 0 0.5rem;
171
- border-radius: 4px;
172
- transition: background-color 0.2s;
173
-
174
- &:hover {
175
- background-color: #eee;
176
- }
177
-
178
- .item-icon {
179
- margin-right: 0.5rem;
180
- }
181
-
182
- .item-title.has-children {
183
- font-weight: 700;
184
- }
185
-
186
- .zd-tree-checkbox {
187
- margin-right: 0.5rem;
188
- display: flex !important;
189
- align-items: center;
190
- padding: 0 3px 3px 0;
191
- }
192
-
193
- .v-input--selection-controls__ripple,
194
- .v-label {
195
- display: none !important;
196
- }
197
- }
198
-
199
- &.sl-vue-tree-selected > .sl-vue-tree-node-item {
200
- background-color: var(--current-row-color);
201
- color: var(--zd-font-color);
202
-
141
+ &.sl-vue-tree-next-selected > .sl-vue-tree-next-node-item {
203
142
  &:hover {
204
143
  background: var(--current-row-hover-color) !important;
205
144
  }
206
145
 
207
- .sl-vue-tree-toggle .v-icon {
146
+ .sl-vue-tree-next-toggle .v-icon {
208
147
  color: var(--zd-font-color);
209
148
  }
210
149
  }
211
150
 
212
- .sl-vue-tree-toggle {
213
- display: flex !important;
214
- align-items: center !important;
151
+ .sl-vue-tree-next-toggle {
152
+ display: flex;
153
+ align-items: center;
215
154
  margin-right: 4px;
216
155
 
217
156
  span .v-icon {
@@ -220,9 +159,28 @@
220
159
  }
221
160
  }
222
161
  }
162
+ }
163
+
164
+ .sl-vue-tree-next-gap {
165
+ display: inline-block;
166
+ width: 25px;
167
+ min-width: 25px;
168
+ flex-shrink: 0;
169
+ }
170
+
171
+ .sl-vue-tree-next-title {
172
+ display: flex;
173
+ align-items: center;
174
+ }
223
175
 
224
- .sl-vue-tree-gap {
225
- width: 16px;
176
+ .sl-vue-tree-next-toggle {
177
+ display: flex;
178
+ align-items: center;
179
+ margin-right: 0;
180
+
181
+ .v-icon,
182
+ i {
183
+ color: #3b3b3b !important;
226
184
  }
227
185
  }
228
186
 
@@ -230,68 +188,15 @@
230
188
  background-color: var(--current-row-color);
231
189
  color: var(--zd-font-color);
232
190
  }
233
- }
234
-
235
- .item-title {
236
- padding: 5px;
237
- }
238
-
239
- .item-title.has-children {
240
- font-weight: 700;
241
- }
242
-
243
- .sl-vue-tree-drag-info {
244
- position: absolute;
245
- background-color: rgba(0, 0, 0, 0.5);
246
- opacity: 0.5;
247
- margin-left: 20px;
248
- margin-bottom: 20px;
249
- padding: 5px 10px;
250
- }
251
191
 
252
- .theme--light.v-icon {
253
- color: rgba(143, 127, 127, 0.54);
254
- }
255
- .sl-vue-tree-next-gap {
256
- display: inline-block;
257
- width: 25px; // ajusta conforme tamanho do teu ícone
258
- flex-shrink: 0;
259
- }
260
-
261
- .sl-vue-tree-gap {
262
- display: inline-block;
263
- flex-shrink: 0;
264
- }
265
- .sl-vue-tree-next-title {
266
- display: flex;
267
- align-items: center;
268
- }
269
-
270
- .sl-vue-tree-next-toggle {
271
- display: flex;
272
- align-items: center;
273
- margin-right: 0px;
274
- }
275
-
276
- .sl-vue-tree-next-toggle .v-icon,
277
- .sl-vue-tree-next-toggle i {
278
- color: #3b3b3b !important;
279
- }
192
+ .align {
193
+ display: inline-block;
194
+ width: 32px;
195
+ min-width: 25px;
196
+ flex-shrink: 0;
197
+ }
280
198
 
281
- .zd-tree-after-title {
282
- display: flex;
283
- align-items: center;
284
- margin-left: 0.5rem;
285
- position: static;
286
- padding: 0;
287
- font-size: inherit;
288
- color: inherit;
289
- }
290
- .zd-tree .sl-vue-tree-nodes-list .sl-vue-tree-node .sl-vue-tree-toggle span .v-icon {
291
- margin: 0px 1px 0px 1px;
292
- padding-bottom: 1.4px;
293
- }
294
- .v-icon.v-icon {
199
+ .v-icon {
295
200
  align-items: center;
296
201
  display: inline-flex;
297
202
  font-feature-settings: "liga";
@@ -301,35 +206,34 @@
301
206
  line-height: 1;
302
207
  position: relative;
303
208
  text-indent: 0;
304
- transition: .3s cubic-bezier(.25,.8,.5,1), visibility 0s;
209
+ transition: .3s cubic-bezier(.25, .8, .5, 1), visibility 0s;
305
210
  vertical-align: middle;
306
- -webkit-user-select: none;
307
- -moz-user-select: none;
308
211
  user-select: none;
309
- }
310
- .v-checkbox.v-input {
311
- height: 30px;
312
- }
313
-
212
+ }
314
213
 
214
+ .v-checkbox.v-input {
215
+ height: 30px;
216
+ min-height: 30px;
217
+ max-height: 30px;
218
+ }
315
219
 
316
- .sl-vue-tree-gap, .sl-vue-tree-next-gap {
317
- display: inline-block;
318
- width: 25px !important;
319
- min-width: 25px !important;
320
- flex-shrink: 0;
321
- }
220
+ .sl-vue-tree-next-node-item,
221
+ .zd-tree-node-row {
222
+ max-height: 30px;
223
+ min-height: 30px;
224
+ height: 30px;
225
+ box-sizing: border-box;
226
+ align-items: center;
227
+ display: flex;
228
+ }
322
229
 
323
- .zd-tree .sl-vue-tree-nodes-list > .sl-vue-tree-node > .sl-vue-tree-node-item {
324
- padding-left: 25px !important;
325
- }
326
- .align {
327
- display: inline-block;
328
- width: 25px;
329
- min-width: 25px;
330
- flex-shrink: 0;
331
- }
332
- .zd-text p {
333
- padding: 6px;
230
+ .zd-tree-node-row {
231
+ display: flex;
232
+ align-items: center;
233
+ position: relative;
234
+ }
235
+ .item-title.has-children {
236
+ font-weight: 700;
237
+ }
334
238
  }
335
239
  </style>
@@ -1,4 +1,6 @@
1
1
  import type { ITreeConditionComponent } from '@zeedhi/common';
2
+ import { type ITreeNode } from '@zeedhi/common';
3
+ import type { IDictionary } from '@zeedhi/core';
2
4
  import { type PropType, defineComponent } from 'vue';
3
5
  import { buildProps } from '../../utils/buildProps';
4
6
 
@@ -7,7 +9,7 @@ export const ZdTreeAfterTitleProps = buildProps({
7
9
  type: Object as PropType<ITreeConditionComponent>,
8
10
  },
9
11
  node: {
10
- type: Object,
12
+ type: Object as PropType<ITreeNode<IDictionary>>,
11
13
  },
12
14
  });
13
15
 
@@ -1,9 +1,9 @@
1
1
  <template>
2
2
  <span
3
- v-if="afterTitleSlot && afterTitleSlot.text"
4
3
  class="zd-tree-after-title"
5
4
  >
6
5
  <component
6
+ v-if="afterTitleSlot && afterTitleSlot.text"
7
7
  class="zd-display-inline-block"
8
8
  :is="afterTitleSlot.component"
9
9
  v-bind="afterTitleSlot"
@@ -15,11 +15,19 @@
15
15
  <script lang="ts" src="./ZdTreeAfterTitle.ts"></script>
16
16
 
17
17
  <style>
18
- @import 'sl-vue-tree-next/sl-vue-tree-next-minimal.css';
19
18
  .zd-tree-after-title {
20
- display: inline-flex;
21
- align-items: center;
22
- position: static;
19
+ height: 30px;
20
+ min-height: 30px;
21
+ max-height: 30px;
22
+ gap: 2px;
23
+ position: absolute;
24
+ }
25
+ .after-slot-color {
26
+ background: #ccc;
27
+ margin-left: 10px;
28
+ padding: 6px 6px;
29
+ font-weight: normal;
30
+ font-size: 12px;
31
+ color: white;
23
32
  }
24
-
25
33
  </style>
@@ -16,8 +16,6 @@
16
16
  <script lang="ts" src="./ZdTreeCheckbox.ts" />
17
17
 
18
18
  <style lang="scss" >
19
- @import 'sl-vue-tree-next/sl-vue-tree-next-minimal.css';
20
-
21
19
  .zd-tree-checkbox {
22
20
  display: flex !important;
23
21
  align-items: center;
@@ -10,7 +10,7 @@ import {
10
10
  } from '@zeedhi/common';
11
11
  import { IDictionary, Utils } from '@zeedhi/core';
12
12
  import cloneDeep from 'lodash.clonedeep';
13
- import { NotProvidedError } from 'packages/vuetify/src/errors/not-provided';
13
+ import { NotProvidedError } from '../errors/not-provided';
14
14
  import { ComputedRef, UnwrapNestedRefs, computed, inject, nextTick, provide } from 'vue';
15
15
 
16
16
  export type DefaultLayout = {