@ktortu/aaa 0.9.7 → 0.9.9
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/dialog/dialog.css +85 -30
- package/fesm2022/ktortu-aaa-cdk.mjs +5 -0
- package/fesm2022/ktortu-aaa-cdk.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-dialog.mjs +157 -44
- package/fesm2022/ktortu-aaa-dialog.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-forms.mjs +207 -92
- package/fesm2022/ktortu-aaa-forms.mjs.map +1 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs +21 -1
- package/fesm2022/ktortu-aaa-tooltip.mjs.map +1 -1
- package/forms/multi-select/multi-select.css +3 -53
- package/forms/styles/field-box.css +11 -1
- package/forms/styles/select-panel.css +81 -40
- package/forms/styles/tokens.css +5 -0
- package/forms/switch/switch.css +6 -0
- package/package.json +1 -1
- package/themes/theme-catppuccin.css +3 -1
- package/themes/theme-cyberpunk.css +1 -1
- package/types/ktortu-aaa-cdk.d.ts +5 -0
- package/types/ktortu-aaa-dialog.d.ts +31 -21
- package/types/ktortu-aaa-forms.d.ts +64 -12
- package/types/ktortu-aaa-tooltip.d.ts +16 -0
|
@@ -140,6 +140,25 @@ class KtTooltip {
|
|
|
140
140
|
clearTimeout(this.showTimer);
|
|
141
141
|
this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());
|
|
142
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Fermeture immédiate à l'activation de la cible (clic souris, tap tactile, stylet).
|
|
145
|
+
* Dès que l'utilisateur AGIT sur l'élément (typiquement un bouton qui ouvre une bottom sheet ou un
|
|
146
|
+
* dialog), l'infobulle a fini son rôle : on la ferme sans attendre le hideDelay, et on purge un
|
|
147
|
+
* affichage en attente pour qu'il ne surgisse pas après coup.
|
|
148
|
+
*
|
|
149
|
+
* Sans ce déclencheur, une infobulle affichée au survol SURVIVAIT à l'ouverture d'un overlay : le
|
|
150
|
+
* pointeur reste sur la cible (aucun `mouseleave`) et un clic ne défocalise pas toujours (aucun
|
|
151
|
+
* `focusout` fiable, ex. Safari/Firefox macOS). Comme l'infobulle est un popover en top layer, elle
|
|
152
|
+
* flottait alors AU-DESSUS de l'overlay (lui empilé au z-index) — impossible à masquer autrement.
|
|
153
|
+
*
|
|
154
|
+
* `pointerdown` (et non `click`) car il précède l'ouverture de l'overlay et le déplacement de focus
|
|
155
|
+
* → zéro flash. On ne fait ni preventDefault ni stopPropagation : l'action native (clic) doit suivre
|
|
156
|
+
* son cours. Le cas clavier (Entrée/Espace) reste couvert par `focusout` quand l'overlay prend le focus.
|
|
157
|
+
*/
|
|
158
|
+
onActivate() {
|
|
159
|
+
clearTimeout(this.showTimer);
|
|
160
|
+
this.dismiss();
|
|
161
|
+
}
|
|
143
162
|
onEscape(event) {
|
|
144
163
|
if (!this.isShown())
|
|
145
164
|
return;
|
|
@@ -322,7 +341,7 @@ class KtTooltip {
|
|
|
322
341
|
this.fallbackListeners = [];
|
|
323
342
|
}
|
|
324
343
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
325
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtTooltip, isStandalone: true, selector: "[ktTooltip]", inputs: { ktTooltip: { classPropertyName: "ktTooltip", publicName: "ktTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "hideDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focusin": "show()", "focusout": "hide()", "keydown.escape": "onEscape($event)" }, properties: { "attr.aria-describedby": "describedById()" } }, ngImport: i0 });
|
|
344
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.1", type: KtTooltip, isStandalone: true, selector: "[ktTooltip]", inputs: { ktTooltip: { classPropertyName: "ktTooltip", publicName: "ktTooltip", isSignal: true, isRequired: true, transformFunction: null }, tooltipPosition: { classPropertyName: "tooltipPosition", publicName: "tooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, tooltipDisabled: { classPropertyName: "tooltipDisabled", publicName: "tooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, showDelay: { classPropertyName: "showDelay", publicName: "showDelay", isSignal: true, isRequired: false, transformFunction: null }, hideDelay: { classPropertyName: "hideDelay", publicName: "hideDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "show()", "mouseleave": "hide()", "focusin": "show()", "focusout": "hide()", "pointerdown": "onActivate()", "keydown.escape": "onEscape($event)" }, properties: { "attr.aria-describedby": "describedById()" } }, ngImport: i0 });
|
|
326
345
|
}
|
|
327
346
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: KtTooltip, decorators: [{
|
|
328
347
|
type: Directive,
|
|
@@ -334,6 +353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImpor
|
|
|
334
353
|
'(mouseleave)': 'hide()',
|
|
335
354
|
'(focusin)': 'show()',
|
|
336
355
|
'(focusout)': 'hide()',
|
|
356
|
+
'(pointerdown)': 'onActivate()',
|
|
337
357
|
'(keydown.escape)': 'onEscape($event)',
|
|
338
358
|
},
|
|
339
359
|
}]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ktortu-aaa-tooltip.mjs","sources":["../../../../projects/ktortu/aaa/tooltip/tooltip.ts","../../../../projects/ktortu/aaa/tooltip/ktortu-aaa-tooltip.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n ElementRef,\n EmbeddedViewRef,\n InjectionToken,\n OnDestroy,\n Provider,\n Renderer2,\n TemplateRef,\n ViewContainerRef,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n isDevMode,\n signal,\n PLATFORM_ID,\n} from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\nexport type KtTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/** Défauts d'infobulle (délais, position) injectables via `provideKtTooltip` / `KT_TOOLTIP_CONFIG`. */\nexport interface KtTooltipConfig {\n /** Délai (ms) avant apparition au survol/focus. */\n showDelay: number;\n /** Délai (ms) avant masquage (laisse le temps d'atteindre l'infobulle, WCAG « hoverable »). */\n hideDelay: number;\n /** Position de l'infobulle autour de la cible. */\n position: KtTooltipPosition;\n}\n\nexport const KT_TOOLTIP_CONFIG = new InjectionToken<Partial<KtTooltipConfig>>('KT_TOOLTIP_CONFIG');\n\n/**\n * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.\n *\n * @example\n * ```ts\n * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]\n * ```\n */\nexport function provideKtTooltip(config: Partial<KtTooltipConfig>): Provider {\n return { provide: KT_TOOLTIP_CONFIG, useValue: config };\n}\n\n/**\n * Infobulle accessible posée sur n'importe quel élément focusable/survolable.\n * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme\n * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**\n * (un `role=\"tooltip\"` ne doit pas contenir de lien/bouton/champ).\n *\n * @example\n * ```html\n * <button ktTooltip=\"Enregistrer le brouillon\">Enregistrer</button>\n * <span ktTooltip=\"Aide\" tooltipPosition=\"right\" [showDelay]=\"300\">?</span>\n * ```\n */\n@Directive({\n selector: '[ktTooltip]',\n host: {\n '[attr.aria-describedby]': 'describedById()',\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusin)': 'show()',\n '(focusout)': 'hide()',\n '(keydown.escape)': 'onEscape($event)',\n },\n})\nexport class KtTooltip implements OnDestroy {\n private readonly config = inject(KT_TOOLTIP_CONFIG, { optional: true });\n private readonly doc = inject(DOCUMENT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly vcr = inject(ViewContainerRef);\n private readonly platformId = inject(PLATFORM_ID);\n\n /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */\n readonly ktTooltip = input.required<string | TemplateRef<unknown>>();\n /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */\n readonly tooltipPosition = input<KtTooltipPosition>(this.config?.position ?? 'top');\n /** Désactive l'affichage de l'infobulle. @default false */\n readonly tooltipDisabled = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */\n readonly showDelay = input<number>(this.config?.showDelay ?? 150);\n /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */\n readonly hideDelay = input<number>(this.config?.hideDelay ?? 100);\n\n private readonly idGen = inject(KtIdGenerator);\n private readonly uid = this.idGen.generateId('tooltip');\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n /** Id du noeud `role=\"tooltip\"`. Public : sert aux liaisons d'accessibilité (`aria-describedby`) du déclencheur. */\n readonly idForA11y = this.tooltipId;\n private readonly anchorName = `--kt-tooltip-anchor-${this.uid}`;\n\n /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).\n Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */\n readonly isActive = computed(() => {\n if (this.tooltipDisabled()) return false;\n\n const content = this.ktTooltip();\n if (typeof content === 'string') return content.trim().length > 0;\n return true;\n });\n\n // Retourner null retire l'attribut (même astuce que aria-disabled dans button).\n // aria-describedby n'est posé sur le déclencheur que lorsque le tooltip est affiché : sinon il\n // référencerait un nœud absent du DOM (création lazy), donnant une référence pendante aux AT.\n protected describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null));\n\n private tip: HTMLElement | null = null;\n private view: EmbeddedViewRef<unknown> | null = null;\n private listeners: (() => void)[] = [];\n private showTimer: ReturnType<typeof setTimeout> | undefined;\n private hideTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly isShown = signal(false);\n private _supportsAnchor: boolean | null = null;\n private get supportsAnchor(): boolean {\n if (this._supportsAnchor === null) {\n this._supportsAnchor =\n isPlatformBrowser(this.platformId) &&\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('anchor-name: --x');\n }\n return this._supportsAnchor;\n }\n private fallbackListeners: (() => void)[] = [];\n private activeTemplate: TemplateRef<unknown> | null = null;\n private escListener: (() => void) | null = null;\n\n constructor() {\n // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés\n // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.\n if (isPlatformBrowser(this.platformId)) {\n this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);\n }\n\n // Gestion réactive du cycle de vie du DOM du Tooltip\n effect(() => {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Création lazy : uniquement si actif ET affiché\n if (!this.isActive() || !this.isShown()) {\n this.destroyTip();\n return;\n }\n\n const tip = this.ensureTip();\n this.registerEscapeListener();\n this.syncContent();\n\n try {\n tip.showPopover?.();\n } catch {\n // Ignorer si déjà ouvert ou non supporté\n }\n\n if (!this.supportsAnchor) {\n this.positionFallback();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroyTip();\n }\n\n protected show(): void {\n if (!this.isActive()) return;\n\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n }, this.showDelay());\n }\n\n protected hide(): void {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());\n }\n\n protected onEscape(event: Event): void {\n if (!this.isShown()) return;\n\n // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.\n this.dismiss();\n event.stopPropagation();\n }\n\n private dismiss(): void {\n if (!this.isShown()) return;\n\n this.isShown.set(false);\n }\n\n private ensureTip(): HTMLElement {\n if (this.tip) return this.tip;\n\n const tip = this.renderer.createElement('div') as HTMLElement;\n this.renderer.setAttribute(tip, 'role', 'tooltip');\n this.renderer.setAttribute(tip, 'id', this.tooltipId);\n // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.\n this.renderer.setAttribute(tip, 'popover', 'manual');\n this.renderer.addClass(tip, 'kt-tooltip');\n // setProperty natif : indispensable pour une propriété CSS à tiret.\n tip.style.setProperty('position-anchor', this.anchorName);\n // Top-layer : ajouté au body, immunisé contre overflow/z-index.\n this.renderer.appendChild(this.doc.body, tip);\n\n // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.\n this.listeners.push(\n this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)),\n this.renderer.listen(tip, 'mouseleave', () => this.hide()),\n );\n\n this.tip = tip;\n return tip;\n }\n\n private registerEscapeListener(): void {\n if (this.escListener) return;\n this.escListener = this.renderer.listen('document', 'keydown.escape', (event: KeyboardEvent) => {\n if (this.isShown()) {\n this.dismiss();\n event.stopPropagation();\n }\n });\n }\n\n private syncContent(): void {\n if (!this.tip) return;\n\n this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());\n\n const content = this.ktTooltip();\n\n if (content instanceof TemplateRef) {\n if (this.activeTemplate === content) return;\n this.clearContent();\n this.activeTemplate = content;\n\n this.view = this.vcr.createEmbeddedView(content);\n this.view.detectChanges();\n for (const node of this.view.rootNodes) {\n this.renderer.appendChild(this.tip, node);\n }\n if (isDevMode()) {\n this.warnIfInteractive();\n }\n return;\n }\n\n this.clearContent();\n this.renderer.setProperty(this.tip, 'textContent', content);\n }\n\n private clearContent(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n this.activeTemplate = null;\n if (this.tip) {\n this.renderer.setProperty(this.tip, 'textContent', '');\n }\n }\n\n // Garde-fou a11y : un role=\"tooltip\" ne doit pas contenir d'éléments focusables.\n private warnIfInteractive(): void {\n if (!this.tip) return;\n\n const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');\n if (!interactive) return;\n\n console.warn(\n `[ktTooltip] Un role=\"tooltip\" ne doit pas contenir d'éléments interactifs ` +\n `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`,\n );\n }\n\n private destroyTip(): void {\n clearTimeout(this.showTimer);\n clearTimeout(this.hideTimer);\n\n for (const unlisten of this.listeners) unlisten();\n this.listeners = [];\n this.clearFallbackListeners();\n\n if (this.escListener) {\n this.escListener();\n this.escListener = null;\n }\n\n this.view?.destroy();\n this.view = null;\n this.activeTemplate = null;\n\n if (this.tip) {\n try {\n this.tip.hidePopover?.();\n } catch {\n // Ignorer si déjà fermé ou non supporté\n }\n this.tip.remove();\n this.tip = null;\n }\n\n if (this.isShown()) {\n this.isShown.set(false);\n }\n }\n\n private positionFallback(): void {\n if (!this.tip) return;\n const triggerEl = this.host.nativeElement;\n const triggerRect = triggerEl.getBoundingClientRect();\n const tooltipRect = this.tip.getBoundingClientRect();\n const position = this.tooltipPosition();\n const gap = 8;\n\n let top = 0;\n let left = 0;\n\n if (position === 'top') {\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'bottom') {\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'left') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n } else if (position === 'right') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n }\n\n const viewWidth = window.innerWidth;\n const viewHeight = window.innerHeight;\n\n if (left < 4) left = 4;\n if (left + tooltipRect.width > viewWidth - 4) {\n left = viewWidth - tooltipRect.width - 4;\n }\n if (top < 4) {\n if (position === 'top') {\n top = triggerRect.bottom + gap;\n } else {\n top = 4;\n }\n }\n if (top + tooltipRect.height > viewHeight - 4) {\n if (position === 'bottom') {\n top = triggerRect.top - tooltipRect.height - gap;\n } else {\n top = viewHeight - tooltipRect.height - 4;\n }\n }\n\n this.tip.style.position = 'fixed';\n this.tip.style.top = `${top}px`;\n this.tip.style.left = `${left}px`;\n this.tip.style.margin = '0';\n }\n\n private registerFallbackListeners(): void {\n this.clearFallbackListeners();\n if (this.supportsAnchor || !isPlatformBrowser(this.platformId)) return;\n\n const onScrollOrResize = () => {\n this.positionFallback();\n };\n window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });\n window.addEventListener('resize', onScrollOrResize);\n\n this.fallbackListeners.push(\n () => window.removeEventListener('scroll', onScrollOrResize, { capture: true }),\n () => window.removeEventListener('resize', onScrollOrResize),\n );\n }\n\n private clearFallbackListeners(): void {\n for (const remove of this.fallbackListeners) remove();\n this.fallbackListeners = [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ktortu-aaa-tooltip.mjs","sources":["../../../../projects/ktortu/aaa/tooltip/tooltip.ts","../../../../projects/ktortu/aaa/tooltip/ktortu-aaa-tooltip.ts"],"sourcesContent":["import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport {\n Directive,\n ElementRef,\n EmbeddedViewRef,\n InjectionToken,\n OnDestroy,\n Provider,\n Renderer2,\n TemplateRef,\n ViewContainerRef,\n booleanAttribute,\n computed,\n effect,\n inject,\n input,\n isDevMode,\n signal,\n PLATFORM_ID,\n} from '@angular/core';\nimport { KtIdGenerator } from '@ktortu/aaa/cdk';\n\nexport type KtTooltipPosition = 'top' | 'bottom' | 'left' | 'right';\n\n/** Défauts d'infobulle (délais, position) injectables via `provideKtTooltip` / `KT_TOOLTIP_CONFIG`. */\nexport interface KtTooltipConfig {\n /** Délai (ms) avant apparition au survol/focus. */\n showDelay: number;\n /** Délai (ms) avant masquage (laisse le temps d'atteindre l'infobulle, WCAG « hoverable »). */\n hideDelay: number;\n /** Position de l'infobulle autour de la cible. */\n position: KtTooltipPosition;\n}\n\nexport const KT_TOOLTIP_CONFIG = new InjectionToken<Partial<KtTooltipConfig>>('KT_TOOLTIP_CONFIG');\n\n/**\n * Fournit des défauts d'infobulle (délais, position) pour un sous-arbre ou l'application entière.\n *\n * @example\n * ```ts\n * providers: [provideKtTooltip({ showDelay: 300, position: 'bottom' })]\n * ```\n */\nexport function provideKtTooltip(config: Partial<KtTooltipConfig>): Provider {\n return { provide: KT_TOOLTIP_CONFIG, useValue: config };\n}\n\n/**\n * Infobulle accessible posée sur n'importe quel élément focusable/survolable.\n * Apparaît au survol et au focus, reste « hoverable » (WCAG 1.4.13) et se ferme\n * par Échap. Le contenu peut être un texte simple ou un `TemplateRef` **non interactif**\n * (un `role=\"tooltip\"` ne doit pas contenir de lien/bouton/champ).\n *\n * @example\n * ```html\n * <button ktTooltip=\"Enregistrer le brouillon\">Enregistrer</button>\n * <span ktTooltip=\"Aide\" tooltipPosition=\"right\" [showDelay]=\"300\">?</span>\n * ```\n */\n@Directive({\n selector: '[ktTooltip]',\n host: {\n '[attr.aria-describedby]': 'describedById()',\n '(mouseenter)': 'show()',\n '(mouseleave)': 'hide()',\n '(focusin)': 'show()',\n '(focusout)': 'hide()',\n '(pointerdown)': 'onActivate()',\n '(keydown.escape)': 'onEscape($event)',\n },\n})\nexport class KtTooltip implements OnDestroy {\n private readonly config = inject(KT_TOOLTIP_CONFIG, { optional: true });\n private readonly doc = inject(DOCUMENT);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly vcr = inject(ViewContainerRef);\n private readonly platformId = inject(PLATFORM_ID);\n\n /** Contenu de l'infobulle : texte simple (injecté en `textContent`) ou `TemplateRef` non interactif. */\n readonly ktTooltip = input.required<string | TemplateRef<unknown>>();\n /** Position de l'infobulle autour de la cible. @default 'top' (ou KT_TOOLTIP_CONFIG.position) */\n readonly tooltipPosition = input<KtTooltipPosition>(this.config?.position ?? 'top');\n /** Désactive l'affichage de l'infobulle. @default false */\n readonly tooltipDisabled = input<boolean, unknown>(false, { transform: booleanAttribute });\n /** Délai (ms) avant apparition au survol/focus. @default 150 (ou KT_TOOLTIP_CONFIG.showDelay) */\n readonly showDelay = input<number>(this.config?.showDelay ?? 150);\n /** Délai (ms) avant masquage ; laisse le temps d'amener le pointeur sur l'infobulle (WCAG « hoverable »). @default 100 (ou KT_TOOLTIP_CONFIG.hideDelay) */\n readonly hideDelay = input<number>(this.config?.hideDelay ?? 100);\n\n private readonly idGen = inject(KtIdGenerator);\n private readonly uid = this.idGen.generateId('tooltip');\n private readonly tooltipId = `kt-tooltip-${this.uid}`;\n /** Id du noeud `role=\"tooltip\"`. Public : sert aux liaisons d'accessibilité (`aria-describedby`) du déclencheur. */\n readonly idForA11y = this.tooltipId;\n private readonly anchorName = `--kt-tooltip-anchor-${this.uid}`;\n\n /** Vrai quand l'infobulle est susceptible de s'afficher (contenu non vide et non désactivée).\n Public : lu par `KtField` pour câbler `aria-describedby` du contrôle sur l'infobulle d'aide. */\n readonly isActive = computed(() => {\n if (this.tooltipDisabled()) return false;\n\n const content = this.ktTooltip();\n if (typeof content === 'string') return content.trim().length > 0;\n return true;\n });\n\n // Retourner null retire l'attribut (même astuce que aria-disabled dans button).\n // aria-describedby n'est posé sur le déclencheur que lorsque le tooltip est affiché : sinon il\n // référencerait un nœud absent du DOM (création lazy), donnant une référence pendante aux AT.\n protected describedById = computed(() => (this.isActive() && this.isShown() ? this.tooltipId : null));\n\n private tip: HTMLElement | null = null;\n private view: EmbeddedViewRef<unknown> | null = null;\n private listeners: (() => void)[] = [];\n private showTimer: ReturnType<typeof setTimeout> | undefined;\n private hideTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly isShown = signal(false);\n private _supportsAnchor: boolean | null = null;\n private get supportsAnchor(): boolean {\n if (this._supportsAnchor === null) {\n this._supportsAnchor =\n isPlatformBrowser(this.platformId) &&\n typeof CSS !== 'undefined' &&\n typeof CSS.supports === 'function' &&\n CSS.supports('anchor-name: --x');\n }\n return this._supportsAnchor;\n }\n private fallbackListeners: (() => void)[] = [];\n private activeTemplate: TemplateRef<unknown> | null = null;\n private escListener: (() => void) | null = null;\n\n constructor() {\n // Ancre le déclencheur. setProperty (et non Renderer2.setStyle) car les propriétés\n // CSS à tiret ne sont appliquées qu'ainsi de façon fiable.\n if (isPlatformBrowser(this.platformId)) {\n this.host.nativeElement.style.setProperty('anchor-name', this.anchorName);\n }\n\n // Gestion réactive du cycle de vie du DOM du Tooltip\n effect(() => {\n if (!isPlatformBrowser(this.platformId)) return;\n\n // Création lazy : uniquement si actif ET affiché\n if (!this.isActive() || !this.isShown()) {\n this.destroyTip();\n return;\n }\n\n const tip = this.ensureTip();\n this.registerEscapeListener();\n this.syncContent();\n\n try {\n tip.showPopover?.();\n } catch {\n // Ignorer si déjà ouvert ou non supporté\n }\n\n if (!this.supportsAnchor) {\n this.positionFallback();\n }\n });\n }\n\n ngOnDestroy(): void {\n this.destroyTip();\n }\n\n protected show(): void {\n if (!this.isActive()) return;\n\n clearTimeout(this.hideTimer);\n this.showTimer = setTimeout(() => {\n if (this.isShown()) return;\n\n this.isShown.set(true);\n\n if (!this.supportsAnchor) {\n this.registerFallbackListeners();\n }\n }, this.showDelay());\n }\n\n protected hide(): void {\n clearTimeout(this.showTimer);\n this.hideTimer = setTimeout(() => this.dismiss(), this.hideDelay());\n }\n\n /**\n * Fermeture immédiate à l'activation de la cible (clic souris, tap tactile, stylet).\n * Dès que l'utilisateur AGIT sur l'élément (typiquement un bouton qui ouvre une bottom sheet ou un\n * dialog), l'infobulle a fini son rôle : on la ferme sans attendre le hideDelay, et on purge un\n * affichage en attente pour qu'il ne surgisse pas après coup.\n *\n * Sans ce déclencheur, une infobulle affichée au survol SURVIVAIT à l'ouverture d'un overlay : le\n * pointeur reste sur la cible (aucun `mouseleave`) et un clic ne défocalise pas toujours (aucun\n * `focusout` fiable, ex. Safari/Firefox macOS). Comme l'infobulle est un popover en top layer, elle\n * flottait alors AU-DESSUS de l'overlay (lui empilé au z-index) — impossible à masquer autrement.\n *\n * `pointerdown` (et non `click`) car il précède l'ouverture de l'overlay et le déplacement de focus\n * → zéro flash. On ne fait ni preventDefault ni stopPropagation : l'action native (clic) doit suivre\n * son cours. Le cas clavier (Entrée/Espace) reste couvert par `focusout` quand l'overlay prend le focus.\n */\n protected onActivate(): void {\n clearTimeout(this.showTimer);\n this.dismiss();\n }\n\n protected onEscape(event: Event): void {\n if (!this.isShown()) return;\n\n // Dismiss sans déplacer le pointeur (WCAG 1.4.13) ; on n'annule pas l'action native.\n this.dismiss();\n event.stopPropagation();\n }\n\n private dismiss(): void {\n if (!this.isShown()) return;\n\n this.isShown.set(false);\n }\n\n private ensureTip(): HTMLElement {\n if (this.tip) return this.tip;\n\n const tip = this.renderer.createElement('div') as HTMLElement;\n this.renderer.setAttribute(tip, 'role', 'tooltip');\n this.renderer.setAttribute(tip, 'id', this.tooltipId);\n // manual : on gère nous-mêmes Échap et la fermeture au survol/blur.\n this.renderer.setAttribute(tip, 'popover', 'manual');\n this.renderer.addClass(tip, 'kt-tooltip');\n // setProperty natif : indispensable pour une propriété CSS à tiret.\n tip.style.setProperty('position-anchor', this.anchorName);\n // Top-layer : ajouté au body, immunisé contre overflow/z-index.\n this.renderer.appendChild(this.doc.body, tip);\n\n // Hoverable : passer le pointeur du trigger au tooltip ne le ferme pas.\n this.listeners.push(\n this.renderer.listen(tip, 'mouseenter', () => clearTimeout(this.hideTimer)),\n this.renderer.listen(tip, 'mouseleave', () => this.hide()),\n );\n\n this.tip = tip;\n return tip;\n }\n\n private registerEscapeListener(): void {\n if (this.escListener) return;\n this.escListener = this.renderer.listen('document', 'keydown.escape', (event: KeyboardEvent) => {\n if (this.isShown()) {\n this.dismiss();\n event.stopPropagation();\n }\n });\n }\n\n private syncContent(): void {\n if (!this.tip) return;\n\n this.renderer.setAttribute(this.tip, 'data-position', this.tooltipPosition());\n\n const content = this.ktTooltip();\n\n if (content instanceof TemplateRef) {\n if (this.activeTemplate === content) return;\n this.clearContent();\n this.activeTemplate = content;\n\n this.view = this.vcr.createEmbeddedView(content);\n this.view.detectChanges();\n for (const node of this.view.rootNodes) {\n this.renderer.appendChild(this.tip, node);\n }\n if (isDevMode()) {\n this.warnIfInteractive();\n }\n return;\n }\n\n this.clearContent();\n this.renderer.setProperty(this.tip, 'textContent', content);\n }\n\n private clearContent(): void {\n if (this.view) {\n this.view.destroy();\n this.view = null;\n }\n this.activeTemplate = null;\n if (this.tip) {\n this.renderer.setProperty(this.tip, 'textContent', '');\n }\n }\n\n // Garde-fou a11y : un role=\"tooltip\" ne doit pas contenir d'éléments focusables.\n private warnIfInteractive(): void {\n if (!this.tip) return;\n\n const interactive = this.tip.querySelector('a[href], button, input, select, textarea, [tabindex]');\n if (!interactive) return;\n\n console.warn(\n `[ktTooltip] Un role=\"tooltip\" ne doit pas contenir d'éléments interactifs ` +\n `(<${interactive.nodeName.toLowerCase()}>). Utilisez plutôt un toggletip ou un <dialog>.`,\n );\n }\n\n private destroyTip(): void {\n clearTimeout(this.showTimer);\n clearTimeout(this.hideTimer);\n\n for (const unlisten of this.listeners) unlisten();\n this.listeners = [];\n this.clearFallbackListeners();\n\n if (this.escListener) {\n this.escListener();\n this.escListener = null;\n }\n\n this.view?.destroy();\n this.view = null;\n this.activeTemplate = null;\n\n if (this.tip) {\n try {\n this.tip.hidePopover?.();\n } catch {\n // Ignorer si déjà fermé ou non supporté\n }\n this.tip.remove();\n this.tip = null;\n }\n\n if (this.isShown()) {\n this.isShown.set(false);\n }\n }\n\n private positionFallback(): void {\n if (!this.tip) return;\n const triggerEl = this.host.nativeElement;\n const triggerRect = triggerEl.getBoundingClientRect();\n const tooltipRect = this.tip.getBoundingClientRect();\n const position = this.tooltipPosition();\n const gap = 8;\n\n let top = 0;\n let left = 0;\n\n if (position === 'top') {\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'bottom') {\n top = triggerRect.bottom + gap;\n left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;\n } else if (position === 'left') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n } else if (position === 'right') {\n top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;\n left = triggerRect.right + gap;\n }\n\n const viewWidth = window.innerWidth;\n const viewHeight = window.innerHeight;\n\n if (left < 4) left = 4;\n if (left + tooltipRect.width > viewWidth - 4) {\n left = viewWidth - tooltipRect.width - 4;\n }\n if (top < 4) {\n if (position === 'top') {\n top = triggerRect.bottom + gap;\n } else {\n top = 4;\n }\n }\n if (top + tooltipRect.height > viewHeight - 4) {\n if (position === 'bottom') {\n top = triggerRect.top - tooltipRect.height - gap;\n } else {\n top = viewHeight - tooltipRect.height - 4;\n }\n }\n\n this.tip.style.position = 'fixed';\n this.tip.style.top = `${top}px`;\n this.tip.style.left = `${left}px`;\n this.tip.style.margin = '0';\n }\n\n private registerFallbackListeners(): void {\n this.clearFallbackListeners();\n if (this.supportsAnchor || !isPlatformBrowser(this.platformId)) return;\n\n const onScrollOrResize = () => {\n this.positionFallback();\n };\n window.addEventListener('scroll', onScrollOrResize, { passive: true, capture: true });\n window.addEventListener('resize', onScrollOrResize);\n\n this.fallbackListeners.push(\n () => window.removeEventListener('scroll', onScrollOrResize, { capture: true }),\n () => window.removeEventListener('resize', onScrollOrResize),\n );\n }\n\n private clearFallbackListeners(): void {\n for (const remove of this.fallbackListeners) remove();\n this.fallbackListeners = [];\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,58 +1,8 @@
|
|
|
1
1
|
@layer kt-aaa.components {
|
|
2
2
|
/* Styles SPÉCIFIQUES au multi-select. Tout le panneau commun (trigger, popup, listbox, options,
|
|
3
|
-
filtre, bottom-sheet mobile) vient de ../styles/select-panel.css, chargé en
|
|
4
|
-
styleUrls — ici uniquement :
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/* Réserve la place de la croix (sibling absolu) : sur le TEXTE, pas sur le padding du
|
|
8
|
-
trigger — la flèche reste collée au bord, la croix se glisse entre texte et flèche. */
|
|
9
|
-
.kt-select__trigger--clearable .kt-select__value {
|
|
10
|
-
margin-inline-end: 2rem;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/* Tout effacer : entre le texte et la flèche, disposition standard « texte … ✕ ▾ ».
|
|
14
|
-
24px visibles ; cible étendue à 44px via ::after transparent (AAA). */
|
|
15
|
-
.kt-select__clear {
|
|
16
|
-
position: absolute;
|
|
17
|
-
inset-block-start: 50%;
|
|
18
|
-
inset-inline-end: 2.5rem;
|
|
19
|
-
translate: 0 -50%;
|
|
20
|
-
display: inline-flex;
|
|
21
|
-
align-items: center;
|
|
22
|
-
justify-content: center;
|
|
23
|
-
inline-size: 24px;
|
|
24
|
-
block-size: 24px;
|
|
25
|
-
padding: 0;
|
|
26
|
-
border: 0;
|
|
27
|
-
border-radius: 50%;
|
|
28
|
-
background: transparent;
|
|
29
|
-
color: var(--field-icon-color, #5f6368);
|
|
30
|
-
cursor: pointer;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.kt-select__clear::after {
|
|
34
|
-
content: '';
|
|
35
|
-
position: absolute;
|
|
36
|
-
inset: -10px;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.kt-select__clear:hover {
|
|
40
|
-
background-color: color-mix(in srgb, currentColor 12%, transparent);
|
|
41
|
-
color: var(--field-color, inherit);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.kt-select__clear:focus-visible {
|
|
45
|
-
outline: 2px solid var(--field-border-color-focus, #0b57d0);
|
|
46
|
-
outline-offset: 1px;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.kt-select__clear-icon {
|
|
50
|
-
font-family: 'Material Symbols Outlined';
|
|
51
|
-
font-feature-settings: 'liga';
|
|
52
|
-
font-size: 1.25rem;
|
|
53
|
-
line-height: 1;
|
|
54
|
-
-webkit-font-smoothing: antialiased;
|
|
55
|
-
}
|
|
3
|
+
filtre, bottom-sheet mobile, croix « effacer ») vient de ../styles/select-panel.css, chargé en
|
|
4
|
+
premier via styleUrls — ici uniquement : barre d'actions, compteur, checkboxes d'option et
|
|
5
|
+
chips révocables. */
|
|
56
6
|
|
|
57
7
|
/* Barre d'actions de masse (Tout sélectionner / Tout effacer) en tête de panneau. */
|
|
58
8
|
.kt-select__actions {
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
color: inherit;
|
|
88
88
|
font: inherit;
|
|
89
89
|
caret-color: var(--field-caret-color, auto); /* bascule (thème terminal, etc.) */
|
|
90
|
-
padding-inline-end: 0.5rem;
|
|
90
|
+
padding-inline-end: var(--field-input-padding-end, 0.5rem);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
.kt-field-box__input:disabled {
|
|
@@ -95,6 +95,16 @@
|
|
|
95
95
|
color: color-mix(in srgb, currentColor 50%, transparent);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/* Types temporels natifs (date/time/datetime-local/month) : l'indicateur natif de sélecteur
|
|
99
|
+
(calendrier/horloge) vit à la FIN de l'input et gère déjà son propre espacement. Le respir de
|
|
100
|
+
fin « texte » ne protège ici aucune saisie libre : il ne ferait que repousser ce picto vers
|
|
101
|
+
l'intérieur (renfoncement de 1.25rem = box 0.75 + input 0.5, incohérent avec les champs texte).
|
|
102
|
+
On remet donc le token à 0 ; la gouttière commune reste le padding de la boîte (0.75rem). La
|
|
103
|
+
propriété consommatrice est LOGIQUE => l'indicateur bascule aussi côté départ en RTL. */
|
|
104
|
+
.kt-field-box__input:is([type='date'], [type='time'], [type='datetime-local'], [type='month']) {
|
|
105
|
+
--field-input-padding-end: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
98
108
|
/* Datalist : masque la flèche déroulante native (Chromium) sur les champs texte/number. Le
|
|
99
109
|
pseudo-élément étant partagé avec l'icône de picker des champs date/heure (qui peuvent eux
|
|
100
110
|
aussi porter un `list`), on restreint aux types concernés pour ne pas masquer leur picker. */
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
--select-popup-enter-animation (défaut : none — entrée du dropdown desktop ; keyframes de
|
|
12
12
|
thème limitées à transform/opacity/filter, le popup est ancré : ne pas animer la position),
|
|
13
13
|
--kt-sheet-anim-duration (défaut : 120ms — glissement + scrim de la bottom-sheet mobile).
|
|
14
|
-
Les règles spécifiques au multi (chips,
|
|
14
|
+
Les règles spécifiques au multi (chips, actions de masse, compteur, checkbox) vivent dans
|
|
15
|
+
multi-select.css. La croix « effacer » (clearable) est PARTAGÉE (single + multi) : elle est ici. */
|
|
15
16
|
:host {
|
|
16
17
|
display: block;
|
|
17
18
|
}
|
|
@@ -67,6 +68,57 @@
|
|
|
67
68
|
transform: rotate(180deg);
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
/* ===== Croix « effacer » (clearable) — PARTAGÉE single + multi ===== */
|
|
72
|
+
/* Réserve la place de la croix (sibling absolu) : sur le TEXTE, pas sur le padding du trigger —
|
|
73
|
+
la flèche reste collée au bord, la croix se glisse entre texte et flèche. */
|
|
74
|
+
.kt-select__trigger--clearable .kt-select__value {
|
|
75
|
+
margin-inline-end: 2rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Effacer : entre le texte et la flèche, disposition standard « texte … ✕ ▾ ».
|
|
79
|
+
24px visibles ; cible étendue à 44px via ::after transparent (AAA). */
|
|
80
|
+
.kt-select__clear {
|
|
81
|
+
position: absolute;
|
|
82
|
+
inset-block-start: 50%;
|
|
83
|
+
inset-inline-end: 2.5rem;
|
|
84
|
+
translate: 0 -50%;
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
inline-size: 24px;
|
|
89
|
+
block-size: 24px;
|
|
90
|
+
padding: 0;
|
|
91
|
+
border: 0;
|
|
92
|
+
border-radius: 50%;
|
|
93
|
+
background: transparent;
|
|
94
|
+
color: var(--field-icon-color, #5f6368);
|
|
95
|
+
cursor: pointer;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.kt-select__clear::after {
|
|
99
|
+
content: '';
|
|
100
|
+
position: absolute;
|
|
101
|
+
inset: -10px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.kt-select__clear:hover {
|
|
105
|
+
background-color: color-mix(in srgb, currentColor 12%, transparent);
|
|
106
|
+
color: var(--field-color, inherit);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.kt-select__clear:focus-visible {
|
|
110
|
+
outline: 2px solid var(--field-border-color-focus, #0b57d0);
|
|
111
|
+
outline-offset: 1px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.kt-select__clear-icon {
|
|
115
|
+
font-family: 'Material Symbols Outlined';
|
|
116
|
+
font-feature-settings: 'liga';
|
|
117
|
+
font-size: 1.25rem;
|
|
118
|
+
line-height: 1;
|
|
119
|
+
-webkit-font-smoothing: antialiased;
|
|
120
|
+
}
|
|
121
|
+
|
|
70
122
|
/* Conteneur popover (div). Affiché en top-layer via le Popover API.
|
|
71
123
|
border-box pour aligner la largeur sur le trigger. */
|
|
72
124
|
.kt-select__popup {
|
|
@@ -225,7 +277,10 @@
|
|
|
225
277
|
/* ===== ÉCRAN COMPACT : bottom-sheet (même Popover, restylé) =====
|
|
226
278
|
Pilotée par la CLASSE `kt-select__popup--sheet` posée en JS par le composant (signal
|
|
227
279
|
`KtViewport.isCompact()`) — et NON par un `@media` : le seuil est configurable par appli
|
|
228
|
-
(`provideKtBreakpoints`), source unique JS qui pilote aussi ce style.
|
|
280
|
+
(`provideKtBreakpoints`), source unique JS qui pilote aussi ce style.
|
|
281
|
+
ADR-0005 : le popup est un SCROLLER à snap — spacer (un écran, snap « fermé ») puis carte
|
|
282
|
+
(snap « ouvert » en bas). Le drag-to-dismiss « attrapable partout » et l'arbitrage avec la
|
|
283
|
+
listbox interne sont NATIFS (latching) ; l'entrée/sortie = scrolls programmatiques (JS). */
|
|
229
284
|
.kt-select__popup--sheet {
|
|
230
285
|
position: fixed !important;
|
|
231
286
|
inset: 0 !important;
|
|
@@ -241,10 +296,22 @@
|
|
|
241
296
|
background: transparent !important;
|
|
242
297
|
box-shadow: none !important;
|
|
243
298
|
border-radius: 0 !important;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
299
|
+
display: block;
|
|
300
|
+
overflow-y: auto !important;
|
|
301
|
+
scroll-snap-type: y mandatory;
|
|
302
|
+
/* Pas de scroll chaining vers le fond (le body est déjà verrouillé — ceinture et bretelles). */
|
|
303
|
+
overscroll-behavior: contain;
|
|
304
|
+
/* Le scroller EST le geste : pas de barre de défilement visible sur l'overlay. */
|
|
305
|
+
scrollbar-width: none;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/* Spacer de dismiss : un écran entier au-dessus de la carte. Sous le scrim (z-index 1) :
|
|
309
|
+
les clics l'atteignent (fermeture), les gestes tactiles remontent au scroller (drag depuis
|
|
310
|
+
le scrim, façon Instagram). */
|
|
311
|
+
.kt-select__popup--sheet .kt-select__sheet-spacer {
|
|
312
|
+
block-size: 100%;
|
|
313
|
+
scroll-snap-align: start;
|
|
314
|
+
scroll-snap-stop: always;
|
|
248
315
|
}
|
|
249
316
|
|
|
250
317
|
.kt-select__popup--sheet .kt-select__sheet-card {
|
|
@@ -258,11 +325,10 @@
|
|
|
258
325
|
max-block-size: var(--kt-sheet-max-block-size, 85svh);
|
|
259
326
|
width: 100%;
|
|
260
327
|
overflow: hidden;
|
|
261
|
-
/*
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
transition: translate var(--kt-sheet-anim-duration, 120ms) ease;
|
|
328
|
+
/* Snap « ouvert » : bord bas de la carte aligné au bas du viewport. L'entrée (glissement
|
|
329
|
+
du bas) est le scroll programmatique d'ouverture — plus de keyframe kt-sheet-in ici. */
|
|
330
|
+
scroll-snap-align: end;
|
|
331
|
+
scroll-snap-stop: always;
|
|
266
332
|
}
|
|
267
333
|
|
|
268
334
|
/* Sheet FILTRABLE : hauteur STABLE (et non « au contenu plafonné »). Sans ça, filtrer raccourcit
|
|
@@ -273,24 +339,6 @@
|
|
|
273
339
|
max-block-size: var(--kt-sheet-max-block-size, 85svh);
|
|
274
340
|
}
|
|
275
341
|
|
|
276
|
-
.kt-select__popup--sheet:popover-open .kt-select__sheet-card {
|
|
277
|
-
translate: 0 0;
|
|
278
|
-
/* Entrée : glissement du bas (keyframe PARTAGÉE kt-sheet-in). */
|
|
279
|
-
animation: var(--select-sheet-enter-animation, kt-sheet-in var(--kt-sheet-anim-duration, 120ms) ease);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/* Pendant le drag : la feuille suit le doigt (translate posé en inline), sans transition. */
|
|
283
|
-
.kt-select__popup--sheet .kt-select__sheet-card.kt-select__popup--dragging {
|
|
284
|
-
transition: none;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/* Pendant la fermeture déclenchée par JS */
|
|
288
|
-
.kt-select__popup--sheet.kt-select__popup--closing .kt-select__sheet-card,
|
|
289
|
-
.kt-select__popup--sheet:popover-open.kt-select__popup--closing .kt-select__sheet-card {
|
|
290
|
-
translate: 0 100%;
|
|
291
|
-
transition: translate var(--kt-sheet-exit-duration, 90ms) cubic-bezier(0.4, 0, 0.2, 1);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
342
|
/* Masquer le backdrop popover natif car pointer-events: none y est forcé par le navigateur */
|
|
295
343
|
::ng-deep .kt-select__popup--sheet::backdrop {
|
|
296
344
|
display: none !important;
|
|
@@ -344,27 +392,20 @@
|
|
|
344
392
|
}
|
|
345
393
|
|
|
346
394
|
@media (prefers-reduced-motion: reduce) {
|
|
347
|
-
.kt-select__popup--sheet .kt-select__sheet-card,
|
|
348
395
|
.kt-select__popup--sheet .kt-select__sheet-scrim {
|
|
349
396
|
transition: none;
|
|
350
|
-
translate: 0 0;
|
|
351
397
|
}
|
|
352
398
|
}
|
|
353
399
|
|
|
354
|
-
/* Poignée
|
|
355
|
-
|
|
400
|
+
/* Poignée DÉCORATIVE (ADR-0005) : simple affordance visuelle « ceci se tire » — la sheet
|
|
401
|
+
s'attrape partout au toucher (scroll natif). Ni cursor grab (mensonger : pas de drag souris),
|
|
402
|
+
ni touch-action (le geste EST le scroll), ni cible 44px (ce n'est plus un contrôle). */
|
|
356
403
|
.kt-select__sheet-grab {
|
|
357
404
|
display: flex;
|
|
358
405
|
align-items: center;
|
|
359
406
|
justify-content: center;
|
|
360
407
|
flex: none;
|
|
361
|
-
block-size:
|
|
362
|
-
cursor: grab;
|
|
363
|
-
touch-action: none;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
.kt-select__sheet-grab:active {
|
|
367
|
-
cursor: grabbing;
|
|
408
|
+
block-size: 28px;
|
|
368
409
|
}
|
|
369
410
|
|
|
370
411
|
.kt-select__sheet-grab::before {
|
package/forms/styles/tokens.css
CHANGED
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
--field-padding-y: 0.5rem;
|
|
36
36
|
--field-gap: 0.375rem;
|
|
37
37
|
--field-control-gap: 0.5rem;
|
|
38
|
+
/* Respir de fin propre à l'input (texte/caret), distinct de la gouttière de la boîte
|
|
39
|
+
(--field-padding-x) et de l'écart entre contrôles (--field-control-gap). Neutralisé à 0 pour
|
|
40
|
+
les champs temporels natifs (cf. field-box.css : l'indicateur de picker gère son propre
|
|
41
|
+
espacement, ce respir ne ferait que le décaler vers l'intérieur). */
|
|
42
|
+
--field-input-padding-end: 0.5rem;
|
|
38
43
|
/* Largeur du champ : un seul réglage pilote tous les champs. Défaut `auto` (remplit le
|
|
39
44
|
conteneur en bloc, se dimensionne au contenu en flex). Ex. global : --field-width: 320px. */
|
|
40
45
|
--field-width: auto;
|
package/forms/switch/switch.css
CHANGED
|
@@ -143,6 +143,12 @@
|
|
|
143
143
|
user-select: none;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/* Label vide (ni texte ni contenu projeté — switch nommé via ariaLabel) : masqué pour ne pas
|
|
147
|
+
réserver l'écart flex de la rangée. Le label reste dans le DOM pour accueillir la projection. */
|
|
148
|
+
.kt-switch-label:empty {
|
|
149
|
+
display: none;
|
|
150
|
+
}
|
|
151
|
+
|
|
146
152
|
.kt-switch-field--disabled .kt-switch-label {
|
|
147
153
|
cursor: not-allowed;
|
|
148
154
|
color: var(--field-hint-color, #5f6368);
|
package/package.json
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
/* ============ Socle ============ */
|
|
14
14
|
--kt-surface: light-dark(#eff1f5, #1e1e2e); /* base */
|
|
15
15
|
--kt-on-surface: light-dark(#4c4f69, #cdd6f4); /* text, ~12:1 */
|
|
16
|
-
|
|
16
|
+
/* Latte : subtext1 (subtext0 = 4.36:1, sous AA). 5.5:1 = AA confortable ; 7:1 exigerait
|
|
17
|
+
d'égaler text (#4c4f69) et tuerait la hiérarchie visuelle. Mocha : subtext0, ~7.4:1. */
|
|
18
|
+
--kt-muted: light-dark(#5c5f77, #a6adc8);
|
|
17
19
|
--kt-outline: light-dark(#bcc0cc, #6c7086); /* overlay0 */
|
|
18
20
|
--kt-outline-strong: light-dark(#9ca0b0, #9399b2); /* overlay2 */
|
|
19
21
|
--kt-primary: light-dark(#4a0e94, #cba6f7); /* mauve assombri pour AAA */
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
/* ============ Socle (cyan/magenta sur quasi-noir) ============ */
|
|
48
48
|
--kt-surface: light-dark(#f0f8ff, #0b0f1a);
|
|
49
49
|
--kt-on-surface: light-dark(#04141a, #e6f6ff); /* ~15:1 */
|
|
50
|
-
--kt-muted: light-dark(#
|
|
50
|
+
--kt-muted: light-dark(#3d5468, #94b2c8); /* 7.3:1 (l'ancien #5a7a91 = 4.23:1, sous AA) / ~7:1 */
|
|
51
51
|
--kt-outline: light-dark(#9ec3d9, #2f5a73); /* 3:1 non-texte */
|
|
52
52
|
--kt-outline-strong: light-dark(#5fb6da, #5fb6da);
|
|
53
53
|
--kt-primary: light-dark(#003847, #28d6ef); /* cyan, texte ~10:1 */
|
|
@@ -28,6 +28,11 @@ interface KtSheetDragOptions {
|
|
|
28
28
|
* gère que le glissement. Le gating « écran compact uniquement » reste à l'appelant (signal `isCompact`
|
|
29
29
|
* de `KtViewport`) — la primitive est volontairement agnostique.
|
|
30
30
|
*
|
|
31
|
+
* @deprecated ADR-0005 — les sheets de la lib (Select compact, Dialog `sheet`) sont désormais des
|
|
32
|
+
* scrollers à snap : le drag-to-dismiss « attrapable partout » et l'arbitrage avec le scroll
|
|
33
|
+
* interne sont NATIFS ; cette primitive « poignée + translate » n'a plus de consommateur interne.
|
|
34
|
+
* Sera supprimée dans une prochaine version majeure.
|
|
35
|
+
*
|
|
31
36
|
* @param opts Élément à translater, callback de fermeture, classe de drag et seuil optionnel.
|
|
32
37
|
* @returns Un contrôleur {@link KtSheetDrag} (`start` à brancher sur `pointerdown`, `destroy` au teardown).
|
|
33
38
|
* @example
|
|
@@ -162,30 +162,14 @@ declare class KtDialogFocusInitial {
|
|
|
162
162
|
static ɵdir: i0.ɵɵDirectiveDeclaration<KtDialogFocusInitial, "[ktDialogFocusInitial]", never, {}, {}, never, never, true, never>;
|
|
163
163
|
}
|
|
164
164
|
/**
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* présentation `sheet` / `centered-sheet`. Le drag n'est actif que si le dialog est EFFECTIVEMENT
|
|
171
|
-
* en mode sheet (la pane porte `kt-dialog--sheet`) — pas de dépendance au viewport : un `sheet`
|
|
172
|
-
* toujours-bottom-sheet se drague aussi à la souris.
|
|
173
|
-
*
|
|
174
|
-
* @example
|
|
175
|
-
* ```html
|
|
176
|
-
* <div ktDialogContent>
|
|
177
|
-
* <div ktDialogSheetHandle></div>
|
|
178
|
-
* …
|
|
179
|
-
* </div>
|
|
180
|
-
* ```
|
|
165
|
+
* @deprecated ADR-0005 — la poignée est désormais RENDUE AUTOMATIQUEMENT par `KtDialogContainer`
|
|
166
|
+
* en présentation `sheet` (opt-out : panelClass additionnel `kt-dialog--no-handle`), et le
|
|
167
|
+
* drag-to-dismiss s'attrape sur TOUTE la surface de la sheet (scroll-snap natif). Cette
|
|
168
|
+
* directive est INERTE et son hôte est masqué (évite une double poignée) : retirez-la de vos
|
|
169
|
+
* templates. Sera supprimée dans une prochaine version majeure.
|
|
181
170
|
*/
|
|
182
171
|
declare class KtDialogSheetHandle {
|
|
183
|
-
private readonly dialogRef;
|
|
184
|
-
private readonly host;
|
|
185
|
-
private readonly destroyRef;
|
|
186
|
-
private readonly drag;
|
|
187
172
|
constructor();
|
|
188
|
-
protected onStart(event: PointerEvent): void;
|
|
189
173
|
static ɵfac: i0.ɵɵFactoryDeclaration<KtDialogSheetHandle, never>;
|
|
190
174
|
static ɵdir: i0.ɵɵDirectiveDeclaration<KtDialogSheetHandle, "[ktDialogSheetHandle]", never, {}, {}, never, never, true, never>;
|
|
191
175
|
}
|
|
@@ -357,7 +341,14 @@ declare class KtDialogContainer extends CdkDialogContainer {
|
|
|
357
341
|
private readonly elementRef;
|
|
358
342
|
private readonly host;
|
|
359
343
|
private readonly platformId;
|
|
344
|
+
private readonly destroyRef;
|
|
345
|
+
private readonly bodyScrollLock;
|
|
360
346
|
protected readonly isClosing: i0.WritableSignal<boolean>;
|
|
347
|
+
/** Armé quand l'ouverture a dépassé 50px : un repos à ~0 est alors forcément le snap « fermé ». */
|
|
348
|
+
private sheetArmed;
|
|
349
|
+
/** Fermeture réelle en attente du repos au snap « fermé » (sortie programmatique animée). */
|
|
350
|
+
private pendingSheetClose;
|
|
351
|
+
private sheetCloseTimer;
|
|
361
352
|
/** Premier id de la file `aria-labelledby` exposée par `CdkDialogContainer`. Le membre
|
|
362
353
|
`_ariaLabelledByQueue` est interne au CDK (préfixe `_`) : on l'encapsule ICI, gardé, pour que
|
|
363
354
|
le binding de template ne lise jamais l'interne directement. Si une montée du CDK retire ou
|
|
@@ -365,6 +356,25 @@ declare class KtDialogContainer extends CdkDialogContainer {
|
|
|
365
356
|
protected get ariaLabelledBy(): string | null;
|
|
366
357
|
constructor();
|
|
367
358
|
protected isSheet(): boolean;
|
|
359
|
+
/** Poignée décorative auto-rendue en présentation sheet. Opt-out : panelClass `kt-dialog--no-handle`. */
|
|
360
|
+
protected showSheetHandle(): boolean;
|
|
361
|
+
/** Tap sur le spacer (zone extérieure à la carte) = fermeture, façon backdrop. Le conteneur
|
|
362
|
+
captant désormais le tactile (pointer-events auto, requis pour le drag iOS), le clic ne
|
|
363
|
+
traverse plus vers le backdrop CDK : on porte donc ICI la fermeture au tap-extérieur, en
|
|
364
|
+
respectant `disableClose` (comme le faisait le backdropClick natif). Un drag n'émet pas de
|
|
365
|
+
`click` (le navigateur le supprime après un scroll) : seul un vrai tap ferme. */
|
|
366
|
+
protected onScrimClick(): void;
|
|
367
|
+
/** Sheet scroll-snap : écouteurs (détection du repos + garde molette) et scroll d'ENTRÉE
|
|
368
|
+
programmatique vers le snap « ouvert ». Appelé au premier rendu, en présentation sheet. */
|
|
369
|
+
private initSheetGesture;
|
|
370
|
+
private prefersReducedMotion;
|
|
371
|
+
/** Détection du snap « fermé » par position de scroll (ni scrollsnapchange ni scrollend — cf.
|
|
372
|
+
ADR-0005). Un repos à ~0 finalise la fermeture en attente, ou EST une fermeture par geste. */
|
|
373
|
+
private readonly onSheetScroll;
|
|
374
|
+
/** La molette ne ferme JAMAIS la sheet (pas de geste souris — ADR-0005) : seuls les scrollers
|
|
375
|
+
INTERNES peuvent consommer, dans leurs bornes (générique : un dialog peut imbriquer
|
|
376
|
+
plusieurs zones scrollables). */
|
|
377
|
+
private readonly onSheetWheel;
|
|
368
378
|
private animateAndClose;
|
|
369
379
|
static ɵfac: i0.ɵɵFactoryDeclaration<KtDialogContainer, never>;
|
|
370
380
|
static ɵcmp: i0.ɵɵComponentDeclaration<KtDialogContainer, "kt-dialog-container", never, {}, {}, never, never, true, never>;
|