@cadriciel/ui 0.4.1 → 0.6.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.
- package/fesm2022/cadriciel-ui.mjs +1699 -12
- package/fesm2022/cadriciel-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/cadriciel-ui.d.ts +560 -3
|
@@ -4090,6 +4090,19 @@ class CadDialogContainerComponent {
|
|
|
4090
4090
|
const vertical = c.drawerPosition === 'top' || c.drawerPosition === 'bottom';
|
|
4091
4091
|
return vertical ? '100%' : (CadDialogContainerComponent.DRAWER_SIZES[s] ?? s);
|
|
4092
4092
|
}
|
|
4093
|
+
// EN PLEIN ÉCRAN MOBILE, LA TAILLE DEMANDÉE N'A PLUS DE SENS : c'est l'écran qui décide.
|
|
4094
|
+
// Sans ça, `size="md"` continuait de valoir 480px et, plafonné par le `max-width: 92%`
|
|
4095
|
+
// ci-dessous, rendait un dialogue de 352px avec des marges — alors qu'un `size="sm"`
|
|
4096
|
+
// (360px) tenait, lui, dans les 390px et paraissait plein écran. Deux dialogues déclarés
|
|
4097
|
+
// dans le même mode s'affichaient donc différemment (signalé par SZU le 22/08/2026).
|
|
4098
|
+
// On corrige à la SOURCE : le CSS tentait de rattraper ça en aval avec des `!important`,
|
|
4099
|
+
// qui ne peuvent pas gagner contre une largeur en ligne dans la chaîne de dimensionnement.
|
|
4100
|
+
// « 100% » ne suffit PAS ici : le panneau CDK qui nous porte a une largeur AUTOMATIQUE,
|
|
4101
|
+
// donc un pourcentage se résout circulairement sur la largeur du contenu — mesuré à 352px
|
|
4102
|
+
// au lieu de 390. On vise donc le viewport. Pas de risque de gouttière d'ascenseur : ce
|
|
4103
|
+
// mode n'existe que sous le seuil mobile, où il n'y a pas d'ascenseur classique.
|
|
4104
|
+
if (this.mobileMode() === 'full')
|
|
4105
|
+
return '100dvw';
|
|
4093
4106
|
return c.width ?? CadDialogContainerComponent.SIZES[c.size ?? 'md'] ?? '480px';
|
|
4094
4107
|
}, ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
|
|
4095
4108
|
height = computed(() => {
|
|
@@ -4103,7 +4116,10 @@ class CadDialogContainerComponent {
|
|
|
4103
4116
|
}
|
|
4104
4117
|
return c.height ?? null;
|
|
4105
4118
|
}, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
|
|
4106
|
-
|
|
4119
|
+
/** Le plafond à 92% laisse respirer un dialogue centré ; en plein écran mobile il n'a plus lieu d'être. */
|
|
4120
|
+
maxWidth = computed(() => this.config().kind === 'drawer' || this.mobileMode() === 'full'
|
|
4121
|
+
? '100%'
|
|
4122
|
+
: (this.config().maxWidth ?? (this.config().size === 'full' ? '100%' : '92%')), ...(ngDevMode ? [{ debugName: "maxWidth" }] : /* istanbul ignore next */ []));
|
|
4107
4123
|
drag = signal(null, ...(ngDevMode ? [{ debugName: "drag" }] : /* istanbul ignore next */ []));
|
|
4108
4124
|
dragTransform = computed(() => { const d = this.drag(); return d ? `translate(${d.x}px, ${d.y}px)` : null; }, ...(ngDevMode ? [{ debugName: "dragTransform" }] : /* istanbul ignore next */ []));
|
|
4109
4125
|
toggleMaximize() { this.maximized.set(!this.maximized()); this.drag.set(null); this.maximizeChange.emit(this.maximized()); }
|
|
@@ -4148,7 +4164,7 @@ class CadDialogContainerComponent {
|
|
|
4148
4164
|
<footer class="cad-dialog__footer"><ng-container *ngTemplateOutlet="config().footer!" /></footer>
|
|
4149
4165
|
}
|
|
4150
4166
|
</div>
|
|
4151
|
-
`, isInline: true, styles: [".cdk-overlay-container{position:fixed;z-index:var(--cad-z-overlay, 100002);pointer-events:none;top:0;left:0;width:100%;height:100%}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000;width:100%;height:100%}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:0;transition:opacity var(--cad-dur, .14s) var(--cad-ease, ease)}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{visibility:visible;opacity:0}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cad-overlay-backdrop{background:var(--cad-backdrop, rgba(2, 6, 23, .45))}.cad-overlay-backdrop.is-hidden{display:none}.cad-overlay-pane{pointer-events:auto}.cad-overlay-pane.is-drawer-pane{height:100%}.cad-dialog-container{display:flex;outline:none;font-family:var(--cad-font);font-size:var(--cad-font-size);color:var(--cad-fg);max-height:100%;max-width:100%}.cad-dialog-container.is-hidden{display:none}.cad-dialog{display:flex;flex-direction:column;background:var(--cad-surface);border:1px solid var(--cad-border);border-radius:var(--cad-radius-lg);box-shadow:var(--cad-shadow-lg);max-height:92vh;min-width:0;outline:none;box-sizing:border-box;opacity:0;transform:translateY(6px) scale(.98);transition:opacity var(--cad-dur) var(--cad-ease),transform var(--cad-dur) var(--cad-ease)}.cad-dialog-container.is-open .cad-dialog{opacity:1;transform:none}.cad-dialog-container.is-maximized .cad-dialog{width:100%!important;max-width:100%!important;height:100vh!important;max-height:100vh;border-radius:0}.cad-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 16px 10px;flex:none}.cad-dialog__header.is-draggable{cursor:move;-webkit-user-select:none;user-select:none}.cad-dialog__title{margin:0;font-size:14.5px;font-weight:600;color:var(--cad-fg);min-width:0}.cad-dialog__actions{display:inline-flex;gap:2px;margin-left:auto;flex:none}.cad-dialog__icon-btn{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:var(--cad-radius-sm);background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:0;transition:background var(--cad-dur),color var(--cad-dur)}.cad-dialog__icon-btn:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-dialog__icon-btn:focus-visible{outline:2px solid var(--cad-ring);outline-offset:1px}.cad-dialog__body{padding:4px 16px 14px;color:var(--cad-fg-secondary);font-size:var(--cad-font-size);overflow:auto;flex:1;min-height:0}.cad-dialog__body:first-child{padding-top:16px}.cad-dialog__footer{display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--cad-border);background:var(--cad-bg-subtle);border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);flex:none}.cad-dialog-container.is-drawer{height:100%}.cad-dialog-container.is-drawer .cad-dialog{max-height:none;height:100%;border-radius:0;opacity:1;transform:none;transition:transform .18s var(--cad-ease)}.cad-dialog-container.is-drawer .cad-dialog__footer{border-radius:0}.cad-dialog-container.is-drawer.pos-right .cad-dialog{transform:translate(100%);border-width:0 0 0 1px}.cad-dialog-container.is-drawer.pos-left .cad-dialog{transform:translate(-100%);border-width:0 1px 0 0}.cad-dialog-container.is-drawer.pos-top .cad-dialog{transform:translateY(-100%);border-width:0 0 1px 0}.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{transform:translateY(100%);border-width:1px 0 0 0}.cad-dialog-container.is-drawer.is-open .cad-dialog{transform:none}.cad-dialog-container.is-drawer.pos-top,.cad-dialog-container.is-drawer.pos-bottom{width:100%}.cad-dialog-container.is-drawer.pos-top .cad-dialog,.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{width:100%!important;max-width:100%!important}.cad-dialog-container.is-mobile-full{width:
|
|
4167
|
+
`, isInline: true, styles: [".cdk-overlay-container{position:fixed;z-index:var(--cad-z-overlay, 100002);pointer-events:none;top:0;left:0;width:100%;height:100%}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000;width:100%;height:100%}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:0;transition:opacity var(--cad-dur, .14s) var(--cad-ease, ease)}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{visibility:visible;opacity:0}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cad-overlay-backdrop{background:var(--cad-backdrop, rgba(2, 6, 23, .45))}.cad-overlay-backdrop.is-hidden{display:none}.cad-overlay-pane{pointer-events:auto}.cad-overlay-pane.is-drawer-pane{height:100%}.cad-dialog-container{display:flex;outline:none;font-family:var(--cad-font);font-size:var(--cad-font-size);color:var(--cad-fg);max-height:100%;max-width:100%}.cad-dialog-container.is-hidden{display:none}.cad-dialog{display:flex;flex-direction:column;background:var(--cad-surface);border:1px solid var(--cad-border);border-radius:var(--cad-radius-lg);box-shadow:var(--cad-shadow-lg);max-height:92vh;min-width:0;outline:none;box-sizing:border-box;opacity:0;transform:translateY(6px) scale(.98);transition:opacity var(--cad-dur) var(--cad-ease),transform var(--cad-dur) var(--cad-ease)}.cad-dialog-container.is-open .cad-dialog{opacity:1;transform:none}.cad-dialog-container.is-maximized .cad-dialog{width:100%!important;max-width:100%!important;height:100vh!important;max-height:100vh;border-radius:0}.cad-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 16px 10px;flex:none}.cad-dialog__header.is-draggable{cursor:move;-webkit-user-select:none;user-select:none}.cad-dialog__title{margin:0;font-size:14.5px;font-weight:600;color:var(--cad-fg);min-width:0}.cad-dialog__actions{display:inline-flex;gap:2px;margin-left:auto;flex:none}.cad-dialog__icon-btn{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:var(--cad-radius-sm);background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:0;transition:background var(--cad-dur),color var(--cad-dur)}.cad-dialog__icon-btn:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-dialog__icon-btn:focus-visible{outline:2px solid var(--cad-ring);outline-offset:1px}.cad-dialog__body{padding:4px 16px 14px;color:var(--cad-fg-secondary);font-size:var(--cad-font-size);overflow:auto;flex:1;min-height:0}.cad-dialog__body:first-child{padding-top:16px}.cad-dialog__footer>[cadDialogFooter]{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;width:100%}.cad-dialog__footer{display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--cad-border);background:var(--cad-bg-subtle);border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);flex:none}.cad-dialog-container.is-drawer{height:100%}.cad-dialog-container.is-drawer .cad-dialog{max-height:none;height:100%;border-radius:0;opacity:1;transform:none;transition:transform .18s var(--cad-ease)}.cad-dialog-container.is-drawer .cad-dialog__footer{border-radius:0}.cad-dialog-container.is-drawer.pos-right .cad-dialog{transform:translate(100%);border-width:0 0 0 1px}.cad-dialog-container.is-drawer.pos-left .cad-dialog{transform:translate(-100%);border-width:0 1px 0 0}.cad-dialog-container.is-drawer.pos-top .cad-dialog{transform:translateY(-100%);border-width:0 0 1px 0}.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{transform:translateY(100%);border-width:1px 0 0 0}.cad-dialog-container.is-drawer.is-open .cad-dialog{transform:none}.cad-dialog-container.is-drawer.pos-top,.cad-dialog-container.is-drawer.pos-bottom{width:100%}.cad-dialog-container.is-drawer.pos-top .cad-dialog,.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{width:100%!important;max-width:100%!important}.cad-dialog-container.is-mobile-full{width:100dvw;height:100dvh;max-height:100dvh;align-items:flex-start}.cad-dialog-container.is-mobile-full .cad-dialog{width:100dvw!important;max-width:100dvw!important;height:auto!important;max-height:100dvh;border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);border:0;box-shadow:none;padding-bottom:env(safe-area-inset-bottom)}.cad-dialog-container.is-mobile-full .cad-dialog__header{position:sticky;top:0;background:var(--cad-surface);z-index:1;padding-top:calc(14px + env(safe-area-inset-top))}.cad-dialog-container.is-mobile-full .cad-dialog__footer{border-radius:0}.cad-overlay-pane.is-mobile-sheet-pane{width:100%;max-width:100%}.cad-dialog-container.is-mobile-sheet{width:100%;align-items:flex-end}.cad-dialog-container.is-mobile-sheet .cad-dialog{position:relative;width:100%!important;max-width:100%!important;height:92dvh!important;max-height:92dvh;border-radius:16px 16px 0 0;border-bottom:0;box-shadow:0 -8px 32px #0000002e;padding-bottom:env(safe-area-inset-bottom);opacity:1;transform:translateY(100%);transition:transform .2s var(--cad-ease)}.cad-dialog-container.is-mobile-sheet.sheet-h-auto .cad-dialog{height:auto!important}.cad-dialog-container.is-mobile-sheet .cad-dialog:before{content:\"\";position:absolute;top:8px;left:50%;width:36px;height:4px;margin-left:-18px;border-radius:2px;background:var(--cad-border-strong)}.cad-dialog-container.is-mobile-sheet .cad-dialog__header{padding-top:20px}.cad-dialog-container.is-mobile-sheet .cad-dialog__body:first-child{padding-top:22px}.cad-dialog-container.is-mobile-sheet.is-open .cad-dialog{transform:none}.cad-dialog-container.is-mobile-sheet .cad-dialog__footer{border-radius:0}.cad-confirm-dialog.is-mobile-sheet .cad-dialog__footer{flex-direction:column-reverse;align-items:stretch;gap:8px}.cad-confirm-dialog.is-mobile-sheet .cad-dialog__footer>*{width:100%;height:44px}@media(prefers-reduced-motion:reduce){.cad-dialog,.cad-dialog-container.is-drawer .cad-dialog,.cad-dialog-container.is-mobile-sheet .cad-dialog,.cdk-overlay-backdrop{transition:none!important}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1$1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: CadIconComponent, selector: "cad-icon", inputs: ["name", "size", "strokeWidth", "label", "title", "spin", "filled", "flip", "rotate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
4152
4168
|
}
|
|
4153
4169
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadDialogContainerComponent, decorators: [{
|
|
4154
4170
|
type: Component,
|
|
@@ -4194,7 +4210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
4194
4210
|
<footer class="cad-dialog__footer"><ng-container *ngTemplateOutlet="config().footer!" /></footer>
|
|
4195
4211
|
}
|
|
4196
4212
|
</div>
|
|
4197
|
-
`, styles: [".cdk-overlay-container{position:fixed;z-index:var(--cad-z-overlay, 100002);pointer-events:none;top:0;left:0;width:100%;height:100%}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000;width:100%;height:100%}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:0;transition:opacity var(--cad-dur, .14s) var(--cad-ease, ease)}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{visibility:visible;opacity:0}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cad-overlay-backdrop{background:var(--cad-backdrop, rgba(2, 6, 23, .45))}.cad-overlay-backdrop.is-hidden{display:none}.cad-overlay-pane{pointer-events:auto}.cad-overlay-pane.is-drawer-pane{height:100%}.cad-dialog-container{display:flex;outline:none;font-family:var(--cad-font);font-size:var(--cad-font-size);color:var(--cad-fg);max-height:100%;max-width:100%}.cad-dialog-container.is-hidden{display:none}.cad-dialog{display:flex;flex-direction:column;background:var(--cad-surface);border:1px solid var(--cad-border);border-radius:var(--cad-radius-lg);box-shadow:var(--cad-shadow-lg);max-height:92vh;min-width:0;outline:none;box-sizing:border-box;opacity:0;transform:translateY(6px) scale(.98);transition:opacity var(--cad-dur) var(--cad-ease),transform var(--cad-dur) var(--cad-ease)}.cad-dialog-container.is-open .cad-dialog{opacity:1;transform:none}.cad-dialog-container.is-maximized .cad-dialog{width:100%!important;max-width:100%!important;height:100vh!important;max-height:100vh;border-radius:0}.cad-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 16px 10px;flex:none}.cad-dialog__header.is-draggable{cursor:move;-webkit-user-select:none;user-select:none}.cad-dialog__title{margin:0;font-size:14.5px;font-weight:600;color:var(--cad-fg);min-width:0}.cad-dialog__actions{display:inline-flex;gap:2px;margin-left:auto;flex:none}.cad-dialog__icon-btn{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:var(--cad-radius-sm);background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:0;transition:background var(--cad-dur),color var(--cad-dur)}.cad-dialog__icon-btn:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-dialog__icon-btn:focus-visible{outline:2px solid var(--cad-ring);outline-offset:1px}.cad-dialog__body{padding:4px 16px 14px;color:var(--cad-fg-secondary);font-size:var(--cad-font-size);overflow:auto;flex:1;min-height:0}.cad-dialog__body:first-child{padding-top:16px}.cad-dialog__footer{display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--cad-border);background:var(--cad-bg-subtle);border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);flex:none}.cad-dialog-container.is-drawer{height:100%}.cad-dialog-container.is-drawer .cad-dialog{max-height:none;height:100%;border-radius:0;opacity:1;transform:none;transition:transform .18s var(--cad-ease)}.cad-dialog-container.is-drawer .cad-dialog__footer{border-radius:0}.cad-dialog-container.is-drawer.pos-right .cad-dialog{transform:translate(100%);border-width:0 0 0 1px}.cad-dialog-container.is-drawer.pos-left .cad-dialog{transform:translate(-100%);border-width:0 1px 0 0}.cad-dialog-container.is-drawer.pos-top .cad-dialog{transform:translateY(-100%);border-width:0 0 1px 0}.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{transform:translateY(100%);border-width:1px 0 0 0}.cad-dialog-container.is-drawer.is-open .cad-dialog{transform:none}.cad-dialog-container.is-drawer.pos-top,.cad-dialog-container.is-drawer.pos-bottom{width:100%}.cad-dialog-container.is-drawer.pos-top .cad-dialog,.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{width:100%!important;max-width:100%!important}.cad-dialog-container.is-mobile-full{width:
|
|
4213
|
+
`, styles: [".cdk-overlay-container{position:fixed;z-index:var(--cad-z-overlay, 100002);pointer-events:none;top:0;left:0;width:100%;height:100%}.cdk-overlay-container:empty{display:none}.cdk-global-overlay-wrapper{display:flex;position:absolute;z-index:1000;width:100%;height:100%}.cdk-overlay-pane{position:absolute;pointer-events:auto;box-sizing:border-box;z-index:1000;display:flex;max-width:100%;max-height:100%}.cdk-overlay-backdrop{position:absolute;inset:0;z-index:1000;pointer-events:auto;-webkit-tap-highlight-color:transparent;opacity:0;transition:opacity var(--cad-dur, .14s) var(--cad-ease, ease)}.cdk-overlay-backdrop.cdk-overlay-backdrop-showing{opacity:1}.cdk-overlay-transparent-backdrop{transition:visibility 1ms linear,opacity 1ms linear;visibility:hidden;opacity:1}.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing{visibility:visible;opacity:0}.cdk-overlay-connected-position-bounding-box{position:absolute;z-index:1000;display:flex;flex-direction:column;min-width:1px;min-height:1px}.cdk-global-scrollblock{position:fixed;width:100%;overflow-y:scroll}.cad-overlay-backdrop{background:var(--cad-backdrop, rgba(2, 6, 23, .45))}.cad-overlay-backdrop.is-hidden{display:none}.cad-overlay-pane{pointer-events:auto}.cad-overlay-pane.is-drawer-pane{height:100%}.cad-dialog-container{display:flex;outline:none;font-family:var(--cad-font);font-size:var(--cad-font-size);color:var(--cad-fg);max-height:100%;max-width:100%}.cad-dialog-container.is-hidden{display:none}.cad-dialog{display:flex;flex-direction:column;background:var(--cad-surface);border:1px solid var(--cad-border);border-radius:var(--cad-radius-lg);box-shadow:var(--cad-shadow-lg);max-height:92vh;min-width:0;outline:none;box-sizing:border-box;opacity:0;transform:translateY(6px) scale(.98);transition:opacity var(--cad-dur) var(--cad-ease),transform var(--cad-dur) var(--cad-ease)}.cad-dialog-container.is-open .cad-dialog{opacity:1;transform:none}.cad-dialog-container.is-maximized .cad-dialog{width:100%!important;max-width:100%!important;height:100vh!important;max-height:100vh;border-radius:0}.cad-dialog__header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:14px 16px 10px;flex:none}.cad-dialog__header.is-draggable{cursor:move;-webkit-user-select:none;user-select:none}.cad-dialog__title{margin:0;font-size:14.5px;font-weight:600;color:var(--cad-fg);min-width:0}.cad-dialog__actions{display:inline-flex;gap:2px;margin-left:auto;flex:none}.cad-dialog__icon-btn{display:grid;place-items:center;width:26px;height:26px;border:0;border-radius:var(--cad-radius-sm);background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:0;transition:background var(--cad-dur),color var(--cad-dur)}.cad-dialog__icon-btn:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-dialog__icon-btn:focus-visible{outline:2px solid var(--cad-ring);outline-offset:1px}.cad-dialog__body{padding:4px 16px 14px;color:var(--cad-fg-secondary);font-size:var(--cad-font-size);overflow:auto;flex:1;min-height:0}.cad-dialog__body:first-child{padding-top:16px}.cad-dialog__footer>[cadDialogFooter]{display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap;width:100%}.cad-dialog__footer{display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 16px;border-top:1px solid var(--cad-border);background:var(--cad-bg-subtle);border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);flex:none}.cad-dialog-container.is-drawer{height:100%}.cad-dialog-container.is-drawer .cad-dialog{max-height:none;height:100%;border-radius:0;opacity:1;transform:none;transition:transform .18s var(--cad-ease)}.cad-dialog-container.is-drawer .cad-dialog__footer{border-radius:0}.cad-dialog-container.is-drawer.pos-right .cad-dialog{transform:translate(100%);border-width:0 0 0 1px}.cad-dialog-container.is-drawer.pos-left .cad-dialog{transform:translate(-100%);border-width:0 1px 0 0}.cad-dialog-container.is-drawer.pos-top .cad-dialog{transform:translateY(-100%);border-width:0 0 1px 0}.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{transform:translateY(100%);border-width:1px 0 0 0}.cad-dialog-container.is-drawer.is-open .cad-dialog{transform:none}.cad-dialog-container.is-drawer.pos-top,.cad-dialog-container.is-drawer.pos-bottom{width:100%}.cad-dialog-container.is-drawer.pos-top .cad-dialog,.cad-dialog-container.is-drawer.pos-bottom .cad-dialog{width:100%!important;max-width:100%!important}.cad-dialog-container.is-mobile-full{width:100dvw;height:100dvh;max-height:100dvh;align-items:flex-start}.cad-dialog-container.is-mobile-full .cad-dialog{width:100dvw!important;max-width:100dvw!important;height:auto!important;max-height:100dvh;border-radius:0 0 var(--cad-radius-lg) var(--cad-radius-lg);border:0;box-shadow:none;padding-bottom:env(safe-area-inset-bottom)}.cad-dialog-container.is-mobile-full .cad-dialog__header{position:sticky;top:0;background:var(--cad-surface);z-index:1;padding-top:calc(14px + env(safe-area-inset-top))}.cad-dialog-container.is-mobile-full .cad-dialog__footer{border-radius:0}.cad-overlay-pane.is-mobile-sheet-pane{width:100%;max-width:100%}.cad-dialog-container.is-mobile-sheet{width:100%;align-items:flex-end}.cad-dialog-container.is-mobile-sheet .cad-dialog{position:relative;width:100%!important;max-width:100%!important;height:92dvh!important;max-height:92dvh;border-radius:16px 16px 0 0;border-bottom:0;box-shadow:0 -8px 32px #0000002e;padding-bottom:env(safe-area-inset-bottom);opacity:1;transform:translateY(100%);transition:transform .2s var(--cad-ease)}.cad-dialog-container.is-mobile-sheet.sheet-h-auto .cad-dialog{height:auto!important}.cad-dialog-container.is-mobile-sheet .cad-dialog:before{content:\"\";position:absolute;top:8px;left:50%;width:36px;height:4px;margin-left:-18px;border-radius:2px;background:var(--cad-border-strong)}.cad-dialog-container.is-mobile-sheet .cad-dialog__header{padding-top:20px}.cad-dialog-container.is-mobile-sheet .cad-dialog__body:first-child{padding-top:22px}.cad-dialog-container.is-mobile-sheet.is-open .cad-dialog{transform:none}.cad-dialog-container.is-mobile-sheet .cad-dialog__footer{border-radius:0}.cad-confirm-dialog.is-mobile-sheet .cad-dialog__footer{flex-direction:column-reverse;align-items:stretch;gap:8px}.cad-confirm-dialog.is-mobile-sheet .cad-dialog__footer>*{width:100%;height:44px}@media(prefers-reduced-motion:reduce){.cad-dialog,.cad-dialog-container.is-drawer .cad-dialog,.cad-dialog-container.is-mobile-sheet .cad-dialog,.cdk-overlay-backdrop{transition:none!important}}\n"] }]
|
|
4198
4214
|
}], propDecorators: { closeRequest: [{ type: i0.Output, args: ["closeRequest"] }], attached: [{ type: i0.Output, args: ["attached"] }], maximizeChange: [{ type: i0.Output, args: ["maximizeChange"] }] } });
|
|
4199
4215
|
|
|
4200
4216
|
const ANIM_MS = 180;
|
|
@@ -6314,6 +6330,44 @@ const CAD_SHELL = new InjectionToken('CAD_SHELL');
|
|
|
6314
6330
|
* <cad-bottom-nav cadShellBottom [items]="dest" [(value)]="page"/>
|
|
6315
6331
|
* </cad-app-shell>
|
|
6316
6332
|
* ```
|
|
6333
|
+
*
|
|
6334
|
+
* ⚠️ N'ENVELOPPEZ JAMAIS UN EMPLACEMENT DANS UN `@if` (ni `@for`, ni `<ng-template>`).
|
|
6335
|
+
*
|
|
6336
|
+
* La projection de contenu est STATIQUE : Angular apparie les nœuds aux sélecteurs de
|
|
6337
|
+
* `ng-content` sur la structure déclarée. Un `<header cadShellBar>` placé dans un bloc de
|
|
6338
|
+
* flux de contrôle n'est jamais apparié — il tombe dans l'emplacement PAR DÉFAUT, donc dans
|
|
6339
|
+
* la zone de CONTENU. Rien ne le signale : ça compile, ça s'affiche, et la barre se met à
|
|
6340
|
+
* défiler avec le contenu — exactement le défaut que cette coquille existe pour empêcher.
|
|
6341
|
+
* Constaté au navigateur le 22/08/2026 sur le showcase (`.cad-shell__bar` mesurait 0×0).
|
|
6342
|
+
*
|
|
6343
|
+
* ```html
|
|
6344
|
+
* <!-- FAUX : la barre atterrit dans le contenu -->
|
|
6345
|
+
* @if (connecte()) { <header cadShellBar>…</header> }
|
|
6346
|
+
*
|
|
6347
|
+
* <!-- JUSTE : l'emplacement est toujours rendu, c'est son CONTENU qui varie -->
|
|
6348
|
+
* <header cadShellBar [class.est-masque]="!connecte()">…</header>
|
|
6349
|
+
* ```
|
|
6350
|
+
*
|
|
6351
|
+
* Une rangée ou une colonne `auto` dont l'unique enfant est en `display: none` se replie à
|
|
6352
|
+
* zéro : masquer ainsi ne laisse aucune trace dans la mise en page.
|
|
6353
|
+
*
|
|
6354
|
+
* ⚠️ ZONES SÛRES — DEUX CONDITIONS, ET LA PREMIÈRE EST DANS `index.html`.
|
|
6355
|
+
*
|
|
6356
|
+
* 1. **`<meta name="viewport" content="…, viewport-fit=cover">`**. Sans lui, iOS encadre la
|
|
6357
|
+
* page : elle ne s'étend jamais sous l'encoche, la bande du haut est peinte par le SYSTÈME,
|
|
6358
|
+
* et **tous les `env(safe-area-inset-*)` valent 0**. Toute la mécanique de zone sûre de la
|
|
6359
|
+
* bibliothèque — celle de `cad-bottom-nav`, celle du tiroir en mode temporaire — est alors
|
|
6360
|
+
* inerte sans que rien ne le signale.
|
|
6361
|
+
* 2. **La barre peint sa propre zone sûre haute** : `padding-top: env(safe-area-inset-top)`
|
|
6362
|
+
* sur l'élément projeté, PAS sur la coquille. Le rembourrage est intérieur au fond, donc la
|
|
6363
|
+
* couleur de la barre monte jusqu'au bord de l'écran. Le poser côté coquille laisserait la
|
|
6364
|
+
* bande sous l'encoche au fond de la COQUILLE : la cassure resterait, d'une autre couleur.
|
|
6365
|
+
* Avec `box-sizing: border-box`, penser au `min-height: calc(52px + env(safe-area-inset-top))`
|
|
6366
|
+
* — sinon l'encoche mange la hauteur du contenu.
|
|
6367
|
+
*
|
|
6368
|
+
* En application autonome (ajoutée à l'écran d'accueil), la page ne passe pas sous la bande
|
|
6369
|
+
* d'état : `viewport-fit=cover` n'y suffit pas et c'est `<meta name="theme-color">`, tenu à
|
|
6370
|
+
* jour avec le thème, qui donne la continuité.
|
|
6317
6371
|
*/
|
|
6318
6372
|
class CadAppShellComponent {
|
|
6319
6373
|
bp = inject(CadBreakpointService);
|
|
@@ -9398,6 +9452,15 @@ class CadNavDrawerComponent {
|
|
|
9398
9452
|
open = model(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
9399
9453
|
/** Entrée courante, comparée à `item.value`. */
|
|
9400
9454
|
value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
9455
|
+
/**
|
|
9456
|
+
* Clés des intertitres repliés (`item.value`, à défaut `item.label`).
|
|
9457
|
+
*
|
|
9458
|
+
* Un TABLEAU et non un `Set` : c'est ce qui se lie en deux sens, se compare, et surtout se
|
|
9459
|
+
* sérialise tel quel — l'hôte qui veut persister l'état le pose dans `localStorage` sans
|
|
9460
|
+
* conversion. Le composant ne persiste rien lui-même : il ne saurait pas sous quelle clé,
|
|
9461
|
+
* ni s'il a le droit.
|
|
9462
|
+
*/
|
|
9463
|
+
collapsed = model([], ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
|
|
9401
9464
|
mode = input('auto', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
9402
9465
|
/** Seuil de bascule permanent → tiroir, en mode `auto`. */
|
|
9403
9466
|
breakpoint = input('md', ...(ngDevMode ? [{ debugName: "breakpoint" }] : /* istanbul ignore next */ []));
|
|
@@ -9426,6 +9489,42 @@ class CadNavDrawerComponent {
|
|
|
9426
9489
|
}, ...(ngDevMode ? [{ debugName: "effective" }] : /* istanbul ignore next */ []));
|
|
9427
9490
|
temporary = computed(() => this.effective() === 'temporary', ...(ngDevMode ? [{ debugName: "temporary" }] : /* istanbul ignore next */ []));
|
|
9428
9491
|
rail = computed(() => this.effective() === 'rail', ...(ngDevMode ? [{ debugName: "rail" }] : /* istanbul ignore next */ []));
|
|
9492
|
+
/** Clé d'un intertitre. `value` d'abord : un libellé se renomme, une clé non. */
|
|
9493
|
+
cle(it) { return it.value ?? it.label; }
|
|
9494
|
+
/**
|
|
9495
|
+
* Les lignes à rendre : les intertitres toujours, les entrées seulement si leur intertitre
|
|
9496
|
+
* n'est pas replié. Une entrée qui précède tout intertitre n'appartient à aucun groupe et
|
|
9497
|
+
* ne se replie donc jamais — sans quoi elle serait masquée sans bouton pour la rouvrir.
|
|
9498
|
+
*/
|
|
9499
|
+
rows = computed(() => {
|
|
9500
|
+
const replies = new Set(this.collapsed());
|
|
9501
|
+
const rail = this.rail();
|
|
9502
|
+
const out = [];
|
|
9503
|
+
let courante = null;
|
|
9504
|
+
for (const item of this.items()) {
|
|
9505
|
+
if (item.section) {
|
|
9506
|
+
// En rail l'intertitre devient un filet : plus de bouton, donc rien ne se replie.
|
|
9507
|
+
const collapsible = !rail && !!item.collapsible;
|
|
9508
|
+
const key = this.cle(item);
|
|
9509
|
+
courante = { item, key, collapsible, collapsed: collapsible && replies.has(key), count: 0 };
|
|
9510
|
+
out.push(courante);
|
|
9511
|
+
continue;
|
|
9512
|
+
}
|
|
9513
|
+
// Le compte est celui du GROUPE, pas de ce qui est visible : il doit rester le même
|
|
9514
|
+
// une fois replié, sinon il annoncerait zéro au moment où il sert le plus.
|
|
9515
|
+
if (courante)
|
|
9516
|
+
courante.count++;
|
|
9517
|
+
if (courante?.collapsed)
|
|
9518
|
+
continue;
|
|
9519
|
+
out.push({ item, key: '', collapsible: false, collapsed: false, count: 0 });
|
|
9520
|
+
}
|
|
9521
|
+
return out;
|
|
9522
|
+
}, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
9523
|
+
toggleSection(r) {
|
|
9524
|
+
const s = new Set(this.collapsed());
|
|
9525
|
+
s.has(r.key) ? s.delete(r.key) : s.add(r.key);
|
|
9526
|
+
this.collapsed.set([...s]);
|
|
9527
|
+
}
|
|
9429
9528
|
wasOpen = signal(false, ...(ngDevMode ? [{ debugName: "wasOpen" }] : /* istanbul ignore next */ []));
|
|
9430
9529
|
constructor() {
|
|
9431
9530
|
effect(() => {
|
|
@@ -9471,7 +9570,7 @@ class CadNavDrawerComponent {
|
|
|
9471
9570
|
this.open.set(false);
|
|
9472
9571
|
}
|
|
9473
9572
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadNavDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9474
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CadNavDrawerComponent, isStandalone: true, selector: "cad-nav-drawer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, breakpoint: { classPropertyName: "breakpoint", publicName: "breakpoint", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, closeOnNavigate: { classPropertyName: "closeOnNavigate", publicName: "closeOnNavigate", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, dismissableScrim: { classPropertyName: "dismissableScrim", publicName: "dismissableScrim", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", value: "valueChange", opened: "opened", closed: "closed", itemClick: "itemClick", changed: "changed" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "class.is-temporary": "temporary()", "class.is-permanent": "!temporary()", "class.is-rail": "rail()", "class.is-open": "open()", "class.is-right": "position() === \"right\"" }, classAttribute: "cad-nav-drawer" }, queries: [{ propertyName: "headerSlot", first: true, predicate: CadNavDrawerHeaderDirective, descendants: true, isSignal: true }, { propertyName: "footerSlot", first: true, predicate: CadNavDrawerFooterDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
9573
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CadNavDrawerComponent, isStandalone: true, selector: "cad-nav-drawer", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, breakpoint: { classPropertyName: "breakpoint", publicName: "breakpoint", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, closeOnNavigate: { classPropertyName: "closeOnNavigate", publicName: "closeOnNavigate", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, dismissableScrim: { classPropertyName: "dismissableScrim", publicName: "dismissableScrim", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", value: "valueChange", collapsed: "collapsedChange", opened: "opened", closed: "closed", itemClick: "itemClick", changed: "changed" }, host: { listeners: { "document:keydown.escape": "onEscape()" }, properties: { "class.is-temporary": "temporary()", "class.is-permanent": "!temporary()", "class.is-rail": "rail()", "class.is-open": "open()", "class.is-right": "position() === \"right\"" }, classAttribute: "cad-nav-drawer" }, queries: [{ propertyName: "headerSlot", first: true, predicate: CadNavDrawerHeaderDirective, descendants: true, isSignal: true }, { propertyName: "footerSlot", first: true, predicate: CadNavDrawerFooterDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
9475
9574
|
<!-- Le voile n'existe qu'en mode tiroir : en permanent il n'y a rien à recouvrir. -->
|
|
9476
9575
|
@if (temporary() && open()) {
|
|
9477
9576
|
<div class="cad-nav-drawer__scrim" (click)="dismiss()" aria-hidden="true"></div>
|
|
@@ -9492,11 +9591,28 @@ class CadNavDrawerComponent {
|
|
|
9492
9591
|
</div>
|
|
9493
9592
|
|
|
9494
9593
|
<ul class="cad-nav-drawer__list" role="list">
|
|
9495
|
-
@for (
|
|
9594
|
+
@for (r of rows(); track $index) {
|
|
9595
|
+
@let it = r.item;
|
|
9496
9596
|
@if (it.section) {
|
|
9497
9597
|
<!-- En rail, un intertitre n'a plus de place : un filet le remplace. -->
|
|
9498
9598
|
@if (rail()) {
|
|
9499
9599
|
<li class="cad-nav-drawer__rule" role="separator"></li>
|
|
9600
|
+
} @else if (r.collapsible) {
|
|
9601
|
+
<li>
|
|
9602
|
+
<button
|
|
9603
|
+
type="button"
|
|
9604
|
+
class="cad-nav-drawer__section is-collapsible"
|
|
9605
|
+
[class.is-collapsed]="r.collapsed"
|
|
9606
|
+
[attr.aria-expanded]="!r.collapsed"
|
|
9607
|
+
(click)="toggleSection(r)"
|
|
9608
|
+
>
|
|
9609
|
+
<cad-icon name="chevron-down" [size]="12" class="cad-nav-drawer__chev"/>
|
|
9610
|
+
<span class="cad-nav-drawer__label">{{ it.label }}</span>
|
|
9611
|
+
<!-- Un compte DÉCLARÉ l'emporte sur le compte calculé : une valeur posée
|
|
9612
|
+
par l'hôte est une affirmation, pas un oubli à combler. -->
|
|
9613
|
+
<span class="cad-nav-drawer__badge">{{ it.badge ?? r.count }}</span>
|
|
9614
|
+
</button>
|
|
9615
|
+
</li>
|
|
9500
9616
|
} @else {
|
|
9501
9617
|
<li class="cad-nav-drawer__section">{{ it.label }}</li>
|
|
9502
9618
|
}
|
|
@@ -9547,7 +9663,7 @@ class CadNavDrawerComponent {
|
|
|
9547
9663
|
<span class="cad-nav-drawer__dot" [attr.title]="it.badge"></span>
|
|
9548
9664
|
}
|
|
9549
9665
|
</ng-template>
|
|
9550
|
-
`, isInline: true, styles: [":host{display:block}:host(.is-permanent){flex:none}.cad-nav-drawer__panel{display:flex;flex-direction:column;min-height:0;height:100%;width:var(--cad-nav-drawer-w, 240px);background:var(--cad-bg-subtle);border-right:1px solid var(--cad-border);transition:width var(--cad-dur) var(--cad-ease)}:host(.is-rail) .cad-nav-drawer__panel{width:var(--cad-nav-drawer-rail-w, 56px)}:host(.is-right) .cad-nav-drawer__panel{border-right:0;border-left:1px solid var(--cad-border)}:host(.is-temporary){position:fixed;inset:0 auto 0 0;z-index:var(--cad-z-overlay, 100002);pointer-events:none}:host(.is-temporary.is-right){inset:0 0 0 auto}:host(.is-temporary) .cad-nav-drawer__panel{pointer-events:auto;height:100%;box-shadow:var(--cad-shadow-lg, 0 12px 24px rgba(15,23,42,.18));transform:translate(-100%);transition:transform var(--cad-dur) var(--cad-ease)}:host(.is-temporary.is-right) .cad-nav-drawer__panel{transform:translate(100%)}:host(.is-temporary.is-open) .cad-nav-drawer__panel{transform:translate(0)}.cad-nav-drawer__scrim{position:fixed;inset:0;background:var(--cad-backdrop, rgba(2,6,23,.45));pointer-events:auto;z-index:-1}.cad-nav-drawer__head{display:flex;align-items:center;gap:9px;flex:none;padding:14px 14px 12px;border-bottom:1px solid var(--cad-border);min-height:48px;color:var(--cad-fg);font-size:13px}:host(.is-rail) .cad-nav-drawer__head{justify-content:center;padding:14px 0 12px}.cad-nav-drawer__head cad-icon{color:var(--cad-accent);flex:none}.cad-nav-drawer__list{list-style:none;margin:0;padding:8px 0;flex:1;min-height:0;overflow-y:auto}.cad-nav-drawer__section{padding:12px 14px 5px;font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__rule{height:1px;margin:8px 12px;background:var(--cad-border)}.cad-nav-drawer__item{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;cursor:pointer;padding:8px 14px;min-height:38px;color:var(--cad-fg-secondary);font:12.5px var(--cad-font);text-decoration:none}:host(.is-rail) .cad-nav-drawer__item{justify-content:center;padding:10px 0}.cad-nav-drawer__item:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-nav-drawer__item:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__item.is-active{background:var(--cad-accent-soft);color:var(--cad-accent);font-weight:500;box-shadow:inset 3px 0 0 var(--cad-accent)}:host(.is-right) .cad-nav-drawer__item.is-active{box-shadow:inset -3px 0 0 var(--cad-accent)}.cad-nav-drawer__item.is-disabled,.cad-nav-drawer__item:disabled{opacity:.45;cursor:not-allowed}.cad-nav-drawer__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cad-nav-drawer__badge{flex:none;font-size:10.5px;font-family:var(--cad-font-mono);border-radius:var(--cad-radius-pill);padding:1px 7px;background:var(--cad-elevated, var(--cad-border));color:var(--cad-fg-secondary)}.cad-nav-drawer__item.is-active .cad-nav-drawer__badge{background:var(--cad-accent);color:var(--cad-fg-on-accent)}.cad-nav-drawer__dot{position:absolute;margin:-14px 0 0 14px;width:7px;height:7px;border-radius:50%;background:var(--cad-danger, #f85149)}.cad-nav-drawer__foot{flex:none;border-top:1px solid var(--cad-border);padding:10px 14px}.cad-nav-drawer__foot.is-empty{display:none}:host(.is-rail) .cad-nav-drawer__foot{padding:10px 0;display:flex;justify-content:center}:host-context(.cad-touch) .cad-nav-drawer__item{min-height:44px}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__panel{transition:none}}\n"], dependencies: [{ kind: "component", type: CadIconComponent, selector: "cad-icon", inputs: ["name", "size", "strokeWidth", "label", "title", "spin", "filled", "flip", "rotate"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9666
|
+
`, isInline: true, styles: [":host{display:block}:host(.is-permanent){flex:none}.cad-nav-drawer__panel{display:flex;flex-direction:column;min-height:0;height:100%;width:var(--cad-nav-drawer-w, 240px);background:var(--cad-bg-subtle);border-right:1px solid var(--cad-border);transition:width var(--cad-dur) var(--cad-ease)}:host(.is-rail) .cad-nav-drawer__panel{width:var(--cad-nav-drawer-rail-w, 56px)}:host(.is-right) .cad-nav-drawer__panel{border-right:0;border-left:1px solid var(--cad-border)}:host(.is-temporary){position:fixed;inset:0 auto 0 0;z-index:var(--cad-z-overlay, 100002);pointer-events:none}:host(.is-temporary.is-right){inset:0 0 0 auto}:host(.is-temporary) .cad-nav-drawer__panel{pointer-events:auto;height:100%;box-shadow:var(--cad-shadow-lg, 0 12px 24px rgba(15,23,42,.18));transform:translate(-100%);transition:transform var(--cad-dur) var(--cad-ease);padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}:host(.is-temporary.is-right) .cad-nav-drawer__panel{transform:translate(100%)}:host(.is-temporary.is-open) .cad-nav-drawer__panel{transform:translate(0)}.cad-nav-drawer__scrim{position:fixed;inset:0;background:var(--cad-backdrop, rgba(2,6,23,.45));pointer-events:auto;z-index:-1}.cad-nav-drawer__head{display:flex;align-items:center;gap:9px;flex:none;padding:14px 14px 12px;border-bottom:1px solid var(--cad-border);min-height:48px;color:var(--cad-fg);font-size:13px}:host(.is-rail) .cad-nav-drawer__head{justify-content:center;padding:14px 0 12px}.cad-nav-drawer__head cad-icon{color:var(--cad-accent);flex:none}.cad-nav-drawer__list{list-style:none;margin:0;padding:8px 0;flex:1;min-height:0;overflow-y:auto}.cad-nav-drawer__section{padding:12px 14px 5px;font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__rule{height:1px;margin:8px 12px;background:var(--cad-border)}.cad-nav-drawer__section.is-collapsible{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;cursor:pointer;padding:12px 14px 5px;font:500 10px var(--cad-font);letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__section.is-collapsible:hover{color:var(--cad-fg-secondary)}.cad-nav-drawer__section.is-collapsible:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__chev{flex:none;transition:transform var(--cad-dur) var(--cad-ease)}.cad-nav-drawer__section.is-collapsed .cad-nav-drawer__chev{transform:rotate(-90deg)}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__chev{transition:none}}.cad-nav-drawer__item{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;cursor:pointer;padding:8px 14px;min-height:38px;color:var(--cad-fg-secondary);font:12.5px var(--cad-font);text-decoration:none}:host(.is-rail) .cad-nav-drawer__item{justify-content:center;padding:10px 0}.cad-nav-drawer__item:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-nav-drawer__item:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__item.is-active{background:var(--cad-accent-soft);color:var(--cad-accent);font-weight:500;box-shadow:inset 3px 0 0 var(--cad-accent)}:host(.is-right) .cad-nav-drawer__item.is-active{box-shadow:inset -3px 0 0 var(--cad-accent)}.cad-nav-drawer__item.is-disabled,.cad-nav-drawer__item:disabled{opacity:.45;cursor:not-allowed}.cad-nav-drawer__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cad-nav-drawer__badge{flex:none;font-size:10.5px;font-family:var(--cad-font-mono);border-radius:var(--cad-radius-pill);padding:1px 7px;background:var(--cad-elevated, var(--cad-border));color:var(--cad-fg-secondary)}.cad-nav-drawer__item.is-active .cad-nav-drawer__badge{background:var(--cad-accent);color:var(--cad-fg-on-accent)}.cad-nav-drawer__dot{position:absolute;margin:-14px 0 0 14px;width:7px;height:7px;border-radius:50%;background:var(--cad-danger, #f85149)}.cad-nav-drawer__foot{flex:none;border-top:1px solid var(--cad-border);padding:10px 14px}.cad-nav-drawer__foot.is-empty{display:none}:host(.is-rail) .cad-nav-drawer__foot{padding:10px 0;display:flex;justify-content:center}:host-context(.cad-touch) .cad-nav-drawer__item{min-height:44px}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__panel{transition:none}}\n"], dependencies: [{ kind: "component", type: CadIconComponent, selector: "cad-icon", inputs: ["name", "size", "strokeWidth", "label", "title", "spin", "filled", "flip", "rotate"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9551
9667
|
}
|
|
9552
9668
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadNavDrawerComponent, decorators: [{
|
|
9553
9669
|
type: Component,
|
|
@@ -9579,11 +9695,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
9579
9695
|
</div>
|
|
9580
9696
|
|
|
9581
9697
|
<ul class="cad-nav-drawer__list" role="list">
|
|
9582
|
-
@for (
|
|
9698
|
+
@for (r of rows(); track $index) {
|
|
9699
|
+
@let it = r.item;
|
|
9583
9700
|
@if (it.section) {
|
|
9584
9701
|
<!-- En rail, un intertitre n'a plus de place : un filet le remplace. -->
|
|
9585
9702
|
@if (rail()) {
|
|
9586
9703
|
<li class="cad-nav-drawer__rule" role="separator"></li>
|
|
9704
|
+
} @else if (r.collapsible) {
|
|
9705
|
+
<li>
|
|
9706
|
+
<button
|
|
9707
|
+
type="button"
|
|
9708
|
+
class="cad-nav-drawer__section is-collapsible"
|
|
9709
|
+
[class.is-collapsed]="r.collapsed"
|
|
9710
|
+
[attr.aria-expanded]="!r.collapsed"
|
|
9711
|
+
(click)="toggleSection(r)"
|
|
9712
|
+
>
|
|
9713
|
+
<cad-icon name="chevron-down" [size]="12" class="cad-nav-drawer__chev"/>
|
|
9714
|
+
<span class="cad-nav-drawer__label">{{ it.label }}</span>
|
|
9715
|
+
<!-- Un compte DÉCLARÉ l'emporte sur le compte calculé : une valeur posée
|
|
9716
|
+
par l'hôte est une affirmation, pas un oubli à combler. -->
|
|
9717
|
+
<span class="cad-nav-drawer__badge">{{ it.badge ?? r.count }}</span>
|
|
9718
|
+
</button>
|
|
9719
|
+
</li>
|
|
9587
9720
|
} @else {
|
|
9588
9721
|
<li class="cad-nav-drawer__section">{{ it.label }}</li>
|
|
9589
9722
|
}
|
|
@@ -9634,8 +9767,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
9634
9767
|
<span class="cad-nav-drawer__dot" [attr.title]="it.badge"></span>
|
|
9635
9768
|
}
|
|
9636
9769
|
</ng-template>
|
|
9637
|
-
`, styles: [":host{display:block}:host(.is-permanent){flex:none}.cad-nav-drawer__panel{display:flex;flex-direction:column;min-height:0;height:100%;width:var(--cad-nav-drawer-w, 240px);background:var(--cad-bg-subtle);border-right:1px solid var(--cad-border);transition:width var(--cad-dur) var(--cad-ease)}:host(.is-rail) .cad-nav-drawer__panel{width:var(--cad-nav-drawer-rail-w, 56px)}:host(.is-right) .cad-nav-drawer__panel{border-right:0;border-left:1px solid var(--cad-border)}:host(.is-temporary){position:fixed;inset:0 auto 0 0;z-index:var(--cad-z-overlay, 100002);pointer-events:none}:host(.is-temporary.is-right){inset:0 0 0 auto}:host(.is-temporary) .cad-nav-drawer__panel{pointer-events:auto;height:100%;box-shadow:var(--cad-shadow-lg, 0 12px 24px rgba(15,23,42,.18));transform:translate(-100%);transition:transform var(--cad-dur) var(--cad-ease)}:host(.is-temporary.is-right) .cad-nav-drawer__panel{transform:translate(100%)}:host(.is-temporary.is-open) .cad-nav-drawer__panel{transform:translate(0)}.cad-nav-drawer__scrim{position:fixed;inset:0;background:var(--cad-backdrop, rgba(2,6,23,.45));pointer-events:auto;z-index:-1}.cad-nav-drawer__head{display:flex;align-items:center;gap:9px;flex:none;padding:14px 14px 12px;border-bottom:1px solid var(--cad-border);min-height:48px;color:var(--cad-fg);font-size:13px}:host(.is-rail) .cad-nav-drawer__head{justify-content:center;padding:14px 0 12px}.cad-nav-drawer__head cad-icon{color:var(--cad-accent);flex:none}.cad-nav-drawer__list{list-style:none;margin:0;padding:8px 0;flex:1;min-height:0;overflow-y:auto}.cad-nav-drawer__section{padding:12px 14px 5px;font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__rule{height:1px;margin:8px 12px;background:var(--cad-border)}.cad-nav-drawer__item{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;cursor:pointer;padding:8px 14px;min-height:38px;color:var(--cad-fg-secondary);font:12.5px var(--cad-font);text-decoration:none}:host(.is-rail) .cad-nav-drawer__item{justify-content:center;padding:10px 0}.cad-nav-drawer__item:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-nav-drawer__item:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__item.is-active{background:var(--cad-accent-soft);color:var(--cad-accent);font-weight:500;box-shadow:inset 3px 0 0 var(--cad-accent)}:host(.is-right) .cad-nav-drawer__item.is-active{box-shadow:inset -3px 0 0 var(--cad-accent)}.cad-nav-drawer__item.is-disabled,.cad-nav-drawer__item:disabled{opacity:.45;cursor:not-allowed}.cad-nav-drawer__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cad-nav-drawer__badge{flex:none;font-size:10.5px;font-family:var(--cad-font-mono);border-radius:var(--cad-radius-pill);padding:1px 7px;background:var(--cad-elevated, var(--cad-border));color:var(--cad-fg-secondary)}.cad-nav-drawer__item.is-active .cad-nav-drawer__badge{background:var(--cad-accent);color:var(--cad-fg-on-accent)}.cad-nav-drawer__dot{position:absolute;margin:-14px 0 0 14px;width:7px;height:7px;border-radius:50%;background:var(--cad-danger, #f85149)}.cad-nav-drawer__foot{flex:none;border-top:1px solid var(--cad-border);padding:10px 14px}.cad-nav-drawer__foot.is-empty{display:none}:host(.is-rail) .cad-nav-drawer__foot{padding:10px 0;display:flex;justify-content:center}:host-context(.cad-touch) .cad-nav-drawer__item{min-height:44px}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__panel{transition:none}}\n"] }]
|
|
9638
|
-
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], breakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "breakpoint", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], closeOnNavigate: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnNavigate", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], dismissableScrim: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissableScrim", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], changed: [{ type: i0.Output, args: ["changed"] }], headerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadNavDrawerHeaderDirective), { isSignal: true }] }], footerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadNavDrawerFooterDirective), { isSignal: true }] }], onEscape: [{
|
|
9770
|
+
`, styles: [":host{display:block}:host(.is-permanent){flex:none}.cad-nav-drawer__panel{display:flex;flex-direction:column;min-height:0;height:100%;width:var(--cad-nav-drawer-w, 240px);background:var(--cad-bg-subtle);border-right:1px solid var(--cad-border);transition:width var(--cad-dur) var(--cad-ease)}:host(.is-rail) .cad-nav-drawer__panel{width:var(--cad-nav-drawer-rail-w, 56px)}:host(.is-right) .cad-nav-drawer__panel{border-right:0;border-left:1px solid var(--cad-border)}:host(.is-temporary){position:fixed;inset:0 auto 0 0;z-index:var(--cad-z-overlay, 100002);pointer-events:none}:host(.is-temporary.is-right){inset:0 0 0 auto}:host(.is-temporary) .cad-nav-drawer__panel{pointer-events:auto;height:100%;box-shadow:var(--cad-shadow-lg, 0 12px 24px rgba(15,23,42,.18));transform:translate(-100%);transition:transform var(--cad-dur) var(--cad-ease);padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}:host(.is-temporary.is-right) .cad-nav-drawer__panel{transform:translate(100%)}:host(.is-temporary.is-open) .cad-nav-drawer__panel{transform:translate(0)}.cad-nav-drawer__scrim{position:fixed;inset:0;background:var(--cad-backdrop, rgba(2,6,23,.45));pointer-events:auto;z-index:-1}.cad-nav-drawer__head{display:flex;align-items:center;gap:9px;flex:none;padding:14px 14px 12px;border-bottom:1px solid var(--cad-border);min-height:48px;color:var(--cad-fg);font-size:13px}:host(.is-rail) .cad-nav-drawer__head{justify-content:center;padding:14px 0 12px}.cad-nav-drawer__head cad-icon{color:var(--cad-accent);flex:none}.cad-nav-drawer__list{list-style:none;margin:0;padding:8px 0;flex:1;min-height:0;overflow-y:auto}.cad-nav-drawer__section{padding:12px 14px 5px;font-size:10px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__rule{height:1px;margin:8px 12px;background:var(--cad-border)}.cad-nav-drawer__section.is-collapsible{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:8px;width:100%;cursor:pointer;padding:12px 14px 5px;font:500 10px var(--cad-font);letter-spacing:.07em;text-transform:uppercase;color:var(--cad-fg-muted)}.cad-nav-drawer__section.is-collapsible:hover{color:var(--cad-fg-secondary)}.cad-nav-drawer__section.is-collapsible:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__chev{flex:none;transition:transform var(--cad-dur) var(--cad-ease)}.cad-nav-drawer__section.is-collapsed .cad-nav-drawer__chev{transform:rotate(-90deg)}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__chev{transition:none}}.cad-nav-drawer__item{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:10px;width:100%;cursor:pointer;padding:8px 14px;min-height:38px;color:var(--cad-fg-secondary);font:12.5px var(--cad-font);text-decoration:none}:host(.is-rail) .cad-nav-drawer__item{justify-content:center;padding:10px 0}.cad-nav-drawer__item:hover{background:var(--cad-hover);color:var(--cad-fg)}.cad-nav-drawer__item:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.cad-nav-drawer__item.is-active{background:var(--cad-accent-soft);color:var(--cad-accent);font-weight:500;box-shadow:inset 3px 0 0 var(--cad-accent)}:host(.is-right) .cad-nav-drawer__item.is-active{box-shadow:inset -3px 0 0 var(--cad-accent)}.cad-nav-drawer__item.is-disabled,.cad-nav-drawer__item:disabled{opacity:.45;cursor:not-allowed}.cad-nav-drawer__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cad-nav-drawer__badge{flex:none;font-size:10.5px;font-family:var(--cad-font-mono);border-radius:var(--cad-radius-pill);padding:1px 7px;background:var(--cad-elevated, var(--cad-border));color:var(--cad-fg-secondary)}.cad-nav-drawer__item.is-active .cad-nav-drawer__badge{background:var(--cad-accent);color:var(--cad-fg-on-accent)}.cad-nav-drawer__dot{position:absolute;margin:-14px 0 0 14px;width:7px;height:7px;border-radius:50%;background:var(--cad-danger, #f85149)}.cad-nav-drawer__foot{flex:none;border-top:1px solid var(--cad-border);padding:10px 14px}.cad-nav-drawer__foot.is-empty{display:none}:host(.is-rail) .cad-nav-drawer__foot{padding:10px 0;display:flex;justify-content:center}:host-context(.cad-touch) .cad-nav-drawer__item{min-height:44px}@media(prefers-reduced-motion:reduce){.cad-nav-drawer__panel{transition:none}}\n"] }]
|
|
9771
|
+
}], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], breakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "breakpoint", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], closeOnNavigate: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnNavigate", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], dismissableScrim: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissableScrim", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], changed: [{ type: i0.Output, args: ["changed"] }], headerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadNavDrawerHeaderDirective), { isSignal: true }] }], footerSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadNavDrawerFooterDirective), { isSignal: true }] }], onEscape: [{
|
|
9639
9772
|
type: HostListener,
|
|
9640
9773
|
args: ['document:keydown.escape']
|
|
9641
9774
|
}] } });
|
|
@@ -12376,7 +12509,7 @@ class CadToastComponent {
|
|
|
12376
12509
|
}
|
|
12377
12510
|
</div>
|
|
12378
12511
|
}
|
|
12379
|
-
`, isInline: true, styles: [":host{position:fixed;display:flex;flex-direction:column;gap:8px;width:340px;max-width:calc(100% - 32px);pointer-events:none;font-family:var(--cad-font)}:host(.pos-top-right){top:
|
|
12512
|
+
`, isInline: true, styles: [":host{position:fixed;display:flex;flex-direction:column;gap:8px;width:340px;max-width:calc(100% - 32px);pointer-events:none;font-family:var(--cad-font)}:host{--_haut: calc(16px + max(var(--cad-shell-top, 0px), env(safe-area-inset-top, 0px))) ;--_bas: calc(16px + max(var(--cad-shell-bottom, 0px), env(safe-area-inset-bottom, 0px))) }:host(.pos-top-right){top:var(--_haut);right:16px}:host(.pos-top-left){top:var(--_haut);left:16px}:host(.pos-bottom-right){bottom:var(--_bas);right:16px;flex-direction:column-reverse}:host(.pos-bottom-left){bottom:var(--_bas);left:16px;flex-direction:column-reverse}:host(.pos-top-center){top:var(--_haut);left:50%;transform:translate(-50%)}:host(.pos-bottom-center){bottom:var(--_bas);left:50%;transform:translate(-50%);flex-direction:column-reverse}.cad-toast__item{--_c: var(--cad-accent);position:relative;overflow:hidden;pointer-events:auto;display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:var(--cad-overlay);--cad-hover: var(--cad-overlay-hover);border:1px solid var(--cad-border);border-left:3px solid var(--_c);box-shadow:var(--cad-shadow-lg);color:var(--cad-fg);animation:cad-toast-in .18s var(--cad-ease)}.cad-toast__item.is-out{animation:cad-toast-out .16s var(--cad-ease) forwards}:host(.pos-top-left) .cad-toast__item,:host(.pos-bottom-left) .cad-toast__item{animation-name:cad-toast-in-l}.cad-toast__item.sev-success{--_c: var(--cad-success)}.cad-toast__item.sev-info{--_c: var(--cad-info)}.cad-toast__item.sev-warning{--_c: var(--cad-warning)}.cad-toast__item.sev-danger{--_c: var(--cad-danger)}.cad-toast__item.sev-secondary{--_c: var(--cad-fg-muted)}.cad-toast__item.sev-contrast{--_c: var(--cad-fg);background:var(--cad-fg);color:var(--cad-bg)}.cad-toast__icon{color:var(--_c);margin-top:1px;flex:none}.cad-toast__text{display:grid;gap:2px;flex:1;min-width:0}.cad-toast__text b{font-weight:600;font-size:13px}.cad-toast__text span{color:var(--cad-fg-secondary);font-size:12.5px;line-height:1.4}.sev-contrast .cad-toast__text span{color:inherit;opacity:.8}.cad-toast__actions{display:flex;gap:4px;margin-top:4px;margin-left:-8px}.cad-toast__close{border:0;background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:2px;border-radius:4px;display:grid;place-items:center;flex:none;margin:-2px -4px 0 0}.cad-toast__close:hover{color:var(--cad-fg);background:var(--cad-hover)}.cad-toast__progress{position:absolute;left:0;bottom:0;height:2px;width:100%;background:var(--_c);opacity:.5;transform-origin:left;animation:cad-toast-life linear forwards}@keyframes cad-toast-in{0%{opacity:0;transform:translate(24px)}to{opacity:1;transform:none}}@keyframes cad-toast-in-l{0%{opacity:0;transform:translate(-24px)}to{opacity:1;transform:none}}@keyframes cad-toast-out{to{opacity:0;transform:scale(.96)}}@keyframes cad-toast-life{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media(prefers-reduced-motion:reduce){.cad-toast__item,.cad-toast__item.is-out{animation-duration:1ms}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CadIconComponent, selector: "cad-icon", inputs: ["name", "size", "strokeWidth", "label", "title", "spin", "filled", "flip", "rotate"] }, { kind: "component", type: CadButtonComponent, selector: "button[cadButton], a[cadButton]", inputs: ["severity", "variant", "size", "loading", "disabled", "icon", "block", "value", "pressed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12380
12513
|
}
|
|
12381
12514
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadToastComponent, decorators: [{
|
|
12382
12515
|
type: Component,
|
|
@@ -12409,7 +12542,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
12409
12542
|
}
|
|
12410
12543
|
</div>
|
|
12411
12544
|
}
|
|
12412
|
-
`, styles: [":host{position:fixed;display:flex;flex-direction:column;gap:8px;width:340px;max-width:calc(100% - 32px);pointer-events:none;font-family:var(--cad-font)}:host(.pos-top-right){top:
|
|
12545
|
+
`, styles: [":host{position:fixed;display:flex;flex-direction:column;gap:8px;width:340px;max-width:calc(100% - 32px);pointer-events:none;font-family:var(--cad-font)}:host{--_haut: calc(16px + max(var(--cad-shell-top, 0px), env(safe-area-inset-top, 0px))) ;--_bas: calc(16px + max(var(--cad-shell-bottom, 0px), env(safe-area-inset-bottom, 0px))) }:host(.pos-top-right){top:var(--_haut);right:16px}:host(.pos-top-left){top:var(--_haut);left:16px}:host(.pos-bottom-right){bottom:var(--_bas);right:16px;flex-direction:column-reverse}:host(.pos-bottom-left){bottom:var(--_bas);left:16px;flex-direction:column-reverse}:host(.pos-top-center){top:var(--_haut);left:50%;transform:translate(-50%)}:host(.pos-bottom-center){bottom:var(--_bas);left:50%;transform:translate(-50%);flex-direction:column-reverse}.cad-toast__item{--_c: var(--cad-accent);position:relative;overflow:hidden;pointer-events:auto;display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:var(--cad-overlay);--cad-hover: var(--cad-overlay-hover);border:1px solid var(--cad-border);border-left:3px solid var(--_c);box-shadow:var(--cad-shadow-lg);color:var(--cad-fg);animation:cad-toast-in .18s var(--cad-ease)}.cad-toast__item.is-out{animation:cad-toast-out .16s var(--cad-ease) forwards}:host(.pos-top-left) .cad-toast__item,:host(.pos-bottom-left) .cad-toast__item{animation-name:cad-toast-in-l}.cad-toast__item.sev-success{--_c: var(--cad-success)}.cad-toast__item.sev-info{--_c: var(--cad-info)}.cad-toast__item.sev-warning{--_c: var(--cad-warning)}.cad-toast__item.sev-danger{--_c: var(--cad-danger)}.cad-toast__item.sev-secondary{--_c: var(--cad-fg-muted)}.cad-toast__item.sev-contrast{--_c: var(--cad-fg);background:var(--cad-fg);color:var(--cad-bg)}.cad-toast__icon{color:var(--_c);margin-top:1px;flex:none}.cad-toast__text{display:grid;gap:2px;flex:1;min-width:0}.cad-toast__text b{font-weight:600;font-size:13px}.cad-toast__text span{color:var(--cad-fg-secondary);font-size:12.5px;line-height:1.4}.sev-contrast .cad-toast__text span{color:inherit;opacity:.8}.cad-toast__actions{display:flex;gap:4px;margin-top:4px;margin-left:-8px}.cad-toast__close{border:0;background:transparent;color:var(--cad-fg-muted);cursor:pointer;padding:2px;border-radius:4px;display:grid;place-items:center;flex:none;margin:-2px -4px 0 0}.cad-toast__close:hover{color:var(--cad-fg);background:var(--cad-hover)}.cad-toast__progress{position:absolute;left:0;bottom:0;height:2px;width:100%;background:var(--_c);opacity:.5;transform-origin:left;animation:cad-toast-life linear forwards}@keyframes cad-toast-in{0%{opacity:0;transform:translate(24px)}to{opacity:1;transform:none}}@keyframes cad-toast-in-l{0%{opacity:0;transform:translate(-24px)}to{opacity:1;transform:none}}@keyframes cad-toast-out{to{opacity:0;transform:scale(.96)}}@keyframes cad-toast-life{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media(prefers-reduced-motion:reduce){.cad-toast__item,.cad-toast__item.is-out{animation-duration:1ms}}\n"] }]
|
|
12413
12546
|
}], ctorParameters: () => [], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }], life: [{ type: i0.Input, args: [{ isSignal: true, alias: "life", required: false }] }], maxVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisible", required: false }] }], preventDuplicates: [{ type: i0.Input, args: [{ isSignal: true, alias: "preventDuplicates", required: false }] }], showProgress: [{ type: i0.Input, args: [{ isSignal: true, alias: "showProgress", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], clicked: [{ type: i0.Output, args: ["clicked"] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadToastItemDirective), { isSignal: true }] }] } });
|
|
12414
12547
|
|
|
12415
12548
|
/**
|
|
@@ -18818,6 +18951,7 @@ function cadNormalizePlan(plan, options = {}) {
|
|
|
18818
18951
|
start,
|
|
18819
18952
|
end,
|
|
18820
18953
|
milestone,
|
|
18954
|
+
allDay: !!t.allDay,
|
|
18821
18955
|
bucket: t.bucket ?? null,
|
|
18822
18956
|
rank: cadIsRank(t.rank) ? t.rank : '',
|
|
18823
18957
|
assignments,
|
|
@@ -19017,6 +19151,552 @@ function cadFindLinkCycle(links) {
|
|
|
19017
19151
|
/** Tâches qu'aucune vue temporelle ne sait placer — la zone « non planifié », jamais le silence. */
|
|
19018
19152
|
const cadUnscheduled = (plan) => plan.tasks.filter(t => !t.scheduled);
|
|
19019
19153
|
|
|
19154
|
+
/**
|
|
19155
|
+
* Dépliage des séries récurrentes — EN LECTURE SEULE.
|
|
19156
|
+
*
|
|
19157
|
+
* CE QUE CE FICHIER FAIT, ET CE QU'IL NE FAIT PAS. Il projette une règle en occurrences pour
|
|
19158
|
+
* qu'une vue puisse les afficher. Il n'écrit rien, ne modifie aucune série, et ne connaît pas
|
|
19159
|
+
* la sémantique d'édition à trois branches (« cette occurrence / celle-ci et les suivantes /
|
|
19160
|
+
* toutes »), qui reste entière dans son propre lot.
|
|
19161
|
+
*
|
|
19162
|
+
* C'est un choix, pas un raccourci : une récurrence à moitié faite PERD DES MODIFICATIONS SANS
|
|
19163
|
+
* LE DIRE, ce qui est pire que pas de récurrence. Déplier pour afficher n'écrit rien, donc ne
|
|
19164
|
+
* peut rien perdre. On livre donc la moitié qui est sûre.
|
|
19165
|
+
*
|
|
19166
|
+
* SOUS-ENSEMBLE RRULE ASSUMÉ (RFC 5545) : `FREQ` (DAILY, WEEKLY, MONTHLY, YEARLY), `INTERVAL`,
|
|
19167
|
+
* `BYDAY` (en hebdomadaire), `BYMONTHDAY` (en mensuel), `COUNT`, `UNTIL`.
|
|
19168
|
+
* EXCLUS ET DOCUMENTÉS : `BYSETPOS` composé, `BYYEARDAY`, `BYWEEKNO`, `VTIMEZONE`, et les
|
|
19169
|
+
* préfixes ordinaux de `BYDAY` (`2MO` = deuxième lundi). Une règle qui en contient est rendue
|
|
19170
|
+
* telle qu'elle peut l'être, et l'anomalie est signalée — jamais silencieusement approximée.
|
|
19171
|
+
*/
|
|
19172
|
+
/** Jours iCalendar, dans l'ordre de `Date.getDay()` : 0 = dimanche. */
|
|
19173
|
+
const JOURS_ICAL = { SU: 0, MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6 };
|
|
19174
|
+
/** Parties que ce moteur sait lire. Tout le reste atterrit dans `ignore`. */
|
|
19175
|
+
const CONNUES = new Set(['FREQ', 'INTERVAL', 'BYDAY', 'BYMONTHDAY', 'COUNT', 'UNTIL', 'WKST']);
|
|
19176
|
+
/**
|
|
19177
|
+
* Analyse une chaîne `RRULE`. Rend `null` si elle est inexploitable — jamais une règle
|
|
19178
|
+
* approximative : mieux vaut un événement unique qu'une série fausse.
|
|
19179
|
+
*/
|
|
19180
|
+
function cadParseRRule(entree) {
|
|
19181
|
+
if (!entree)
|
|
19182
|
+
return null;
|
|
19183
|
+
const brut = entree.replace(/^RRULE:/i, '').trim();
|
|
19184
|
+
if (!brut)
|
|
19185
|
+
return null;
|
|
19186
|
+
const parts = new Map();
|
|
19187
|
+
const ignore = [];
|
|
19188
|
+
for (const morceau of brut.split(';')) {
|
|
19189
|
+
const i = morceau.indexOf('=');
|
|
19190
|
+
if (i < 0)
|
|
19191
|
+
continue;
|
|
19192
|
+
const cle = morceau.slice(0, i).trim().toUpperCase();
|
|
19193
|
+
const val = morceau.slice(i + 1).trim();
|
|
19194
|
+
if (!CONNUES.has(cle)) {
|
|
19195
|
+
ignore.push(cle);
|
|
19196
|
+
continue;
|
|
19197
|
+
}
|
|
19198
|
+
parts.set(cle, val);
|
|
19199
|
+
}
|
|
19200
|
+
const freq = (parts.get('FREQ') || '').toUpperCase();
|
|
19201
|
+
if (freq !== 'DAILY' && freq !== 'WEEKLY' && freq !== 'MONTHLY' && freq !== 'YEARLY')
|
|
19202
|
+
return null;
|
|
19203
|
+
const interval = Math.max(1, Number(parts.get('INTERVAL') || 1) || 1);
|
|
19204
|
+
let byday = null;
|
|
19205
|
+
const bydayBrut = parts.get('BYDAY');
|
|
19206
|
+
if (bydayBrut) {
|
|
19207
|
+
const jours = [];
|
|
19208
|
+
for (const j of bydayBrut.split(',')) {
|
|
19209
|
+
const net = j.trim().toUpperCase();
|
|
19210
|
+
// « 2MO » (deuxième lundi) n'est pas géré : on le signale plutôt que de le lire « MO ».
|
|
19211
|
+
if (/^[+-]?\d/.test(net)) {
|
|
19212
|
+
ignore.push('BYDAY:' + net);
|
|
19213
|
+
continue;
|
|
19214
|
+
}
|
|
19215
|
+
const n = JOURS_ICAL[net];
|
|
19216
|
+
if (n !== undefined)
|
|
19217
|
+
jours.push(n);
|
|
19218
|
+
}
|
|
19219
|
+
byday = jours.length ? jours.sort((a, b) => a - b) : null;
|
|
19220
|
+
}
|
|
19221
|
+
let bymonthday = null;
|
|
19222
|
+
const bmdBrut = parts.get('BYMONTHDAY');
|
|
19223
|
+
if (bmdBrut) {
|
|
19224
|
+
const q = bmdBrut.split(',').map((x) => Number(x.trim())).filter((x) => Number.isInteger(x) && x >= 1 && x <= 31);
|
|
19225
|
+
bymonthday = q.length ? q : null;
|
|
19226
|
+
}
|
|
19227
|
+
const count = parts.has('COUNT') ? Math.max(0, Number(parts.get('COUNT')) || 0) : null;
|
|
19228
|
+
const until = parts.has('UNTIL') ? cadParseUntil(parts.get('UNTIL')) : null;
|
|
19229
|
+
return { freq, interval, byday, bymonthday, count, until, ignore };
|
|
19230
|
+
}
|
|
19231
|
+
/** `UNTIL` en forme iCalendar (`20260930T235959Z`) ou en ISO. */
|
|
19232
|
+
function cadParseUntil(v) {
|
|
19233
|
+
const m = /^(\d{4})(\d{2})(\d{2})(?:T(\d{2})(\d{2})(\d{2})Z?)?$/.exec(v.trim());
|
|
19234
|
+
if (m) {
|
|
19235
|
+
const d = new Date(+m[1], +m[2] - 1, +m[3], +(m[4] ?? 23), +(m[5] ?? 59), +(m[6] ?? 59));
|
|
19236
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
19237
|
+
}
|
|
19238
|
+
const d = new Date(v);
|
|
19239
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
19240
|
+
}
|
|
19241
|
+
/** Garde-fou : une règle mal formée ne doit pas produire une boucle infinie mais un message. */
|
|
19242
|
+
const PLAFOND = 750;
|
|
19243
|
+
const JOUR_MS = 86_400_000;
|
|
19244
|
+
function memeJour(a, b) {
|
|
19245
|
+
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
|
|
19246
|
+
}
|
|
19247
|
+
function cle(d) {
|
|
19248
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
19249
|
+
}
|
|
19250
|
+
function horodatage(d, allDay) {
|
|
19251
|
+
return allDay ? cle(d) : `${cle(d)}T${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
|
|
19252
|
+
}
|
|
19253
|
+
function avance(d, jours) {
|
|
19254
|
+
const n = new Date(d);
|
|
19255
|
+
n.setDate(n.getDate() + jours);
|
|
19256
|
+
return n;
|
|
19257
|
+
}
|
|
19258
|
+
/**
|
|
19259
|
+
* Déplie les tâches sur la fenêtre `[du, au]`.
|
|
19260
|
+
*
|
|
19261
|
+
* TROIS RÈGLES, dans cet ordre :
|
|
19262
|
+
* ① une tâche sans règle donne une occurrence unique, si elle croise la fenêtre ;
|
|
19263
|
+
* ② une tâche avec règle est projetée, `exdates` retirées ;
|
|
19264
|
+
* ③ une occurrence MODIFIÉE (`masterId` + `recurrenceId`) REMPLACE celle que la règle aurait
|
|
19265
|
+
* produite à cette date — convention iCalendar. Sans ce remplacement on afficherait les
|
|
19266
|
+
* deux, et l'utilisateur verrait sa modification en double au lieu de la voir appliquée.
|
|
19267
|
+
*/
|
|
19268
|
+
function cadExpandOccurrences(taches, du, au) {
|
|
19269
|
+
const occurrences = [];
|
|
19270
|
+
const issues = [];
|
|
19271
|
+
// ③ d'abord : on répertorie les exceptions pour savoir quoi remplacer.
|
|
19272
|
+
const exceptions = new Map();
|
|
19273
|
+
for (const t of taches) {
|
|
19274
|
+
if (t.masterId && t.recurrenceId)
|
|
19275
|
+
exceptions.set(`${t.masterId}@${cle(t.recurrenceId)}`, t);
|
|
19276
|
+
}
|
|
19277
|
+
for (const t of taches) {
|
|
19278
|
+
// Une exception est rendue par la série qu'elle corrige, pas deux fois.
|
|
19279
|
+
if (t.masterId && t.recurrenceId)
|
|
19280
|
+
continue;
|
|
19281
|
+
if (!t.start) {
|
|
19282
|
+
if (t.rrule)
|
|
19283
|
+
issues.push({ taskId: t.id, code: 'sans-date' });
|
|
19284
|
+
continue;
|
|
19285
|
+
}
|
|
19286
|
+
const duree = t.end ? Math.max(0, t.end.getTime() - t.start.getTime()) : 0;
|
|
19287
|
+
if (!t.rrule) {
|
|
19288
|
+
if (croise(t.start, t.end ?? t.start, du, au)) {
|
|
19289
|
+
occurrences.push(fabrique(t, t.start, duree, false, false));
|
|
19290
|
+
}
|
|
19291
|
+
continue;
|
|
19292
|
+
}
|
|
19293
|
+
const regle = cadParseRRule(t.rrule);
|
|
19294
|
+
if (!regle) {
|
|
19295
|
+
issues.push({ taskId: t.id, code: 'rrule-illisible', detail: t.rrule });
|
|
19296
|
+
// Une règle illisible ne fait pas disparaître l'événement : il reste, seul.
|
|
19297
|
+
if (croise(t.start, t.end ?? t.start, du, au))
|
|
19298
|
+
occurrences.push(fabrique(t, t.start, duree, false, false));
|
|
19299
|
+
continue;
|
|
19300
|
+
}
|
|
19301
|
+
if (regle.ignore.length) {
|
|
19302
|
+
issues.push({ taskId: t.id, code: 'rrule-partielle', detail: regle.ignore.join(', ') });
|
|
19303
|
+
}
|
|
19304
|
+
const exclues = new Set(t.exdates.map((x) => cle(new Date(x))));
|
|
19305
|
+
let rendues = 0;
|
|
19306
|
+
let tours = 0;
|
|
19307
|
+
let curseur = new Date(t.start);
|
|
19308
|
+
while (tours++ < PLAFOND) {
|
|
19309
|
+
if (regle.count !== null && rendues >= regle.count)
|
|
19310
|
+
break;
|
|
19311
|
+
if (curseur.getTime() > au.getTime())
|
|
19312
|
+
break;
|
|
19313
|
+
if (regle.until && curseur.getTime() > regle.until.getTime())
|
|
19314
|
+
break;
|
|
19315
|
+
for (const debut of datesDuTour(curseur, regle, t.start)) {
|
|
19316
|
+
if (regle.count !== null && rendues >= regle.count)
|
|
19317
|
+
break;
|
|
19318
|
+
if (debut.getTime() < t.start.getTime())
|
|
19319
|
+
continue;
|
|
19320
|
+
if (regle.until && debut.getTime() > regle.until.getTime())
|
|
19321
|
+
break;
|
|
19322
|
+
rendues++;
|
|
19323
|
+
if (exclues.has(cle(debut)))
|
|
19324
|
+
continue;
|
|
19325
|
+
if (debut.getTime() > au.getTime())
|
|
19326
|
+
continue;
|
|
19327
|
+
const remplacement = exceptions.get(`${t.id}@${cle(debut)}`);
|
|
19328
|
+
if (remplacement) {
|
|
19329
|
+
if (remplacement.start && croise(remplacement.start, remplacement.end ?? remplacement.start, du, au)) {
|
|
19330
|
+
const d2 = remplacement.end ? remplacement.end.getTime() - remplacement.start.getTime() : duree;
|
|
19331
|
+
occurrences.push(fabrique(remplacement, remplacement.start, d2, true, true));
|
|
19332
|
+
}
|
|
19333
|
+
continue;
|
|
19334
|
+
}
|
|
19335
|
+
const fin = new Date(debut.getTime() + duree);
|
|
19336
|
+
if (croise(debut, fin, du, au))
|
|
19337
|
+
occurrences.push(fabrique(t, debut, duree, true, false));
|
|
19338
|
+
}
|
|
19339
|
+
curseur = tourSuivant(curseur, regle);
|
|
19340
|
+
}
|
|
19341
|
+
if (tours >= PLAFOND)
|
|
19342
|
+
issues.push({ taskId: t.id, code: 'plafond-atteint', detail: String(PLAFOND) });
|
|
19343
|
+
}
|
|
19344
|
+
occurrences.sort((a, b) => a.start.getTime() - b.start.getTime() || a.id.localeCompare(b.id));
|
|
19345
|
+
return { occurrences, issues };
|
|
19346
|
+
}
|
|
19347
|
+
function croise(debut, fin, du, au) {
|
|
19348
|
+
return fin.getTime() >= du.getTime() && debut.getTime() <= au.getTime();
|
|
19349
|
+
}
|
|
19350
|
+
function fabrique(t, debut, duree, recurring, overridden) {
|
|
19351
|
+
const start = new Date(debut);
|
|
19352
|
+
const end = new Date(debut.getTime() + duree);
|
|
19353
|
+
return {
|
|
19354
|
+
id: `${t.masterId ?? t.id}@${horodatage(start, t.allDay)}`,
|
|
19355
|
+
taskId: t.id,
|
|
19356
|
+
start,
|
|
19357
|
+
end,
|
|
19358
|
+
allDay: t.allDay,
|
|
19359
|
+
recurring,
|
|
19360
|
+
overridden,
|
|
19361
|
+
task: t,
|
|
19362
|
+
};
|
|
19363
|
+
}
|
|
19364
|
+
/** Les dates produites par UN tour de la règle (une semaine, un mois, un jour…). */
|
|
19365
|
+
function datesDuTour(curseur, r, ancre) {
|
|
19366
|
+
const h = ancre.getHours(), m = ancre.getMinutes();
|
|
19367
|
+
const pose = (d) => { const n = new Date(d); n.setHours(h, m, 0, 0); return n; };
|
|
19368
|
+
if (r.freq === 'WEEKLY' && r.byday) {
|
|
19369
|
+
// Le curseur est posé sur le début de semaine du tour ; on émet les jours visés.
|
|
19370
|
+
const lundi = debutSemaine(curseur);
|
|
19371
|
+
return r.byday.map((j) => pose(avance(lundi, (j + 6) % 7)));
|
|
19372
|
+
}
|
|
19373
|
+
if (r.freq === 'MONTHLY' && r.bymonthday) {
|
|
19374
|
+
return r.bymonthday
|
|
19375
|
+
.map((q) => {
|
|
19376
|
+
const d = new Date(curseur.getFullYear(), curseur.getMonth(), q);
|
|
19377
|
+
// Le 31 d'un mois de 30 jours n'existe pas : on ne le décale pas en douce, on le saute.
|
|
19378
|
+
return d.getMonth() === curseur.getMonth() ? pose(d) : null;
|
|
19379
|
+
})
|
|
19380
|
+
.filter((d) => d !== null)
|
|
19381
|
+
.sort((a, b) => a.getTime() - b.getTime());
|
|
19382
|
+
}
|
|
19383
|
+
return [pose(curseur)];
|
|
19384
|
+
}
|
|
19385
|
+
function tourSuivant(curseur, r) {
|
|
19386
|
+
const n = new Date(curseur);
|
|
19387
|
+
if (r.freq === 'DAILY')
|
|
19388
|
+
n.setDate(n.getDate() + r.interval);
|
|
19389
|
+
else if (r.freq === 'WEEKLY')
|
|
19390
|
+
n.setDate(n.getDate() + 7 * r.interval);
|
|
19391
|
+
else if (r.freq === 'MONTHLY') {
|
|
19392
|
+
// On repart du 1er : sans ça, un 31 janvier + 1 mois donne le 3 mars et la série dérive
|
|
19393
|
+
// de mois en mois. Le quantième visé est réappliqué par datesDuTour.
|
|
19394
|
+
const j = r.bymonthday ? 1 : n.getDate();
|
|
19395
|
+
n.setDate(1);
|
|
19396
|
+
n.setMonth(n.getMonth() + r.interval);
|
|
19397
|
+
if (!r.bymonthday)
|
|
19398
|
+
n.setDate(Math.min(j, joursDansMois(n.getFullYear(), n.getMonth())));
|
|
19399
|
+
}
|
|
19400
|
+
else {
|
|
19401
|
+
n.setFullYear(n.getFullYear() + r.interval);
|
|
19402
|
+
}
|
|
19403
|
+
return n;
|
|
19404
|
+
}
|
|
19405
|
+
function joursDansMois(annee, mois) {
|
|
19406
|
+
return new Date(annee, mois + 1, 0).getDate();
|
|
19407
|
+
}
|
|
19408
|
+
/** Lundi de la semaine de `d`. */
|
|
19409
|
+
function debutSemaine(d) {
|
|
19410
|
+
const n = new Date(d);
|
|
19411
|
+
n.setHours(0, 0, 0, 0);
|
|
19412
|
+
n.setDate(n.getDate() - ((n.getDay() + 6) % 7));
|
|
19413
|
+
return n;
|
|
19414
|
+
}
|
|
19415
|
+
const CAD_RECURRENCE_INTERNE = { debutSemaine, joursDansMois, memeJour, JOUR_MS };
|
|
19416
|
+
|
|
19417
|
+
/**
|
|
19418
|
+
* Mise en page d'un calendrier — logique PURE, sans DOM, donc testable seule.
|
|
19419
|
+
*
|
|
19420
|
+
* Trois calculs, et ce sont les trois endroits où un calendrier se trompe :
|
|
19421
|
+
* ① la grille du mois (combien de rangées, quels jours débordent) ;
|
|
19422
|
+
* ② les BANDEAUX multi-jours, continus à travers une rangée de semaine ;
|
|
19423
|
+
* ③ le placement côte à côte des événements horodatés d'une journée.
|
|
19424
|
+
*
|
|
19425
|
+
* BORNE DE FIN : dans cette bibliothèque, `end` est INCLUSIVE pour un événement journée
|
|
19426
|
+
* entière — « congés du 21 au 25 » couvre le 25. La RFC 5545 la veut exclusive (DTEND au 26).
|
|
19427
|
+
* On diverge SCIEMMENT : c'est ce qu'un humain saisit, c'est ce que font déjà le gantt et le
|
|
19428
|
+
* scheduler pour une tâche qui « finit le 25 », et mélanger les deux conventions en silence
|
|
19429
|
+
* est la première cause d'erreur d'un jour dans un calendrier. Un import iCalendar devra donc
|
|
19430
|
+
* retrancher un jour à DTEND — c'est le travail de l'import, pas celui de la vue.
|
|
19431
|
+
*/
|
|
19432
|
+
/** Numéro de jour absolu, insensible au fuseau et à l'heure d'été. */
|
|
19433
|
+
function cadNumeroJour(d) {
|
|
19434
|
+
return Math.round(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) / 86_400_000);
|
|
19435
|
+
}
|
|
19436
|
+
/** Minuit local du jour de `d`. */
|
|
19437
|
+
function cadMinuit(d) {
|
|
19438
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
|
|
19439
|
+
}
|
|
19440
|
+
/** Début de la semaine contenant `d`. `premierJour` : 1 = lundi (défaut), 0 = dimanche. */
|
|
19441
|
+
function cadDebutSemaine(d, premierJour = 1) {
|
|
19442
|
+
const n = cadMinuit(d);
|
|
19443
|
+
const decalage = (n.getDay() - premierJour + 7) % 7;
|
|
19444
|
+
n.setDate(n.getDate() - decalage);
|
|
19445
|
+
return n;
|
|
19446
|
+
}
|
|
19447
|
+
/**
|
|
19448
|
+
* Grille du mois contenant `ancre`.
|
|
19449
|
+
*
|
|
19450
|
+
* On rend 5 OU 6 rangées, selon ce que le mois demande — jamais un nombre fixe. Forcer 6
|
|
19451
|
+
* rangées laisse une semaine entière vide neuf mois sur douze ; en forcer 5 tronque les mois
|
|
19452
|
+
* de 31 jours qui commencent un samedi. La hauteur de la vue s'adapte, pas la vérité.
|
|
19453
|
+
*/
|
|
19454
|
+
function cadMonthGrid(ancre, premierJour = 1) {
|
|
19455
|
+
const annee = ancre.getFullYear();
|
|
19456
|
+
const mois = ancre.getMonth();
|
|
19457
|
+
const premier = new Date(annee, mois, 1);
|
|
19458
|
+
const debut = cadDebutSemaine(premier, premierJour);
|
|
19459
|
+
const dernier = new Date(annee, mois + 1, 0);
|
|
19460
|
+
const finGrille = cadDebutSemaine(dernier, premierJour);
|
|
19461
|
+
const rangees = Math.round((cadNumeroJour(finGrille) - cadNumeroJour(debut)) / 7) + 1;
|
|
19462
|
+
const semaines = [];
|
|
19463
|
+
for (let r = 0; r < rangees; r++) {
|
|
19464
|
+
const semaine = [];
|
|
19465
|
+
for (let j = 0; j < 7; j++) {
|
|
19466
|
+
const d = new Date(debut);
|
|
19467
|
+
d.setDate(d.getDate() + r * 7 + j);
|
|
19468
|
+
semaine.push(d);
|
|
19469
|
+
}
|
|
19470
|
+
semaines.push(semaine);
|
|
19471
|
+
}
|
|
19472
|
+
return { debut, semaines, mois, annee };
|
|
19473
|
+
}
|
|
19474
|
+
/** Une occurrence va au bandeau si elle est journée entière OU si elle franchit un minuit. */
|
|
19475
|
+
function cadEstBandeau(o) {
|
|
19476
|
+
return o.allDay || cadNumeroJour(o.start) !== cadNumeroJour(o.end);
|
|
19477
|
+
}
|
|
19478
|
+
/**
|
|
19479
|
+
* Range les bandeaux d'une rangée de semaine en voies.
|
|
19480
|
+
*
|
|
19481
|
+
* Le tri place les plus LONGS en haut : sans lui, un événement d'un jour posé en voie 0 coupe
|
|
19482
|
+
* en deux la place d'un événement de cinq jours, qui doit alors descendre — et la rangée
|
|
19483
|
+
* devient un escalier illisible.
|
|
19484
|
+
*/
|
|
19485
|
+
function cadWeekBands(occurrences, jours) {
|
|
19486
|
+
if (!jours.length)
|
|
19487
|
+
return { bandes: [], voies: 0 };
|
|
19488
|
+
const j0 = cadNumeroJour(jours[0]);
|
|
19489
|
+
const j1 = cadNumeroJour(jours[jours.length - 1]);
|
|
19490
|
+
const candidats = occurrences
|
|
19491
|
+
.filter(cadEstBandeau)
|
|
19492
|
+
.map((o) => {
|
|
19493
|
+
const d = cadNumeroJour(o.start);
|
|
19494
|
+
const f = cadNumeroJour(o.end);
|
|
19495
|
+
return { o, d, f };
|
|
19496
|
+
})
|
|
19497
|
+
.filter(({ d, f }) => f >= j0 && d <= j1)
|
|
19498
|
+
.sort((a, b) => (b.f - b.d) - (a.f - a.d) || a.d - b.d || a.o.id.localeCompare(b.o.id));
|
|
19499
|
+
const occupe = [];
|
|
19500
|
+
const bandes = candidats.map(({ o, d, f }) => {
|
|
19501
|
+
const colDebut = Math.max(0, d - j0);
|
|
19502
|
+
const colFin = Math.min(jours.length - 1, f - j0);
|
|
19503
|
+
let voie = 0;
|
|
19504
|
+
while (occupe[voie]?.some(([a, b]) => !(b < colDebut || a > colFin)))
|
|
19505
|
+
voie++;
|
|
19506
|
+
(occupe[voie] ??= []).push([colDebut, colFin]);
|
|
19507
|
+
return { occurrence: o, colDebut, colFin, voie, continueAvant: d < j0, continueApres: f > j1 };
|
|
19508
|
+
});
|
|
19509
|
+
return { bandes, voies: occupe.length };
|
|
19510
|
+
}
|
|
19511
|
+
/**
|
|
19512
|
+
* Place les événements horodatés d'une journée, côte à côte quand ils se chevauchent.
|
|
19513
|
+
*
|
|
19514
|
+
* Le nombre de voies est celui du GROUPE de chevauchement, pas de la journée : deux réunions
|
|
19515
|
+
* qui se chevauchent le matin ne doivent pas rétrécir de moitié une réunion isolée de
|
|
19516
|
+
* l'après-midi. C'est l'erreur la plus courante des calendriers faits à la main.
|
|
19517
|
+
*
|
|
19518
|
+
* `plageDebut` / `plageFin` en minutes depuis minuit. Un événement hors plage est CONSERVÉ et
|
|
19519
|
+
* ramené au bord : le faire disparaître serait le mensonge le plus grave qu'une vue puisse
|
|
19520
|
+
* commettre.
|
|
19521
|
+
*/
|
|
19522
|
+
function cadPackDay(occurrences, plageDebut = 7 * 60, plageFin = 20 * 60) {
|
|
19523
|
+
const plage = Math.max(1, plageFin - plageDebut);
|
|
19524
|
+
const items = occurrences
|
|
19525
|
+
.filter((o) => !cadEstBandeau(o))
|
|
19526
|
+
.map((o) => {
|
|
19527
|
+
const d = o.start.getHours() * 60 + o.start.getMinutes();
|
|
19528
|
+
const f = Math.max(d + 15, o.end.getHours() * 60 + o.end.getMinutes());
|
|
19529
|
+
return { o, d, f };
|
|
19530
|
+
})
|
|
19531
|
+
.sort((a, b) => a.d - b.d || b.f - a.f);
|
|
19532
|
+
// ① voies par balayage, première voie libre.
|
|
19533
|
+
const finVoie = [];
|
|
19534
|
+
const places = items.map((it) => {
|
|
19535
|
+
let voie = finVoie.findIndex((fin) => fin <= it.d);
|
|
19536
|
+
if (voie === -1) {
|
|
19537
|
+
voie = finVoie.length;
|
|
19538
|
+
finVoie.push(it.f);
|
|
19539
|
+
}
|
|
19540
|
+
else
|
|
19541
|
+
finVoie[voie] = it.f;
|
|
19542
|
+
return { ...it, voie };
|
|
19543
|
+
});
|
|
19544
|
+
// ② groupes de chevauchement : on ne partage la largeur qu'entre voisins réels.
|
|
19545
|
+
const slots = [];
|
|
19546
|
+
let i = 0;
|
|
19547
|
+
while (i < places.length) {
|
|
19548
|
+
let j = i + 1;
|
|
19549
|
+
let finGroupe = places[i].f;
|
|
19550
|
+
while (j < places.length && places[j].d < finGroupe) {
|
|
19551
|
+
finGroupe = Math.max(finGroupe, places[j].f);
|
|
19552
|
+
j++;
|
|
19553
|
+
}
|
|
19554
|
+
const groupe = places.slice(i, j);
|
|
19555
|
+
const voies = Math.max(...groupe.map((g) => g.voie)) + 1;
|
|
19556
|
+
for (const g of groupe) {
|
|
19557
|
+
const haut = (Math.max(g.d, plageDebut) - plageDebut) / plage;
|
|
19558
|
+
const bas = (Math.min(g.f, plageFin) - plageDebut) / plage;
|
|
19559
|
+
slots.push({
|
|
19560
|
+
occurrence: g.o,
|
|
19561
|
+
haut: Math.max(0, Math.min(1, haut)),
|
|
19562
|
+
hauteur: Math.max(0.01, Math.min(1, bas) - Math.max(0, haut)),
|
|
19563
|
+
voie: g.voie,
|
|
19564
|
+
voies,
|
|
19565
|
+
});
|
|
19566
|
+
}
|
|
19567
|
+
i = j;
|
|
19568
|
+
}
|
|
19569
|
+
return slots;
|
|
19570
|
+
}
|
|
19571
|
+
|
|
19572
|
+
/**
|
|
19573
|
+
* Projection d'un geste d'édition — logique PURE, sans DOM, donc testable seule.
|
|
19574
|
+
*
|
|
19575
|
+
* Un geste ne produit jamais une écriture : il produit une PROPOSITION de bornes, que le
|
|
19576
|
+
* composant émet en intention. C'est ce fichier qui répond à « l'utilisateur a bougé de 43
|
|
19577
|
+
* pixels vers le bas et de 1,2 colonne : qu'est-ce que ça veut dire en dates ? ».
|
|
19578
|
+
*
|
|
19579
|
+
* L'AIMANTAGE EST OBLIGATOIRE, pas cosmétique. Sans lui on crée des réunions de 9 h 07 à
|
|
19580
|
+
* 10 h 23 : personne n'a voulu ça, et la donnée devient impossible à relire.
|
|
19581
|
+
*/
|
|
19582
|
+
const MIN = 60_000;
|
|
19583
|
+
function aimante(minutes, pas) {
|
|
19584
|
+
return Math.round(minutes / Math.max(1, pas)) * Math.max(1, pas);
|
|
19585
|
+
}
|
|
19586
|
+
function minutesDansJour(d) {
|
|
19587
|
+
return d.getHours() * 60 + d.getMinutes();
|
|
19588
|
+
}
|
|
19589
|
+
function poseMinutes(jour, minutes) {
|
|
19590
|
+
const n = new Date(jour.getFullYear(), jour.getMonth(), jour.getDate());
|
|
19591
|
+
n.setMinutes(minutes);
|
|
19592
|
+
return n;
|
|
19593
|
+
}
|
|
19594
|
+
function decaleJours(d, jours) {
|
|
19595
|
+
const n = new Date(d);
|
|
19596
|
+
n.setDate(n.getDate() + jours);
|
|
19597
|
+
return n;
|
|
19598
|
+
}
|
|
19599
|
+
/**
|
|
19600
|
+
* Projette un geste en nouvelles bornes.
|
|
19601
|
+
*
|
|
19602
|
+
* `dx` / `dy` sont les déplacements du pointeur en pixels depuis le début du geste.
|
|
19603
|
+
*
|
|
19604
|
+
* TROIS INVARIANTS, et chacun corrige une bêtise classique :
|
|
19605
|
+
* ① un déplacement CONSERVE la durée — sinon déplacer une réunion la rallonge en douce ;
|
|
19606
|
+
* ② un redimensionnement ne franchit JAMAIS l'autre bord : il s'arrête à un pas ;
|
|
19607
|
+
* ③ un événement journée entière ne bouge qu'en JOURS — lui donner une heure en le glissant
|
|
19608
|
+
* le ferait sortir du bandeau, ce que personne n'a demandé.
|
|
19609
|
+
*/
|
|
19610
|
+
function cadProjeterEdition(kind, base, dx, dy, g) {
|
|
19611
|
+
const jours = g.largeurJour > 0 ? Math.round(dx / g.largeurJour) : 0;
|
|
19612
|
+
const minutesBrutes = g.hauteurHeure > 0 ? (dy / g.hauteurHeure) * 60 : 0;
|
|
19613
|
+
const dMin = aimante(minutesBrutes, g.pas);
|
|
19614
|
+
// ③ journée entière : seuls les jours comptent.
|
|
19615
|
+
if (base.allDay) {
|
|
19616
|
+
if (kind === 'move')
|
|
19617
|
+
return { start: decaleJours(base.start, jours), end: decaleJours(base.end, jours) };
|
|
19618
|
+
if (kind === 'resize-start') {
|
|
19619
|
+
const s = decaleJours(base.start, jours);
|
|
19620
|
+
return { start: s > base.end ? base.end : s, end: base.end };
|
|
19621
|
+
}
|
|
19622
|
+
if (kind === 'resize-end') {
|
|
19623
|
+
const e = decaleJours(base.end, jours);
|
|
19624
|
+
return { start: base.start, end: e < base.start ? base.start : e };
|
|
19625
|
+
}
|
|
19626
|
+
return { start: base.start, end: base.end };
|
|
19627
|
+
}
|
|
19628
|
+
const duree = Math.max(g.pas, Math.round((base.end.getTime() - base.start.getTime()) / MIN));
|
|
19629
|
+
if (kind === 'move' || kind === 'create') {
|
|
19630
|
+
// ① la durée est conservée. On borne le DÉBUT à la plage affichée, jamais la durée :
|
|
19631
|
+
// rogner la fin en douce ferait raccourcir un rendez-vous qu'on voulait seulement déplacer.
|
|
19632
|
+
const vise = aimante(minutesDansJour(base.start) + dMin, g.pas);
|
|
19633
|
+
const debut = Math.max(g.plageDebut, Math.min(vise, g.plageFin - g.pas));
|
|
19634
|
+
const jour = decaleJours(base.start, jours);
|
|
19635
|
+
const start = poseMinutes(jour, debut);
|
|
19636
|
+
return { start, end: new Date(start.getTime() + duree * MIN) };
|
|
19637
|
+
}
|
|
19638
|
+
if (kind === 'resize-start') {
|
|
19639
|
+
const finMin = minutesDansJour(base.end);
|
|
19640
|
+
const vise = aimante(minutesDansJour(base.start) + dMin, g.pas);
|
|
19641
|
+
// ② on s'arrête un pas avant la fin, jamais au-delà.
|
|
19642
|
+
const debut = Math.max(g.plageDebut, Math.min(vise, finMin - g.pas));
|
|
19643
|
+
return { start: poseMinutes(base.start, debut), end: base.end };
|
|
19644
|
+
}
|
|
19645
|
+
const debutMin = minutesDansJour(base.start);
|
|
19646
|
+
const vise = aimante(minutesDansJour(base.end) + dMin, g.pas);
|
|
19647
|
+
const fin = Math.min(g.plageFin, Math.max(vise, debutMin + g.pas));
|
|
19648
|
+
return { start: base.start, end: poseMinutes(base.end, fin) };
|
|
19649
|
+
}
|
|
19650
|
+
/**
|
|
19651
|
+
* Bornes d'une création par glisser sur une plage vide.
|
|
19652
|
+
*
|
|
19653
|
+
* `y0` / `y1` sont les positions verticales dans la colonne, en pixels. On aimante les DEUX
|
|
19654
|
+
* bords, et on garantit au moins un pas : un clic sec ne doit pas produire un événement de
|
|
19655
|
+
* durée nulle, invisible et impossible à rattraper.
|
|
19656
|
+
*/
|
|
19657
|
+
function cadProjeterCreation(jour, y0, y1, g) {
|
|
19658
|
+
const enMinutes = (y) => g.plageDebut + (y / Math.max(1, g.hauteurHeure)) * 60;
|
|
19659
|
+
const a = aimante(enMinutes(Math.min(y0, y1)), g.pas);
|
|
19660
|
+
let b = aimante(enMinutes(Math.max(y0, y1)), g.pas);
|
|
19661
|
+
if (b - a < g.pas)
|
|
19662
|
+
b = a + g.pas;
|
|
19663
|
+
const debut = Math.max(g.plageDebut, Math.min(a, g.plageFin - g.pas));
|
|
19664
|
+
const fin = Math.min(g.plageFin, Math.max(b, debut + g.pas));
|
|
19665
|
+
return { start: poseMinutes(jour, debut), end: poseMinutes(jour, fin) };
|
|
19666
|
+
}
|
|
19667
|
+
/**
|
|
19668
|
+
* Projection d'un geste dans une GRILLE DE MOIS — et ce n'est pas la même que dans une grille
|
|
19669
|
+
* horaire, contrairement à ce que j'avais écrit.
|
|
19670
|
+
*
|
|
19671
|
+
* Dans un mois, l'axe vertical n'est PAS le temps de la journée : c'est la semaine. Descendre
|
|
19672
|
+
* d'une rangée avance de SEPT JOURS, et l'heure ne bouge pas. Utiliser la projection horaire
|
|
19673
|
+
* ici donnait « +3 h » au lieu de « +7 jours » (mesuré au navigateur le 22/08/2026 : glisser
|
|
19674
|
+
* d'une rangée déplaçait un rendez-vous de 10 h 30 à 13 h 30 sans changer de date).
|
|
19675
|
+
*
|
|
19676
|
+
* Une seule règle à retenir : dans le mois, un geste ne déplace que des JOURS.
|
|
19677
|
+
*/
|
|
19678
|
+
function cadProjeterMois(kind, base, dx, dy, g) {
|
|
19679
|
+
const colonnes = g.largeurJour > 0 ? Math.round(dx / g.largeurJour) : 0;
|
|
19680
|
+
const rangees = g.hauteurRangee > 0 ? Math.round(dy / g.hauteurRangee) : 0;
|
|
19681
|
+
const jours = colonnes + 7 * rangees;
|
|
19682
|
+
if (kind === 'resize-start') {
|
|
19683
|
+
const s = decaleJours(base.start, jours);
|
|
19684
|
+
return { start: s > base.end ? base.end : s, end: base.end };
|
|
19685
|
+
}
|
|
19686
|
+
if (kind === 'resize-end') {
|
|
19687
|
+
const e = decaleJours(base.end, jours);
|
|
19688
|
+
return { start: base.start, end: e < base.start ? base.start : e };
|
|
19689
|
+
}
|
|
19690
|
+
// L'heure est conservée telle quelle : decaleJours ne touche qu'au quantième.
|
|
19691
|
+
return { start: decaleJours(base.start, jours), end: decaleJours(base.end, jours) };
|
|
19692
|
+
}
|
|
19693
|
+
/** Déplacement au CLAVIER, exprimé dans la même unité qu'un geste : jours et pas. */
|
|
19694
|
+
function cadProjeterClavier(kind, base, jours, pas, g) {
|
|
19695
|
+
// On repasse par la MÊME projection que le pointeur : une seule logique de placement à
|
|
19696
|
+
// éprouver, et le clavier n'est pas une reprise ultérieure qui dérive.
|
|
19697
|
+
return cadProjeterEdition(kind, base, jours * g.largeurJour, (pas * g.pas / 60) * g.hauteurHeure, g);
|
|
19698
|
+
}
|
|
19699
|
+
|
|
19020
19700
|
/** Styles de cad-taskboard (présentations cartes et liste). Tokens --cad-* uniquement. */
|
|
19021
19701
|
const CAD_TASKBOARD_STYLES = `
|
|
19022
19702
|
:host { display: flex; flex-direction: column; min-height: 0; height: 100%; font: var(--cad-font-size)/1.35 var(--cad-font); color: var(--cad-fg); background: var(--cad-bg); }
|
|
@@ -19540,9 +20220,1016 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
19540
20220
|
`, styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%;font:var(--cad-font-size)/1.35 var(--cad-font);color:var(--cad-fg);background:var(--cad-bg)}.tb__board{flex:1;min-height:0;display:flex;gap:12px;padding:12px;overflow-x:auto;overflow-y:hidden;scrollbar-gutter:stable}.tb__col{flex:0 0 var(--cad-taskboard-col, 258px);display:flex;flex-direction:column;min-height:0;background:var(--cad-bg-subtle);border:1px solid var(--cad-border);border-radius:var(--cad-radius)}.tb__head{display:flex;align-items:center;gap:8px;padding:9px 11px;border-bottom:1px solid var(--cad-border)}.tb__dot{width:8px;height:8px;border-radius:50%;flex:none;background:var(--_c, var(--cad-border-strong))}.tb__name{font-weight:500;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb__count{font-family:var(--cad-font-mono);font-size:var(--cad-font-size-sm);padding:2px 7px;border-radius:var(--cad-radius-pill);background:var(--cad-elevated);color:var(--cad-fg-muted);font-variant-numeric:tabular-nums;white-space:nowrap}.tb__count.is-full{background:var(--cad-warning-soft);color:var(--cad-warning)}.tb__count.is-over{background:var(--cad-danger-soft);color:var(--cad-danger);font-weight:500}.tb__list{flex:1;min-height:0;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:8px;scrollbar-gutter:stable}.tb__list.cdk-drop-list-dragging{background:var(--cad-accent-soft)}.tb__card{background:var(--cad-surface);border:1px solid var(--cad-border);border-radius:var(--cad-radius-sm);padding:9px 10px;box-shadow:var(--cad-shadow-sm);display:flex;flex-direction:column;gap:7px;cursor:grab;-webkit-user-select:none;user-select:none;transition:border-color var(--cad-dur) var(--cad-ease),box-shadow var(--cad-dur) var(--cad-ease)}.tb__card:hover{border-color:var(--cad-border-strong);box-shadow:var(--cad-shadow-md)}.tb__card:focus-visible{outline:2px solid var(--cad-ring);outline-offset:1px}.tb__card.is-orphan{border-left:2px dashed var(--cad-warning)}:host(.is-static) .tb__card,:host(.is-static) .tb__row{cursor:default}.tb__title{font-weight:500;line-height:1.32}.tb__meta{display:flex;align-items:center;gap:7px;flex-wrap:wrap}.tb__tag{font-family:var(--cad-font-mono);font-size:10px;padding:2px 6px;border-radius:var(--cad-radius-sm);background:var(--cad-elevated);color:var(--cad-fg-secondary)}.tb__due{font-family:var(--cad-font-mono);font-size:var(--cad-font-size-sm);color:var(--cad-fg-muted);font-variant-numeric:tabular-nums}.tb__due.is-late{color:var(--cad-danger);font-weight:500}.tb__sp{flex:1 1 auto}.tb__prog{height:3px;border-radius:var(--cad-radius-pill);background:var(--cad-elevated);overflow:hidden}.tb__prog i{display:block;height:100%;border-radius:var(--cad-radius-pill);background:var(--cad-accent)}.tb__prog.is-done i{background:var(--cad-success)}.tb__empty{padding:14px 10px;text-align:center;color:var(--cad-fg-muted);font-size:var(--cad-font-size-sm);border:1px dashed var(--cad-border-strong);border-radius:var(--cad-radius-sm)}.tb__rows{flex:1;min-height:0;overflow-y:auto;padding-bottom:12px;scrollbar-gutter:stable}.tb__grp{display:flex;align-items:center;gap:8px;width:100%;padding:8px 14px;background:var(--cad-bg-subtle);border-top:1px solid var(--cad-border);border-bottom:1px solid var(--cad-border);position:sticky;top:0;z-index:1;cursor:pointer;text-align:left;font:inherit;color:inherit}.tb__grp:hover{background:var(--cad-hover)}.tb__grp:focus-visible{outline:2px solid var(--cad-ring);outline-offset:-2px}.tb__grp cad-icon{color:var(--cad-fg-muted);transition:transform var(--cad-dur) var(--cad-ease)}.tb__grp.is-collapsed cad-icon{transform:rotate(-90deg)}.tb__grp b{font-weight:500}.tb__group-list{display:block}.tb__row{display:grid;grid-template-columns:1fr 92px 88px 26px;align-items:center;gap:12px;padding:8px 14px;border-bottom:1px solid var(--cad-border);cursor:grab;-webkit-user-select:none;user-select:none;background:var(--cad-bg)}.tb__row:hover{background:var(--cad-hover)}.tb__row:focus-visible{outline:2px solid var(--cad-ring);outline-offset:-2px}.tb__row.is-orphan{box-shadow:inset 2px 0 0 var(--cad-warning)}.tb__main{min-width:0;display:flex;flex-direction:column;gap:4px}.tb__main .tb__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tb__pct{display:flex;align-items:center;gap:7px}.tb__pct .tb__prog{flex:1}.tb__pct span{font-family:var(--cad-font-mono);font-size:10px;color:var(--cad-fg-muted);font-variant-numeric:tabular-nums}:host(.is-compact) .tb__row{grid-template-columns:1fr 26px}:host(.is-compact) .tb__cell-due,:host(.is-compact) .tb__pct{display:none}:host(.is-compact) .tb__mob{display:inline-flex}.tb__mob{display:none;align-items:center;gap:7px}.cdk-drag-preview{box-shadow:var(--cad-shadow-lg);border-radius:var(--cad-radius-sm);background:var(--cad-overlay);--cad-hover: var(--cad-overlay-hover);border:1px solid var(--cad-border)}.cdk-drag-placeholder{opacity:.34}.cdk-drag-animating{transition:transform .18s var(--cad-ease)}.tb__list.cdk-drop-list-dragging .tb__card:not(.cdk-drag-placeholder),.tb__group-list.cdk-drop-list-dragging .tb__row:not(.cdk-drag-placeholder){transition:transform .18s var(--cad-ease)}.tb__live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@media(prefers-reduced-motion:reduce){.cdk-drag-animating,.tb__list.cdk-drop-list-dragging .tb__card,.tb__grp cad-icon{transition:none}}\n"] }]
|
|
19541
20221
|
}], propDecorators: { plan: [{ type: i0.Input, args: [{ isSignal: true, alias: "plan", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }], dragDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "dragDisabled", required: false }] }], collapsedKeys: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsedKeys", required: false }] }, { type: i0.Output, args: ["collapsedKeysChange"] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], dateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateFormat", required: false }] }], today: [{ type: i0.Input, args: [{ isSignal: true, alias: "today", required: false }] }], taskMove: [{ type: i0.Output, args: ["taskMove"] }], taskAssign: [{ type: i0.Output, args: ["taskAssign"] }], taskOpen: [{ type: i0.Output, args: ["taskOpen"] }], wipExceeded: [{ type: i0.Output, args: ["wipExceeded"] }], cardTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadTaskCardDirective), { isSignal: true }] }], rowTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CadTaskRowDirective), { isSignal: true }] }] } });
|
|
19542
20222
|
|
|
20223
|
+
/**
|
|
20224
|
+
* Styles de cad-calendar. Tokens --cad-* uniquement.
|
|
20225
|
+
*
|
|
20226
|
+
* ATTENTION : ce fichier n'est PAS couvert par tools/check-styles.mjs, qui ne scanne que les
|
|
20227
|
+
* blocs « styles: [ » en ligne. Aucun accent grave dans les commentaires ci-dessous : un seul
|
|
20228
|
+
* refermerait le litteral gabarit et Angular echouerait sur « Failed to resolve styles ».
|
|
20229
|
+
*/
|
|
20230
|
+
const CAD_CALENDAR_STYLES = `
|
|
20231
|
+
:host { display: flex; flex-direction: column; min-height: 0; height: 100%;
|
|
20232
|
+
font: var(--cad-font-size)/1.4 var(--cad-font); color: var(--cad-fg); background: var(--cad-bg); }
|
|
20233
|
+
|
|
20234
|
+
.cal__corps { flex: 1; min-height: 0; display: flex; }
|
|
20235
|
+
.cal__vue { flex: 1; min-width: 0; min-height: 0; overflow: auto; }
|
|
20236
|
+
|
|
20237
|
+
/* ---------------- MOIS ---------------- */
|
|
20238
|
+
.mois { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
20239
|
+
grid-template-rows: auto; grid-auto-rows: minmax(84px, 1fr); min-height: 100%; }
|
|
20240
|
+
/* grid-template-rows: auto pour la premiere rangee : sans elle, grid-auto-rows s'applique
|
|
20241
|
+
aussi aux en-tetes de jour, qui heritent de la hauteur des cases et laissent une bande vide. */
|
|
20242
|
+
.mois__jsem { padding: 6px 8px; text-align: right; border-bottom: 1px solid var(--cad-border-strong);
|
|
20243
|
+
background: var(--cad-bg-subtle); position: sticky; top: 0; z-index: 4;
|
|
20244
|
+
font: 600 10.5px var(--cad-font-mono); letter-spacing: .06em; text-transform: uppercase;
|
|
20245
|
+
color: var(--cad-fg-muted); }
|
|
20246
|
+
|
|
20247
|
+
/* La rangee de semaine est un CONTENEUR relatif : les bandeaux multi-jours sont un calque
|
|
20248
|
+
par-dessus les cases, seule facon de les rendre continus d'un jour a l'autre. */
|
|
20249
|
+
.mois__sem { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
20250
|
+
position: relative; border-bottom: 1px solid var(--cad-border); min-height: 84px; }
|
|
20251
|
+
.mois__jour { border-right: 1px solid var(--cad-border); padding: 3px; min-width: 0;
|
|
20252
|
+
display: flex; flex-direction: column; gap: 2px; }
|
|
20253
|
+
.mois__jour:last-child { border-right: 0; }
|
|
20254
|
+
.mois__jour.is-hors { background: var(--cad-bg-subtle); }
|
|
20255
|
+
.mois__jour.is-ferme { background: var(--cad-bg-subtle); }
|
|
20256
|
+
.mois__n { font: 11px var(--cad-font-mono); color: var(--cad-fg-secondary); text-align: right;
|
|
20257
|
+
padding: 1px 3px; font-variant-numeric: tabular-nums; flex: none; }
|
|
20258
|
+
.mois__jour.is-auj .mois__n { background: var(--cad-accent); color: var(--cad-fg-on-accent);
|
|
20259
|
+
border-radius: var(--cad-radius-sm); font-weight: 600; }
|
|
20260
|
+
.mois__reserve { flex: none; }
|
|
20261
|
+
|
|
20262
|
+
.calque { position: absolute; left: 0; right: 0; pointer-events: none; z-index: 2; }
|
|
20263
|
+
.bandeau { position: absolute; height: 17px; border-radius: var(--cad-radius-sm); padding: 0 7px;
|
|
20264
|
+
font-size: 10.5px; line-height: 17px; white-space: nowrap; overflow: hidden;
|
|
20265
|
+
text-overflow: ellipsis; pointer-events: auto; cursor: pointer;
|
|
20266
|
+
background: color-mix(in srgb, var(--_c) 22%, transparent); color: var(--_c);
|
|
20267
|
+
border: 1px solid color-mix(in srgb, var(--_c) 42%, transparent); }
|
|
20268
|
+
.bandeau.is-avant { border-top-left-radius: 0; border-bottom-left-radius: 0; border-left-style: dashed; }
|
|
20269
|
+
.bandeau.is-apres { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right-style: dashed; }
|
|
20270
|
+
|
|
20271
|
+
.puce { display: flex; align-items: center; gap: 5px; font-size: 10.5px; padding: 1px 5px;
|
|
20272
|
+
border-radius: var(--cad-radius-sm); white-space: nowrap; overflow: hidden;
|
|
20273
|
+
text-overflow: ellipsis; cursor: pointer; border-left: 2px solid var(--_c);
|
|
20274
|
+
background: color-mix(in srgb, var(--_c) 13%, transparent); color: var(--_c); }
|
|
20275
|
+
.puce:hover { background: color-mix(in srgb, var(--_c) 22%, transparent); }
|
|
20276
|
+
.puce__h { font: 9.5px var(--cad-font-mono); opacity: .85; flex: none; font-variant-numeric: tabular-nums; }
|
|
20277
|
+
.puce__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
20278
|
+
.plus { all: unset; box-sizing: border-box; font-size: 10px; color: var(--cad-fg-muted);
|
|
20279
|
+
padding: 1px 5px; cursor: pointer; border-radius: var(--cad-radius-sm); }
|
|
20280
|
+
.plus:hover { color: var(--cad-accent); background: var(--cad-hover); }
|
|
20281
|
+
|
|
20282
|
+
/* ---------------- SEMAINE / JOUR ---------------- */
|
|
20283
|
+
.grille { min-width: 0; display: flex; flex-direction: column; height: 100%; }
|
|
20284
|
+
.grille__hd { display: grid; position: sticky; top: 0; z-index: 5; background: var(--cad-bg-subtle);
|
|
20285
|
+
border-bottom: 1px solid var(--cad-border-strong); flex: none; }
|
|
20286
|
+
.grille__hd > div { padding: 5px 6px; text-align: center; border-right: 1px solid var(--cad-border); min-width: 0; }
|
|
20287
|
+
.grille__hd > div:last-child { border-right: 0; }
|
|
20288
|
+
.grille__d { font: 10px var(--cad-font-mono); color: var(--cad-fg-muted);
|
|
20289
|
+
text-transform: uppercase; letter-spacing: .06em; }
|
|
20290
|
+
.grille__n { font-size: 16px; font-weight: 600; letter-spacing: -.02em; }
|
|
20291
|
+
.is-auj .grille__n { color: var(--cad-accent); }
|
|
20292
|
+
|
|
20293
|
+
.bande { display: grid; border-bottom: 1px solid var(--cad-border-strong);
|
|
20294
|
+
background: var(--cad-bg-subtle); flex: none; }
|
|
20295
|
+
.bande__lbl { font: 9px var(--cad-font-mono); color: var(--cad-fg-muted); padding: 4px 6px;
|
|
20296
|
+
text-align: right; border-right: 1px solid var(--cad-border); }
|
|
20297
|
+
.bande__zone { grid-column: 2 / -1; position: relative; padding: 2px 0; }
|
|
20298
|
+
|
|
20299
|
+
.heures { display: grid; position: relative; flex: 1; min-height: 0; overflow: auto; }
|
|
20300
|
+
.heures__lbl { border-right: 1px solid var(--cad-border); }
|
|
20301
|
+
.heures__lbl > div { font: 9.5px var(--cad-font-mono); color: var(--cad-fg-muted);
|
|
20302
|
+
text-align: right; padding-right: 6px; transform: translateY(-6px); }
|
|
20303
|
+
.heures__col { border-right: 1px solid var(--cad-border); position: relative; min-width: 0; }
|
|
20304
|
+
.heures__col:last-child { border-right: 0; }
|
|
20305
|
+
.heures__col.is-ferme { background: var(--cad-bg-subtle); }
|
|
20306
|
+
.trait { position: absolute; left: 0; right: 0; border-top: 1px solid var(--cad-border); pointer-events: none; }
|
|
20307
|
+
.trait.is-demi { border-top-style: dotted; opacity: .55; }
|
|
20308
|
+
|
|
20309
|
+
.evt { position: absolute; border-radius: var(--cad-radius-sm); padding: 1px 5px; overflow: hidden;
|
|
20310
|
+
cursor: pointer; border-left: 3px solid var(--_c); font-size: 10.5px; line-height: 1.25;
|
|
20311
|
+
background: color-mix(in srgb, var(--_c) 15%, transparent); color: var(--_c); }
|
|
20312
|
+
.evt:hover { background: color-mix(in srgb, var(--_c) 26%, transparent); }
|
|
20313
|
+
.evt__t { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
20314
|
+
.evt__h { font: 9px var(--cad-font-mono); opacity: .85; }
|
|
20315
|
+
.maintenant { position: absolute; left: 0; right: 0; height: 2px; background: var(--cad-danger); z-index: 4; pointer-events: none; }
|
|
20316
|
+
.maintenant::before { content: ''; position: absolute; left: -3px; top: -3px; width: 8px; height: 8px;
|
|
20317
|
+
border-radius: 50%; background: var(--cad-danger); }
|
|
20318
|
+
|
|
20319
|
+
/* ---------------- AGENDA ---------------- */
|
|
20320
|
+
.agenda { display: flex; flex-direction: column; }
|
|
20321
|
+
.ag__jour { display: grid; grid-template-columns: 72px minmax(0, 1fr); border-bottom: 1px solid var(--cad-border); }
|
|
20322
|
+
.ag__d { padding: 9px 11px; border-right: 1px solid var(--cad-border); background: var(--cad-bg-subtle); }
|
|
20323
|
+
.ag__d b { display: block; font-size: 18px; font-weight: 600; letter-spacing: -.02em; }
|
|
20324
|
+
.ag__d span { display: block; font: 9.5px var(--cad-font-mono); color: var(--cad-fg-muted); text-transform: uppercase; }
|
|
20325
|
+
.ag__d.is-auj b { color: var(--cad-accent); }
|
|
20326
|
+
.ag__l { padding: 5px 0; min-width: 0; }
|
|
20327
|
+
.ag__e { all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 9px;
|
|
20328
|
+
padding: 6px 11px; cursor: pointer; width: 100%; min-height: 34px; }
|
|
20329
|
+
.ag__e:hover { background: var(--cad-hover); }
|
|
20330
|
+
.ag__e:focus-visible { outline: 2px solid var(--cad-accent); outline-offset: -2px; }
|
|
20331
|
+
.ag__p { width: 8px; height: 8px; border-radius: 50%; background: var(--_c); flex: none; }
|
|
20332
|
+
.ag__h { font: 11px var(--cad-font-mono); color: var(--cad-fg-secondary); flex: none;
|
|
20333
|
+
width: 92px; font-variant-numeric: tabular-nums; }
|
|
20334
|
+
.ag__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
20335
|
+
.ag__c { margin-left: auto; font-size: 10.5px; color: var(--cad-fg-muted); flex: none; }
|
|
20336
|
+
|
|
20337
|
+
/* ---------------- ANNEE ---------------- */
|
|
20338
|
+
.annee { display: grid; grid-template-columns: repeat(auto-fill, minmax(178px, 1fr)); gap: 14px; padding: 14px; }
|
|
20339
|
+
.mm { border: 1px solid var(--cad-border); border-radius: var(--cad-radius); padding: 8px; background: var(--cad-surface); }
|
|
20340
|
+
.mm__t { font-size: 12px; font-weight: 600; margin-bottom: 5px; text-transform: capitalize; }
|
|
20341
|
+
.mm__g { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
|
|
20342
|
+
.mm__g > span, .mm__g > button { all: unset; box-sizing: border-box; text-align: center;
|
|
20343
|
+
font: 9.5px var(--cad-font-mono); padding: 2px 0; border-radius: 3px;
|
|
20344
|
+
color: var(--cad-fg-secondary); font-variant-numeric: tabular-nums; }
|
|
20345
|
+
.mm__g > span { color: var(--cad-fg-muted); font-weight: 500; }
|
|
20346
|
+
.mm__g > button { cursor: pointer; position: relative; }
|
|
20347
|
+
.mm__g > button:hover { background: var(--cad-hover); }
|
|
20348
|
+
.mm__g > button.is-hors { opacity: .35; }
|
|
20349
|
+
.mm__g > button.is-auj { background: var(--cad-accent); color: var(--cad-fg-on-accent); font-weight: 600; }
|
|
20350
|
+
.mm__pt { position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
|
|
20351
|
+
width: 3px; height: 3px; border-radius: 50%; background: var(--cad-accent); }
|
|
20352
|
+
.mm__g > button.is-auj .mm__pt { background: var(--cad-fg-on-accent); }
|
|
20353
|
+
|
|
20354
|
+
/* ---------------- EDITION ---------------- */
|
|
20355
|
+
/* Les poignees n'existent que si l'edition est active ET l'evenement manipulable : une
|
|
20356
|
+
poignee qui ne repond pas est pire que pas de poignee. */
|
|
20357
|
+
.evt.is-editable, .bandeau.is-editable, .puce.is-editable { cursor: grab; }
|
|
20358
|
+
.evt.is-editable:active, .bandeau.is-editable:active, .puce.is-editable:active { cursor: grabbing; }
|
|
20359
|
+
.poignee { position: absolute; z-index: 2; }
|
|
20360
|
+
.evt .poignee { left: 0; right: 0; height: 6px; cursor: ns-resize; }
|
|
20361
|
+
.evt .poignee.is-haut { top: 0; }
|
|
20362
|
+
.evt .poignee.is-bas { bottom: 0; }
|
|
20363
|
+
.bandeau .poignee { top: 0; bottom: 0; width: 6px; cursor: ew-resize; }
|
|
20364
|
+
.bandeau .poignee.is-haut { left: 0; }
|
|
20365
|
+
.bandeau .poignee.is-bas { right: 0; }
|
|
20366
|
+
.poignee::after { content: ''; position: absolute; inset: 0; }
|
|
20367
|
+
|
|
20368
|
+
/* Une occurrence de SERIE n'est pas manipulable tant que l'edition de recurrence n'existe
|
|
20369
|
+
pas : bouger une occurrence sans savoir si l'on modifie l'occurrence, la suite ou toute la
|
|
20370
|
+
serie perdrait la modification en silence. On le MONTRE au lieu de laisser essayer. */
|
|
20371
|
+
.evt.is-verrouille, .bandeau.is-verrouille, .puce.is-verrouille { cursor: not-allowed; position: relative; }
|
|
20372
|
+
.evt.is-verrouille::after, .bandeau.is-verrouille::after, .puce.is-verrouille::after {
|
|
20373
|
+
content: ''; position: absolute; inset: 0; pointer-events: none;
|
|
20374
|
+
background: repeating-linear-gradient(-45deg, currentColor 0 1px, transparent 1px 5px); opacity: .18; }
|
|
20375
|
+
|
|
20376
|
+
/* Fantome du geste en cours : il montre ou l'on va tomber, apres aimantage. */
|
|
20377
|
+
.fantome { position: absolute; z-index: 6; pointer-events: none; border-radius: var(--cad-radius-sm);
|
|
20378
|
+
background: var(--cad-accent-soft); border: 1px dashed var(--cad-accent);
|
|
20379
|
+
color: var(--cad-accent); font: 10.5px var(--cad-font-mono); padding: 1px 5px;
|
|
20380
|
+
overflow: hidden; white-space: nowrap; }
|
|
20381
|
+
|
|
20382
|
+
/* ---------------- vide ---------------- */
|
|
20383
|
+
.vide { padding: 28px 16px; color: var(--cad-fg-muted); text-align: center; }
|
|
20384
|
+
|
|
20385
|
+
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
|
|
20386
|
+
`;
|
|
20387
|
+
|
|
20388
|
+
/**
|
|
20389
|
+
* `<cad-calendar [plan]="plan" [sources]="agendas" view="auto"/>`
|
|
20390
|
+
*
|
|
20391
|
+
* LA GRILLE EST LE TEMPS — c'est ce qui le distingue de `cad-scheduler`, dont les lignes sont
|
|
20392
|
+
* des ressources. On répond ici à « qu'est-ce qui se passe le 17 ? », là-bas à « qui est libre
|
|
20393
|
+
* jeudi ? ». Deux questions, deux composants, un seul document JSON.
|
|
20394
|
+
*
|
|
20395
|
+
* L'AGENDA D'UNE TÂCHE EST SON `bucket`. Pas un champ de plus : le taskboard rend les buckets
|
|
20396
|
+
* en colonnes, le calendrier les rend en agendas superposés. C'est le pari « une donnée,
|
|
20397
|
+
* plusieurs vues » qui paie, et ça évite d'inventer un `calendarId` que les autres vues
|
|
20398
|
+
* ignoreraient.
|
|
20399
|
+
*
|
|
20400
|
+
* LA RÉCURRENCE EST EN LECTURE SEULE (voir `planning.recurrence.ts`). On déplie une règle pour
|
|
20401
|
+
* l'afficher ; on n'édite pas de série. Une récurrence à moitié faite perd des modifications
|
|
20402
|
+
* sans le dire — déplier n'écrit rien, donc ne peut rien perdre.
|
|
20403
|
+
*
|
|
20404
|
+
* LE COMPOSANT N'ÉCRIT JAMAIS : il émet `eventClick`, `dateClick`, `rangeChange`. Masquer un
|
|
20405
|
+
* agenda est en revanche un état de PRÉSENTATION, donc un `model()` qu'il porte lui-même.
|
|
20406
|
+
*/
|
|
20407
|
+
class CadCalendarComponent {
|
|
20408
|
+
Math = Math;
|
|
20409
|
+
bp = inject(CadBreakpointService);
|
|
20410
|
+
hote = inject((ElementRef));
|
|
20411
|
+
/**
|
|
20412
|
+
* Une colonne de jour, pour mesurer la largeur d'un pas horizontal.
|
|
20413
|
+
*
|
|
20414
|
+
* On MESURE au lieu de calculer : les colonnes sont en `minmax(0, 1fr)`, donc leur largeur
|
|
20415
|
+
* dépend du conteneur, de la barre de défilement et du zoom. Un calcul serait faux dès que
|
|
20416
|
+
* l'un des trois change, et le glisser dériverait d'un jour sans que rien ne le signale.
|
|
20417
|
+
*/
|
|
20418
|
+
largeurColonne() {
|
|
20419
|
+
const el = this.hote.nativeElement;
|
|
20420
|
+
return el.querySelector('.heures__col') ?? el.querySelector('.mois__jour');
|
|
20421
|
+
}
|
|
20422
|
+
plan = input(null, ...(ngDevMode ? [{ debugName: "plan" }] : /* istanbul ignore next */ []));
|
|
20423
|
+
/** Agendas superposables. Un `bucket` sans source déclarée prend l'accent et son propre nom. */
|
|
20424
|
+
sources = input([], ...(ngDevMode ? [{ debugName: "sources" }] : /* istanbul ignore next */ []));
|
|
20425
|
+
/** Agendas décochés. État de PRÉSENTATION, donc porté ici et lié en deux sens. */
|
|
20426
|
+
hidden = model(new Set(), ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
20427
|
+
view = model('auto', ...(ngDevMode ? [{ debugName: "view" }] : /* istanbul ignore next */ []));
|
|
20428
|
+
/** Date d'ancrage : le mois, la semaine ou le jour affiché. */
|
|
20429
|
+
date = model(new Date(), ...(ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []));
|
|
20430
|
+
/** 1 = lundi (défaut), 0 = dimanche. Touche le mois, la semaine ET le mini-calendrier. */
|
|
20431
|
+
firstDay = input(1, ...(ngDevMode ? [{ debugName: "firstDay" }] : /* istanbul ignore next */ []));
|
|
20432
|
+
/** Plage horaire affichée, en heures. Réglable : 7 → 20 par défaut. */
|
|
20433
|
+
dayStart = input(7, ...(ngDevMode ? [{ debugName: "dayStart" }] : /* istanbul ignore next */ []));
|
|
20434
|
+
dayEnd = input(20, ...(ngDevMode ? [{ debugName: "dayEnd" }] : /* istanbul ignore next */ []));
|
|
20435
|
+
hourHeight = input(34, ...(ngDevMode ? [{ debugName: "hourHeight" }] : /* istanbul ignore next */ []));
|
|
20436
|
+
/** Événements montrés dans une case de mois avant le « +N ». */
|
|
20437
|
+
maxPerDay = input(3, ...(ngDevMode ? [{ debugName: "maxPerDay" }] : /* istanbul ignore next */ []));
|
|
20438
|
+
workCalendar = input(null, ...(ngDevMode ? [{ debugName: "workCalendar" }] : /* istanbul ignore next */ []));
|
|
20439
|
+
today = input(null, ...(ngDevMode ? [{ debugName: "today" }] : /* istanbul ignore next */ []));
|
|
20440
|
+
locale = input('fr-FR', ...(ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []));
|
|
20441
|
+
emptyText = input('Aucun événement sur la période', ...(ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []));
|
|
20442
|
+
ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
20443
|
+
showNow = input(true, { ...(ngDevMode ? { debugName: "showNow" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
20444
|
+
eventClick = output();
|
|
20445
|
+
dateClick = output();
|
|
20446
|
+
/** La fenêtre affichée a changé : l'hôte peut aller chercher les données qui manquent. */
|
|
20447
|
+
rangeChange = output();
|
|
20448
|
+
/** Gestes d'édition. `false` = vue en lecture, sans poignée ni curseur trompeur. */
|
|
20449
|
+
editable = input(false, { ...(ngDevMode ? { debugName: "editable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
20450
|
+
/** Aimantage, en minutes. Sans lui on crée des réunions de 9 h 07 que personne n'a voulues. */
|
|
20451
|
+
snap = input(15, ...(ngDevMode ? [{ debugName: "snap" }] : /* istanbul ignore next */ []));
|
|
20452
|
+
eventMove = output();
|
|
20453
|
+
eventResize = output();
|
|
20454
|
+
eventCreate = output();
|
|
20455
|
+
/** `auto` : agenda sous le seuil. Une grille de mois à 55 px par jour ne montre plus rien. */
|
|
20456
|
+
vueEffective = computed(() => {
|
|
20457
|
+
const v = this.view();
|
|
20458
|
+
if (v !== 'auto')
|
|
20459
|
+
return v;
|
|
20460
|
+
return this.bp.isMobile() ? 'agenda' : 'month';
|
|
20461
|
+
}, ...(ngDevMode ? [{ debugName: "vueEffective" }] : /* istanbul ignore next */ []));
|
|
20462
|
+
normalise = computed(() => cadNormalizePlan(this.plan()), ...(ngDevMode ? [{ debugName: "normalise" }] : /* istanbul ignore next */ []));
|
|
20463
|
+
ajd = computed(() => cadMinuit(this.today() ?? new Date()), ...(ngDevMode ? [{ debugName: "ajd" }] : /* istanbul ignore next */ []));
|
|
20464
|
+
hauteurHeure = computed(() => this.hourHeight(), ...(ngDevMode ? [{ debugName: "hauteurHeure" }] : /* istanbul ignore next */ []));
|
|
20465
|
+
hauteurTotale = computed(() => (this.dayEnd() - this.dayStart()) * this.hourHeight(), ...(ngDevMode ? [{ debugName: "hauteurTotale" }] : /* istanbul ignore next */ []));
|
|
20466
|
+
heuresAffichees = computed(() => {
|
|
20467
|
+
const out = [];
|
|
20468
|
+
for (let h = this.dayStart(); h <= this.dayEnd(); h++)
|
|
20469
|
+
out.push(h);
|
|
20470
|
+
return out;
|
|
20471
|
+
}, ...(ngDevMode ? [{ debugName: "heuresAffichees" }] : /* istanbul ignore next */ []));
|
|
20472
|
+
/** Fenêtre couverte par la vue courante. Elle borne le dépliage : on ne projette pas l'infini. */
|
|
20473
|
+
fenetre = computed(() => {
|
|
20474
|
+
const d = this.date();
|
|
20475
|
+
const v = this.vueEffective();
|
|
20476
|
+
if (v === 'day') {
|
|
20477
|
+
const s = cadMinuit(d);
|
|
20478
|
+
return { start: s, end: new Date(s.getFullYear(), s.getMonth(), s.getDate(), 23, 59, 59) };
|
|
20479
|
+
}
|
|
20480
|
+
if (v === 'week') {
|
|
20481
|
+
const s = cadDebutSemaine(d, this.firstDay());
|
|
20482
|
+
const e = new Date(s);
|
|
20483
|
+
e.setDate(e.getDate() + 6);
|
|
20484
|
+
e.setHours(23, 59, 59);
|
|
20485
|
+
return { start: s, end: e };
|
|
20486
|
+
}
|
|
20487
|
+
if (v === 'year') {
|
|
20488
|
+
return { start: new Date(d.getFullYear(), 0, 1), end: new Date(d.getFullYear(), 11, 31, 23, 59, 59) };
|
|
20489
|
+
}
|
|
20490
|
+
const g = cadMonthGrid(d, this.firstDay());
|
|
20491
|
+
const dernier = g.semaines[g.semaines.length - 1][6];
|
|
20492
|
+
return { start: g.debut, end: new Date(dernier.getFullYear(), dernier.getMonth(), dernier.getDate(), 23, 59, 59) };
|
|
20493
|
+
}, ...(ngDevMode ? [{ debugName: "fenetre" }] : /* istanbul ignore next */ []));
|
|
20494
|
+
/**
|
|
20495
|
+
* CORRECTIF OPTIMISTE. Le composant n'écrit jamais dans le document — mais sans état local
|
|
20496
|
+
* le geste serait mort à l'écran : on relâche, et la barre revient à sa place en attendant
|
|
20497
|
+
* que l'hôte réponde. On garde donc les bornes proposées, ATTACHÉES au `plan` d'origine, et
|
|
20498
|
+
* on les abandonne dès qu'un nouveau `plan` arrive. Même patron que `cad-taskboard`.
|
|
20499
|
+
*/
|
|
20500
|
+
patch = signal({ src: null, map: new Map() }, ...(ngDevMode ? [{ debugName: "patch" }] : /* istanbul ignore next */ []));
|
|
20501
|
+
occurrences = computed(() => {
|
|
20502
|
+
const f = this.fenetre();
|
|
20503
|
+
const caches = this.hidden();
|
|
20504
|
+
const { occurrences } = cadExpandOccurrences(this.normalise().tasks, f.start, f.end);
|
|
20505
|
+
const base = occurrences.filter((o) => !caches.has(o.task.bucket ?? ''));
|
|
20506
|
+
const p = this.patch();
|
|
20507
|
+
if (p.src !== this.plan() || !p.map.size)
|
|
20508
|
+
return base;
|
|
20509
|
+
return base.map((o) => {
|
|
20510
|
+
const n = p.map.get(o.id);
|
|
20511
|
+
return n ? { ...o, start: n.start, end: n.end } : o;
|
|
20512
|
+
});
|
|
20513
|
+
}, ...(ngDevMode ? [{ debugName: "occurrences" }] : /* istanbul ignore next */ []));
|
|
20514
|
+
/** Fantôme du geste en cours : il montre où l'on va tomber, APRÈS aimantage. */
|
|
20515
|
+
fantome = signal(null, ...(ngDevMode ? [{ debugName: "fantome" }] : /* istanbul ignore next */ []));
|
|
20516
|
+
/** Anomalies de dépliage — jamais tues : l'hôte peut les montrer. */
|
|
20517
|
+
issues = computed(() => cadExpandOccurrences(this.normalise().tasks, this.fenetre().start, this.fenetre().end).issues, ...(ngDevMode ? [{ debugName: "issues" }] : /* istanbul ignore next */ []));
|
|
20518
|
+
parJour = computed(() => {
|
|
20519
|
+
const carte = new Map();
|
|
20520
|
+
for (const o of this.occurrences()) {
|
|
20521
|
+
const d0 = cadNumeroJour(o.start), d1 = cadNumeroJour(o.end);
|
|
20522
|
+
for (let n = d0; n <= d1; n++)
|
|
20523
|
+
(carte.get(n) ?? carte.set(n, []).get(n)).push(o);
|
|
20524
|
+
}
|
|
20525
|
+
return carte;
|
|
20526
|
+
}, ...(ngDevMode ? [{ debugName: "parJour" }] : /* istanbul ignore next */ []));
|
|
20527
|
+
nomsJours = computed(() => {
|
|
20528
|
+
const base = ['lun', 'mar', 'mer', 'jeu', 'ven', 'sam', 'dim'];
|
|
20529
|
+
return this.firstDay() === 0 ? ['dim', ...base.slice(0, 6)] : base;
|
|
20530
|
+
}, ...(ngDevMode ? [{ debugName: "nomsJours" }] : /* istanbul ignore next */ []));
|
|
20531
|
+
semaines = computed(() => {
|
|
20532
|
+
const g = cadMonthGrid(this.date(), this.firstDay());
|
|
20533
|
+
const occ = this.occurrences();
|
|
20534
|
+
const wc = this.workCalendar();
|
|
20535
|
+
const ajd = cadNumeroJour(this.ajd());
|
|
20536
|
+
const max = this.maxPerDay();
|
|
20537
|
+
return g.semaines.map((jours) => {
|
|
20538
|
+
const { bandes, voies } = cadWeekBands(occ, jours);
|
|
20539
|
+
return {
|
|
20540
|
+
voies,
|
|
20541
|
+
bandes,
|
|
20542
|
+
jours: jours.map((date) => {
|
|
20543
|
+
const n = cadNumeroJour(date);
|
|
20544
|
+
const duJour = (this.parJour().get(n) ?? []).filter((o) => !cadEstBandeau(o));
|
|
20545
|
+
return {
|
|
20546
|
+
date, cle: n, n: date.getDate(),
|
|
20547
|
+
hors: date.getMonth() !== g.mois,
|
|
20548
|
+
auj: n === ajd,
|
|
20549
|
+
ferme: wc ? !wc.isWorkday(date) : false,
|
|
20550
|
+
puces: duJour.slice(0, max),
|
|
20551
|
+
reste: Math.max(0, duJour.length - max),
|
|
20552
|
+
};
|
|
20553
|
+
}),
|
|
20554
|
+
};
|
|
20555
|
+
});
|
|
20556
|
+
}, ...(ngDevMode ? [{ debugName: "semaines" }] : /* istanbul ignore next */ []));
|
|
20557
|
+
joursGrille = computed(() => {
|
|
20558
|
+
const v = this.vueEffective();
|
|
20559
|
+
const jours = v === 'day'
|
|
20560
|
+
? [cadMinuit(this.date())]
|
|
20561
|
+
: Array.from({ length: 7 }, (_, k) => { const d = cadDebutSemaine(this.date(), this.firstDay()); d.setDate(d.getDate() + k); return d; });
|
|
20562
|
+
const wc = this.workCalendar();
|
|
20563
|
+
const ajd = cadNumeroJour(this.ajd());
|
|
20564
|
+
return jours.map((date) => {
|
|
20565
|
+
const n = cadNumeroJour(date);
|
|
20566
|
+
return {
|
|
20567
|
+
date, cle: n, n: date.getDate(), jsem: this.nomsJours()[(date.getDay() + 6) % 7],
|
|
20568
|
+
auj: n === ajd,
|
|
20569
|
+
ferme: wc ? !wc.isWorkday(date) : false,
|
|
20570
|
+
slots: cadPackDay(this.parJour().get(n) ?? [], this.dayStart() * 60, this.dayEnd() * 60),
|
|
20571
|
+
};
|
|
20572
|
+
});
|
|
20573
|
+
}, ...(ngDevMode ? [{ debugName: "joursGrille" }] : /* istanbul ignore next */ []));
|
|
20574
|
+
bandeGrille = computed(() => cadWeekBands(this.occurrences(), this.joursGrille().map((j) => j.date)), ...(ngDevMode ? [{ debugName: "bandeGrille" }] : /* istanbul ignore next */ []));
|
|
20575
|
+
colonnes = computed(() => `54px repeat(${this.joursGrille().length}, minmax(0, 1fr))`, ...(ngDevMode ? [{ debugName: "colonnes" }] : /* istanbul ignore next */ []));
|
|
20576
|
+
maintenant = computed(() => {
|
|
20577
|
+
if (!this.showNow())
|
|
20578
|
+
return null;
|
|
20579
|
+
const n = this.today() ?? new Date();
|
|
20580
|
+
const m = n.getHours() * 60 + n.getMinutes();
|
|
20581
|
+
if (m < this.dayStart() * 60 || m > this.dayEnd() * 60)
|
|
20582
|
+
return null;
|
|
20583
|
+
return (m - this.dayStart() * 60) / 60 * this.hourHeight();
|
|
20584
|
+
}, ...(ngDevMode ? [{ debugName: "maintenant" }] : /* istanbul ignore next */ []));
|
|
20585
|
+
groupes = computed(() => {
|
|
20586
|
+
const carte = new Map();
|
|
20587
|
+
for (const [n, liste] of this.parJour())
|
|
20588
|
+
carte.set(n, liste);
|
|
20589
|
+
const ajd = cadNumeroJour(this.ajd());
|
|
20590
|
+
return [...carte.entries()]
|
|
20591
|
+
.sort((a, b) => a[0] - b[0])
|
|
20592
|
+
.map(([n, evts]) => {
|
|
20593
|
+
const date = evts[0].start;
|
|
20594
|
+
const d = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
20595
|
+
// Le jour du groupe est celui de la CASE, pas du premier événement : un multi-jours
|
|
20596
|
+
// apparaît dans chaque jour qu'il couvre, avec le bon quantième.
|
|
20597
|
+
const vrai = new Date(d);
|
|
20598
|
+
vrai.setDate(vrai.getDate() + (n - cadNumeroJour(d)));
|
|
20599
|
+
return {
|
|
20600
|
+
cle: n, n: vrai.getDate(), auj: n === ajd,
|
|
20601
|
+
jsem: this.nomsJours()[(vrai.getDay() + 6) % 7],
|
|
20602
|
+
evts: [...evts].sort((a, b) => Number(b.allDay) - Number(a.allDay) || a.start.getTime() - b.start.getTime()),
|
|
20603
|
+
};
|
|
20604
|
+
});
|
|
20605
|
+
}, ...(ngDevMode ? [{ debugName: "groupes" }] : /* istanbul ignore next */ []));
|
|
20606
|
+
miniMois = computed(() => {
|
|
20607
|
+
const an = this.date().getFullYear();
|
|
20608
|
+
const ajd = cadNumeroJour(this.ajd());
|
|
20609
|
+
const charge = this.parJour();
|
|
20610
|
+
return Array.from({ length: 12 }, (_, m) => {
|
|
20611
|
+
const g = cadMonthGrid(new Date(an, m, 1), this.firstDay());
|
|
20612
|
+
return {
|
|
20613
|
+
mois: m,
|
|
20614
|
+
titre: new Date(an, m, 1).toLocaleDateString(this.locale(), { month: 'long' }),
|
|
20615
|
+
jours: g.semaines.flat().map((date) => {
|
|
20616
|
+
const n = cadNumeroJour(date);
|
|
20617
|
+
return { date, cle: n, n: date.getDate(), hors: date.getMonth() !== m, auj: n === ajd, charge: (charge.get(n) ?? []).length };
|
|
20618
|
+
}),
|
|
20619
|
+
};
|
|
20620
|
+
});
|
|
20621
|
+
}, ...(ngDevMode ? [{ debugName: "miniMois" }] : /* istanbul ignore next */ []));
|
|
20622
|
+
couleur(o) {
|
|
20623
|
+
const b = o.task.bucket ?? '';
|
|
20624
|
+
const s = this.sources().find((x) => x.id === b);
|
|
20625
|
+
return o.task.color || s?.color || 'var(--cad-accent)';
|
|
20626
|
+
}
|
|
20627
|
+
nomSource(o) {
|
|
20628
|
+
const b = o.task.bucket ?? '';
|
|
20629
|
+
return this.sources().find((x) => x.id === b)?.label ?? b;
|
|
20630
|
+
}
|
|
20631
|
+
heure(d) {
|
|
20632
|
+
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`;
|
|
20633
|
+
}
|
|
20634
|
+
titre(o) {
|
|
20635
|
+
const q = o.allDay ? 'journée entière' : `${this.heure(o.start)} – ${this.heure(o.end)}`;
|
|
20636
|
+
const s = this.nomSource(o);
|
|
20637
|
+
return `${o.task.label} · ${q}${s ? ' · ' + s : ''}${o.recurring ? ' · récurrent' : ''}`;
|
|
20638
|
+
}
|
|
20639
|
+
/**
|
|
20640
|
+
* Une occurrence de SÉRIE n'est pas manipulable tant que l'édition de récurrence n'existe
|
|
20641
|
+
* pas. Bouger l'une d'elles sans savoir si l'on modifie l'occurrence, la suite ou toute la
|
|
20642
|
+
* série perdrait la modification EN SILENCE. On le montre (hachures, curseur interdit,
|
|
20643
|
+
* motif au survol) plutôt que de laisser essayer et rater.
|
|
20644
|
+
*/
|
|
20645
|
+
manipulable(o) {
|
|
20646
|
+
return this.editable() && !o.recurring && !o.task.locked;
|
|
20647
|
+
}
|
|
20648
|
+
motifVerrou(o) {
|
|
20649
|
+
if (!this.editable())
|
|
20650
|
+
return '';
|
|
20651
|
+
if (o.task.locked)
|
|
20652
|
+
return 'Verrouillé';
|
|
20653
|
+
if (o.recurring)
|
|
20654
|
+
return 'Série : édition au lot récurrence';
|
|
20655
|
+
return '';
|
|
20656
|
+
}
|
|
20657
|
+
geometrie(largeurJour) {
|
|
20658
|
+
return {
|
|
20659
|
+
hauteurHeure: this.hourHeight(),
|
|
20660
|
+
largeurJour,
|
|
20661
|
+
pas: Math.max(1, this.snap()),
|
|
20662
|
+
plageDebut: this.dayStart() * 60,
|
|
20663
|
+
plageFin: this.dayEnd() * 60,
|
|
20664
|
+
};
|
|
20665
|
+
}
|
|
20666
|
+
/**
|
|
20667
|
+
* Un glisser ne doit PAS produire aussi un clic.
|
|
20668
|
+
*
|
|
20669
|
+
* Le navigateur synthétise un `click` après tout `pointerup` sur un bouton : sans cette
|
|
20670
|
+
* garde, déplacer un événement émettait `eventMove` PUIS `eventClick`, et un hôte qui ouvre
|
|
20671
|
+
* une fiche au clic en ouvrirait une à chaque déplacement. Constaté au navigateur le
|
|
20672
|
+
* 22/08/2026 — un test unitaire ne l'aurait pas vu, le clic synthétique n'existe pas en jsdom.
|
|
20673
|
+
*/
|
|
20674
|
+
finGeste = 0;
|
|
20675
|
+
poser(o, bornes) {
|
|
20676
|
+
const p = this.patch();
|
|
20677
|
+
const map = p.src === this.plan() ? new Map(p.map) : new Map();
|
|
20678
|
+
map.set(o.id, bornes);
|
|
20679
|
+
this.patch.set({ src: this.plan(), map });
|
|
20680
|
+
}
|
|
20681
|
+
/**
|
|
20682
|
+
* Un geste au pointeur. Le patron vient de `cadStartResize` de `cad-table` : on écoute sur
|
|
20683
|
+
* le DOCUMENT, pas sur l'élément — sinon le geste s'interrompt dès que le pointeur sort de
|
|
20684
|
+
* la barre, ce qui arrive tout le temps quand on déplace vite.
|
|
20685
|
+
*/
|
|
20686
|
+
geste(kind, o, ev, colonne) {
|
|
20687
|
+
if (!this.manipulable(o))
|
|
20688
|
+
return;
|
|
20689
|
+
ev.preventDefault();
|
|
20690
|
+
ev.stopPropagation();
|
|
20691
|
+
const g = this.geometrie(colonne?.getBoundingClientRect().width ?? 0);
|
|
20692
|
+
const base = { start: o.start, end: o.end, allDay: o.allDay };
|
|
20693
|
+
const x0 = ev.clientX, y0 = ev.clientY;
|
|
20694
|
+
let bouge = false;
|
|
20695
|
+
const projette = (e) => cadProjeterEdition(kind, base, e.clientX - x0, e.clientY - y0, g);
|
|
20696
|
+
const move = (e) => { bouge = true; this.poser(o, projette(e)); };
|
|
20697
|
+
const up = (e) => {
|
|
20698
|
+
document.removeEventListener('pointermove', move);
|
|
20699
|
+
document.removeEventListener('pointerup', up);
|
|
20700
|
+
if (!bouge)
|
|
20701
|
+
return;
|
|
20702
|
+
this.finGeste = Date.now();
|
|
20703
|
+
const b = projette(e);
|
|
20704
|
+
if (b.start.getTime() === base.start.getTime() && b.end.getTime() === base.end.getTime())
|
|
20705
|
+
return;
|
|
20706
|
+
this.poser(o, b);
|
|
20707
|
+
const charge = { occurrence: o, start: b.start, end: b.end };
|
|
20708
|
+
(kind === 'move' ? this.eventMove : this.eventResize).emit(charge);
|
|
20709
|
+
};
|
|
20710
|
+
document.addEventListener('pointermove', move);
|
|
20711
|
+
document.addEventListener('pointerup', up);
|
|
20712
|
+
}
|
|
20713
|
+
/**
|
|
20714
|
+
* Geste dans la GRILLE DE MOIS — projection différente, et c'est la correction du 22/08/2026.
|
|
20715
|
+
*
|
|
20716
|
+
* Ici l'axe vertical n'est pas l'heure : c'est la semaine. Une rangée vaut SEPT JOURS et
|
|
20717
|
+
* l'heure ne bouge pas. En passant par la projection horaire, glisser d'une rangée déplaçait
|
|
20718
|
+
* un rendez-vous de 10 h 30 à 13 h 30 sans changer de date — mesuré au navigateur, signalé
|
|
20719
|
+
* par SZU. On MESURE la rangée plutôt que de la calculer : sa hauteur dépend du nombre de
|
|
20720
|
+
* voies de bandeaux, donc elle change d'une semaine à l'autre.
|
|
20721
|
+
*/
|
|
20722
|
+
gesteMois(kind, o, ev) {
|
|
20723
|
+
if (!this.manipulable(o))
|
|
20724
|
+
return;
|
|
20725
|
+
ev.preventDefault();
|
|
20726
|
+
ev.stopPropagation();
|
|
20727
|
+
const el = this.hote.nativeElement;
|
|
20728
|
+
const rangee = ev.target.closest('.mois__sem') ?? el.querySelector('.mois__sem');
|
|
20729
|
+
const g = {
|
|
20730
|
+
largeurJour: el.querySelector('.mois__jour')?.getBoundingClientRect().width ?? 0,
|
|
20731
|
+
hauteurRangee: rangee?.getBoundingClientRect().height ?? 0,
|
|
20732
|
+
};
|
|
20733
|
+
const base = { start: o.start, end: o.end, allDay: o.allDay };
|
|
20734
|
+
const x0 = ev.clientX, y0 = ev.clientY;
|
|
20735
|
+
let bouge = false;
|
|
20736
|
+
const projette = (e) => cadProjeterMois(kind, base, e.clientX - x0, e.clientY - y0, g);
|
|
20737
|
+
const move = (e) => { bouge = true; this.poser(o, projette(e)); };
|
|
20738
|
+
const up = (e) => {
|
|
20739
|
+
document.removeEventListener('pointermove', move);
|
|
20740
|
+
document.removeEventListener('pointerup', up);
|
|
20741
|
+
if (!bouge)
|
|
20742
|
+
return;
|
|
20743
|
+
this.finGeste = Date.now();
|
|
20744
|
+
const b = projette(e);
|
|
20745
|
+
if (b.start.getTime() === base.start.getTime() && b.end.getTime() === base.end.getTime())
|
|
20746
|
+
return;
|
|
20747
|
+
this.poser(o, b);
|
|
20748
|
+
const charge = { occurrence: o, start: b.start, end: b.end };
|
|
20749
|
+
(kind === 'move' ? this.eventMove : this.eventResize).emit(charge);
|
|
20750
|
+
};
|
|
20751
|
+
document.addEventListener('pointermove', move);
|
|
20752
|
+
document.addEventListener('pointerup', up);
|
|
20753
|
+
}
|
|
20754
|
+
/** Création par glisser sur une plage libre. Un clic sec produit un pas, jamais rien. */
|
|
20755
|
+
creer(jour, ev, colonne) {
|
|
20756
|
+
if (!this.editable())
|
|
20757
|
+
return;
|
|
20758
|
+
if (ev.target.closest('.evt'))
|
|
20759
|
+
return;
|
|
20760
|
+
ev.preventDefault();
|
|
20761
|
+
const rect = colonne.getBoundingClientRect();
|
|
20762
|
+
const g = this.geometrie(rect.width);
|
|
20763
|
+
const y0 = ev.clientY - rect.top;
|
|
20764
|
+
const cle = cadNumeroJour(jour);
|
|
20765
|
+
const dessine = (y1) => {
|
|
20766
|
+
const b = cadProjeterCreation(jour, y0, y1, g);
|
|
20767
|
+
const h = (o) => (o.getHours() * 60 + o.getMinutes() - g.plageDebut) / 60 * g.hauteurHeure;
|
|
20768
|
+
this.fantome.set({ jour: cle, haut: h(b.start), hauteur: Math.max(12, h(b.end) - h(b.start)),
|
|
20769
|
+
texte: this.heure(b.start) + ' – ' + this.heure(b.end) });
|
|
20770
|
+
return b;
|
|
20771
|
+
};
|
|
20772
|
+
dessine(y0);
|
|
20773
|
+
const move = (e) => dessine(e.clientY - rect.top);
|
|
20774
|
+
const up = (e) => {
|
|
20775
|
+
document.removeEventListener('pointermove', move);
|
|
20776
|
+
document.removeEventListener('pointerup', up);
|
|
20777
|
+
const b = cadProjeterCreation(jour, y0, e.clientY - rect.top, g);
|
|
20778
|
+
this.fantome.set(null);
|
|
20779
|
+
this.finGeste = Date.now();
|
|
20780
|
+
this.eventCreate.emit({ start: b.start, end: b.end, allDay: false });
|
|
20781
|
+
};
|
|
20782
|
+
document.addEventListener('pointermove', move);
|
|
20783
|
+
document.addEventListener('pointerup', up);
|
|
20784
|
+
}
|
|
20785
|
+
/**
|
|
20786
|
+
* Le CLAVIER passe par la MÊME projection que le pointeur — une seule logique de placement
|
|
20787
|
+
* à éprouver, et l'accessibilité n'est pas une reprise ultérieure qui dérive.
|
|
20788
|
+
* Ctrl/Cmd + flèches déplacent, Maj + flèches verticales redimensionnent par le bas.
|
|
20789
|
+
*/
|
|
20790
|
+
clavier(o, e) {
|
|
20791
|
+
if (!this.manipulable(o))
|
|
20792
|
+
return;
|
|
20793
|
+
const fleches = {
|
|
20794
|
+
ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1],
|
|
20795
|
+
};
|
|
20796
|
+
const d = fleches[e.key];
|
|
20797
|
+
if (!d)
|
|
20798
|
+
return;
|
|
20799
|
+
const deplace = e.ctrlKey || e.metaKey;
|
|
20800
|
+
const taille = e.shiftKey;
|
|
20801
|
+
if (!deplace && !taille)
|
|
20802
|
+
return;
|
|
20803
|
+
e.preventDefault();
|
|
20804
|
+
const g = this.geometrie(1);
|
|
20805
|
+
const base = { start: o.start, end: o.end, allDay: o.allDay };
|
|
20806
|
+
const kind = taille ? 'resize-end' : 'move';
|
|
20807
|
+
const b = cadProjeterEdition(kind, base, d[0] * g.largeurJour, (d[1] * g.pas / 60) * g.hauteurHeure, g);
|
|
20808
|
+
this.poser(o, b);
|
|
20809
|
+
(kind === 'move' ? this.eventMove : this.eventResize).emit({ occurrence: o, start: b.start, end: b.end });
|
|
20810
|
+
}
|
|
20811
|
+
clicEvenement(occurrence, originalEvent) {
|
|
20812
|
+
// Le clic qui SUIT un glisser est celui du navigateur, pas celui de l'utilisateur.
|
|
20813
|
+
if (Date.now() - this.finGeste < 300)
|
|
20814
|
+
return;
|
|
20815
|
+
this.eventClick.emit({ occurrence, originalEvent });
|
|
20816
|
+
}
|
|
20817
|
+
/** Le « +N » et un jour de la vue année mènent au JOUR : c'est ce qu'on cherchait. */
|
|
20818
|
+
voirJour(date, originalEvent) {
|
|
20819
|
+
this.dateClick.emit({ date, originalEvent });
|
|
20820
|
+
this.date.set(date);
|
|
20821
|
+
if (this.view() !== 'auto')
|
|
20822
|
+
this.view.set('day');
|
|
20823
|
+
}
|
|
20824
|
+
constructor() {
|
|
20825
|
+
// La fenêtre est annoncée : un hôte qui charge à la demande sait quoi aller chercher.
|
|
20826
|
+
let derniere = '';
|
|
20827
|
+
setTimeout(() => {
|
|
20828
|
+
const f = this.fenetre();
|
|
20829
|
+
const k = f.start.toISOString() + f.end.toISOString();
|
|
20830
|
+
if (k !== derniere) {
|
|
20831
|
+
derniere = k;
|
|
20832
|
+
this.rangeChange.emit(f);
|
|
20833
|
+
}
|
|
20834
|
+
});
|
|
20835
|
+
}
|
|
20836
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadCalendarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
20837
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CadCalendarComponent, isStandalone: true, selector: "cad-calendar", inputs: { plan: { classPropertyName: "plan", publicName: "plan", isSignal: true, isRequired: false, transformFunction: null }, sources: { classPropertyName: "sources", publicName: "sources", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, view: { classPropertyName: "view", publicName: "view", isSignal: true, isRequired: false, transformFunction: null }, date: { classPropertyName: "date", publicName: "date", isSignal: true, isRequired: false, transformFunction: null }, firstDay: { classPropertyName: "firstDay", publicName: "firstDay", isSignal: true, isRequired: false, transformFunction: null }, dayStart: { classPropertyName: "dayStart", publicName: "dayStart", isSignal: true, isRequired: false, transformFunction: null }, dayEnd: { classPropertyName: "dayEnd", publicName: "dayEnd", isSignal: true, isRequired: false, transformFunction: null }, hourHeight: { classPropertyName: "hourHeight", publicName: "hourHeight", isSignal: true, isRequired: false, transformFunction: null }, maxPerDay: { classPropertyName: "maxPerDay", publicName: "maxPerDay", isSignal: true, isRequired: false, transformFunction: null }, workCalendar: { classPropertyName: "workCalendar", publicName: "workCalendar", isSignal: true, isRequired: false, transformFunction: null }, today: { classPropertyName: "today", publicName: "today", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, showNow: { classPropertyName: "showNow", publicName: "showNow", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { hidden: "hiddenChange", view: "viewChange", date: "dateChange", eventClick: "eventClick", dateClick: "dateClick", rangeChange: "rangeChange", eventMove: "eventMove", eventResize: "eventResize", eventCreate: "eventCreate" }, host: { attributes: { "role": "region" }, properties: { "attr.aria-label": "ariaLabel() || null" }, classAttribute: "cad-calendar" }, ngImport: i0, template: `
|
|
20838
|
+
<div class="cal__corps">
|
|
20839
|
+
<div class="cal__vue">
|
|
20840
|
+
@switch (vueEffective()) {
|
|
20841
|
+
@case ('month') {
|
|
20842
|
+
<div class="mois">
|
|
20843
|
+
@for (n of nomsJours(); track $index) { <div class="mois__jsem">{{ n }}</div> }
|
|
20844
|
+
@for (sem of semaines(); track $index) {
|
|
20845
|
+
<div class="mois__sem">
|
|
20846
|
+
@for (j of sem.jours; track j.cle) {
|
|
20847
|
+
<div class="mois__jour"
|
|
20848
|
+
[class.is-hors]="j.hors" [class.is-auj]="j.auj" [class.is-ferme]="j.ferme">
|
|
20849
|
+
<div class="mois__n">{{ j.n }}</div>
|
|
20850
|
+
<!-- La place des bandeaux est RÉSERVÉE dans chaque case : le calque étant
|
|
20851
|
+
en position absolue, sans cette réserve il recouvrirait les puces. -->
|
|
20852
|
+
<div class="mois__reserve" [style.height.px]="sem.voies * 19"></div>
|
|
20853
|
+
@for (o of j.puces; track o.id) {
|
|
20854
|
+
<button type="button" class="puce"
|
|
20855
|
+
[class.is-editable]="manipulable(o)"
|
|
20856
|
+
[class.is-verrouille]="editable() && !manipulable(o)"
|
|
20857
|
+
[style.--_c]="couleur(o)"
|
|
20858
|
+
[title]="titre(o) + (motifVerrou(o) ? ' · ' + motifVerrou(o) : '')"
|
|
20859
|
+
(pointerdown)="gesteMois('move', o, $event)"
|
|
20860
|
+
(keydown)="clavier(o, $event)"
|
|
20861
|
+
(click)="clicEvenement(o, $event)">
|
|
20862
|
+
@if (!o.allDay) { <span class="puce__h">{{ heure(o.start) }}</span> }
|
|
20863
|
+
<span class="puce__t">{{ o.task.label }}</span>
|
|
20864
|
+
@if (o.recurring) { <span aria-hidden="true">↻</span> }
|
|
20865
|
+
</button>
|
|
20866
|
+
}
|
|
20867
|
+
@if (j.reste > 0) {
|
|
20868
|
+
<button type="button" class="plus" (click)="voirJour(j.date, $event)">
|
|
20869
|
+
+{{ j.reste }} autre{{ j.reste > 1 ? 's' : '' }}
|
|
20870
|
+
</button>
|
|
20871
|
+
}
|
|
20872
|
+
</div>
|
|
20873
|
+
}
|
|
20874
|
+
<!-- CALQUE DES BANDEAUX : un multi-jours doit être CONTINU d'un jour à
|
|
20875
|
+
l'autre. Le dessiner dans chaque case le répéterait ; il vit donc
|
|
20876
|
+
au-dessus de la rangée, en pourcentages de sa largeur. -->
|
|
20877
|
+
<div class="calque" [style.top.px]="20">
|
|
20878
|
+
@for (b of sem.bandes; track b.occurrence.id) {
|
|
20879
|
+
<button type="button" class="bandeau"
|
|
20880
|
+
[class.is-avant]="b.continueAvant" [class.is-apres]="b.continueApres"
|
|
20881
|
+
[class.is-editable]="manipulable(b.occurrence)"
|
|
20882
|
+
[class.is-verrouille]="editable() && !manipulable(b.occurrence)"
|
|
20883
|
+
[style.--_c]="couleur(b.occurrence)"
|
|
20884
|
+
[style.left.%]="b.colDebut / 7 * 100"
|
|
20885
|
+
[style.width.%]="(b.colFin - b.colDebut + 1) / 7 * 100"
|
|
20886
|
+
[style.top.px]="b.voie * 19"
|
|
20887
|
+
[title]="titre(b.occurrence) + (motifVerrou(b.occurrence) ? ' · ' + motifVerrou(b.occurrence) : '')"
|
|
20888
|
+
(pointerdown)="gesteMois('move', b.occurrence, $event)"
|
|
20889
|
+
(keydown)="clavier(b.occurrence, $event)"
|
|
20890
|
+
(click)="clicEvenement(b.occurrence, $event)">
|
|
20891
|
+
{{ b.continueAvant ? '◀ ' : '' }}{{ b.occurrence.task.label }}{{ b.continueApres ? ' ▶' : '' }}
|
|
20892
|
+
@if (manipulable(b.occurrence)) {
|
|
20893
|
+
<span class="poignee is-haut" (pointerdown)="gesteMois('resize-start', b.occurrence, $event)"></span>
|
|
20894
|
+
<span class="poignee is-bas" (pointerdown)="gesteMois('resize-end', b.occurrence, $event)"></span>
|
|
20895
|
+
}
|
|
20896
|
+
</button>
|
|
20897
|
+
}
|
|
20898
|
+
</div>
|
|
20899
|
+
</div>
|
|
20900
|
+
}
|
|
20901
|
+
</div>
|
|
20902
|
+
}
|
|
20903
|
+
|
|
20904
|
+
@case ('agenda') {
|
|
20905
|
+
<div class="agenda">
|
|
20906
|
+
@for (g of groupes(); track g.cle) {
|
|
20907
|
+
<div class="ag__jour">
|
|
20908
|
+
<div class="ag__d" [class.is-auj]="g.auj"><b>{{ g.n }}</b><span>{{ g.jsem }}</span></div>
|
|
20909
|
+
<div class="ag__l">
|
|
20910
|
+
@for (o of g.evts; track o.id) {
|
|
20911
|
+
<button type="button" class="ag__e" [style.--_c]="couleur(o)" (click)="clicEvenement(o, $event)">
|
|
20912
|
+
<span class="ag__p"></span>
|
|
20913
|
+
<span class="ag__h">{{ o.allDay ? 'journée' : heure(o.start) + ' – ' + heure(o.end) }}</span>
|
|
20914
|
+
<span class="ag__t">{{ o.task.label }}@if (o.recurring) { <span aria-hidden="true"> ↻</span> }</span>
|
|
20915
|
+
<span class="ag__c">{{ nomSource(o) }}</span>
|
|
20916
|
+
</button>
|
|
20917
|
+
}
|
|
20918
|
+
</div>
|
|
20919
|
+
</div>
|
|
20920
|
+
} @empty { <div class="vide">{{ emptyText() }}</div> }
|
|
20921
|
+
</div>
|
|
20922
|
+
}
|
|
20923
|
+
|
|
20924
|
+
@case ('year') {
|
|
20925
|
+
<div class="annee">
|
|
20926
|
+
@for (m of miniMois(); track m.mois) {
|
|
20927
|
+
<div class="mm">
|
|
20928
|
+
<div class="mm__t">{{ m.titre }}</div>
|
|
20929
|
+
<div class="mm__g">
|
|
20930
|
+
@for (n of nomsJours(); track $index) { <span>{{ n.charAt(0) }}</span> }
|
|
20931
|
+
@for (j of m.jours; track j.cle) {
|
|
20932
|
+
<button type="button" [class.is-hors]="j.hors" [class.is-auj]="j.auj"
|
|
20933
|
+
[title]="j.charge ? j.charge + ' événement(s)' : ''"
|
|
20934
|
+
(click)="voirJour(j.date, $event)">
|
|
20935
|
+
{{ j.n }}@if (j.charge) { <span class="mm__pt"></span> }
|
|
20936
|
+
</button>
|
|
20937
|
+
}
|
|
20938
|
+
</div>
|
|
20939
|
+
</div>
|
|
20940
|
+
}
|
|
20941
|
+
</div>
|
|
20942
|
+
}
|
|
20943
|
+
|
|
20944
|
+
@default {
|
|
20945
|
+
<div class="grille">
|
|
20946
|
+
<div class="grille__hd" [style.grid-template-columns]="colonnes()">
|
|
20947
|
+
<div></div>
|
|
20948
|
+
@for (j of joursGrille(); track j.cle) {
|
|
20949
|
+
<div [class.is-auj]="j.auj"><div class="grille__d">{{ j.jsem }}</div><div class="grille__n">{{ j.n }}</div></div>
|
|
20950
|
+
}
|
|
20951
|
+
</div>
|
|
20952
|
+
|
|
20953
|
+
<div class="bande" [style.grid-template-columns]="colonnes()">
|
|
20954
|
+
<div class="bande__lbl">jour</div>
|
|
20955
|
+
<div class="bande__zone" [style.height.px]="Math.max(1, bandeGrille().voies) * 19 + 2">
|
|
20956
|
+
@for (b of bandeGrille().bandes; track b.occurrence.id) {
|
|
20957
|
+
<button type="button" class="bandeau" #bd
|
|
20958
|
+
[class.is-avant]="b.continueAvant" [class.is-apres]="b.continueApres"
|
|
20959
|
+
[class.is-editable]="manipulable(b.occurrence)"
|
|
20960
|
+
[class.is-verrouille]="editable() && !manipulable(b.occurrence)"
|
|
20961
|
+
[style.--_c]="couleur(b.occurrence)"
|
|
20962
|
+
[style.left.%]="b.colDebut / joursGrille().length * 100"
|
|
20963
|
+
[style.width.%]="(b.colFin - b.colDebut + 1) / joursGrille().length * 100"
|
|
20964
|
+
[style.top.px]="b.voie * 19"
|
|
20965
|
+
[title]="titre(b.occurrence) + (motifVerrou(b.occurrence) ? ' · ' + motifVerrou(b.occurrence) : '')"
|
|
20966
|
+
(pointerdown)="geste('move', b.occurrence, $event, largeurColonne())"
|
|
20967
|
+
(keydown)="clavier(b.occurrence, $event)"
|
|
20968
|
+
(click)="clicEvenement(b.occurrence, $event)">
|
|
20969
|
+
{{ b.continueAvant ? '◀ ' : '' }}{{ b.occurrence.task.label }}{{ b.continueApres ? ' ▶' : '' }}
|
|
20970
|
+
@if (manipulable(b.occurrence)) {
|
|
20971
|
+
<span class="poignee is-haut" (pointerdown)="geste('resize-start', b.occurrence, $event, largeurColonne())"></span>
|
|
20972
|
+
<span class="poignee is-bas" (pointerdown)="geste('resize-end', b.occurrence, $event, largeurColonne())"></span>
|
|
20973
|
+
}
|
|
20974
|
+
</button>
|
|
20975
|
+
}
|
|
20976
|
+
</div>
|
|
20977
|
+
</div>
|
|
20978
|
+
|
|
20979
|
+
<div class="heures" [style.grid-template-columns]="colonnes()">
|
|
20980
|
+
<div class="heures__lbl">
|
|
20981
|
+
@for (h of heuresAffichees(); track h) { <div [style.height.px]="hauteurHeure()">{{ h }}h</div> }
|
|
20982
|
+
</div>
|
|
20983
|
+
@for (j of joursGrille(); track j.cle) {
|
|
20984
|
+
<div class="heures__col" #col [class.is-ferme]="j.ferme"
|
|
20985
|
+
(pointerdown)="creer(j.date, $event, col)">
|
|
20986
|
+
@for (h of heuresAffichees(); track h) {
|
|
20987
|
+
<div class="trait" [style.top.px]="(h - dayStart()) * hauteurHeure()"></div>
|
|
20988
|
+
<div class="trait is-demi" [style.top.px]="(h - dayStart()) * hauteurHeure() + hauteurHeure() / 2"></div>
|
|
20989
|
+
}
|
|
20990
|
+
@for (s of j.slots; track s.occurrence.id) {
|
|
20991
|
+
<button type="button" class="evt"
|
|
20992
|
+
[class.is-editable]="manipulable(s.occurrence)"
|
|
20993
|
+
[class.is-verrouille]="editable() && !manipulable(s.occurrence)"
|
|
20994
|
+
[style.--_c]="couleur(s.occurrence)"
|
|
20995
|
+
[style.top.px]="s.haut * hauteurTotale()"
|
|
20996
|
+
[style.height.px]="Math.max(16, s.hauteur * hauteurTotale() - 2)"
|
|
20997
|
+
[style.left]="'calc(' + (s.voie / s.voies * 100) + '% + 1px)'"
|
|
20998
|
+
[style.width]="'calc(' + (100 / s.voies) + '% - 3px)'"
|
|
20999
|
+
[title]="titre(s.occurrence) + (motifVerrou(s.occurrence) ? ' · ' + motifVerrou(s.occurrence) : '')"
|
|
21000
|
+
(pointerdown)="geste('move', s.occurrence, $event, col)"
|
|
21001
|
+
(keydown)="clavier(s.occurrence, $event)"
|
|
21002
|
+
(click)="clicEvenement(s.occurrence, $event)">
|
|
21003
|
+
<span class="evt__t">{{ s.occurrence.task.label }}@if (s.occurrence.recurring) { <span aria-hidden="true"> ↻</span> }</span>
|
|
21004
|
+
@if (s.hauteur * hauteurTotale() > 30) {
|
|
21005
|
+
<span class="evt__h">{{ heure(s.occurrence.start) }} – {{ heure(s.occurrence.end) }}</span>
|
|
21006
|
+
}
|
|
21007
|
+
@if (manipulable(s.occurrence)) {
|
|
21008
|
+
<span class="poignee is-haut" (pointerdown)="geste('resize-start', s.occurrence, $event, col)"></span>
|
|
21009
|
+
<span class="poignee is-bas" (pointerdown)="geste('resize-end', s.occurrence, $event, col)"></span>
|
|
21010
|
+
}
|
|
21011
|
+
</button>
|
|
21012
|
+
}
|
|
21013
|
+
@if (fantome(); as f) {
|
|
21014
|
+
@if (f.jour === j.cle) {
|
|
21015
|
+
<div class="fantome" [style.top.px]="f.haut" [style.height.px]="f.hauteur"
|
|
21016
|
+
[style.left.px]="2" [style.right.px]="2">{{ f.texte }}</div>
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
21019
|
+
@if (j.auj && maintenant() !== null) {
|
|
21020
|
+
<div class="maintenant" [style.top.px]="maintenant()"></div>
|
|
21021
|
+
}
|
|
21022
|
+
</div>
|
|
21023
|
+
}
|
|
21024
|
+
</div>
|
|
21025
|
+
</div>
|
|
21026
|
+
}
|
|
21027
|
+
}
|
|
21028
|
+
</div>
|
|
21029
|
+
</div>
|
|
21030
|
+
`, isInline: true, styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%;font:var(--cad-font-size)/1.4 var(--cad-font);color:var(--cad-fg);background:var(--cad-bg)}.cal__corps{flex:1;min-height:0;display:flex}.cal__vue{flex:1;min-width:0;min-height:0;overflow:auto}.mois{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));grid-template-rows:auto;grid-auto-rows:minmax(84px,1fr);min-height:100%}.mois__jsem{padding:6px 8px;text-align:right;border-bottom:1px solid var(--cad-border-strong);background:var(--cad-bg-subtle);position:sticky;top:0;z-index:4;font:600 10.5px var(--cad-font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--cad-fg-muted)}.mois__sem{grid-column:1 / -1;display:grid;grid-template-columns:repeat(7,minmax(0,1fr));position:relative;border-bottom:1px solid var(--cad-border);min-height:84px}.mois__jour{border-right:1px solid var(--cad-border);padding:3px;min-width:0;display:flex;flex-direction:column;gap:2px}.mois__jour:last-child{border-right:0}.mois__jour.is-hors,.mois__jour.is-ferme{background:var(--cad-bg-subtle)}.mois__n{font:11px var(--cad-font-mono);color:var(--cad-fg-secondary);text-align:right;padding:1px 3px;font-variant-numeric:tabular-nums;flex:none}.mois__jour.is-auj .mois__n{background:var(--cad-accent);color:var(--cad-fg-on-accent);border-radius:var(--cad-radius-sm);font-weight:600}.mois__reserve{flex:none}.calque{position:absolute;left:0;right:0;pointer-events:none;z-index:2}.bandeau{position:absolute;height:17px;border-radius:var(--cad-radius-sm);padding:0 7px;font-size:10.5px;line-height:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:auto;cursor:pointer;background:color-mix(in srgb,var(--_c) 22%,transparent);color:var(--_c);border:1px solid color-mix(in srgb,var(--_c) 42%,transparent)}.bandeau.is-avant{border-top-left-radius:0;border-bottom-left-radius:0;border-left-style:dashed}.bandeau.is-apres{border-top-right-radius:0;border-bottom-right-radius:0;border-right-style:dashed}.puce{display:flex;align-items:center;gap:5px;font-size:10.5px;padding:1px 5px;border-radius:var(--cad-radius-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;border-left:2px solid var(--_c);background:color-mix(in srgb,var(--_c) 13%,transparent);color:var(--_c)}.puce:hover{background:color-mix(in srgb,var(--_c) 22%,transparent)}.puce__h{font:9.5px var(--cad-font-mono);opacity:.85;flex:none;font-variant-numeric:tabular-nums}.puce__t{min-width:0;overflow:hidden;text-overflow:ellipsis}.plus{all:unset;box-sizing:border-box;font-size:10px;color:var(--cad-fg-muted);padding:1px 5px;cursor:pointer;border-radius:var(--cad-radius-sm)}.plus:hover{color:var(--cad-accent);background:var(--cad-hover)}.grille{min-width:0;display:flex;flex-direction:column;height:100%}.grille__hd{display:grid;position:sticky;top:0;z-index:5;background:var(--cad-bg-subtle);border-bottom:1px solid var(--cad-border-strong);flex:none}.grille__hd>div{padding:5px 6px;text-align:center;border-right:1px solid var(--cad-border);min-width:0}.grille__hd>div:last-child{border-right:0}.grille__d{font:10px var(--cad-font-mono);color:var(--cad-fg-muted);text-transform:uppercase;letter-spacing:.06em}.grille__n{font-size:16px;font-weight:600;letter-spacing:-.02em}.is-auj .grille__n{color:var(--cad-accent)}.bande{display:grid;border-bottom:1px solid var(--cad-border-strong);background:var(--cad-bg-subtle);flex:none}.bande__lbl{font:9px var(--cad-font-mono);color:var(--cad-fg-muted);padding:4px 6px;text-align:right;border-right:1px solid var(--cad-border)}.bande__zone{grid-column:2 / -1;position:relative;padding:2px 0}.heures{display:grid;position:relative;flex:1;min-height:0;overflow:auto}.heures__lbl{border-right:1px solid var(--cad-border)}.heures__lbl>div{font:9.5px var(--cad-font-mono);color:var(--cad-fg-muted);text-align:right;padding-right:6px;transform:translateY(-6px)}.heures__col{border-right:1px solid var(--cad-border);position:relative;min-width:0}.heures__col:last-child{border-right:0}.heures__col.is-ferme{background:var(--cad-bg-subtle)}.trait{position:absolute;left:0;right:0;border-top:1px solid var(--cad-border);pointer-events:none}.trait.is-demi{border-top-style:dotted;opacity:.55}.evt{position:absolute;border-radius:var(--cad-radius-sm);padding:1px 5px;overflow:hidden;cursor:pointer;border-left:3px solid var(--_c);font-size:10.5px;line-height:1.25;background:color-mix(in srgb,var(--_c) 15%,transparent);color:var(--_c)}.evt:hover{background:color-mix(in srgb,var(--_c) 26%,transparent)}.evt__t{display:block;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.evt__h{font:9px var(--cad-font-mono);opacity:.85}.maintenant{position:absolute;left:0;right:0;height:2px;background:var(--cad-danger);z-index:4;pointer-events:none}.maintenant:before{content:\"\";position:absolute;left:-3px;top:-3px;width:8px;height:8px;border-radius:50%;background:var(--cad-danger)}.agenda{display:flex;flex-direction:column}.ag__jour{display:grid;grid-template-columns:72px minmax(0,1fr);border-bottom:1px solid var(--cad-border)}.ag__d{padding:9px 11px;border-right:1px solid var(--cad-border);background:var(--cad-bg-subtle)}.ag__d b{display:block;font-size:18px;font-weight:600;letter-spacing:-.02em}.ag__d span{display:block;font:9.5px var(--cad-font-mono);color:var(--cad-fg-muted);text-transform:uppercase}.ag__d.is-auj b{color:var(--cad-accent)}.ag__l{padding:5px 0;min-width:0}.ag__e{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:9px;padding:6px 11px;cursor:pointer;width:100%;min-height:34px}.ag__e:hover{background:var(--cad-hover)}.ag__e:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.ag__p{width:8px;height:8px;border-radius:50%;background:var(--_c);flex:none}.ag__h{font:11px var(--cad-font-mono);color:var(--cad-fg-secondary);flex:none;width:92px;font-variant-numeric:tabular-nums}.ag__t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag__c{margin-left:auto;font-size:10.5px;color:var(--cad-fg-muted);flex:none}.annee{display:grid;grid-template-columns:repeat(auto-fill,minmax(178px,1fr));gap:14px;padding:14px}.mm{border:1px solid var(--cad-border);border-radius:var(--cad-radius);padding:8px;background:var(--cad-surface)}.mm__t{font-size:12px;font-weight:600;margin-bottom:5px;text-transform:capitalize}.mm__g{display:grid;grid-template-columns:repeat(7,1fr);gap:1px}.mm__g>span,.mm__g>button{all:unset;box-sizing:border-box;text-align:center;font:9.5px var(--cad-font-mono);padding:2px 0;border-radius:3px;color:var(--cad-fg-secondary);font-variant-numeric:tabular-nums}.mm__g>span{color:var(--cad-fg-muted);font-weight:500}.mm__g>button{cursor:pointer;position:relative}.mm__g>button:hover{background:var(--cad-hover)}.mm__g>button.is-hors{opacity:.35}.mm__g>button.is-auj{background:var(--cad-accent);color:var(--cad-fg-on-accent);font-weight:600}.mm__pt{position:absolute;left:50%;bottom:0;transform:translate(-50%);width:3px;height:3px;border-radius:50%;background:var(--cad-accent)}.mm__g>button.is-auj .mm__pt{background:var(--cad-fg-on-accent)}.evt.is-editable,.bandeau.is-editable,.puce.is-editable{cursor:grab}.evt.is-editable:active,.bandeau.is-editable:active,.puce.is-editable:active{cursor:grabbing}.poignee{position:absolute;z-index:2}.evt .poignee{left:0;right:0;height:6px;cursor:ns-resize}.evt .poignee.is-haut{top:0}.evt .poignee.is-bas{bottom:0}.bandeau .poignee{top:0;bottom:0;width:6px;cursor:ew-resize}.bandeau .poignee.is-haut{left:0}.bandeau .poignee.is-bas{right:0}.poignee:after{content:\"\";position:absolute;inset:0}.evt.is-verrouille,.bandeau.is-verrouille,.puce.is-verrouille{cursor:not-allowed;position:relative}.evt.is-verrouille:after,.bandeau.is-verrouille:after,.puce.is-verrouille:after{content:\"\";position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(-45deg,currentColor 0 1px,transparent 1px 5px);opacity:.18}.fantome{position:absolute;z-index:6;pointer-events:none;border-radius:var(--cad-radius-sm);background:var(--cad-accent-soft);border:1px dashed var(--cad-accent);color:var(--cad-accent);font:10.5px var(--cad-font-mono);padding:1px 5px;overflow:hidden;white-space:nowrap}.vide{padding:28px 16px;color:var(--cad-fg-muted);text-align:center}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
21031
|
+
}
|
|
21032
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CadCalendarComponent, decorators: [{
|
|
21033
|
+
type: Component,
|
|
21034
|
+
args: [{ selector: 'cad-calendar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'cad-calendar', '[attr.aria-label]': 'ariaLabel() || null', role: 'region' }, template: `
|
|
21035
|
+
<div class="cal__corps">
|
|
21036
|
+
<div class="cal__vue">
|
|
21037
|
+
@switch (vueEffective()) {
|
|
21038
|
+
@case ('month') {
|
|
21039
|
+
<div class="mois">
|
|
21040
|
+
@for (n of nomsJours(); track $index) { <div class="mois__jsem">{{ n }}</div> }
|
|
21041
|
+
@for (sem of semaines(); track $index) {
|
|
21042
|
+
<div class="mois__sem">
|
|
21043
|
+
@for (j of sem.jours; track j.cle) {
|
|
21044
|
+
<div class="mois__jour"
|
|
21045
|
+
[class.is-hors]="j.hors" [class.is-auj]="j.auj" [class.is-ferme]="j.ferme">
|
|
21046
|
+
<div class="mois__n">{{ j.n }}</div>
|
|
21047
|
+
<!-- La place des bandeaux est RÉSERVÉE dans chaque case : le calque étant
|
|
21048
|
+
en position absolue, sans cette réserve il recouvrirait les puces. -->
|
|
21049
|
+
<div class="mois__reserve" [style.height.px]="sem.voies * 19"></div>
|
|
21050
|
+
@for (o of j.puces; track o.id) {
|
|
21051
|
+
<button type="button" class="puce"
|
|
21052
|
+
[class.is-editable]="manipulable(o)"
|
|
21053
|
+
[class.is-verrouille]="editable() && !manipulable(o)"
|
|
21054
|
+
[style.--_c]="couleur(o)"
|
|
21055
|
+
[title]="titre(o) + (motifVerrou(o) ? ' · ' + motifVerrou(o) : '')"
|
|
21056
|
+
(pointerdown)="gesteMois('move', o, $event)"
|
|
21057
|
+
(keydown)="clavier(o, $event)"
|
|
21058
|
+
(click)="clicEvenement(o, $event)">
|
|
21059
|
+
@if (!o.allDay) { <span class="puce__h">{{ heure(o.start) }}</span> }
|
|
21060
|
+
<span class="puce__t">{{ o.task.label }}</span>
|
|
21061
|
+
@if (o.recurring) { <span aria-hidden="true">↻</span> }
|
|
21062
|
+
</button>
|
|
21063
|
+
}
|
|
21064
|
+
@if (j.reste > 0) {
|
|
21065
|
+
<button type="button" class="plus" (click)="voirJour(j.date, $event)">
|
|
21066
|
+
+{{ j.reste }} autre{{ j.reste > 1 ? 's' : '' }}
|
|
21067
|
+
</button>
|
|
21068
|
+
}
|
|
21069
|
+
</div>
|
|
21070
|
+
}
|
|
21071
|
+
<!-- CALQUE DES BANDEAUX : un multi-jours doit être CONTINU d'un jour à
|
|
21072
|
+
l'autre. Le dessiner dans chaque case le répéterait ; il vit donc
|
|
21073
|
+
au-dessus de la rangée, en pourcentages de sa largeur. -->
|
|
21074
|
+
<div class="calque" [style.top.px]="20">
|
|
21075
|
+
@for (b of sem.bandes; track b.occurrence.id) {
|
|
21076
|
+
<button type="button" class="bandeau"
|
|
21077
|
+
[class.is-avant]="b.continueAvant" [class.is-apres]="b.continueApres"
|
|
21078
|
+
[class.is-editable]="manipulable(b.occurrence)"
|
|
21079
|
+
[class.is-verrouille]="editable() && !manipulable(b.occurrence)"
|
|
21080
|
+
[style.--_c]="couleur(b.occurrence)"
|
|
21081
|
+
[style.left.%]="b.colDebut / 7 * 100"
|
|
21082
|
+
[style.width.%]="(b.colFin - b.colDebut + 1) / 7 * 100"
|
|
21083
|
+
[style.top.px]="b.voie * 19"
|
|
21084
|
+
[title]="titre(b.occurrence) + (motifVerrou(b.occurrence) ? ' · ' + motifVerrou(b.occurrence) : '')"
|
|
21085
|
+
(pointerdown)="gesteMois('move', b.occurrence, $event)"
|
|
21086
|
+
(keydown)="clavier(b.occurrence, $event)"
|
|
21087
|
+
(click)="clicEvenement(b.occurrence, $event)">
|
|
21088
|
+
{{ b.continueAvant ? '◀ ' : '' }}{{ b.occurrence.task.label }}{{ b.continueApres ? ' ▶' : '' }}
|
|
21089
|
+
@if (manipulable(b.occurrence)) {
|
|
21090
|
+
<span class="poignee is-haut" (pointerdown)="gesteMois('resize-start', b.occurrence, $event)"></span>
|
|
21091
|
+
<span class="poignee is-bas" (pointerdown)="gesteMois('resize-end', b.occurrence, $event)"></span>
|
|
21092
|
+
}
|
|
21093
|
+
</button>
|
|
21094
|
+
}
|
|
21095
|
+
</div>
|
|
21096
|
+
</div>
|
|
21097
|
+
}
|
|
21098
|
+
</div>
|
|
21099
|
+
}
|
|
21100
|
+
|
|
21101
|
+
@case ('agenda') {
|
|
21102
|
+
<div class="agenda">
|
|
21103
|
+
@for (g of groupes(); track g.cle) {
|
|
21104
|
+
<div class="ag__jour">
|
|
21105
|
+
<div class="ag__d" [class.is-auj]="g.auj"><b>{{ g.n }}</b><span>{{ g.jsem }}</span></div>
|
|
21106
|
+
<div class="ag__l">
|
|
21107
|
+
@for (o of g.evts; track o.id) {
|
|
21108
|
+
<button type="button" class="ag__e" [style.--_c]="couleur(o)" (click)="clicEvenement(o, $event)">
|
|
21109
|
+
<span class="ag__p"></span>
|
|
21110
|
+
<span class="ag__h">{{ o.allDay ? 'journée' : heure(o.start) + ' – ' + heure(o.end) }}</span>
|
|
21111
|
+
<span class="ag__t">{{ o.task.label }}@if (o.recurring) { <span aria-hidden="true"> ↻</span> }</span>
|
|
21112
|
+
<span class="ag__c">{{ nomSource(o) }}</span>
|
|
21113
|
+
</button>
|
|
21114
|
+
}
|
|
21115
|
+
</div>
|
|
21116
|
+
</div>
|
|
21117
|
+
} @empty { <div class="vide">{{ emptyText() }}</div> }
|
|
21118
|
+
</div>
|
|
21119
|
+
}
|
|
21120
|
+
|
|
21121
|
+
@case ('year') {
|
|
21122
|
+
<div class="annee">
|
|
21123
|
+
@for (m of miniMois(); track m.mois) {
|
|
21124
|
+
<div class="mm">
|
|
21125
|
+
<div class="mm__t">{{ m.titre }}</div>
|
|
21126
|
+
<div class="mm__g">
|
|
21127
|
+
@for (n of nomsJours(); track $index) { <span>{{ n.charAt(0) }}</span> }
|
|
21128
|
+
@for (j of m.jours; track j.cle) {
|
|
21129
|
+
<button type="button" [class.is-hors]="j.hors" [class.is-auj]="j.auj"
|
|
21130
|
+
[title]="j.charge ? j.charge + ' événement(s)' : ''"
|
|
21131
|
+
(click)="voirJour(j.date, $event)">
|
|
21132
|
+
{{ j.n }}@if (j.charge) { <span class="mm__pt"></span> }
|
|
21133
|
+
</button>
|
|
21134
|
+
}
|
|
21135
|
+
</div>
|
|
21136
|
+
</div>
|
|
21137
|
+
}
|
|
21138
|
+
</div>
|
|
21139
|
+
}
|
|
21140
|
+
|
|
21141
|
+
@default {
|
|
21142
|
+
<div class="grille">
|
|
21143
|
+
<div class="grille__hd" [style.grid-template-columns]="colonnes()">
|
|
21144
|
+
<div></div>
|
|
21145
|
+
@for (j of joursGrille(); track j.cle) {
|
|
21146
|
+
<div [class.is-auj]="j.auj"><div class="grille__d">{{ j.jsem }}</div><div class="grille__n">{{ j.n }}</div></div>
|
|
21147
|
+
}
|
|
21148
|
+
</div>
|
|
21149
|
+
|
|
21150
|
+
<div class="bande" [style.grid-template-columns]="colonnes()">
|
|
21151
|
+
<div class="bande__lbl">jour</div>
|
|
21152
|
+
<div class="bande__zone" [style.height.px]="Math.max(1, bandeGrille().voies) * 19 + 2">
|
|
21153
|
+
@for (b of bandeGrille().bandes; track b.occurrence.id) {
|
|
21154
|
+
<button type="button" class="bandeau" #bd
|
|
21155
|
+
[class.is-avant]="b.continueAvant" [class.is-apres]="b.continueApres"
|
|
21156
|
+
[class.is-editable]="manipulable(b.occurrence)"
|
|
21157
|
+
[class.is-verrouille]="editable() && !manipulable(b.occurrence)"
|
|
21158
|
+
[style.--_c]="couleur(b.occurrence)"
|
|
21159
|
+
[style.left.%]="b.colDebut / joursGrille().length * 100"
|
|
21160
|
+
[style.width.%]="(b.colFin - b.colDebut + 1) / joursGrille().length * 100"
|
|
21161
|
+
[style.top.px]="b.voie * 19"
|
|
21162
|
+
[title]="titre(b.occurrence) + (motifVerrou(b.occurrence) ? ' · ' + motifVerrou(b.occurrence) : '')"
|
|
21163
|
+
(pointerdown)="geste('move', b.occurrence, $event, largeurColonne())"
|
|
21164
|
+
(keydown)="clavier(b.occurrence, $event)"
|
|
21165
|
+
(click)="clicEvenement(b.occurrence, $event)">
|
|
21166
|
+
{{ b.continueAvant ? '◀ ' : '' }}{{ b.occurrence.task.label }}{{ b.continueApres ? ' ▶' : '' }}
|
|
21167
|
+
@if (manipulable(b.occurrence)) {
|
|
21168
|
+
<span class="poignee is-haut" (pointerdown)="geste('resize-start', b.occurrence, $event, largeurColonne())"></span>
|
|
21169
|
+
<span class="poignee is-bas" (pointerdown)="geste('resize-end', b.occurrence, $event, largeurColonne())"></span>
|
|
21170
|
+
}
|
|
21171
|
+
</button>
|
|
21172
|
+
}
|
|
21173
|
+
</div>
|
|
21174
|
+
</div>
|
|
21175
|
+
|
|
21176
|
+
<div class="heures" [style.grid-template-columns]="colonnes()">
|
|
21177
|
+
<div class="heures__lbl">
|
|
21178
|
+
@for (h of heuresAffichees(); track h) { <div [style.height.px]="hauteurHeure()">{{ h }}h</div> }
|
|
21179
|
+
</div>
|
|
21180
|
+
@for (j of joursGrille(); track j.cle) {
|
|
21181
|
+
<div class="heures__col" #col [class.is-ferme]="j.ferme"
|
|
21182
|
+
(pointerdown)="creer(j.date, $event, col)">
|
|
21183
|
+
@for (h of heuresAffichees(); track h) {
|
|
21184
|
+
<div class="trait" [style.top.px]="(h - dayStart()) * hauteurHeure()"></div>
|
|
21185
|
+
<div class="trait is-demi" [style.top.px]="(h - dayStart()) * hauteurHeure() + hauteurHeure() / 2"></div>
|
|
21186
|
+
}
|
|
21187
|
+
@for (s of j.slots; track s.occurrence.id) {
|
|
21188
|
+
<button type="button" class="evt"
|
|
21189
|
+
[class.is-editable]="manipulable(s.occurrence)"
|
|
21190
|
+
[class.is-verrouille]="editable() && !manipulable(s.occurrence)"
|
|
21191
|
+
[style.--_c]="couleur(s.occurrence)"
|
|
21192
|
+
[style.top.px]="s.haut * hauteurTotale()"
|
|
21193
|
+
[style.height.px]="Math.max(16, s.hauteur * hauteurTotale() - 2)"
|
|
21194
|
+
[style.left]="'calc(' + (s.voie / s.voies * 100) + '% + 1px)'"
|
|
21195
|
+
[style.width]="'calc(' + (100 / s.voies) + '% - 3px)'"
|
|
21196
|
+
[title]="titre(s.occurrence) + (motifVerrou(s.occurrence) ? ' · ' + motifVerrou(s.occurrence) : '')"
|
|
21197
|
+
(pointerdown)="geste('move', s.occurrence, $event, col)"
|
|
21198
|
+
(keydown)="clavier(s.occurrence, $event)"
|
|
21199
|
+
(click)="clicEvenement(s.occurrence, $event)">
|
|
21200
|
+
<span class="evt__t">{{ s.occurrence.task.label }}@if (s.occurrence.recurring) { <span aria-hidden="true"> ↻</span> }</span>
|
|
21201
|
+
@if (s.hauteur * hauteurTotale() > 30) {
|
|
21202
|
+
<span class="evt__h">{{ heure(s.occurrence.start) }} – {{ heure(s.occurrence.end) }}</span>
|
|
21203
|
+
}
|
|
21204
|
+
@if (manipulable(s.occurrence)) {
|
|
21205
|
+
<span class="poignee is-haut" (pointerdown)="geste('resize-start', s.occurrence, $event, col)"></span>
|
|
21206
|
+
<span class="poignee is-bas" (pointerdown)="geste('resize-end', s.occurrence, $event, col)"></span>
|
|
21207
|
+
}
|
|
21208
|
+
</button>
|
|
21209
|
+
}
|
|
21210
|
+
@if (fantome(); as f) {
|
|
21211
|
+
@if (f.jour === j.cle) {
|
|
21212
|
+
<div class="fantome" [style.top.px]="f.haut" [style.height.px]="f.hauteur"
|
|
21213
|
+
[style.left.px]="2" [style.right.px]="2">{{ f.texte }}</div>
|
|
21214
|
+
}
|
|
21215
|
+
}
|
|
21216
|
+
@if (j.auj && maintenant() !== null) {
|
|
21217
|
+
<div class="maintenant" [style.top.px]="maintenant()"></div>
|
|
21218
|
+
}
|
|
21219
|
+
</div>
|
|
21220
|
+
}
|
|
21221
|
+
</div>
|
|
21222
|
+
</div>
|
|
21223
|
+
}
|
|
21224
|
+
}
|
|
21225
|
+
</div>
|
|
21226
|
+
</div>
|
|
21227
|
+
`, styles: [":host{display:flex;flex-direction:column;min-height:0;height:100%;font:var(--cad-font-size)/1.4 var(--cad-font);color:var(--cad-fg);background:var(--cad-bg)}.cal__corps{flex:1;min-height:0;display:flex}.cal__vue{flex:1;min-width:0;min-height:0;overflow:auto}.mois{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));grid-template-rows:auto;grid-auto-rows:minmax(84px,1fr);min-height:100%}.mois__jsem{padding:6px 8px;text-align:right;border-bottom:1px solid var(--cad-border-strong);background:var(--cad-bg-subtle);position:sticky;top:0;z-index:4;font:600 10.5px var(--cad-font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--cad-fg-muted)}.mois__sem{grid-column:1 / -1;display:grid;grid-template-columns:repeat(7,minmax(0,1fr));position:relative;border-bottom:1px solid var(--cad-border);min-height:84px}.mois__jour{border-right:1px solid var(--cad-border);padding:3px;min-width:0;display:flex;flex-direction:column;gap:2px}.mois__jour:last-child{border-right:0}.mois__jour.is-hors,.mois__jour.is-ferme{background:var(--cad-bg-subtle)}.mois__n{font:11px var(--cad-font-mono);color:var(--cad-fg-secondary);text-align:right;padding:1px 3px;font-variant-numeric:tabular-nums;flex:none}.mois__jour.is-auj .mois__n{background:var(--cad-accent);color:var(--cad-fg-on-accent);border-radius:var(--cad-radius-sm);font-weight:600}.mois__reserve{flex:none}.calque{position:absolute;left:0;right:0;pointer-events:none;z-index:2}.bandeau{position:absolute;height:17px;border-radius:var(--cad-radius-sm);padding:0 7px;font-size:10.5px;line-height:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:auto;cursor:pointer;background:color-mix(in srgb,var(--_c) 22%,transparent);color:var(--_c);border:1px solid color-mix(in srgb,var(--_c) 42%,transparent)}.bandeau.is-avant{border-top-left-radius:0;border-bottom-left-radius:0;border-left-style:dashed}.bandeau.is-apres{border-top-right-radius:0;border-bottom-right-radius:0;border-right-style:dashed}.puce{display:flex;align-items:center;gap:5px;font-size:10.5px;padding:1px 5px;border-radius:var(--cad-radius-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;border-left:2px solid var(--_c);background:color-mix(in srgb,var(--_c) 13%,transparent);color:var(--_c)}.puce:hover{background:color-mix(in srgb,var(--_c) 22%,transparent)}.puce__h{font:9.5px var(--cad-font-mono);opacity:.85;flex:none;font-variant-numeric:tabular-nums}.puce__t{min-width:0;overflow:hidden;text-overflow:ellipsis}.plus{all:unset;box-sizing:border-box;font-size:10px;color:var(--cad-fg-muted);padding:1px 5px;cursor:pointer;border-radius:var(--cad-radius-sm)}.plus:hover{color:var(--cad-accent);background:var(--cad-hover)}.grille{min-width:0;display:flex;flex-direction:column;height:100%}.grille__hd{display:grid;position:sticky;top:0;z-index:5;background:var(--cad-bg-subtle);border-bottom:1px solid var(--cad-border-strong);flex:none}.grille__hd>div{padding:5px 6px;text-align:center;border-right:1px solid var(--cad-border);min-width:0}.grille__hd>div:last-child{border-right:0}.grille__d{font:10px var(--cad-font-mono);color:var(--cad-fg-muted);text-transform:uppercase;letter-spacing:.06em}.grille__n{font-size:16px;font-weight:600;letter-spacing:-.02em}.is-auj .grille__n{color:var(--cad-accent)}.bande{display:grid;border-bottom:1px solid var(--cad-border-strong);background:var(--cad-bg-subtle);flex:none}.bande__lbl{font:9px var(--cad-font-mono);color:var(--cad-fg-muted);padding:4px 6px;text-align:right;border-right:1px solid var(--cad-border)}.bande__zone{grid-column:2 / -1;position:relative;padding:2px 0}.heures{display:grid;position:relative;flex:1;min-height:0;overflow:auto}.heures__lbl{border-right:1px solid var(--cad-border)}.heures__lbl>div{font:9.5px var(--cad-font-mono);color:var(--cad-fg-muted);text-align:right;padding-right:6px;transform:translateY(-6px)}.heures__col{border-right:1px solid var(--cad-border);position:relative;min-width:0}.heures__col:last-child{border-right:0}.heures__col.is-ferme{background:var(--cad-bg-subtle)}.trait{position:absolute;left:0;right:0;border-top:1px solid var(--cad-border);pointer-events:none}.trait.is-demi{border-top-style:dotted;opacity:.55}.evt{position:absolute;border-radius:var(--cad-radius-sm);padding:1px 5px;overflow:hidden;cursor:pointer;border-left:3px solid var(--_c);font-size:10.5px;line-height:1.25;background:color-mix(in srgb,var(--_c) 15%,transparent);color:var(--_c)}.evt:hover{background:color-mix(in srgb,var(--_c) 26%,transparent)}.evt__t{display:block;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.evt__h{font:9px var(--cad-font-mono);opacity:.85}.maintenant{position:absolute;left:0;right:0;height:2px;background:var(--cad-danger);z-index:4;pointer-events:none}.maintenant:before{content:\"\";position:absolute;left:-3px;top:-3px;width:8px;height:8px;border-radius:50%;background:var(--cad-danger)}.agenda{display:flex;flex-direction:column}.ag__jour{display:grid;grid-template-columns:72px minmax(0,1fr);border-bottom:1px solid var(--cad-border)}.ag__d{padding:9px 11px;border-right:1px solid var(--cad-border);background:var(--cad-bg-subtle)}.ag__d b{display:block;font-size:18px;font-weight:600;letter-spacing:-.02em}.ag__d span{display:block;font:9.5px var(--cad-font-mono);color:var(--cad-fg-muted);text-transform:uppercase}.ag__d.is-auj b{color:var(--cad-accent)}.ag__l{padding:5px 0;min-width:0}.ag__e{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:9px;padding:6px 11px;cursor:pointer;width:100%;min-height:34px}.ag__e:hover{background:var(--cad-hover)}.ag__e:focus-visible{outline:2px solid var(--cad-accent);outline-offset:-2px}.ag__p{width:8px;height:8px;border-radius:50%;background:var(--_c);flex:none}.ag__h{font:11px var(--cad-font-mono);color:var(--cad-fg-secondary);flex:none;width:92px;font-variant-numeric:tabular-nums}.ag__t{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ag__c{margin-left:auto;font-size:10.5px;color:var(--cad-fg-muted);flex:none}.annee{display:grid;grid-template-columns:repeat(auto-fill,minmax(178px,1fr));gap:14px;padding:14px}.mm{border:1px solid var(--cad-border);border-radius:var(--cad-radius);padding:8px;background:var(--cad-surface)}.mm__t{font-size:12px;font-weight:600;margin-bottom:5px;text-transform:capitalize}.mm__g{display:grid;grid-template-columns:repeat(7,1fr);gap:1px}.mm__g>span,.mm__g>button{all:unset;box-sizing:border-box;text-align:center;font:9.5px var(--cad-font-mono);padding:2px 0;border-radius:3px;color:var(--cad-fg-secondary);font-variant-numeric:tabular-nums}.mm__g>span{color:var(--cad-fg-muted);font-weight:500}.mm__g>button{cursor:pointer;position:relative}.mm__g>button:hover{background:var(--cad-hover)}.mm__g>button.is-hors{opacity:.35}.mm__g>button.is-auj{background:var(--cad-accent);color:var(--cad-fg-on-accent);font-weight:600}.mm__pt{position:absolute;left:50%;bottom:0;transform:translate(-50%);width:3px;height:3px;border-radius:50%;background:var(--cad-accent)}.mm__g>button.is-auj .mm__pt{background:var(--cad-fg-on-accent)}.evt.is-editable,.bandeau.is-editable,.puce.is-editable{cursor:grab}.evt.is-editable:active,.bandeau.is-editable:active,.puce.is-editable:active{cursor:grabbing}.poignee{position:absolute;z-index:2}.evt .poignee{left:0;right:0;height:6px;cursor:ns-resize}.evt .poignee.is-haut{top:0}.evt .poignee.is-bas{bottom:0}.bandeau .poignee{top:0;bottom:0;width:6px;cursor:ew-resize}.bandeau .poignee.is-haut{left:0}.bandeau .poignee.is-bas{right:0}.poignee:after{content:\"\";position:absolute;inset:0}.evt.is-verrouille,.bandeau.is-verrouille,.puce.is-verrouille{cursor:not-allowed;position:relative}.evt.is-verrouille:after,.bandeau.is-verrouille:after,.puce.is-verrouille:after{content:\"\";position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(-45deg,currentColor 0 1px,transparent 1px 5px);opacity:.18}.fantome{position:absolute;z-index:6;pointer-events:none;border-radius:var(--cad-radius-sm);background:var(--cad-accent-soft);border:1px dashed var(--cad-accent);color:var(--cad-accent);font:10.5px var(--cad-font-mono);padding:1px 5px;overflow:hidden;white-space:nowrap}.vide{padding:28px 16px;color:var(--cad-fg-muted);text-align:center}@media(prefers-reduced-motion:reduce){*{transition:none!important}}\n"] }]
|
|
21228
|
+
}], ctorParameters: () => [], propDecorators: { plan: [{ type: i0.Input, args: [{ isSignal: true, alias: "plan", required: false }] }], sources: [{ type: i0.Input, args: [{ isSignal: true, alias: "sources", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }, { type: i0.Output, args: ["hiddenChange"] }], view: [{ type: i0.Input, args: [{ isSignal: true, alias: "view", required: false }] }, { type: i0.Output, args: ["viewChange"] }], date: [{ type: i0.Input, args: [{ isSignal: true, alias: "date", required: false }] }, { type: i0.Output, args: ["dateChange"] }], firstDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDay", required: false }] }], dayStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayStart", required: false }] }], dayEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "dayEnd", required: false }] }], hourHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "hourHeight", required: false }] }], maxPerDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxPerDay", required: false }] }], workCalendar: [{ type: i0.Input, args: [{ isSignal: true, alias: "workCalendar", required: false }] }], today: [{ type: i0.Input, args: [{ isSignal: true, alias: "today", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], showNow: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNow", required: false }] }], eventClick: [{ type: i0.Output, args: ["eventClick"] }], dateClick: [{ type: i0.Output, args: ["dateClick"] }], rangeChange: [{ type: i0.Output, args: ["rangeChange"] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], snap: [{ type: i0.Input, args: [{ isSignal: true, alias: "snap", required: false }] }], eventMove: [{ type: i0.Output, args: ["eventMove"] }], eventResize: [{ type: i0.Output, args: ["eventResize"] }], eventCreate: [{ type: i0.Output, args: ["eventCreate"] }] } });
|
|
21229
|
+
|
|
19543
21230
|
/**
|
|
19544
21231
|
* Generated bundle index. Do not edit.
|
|
19545
21232
|
*/
|
|
19546
21233
|
|
|
19547
|
-
export { BanGeocoder, CAD_BREAKPOINTS, CAD_CHART_PALETTE, CAD_COLOR_PRESETS, CAD_DEFAULT_BASEMAPS, CAD_DEFAULT_PRIORITY_BREAKPOINTS, CAD_DIALOG_DATA, CAD_FILTER_OPERATORS, CAD_GEOCODER, CAD_ICONS, CAD_ICONS_CEREMA, CAD_ICONS_CORE, CAD_ICONS_DATA, CAD_ICONS_FILES, CAD_ICONS_GEO, CAD_ICONS_SUBSET, CAD_ICONS_TOKEN, CAD_ICONS_UI, CAD_ICON_ALIASES, CAD_ICON_CATEGORIES, CAD_MAPLIBRE_CSS_URL, CAD_MAP_CHILD, CAD_MAP_DEFAULTS, CAD_MAP_GLOBAL_STYLES, CAD_MAP_GLYPHS, CAD_MAP_PALETTE, CAD_MASK_PRESETS, CAD_MOBILE_BREAKPOINT, CAD_SELECT_POSITIONS, CAD_SELECT_TRIGGER_STYLES, CAD_SHEET_DATA, CAD_SHELL, CAD_TOUCH_DENSITY, CadAccordionComponent, CadAccordionPanelComponent, CadAppShellComponent, CadAvatarComponent, CadAvatarGroupComponent, CadBadgeComponent, CadBadgeDirective, CadBlockDirective, CadBlockOverlayComponent, CadBlockUiComponent, CadBottomNavComponent, CadBreadcrumbComponent, CadBreadcrumbItemDirective, CadBreakpointService, CadButtonComponent, CadButtonGroupComponent, CadCaptionDirective, CadCardComponent, CadCardDirective, CadCardHeaderDirective, CadCarouselComponent, CadCarouselItemDirective, CadCascadeSelectComponent, CadCellTemplateDirective, CadCenterComponent, CadChartComponent, CadCheckboxComponent, CadChipComponent, CadClusterComponent, CadColDirective, CadColorpickerComponent, CadColumnComponent, CadComboComponent, CadConfirmContentComponent, CadConfirmDialogComponent, CadConfirmService, CadContainerComponent, CadDataviewComponent, CadDataviewGridDirective, CadDataviewListDirective, CadDatepickerComponent, CadDialogComponent, CadDialogContainerComponent, CadDialogFooterDirective, CadDialogHeaderDirective, CadDialogRef, CadDialogService, CadDividerComponent, CadDrawerComponent, CadEditFocusDirective, CadEditorTemplateDirective, CadEmptyDirective, CadFieldComponent, CadFieldsetComponent, CadFieldsetLegendDirective, CadFilterChipComponent, CadFilterTemplateDirective, CadGeocodingService, CadGridComponent, CadGroupFooterDirective, CadGroupHeaderDirective, CadHeaderTemplateDirective, CadIconComponent, CadIconRegistry, CadIfDirective, CadImageComponent, CadInplaceComponent, CadInplaceContentDirective, CadInplaceDisplayDirective, CadInputDirective, CadJsonEditorComponent, CadKeyFilterDirective, CadListEmptyDirective, CadListFooterDirective, CadListHeaderDirective, CadListItemDirective, CadListboxComponent, CadMapBasemapRegistry, CadMapBasemapsComponent, CadMapCardComponent, CadMapChromeComponent, CadMapComponent, CadMapDrawEngine, CadMapLayerComponent, CadMapLayerGroupComponent, CadMapLayerToggleComponent, CadMapLegendComponent, CadMapMenuComponent, CadMapPanelComponent, CadMapPanels, CadMapRailComponent, CadMapRailItemComponent, CadMapSearchComponent, CadMapSectionComponent, CadMaskDirective, CadMenuComponent, CadMenubarComponent, CadMessageComponent, CadMeterComponent, CadMeterLabelDirective, CadMultiselectComponent, CadNavDrawerComponent, CadNavDrawerFooterDirective, CadNavDrawerHeaderDirective, CadNumberComponent, CadOptionListComponent, CadOrderlistComponent, CadOrgNodeDirective, CadOrgchartComponent, CadOverlayBase, CadPaginatorComponent, CadPanelComponent, CadPanelContentDirective, CadPanelHeaderDirective, CadPanelHeadingDirective, CadPasswordComponent, CadPicklistComponent, CadPopoverComponent, CadProgressComponent, CadRadioComponent, CadRadioGroupComponent, CadRatingComponent, CadRowActionsDirective, CadRowCountDirective, CadRowExpansionDirective, CadScrollTopComponent, CadSegmentedComponent, CadSelectBase, CadSelectComponent, CadSelectEmptyDirective, CadSelectFooterDirective, CadSelectHeaderDirective, CadSelectItemDirective, CadSelectSelectedDirective, CadSheetContainerComponent, CadSheetRef, CadSheetService, CadSidebarComponent, CadSidebarPanelDirective, CadSkeletonComponent, CadSliderComponent, CadSpacerComponent, CadSpeedDialComponent, CadSpinnerComponent, CadSplitButtonComponent, CadSplitComponent, CadSplitterComponent, CadSplitterPanelComponent, CadStackComponent, CadStepComponent, CadStepperComponent, CadSwitchComponent, CadTabComponent, CadTabContentDirective, CadTabLabelDirective, CadTableBase, CadTableComponent, CadTableEdit, CadTableEditUi, CadTableFooterDirective, CadTablePanelComponent, CadTableResponsive, CadTableSelection, CadTableSticky, CadTableVirtual, CadTabsComponent, CadTagComponent, CadTaskCardDirective, CadTaskRowDirective, CadTaskboardComponent, CadTimeAxis, CadTimelineComponent, CadTimelineContentDirective, CadTimelineMarkerDirective, CadTimelineOppositeDirective, CadToastComponent, CadToastItemDirective, CadToastService, CadToggleButtonComponent, CadTooltipComponent, CadTooltipDirective, CadTreeAdapter, CadTreeComponent, CadTreeNodeDirective, CadTreeselectComponent, CadUploadComponent, CadUploadContentDirective, CadUploadEmptyDirective, CadUploadItemDirective, CadValueAccessor, CadWorkCalendar, MAPLIBRE_MIN_CSS, addDays, addMonths, addYears, cadAggregate, cadApplyColumnOrder, cadApplyMask, cadArea, cadAutosizeWidth, cadBasemapThumbnail, cadBoundsOf, cadCategories, cadCentroid, cadColorExpr, cadCompare, cadCompareRank, cadCurrentOperator, cadDefaultMatchMode, cadDistance, cadDownloadCsv, cadDurationToMinutes, cadFilterData, cadFilterKindOf, cadFilterOperators, cadFilterRows, cadFindLinkCycle, cadFmtArea, cadFmtLength, cadFormatCell, cadFormatColor, cadFormatDuration, cadFormatSize, cadFrenchHolidays, cadGap, cadGeoJSONStats, cadGeometryKinds, cadHeaderMenuItems, cadHighlightJson, cadHslToRgb, cadHsvToRgb, cadId, cadIsGroupKey, cadIsRank, cadJsonErrorPos, cadLegendFromStyle, cadLength, cadMapEstVivante, cadMapLayerOf, cadMapLayersOf, cadMatch, cadMoveColumn, cadMoveItems, cadNormalize, cadNormalizeOptions, cadNormalizePlan, cadNumberExpr, cadPadBounds, cadParseColor, cadParseDuration, cadParseResponsive, cadPlanHeader, cadPlanTicks, cadPropsTable, cadRankBetween, cadRankFirst, cadRankLast, cadRankSequence, cadResolve, cadResolveResponsive, cadResponsive, cadRgbToHsl, cadRgbToHsv, cadRingArea, cadRowKey, cadRowPredicate, cadSameValue, cadScaleNext, cadScaleStart, cadSortData, cadStartResize, cadStyleToExpressions, cadUnmask, cadUnscheduled, cadValidateGeoJSON, cadValueForOperator, cadWriteField, compareDay, daysInMonth, endOfMonth, ensureMaplibreCss, formatDate, isBetweenDay, isSameDay, isSameMonth, isValidDate, isoOf, isoWeek, loadChartJs, loadMaplibre, monthNames, pad2, parseIso, parseWithFormat, provideCadIcons, startOfDay, startOfMonth, toDate, weekdayNames };
|
|
21234
|
+
export { BanGeocoder, CAD_BREAKPOINTS, CAD_CHART_PALETTE, CAD_COLOR_PRESETS, CAD_DEFAULT_BASEMAPS, CAD_DEFAULT_PRIORITY_BREAKPOINTS, CAD_DIALOG_DATA, CAD_FILTER_OPERATORS, CAD_GEOCODER, CAD_ICONS, CAD_ICONS_CEREMA, CAD_ICONS_CORE, CAD_ICONS_DATA, CAD_ICONS_FILES, CAD_ICONS_GEO, CAD_ICONS_SUBSET, CAD_ICONS_TOKEN, CAD_ICONS_UI, CAD_ICON_ALIASES, CAD_ICON_CATEGORIES, CAD_MAPLIBRE_CSS_URL, CAD_MAP_CHILD, CAD_MAP_DEFAULTS, CAD_MAP_GLOBAL_STYLES, CAD_MAP_GLYPHS, CAD_MAP_PALETTE, CAD_MASK_PRESETS, CAD_MOBILE_BREAKPOINT, CAD_RECURRENCE_INTERNE, CAD_SELECT_POSITIONS, CAD_SELECT_TRIGGER_STYLES, CAD_SHEET_DATA, CAD_SHELL, CAD_TOUCH_DENSITY, CadAccordionComponent, CadAccordionPanelComponent, CadAppShellComponent, CadAvatarComponent, CadAvatarGroupComponent, CadBadgeComponent, CadBadgeDirective, CadBlockDirective, CadBlockOverlayComponent, CadBlockUiComponent, CadBottomNavComponent, CadBreadcrumbComponent, CadBreadcrumbItemDirective, CadBreakpointService, CadButtonComponent, CadButtonGroupComponent, CadCalendarComponent, CadCaptionDirective, CadCardComponent, CadCardDirective, CadCardHeaderDirective, CadCarouselComponent, CadCarouselItemDirective, CadCascadeSelectComponent, CadCellTemplateDirective, CadCenterComponent, CadChartComponent, CadCheckboxComponent, CadChipComponent, CadClusterComponent, CadColDirective, CadColorpickerComponent, CadColumnComponent, CadComboComponent, CadConfirmContentComponent, CadConfirmDialogComponent, CadConfirmService, CadContainerComponent, CadDataviewComponent, CadDataviewGridDirective, CadDataviewListDirective, CadDatepickerComponent, CadDialogComponent, CadDialogContainerComponent, CadDialogFooterDirective, CadDialogHeaderDirective, CadDialogRef, CadDialogService, CadDividerComponent, CadDrawerComponent, CadEditFocusDirective, CadEditorTemplateDirective, CadEmptyDirective, CadFieldComponent, CadFieldsetComponent, CadFieldsetLegendDirective, CadFilterChipComponent, CadFilterTemplateDirective, CadGeocodingService, CadGridComponent, CadGroupFooterDirective, CadGroupHeaderDirective, CadHeaderTemplateDirective, CadIconComponent, CadIconRegistry, CadIfDirective, CadImageComponent, CadInplaceComponent, CadInplaceContentDirective, CadInplaceDisplayDirective, CadInputDirective, CadJsonEditorComponent, CadKeyFilterDirective, CadListEmptyDirective, CadListFooterDirective, CadListHeaderDirective, CadListItemDirective, CadListboxComponent, CadMapBasemapRegistry, CadMapBasemapsComponent, CadMapCardComponent, CadMapChromeComponent, CadMapComponent, CadMapDrawEngine, CadMapLayerComponent, CadMapLayerGroupComponent, CadMapLayerToggleComponent, CadMapLegendComponent, CadMapMenuComponent, CadMapPanelComponent, CadMapPanels, CadMapRailComponent, CadMapRailItemComponent, CadMapSearchComponent, CadMapSectionComponent, CadMaskDirective, CadMenuComponent, CadMenubarComponent, CadMessageComponent, CadMeterComponent, CadMeterLabelDirective, CadMultiselectComponent, CadNavDrawerComponent, CadNavDrawerFooterDirective, CadNavDrawerHeaderDirective, CadNumberComponent, CadOptionListComponent, CadOrderlistComponent, CadOrgNodeDirective, CadOrgchartComponent, CadOverlayBase, CadPaginatorComponent, CadPanelComponent, CadPanelContentDirective, CadPanelHeaderDirective, CadPanelHeadingDirective, CadPasswordComponent, CadPicklistComponent, CadPopoverComponent, CadProgressComponent, CadRadioComponent, CadRadioGroupComponent, CadRatingComponent, CadRowActionsDirective, CadRowCountDirective, CadRowExpansionDirective, CadScrollTopComponent, CadSegmentedComponent, CadSelectBase, CadSelectComponent, CadSelectEmptyDirective, CadSelectFooterDirective, CadSelectHeaderDirective, CadSelectItemDirective, CadSelectSelectedDirective, CadSheetContainerComponent, CadSheetRef, CadSheetService, CadSidebarComponent, CadSidebarPanelDirective, CadSkeletonComponent, CadSliderComponent, CadSpacerComponent, CadSpeedDialComponent, CadSpinnerComponent, CadSplitButtonComponent, CadSplitComponent, CadSplitterComponent, CadSplitterPanelComponent, CadStackComponent, CadStepComponent, CadStepperComponent, CadSwitchComponent, CadTabComponent, CadTabContentDirective, CadTabLabelDirective, CadTableBase, CadTableComponent, CadTableEdit, CadTableEditUi, CadTableFooterDirective, CadTablePanelComponent, CadTableResponsive, CadTableSelection, CadTableSticky, CadTableVirtual, CadTabsComponent, CadTagComponent, CadTaskCardDirective, CadTaskRowDirective, CadTaskboardComponent, CadTimeAxis, CadTimelineComponent, CadTimelineContentDirective, CadTimelineMarkerDirective, CadTimelineOppositeDirective, CadToastComponent, CadToastItemDirective, CadToastService, CadToggleButtonComponent, CadTooltipComponent, CadTooltipDirective, CadTreeAdapter, CadTreeComponent, CadTreeNodeDirective, CadTreeselectComponent, CadUploadComponent, CadUploadContentDirective, CadUploadEmptyDirective, CadUploadItemDirective, CadValueAccessor, CadWorkCalendar, MAPLIBRE_MIN_CSS, addDays, addMonths, addYears, cadAggregate, cadApplyColumnOrder, cadApplyMask, cadArea, cadAutosizeWidth, cadBasemapThumbnail, cadBoundsOf, cadCategories, cadCentroid, cadColorExpr, cadCompare, cadCompareRank, cadCurrentOperator, cadDebutSemaine, cadDefaultMatchMode, cadDistance, cadDownloadCsv, cadDurationToMinutes, cadEstBandeau, cadExpandOccurrences, cadFilterData, cadFilterKindOf, cadFilterOperators, cadFilterRows, cadFindLinkCycle, cadFmtArea, cadFmtLength, cadFormatCell, cadFormatColor, cadFormatDuration, cadFormatSize, cadFrenchHolidays, cadGap, cadGeoJSONStats, cadGeometryKinds, cadHeaderMenuItems, cadHighlightJson, cadHslToRgb, cadHsvToRgb, cadId, cadIsGroupKey, cadIsRank, cadJsonErrorPos, cadLegendFromStyle, cadLength, cadMapEstVivante, cadMapLayerOf, cadMapLayersOf, cadMatch, cadMinuit, cadMonthGrid, cadMoveColumn, cadMoveItems, cadNormalize, cadNormalizeOptions, cadNormalizePlan, cadNumberExpr, cadNumeroJour, cadPackDay, cadPadBounds, cadParseColor, cadParseDuration, cadParseRRule, cadParseResponsive, cadPlanHeader, cadPlanTicks, cadProjeterClavier, cadProjeterCreation, cadProjeterEdition, cadProjeterMois, cadPropsTable, cadRankBetween, cadRankFirst, cadRankLast, cadRankSequence, cadResolve, cadResolveResponsive, cadResponsive, cadRgbToHsl, cadRgbToHsv, cadRingArea, cadRowKey, cadRowPredicate, cadSameValue, cadScaleNext, cadScaleStart, cadSortData, cadStartResize, cadStyleToExpressions, cadUnmask, cadUnscheduled, cadValidateGeoJSON, cadValueForOperator, cadWeekBands, cadWriteField, compareDay, daysInMonth, endOfMonth, ensureMaplibreCss, formatDate, isBetweenDay, isSameDay, isSameMonth, isValidDate, isoOf, isoWeek, loadChartJs, loadMaplibre, monthNames, pad2, parseIso, parseWithFormat, provideCadIcons, startOfDay, startOfMonth, toDate, weekdayNames };
|
|
19548
21235
|
//# sourceMappingURL=cadriciel-ui.mjs.map
|