@edsis/ui 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/accordion/README.md +195 -0
- package/alert/README.md +177 -0
- package/alert-dialog/README.md +239 -0
- package/aspect-ratio/README.md +112 -0
- package/avatar/README.md +176 -0
- package/badge/README.md +133 -0
- package/breadcrumb/README.md +216 -0
- package/button/README.md +139 -0
- package/button-group/README.md +204 -0
- package/calendar/README.md +132 -0
- package/card/README.md +220 -0
- package/carousel/README.md +276 -0
- package/chart/README.md +249 -0
- package/checkbox/README.md +149 -0
- package/collapsible/README.md +191 -0
- package/combobox/README.md +198 -0
- package/command/README.md +275 -0
- package/composer/README.md +235 -0
- package/context-menu/README.md +267 -0
- package/date-picker/README.md +177 -0
- package/dialog/README.md +237 -0
- package/drawer/README.md +145 -0
- package/dropdown-menu/README.md +311 -0
- package/editor/README.md +136 -0
- package/empty/README.md +183 -0
- package/fesm2022/edsis-ui-accordion.mjs +174 -0
- package/fesm2022/edsis-ui-accordion.mjs.map +1 -0
- package/fesm2022/edsis-ui-alert-dialog.mjs +242 -0
- package/fesm2022/edsis-ui-alert-dialog.mjs.map +1 -0
- package/fesm2022/edsis-ui-alert.mjs +90 -0
- package/fesm2022/edsis-ui-alert.mjs.map +1 -0
- package/fesm2022/edsis-ui-aspect-ratio.mjs +33 -0
- package/fesm2022/edsis-ui-aspect-ratio.mjs.map +1 -0
- package/fesm2022/edsis-ui-avatar.mjs +123 -0
- package/fesm2022/edsis-ui-avatar.mjs.map +1 -0
- package/fesm2022/edsis-ui-badge.mjs +47 -0
- package/fesm2022/edsis-ui-badge.mjs.map +1 -0
- package/fesm2022/edsis-ui-breadcrumb.mjs +186 -0
- package/fesm2022/edsis-ui-breadcrumb.mjs.map +1 -0
- package/fesm2022/edsis-ui-button-group.mjs +95 -0
- package/fesm2022/edsis-ui-button-group.mjs.map +1 -0
- package/fesm2022/edsis-ui-button.mjs +64 -0
- package/fesm2022/edsis-ui-button.mjs.map +1 -0
- package/fesm2022/edsis-ui-calendar.mjs +78 -0
- package/fesm2022/edsis-ui-calendar.mjs.map +1 -0
- package/fesm2022/edsis-ui-card.mjs +137 -0
- package/fesm2022/edsis-ui-card.mjs.map +1 -0
- package/fesm2022/edsis-ui-carousel.mjs +310 -0
- package/fesm2022/edsis-ui-carousel.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-area.mjs +6 -0
- package/fesm2022/edsis-ui-chart-area.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-bar.mjs +6 -0
- package/fesm2022/edsis-ui-chart-bar.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-line.mjs +6 -0
- package/fesm2022/edsis-ui-chart-line.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-pie.mjs +6 -0
- package/fesm2022/edsis-ui-chart-pie.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-radar.mjs +6 -0
- package/fesm2022/edsis-ui-chart-radar.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-radial.mjs +6 -0
- package/fesm2022/edsis-ui-chart-radial.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart-scatter.mjs +6 -0
- package/fesm2022/edsis-ui-chart-scatter.mjs.map +1 -0
- package/fesm2022/edsis-ui-chart.mjs +3714 -0
- package/fesm2022/edsis-ui-chart.mjs.map +1 -0
- package/fesm2022/edsis-ui-checkbox.mjs +104 -0
- package/fesm2022/edsis-ui-checkbox.mjs.map +1 -0
- package/fesm2022/edsis-ui-collapsible.mjs +116 -0
- package/fesm2022/edsis-ui-collapsible.mjs.map +1 -0
- package/fesm2022/edsis-ui-combobox.mjs +263 -0
- package/fesm2022/edsis-ui-combobox.mjs.map +1 -0
- package/fesm2022/edsis-ui-command.mjs +268 -0
- package/fesm2022/edsis-ui-command.mjs.map +1 -0
- package/fesm2022/edsis-ui-composer.mjs +329 -0
- package/fesm2022/edsis-ui-composer.mjs.map +1 -0
- package/fesm2022/edsis-ui-context-menu.mjs +100 -0
- package/fesm2022/edsis-ui-context-menu.mjs.map +1 -0
- package/fesm2022/edsis-ui-date-picker.mjs +155 -0
- package/fesm2022/edsis-ui-date-picker.mjs.map +1 -0
- package/fesm2022/edsis-ui-dialog.mjs +262 -0
- package/fesm2022/edsis-ui-dialog.mjs.map +1 -0
- package/fesm2022/edsis-ui-drawer.mjs +6 -0
- package/fesm2022/edsis-ui-drawer.mjs.map +1 -0
- package/fesm2022/edsis-ui-dropdown-menu.mjs +466 -0
- package/fesm2022/edsis-ui-dropdown-menu.mjs.map +1 -0
- package/fesm2022/edsis-ui-editor.mjs +692 -0
- package/fesm2022/edsis-ui-editor.mjs.map +1 -0
- package/fesm2022/edsis-ui-empty.mjs +132 -0
- package/fesm2022/edsis-ui-empty.mjs.map +1 -0
- package/fesm2022/edsis-ui-form.mjs +334 -0
- package/fesm2022/edsis-ui-form.mjs.map +1 -0
- package/fesm2022/edsis-ui-hover-card.mjs +284 -0
- package/fesm2022/edsis-ui-hover-card.mjs.map +1 -0
- package/fesm2022/edsis-ui-input-group.mjs +164 -0
- package/fesm2022/edsis-ui-input-group.mjs.map +1 -0
- package/fesm2022/edsis-ui-input-otp.mjs +485 -0
- package/fesm2022/edsis-ui-input-otp.mjs.map +1 -0
- package/fesm2022/edsis-ui-input.mjs +43 -0
- package/fesm2022/edsis-ui-input.mjs.map +1 -0
- package/fesm2022/edsis-ui-item.mjs +241 -0
- package/fesm2022/edsis-ui-item.mjs.map +1 -0
- package/fesm2022/edsis-ui-kanban.mjs +289 -0
- package/fesm2022/edsis-ui-kanban.mjs.map +1 -0
- package/fesm2022/edsis-ui-kbd.mjs +51 -0
- package/fesm2022/edsis-ui-kbd.mjs.map +1 -0
- package/fesm2022/edsis-ui-label.mjs +30 -0
- package/fesm2022/edsis-ui-label.mjs.map +1 -0
- package/fesm2022/edsis-ui-menubar.mjs +302 -0
- package/fesm2022/edsis-ui-menubar.mjs.map +1 -0
- package/fesm2022/edsis-ui-native-select.mjs +61 -0
- package/fesm2022/edsis-ui-native-select.mjs.map +1 -0
- package/fesm2022/edsis-ui-navigation-menu.mjs +399 -0
- package/fesm2022/edsis-ui-navigation-menu.mjs.map +1 -0
- package/fesm2022/edsis-ui-pagination.mjs +216 -0
- package/fesm2022/edsis-ui-pagination.mjs.map +1 -0
- package/fesm2022/edsis-ui-pillbox.mjs +777 -0
- package/fesm2022/edsis-ui-pillbox.mjs.map +1 -0
- package/fesm2022/edsis-ui-popover.mjs +163 -0
- package/fesm2022/edsis-ui-popover.mjs.map +1 -0
- package/fesm2022/edsis-ui-progress.mjs +53 -0
- package/fesm2022/edsis-ui-progress.mjs.map +1 -0
- package/fesm2022/edsis-ui-radio.mjs +111 -0
- package/fesm2022/edsis-ui-radio.mjs.map +1 -0
- package/fesm2022/edsis-ui-resizable.mjs +454 -0
- package/fesm2022/edsis-ui-resizable.mjs.map +1 -0
- package/fesm2022/edsis-ui-scroll-area.mjs +48 -0
- package/fesm2022/edsis-ui-scroll-area.mjs.map +1 -0
- package/fesm2022/edsis-ui-select.mjs +164 -0
- package/fesm2022/edsis-ui-select.mjs.map +1 -0
- package/fesm2022/edsis-ui-separator.mjs +33 -0
- package/fesm2022/edsis-ui-separator.mjs.map +1 -0
- package/fesm2022/edsis-ui-sheet.mjs +264 -0
- package/fesm2022/edsis-ui-sheet.mjs.map +1 -0
- package/fesm2022/edsis-ui-skeleton.mjs +29 -0
- package/fesm2022/edsis-ui-skeleton.mjs.map +1 -0
- package/fesm2022/edsis-ui-slider.mjs +405 -0
- package/fesm2022/edsis-ui-slider.mjs.map +1 -0
- package/fesm2022/edsis-ui-spinner.mjs +58 -0
- package/fesm2022/edsis-ui-spinner.mjs.map +1 -0
- package/fesm2022/edsis-ui-switch.mjs +107 -0
- package/fesm2022/edsis-ui-switch.mjs.map +1 -0
- package/fesm2022/edsis-ui-table.mjs +139 -0
- package/fesm2022/edsis-ui-table.mjs.map +1 -0
- package/fesm2022/edsis-ui-tabs.mjs +252 -0
- package/fesm2022/edsis-ui-tabs.mjs.map +1 -0
- package/fesm2022/edsis-ui-textarea.mjs +37 -0
- package/fesm2022/edsis-ui-textarea.mjs.map +1 -0
- package/fesm2022/edsis-ui-timeline.mjs +213 -0
- package/fesm2022/edsis-ui-timeline.mjs.map +1 -0
- package/fesm2022/edsis-ui-toast.mjs +71 -0
- package/fesm2022/edsis-ui-toast.mjs.map +1 -0
- package/fesm2022/edsis-ui-toggle-group.mjs +269 -0
- package/fesm2022/edsis-ui-toggle-group.mjs.map +1 -0
- package/fesm2022/edsis-ui-toggle.mjs +76 -0
- package/fesm2022/edsis-ui-toggle.mjs.map +1 -0
- package/fesm2022/edsis-ui-tooltip.mjs +339 -0
- package/fesm2022/edsis-ui-tooltip.mjs.map +1 -0
- package/fesm2022/edsis-ui-utils.mjs +13 -0
- package/fesm2022/edsis-ui-utils.mjs.map +1 -0
- package/fesm2022/edsis-ui.mjs +11 -0
- package/fesm2022/edsis-ui.mjs.map +1 -0
- package/form/README.md +210 -0
- package/hover-card/README.md +146 -0
- package/input/README.md +159 -0
- package/input-group/README.md +234 -0
- package/input-otp/README.md +273 -0
- package/item/README.md +247 -0
- package/kanban/README.md +81 -0
- package/kbd/README.md +139 -0
- package/label/README.md +136 -0
- package/menubar/README.md +269 -0
- package/native-select/README.md +176 -0
- package/navigation-menu/README.md +160 -0
- package/package.json +310 -0
- package/pagination/README.md +144 -0
- package/pillbox/README.md +67 -0
- package/popover/README.md +43 -0
- package/progress/README.md +160 -0
- package/radio/README.md +209 -0
- package/resizable/README.md +164 -0
- package/scroll-area/README.md +143 -0
- package/select/README.md +174 -0
- package/separator/README.md +170 -0
- package/sheet/README.md +183 -0
- package/skeleton/README.md +158 -0
- package/slider/README.md +207 -0
- package/spinner/README.md +160 -0
- package/switch/README.md +166 -0
- package/table/README.md +291 -0
- package/tabs/README.md +214 -0
- package/textarea/README.md +154 -0
- package/timeline/README.md +94 -0
- package/toast/README.md +321 -0
- package/toggle/README.md +131 -0
- package/toggle-group/README.md +206 -0
- package/tooltip/README.md +211 -0
- package/types/edsis-ui-accordion.d.ts +51 -0
- package/types/edsis-ui-alert-dialog.d.ts +93 -0
- package/types/edsis-ui-alert.d.ts +37 -0
- package/types/edsis-ui-aspect-ratio.d.ts +12 -0
- package/types/edsis-ui-avatar.d.ts +51 -0
- package/types/edsis-ui-badge.d.ts +19 -0
- package/types/edsis-ui-breadcrumb.d.ts +46 -0
- package/types/edsis-ui-button-group.d.ts +26 -0
- package/types/edsis-ui-button.d.ts +22 -0
- package/types/edsis-ui-calendar.d.ts +33 -0
- package/types/edsis-ui-card.d.ts +60 -0
- package/types/edsis-ui-carousel.d.ts +86 -0
- package/types/edsis-ui-chart-area.d.ts +1 -0
- package/types/edsis-ui-chart-bar.d.ts +1 -0
- package/types/edsis-ui-chart-line.d.ts +1 -0
- package/types/edsis-ui-chart-pie.d.ts +1 -0
- package/types/edsis-ui-chart-radar.d.ts +1 -0
- package/types/edsis-ui-chart-radial.d.ts +1 -0
- package/types/edsis-ui-chart-scatter.d.ts +1 -0
- package/types/edsis-ui-chart.d.ts +1094 -0
- package/types/edsis-ui-checkbox.d.ts +35 -0
- package/types/edsis-ui-collapsible.d.ts +42 -0
- package/types/edsis-ui-combobox.d.ts +51 -0
- package/types/edsis-ui-command.d.ts +99 -0
- package/types/edsis-ui-composer.d.ts +90 -0
- package/types/edsis-ui-context-menu.d.ts +35 -0
- package/types/edsis-ui-date-picker.d.ts +41 -0
- package/types/edsis-ui-dialog.d.ts +87 -0
- package/types/edsis-ui-drawer.d.ts +1 -0
- package/types/edsis-ui-dropdown-menu.d.ts +136 -0
- package/types/edsis-ui-editor.d.ts +123 -0
- package/types/edsis-ui-empty.d.ts +50 -0
- package/types/edsis-ui-form.d.ts +141 -0
- package/types/edsis-ui-hover-card.d.ts +74 -0
- package/types/edsis-ui-input-group.d.ts +51 -0
- package/types/edsis-ui-input-otp.d.ts +136 -0
- package/types/edsis-ui-input.d.ts +16 -0
- package/types/edsis-ui-item.d.ts +88 -0
- package/types/edsis-ui-kanban.d.ts +70 -0
- package/types/edsis-ui-kbd.d.ts +16 -0
- package/types/edsis-ui-label.d.ts +11 -0
- package/types/edsis-ui-menubar.d.ts +67 -0
- package/types/edsis-ui-native-select.d.ts +26 -0
- package/types/edsis-ui-navigation-menu.d.ts +96 -0
- package/types/edsis-ui-pagination.d.ts +34 -0
- package/types/edsis-ui-pillbox.d.ts +157 -0
- package/types/edsis-ui-popover.d.ts +43 -0
- package/types/edsis-ui-progress.d.ts +17 -0
- package/types/edsis-ui-radio.d.ts +40 -0
- package/types/edsis-ui-resizable.d.ts +99 -0
- package/types/edsis-ui-scroll-area.d.ts +19 -0
- package/types/edsis-ui-select.d.ts +57 -0
- package/types/edsis-ui-separator.d.ts +14 -0
- package/types/edsis-ui-sheet.d.ts +76 -0
- package/types/edsis-ui-skeleton.d.ts +10 -0
- package/types/edsis-ui-slider.d.ts +74 -0
- package/types/edsis-ui-spinner.d.ts +13 -0
- package/types/edsis-ui-switch.d.ts +40 -0
- package/types/edsis-ui-table.d.ts +52 -0
- package/types/edsis-ui-tabs.d.ts +92 -0
- package/types/edsis-ui-textarea.d.ts +12 -0
- package/types/edsis-ui-timeline.d.ts +63 -0
- package/types/edsis-ui-toast.d.ts +38 -0
- package/types/edsis-ui-toggle-group.d.ts +89 -0
- package/types/edsis-ui-toggle.d.ts +25 -0
- package/types/edsis-ui-tooltip.d.ts +89 -0
- package/types/edsis-ui-utils.d.ts +5 -0
- package/types/edsis-ui.d.ts +2 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, input, forwardRef, ChangeDetectionStrategy, Component, inject, TemplateRef, Directive, ViewContainerRef, ElementRef, DestroyRef, output, signal, effect } from '@angular/core';
|
|
3
|
+
import { Overlay } from '@angular/cdk/overlay';
|
|
4
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
5
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { merge } from 'rxjs';
|
|
7
|
+
import { filter } from 'rxjs/operators';
|
|
8
|
+
import * as i1 from '@angular/material/tooltip';
|
|
9
|
+
import { MatTooltip } from '@angular/material/tooltip';
|
|
10
|
+
|
|
11
|
+
const TOOLTIP_DEFAULTS = new InjectionToken('TOOLTIP_DEFAULTS');
|
|
12
|
+
class TooltipComponent {
|
|
13
|
+
side = input('top', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
14
|
+
align = input('center', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
15
|
+
sideOffset = input(4, ...(ngDevMode ? [{ debugName: "sideOffset" }] : /* istanbul ignore next */ []));
|
|
16
|
+
openDelay = input(150, ...(ngDevMode ? [{ debugName: "openDelay" }] : /* istanbul ignore next */ []));
|
|
17
|
+
closeDelay = input(0, ...(ngDevMode ? [{ debugName: "closeDelay" }] : /* istanbul ignore next */ []));
|
|
18
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
19
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.14", type: TooltipComponent, isStandalone: true, selector: "ui-tooltip", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "contents" }, providers: [{ provide: TOOLTIP_DEFAULTS, useExisting: forwardRef(() => TooltipComponent) }], ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
20
|
+
}
|
|
21
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipComponent, decorators: [{
|
|
22
|
+
type: Component,
|
|
23
|
+
args: [{
|
|
24
|
+
selector: 'ui-tooltip',
|
|
25
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
26
|
+
providers: [{ provide: TOOLTIP_DEFAULTS, useExisting: forwardRef(() => TooltipComponent) }],
|
|
27
|
+
host: {
|
|
28
|
+
class: 'contents',
|
|
29
|
+
},
|
|
30
|
+
template: '<ng-content />',
|
|
31
|
+
}]
|
|
32
|
+
}], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }] } });
|
|
33
|
+
|
|
34
|
+
class TooltipContentDirective {
|
|
35
|
+
template = inject(TemplateRef);
|
|
36
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipContentDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
37
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: TooltipContentDirective, isStandalone: true, selector: "ng-template[uiTooltipContent]", exportAs: ["uiTooltipContent"], ngImport: i0 });
|
|
38
|
+
}
|
|
39
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipContentDirective, decorators: [{
|
|
40
|
+
type: Directive,
|
|
41
|
+
args: [{
|
|
42
|
+
selector: 'ng-template[uiTooltipContent]',
|
|
43
|
+
exportAs: 'uiTooltipContent',
|
|
44
|
+
}]
|
|
45
|
+
}] });
|
|
46
|
+
|
|
47
|
+
const TOOLTIP_PANEL_CLASSES = [
|
|
48
|
+
'ui-tooltip-panel',
|
|
49
|
+
'pointer-events-none',
|
|
50
|
+
'z-50',
|
|
51
|
+
'max-w-xs',
|
|
52
|
+
'overflow-hidden',
|
|
53
|
+
'rounded-md',
|
|
54
|
+
'border',
|
|
55
|
+
'border-border',
|
|
56
|
+
'bg-primary',
|
|
57
|
+
'px-3',
|
|
58
|
+
'py-1.5',
|
|
59
|
+
'text-xs',
|
|
60
|
+
'font-medium',
|
|
61
|
+
'leading-none',
|
|
62
|
+
'text-primary-foreground',
|
|
63
|
+
'shadow-md',
|
|
64
|
+
'select-none',
|
|
65
|
+
];
|
|
66
|
+
const POSITION_ANCHORS = {
|
|
67
|
+
top: (align) => ({
|
|
68
|
+
originX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',
|
|
69
|
+
originY: 'top',
|
|
70
|
+
overlayX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',
|
|
71
|
+
overlayY: 'bottom',
|
|
72
|
+
}),
|
|
73
|
+
bottom: (align) => ({
|
|
74
|
+
originX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',
|
|
75
|
+
originY: 'bottom',
|
|
76
|
+
overlayX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',
|
|
77
|
+
overlayY: 'top',
|
|
78
|
+
}),
|
|
79
|
+
left: (align) => ({
|
|
80
|
+
originX: 'start',
|
|
81
|
+
originY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',
|
|
82
|
+
overlayX: 'end',
|
|
83
|
+
overlayY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',
|
|
84
|
+
}),
|
|
85
|
+
right: (align) => ({
|
|
86
|
+
originX: 'end',
|
|
87
|
+
originY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',
|
|
88
|
+
overlayX: 'start',
|
|
89
|
+
overlayY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
function positionFor(side, align, sideOffset) {
|
|
93
|
+
const anchor = POSITION_ANCHORS[side](align);
|
|
94
|
+
if (side === 'top') {
|
|
95
|
+
return { ...anchor, offsetY: -sideOffset };
|
|
96
|
+
}
|
|
97
|
+
if (side === 'bottom') {
|
|
98
|
+
return { ...anchor, offsetY: sideOffset };
|
|
99
|
+
}
|
|
100
|
+
if (side === 'left') {
|
|
101
|
+
return { ...anchor, offsetX: -sideOffset };
|
|
102
|
+
}
|
|
103
|
+
return { ...anchor, offsetX: sideOffset };
|
|
104
|
+
}
|
|
105
|
+
let nextTooltipId = 0;
|
|
106
|
+
class TooltipTriggerDirective {
|
|
107
|
+
overlay = inject(Overlay);
|
|
108
|
+
vcr = inject(ViewContainerRef);
|
|
109
|
+
el = inject(ElementRef);
|
|
110
|
+
destroyRef = inject(DestroyRef);
|
|
111
|
+
defaults = inject(TOOLTIP_DEFAULTS, { optional: true });
|
|
112
|
+
uiTooltipTrigger = input.required(...(ngDevMode ? [{ debugName: "uiTooltipTrigger" }] : /* istanbul ignore next */ []));
|
|
113
|
+
side = input(undefined, ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
|
|
114
|
+
align = input(undefined, ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
|
|
115
|
+
sideOffset = input(undefined, ...(ngDevMode ? [{ debugName: "sideOffset" }] : /* istanbul ignore next */ []));
|
|
116
|
+
openDelay = input(undefined, ...(ngDevMode ? [{ debugName: "openDelay" }] : /* istanbul ignore next */ []));
|
|
117
|
+
closeDelay = input(undefined, ...(ngDevMode ? [{ debugName: "closeDelay" }] : /* istanbul ignore next */ []));
|
|
118
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
119
|
+
openedChange = output();
|
|
120
|
+
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
121
|
+
contentId = signal(null, ...(ngDevMode ? [{ debugName: "contentId" }] : /* istanbul ignore next */ []));
|
|
122
|
+
overlayRef = null;
|
|
123
|
+
openTimeoutId = null;
|
|
124
|
+
closeTimeoutId = null;
|
|
125
|
+
isPointerInsideTrigger = false;
|
|
126
|
+
isTriggerFocused = false;
|
|
127
|
+
isDestroying = false;
|
|
128
|
+
constructor() {
|
|
129
|
+
this.destroyRef.onDestroy(() => {
|
|
130
|
+
this.isDestroying = true;
|
|
131
|
+
this.clearOpenTimeout();
|
|
132
|
+
this.clearCloseTimeout();
|
|
133
|
+
this.contentId.set(null);
|
|
134
|
+
this.isOpen.set(false);
|
|
135
|
+
this.overlayRef?.dispose();
|
|
136
|
+
this.overlayRef = null;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
handlePointerEnter() {
|
|
140
|
+
if (this.disabled()) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.isPointerInsideTrigger = true;
|
|
144
|
+
this.clearCloseTimeout();
|
|
145
|
+
this.scheduleOpen();
|
|
146
|
+
}
|
|
147
|
+
handlePointerLeave(event) {
|
|
148
|
+
if (this.el.nativeElement.contains(event.relatedTarget)) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.isPointerInsideTrigger = false;
|
|
152
|
+
this.scheduleClose();
|
|
153
|
+
}
|
|
154
|
+
handleFocusIn() {
|
|
155
|
+
if (this.disabled()) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.isTriggerFocused = true;
|
|
159
|
+
this.clearCloseTimeout();
|
|
160
|
+
this.scheduleOpen();
|
|
161
|
+
}
|
|
162
|
+
handleFocusOut(event) {
|
|
163
|
+
if (this.el.nativeElement.contains(event.relatedTarget)) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.isTriggerFocused = false;
|
|
167
|
+
this.scheduleClose();
|
|
168
|
+
}
|
|
169
|
+
open() {
|
|
170
|
+
if (this.isOpen() || this.disabled()) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const side = this.side() ?? this.defaults?.side() ?? 'top';
|
|
174
|
+
const align = this.align() ?? this.defaults?.align() ?? 'center';
|
|
175
|
+
const sideOffset = this.sideOffset() ?? this.defaults?.sideOffset() ?? 4;
|
|
176
|
+
const primary = positionFor(side, align, sideOffset);
|
|
177
|
+
const fallback = positionFor(this.oppositeSide(side), align, sideOffset);
|
|
178
|
+
const positionStrategy = this.overlay
|
|
179
|
+
.position()
|
|
180
|
+
.flexibleConnectedTo(this.el)
|
|
181
|
+
.withPositions([primary, fallback])
|
|
182
|
+
.withPush(false)
|
|
183
|
+
.withFlexibleDimensions(false);
|
|
184
|
+
this.overlayRef = this.overlay.create({
|
|
185
|
+
positionStrategy,
|
|
186
|
+
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
187
|
+
hasBackdrop: false,
|
|
188
|
+
panelClass: [...TOOLTIP_PANEL_CLASSES],
|
|
189
|
+
});
|
|
190
|
+
const tooltipId = `ui-tooltip-${nextTooltipId++}`;
|
|
191
|
+
this.overlayRef.overlayElement.id = tooltipId;
|
|
192
|
+
this.overlayRef.overlayElement.setAttribute('role', 'tooltip');
|
|
193
|
+
const portal = new TemplatePortal(this.uiTooltipTrigger().template, this.vcr);
|
|
194
|
+
this.overlayRef.attach(portal);
|
|
195
|
+
this.bindOverlayLifecycle();
|
|
196
|
+
this.contentId.set(tooltipId);
|
|
197
|
+
this.isOpen.set(true);
|
|
198
|
+
if (!this.isDestroying) {
|
|
199
|
+
this.openedChange.emit(true);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
close() {
|
|
203
|
+
this.clearOpenTimeout();
|
|
204
|
+
this.clearCloseTimeout();
|
|
205
|
+
if (!this.isOpen()) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
this.overlayRef?.dispose();
|
|
209
|
+
this.overlayRef = null;
|
|
210
|
+
this.contentId.set(null);
|
|
211
|
+
this.isOpen.set(false);
|
|
212
|
+
if (!this.isDestroying) {
|
|
213
|
+
this.openedChange.emit(false);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
bindOverlayLifecycle() {
|
|
217
|
+
if (!this.overlayRef) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
merge(this.overlayRef
|
|
221
|
+
.outsidePointerEvents()
|
|
222
|
+
.pipe(filter((event) => !this.el.nativeElement.contains(event.target))), this.overlayRef.keydownEvents().pipe(filter((event) => event.key === 'Escape')), this.overlayRef.detachments())
|
|
223
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
224
|
+
.subscribe(() => this.close());
|
|
225
|
+
}
|
|
226
|
+
scheduleOpen() {
|
|
227
|
+
this.clearCloseTimeout();
|
|
228
|
+
if (this.isOpen()) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
this.clearOpenTimeout();
|
|
232
|
+
this.openTimeoutId = window.setTimeout(() => {
|
|
233
|
+
this.openTimeoutId = null;
|
|
234
|
+
if (this.disabled() || (!this.isPointerInsideTrigger && !this.isTriggerFocused)) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.open();
|
|
238
|
+
}, this.openDelay() ?? this.defaults?.openDelay() ?? 150);
|
|
239
|
+
}
|
|
240
|
+
scheduleClose() {
|
|
241
|
+
this.clearOpenTimeout();
|
|
242
|
+
if (!this.isOpen()) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this.clearCloseTimeout();
|
|
246
|
+
this.closeTimeoutId = window.setTimeout(() => {
|
|
247
|
+
this.closeTimeoutId = null;
|
|
248
|
+
if (this.isPointerInsideTrigger || this.isTriggerFocused) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
this.close();
|
|
252
|
+
}, this.closeDelay() ?? this.defaults?.closeDelay() ?? 0);
|
|
253
|
+
}
|
|
254
|
+
clearOpenTimeout() {
|
|
255
|
+
if (this.openTimeoutId !== null) {
|
|
256
|
+
window.clearTimeout(this.openTimeoutId);
|
|
257
|
+
this.openTimeoutId = null;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
clearCloseTimeout() {
|
|
261
|
+
if (this.closeTimeoutId !== null) {
|
|
262
|
+
window.clearTimeout(this.closeTimeoutId);
|
|
263
|
+
this.closeTimeoutId = null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
oppositeSide(side) {
|
|
267
|
+
return side === 'top' ? 'bottom' : side === 'bottom' ? 'top' : side === 'left' ? 'right' : 'left';
|
|
268
|
+
}
|
|
269
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
270
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: TooltipTriggerDirective, isStandalone: true, selector: "[uiTooltipTrigger]", inputs: { uiTooltipTrigger: { classPropertyName: "uiTooltipTrigger", publicName: "uiTooltipTrigger", isSignal: true, isRequired: true, transformFunction: null }, side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, sideOffset: { classPropertyName: "sideOffset", publicName: "sideOffset", isSignal: true, isRequired: false, transformFunction: null }, openDelay: { classPropertyName: "openDelay", publicName: "openDelay", isSignal: true, isRequired: false, transformFunction: null }, closeDelay: { classPropertyName: "closeDelay", publicName: "closeDelay", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedChange: "openedChange" }, host: { listeners: { "pointerenter": "handlePointerEnter()", "pointerleave": "handlePointerLeave($event)", "focusin": "handleFocusIn()", "focusout": "handleFocusOut($event)", "keydown.escape": "close()" }, properties: { "attr.aria-describedby": "contentId()", "attr.data-state": "isOpen() ? \"open\" : \"closed\"" } }, exportAs: ["uiTooltipTrigger"], ngImport: i0 });
|
|
271
|
+
}
|
|
272
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipTriggerDirective, decorators: [{
|
|
273
|
+
type: Directive,
|
|
274
|
+
args: [{
|
|
275
|
+
selector: '[uiTooltipTrigger]',
|
|
276
|
+
exportAs: 'uiTooltipTrigger',
|
|
277
|
+
host: {
|
|
278
|
+
'[attr.aria-describedby]': 'contentId()',
|
|
279
|
+
'[attr.data-state]': 'isOpen() ? "open" : "closed"',
|
|
280
|
+
'(pointerenter)': 'handlePointerEnter()',
|
|
281
|
+
'(pointerleave)': 'handlePointerLeave($event)',
|
|
282
|
+
'(focusin)': 'handleFocusIn()',
|
|
283
|
+
'(focusout)': 'handleFocusOut($event)',
|
|
284
|
+
'(keydown.escape)': 'close()',
|
|
285
|
+
},
|
|
286
|
+
}]
|
|
287
|
+
}], ctorParameters: () => [], propDecorators: { uiTooltipTrigger: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiTooltipTrigger", required: true }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], openDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "openDelay", required: false }] }], closeDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeDelay", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }] } });
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Shadcn-styled tooltip directive. Thin wrapper around `matTooltip` that
|
|
291
|
+
* forces the shadcn panel class and sensible defaults.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* <button ui-button [uiTooltip]="'Save changes'" uiTooltipPosition="above">Save</button>
|
|
295
|
+
*/
|
|
296
|
+
class TooltipDirective {
|
|
297
|
+
tooltip = inject(MatTooltip, { host: true });
|
|
298
|
+
uiTooltip = input('', ...(ngDevMode ? [{ debugName: "uiTooltip" }] : /* istanbul ignore next */ []));
|
|
299
|
+
constructor() {
|
|
300
|
+
this.tooltip.tooltipClass = 'ui-tooltip-panel';
|
|
301
|
+
effect(() => {
|
|
302
|
+
this.tooltip.message = this.uiTooltip();
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
show() {
|
|
306
|
+
this.tooltip.show();
|
|
307
|
+
}
|
|
308
|
+
hide() {
|
|
309
|
+
this.tooltip.hide();
|
|
310
|
+
}
|
|
311
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
312
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: TooltipDirective, isStandalone: true, selector: "[uiTooltip]", inputs: { uiTooltip: { classPropertyName: "uiTooltip", publicName: "uiTooltip", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["uiTooltip"], hostDirectives: [{ directive: i1.MatTooltip, inputs: ["matTooltipPosition", "uiTooltipPosition", "matTooltipDisabled", "uiTooltipDisabled", "matTooltipShowDelay", "uiTooltipShowDelay", "matTooltipHideDelay", "uiTooltipHideDelay", "matTooltipTouchGestures", "uiTooltipTouchGestures"] }], ngImport: i0 });
|
|
313
|
+
}
|
|
314
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: TooltipDirective, decorators: [{
|
|
315
|
+
type: Directive,
|
|
316
|
+
args: [{
|
|
317
|
+
selector: '[uiTooltip]',
|
|
318
|
+
hostDirectives: [
|
|
319
|
+
{
|
|
320
|
+
directive: MatTooltip,
|
|
321
|
+
inputs: [
|
|
322
|
+
'matTooltipPosition: uiTooltipPosition',
|
|
323
|
+
'matTooltipDisabled: uiTooltipDisabled',
|
|
324
|
+
'matTooltipShowDelay: uiTooltipShowDelay',
|
|
325
|
+
'matTooltipHideDelay: uiTooltipHideDelay',
|
|
326
|
+
'matTooltipTouchGestures: uiTooltipTouchGestures',
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
],
|
|
330
|
+
exportAs: 'uiTooltip',
|
|
331
|
+
}]
|
|
332
|
+
}], ctorParameters: () => [], propDecorators: { uiTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiTooltip", required: false }] }] } });
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Generated bundle index. Do not edit.
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
export { TOOLTIP_DEFAULTS, TooltipComponent, TooltipContentDirective, TooltipDirective, TooltipTriggerDirective };
|
|
339
|
+
//# sourceMappingURL=edsis-ui-tooltip.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edsis-ui-tooltip.mjs","sources":["../../../library/ui/tooltip/tooltip.component.ts","../../../library/ui/tooltip/tooltip-content.directive.ts","../../../library/ui/tooltip/tooltip-trigger.directive.ts","../../../library/ui/tooltip/tooltip.directive.ts","../../../library/ui/tooltip/edsis-ui-tooltip.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, InjectionToken, Signal, forwardRef, input } from '@angular/core';\n\nexport type TooltipSide = 'top' | 'right' | 'bottom' | 'left';\nexport type TooltipAlign = 'start' | 'center' | 'end';\n\nexport interface TooltipDefaults {\n readonly side: Signal<TooltipSide>;\n readonly align: Signal<TooltipAlign>;\n readonly sideOffset: Signal<number>;\n readonly openDelay: Signal<number>;\n readonly closeDelay: Signal<number>;\n}\n\nexport const TOOLTIP_DEFAULTS = new InjectionToken<TooltipDefaults>('TOOLTIP_DEFAULTS');\n\n@Component({\n selector: 'ui-tooltip',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [{ provide: TOOLTIP_DEFAULTS, useExisting: forwardRef(() => TooltipComponent) }],\n host: {\n class: 'contents',\n },\n template: '<ng-content />',\n})\nexport class TooltipComponent implements TooltipDefaults {\n readonly side = input<TooltipSide>('top');\n readonly align = input<TooltipAlign>('center');\n readonly sideOffset = input(4);\n readonly openDelay = input(150);\n readonly closeDelay = input(0);\n}\n","import { Directive, TemplateRef, inject } from '@angular/core';\n\n@Directive({\n selector: 'ng-template[uiTooltipContent]',\n exportAs: 'uiTooltipContent',\n})\nexport class TooltipContentDirective {\n readonly template = inject<TemplateRef<unknown>>(TemplateRef);\n}\n","import { Overlay, OverlayRef, ConnectedPosition } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport { DestroyRef, Directive, ElementRef, ViewContainerRef, inject, input, output, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { merge } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { TOOLTIP_DEFAULTS, type TooltipAlign, type TooltipSide } from './tooltip.component';\nimport type { TooltipContentDirective } from './tooltip-content.directive';\n\nconst TOOLTIP_PANEL_CLASSES = [\n 'ui-tooltip-panel',\n 'pointer-events-none',\n 'z-50',\n 'max-w-xs',\n 'overflow-hidden',\n 'rounded-md',\n 'border',\n 'border-border',\n 'bg-primary',\n 'px-3',\n 'py-1.5',\n 'text-xs',\n 'font-medium',\n 'leading-none',\n 'text-primary-foreground',\n 'shadow-md',\n 'select-none',\n] as const;\n\nconst POSITION_ANCHORS: Record<TooltipSide, (align: TooltipAlign) => ConnectedPosition> = {\n top: (align) => ({\n originX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',\n originY: 'top',\n overlayX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',\n overlayY: 'bottom',\n }),\n bottom: (align) => ({\n originX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',\n originY: 'bottom',\n overlayX: align === 'start' ? 'start' : align === 'end' ? 'end' : 'center',\n overlayY: 'top',\n }),\n left: (align) => ({\n originX: 'start',\n originY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',\n overlayX: 'end',\n overlayY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',\n }),\n right: (align) => ({\n originX: 'end',\n originY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',\n overlayX: 'start',\n overlayY: align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center',\n }),\n};\n\nfunction positionFor(side: TooltipSide, align: TooltipAlign, sideOffset: number): ConnectedPosition {\n const anchor = POSITION_ANCHORS[side](align);\n\n if (side === 'top') {\n return { ...anchor, offsetY: -sideOffset };\n }\n\n if (side === 'bottom') {\n return { ...anchor, offsetY: sideOffset };\n }\n\n if (side === 'left') {\n return { ...anchor, offsetX: -sideOffset };\n }\n\n return { ...anchor, offsetX: sideOffset };\n}\n\nlet nextTooltipId = 0;\n\n@Directive({\n selector: '[uiTooltipTrigger]',\n exportAs: 'uiTooltipTrigger',\n host: {\n '[attr.aria-describedby]': 'contentId()',\n '[attr.data-state]': 'isOpen() ? \"open\" : \"closed\"',\n '(pointerenter)': 'handlePointerEnter()',\n '(pointerleave)': 'handlePointerLeave($event)',\n '(focusin)': 'handleFocusIn()',\n '(focusout)': 'handleFocusOut($event)',\n '(keydown.escape)': 'close()',\n },\n})\nexport class TooltipTriggerDirective {\n private readonly overlay = inject(Overlay);\n private readonly vcr = inject(ViewContainerRef);\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly defaults = inject(TOOLTIP_DEFAULTS, { optional: true });\n\n readonly uiTooltipTrigger = input.required<TooltipContentDirective>();\n readonly side = input<TooltipSide | undefined>(undefined);\n readonly align = input<TooltipAlign | undefined>(undefined);\n readonly sideOffset = input<number | undefined>(undefined);\n readonly openDelay = input<number | undefined>(undefined);\n readonly closeDelay = input<number | undefined>(undefined);\n readonly disabled = input(false);\n\n readonly openedChange = output<boolean>();\n\n readonly isOpen = signal(false);\n protected readonly contentId = signal<string | null>(null);\n\n private overlayRef: OverlayRef | null = null;\n private openTimeoutId: number | null = null;\n private closeTimeoutId: number | null = null;\n private isPointerInsideTrigger = false;\n private isTriggerFocused = false;\n private isDestroying = false;\n\n constructor() {\n this.destroyRef.onDestroy(() => {\n this.isDestroying = true;\n this.clearOpenTimeout();\n this.clearCloseTimeout();\n this.contentId.set(null);\n this.isOpen.set(false);\n this.overlayRef?.dispose();\n this.overlayRef = null;\n });\n }\n\n handlePointerEnter(): void {\n if (this.disabled()) {\n return;\n }\n\n this.isPointerInsideTrigger = true;\n this.clearCloseTimeout();\n this.scheduleOpen();\n }\n\n handlePointerLeave(event: PointerEvent): void {\n if (this.el.nativeElement.contains(event.relatedTarget as Node | null)) {\n return;\n }\n\n this.isPointerInsideTrigger = false;\n this.scheduleClose();\n }\n\n handleFocusIn(): void {\n if (this.disabled()) {\n return;\n }\n\n this.isTriggerFocused = true;\n this.clearCloseTimeout();\n this.scheduleOpen();\n }\n\n handleFocusOut(event: FocusEvent): void {\n if (this.el.nativeElement.contains(event.relatedTarget as Node | null)) {\n return;\n }\n\n this.isTriggerFocused = false;\n this.scheduleClose();\n }\n\n open(): void {\n if (this.isOpen() || this.disabled()) {\n return;\n }\n\n const side = this.side() ?? this.defaults?.side() ?? 'top';\n const align = this.align() ?? this.defaults?.align() ?? 'center';\n const sideOffset = this.sideOffset() ?? this.defaults?.sideOffset() ?? 4;\n\n const primary = positionFor(side, align, sideOffset);\n const fallback = positionFor(this.oppositeSide(side), align, sideOffset);\n\n const positionStrategy = this.overlay\n .position()\n .flexibleConnectedTo(this.el)\n .withPositions([primary, fallback])\n .withPush(false)\n .withFlexibleDimensions(false);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: this.overlay.scrollStrategies.reposition(),\n hasBackdrop: false,\n panelClass: [...TOOLTIP_PANEL_CLASSES],\n });\n\n const tooltipId = `ui-tooltip-${nextTooltipId++}`;\n this.overlayRef.overlayElement.id = tooltipId;\n this.overlayRef.overlayElement.setAttribute('role', 'tooltip');\n\n const portal = new TemplatePortal(this.uiTooltipTrigger().template, this.vcr);\n this.overlayRef.attach(portal);\n this.bindOverlayLifecycle();\n\n this.contentId.set(tooltipId);\n this.isOpen.set(true);\n\n if (!this.isDestroying) {\n this.openedChange.emit(true);\n }\n }\n\n close(): void {\n this.clearOpenTimeout();\n this.clearCloseTimeout();\n\n if (!this.isOpen()) {\n return;\n }\n\n this.overlayRef?.dispose();\n this.overlayRef = null;\n this.contentId.set(null);\n this.isOpen.set(false);\n\n if (!this.isDestroying) {\n this.openedChange.emit(false);\n }\n }\n\n private bindOverlayLifecycle(): void {\n if (!this.overlayRef) {\n return;\n }\n\n merge(\n this.overlayRef\n .outsidePointerEvents()\n .pipe(filter((event) => !this.el.nativeElement.contains(event.target as Node))),\n this.overlayRef.keydownEvents().pipe(filter((event) => event.key === 'Escape')),\n this.overlayRef.detachments(),\n )\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.close());\n }\n\n private scheduleOpen(): void {\n this.clearCloseTimeout();\n\n if (this.isOpen()) {\n return;\n }\n\n this.clearOpenTimeout();\n this.openTimeoutId = window.setTimeout(\n () => {\n this.openTimeoutId = null;\n\n if (this.disabled() || (!this.isPointerInsideTrigger && !this.isTriggerFocused)) {\n return;\n }\n\n this.open();\n },\n this.openDelay() ?? this.defaults?.openDelay() ?? 150,\n );\n }\n\n private scheduleClose(): void {\n this.clearOpenTimeout();\n\n if (!this.isOpen()) {\n return;\n }\n\n this.clearCloseTimeout();\n this.closeTimeoutId = window.setTimeout(\n () => {\n this.closeTimeoutId = null;\n\n if (this.isPointerInsideTrigger || this.isTriggerFocused) {\n return;\n }\n\n this.close();\n },\n this.closeDelay() ?? this.defaults?.closeDelay() ?? 0,\n );\n }\n\n private clearOpenTimeout(): void {\n if (this.openTimeoutId !== null) {\n window.clearTimeout(this.openTimeoutId);\n this.openTimeoutId = null;\n }\n }\n\n private clearCloseTimeout(): void {\n if (this.closeTimeoutId !== null) {\n window.clearTimeout(this.closeTimeoutId);\n this.closeTimeoutId = null;\n }\n }\n\n private oppositeSide(side: TooltipSide): TooltipSide {\n return side === 'top' ? 'bottom' : side === 'bottom' ? 'top' : side === 'left' ? 'right' : 'left';\n }\n}\n","import { Directive, effect, inject, input } from '@angular/core';\nimport { MatTooltip, TooltipPosition } from '@angular/material/tooltip';\n\n/**\n * Shadcn-styled tooltip directive. Thin wrapper around `matTooltip` that\n * forces the shadcn panel class and sensible defaults.\n *\n * @example\n * <button ui-button [uiTooltip]=\"'Save changes'\" uiTooltipPosition=\"above\">Save</button>\n */\n@Directive({\n selector: '[uiTooltip]',\n hostDirectives: [\n {\n directive: MatTooltip,\n inputs: [\n 'matTooltipPosition: uiTooltipPosition',\n 'matTooltipDisabled: uiTooltipDisabled',\n 'matTooltipShowDelay: uiTooltipShowDelay',\n 'matTooltipHideDelay: uiTooltipHideDelay',\n 'matTooltipTouchGestures: uiTooltipTouchGestures',\n ],\n },\n ],\n exportAs: 'uiTooltip',\n})\nexport class TooltipDirective {\n private readonly tooltip = inject(MatTooltip, { host: true });\n\n readonly uiTooltip = input<string>('');\n\n constructor() {\n this.tooltip.tooltipClass = 'ui-tooltip-panel';\n effect(() => {\n this.tooltip.message = this.uiTooltip();\n });\n }\n\n show(): void {\n this.tooltip.show();\n }\n\n hide(): void {\n this.tooltip.hide();\n }\n}\n\nexport type { TooltipPosition };\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
function cn(...inputs) {
|
|
5
|
+
return twMerge(clsx(inputs));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generated bundle index. Do not edit.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { cn };
|
|
13
|
+
//# sourceMappingURL=edsis-ui-utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edsis-ui-utils.mjs","sources":["../../../library/ui/utils/cn.util.ts","../../../library/ui/utils/edsis-ui-utils.ts"],"sourcesContent":["import { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;AAGM,SAAU,EAAE,CAAC,GAAG,MAAoB,EAAA;AACxC,IAAA,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9B;;ACLA;;AAEG;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edsis-ui.mjs","sources":["../../../library/ui/public-api.ts","../../../library/ui/edsis-ui.ts"],"sourcesContent":["/*\n * Public API Surface of @edsis/ui\n *\n * Komponen dan utilitas diekspos lewat secondary entry point pada setiap folder\n * di dalam library/ui.\n */\n\nexport {};\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;AAKG;;ACLH;;AAEG"}
|
package/form/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Form primitives
|
|
2
|
+
|
|
3
|
+
The shadcn `Field` family maps to this entrypoint. Use it to compose labels,
|
|
4
|
+
descriptions, grouped sections, separators, validation messages, and responsive
|
|
5
|
+
field rows around the existing `input`, `textarea`, `select`, `checkbox`,
|
|
6
|
+
`radio`, `switch`, and `button` primitives.
|
|
7
|
+
|
|
8
|
+
## Import
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import {
|
|
12
|
+
FormContentComponent,
|
|
13
|
+
FormControlDirective,
|
|
14
|
+
FormDescriptionComponent,
|
|
15
|
+
FormFieldComponent,
|
|
16
|
+
FormFieldsetComponent,
|
|
17
|
+
FormGroupComponent,
|
|
18
|
+
FormLabelComponent,
|
|
19
|
+
FormLegendComponent,
|
|
20
|
+
FormMessageComponent,
|
|
21
|
+
FormSeparatorComponent,
|
|
22
|
+
FormTitleComponent,
|
|
23
|
+
} from '@edsis/ui/form';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Composition
|
|
27
|
+
|
|
28
|
+
Use the primitives in these roles:
|
|
29
|
+
|
|
30
|
+
| Upstream concept | Local Angular surface |
|
|
31
|
+
| ------------------ | ------------------------------------------------------------------------------------------------------ |
|
|
32
|
+
| `Field` | `ui-form-field` |
|
|
33
|
+
| `FieldSet` | `fieldset[ui-form-fieldset]` |
|
|
34
|
+
| `FieldLegend` | `legend[ui-form-legend]` |
|
|
35
|
+
| `FieldGroup` | `ui-form-group` |
|
|
36
|
+
| `FieldContent` | `ui-form-content` |
|
|
37
|
+
| `FieldLabel` | `label[ui-form-label]` for native controls, `label[ui-label]` wrappers for checkbox/radio/switch cards |
|
|
38
|
+
| `FieldTitle` | `ui-form-title` |
|
|
39
|
+
| `FieldDescription` | `p[ui-form-description]` |
|
|
40
|
+
| `FieldSeparator` | `ui-form-separator` |
|
|
41
|
+
| `FieldError` | `p[ui-form-message]` |
|
|
42
|
+
|
|
43
|
+
## Basic Usage
|
|
44
|
+
|
|
45
|
+
For native inputs and textareas, pair `label[ui-form-label]` with
|
|
46
|
+
`[uiFormControl]` so ids and helper text stay synchronized.
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<ui-form-field>
|
|
50
|
+
<label ui-form-label>Email</label>
|
|
51
|
+
<input ui-input uiFormControl type="email" placeholder="you@example.com" />
|
|
52
|
+
<p ui-form-description>We'll only use this address for account updates.</p>
|
|
53
|
+
<p ui-form-message>Enter a valid email address.</p>
|
|
54
|
+
</ui-form-field>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Common Patterns
|
|
58
|
+
|
|
59
|
+
### Grouped sections
|
|
60
|
+
|
|
61
|
+
Use semantic fieldsets and legends when several controls belong to the same
|
|
62
|
+
question or form section.
|
|
63
|
+
|
|
64
|
+
```html
|
|
65
|
+
<fieldset ui-form-fieldset>
|
|
66
|
+
<legend ui-form-legend>Address information</legend>
|
|
67
|
+
<p ui-form-description>We need your address to deliver your order.</p>
|
|
68
|
+
|
|
69
|
+
<ui-form-group>
|
|
70
|
+
<ui-form-field>
|
|
71
|
+
<label ui-form-label>Street address</label>
|
|
72
|
+
<input ui-input uiFormControl placeholder="123 Main St" />
|
|
73
|
+
</ui-form-field>
|
|
74
|
+
|
|
75
|
+
<div class="grid gap-4 sm:grid-cols-2">
|
|
76
|
+
<ui-form-field>
|
|
77
|
+
<label ui-form-label>City</label>
|
|
78
|
+
<input ui-input uiFormControl placeholder="New York" />
|
|
79
|
+
</ui-form-field>
|
|
80
|
+
|
|
81
|
+
<ui-form-field>
|
|
82
|
+
<label ui-form-label>Postal code</label>
|
|
83
|
+
<input ui-input uiFormControl placeholder="10001" />
|
|
84
|
+
</ui-form-field>
|
|
85
|
+
</div>
|
|
86
|
+
</ui-form-group>
|
|
87
|
+
</fieldset>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Horizontal checkbox, radio, and switch rows
|
|
91
|
+
|
|
92
|
+
For grouped controls, wrap the row in `label[ui-label]` so the entire card can
|
|
93
|
+
toggle the control, then use `ui-form-content` for the title and helper copy.
|
|
94
|
+
|
|
95
|
+
```html
|
|
96
|
+
<label ui-label class="block rounded-xl border border-border p-4">
|
|
97
|
+
<ui-form-field orientation="horizontal" class="gap-4">
|
|
98
|
+
<ui-checkbox [(ngModel)]="syncDesktop" aria-label="Sync Desktop and Documents folders" />
|
|
99
|
+
<ui-form-content>
|
|
100
|
+
<ui-form-title>Sync Desktop & Documents folders</ui-form-title>
|
|
101
|
+
<p ui-form-description>Your Desktop & Documents folders are being synced with iCloud Drive.</p>
|
|
102
|
+
</ui-form-content>
|
|
103
|
+
</ui-form-field>
|
|
104
|
+
</label>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Select rows
|
|
108
|
+
|
|
109
|
+
Select keeps its own trigger and listbox behavior. Use `ui-form-title` and
|
|
110
|
+
`p[ui-form-description]` around it instead of relying on a generated `for`
|
|
111
|
+
relationship.
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<ui-form-field>
|
|
115
|
+
<ui-form-title>Department</ui-form-title>
|
|
116
|
+
<ui-select aria-label="Department" class="block w-full" placeholder="Choose department">
|
|
117
|
+
<ui-option value="engineering">Engineering</ui-option>
|
|
118
|
+
<ui-option value="design">Design</ui-option>
|
|
119
|
+
<ui-option value="marketing">Marketing</ui-option>
|
|
120
|
+
</ui-select>
|
|
121
|
+
<p ui-form-description>Select your department or area of work.</p>
|
|
122
|
+
</ui-form-field>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Responsive layout
|
|
126
|
+
|
|
127
|
+
Set `orientation="responsive"` on `ui-form-field` when the label and content
|
|
128
|
+
should stack on narrow widths and move into columns on wider screens.
|
|
129
|
+
|
|
130
|
+
```html
|
|
131
|
+
<ui-form-field orientation="responsive">
|
|
132
|
+
<ui-form-content>
|
|
133
|
+
<label ui-form-label>Display name</label>
|
|
134
|
+
<p ui-form-description>Provide the public name shown in comments and invoices.</p>
|
|
135
|
+
</ui-form-content>
|
|
136
|
+
<input ui-input uiFormControl placeholder="Evil Rabbit" />
|
|
137
|
+
</ui-form-field>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Validation and errors
|
|
141
|
+
|
|
142
|
+
`[uiFormControl]` will reflect Angular form state automatically. For external
|
|
143
|
+
validation flows or static examples, use the `invalid` input on
|
|
144
|
+
`ui-form-field`.
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<ui-form-field invalid>
|
|
148
|
+
<label ui-form-label>Email</label>
|
|
149
|
+
<input ui-input uiFormControl type="email" aria-invalid="true" placeholder="name@example.com" />
|
|
150
|
+
<p ui-form-message>Enter a valid email address.</p>
|
|
151
|
+
</ui-form-field>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## API Reference
|
|
155
|
+
|
|
156
|
+
| Primitive | Selector | Inputs | Notes |
|
|
157
|
+
| -------------------------- | --------------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------- |
|
|
158
|
+
| `FormFieldComponent` | `ui-form-field` | `class`, `orientation`, `invalid` | Core field wrapper. `orientation` supports `vertical`, `horizontal`, and `responsive`. |
|
|
159
|
+
| `FormFieldsetComponent` | `fieldset[ui-form-fieldset]` | `class` | Semantic fieldset reset with spacing presets. |
|
|
160
|
+
| `FormLegendComponent` | `legend[ui-form-legend]` | `class`, `variant` | Uses either standard legend sizing or label-sized copy. |
|
|
161
|
+
| `FormGroupComponent` | `ui-form-group` | `class` | Stacks related fields and separators. |
|
|
162
|
+
| `FormContentComponent` | `ui-form-content` | `class` | Secondary text column for horizontal fields and card layouts. |
|
|
163
|
+
| `FormLabelComponent` | `ui-form-label, label[ui-form-label]` | `class` | Visible label tied to the generated control id inside a field. |
|
|
164
|
+
| `FormTitleComponent` | `ui-form-title` | `class` | Non-label heading for grouped controls. |
|
|
165
|
+
| `FormDescriptionComponent` | `ui-form-description, p[ui-form-description]` | `class` | Helper text inside a field or at the fieldset level. |
|
|
166
|
+
| `FormSeparatorComponent` | `ui-form-separator` | `class` | Divider between stacked sections. |
|
|
167
|
+
| `FormMessageComponent` | `ui-form-message, p[ui-form-message]` | `class` | Error text shown when the field is invalid. |
|
|
168
|
+
| `FormControlDirective` | `[uiFormControl]` | none | Auto-wires `id`, `aria-describedby`, and invalid state for native controls. |
|
|
169
|
+
|
|
170
|
+
## Styling and Theming
|
|
171
|
+
|
|
172
|
+
- Field primitives use the same design tokens as the rest of the library:
|
|
173
|
+
`border-border`, `text-foreground`, `text-muted-foreground`, `ring-ring`,
|
|
174
|
+
and `text-destructive`.
|
|
175
|
+
- Pass `class` to widen or tighten the layout around a specific field.
|
|
176
|
+
- `ui-form-separator` uses the border token rather than current text color so
|
|
177
|
+
dividers remain consistent across themes.
|
|
178
|
+
|
|
179
|
+
## Accessibility
|
|
180
|
+
|
|
181
|
+
- Prefer real `fieldset` and `legend` elements for grouped questions.
|
|
182
|
+
- Keep native controls on `[uiFormControl]` when they need synchronized labels,
|
|
183
|
+
descriptions, and message ids.
|
|
184
|
+
- Use `label[ui-label]` wrappers when the entire checkbox, radio, or switch row
|
|
185
|
+
should toggle the control.
|
|
186
|
+
- `p[ui-form-message]` emits `role="alert"` and `aria-live="polite"`.
|
|
187
|
+
|
|
188
|
+
## Keyboard Interactions
|
|
189
|
+
|
|
190
|
+
- Input and textarea fields preserve browser-native editing behavior.
|
|
191
|
+
- Select, checkbox, radio, and switch rows keep the interaction model of their
|
|
192
|
+
own entrypoints.
|
|
193
|
+
- Field wrappers add structure and semantics but do not create extra tab stops.
|
|
194
|
+
|
|
195
|
+
## Angular Notes
|
|
196
|
+
|
|
197
|
+
- `ui-form-label` is best for native controls that participate in
|
|
198
|
+
`[uiFormControl]`.
|
|
199
|
+
- Use `ui-form-title` when the primary text is descriptive rather than a direct
|
|
200
|
+
form label.
|
|
201
|
+
- The local `responsive` orientation uses breakpoint-based layout instead of the
|
|
202
|
+
upstream container-query API.
|
|
203
|
+
|
|
204
|
+
## Source Parity
|
|
205
|
+
|
|
206
|
+
This package is the durable Angular-first mapping for the shadcn `Field`
|
|
207
|
+
documentation. It mirrors the same information architecture while staying
|
|
208
|
+
honest about local differences: there is no dedicated `field` entrypoint, and
|
|
209
|
+
grouped controls continue to use the runtime behavior of the existing input,
|
|
210
|
+
textarea, select, checkbox, radio, switch, and button packages.
|