@tekkare/romulus 0.1.158 → 0.1.160
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/dist/module.json
CHANGED
|
@@ -43,6 +43,13 @@ export interface RmComplexSelectPreset {
|
|
|
43
43
|
export interface RmComplexSelectOption {
|
|
44
44
|
label: string
|
|
45
45
|
value: string
|
|
46
|
+
/**
|
|
47
|
+
* Mention posee a cote du libelle dans la colonne « ajouter ». Sert a dire
|
|
48
|
+
* d'ou sort une option que la liste ne portait pas : une valeur trouvee
|
|
49
|
+
* au-dela du perimetre courant se retient comme les autres, mais ne se lit
|
|
50
|
+
* pas comme les autres.
|
|
51
|
+
*/
|
|
52
|
+
hint?: string
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
const props = withDefaults(defineProps<{
|
|
@@ -155,22 +162,52 @@ const t = computed(() => WORDS[props.lang])
|
|
|
155
162
|
const isOpen = ref(false)
|
|
156
163
|
const removeSearch = ref('')
|
|
157
164
|
const activePreset = ref<string>()
|
|
158
|
-
const alignRight = ref(false)
|
|
159
165
|
const rootRef = ref<HTMLElement>()
|
|
166
|
+
const panelRef = ref<HTMLElement>()
|
|
160
167
|
const addRef = ref<HTMLInputElement>()
|
|
161
168
|
|
|
162
169
|
/** Largeur du panneau, tenue en phase avec la regle `.rm-csel__panel`. */
|
|
163
170
|
const PANEL_WIDTH = 820
|
|
164
171
|
|
|
172
|
+
/** Marge gardee contre les bords de la fenetre. */
|
|
173
|
+
const PANEL_GAP = 8
|
|
174
|
+
|
|
165
175
|
/**
|
|
166
|
-
* Le panneau
|
|
167
|
-
*
|
|
168
|
-
*
|
|
176
|
+
* Le panneau est pose sur la fenetre, pas dans le champ : depose dans le flux,
|
|
177
|
+
* il etait coupe des que le filtre vivait dans un conteneur qui defile (un
|
|
178
|
+
* tiroir, une carte a debordement cache), et aucun reglage de `overflow` chez
|
|
179
|
+
* l'appelant ne le rattrapait.
|
|
180
|
+
*
|
|
181
|
+
* Il sort donc par un `Teleport` et se positionne a la main, sous le champ,
|
|
182
|
+
* cale a gauche par defaut et sur le bord droit du champ quand il depasserait
|
|
183
|
+
* de l'ecran.
|
|
169
184
|
*/
|
|
185
|
+
const panelStyle = ref<Record<string, string>>({})
|
|
186
|
+
|
|
170
187
|
function placePanel() {
|
|
171
188
|
const rect = rootRef.value?.getBoundingClientRect()
|
|
172
189
|
if (!rect) return
|
|
173
|
-
|
|
190
|
+
|
|
191
|
+
const width = Math.min(PANEL_WIDTH, window.innerWidth - PANEL_GAP * 2)
|
|
192
|
+
const left = rect.left + width > window.innerWidth - PANEL_GAP
|
|
193
|
+
? Math.max(PANEL_GAP, rect.right - width)
|
|
194
|
+
: rect.left
|
|
195
|
+
|
|
196
|
+
// Sous le champ, sauf quand il ne reste rien dessous : le panneau se pose
|
|
197
|
+
// alors au-dessus, et sa hauteur se borne a la place reellement libre.
|
|
198
|
+
const below = window.innerHeight - rect.bottom - PANEL_GAP * 2
|
|
199
|
+
const above = rect.top - PANEL_GAP * 2
|
|
200
|
+
const flip = below < 320 && above > below
|
|
201
|
+
|
|
202
|
+
panelStyle.value = {
|
|
203
|
+
position: 'fixed',
|
|
204
|
+
left: `${left}px`,
|
|
205
|
+
width: `${width}px`,
|
|
206
|
+
maxHeight: `${Math.max(240, flip ? above : below)}px`,
|
|
207
|
+
...(flip
|
|
208
|
+
? { bottom: `${window.innerHeight - rect.top + PANEL_GAP}px` }
|
|
209
|
+
: { top: `${rect.bottom + PANEL_GAP}px` }),
|
|
210
|
+
}
|
|
174
211
|
}
|
|
175
212
|
|
|
176
213
|
/** Les chaines nues valent libelle et valeur a la fois. */
|
|
@@ -220,13 +257,31 @@ watch(addInput, (value) => {
|
|
|
220
257
|
}, 500)
|
|
221
258
|
})
|
|
222
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Le panneau suit le champ tant qu'il est ouvert : pose sur la fenetre, il
|
|
262
|
+
* resterait sinon la ou le champ etait avant que la page (ou le tiroir) ne
|
|
263
|
+
* defile.
|
|
264
|
+
*/
|
|
265
|
+
function trackPanel() {
|
|
266
|
+
window.addEventListener('scroll', placePanel, true)
|
|
267
|
+
window.addEventListener('resize', placePanel)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function untrackPanel() {
|
|
271
|
+
window.removeEventListener('scroll', placePanel, true)
|
|
272
|
+
window.removeEventListener('resize', placePanel)
|
|
273
|
+
}
|
|
274
|
+
|
|
223
275
|
function close() {
|
|
224
276
|
isOpen.value = false
|
|
225
277
|
document.removeEventListener('click', onDocumentClick)
|
|
278
|
+
untrackPanel()
|
|
226
279
|
}
|
|
227
280
|
|
|
228
281
|
function onDocumentClick(event: MouseEvent) {
|
|
229
|
-
|
|
282
|
+
const target = event.target as Node
|
|
283
|
+
if (rootRef.value?.contains(target) || panelRef.value?.contains(target)) return
|
|
284
|
+
close()
|
|
230
285
|
}
|
|
231
286
|
|
|
232
287
|
async function toggle() {
|
|
@@ -235,6 +290,7 @@ async function toggle() {
|
|
|
235
290
|
|
|
236
291
|
isOpen.value = true
|
|
237
292
|
placePanel()
|
|
293
|
+
trackPanel()
|
|
238
294
|
rmPanelOpened(close)
|
|
239
295
|
document.addEventListener('click', onDocumentClick)
|
|
240
296
|
await nextTick()
|
|
@@ -285,6 +341,7 @@ onUnmounted(() => {
|
|
|
285
341
|
unregister?.()
|
|
286
342
|
clearTimeout(debounceId)
|
|
287
343
|
document.removeEventListener('click', onDocumentClick)
|
|
344
|
+
untrackPanel()
|
|
288
345
|
})
|
|
289
346
|
</script>
|
|
290
347
|
|
|
@@ -317,11 +374,14 @@ onUnmounted(() => {
|
|
|
317
374
|
<PhCaretDown :size="16" />
|
|
318
375
|
</button>
|
|
319
376
|
|
|
377
|
+
<Teleport to="body">
|
|
320
378
|
<div
|
|
321
379
|
v-show="isOpen"
|
|
380
|
+
ref="panelRef"
|
|
322
381
|
class="rm-csel__panel"
|
|
323
|
-
:
|
|
382
|
+
:style="panelStyle"
|
|
324
383
|
@click.stop
|
|
384
|
+
@keydown.escape="close"
|
|
325
385
|
>
|
|
326
386
|
<div class="rm-csel__column">
|
|
327
387
|
<div v-if="presets && presets.length > 0" class="rm-csel__presets">
|
|
@@ -383,6 +443,7 @@ onUnmounted(() => {
|
|
|
383
443
|
>
|
|
384
444
|
<PhPlusCircle :size="16" weight="fill" />
|
|
385
445
|
<span>{{ option.label }}</span>
|
|
446
|
+
<span v-if="option.hint" class="rm-csel__hint">{{ option.hint }}</span>
|
|
386
447
|
</button>
|
|
387
448
|
</div>
|
|
388
449
|
</div>
|
|
@@ -429,9 +490,10 @@ onUnmounted(() => {
|
|
|
429
490
|
</div>
|
|
430
491
|
</div>
|
|
431
492
|
</div>
|
|
493
|
+
</Teleport>
|
|
432
494
|
</div>
|
|
433
495
|
</template>
|
|
434
496
|
|
|
435
497
|
<style scoped>
|
|
436
|
-
.rm-csel{align-items:stretch;flex-direction:column;position:relative;width:196px}.rm-csel,.rm-csel__label{display:flex;gap:var(--space-4)}.rm-csel__label{align-items:center;color:var(--text-secondary);font-size:var(--font-12,12px);line-height:14px}.rm-csel__info{background:none;border:none;color:var(--text-muted);cursor:pointer;display:flex;padding:0}.rm-csel__field{align-items:center;background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);font-weight:700;gap:var(--space-4);line-height:16px;padding:var(--space-12);text-align:left;width:100%}.rm-csel__field:hover:not(.is-disabled){border-color:rgba(var(--brand-rgb),.3)}.rm-csel__field.is-open{border-color:var(--color-primary)}.rm-csel__field.is-disabled{background:var(--bg-surface-2);color:var(--text-muted);cursor:not-allowed}.rm-csel__field:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.rm-csel__value-slot{display:block;flex:1;min-width:0}.rm-csel__value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-csel__value.is-empty{color:var(--text-muted);font-style:italic;font-weight:400}.rm-csel__field :deep(svg){color:var(--text-secondary);flex-shrink:0}.rm-csel__count{align-items:center;background:rgba(var(--brand-rgb),.1);border-radius:50%;color:var(--color-primary);display:flex;flex-shrink:0;font-size:var(--font-12,12px);font-weight:600;height:20px;justify-content:center;width:20px}.rm-csel__panel{background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-lg,12px);box-shadow:var(--r-shadow-lg,0 8px 24px rgba(0,0,0,.12));box-sizing:border-box;display:flex;
|
|
498
|
+
.rm-csel{align-items:stretch;flex-direction:column;position:relative;width:196px}.rm-csel,.rm-csel__label{display:flex;gap:var(--space-4)}.rm-csel__label{align-items:center;color:var(--text-secondary);font-size:var(--font-12,12px);line-height:14px}.rm-csel__info{background:none;border:none;color:var(--text-muted);cursor:pointer;display:flex;padding:0}.rm-csel__field{align-items:center;background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-14,14px);font-weight:700;gap:var(--space-4);line-height:16px;padding:var(--space-12);text-align:left;width:100%}.rm-csel__field:hover:not(.is-disabled){border-color:rgba(var(--brand-rgb),.3)}.rm-csel__field.is-open{border-color:var(--color-primary)}.rm-csel__field.is-disabled{background:var(--bg-surface-2);color:var(--text-muted);cursor:not-allowed}.rm-csel__field:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.rm-csel__value-slot{display:block;flex:1;min-width:0}.rm-csel__value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-csel__value.is-empty{color:var(--text-muted);font-style:italic;font-weight:400}.rm-csel__field :deep(svg){color:var(--text-secondary);flex-shrink:0}.rm-csel__count{align-items:center;background:rgba(var(--brand-rgb),.1);border-radius:50%;color:var(--color-primary);display:flex;flex-shrink:0;font-size:var(--font-12,12px);font-weight:600;height:20px;justify-content:center;width:20px}.rm-csel__panel{background:var(--bg-surface);border:1.5px solid var(--border-default);border-radius:var(--radius-lg,12px);box-shadow:var(--r-shadow-lg,0 8px 24px rgba(0,0,0,.12));box-sizing:border-box;display:flex;max-height:calc(100vh - 32px);max-width:calc(100vw - 16px);overflow:hidden;position:fixed;z-index:var(--z-popover,1000)}.rm-csel__column{display:flex;flex:1;flex-direction:column;gap:var(--space-8);min-width:0;padding:var(--space-16)}.rm-csel__column--right{border-left:1px solid var(--border-soft);flex:0 0 300px}.rm-csel__presets{border-bottom:1px solid var(--border-soft);display:flex;flex-direction:column;gap:var(--space-8);padding-bottom:var(--space-8)}.rm-csel__pills{display:flex;flex-wrap:wrap;gap:var(--space-4)}.rm-csel__pill{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:9999px;color:var(--text-secondary);cursor:pointer;font-family:inherit;font-size:var(--font-12,12px);padding:var(--space-4) var(--space-10)}.rm-csel__pill.is-active,.rm-csel__pill:hover{border-color:var(--color-primary);color:var(--color-primary)}.rm-csel__pill.is-active{background:rgba(var(--brand-rgb),.1);font-weight:700}.rm-csel__head{align-items:center;display:flex;gap:var(--space-8);justify-content:space-between}.rm-csel__section{color:var(--text-secondary);font-size:var(--font-12,12px);font-weight:700;margin:0}.rm-csel__action{background:none;border:none;color:var(--color-primary);cursor:pointer;font-family:inherit;font-size:var(--font-12,12px);font-weight:600;padding:0}.rm-csel__action:disabled{color:var(--text-muted);cursor:not-allowed}.rm-csel__action:hover:not(:disabled){text-decoration:underline}.rm-csel__action--clear:not(:disabled){color:var(--color-danger)}.rm-csel__search{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-md,8px);display:flex;gap:var(--space-8);padding:var(--space-6) var(--space-10)}.rm-csel__search :deep(svg){color:var(--text-muted);flex-shrink:0}.rm-csel__search-input{background:none;border:none;color:var(--text-primary);font-family:inherit;font-size:var(--font-13,13px);width:100%}.rm-csel__search-input::-moz-placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-csel__search-input::placeholder{color:var(--text-muted);font-size:var(--font-12,12px)}.rm-csel__search-input:focus-visible{outline:none}.rm-csel__state{color:var(--text-secondary);font-size:var(--font-13,13px);font-style:italic;padding-top:var(--space-8)}.rm-csel__loading{display:flex;flex-direction:column;gap:var(--space-10);padding-top:var(--space-8)}.rm-csel__sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}.rm-csel__list{display:flex;flex-direction:column;gap:var(--space-4);height:260px;overflow-x:hidden;overflow-y:auto;scrollbar-width:thin}.rm-csel__option{align-items:flex-start;background:none;border:none;border-radius:var(--radius-sm,4px);color:var(--text-primary);cursor:pointer;display:flex;font-family:inherit;font-size:var(--font-13,13px);gap:var(--space-8);line-height:150%;min-width:0;padding:var(--space-2) var(--space-4);text-align:left}.rm-csel__option span{min-width:0;overflow-wrap:anywhere}.rm-csel__option :deep(svg){background:var(--bg-surface);border-radius:50%;flex-shrink:0;margin-top:3px}.rm-csel__hint{color:var(--text-muted);flex-shrink:0;font-size:var(--font-11,11px);white-space:nowrap}.rm-csel__option:hover{background:rgba(var(--brand-rgb),.05)}.rm-csel__option:focus-visible{outline:2px solid var(--color-primary);outline-offset:-2px}.rm-csel__option--add :deep(svg){color:var(--color-primary)}.rm-csel__option--remove :deep(svg){color:var(--color-danger)}@media (max-width:767px){.rm-csel__panel{flex-direction:column}.rm-csel__column--right{border-left:none;border-top:1px solid var(--border-soft)}.rm-csel__list{height:180px}}
|
|
437
499
|
</style>
|