hamzus-ui 0.0.94 → 0.0.96

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.
package/index.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  // button
4
4
  export { default as Button } from "./src/components/hamzus-ui/Button/Button.svelte"
5
+ export { default as ButtonGroup } from "./src/components/hamzus-ui/ButtonGroup/ButtonGroup.svelte"
5
6
  export { default as IconButton } from "./src/components/hamzus-ui/IconButton/IconButton.svelte"
6
7
  // text
7
8
  export { default as Chips } from "./src/components/hamzus-ui/Chips/Chips.svelte"
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // button
2
2
  export { default as Button } from "./src/components/hamzus-ui/Button/Button.svelte"
3
+ export { default as ButtonGroup } from "./src/components/hamzus-ui/ButtonGroup/ButtonGroup.svelte"
3
4
  export { default as IconButton } from "./src/components/hamzus-ui/IconButton/IconButton.svelte"
4
5
  // text
5
6
  export { default as Chips } from "./src/components/hamzus-ui/Chips/Chips.svelte"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hamzus-ui",
3
- "version": "0.0.94",
3
+ "version": "0.0.96",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "svelte": "index.js",
@@ -58,6 +58,7 @@
58
58
  </script>
59
59
 
60
60
  <div
61
+ class="parent-button-hamzus"
61
62
  style="
62
63
  --button-default-bg:var({colorConfig[variant].defaultBg});
63
64
  --button-default-border:var({colorConfig[variant].defaultBorder});
@@ -76,6 +76,7 @@
76
76
  text-overflow: ellipsis;
77
77
  overflow: hidden;
78
78
  position: relative;
79
+ flex-shrink: 0;
79
80
  }
80
81
  .button > :global(*) {
81
82
  color: var(--button-default-color);
@@ -0,0 +1,41 @@
1
+
2
+
3
+ <div class="button-group">
4
+ <slot></slot>
5
+ </div>
6
+
7
+ <style>
8
+ .button-group {
9
+ display: flex;
10
+ height: fit-content;
11
+ }
12
+ .button-group :global(.button) {
13
+ border-radius: 0px !important;
14
+ }
15
+ /* tout les element sauf le premier doivent avoir une ligne a gauche */
16
+ .button-group :global(> .parent-button-hamzus:not(.parent-button-hamzus:first-child) > .button) {
17
+ border-left: 0px solid var(--button-hover-border) !important;
18
+ }
19
+
20
+ .button-group :global(> .parent-button-hamzus:first-child > .button) {
21
+ border-top-left-radius: var(--radius-m) !important;
22
+ border-bottom-left-radius: var(--radius-m) !important;
23
+ }
24
+ .button-group :global(> .parent-button-hamzus:last-child > .button) {
25
+ border-top-right-radius: var(--radius-m) !important;
26
+ border-bottom-right-radius: var(--radius-m) !important;
27
+ }
28
+ /* tout les element sauf le premier doivent avoir une ligne a gauche */
29
+ .button-group :global(> .parent-popover-hamzus:not(.parent-popover-hamzus:first-child) .button) {
30
+ border-left: 0px solid var(--button-hover-border) !important;
31
+ }
32
+
33
+ .button-group :global(> .parent-popover-hamzus:first-child .button) {
34
+ border-top-left-radius: var(--radius-m) !important;
35
+ border-bottom-left-radius: var(--radius-m) !important;
36
+ }
37
+ .button-group :global(> .parent-popover-hamzus:last-child .button) {
38
+ border-top-right-radius: var(--radius-m) !important;
39
+ border-bottom-right-radius: var(--radius-m) !important;
40
+ }
41
+ </style>
@@ -18,6 +18,8 @@
18
18
  border-radius: var(--radius-l);
19
19
  border: 1px solid var(--bg-3);
20
20
  width: min(100vw, var(--width));
21
+ max-width: var(--hamzus-max-content-width);
22
+ overflow-x: auto;
21
23
  max-height: 100vh;
22
24
  }
23
25
  </style>
@@ -1,6 +1,6 @@
1
1
  <script>
2
2
  import Portal from '../Portal/Portal.svelte';
3
- import { onDestroy, onMount } from 'svelte';
3
+ import { onDestroy, onMount } from 'svelte';
4
4
 
5
5
  // import
6
6
 
@@ -8,8 +8,12 @@ import { onDestroy, onMount } from 'svelte';
8
8
  export let triggerFullWidth = false;
9
9
  export let direction = 'bottom';
10
10
  export let onOpen = undefined;
11
- export let avoidOpening = false
12
- export let style = ""
11
+ export let avoidOpening = false;
12
+ export let avoidClosing = false;
13
+ export let forceOpen = false;
14
+ export let forceClose = false;
15
+ export let style = '';
16
+ export let parentTag = null;
13
17
  // locale var
14
18
  let display = false;
15
19
  let exit = false;
@@ -19,40 +23,70 @@ import { onDestroy, onMount } from 'svelte';
19
23
  let content;
20
24
  let contentContainer;
21
25
 
26
+ let interval = null;
27
+
28
+ let maxContentHeight = null;
29
+ let maxContentWidth = null;
30
+ let triggerHeight = 0;
31
+ let triggerWidth = 0;
22
32
  let top = 0;
23
33
  let left = 0;
24
34
 
25
35
  const padding = 7;
26
36
 
37
+ $: if (forceOpen === true) {
38
+ open()
39
+
40
+
41
+ forceOpen = false
42
+ }
43
+ $: if (forceClose === true) {
44
+ close()
45
+
46
+
47
+ forceClose = false
48
+ }
49
+
27
50
  const entryPosition = {
28
51
  bottom: ['-12px', '0px'],
52
+ [`bottom-right`]: ['-12px', '-12px'],
53
+ [`bottom-left`]: ['-12px', '12px'],
29
54
  top: ['12px', '0px'],
55
+ [`top-right`]: ['12px', '12px'],
56
+ [`top-left`]: ['12px', '-12px'],
30
57
  left: ['0px', '12px'],
31
- right: ['0px', '-12px']
58
+ [`left-top`]: ['-12px', '12px'],
59
+ [`left-bottom`]: ['12px', '12px'],
60
+ right: ['0px', '-12px'],
61
+ [`right-top`]: ['-12px', '-12px'],
62
+ [`right-bottom`]: ['12px', '-12px']
32
63
  };
33
64
  // function
34
- function handleDisplay(e) {
35
- if (avoidOpening) {
36
- return
37
- }
38
- if (!calc[direction]) {
65
+ function handleDisplay(e, force) {
66
+ if (!force && avoidOpening) {
67
+ return;
68
+ }
69
+ if (!entryPosition[direction]) {
39
70
  console.error('Error : direction props not found !');
40
- return
71
+ return;
41
72
  }
42
73
 
43
74
  if (!display) {
44
- [top, left] = calc[direction]();
75
+ calculate();
45
76
  }
46
77
 
47
78
  toggleDisplay();
48
79
 
49
- if (onOpen !== undefined && typeof onOpen === 'function') {
50
- onOpen(e)
51
- }
80
+ if (onOpen !== undefined && typeof onOpen === 'function') {
81
+ onOpen(e);
82
+ }
52
83
  }
53
84
 
54
85
  export let toggleDisplay = () => {
55
86
  if (display) {
87
+ clearInterval(interval);
88
+ interval = null;
89
+
56
90
  // appliquer une animation
57
91
  exit = true;
58
92
  setTimeout(() => {
@@ -62,167 +96,221 @@ import { onDestroy, onMount } from 'svelte';
62
96
  disableExitEvent();
63
97
  enableScroll();
64
98
  } else {
99
+
100
+ interval = setInterval(() => {
101
+ calculate();
102
+ }, 100);
103
+
65
104
  enableExitEvent();
66
105
  disableScroll();
67
106
  }
68
-
107
+
69
108
  display = !display;
70
- }
109
+ };
71
110
 
72
- export let open = ()=>{
73
- if (display) {
74
- return
75
- }
111
+ let open = () => {
112
+ if (display) {
113
+ return;
114
+ }
115
+ calculate();
76
116
 
77
- toggleDisplay()
78
- }
79
- export let close = ()=>{
80
- if (!display) {
81
- return
82
- }
117
+ toggleDisplay();
118
+ };
119
+ let close = () => {
120
+ if (!display) {
121
+ return;
122
+ }
83
123
 
84
- toggleDisplay()
85
- }
86
-
87
- const calc = {
88
- bottom: () => {
89
- // recuperer la taille du content
90
- const contentWidth = content.offsetWidth;
91
- const contentHeight = content.offsetHeight;
92
- // recuperer la taille du trigger
93
- const triggerWidth = trigger.offsetWidth;
94
- const triggerHeight = trigger.offsetHeight;
95
- // recuperer la position du trigger par rapport a la fenetre
96
- const triggerRect = trigger.getBoundingClientRect();
97
- const triggerTop = triggerRect.top;
98
- const triggerLeft = triggerRect.left;
99
- const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
100
- const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
101
-
102
- // return values
103
- let topCalc = triggerTop + triggerHeight + padding;
104
- let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2;
105
-
106
- // verifier si il y a assez de la place en bas
107
- if (triggerBottom < contentHeight) {
108
- topCalc = window.innerHeight - contentHeight - padding;
109
- }
110
- // verifier si il y a assez de place a droite
111
- if (triggerRight < (contentWidth - triggerWidth) / 2) {
112
- leftCalc = window.innerWidth - contentWidth - padding;
113
- }
114
- // verifier si il y a assez de place a gauche
124
+ toggleDisplay();
125
+ };
115
126
 
116
- if (triggerLeft < (contentWidth - triggerWidth) / 2) {
117
- leftCalc = padding;
127
+ function calculate() {
128
+
129
+ // recuperer les données
130
+ maxContentHeight = null;
131
+ maxContentWidth = null;
132
+
133
+ // recuperer le contenue du trigger
134
+ const triggerContent = getFirstChild(trigger);
135
+
136
+ // recuperer la position du trigger par rapport a la fenetre
137
+ const triggerRect = triggerContent.getBoundingClientRect();
138
+
139
+ // recuperer la taille du trigger
140
+ triggerWidth = triggerContent.offsetWidth;
141
+ triggerHeight = triggerContent.offsetHeight;
142
+
143
+ // recuperer l'espace autour du trigger
144
+ const triggerTop = triggerRect.top;
145
+ const triggerLeft = triggerRect.left;
146
+ const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
147
+ const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
148
+
149
+ const calc = {
150
+ bottom: () => {
151
+ // limiter la height par la height disponible en dessous du trigger
152
+ maxContentHeight = triggerBottom - padding;
153
+
154
+ // recuperer le contenue du dropdown
155
+ const contentContent = getFirstChild(content);
156
+
157
+ // recuperer la taille du content
158
+ const contentWidth = contentContent.offsetWidth;
159
+ const contentHeight = contentContent.scrollHeight;
160
+
161
+ // return values
162
+ let topCalc = triggerTop + triggerHeight + padding;
163
+ let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2; // centrer
164
+
165
+ // si il y a pas assez de place en bas on verifie si ya plus de place en haut, si ya plus de place en haut on display en haut
166
+ if (triggerBottom < contentHeight) {
167
+ // y a pas assez de place si il y a plus de place en haut on display en haut
168
+ if (triggerBottom < triggerTop) {
169
+ calc['top']();
170
+ return;
171
+ }
172
+ // ya plus de place ne bas du coup on display en bas et on contraint la hauteur du content
173
+ }
174
+
175
+ top = topCalc;
176
+ left = leftCalc;
177
+ },
178
+ top: () => {
179
+ // contraindre la hauteur maximum disponible pour afficher le dropdown
180
+ maxContentHeight = triggerTop - padding;
181
+
182
+ // recuperer le contenue du dropdown
183
+ const contentContent = getFirstChild(content);
184
+
185
+ // recuperer la taille du content
186
+ const contentWidth = contentContent.offsetWidth;
187
+ const contentHeight = contentContent.offsetHeight;
188
+
189
+ // return values
190
+ let topCalc = triggerTop - contentHeight - padding;
191
+ let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2; // centrer
192
+
193
+ // verifier si il y a assez de la place en haut
194
+ if (triggerTop < contentHeight) {
195
+ // si y a plus de place en bas que en haut on display en bas
196
+ if (triggerTop < triggerBottom) {
197
+ calc['bottom']();
198
+ return;
199
+ }
200
+
201
+ // on contraint la max height du dropdown
202
+ }
203
+
204
+ top = topCalc;
205
+ left = leftCalc;
206
+ },
207
+ left: () => {
208
+ // limiter la height par la height disponible en dessous du trigger
209
+ maxContentHeight = triggerBottom - padding;
210
+ maxContentWidth = triggerLeft - padding;
211
+
212
+ // recuperer le contenue du dropdown
213
+ const contentContent = getFirstChild(content);
214
+
215
+ // recuperer la taille du content
216
+ const contentWidth = contentContent.offsetWidth;
217
+ const contentHeight = contentContent.scrollHeight;
218
+
219
+ // return values
220
+ let topCalc = triggerTop - (contentHeight - triggerHeight) / 2; // centrer;
221
+ let leftCalc = triggerLeft - contentWidth - padding;
222
+
223
+ // verifier si il y a assez de place a gauche
224
+ if (triggerLeft < contentWidth + padding) {
225
+ // si y a plus de place a droite que gauche on display a droite
226
+ if (triggerLeft < triggerRight) {
227
+ calc['right']();
228
+ return;
229
+ }
230
+
231
+ // la width est contraint pour l'affichage
232
+ }
233
+
234
+ top = topCalc;
235
+ left = leftCalc;
236
+ },
237
+ right: () => {
238
+ // limiter la height par la height disponible en dessous du trigger
239
+ maxContentHeight = triggerBottom - padding;
240
+ maxContentWidth = triggerRight - padding;
241
+
242
+ // recuperer le contenue du dropdown
243
+ const contentContent = getFirstChild(content);
244
+
245
+ // recuperer la taille du content
246
+ const contentWidth = contentContent.offsetWidth;
247
+ const contentHeight = contentContent.scrollHeight;
248
+
249
+ // return values
250
+ let topCalc = triggerTop - (contentHeight - triggerHeight) / 2; // centrer;
251
+ let leftCalc = triggerLeft + triggerWidth + padding;
252
+
253
+ // verifier si il y a assez de place a droite
254
+ if (triggerRight < contentWidth + padding) {
255
+ // si y a pas assez de place a droite on verifie si y a plus de place a gauche on display a gauche
256
+ if (triggerRight < triggerLeft) {
257
+ calc['left']();
258
+ return;
259
+ }
260
+
261
+ // la width est contraint pour l'affichage
262
+ }
263
+
264
+ top = topCalc;
265
+ left = leftCalc;
118
266
  }
267
+ };
119
268
 
120
- return [topCalc, leftCalc];
121
- },
122
- top: () => {
123
- // recuperer la taille du content
124
- const contentWidth = content.offsetWidth;
125
- const contentHeight = content.offsetHeight;
126
- // recuperer la taille du trigger
127
- const triggerWidth = trigger.offsetWidth;
128
- const triggerHeight = trigger.offsetHeight;
129
- // recuperer la position du trigger par rapport a la fenetre
130
- const triggerRect = trigger.getBoundingClientRect();
131
- const triggerTop = triggerRect.top;
132
- const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
133
- const triggerLeft = triggerRect.left;
134
- const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
135
-
136
- // return values
137
- let topCalc = triggerTop - contentHeight - padding;
138
- let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2;
139
-
140
- // verifier si il y a assez de la place en haut
141
- if (triggerTop < contentHeight) {
142
- topCalc = padding;
143
- }
144
- // verifier si il y a assez de la place en bas
145
- if (triggerBottom + triggerHeight < contentHeight) {
146
- topCalc = padding;
147
- }
148
- // verifier si il y a assez de place a gauche
149
- if (triggerLeft < (contentWidth - triggerWidth) / 2) {
150
- leftCalc = padding;
151
- }
152
- // verifier si il y a assez de place a droite
153
- if (triggerRight < (contentWidth - triggerWidth) / 2) {
154
- leftCalc = window.innerWidth - contentWidth - padding;
269
+ const subCalc = {
270
+ bottom: () => {
271
+
272
+
273
+ // aligner le contenue au bas du trigger
274
+ top = triggerTop;
275
+ },
276
+ top: () => {
277
+ // recuperer le contenue du dropdown
278
+ const contentContent = getFirstChild(content);
279
+
280
+ // recuperer la taille du content
281
+ const contentWidth = contentContent.offsetWidth;
282
+ const contentHeight = contentContent.offsetHeight;
283
+
284
+ // aligner le contenue au bas du trigger
285
+ top = triggerTop - (contentHeight - triggerHeight);
286
+ },
287
+ left: () => {
288
+ // recuperer le contenue du dropdown
289
+ const contentContent = getFirstChild(content);
290
+
291
+ // recuperer la taille du content
292
+ const contentWidth = contentContent.offsetWidth;
293
+ const contentHeight = contentContent.offsetHeight;
294
+
295
+ // aligner le contenue a la droite du trigger
296
+ left = triggerLeft - (contentWidth - triggerWidth);
297
+ },
298
+ right: () => {
299
+ left = triggerLeft;
155
300
  }
301
+ };
156
302
 
157
- return [topCalc, leftCalc];
158
- },
159
- left: () => {
160
- // recuperer la taille du content
161
- const contentWidth = content.offsetWidth;
162
- const contentHeight = content.offsetHeight;
163
- // recuperer la taille du trigger
164
- const triggerWidth = trigger.offsetWidth;
165
- const triggerHeight = trigger.offsetHeight;
166
- // recuperer la position du trigger par rapport a la fenetre
167
- const triggerRect = trigger.getBoundingClientRect();
168
- const triggerTop = triggerRect.top;
169
- const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
170
- const triggerLeft = triggerRect.left;
171
- const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
172
-
173
- // return values
174
- let topCalc = triggerTop;
175
- let leftCalc = triggerLeft - contentWidth - padding;
176
-
177
- // verifier si il y a assez de la place en haut
178
- if (triggerTop < 0) {
179
- topCalc = padding;
180
- }
181
- // verifier si il y a assez de la place en bas
182
- if (triggerBottom < (contentHeight - triggerHeight)) {
183
- topCalc = window.innerHeight - contentHeight - padding;
184
- }
185
- // verifier si il y a assez de place a gauche
186
- if (triggerLeft < contentWidth + padding) {
187
- leftCalc = padding;
188
- }
303
+ const directionData = direction.split('-');
189
304
 
190
- return [topCalc, leftCalc];
191
- },
192
- right: () => {
193
- // recuperer la taille du content
194
- const contentWidth = content.offsetWidth;
195
- const contentHeight = content.offsetHeight;
196
- // recuperer la taille du trigger
197
- const triggerWidth = trigger.offsetWidth;
198
- const triggerHeight = trigger.offsetHeight;
199
- // recuperer la position du trigger par rapport a la fenetre
200
- const triggerRect = trigger.getBoundingClientRect();
201
- const triggerTop = triggerRect.top;
202
- const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
203
- const triggerLeft = triggerRect.left;
204
- const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
205
-
206
- // return values
207
- let topCalc = triggerTop;
208
- let leftCalc = triggerLeft + triggerWidth + padding;
209
-
210
- // verifier si il y a assez de la place en haut
211
- if (triggerTop < 0) {
212
- topCalc = padding;
213
- }
214
- // verifier si il y a assez de la place en bas
215
- if (triggerBottom < (contentHeight - triggerHeight)) {
216
- topCalc = window.innerHeight - contentHeight - padding;
217
- }
218
- // verifier si il y a assez de place a droite
219
- if (triggerRight < contentWidth + padding) {
220
- leftCalc = window.innerWidth - contentWidth - padding - triggerWidth;
221
- }
305
+ const axe = directionData[0];
306
+ const subDirection = directionData[1];
222
307
 
223
- return [topCalc, leftCalc];
224
- }
225
- };
308
+ calc[axe]();
309
+
310
+ if (subDirection) {
311
+ subCalc[subDirection]()
312
+ }
313
+ }
226
314
 
227
315
  // Bloquer le scroll
228
316
  function disableScroll() {
@@ -237,13 +325,14 @@ import { onDestroy, onMount } from 'svelte';
237
325
  }
238
326
  function updatePos(e) {
239
327
  // recalculer la position
240
- if (!display) {
241
- return
242
- }
243
- [top, left] = calc[direction]();
328
+ if (!display) {
329
+ return;
330
+ }
331
+ calculate();
244
332
  }
245
333
 
246
334
  function enableExitEvent() {
335
+
247
336
  document.addEventListener('click', checkClick);
248
337
  }
249
338
  function disableExitEvent() {
@@ -252,17 +341,64 @@ import { onDestroy, onMount } from 'svelte';
252
341
 
253
342
  function checkClick(event) {
254
343
 
255
- if (event.target.closest('.parent-popover-hamzus') && event.target.closest('.parent-popover-hamzus') === originalParent) {
256
- return
257
- }
258
- if (event.target.closest('.content-popover-hamzus')) {
344
+ // si avoidClosing est true on skip
345
+ if (avoidClosing) {
259
346
  return
260
347
  }
348
+
349
+ // si il click sur le trigger alors on skip
350
+ if (
351
+ event.target.closest('.parent-popover-hamzus') &&
352
+ event.target.closest('.parent-popover-hamzus') === originalParent
353
+ ) {
354
+ const triggerContent = getFirstChild(event.target.closest('.parent-popover-hamzus'));
355
+
356
+ // si le curseur a cliquer dans le triggerContent on skip
357
+ // si le curseur a cliquer dans le triggerContent on skip
358
+ if (triggerContent && triggerContent.contains(event.target)) {
359
+ return; // on skip
360
+ }
361
+ }
362
+
363
+ // si il clique sur un contenue on skip
364
+
365
+ if (event.target.closest('.content-popover-hamzus')) {
261
366
 
262
- handleDisplay();
367
+ return;
368
+ }
369
+
370
+ handleDisplay(null, true);
371
+ }
372
+
373
+ function getFirstChild(node) {
374
+ if (!node) return null;
375
+
376
+ for (const child of node.children) {
377
+ const display = getComputedStyle(child).display;
378
+
379
+ if (display !== 'contents') {
380
+ return child; // trouvé !
381
+ } else {
382
+ // le child est "contents", on cherche dans ses enfants
383
+ const realChild = getFirstChild(child);
384
+ if (realChild) return realChild;
385
+ }
386
+ }
387
+
388
+ return null; // aucun enfant réel trouvé
263
389
  }
264
390
 
265
391
  onMount(() => {
392
+ // recuperer le contenue du trigger
393
+ const triggerContent = getFirstChild(trigger);
394
+ // recuperer la position du trigger par rapport a la fenetre
395
+ const triggerRect = triggerContent.getBoundingClientRect();
396
+
397
+ // recuperer la taille du trigger
398
+ triggerWidth = triggerContent.offsetWidth;
399
+ triggerHeight = triggerContent.offsetHeight;
400
+
401
+
266
402
  return () => {
267
403
  document.removeEventListener('userScroll', updatePos);
268
404
  window.removeEventListener('scroll', updatePos);
@@ -271,32 +407,44 @@ import { onDestroy, onMount } from 'svelte';
271
407
  });
272
408
  </script>
273
409
 
274
- <dropdown bind:this={originalParent} style="{triggerFullWidth ? "width:100%;" : ""} {style}" class="parent-popover-hamzus">
275
- <div bind:this={trigger} class="trigger" style="{triggerFullWidth ? "width:100%;" : ""}" on:click={handleDisplay}>
410
+ <dropdown
411
+ bind:this={originalParent}
412
+ style="{triggerFullWidth ? 'width:100%;' : ''} {style}"
413
+ class="parent-popover-hamzus"
414
+ >
415
+ <div bind:this={trigger} class="trigger" on:click={handleDisplay}>
276
416
  <slot name="trigger" />
277
417
  </div>
278
418
  <Portal disabled={!display} target="body">
279
- <content-container bind:this={contentContainer} class="content-container {!display ? "hidden" : ""}">
280
- <content
281
- bind:this={content}
282
- class="content content-popover-hamzus"
283
- class:display
284
- class:exit
285
- style="--left:{left}px;--top:{top}px;--transform-x:{entryPosition[
286
- direction
287
- ][1]};--transform-y:{entryPosition[direction][0]};"
288
- >
289
- <slot name="content" />
290
- </content>
291
- </content-container>
292
- </Portal>
419
+ <content-container
420
+ bind:this={contentContainer}
421
+ class="content-container {!display ? 'hidden' : ''}"
422
+ style="
423
+ --hamzus-tigger-width:{triggerWidth}px;
424
+ {maxContentHeight ? `--hamzus-max-content-height:${maxContentHeight}px;` : ''}
425
+ {maxContentWidth ? `--hamzus-max-content-width:${maxContentWidth}px;` : ''}
426
+
427
+
428
+ "
429
+ >
430
+ <content
431
+ bind:this={content}
432
+ class="content content-popover-hamzus {parentTag}"
433
+ class:display
434
+ class:exit
435
+ style="--left:{left}px;--top:{top}px;--transform-x:{entryPosition[
436
+ direction
437
+ ][1]};--transform-y:{entryPosition[direction][0]};"
438
+ >
439
+ <slot name="content" />
440
+ </content>
441
+ </content-container>
442
+ </Portal>
293
443
  </dropdown>
294
444
 
295
445
  <style>
296
446
  .trigger {
297
- all: unset;
298
- width: max-content;
299
- display: inline-block;
447
+ display: contents;
300
448
  }
301
449
 
302
450
  .content {
@@ -1,12 +1,21 @@
1
1
 
2
- <span class="separator"></span>
2
+ <div class="separator-container">
3
+ <span class="separator"></span>
4
+ </div>
3
5
 
4
6
  <style>
5
- .separator{
7
+ .separator-container {
6
8
  width: 100%;
7
9
  height: 1px;
10
+ position: relative;
11
+ }
12
+ .separator{
13
+ width: calc(100% + 2 * var(--pad-m));
14
+ height: 1px;
15
+ top: 0;
16
+ left: calc(0 - var(--pad-m));
8
17
  background-color: var(--stroke);
9
- width: calc(100% + var(--pad-m) * 2);
10
18
  transform: translateX(calc(-1 * var(--pad-m))) ;
19
+ position: absolute;
11
20
  }
12
21
  </style>
@@ -0,0 +1,46 @@
1
+ <script>
2
+ export let onClick = undefined
3
+ export let label = ""
4
+ function handleClick() {
5
+ if (onClick && typeof onClick === 'function') {
6
+ onClick()
7
+ }
8
+ }
9
+ </script>
10
+
11
+ <button class="button" on:click={handleClick} {...$$restProps}>
12
+ {#if label}
13
+ <h4>{label}</h4>
14
+ {:else}
15
+ <slot/>
16
+ {/if}
17
+ </button>
18
+
19
+ <style>
20
+ .button{
21
+ width: 100%;
22
+ display: flex;
23
+ align-items: center;
24
+ column-gap: var(--pad-m);
25
+ padding: var(--pad-s) var(--pad-m);
26
+ border-radius: var(--radius-m);
27
+ color: var(--font-2);
28
+ cursor: pointer;
29
+ transition: transform .2s ease-out;
30
+ }
31
+ .button:active {
32
+ transform: scale(.98);
33
+ }
34
+ .button :global(> *) {
35
+ color: var(--font-2);
36
+ fill: var(--font-2);
37
+ }
38
+ .button:hover{
39
+ background-color: var(--bg-3);
40
+ color: var(--font-1);
41
+ }
42
+ .button:hover :global(> *) {
43
+ color: var(--font-1);
44
+ fill: var(--font-2);
45
+ }
46
+ </style>
@@ -0,0 +1,23 @@
1
+ <script>
2
+
3
+ export let width = "max-content"
4
+ export let style;
5
+ </script>
6
+
7
+ <div class="content" style="--width:{width};{style}" {...$$restProps}>
8
+ <slot/>
9
+ </div>
10
+
11
+ <style>
12
+ .content{
13
+ display: flex;
14
+ flex-direction: column;
15
+ row-gap: var(--pad-m);
16
+ padding: var(--pad-m) var(--pad-l);
17
+ background-color: var(--bg-1);
18
+ border-radius: var(--radius-l);
19
+ border: 1px solid var(--bg-3);
20
+ width: min(100vw, var(--width));
21
+ max-height: 100vh;
22
+ }
23
+ </style>
@@ -0,0 +1 @@
1
+ <h5><slot/></h5>
@@ -0,0 +1,361 @@
1
+ <script>
2
+ import Portal from '../Portal/Portal.svelte';
3
+ import { onDestroy, onMount } from 'svelte';
4
+
5
+ // import
6
+
7
+ // props
8
+ export let triggerFullWidth = false;
9
+ export let direction = 'bottom';
10
+ export let onOpen = undefined;
11
+ export let avoidOpening = false
12
+ export let style = ""
13
+ // locale var
14
+ let display = false;
15
+ let exit = false;
16
+
17
+ let originalParent;
18
+ let trigger;
19
+ let content;
20
+ let contentContainer;
21
+
22
+ let top = 0;
23
+ let left = 0;
24
+
25
+ const padding = 7;
26
+
27
+ const entryPosition = {
28
+ bottom: ['-12px', '0px'],
29
+ top: ['12px', '0px'],
30
+ left: ['0px', '12px'],
31
+ right: ['0px', '-12px']
32
+ };
33
+ // function
34
+ function handleDisplay(e) {
35
+ if (avoidOpening) {
36
+ return
37
+ }
38
+ if (!calc[direction]) {
39
+ console.error('Error : direction props not found !');
40
+ return
41
+ }
42
+
43
+ if (!display) {
44
+ [top, left] = calc[direction]();
45
+ }
46
+
47
+ toggleDisplay();
48
+
49
+ if (onOpen !== undefined && typeof onOpen === 'function') {
50
+ onOpen(e)
51
+ }
52
+ }
53
+
54
+ export let toggleDisplay = () => {
55
+ if (display) {
56
+ // appliquer une animation
57
+ exit = true;
58
+ setTimeout(() => {
59
+ exit = false;
60
+ }, 200);
61
+
62
+ disableExitEvent();
63
+ enableScroll();
64
+ } else {
65
+ enableExitEvent();
66
+ disableScroll();
67
+ }
68
+
69
+ display = !display;
70
+ }
71
+
72
+ export let open = ()=>{
73
+ if (display) {
74
+ return
75
+ }
76
+
77
+ toggleDisplay()
78
+ }
79
+ export let close = ()=>{
80
+ if (!display) {
81
+ return
82
+ }
83
+
84
+ toggleDisplay()
85
+ }
86
+
87
+ const calc = {
88
+ bottom: () => {
89
+ // recuperer la taille du content
90
+ const contentWidth = content.offsetWidth;
91
+ const contentHeight = content.offsetHeight;
92
+ // recuperer la taille du trigger
93
+ const triggerWidth = trigger.offsetWidth;
94
+ const triggerHeight = trigger.offsetHeight;
95
+ // recuperer la position du trigger par rapport a la fenetre
96
+ const triggerRect = trigger.getBoundingClientRect();
97
+ const triggerTop = triggerRect.top;
98
+ const triggerLeft = triggerRect.left;
99
+ const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
100
+ const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
101
+
102
+ // return values
103
+ let topCalc = triggerTop + triggerHeight + padding;
104
+ let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2;
105
+
106
+ // verifier si il y a assez de la place en bas
107
+ if (triggerBottom < contentHeight) {
108
+ topCalc = window.innerHeight - contentHeight - padding;
109
+ }
110
+ // verifier si il y a assez de place a droite
111
+ if (triggerRight < (contentWidth - triggerWidth) / 2) {
112
+ leftCalc = window.innerWidth - contentWidth - padding;
113
+ }
114
+ // verifier si il y a assez de place a gauche
115
+
116
+ if (triggerLeft < (contentWidth - triggerWidth) / 2) {
117
+ leftCalc = padding;
118
+ }
119
+
120
+ return [topCalc, leftCalc];
121
+ },
122
+ top: () => {
123
+ // recuperer la taille du content
124
+ const contentWidth = content.offsetWidth;
125
+ const contentHeight = content.offsetHeight;
126
+ // recuperer la taille du trigger
127
+ const triggerWidth = trigger.offsetWidth;
128
+ const triggerHeight = trigger.offsetHeight;
129
+ // recuperer la position du trigger par rapport a la fenetre
130
+ const triggerRect = trigger.getBoundingClientRect();
131
+ const triggerTop = triggerRect.top;
132
+ const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
133
+ const triggerLeft = triggerRect.left;
134
+ const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
135
+
136
+ // return values
137
+ let topCalc = triggerTop - contentHeight - padding;
138
+ let leftCalc = triggerLeft - (contentWidth - triggerWidth) / 2;
139
+
140
+ // verifier si il y a assez de la place en haut
141
+ if (triggerTop < contentHeight) {
142
+ topCalc = padding;
143
+ }
144
+ // verifier si il y a assez de la place en bas
145
+ if (triggerBottom + triggerHeight < contentHeight) {
146
+ topCalc = padding;
147
+ }
148
+ // verifier si il y a assez de place a gauche
149
+ if (triggerLeft < (contentWidth - triggerWidth) / 2) {
150
+ leftCalc = padding;
151
+ }
152
+ // verifier si il y a assez de place a droite
153
+ if (triggerRight < (contentWidth - triggerWidth) / 2) {
154
+ leftCalc = window.innerWidth - contentWidth - padding;
155
+ }
156
+
157
+ return [topCalc, leftCalc];
158
+ },
159
+ left: () => {
160
+ // recuperer la taille du content
161
+ const contentWidth = content.offsetWidth;
162
+ const contentHeight = content.offsetHeight;
163
+ // recuperer la taille du trigger
164
+ const triggerWidth = trigger.offsetWidth;
165
+ const triggerHeight = trigger.offsetHeight;
166
+ // recuperer la position du trigger par rapport a la fenetre
167
+ const triggerRect = trigger.getBoundingClientRect();
168
+ const triggerTop = triggerRect.top;
169
+ const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
170
+ const triggerLeft = triggerRect.left;
171
+ const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
172
+
173
+ // return values
174
+ let topCalc = triggerTop;
175
+ let leftCalc = triggerLeft - contentWidth - padding;
176
+
177
+ // verifier si il y a assez de la place en haut
178
+ if (triggerTop < 0) {
179
+ topCalc = padding;
180
+ }
181
+ // verifier si il y a assez de la place en bas
182
+ if (triggerBottom < (contentHeight - triggerHeight)) {
183
+ topCalc = window.innerHeight - contentHeight - padding;
184
+ }
185
+ // verifier si il y a assez de place a gauche
186
+ if (triggerLeft < contentWidth + padding) {
187
+ leftCalc = padding;
188
+ }
189
+
190
+ return [topCalc, leftCalc];
191
+ },
192
+ right: () => {
193
+ // recuperer la taille du content
194
+ const contentWidth = content.offsetWidth;
195
+ const contentHeight = content.offsetHeight;
196
+ // recuperer la taille du trigger
197
+ const triggerWidth = trigger.offsetWidth;
198
+ const triggerHeight = trigger.offsetHeight;
199
+ // recuperer la position du trigger par rapport a la fenetre
200
+ const triggerRect = trigger.getBoundingClientRect();
201
+ const triggerTop = triggerRect.top;
202
+ const triggerBottom = window.innerHeight - triggerTop - triggerHeight;
203
+ const triggerLeft = triggerRect.left;
204
+ const triggerRight = window.innerWidth - triggerLeft - triggerWidth;
205
+
206
+ // return values
207
+ let topCalc = triggerTop;
208
+ let leftCalc = triggerLeft + triggerWidth + padding;
209
+
210
+ // verifier si il y a assez de la place en haut
211
+ if (triggerTop < 0) {
212
+ topCalc = padding;
213
+ }
214
+ // verifier si il y a assez de la place en bas
215
+ if (triggerBottom < (contentHeight - triggerHeight)) {
216
+ topCalc = window.innerHeight - contentHeight - padding;
217
+ }
218
+ // verifier si il y a assez de place a droite
219
+ if (triggerRight < contentWidth + padding) {
220
+ leftCalc = window.innerWidth - contentWidth - padding - triggerWidth;
221
+ }
222
+
223
+ return [topCalc, leftCalc];
224
+ }
225
+ };
226
+
227
+ // Bloquer le scroll
228
+ function disableScroll() {
229
+ document.addEventListener('userScroll', updatePos);
230
+ window.addEventListener('scroll', updatePos);
231
+ }
232
+
233
+ // Réactiver le scroll
234
+ function enableScroll() {
235
+ document.removeEventListener('userScroll', updatePos);
236
+ window.removeEventListener('scroll', updatePos);
237
+ }
238
+ function updatePos(e) {
239
+ // recalculer la position
240
+ if (!display) {
241
+ return
242
+ }
243
+ [top, left] = calc[direction]();
244
+ }
245
+
246
+ function enableExitEvent() {
247
+ document.addEventListener('click', checkClick);
248
+ }
249
+ function disableExitEvent() {
250
+ document.removeEventListener('click', checkClick);
251
+ }
252
+
253
+ function checkClick(event) {
254
+
255
+ if (event.target.closest('.parent-popover-hamzus') && event.target.closest('.parent-popover-hamzus') === originalParent) {
256
+ return
257
+ }
258
+ if (event.target.closest('.content-popover-hamzus')) {
259
+ return
260
+ }
261
+
262
+ handleDisplay();
263
+ }
264
+
265
+ onMount(() => {
266
+ return () => {
267
+ document.removeEventListener('userScroll', updatePos);
268
+ window.removeEventListener('scroll', updatePos);
269
+ document.removeEventListener('click', checkClick);
270
+ };
271
+ });
272
+ </script>
273
+
274
+ <dropdown bind:this={originalParent} style="{triggerFullWidth ? "width:100%;" : ""} {style}" class="parent-popover-hamzus">
275
+ <div bind:this={trigger} class="trigger" style="{triggerFullWidth ? "width:100%;" : ""}" okn:click={handleDisplay}>
276
+ <slot name="trigger" />
277
+ </div>
278
+ <Portal disabled={!display} target="body">
279
+ <content-container bind:this={contentContainer} class="content-container {!display ? "hidden" : ""}">
280
+ <content
281
+ bind:this={content}
282
+ class="content content-popover-hamzus"
283
+ class:display
284
+ class:exit
285
+ style="--left:{left}px;--top:{top}px;--transform-x:{entryPosition[
286
+ direction
287
+ ][1]};--transform-y:{entryPosition[direction][0]};"
288
+ >
289
+ <slot name="content" />
290
+ </content>
291
+ </content-container>
292
+ </Portal>
293
+ </dropdown>
294
+
295
+ <style>
296
+ .trigger {
297
+ all: unset;
298
+ width: max-content;
299
+ display: inline-block;
300
+ }
301
+
302
+ .content {
303
+ position: fixed;
304
+ top: var(--top);
305
+ left: var(--left);
306
+ display: block;
307
+ user-select: none;
308
+ pointer-events: none;
309
+ opacity: 0;
310
+ z-index: 20;
311
+ }
312
+
313
+ .content.exit {
314
+ display: block;
315
+ animation-name: exit;
316
+ animation-duration: 0.2s;
317
+ animation-timing-function: ease-out;
318
+ }
319
+ .content.display {
320
+ display: block;
321
+ animation-name: entry;
322
+ animation-duration: 0.2s;
323
+ animation-timing-function: ease-out;
324
+ user-select: initial;
325
+ pointer-events: initial;
326
+ opacity: 1;
327
+ }
328
+
329
+ @keyframes entry {
330
+ from {
331
+ display: block;
332
+ opacity: 0;
333
+ user-select: none;
334
+ pointer-events: none;
335
+ transform: translate(var(--transform-x), var(--transform-y)) scale(0.86);
336
+ }
337
+ to {
338
+ display: block;
339
+ opacity: 1;
340
+ user-select: initial;
341
+ pointer-events: initial;
342
+ transform: translate(0px, 0px) scale(1);
343
+ }
344
+ }
345
+ @keyframes exit {
346
+ from {
347
+ display: block;
348
+ opacity: 1;
349
+ user-select: initial;
350
+ pointer-events: initial;
351
+ transform: translate(0px, 0px) scale(1);
352
+ }
353
+ to {
354
+ display: block;
355
+ opacity: 0;
356
+ user-select: none;
357
+ pointer-events: none;
358
+ transform: translate(var(--transform-x), var(--transform-y)) scale(0.86);
359
+ }
360
+ }
361
+ </style>
@@ -0,0 +1,12 @@
1
+
2
+ <span class="separator"></span>
3
+
4
+ <style>
5
+ .separator{
6
+ width: 100%;
7
+ height: 1px;
8
+ background-color: var(--stroke);
9
+ width: calc(100% + var(--pad-m) * 2);
10
+ transform: translateX(calc(-1 * var(--pad-m))) ;
11
+ }
12
+ </style>
@@ -0,0 +1,6 @@
1
+ export { default as Root } from './Root.svelte';
2
+ export { default as Trigger } from './Trigger.svelte';
3
+ export { default as Content } from './Content.svelte';
4
+ export { default as Label } from './Label.svelte';
5
+ export { default as Separator } from './Separator.svelte';
6
+ export { default as Button } from './Button.svelte';
@@ -60,6 +60,7 @@
60
60
  </script>
61
61
 
62
62
  <div
63
+ class="parent-button-hamzus"
63
64
  style="
64
65
  --button-default-bg:var({colorConfig[variant].defaultBg});
65
66
  --button-default-border:var({colorConfig[variant].defaultBorder});
@@ -6,11 +6,12 @@
6
6
 
7
7
  <style>
8
8
  .skeleton {
9
+ display: flex;
9
10
  background: linear-gradient(90deg, var(--bg-2) 25%, var(--bg-3) 50%, var(--bg-2) 75%);
10
11
  background-size: 200% 100%;
11
12
  animation: skeleton-loading 1.5s infinite;
12
13
  border-radius: 4px; /* Pour arrondir les coins */
13
- flex-shrink: 0;
14
+ /* flex-shrink: 0; */
14
15
  }
15
16
 
16
17
  /* Animation */