tailjng 0.1.6 → 0.1.7
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 +12 -4
- package/cli/execute/init-app.js +5 -2
- package/cli/execute/sync-app.js +14 -2
- package/cli/settings/colors-config-utils.js +43 -8
- package/cli/settings/icons-config-utils.js +62 -0
- package/cli/settings/path-utils.js +32 -2
- package/cli/settings/project-utils.js +7 -1
- package/cli/templates/app.generator.js +2 -2
- package/fesm2022/tailjng.mjs +247 -80
- package/fesm2022/tailjng.mjs.map +1 -1
- package/lib/services/static/theme.service.d.ts +39 -1
- package/lib/utils/theme/theme-variables.util.d.ts +31 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -1
- package/registry/components.json +41 -18
- package/src/colors.safelist.css +2 -2
- package/src/lib/components/.config/README.md +11 -0
- package/src/lib/components/.config/colors/README.md +38 -0
- package/src/lib/components/{colors-config → .config/colors}/colors.config.ts +5 -5
- package/src/lib/components/{colors-config → .config/colors}/colors.safelist.css +2 -2
- package/src/lib/components/.config/icons/README.md +26 -0
- package/src/lib/components/.config/icons/icons.lucide.ts +134 -0
- package/src/lib/components/.config/input/README.md +24 -0
- package/src/lib/components/.config/input/input.classes.ts +119 -0
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.css +244 -2
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.html +25 -38
- package/src/lib/components/alert/alert-dialog/dialog-alert.component.ts +66 -56
- package/src/lib/components/alert/alert-dialog/dialog-alert.types.ts +19 -0
- package/src/lib/components/alert/alert-toast/toast-alert.component.css +630 -12
- package/src/lib/components/alert/alert-toast/toast-alert.component.html +103 -102
- package/src/lib/components/alert/alert-toast/toast-alert.component.ts +485 -128
- package/src/lib/components/alert/alert-toast/toast-alert.types.ts +25 -0
- package/src/lib/components/badge/badge.component.html +34 -21
- package/src/lib/components/badge/badge.component.ts +140 -31
- package/src/lib/components/button/button.component.html +16 -10
- package/src/lib/components/button/button.component.ts +162 -22
- package/src/lib/components/card/card-complete/complete-card.component.html +2 -2
- package/src/lib/components/card/card-complete/complete-card.component.ts +26 -16
- package/src/lib/components/card/card-crud-complete/complete-crud-card.component.html +2 -2
- package/src/lib/components/card/card-crud-complete/complete-crud-card.component.ts +26 -16
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.css +97 -0
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.html +54 -46
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.component.ts +135 -64
- package/src/lib/components/checkbox/checkbox-input/input-checkbox.types.ts +3 -0
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.css +112 -0
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.html +28 -25
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.component.ts +67 -15
- package/src/lib/components/checkbox/checkbox-switch/switch-checkbox.types.ts +1 -0
- package/src/lib/components/coach-mark/coach-mark.component.html +4 -22
- package/src/lib/components/coach-mark/coach-mark.component.scss +1 -1
- package/src/lib/components/coach-mark/coach-mark.component.ts +51 -18
- package/src/lib/components/coach-mark/coach-mark.directive.ts +133 -78
- package/src/lib/components/coach-mark/coach-mark.types.ts +12 -0
- package/src/lib/components/dialog/dialog.component.css +103 -1
- package/src/lib/components/dialog/dialog.component.html +46 -66
- package/src/lib/components/dialog/dialog.component.ts +136 -110
- package/src/lib/components/dialog/dialog.types.ts +19 -0
- package/src/lib/components/filter/filter-complete/complete-filter.component.html +16 -19
- package/src/lib/components/filter/filter-complete/complete-filter.component.scss +35 -0
- package/src/lib/components/filter/filter-complete/complete-filter.component.ts +58 -34
- package/src/lib/components/filter/filter-complete/complete-filter.types.ts +7 -0
- package/src/lib/components/filter/filter-complete/complete-filter.util.ts +16 -0
- package/src/lib/components/form/form-container/container-form.component.css +4 -0
- package/src/lib/components/form/form-container/container-form.component.html +2 -2
- package/src/lib/components/form/form-container/container-form.component.ts +72 -16
- package/src/lib/components/form/form-container/container-form.types.ts +42 -0
- package/src/lib/components/form/form-container/form-col-span.directive.ts +25 -0
- package/src/lib/components/form/form-sidebar/sidebar-form.component.css +276 -0
- package/src/lib/components/form/form-sidebar/sidebar-form.component.html +117 -125
- package/src/lib/components/form/form-sidebar/sidebar-form.component.ts +109 -34
- package/src/lib/components/form/form-sidebar/sidebar-form.types.ts +3 -0
- package/src/lib/components/{toggle-radio/toggle-radio.component.css → form/form-validation/validation-form.component.css} +0 -1
- package/src/lib/components/form/form-validation/validation-form.component.html +10 -6
- package/src/lib/components/form/form-validation/validation-form.component.ts +99 -12
- package/src/lib/components/form/form-validation/validation-form.types.ts +33 -0
- package/src/lib/components/icon/icon.component.html +8 -5
- package/src/lib/components/icon/icon.component.ts +111 -9
- package/src/lib/components/input/input/input.component.html +19 -16
- package/src/lib/components/input/input/input.component.ts +130 -53
- package/src/lib/components/input/input/input.types.ts +8 -0
- package/src/lib/components/input/input-file/file-input.component.html +65 -56
- package/src/lib/components/input/input-file/file-input.component.ts +276 -173
- package/src/lib/components/input/input-file/file-input.types.ts +2 -0
- package/src/lib/components/input/input-range/range-input.component.css +67 -0
- package/src/lib/components/input/input-range/range-input.component.html +50 -58
- package/src/lib/components/input/input-range/range-input.component.ts +148 -60
- package/src/lib/components/input/input-range/range-input.types.ts +7 -0
- package/src/lib/components/input/input-textarea/textarea-input.component.html +16 -7
- package/src/lib/components/input/input-textarea/textarea-input.component.ts +140 -50
- package/src/lib/components/input/input-textarea/textarea-input.types.ts +2 -0
- package/src/lib/components/label/label.component.html +17 -16
- package/src/lib/components/label/label.component.ts +70 -16
- package/src/lib/components/label/label.types.ts +2 -0
- package/src/lib/components/menu/menu-options-table/menu-options-defaults.ts +34 -0
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.html +34 -20
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.ts +211 -58
- package/src/lib/components/menu/menu-options-table/options-table-menu.types.ts +38 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.html +49 -52
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.ts +112 -24
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.types.ts +9 -0
- package/src/lib/components/mode-toggle/mode-toggle.component.html +11 -16
- package/src/lib/components/mode-toggle/mode-toggle.component.ts +69 -33
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.html +4 -4
- package/src/lib/components/paginator/paginator-complete/complete-paginator.component.ts +31 -7
- package/src/lib/components/paginator/paginator-complete/complete-paginator.types.ts +12 -0
- package/src/lib/components/paginator/paginator-complete/complete-paginator.util.ts +36 -0
- package/src/lib/components/progress-bar/progress-bar.component.css +11 -0
- package/src/lib/components/progress-bar/progress-bar.component.html +41 -40
- package/src/lib/components/progress-bar/progress-bar.component.ts +95 -11
- package/src/lib/components/progress-bar/progress-bar.types.ts +2 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.component.css +6 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.component.html +54 -44
- package/src/lib/components/select/select-dropdown/dropdown-select.component.ts +450 -509
- package/src/lib/components/select/select-dropdown/dropdown-select.types.ts +43 -0
- package/src/lib/components/select/select-dropdown/dropdown-select.util.ts +179 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.css +6 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.html +131 -42
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.ts +491 -475
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.types.ts +22 -0
- package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.util.ts +20 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.component.css +10 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.component.html +76 -60
- package/src/lib/components/select/select-multi-table/multi-table-select.component.ts +250 -313
- package/src/lib/components/select/select-multi-table/multi-table-select.types.ts +10 -0
- package/src/lib/components/select/select-multi-table/multi-table-select.util.ts +5 -0
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.css +212 -0
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.html +62 -53
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.ts +84 -27
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.types.ts +2 -0
- package/src/lib/components/table/table-complete/complete-table.component.html +15 -17
- package/src/lib/components/table/table-complete/complete-table.component.ts +190 -338
- package/src/lib/components/table/table-complete/complete-table.types.ts +28 -0
- package/src/lib/components/table/table-complete/complete-table.util.ts +236 -0
- package/src/lib/components/table/table-complete/index.ts +2 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.animations.ts +34 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.html +73 -128
- package/src/lib/components/table/table-crud-complete/complete-crud-table.component.ts +542 -829
- package/src/lib/components/table/table-crud-complete/complete-crud-table.types.ts +57 -0
- package/src/lib/components/table/table-crud-complete/complete-crud-table.util.ts +723 -0
- package/src/lib/components/table/table-crud-complete/index.ts +3 -0
- package/src/lib/components/theme-generator/theme-generator.component.css +21 -0
- package/src/lib/components/theme-generator/theme-generator.component.html +146 -116
- package/src/lib/components/theme-generator/theme-generator.component.ts +44 -24
- package/src/lib/components/toggle-radio/shared/toggle-options.types.ts +8 -0
- package/src/lib/components/toggle-radio/shared/toggle-options.util.ts +44 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.css +135 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.html +52 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.component.ts +198 -0
- package/src/lib/components/toggle-radio/toggle-radio/toggle-radio.types.ts +1 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.css +108 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.html +37 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.component.ts +193 -0
- package/src/lib/components/toggle-radio/toggle-segment/segment-toggle.types.ts +1 -0
- package/src/lib/components/tooltip/tooltip.directive.ts +12 -9
- package/src/lib/components/tooltip/tooltip.service.ts +331 -133
- package/src/lib/components/tooltip/tooltip.types.ts +9 -0
- package/src/lib/components/viewer/viewer-image/image-viewer.component.css +90 -4
- package/src/lib/components/viewer/viewer-image/image-viewer.component.html +52 -103
- package/src/lib/components/viewer/viewer-image/image-viewer.component.ts +182 -177
- package/src/lib/components/viewer/viewer-image/image-viewer.types.ts +3 -0
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.css +177 -0
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.html +74 -24
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.ts +168 -15
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.types.ts +1 -0
- package/src/styles.css +2 -2
- package/lib/services/static/icons.service.d.ts +0 -65
- package/src/lib/components/colors-config/README.md +0 -38
- package/src/lib/components/form/form-sidebar/sidebar-form.component.scss +0 -0
- package/src/lib/components/form/form-validation/validation-form.component.scss +0 -0
- package/src/lib/components/menu/menu-options-table/options-table-menu.component.scss +0 -0
- package/src/lib/components/menu/options-coach-menu/options-coach-menu.component.scss +0 -12
- package/src/lib/components/sidebar/sidebar-static/static-sidebar.component.scss +0 -0
- package/src/lib/components/toggle-radio/toggle-radio.component.html +0 -51
- package/src/lib/components/toggle-radio/toggle-radio.component.ts +0 -222
- package/src/lib/components/viewer/viewer-pdf/pdf-viewer.component.scss +0 -0
- package/tailjng-0.1.6.tgz +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Static options list or API-backed searchable select. */
|
|
2
|
+
export type DropdownSelectType = 'dropdown' | 'searchable';
|
|
3
|
+
|
|
4
|
+
/** Sort order for searchable API requests. */
|
|
5
|
+
export type DropdownSortOrder = 'ASC' | 'DESC';
|
|
6
|
+
|
|
7
|
+
/** Normalized option shown in the panel list. */
|
|
8
|
+
export type DropdownOption<TOriginal = unknown> = {
|
|
9
|
+
value: unknown;
|
|
10
|
+
text: string;
|
|
11
|
+
original?: TOriginal;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Placeholder map for `{param}` segments in {@link JDropdownSelectComponent.endpoint}. */
|
|
15
|
+
export type DropdownSelectDynamicParams = Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
/** Default filters sent as `filter[key]` query params (searchable mode). */
|
|
18
|
+
export type DropdownSelectDefaultFilters = { [key: string]: any };
|
|
19
|
+
|
|
20
|
+
export type DropdownPanelPosition = {
|
|
21
|
+
/** Viewport `top` in pixels after positioning. */
|
|
22
|
+
top: number;
|
|
23
|
+
/** Viewport `left` in pixels after positioning. */
|
|
24
|
+
left: number;
|
|
25
|
+
/** Final panel width in pixels. */
|
|
26
|
+
width: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Tunables for {@link positionDropdownPanel}. */
|
|
30
|
+
export type DropdownPanelPositionConfig = {
|
|
31
|
+
/** Minimum distance from viewport edges. */
|
|
32
|
+
viewportPadding: number;
|
|
33
|
+
/** Gap between trigger and panel. */
|
|
34
|
+
dropdownGap: number;
|
|
35
|
+
/** Stacking order (`position: fixed`). */
|
|
36
|
+
dropdownZIndex: number;
|
|
37
|
+
/** Minimum panel width when trigger is narrower. */
|
|
38
|
+
minPanelWidth: number;
|
|
39
|
+
/** Minimum scrollable list height when constrained. */
|
|
40
|
+
minOptionsHeight: number;
|
|
41
|
+
/** CSS selector for the scrollable options container. */
|
|
42
|
+
optionsListSelector: string;
|
|
43
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DropdownOption,
|
|
3
|
+
DropdownPanelPosition,
|
|
4
|
+
DropdownPanelPositionConfig,
|
|
5
|
+
} from './dropdown-select.types';
|
|
6
|
+
|
|
7
|
+
/** Default viewport positioning values for {@link JDropdownSelectComponent}. */
|
|
8
|
+
export const DROPDOWN_PANEL_DEFAULTS: DropdownPanelPositionConfig = {
|
|
9
|
+
viewportPadding: 8,
|
|
10
|
+
dropdownGap: 4,
|
|
11
|
+
dropdownZIndex: 1100,
|
|
12
|
+
minPanelWidth: 250,
|
|
13
|
+
minOptionsHeight: 80,
|
|
14
|
+
optionsListSelector: '.jdropdown-options-list',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Reads a nested property using dot notation (`a.b.c`). */
|
|
18
|
+
export function getNestedValue(obj: unknown, path: string): unknown {
|
|
19
|
+
let value: unknown = obj;
|
|
20
|
+
|
|
21
|
+
for (const part of path.split('.')) {
|
|
22
|
+
if (value == null || typeof value !== 'object') {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
value = (value as Record<string, unknown>)[part];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return value ?? '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Builds the display label for one option object. */
|
|
33
|
+
export function resolveOptionLabel(
|
|
34
|
+
option: Record<string, unknown>,
|
|
35
|
+
optionLabel: string | string[],
|
|
36
|
+
labelSeparator: string,
|
|
37
|
+
): string {
|
|
38
|
+
if (Array.isArray(optionLabel)) {
|
|
39
|
+
return optionLabel
|
|
40
|
+
.map((key) => String(getNestedValue(option, key)))
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join(labelSeparator);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return String(getNestedValue(option, optionLabel));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Maps primitive arrays (`['a', 'b']`) to panel options. */
|
|
49
|
+
export function mapPrimitiveOptions(options: unknown[]): DropdownOption[] {
|
|
50
|
+
return options.map((option) => ({
|
|
51
|
+
value: option,
|
|
52
|
+
text: String(option),
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Maps object arrays to panel options using `optionLabel` / `optionValue`. */
|
|
57
|
+
export function mapObjectOptions(
|
|
58
|
+
options: Record<string, unknown>[],
|
|
59
|
+
optionLabel: string | string[],
|
|
60
|
+
optionValue: string,
|
|
61
|
+
labelSeparator: string,
|
|
62
|
+
): DropdownOption[] {
|
|
63
|
+
return options.map((option) => ({
|
|
64
|
+
value: option[optionValue],
|
|
65
|
+
text: resolveOptionLabel(option, optionLabel, labelSeparator),
|
|
66
|
+
original: option,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Local text filter for static dropdown mode. */
|
|
71
|
+
export function filterOptionsBySearch(
|
|
72
|
+
options: DropdownOption[],
|
|
73
|
+
searchTerm: string,
|
|
74
|
+
): DropdownOption[] {
|
|
75
|
+
if (!searchTerm.trim()) {
|
|
76
|
+
return [...options];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const normalized = searchTerm.toLowerCase();
|
|
80
|
+
return options.filter((option) => option.text.toLowerCase().includes(normalized));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Replaces `{param}` placeholders in a CRUD endpoint template. */
|
|
84
|
+
export function rebuildEndpointUrl(
|
|
85
|
+
rawEndpoint: string,
|
|
86
|
+
dynamicParams: Record<string, unknown>,
|
|
87
|
+
): string {
|
|
88
|
+
return rawEndpoint.replace(/\{([^}]+)\}/g, (_, key: string) =>
|
|
89
|
+
String(dynamicParams?.[key] ?? ''),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Clears dynamic max-height applied while positioning the panel. */
|
|
94
|
+
export function resetDropdownPanelStyles(
|
|
95
|
+
panel: HTMLElement,
|
|
96
|
+
optionsListSelector = DROPDOWN_PANEL_DEFAULTS.optionsListSelector,
|
|
97
|
+
): void {
|
|
98
|
+
const optionsList = panel.querySelector(optionsListSelector) as HTMLElement | null;
|
|
99
|
+
if (optionsList) {
|
|
100
|
+
optionsList.style.maxHeight = '';
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Positions the floating panel with `position: fixed`, flipping above/below
|
|
106
|
+
* the trigger and clamping within the viewport.
|
|
107
|
+
*/
|
|
108
|
+
export function positionDropdownPanel(
|
|
109
|
+
panel: HTMLElement,
|
|
110
|
+
buttonRect: DOMRect,
|
|
111
|
+
config: DropdownPanelPositionConfig = DROPDOWN_PANEL_DEFAULTS,
|
|
112
|
+
): DropdownPanelPosition {
|
|
113
|
+
resetDropdownPanelStyles(panel, config.optionsListSelector);
|
|
114
|
+
|
|
115
|
+
const width = Math.max(buttonRect.width, config.minPanelWidth);
|
|
116
|
+
|
|
117
|
+
panel.style.position = 'fixed';
|
|
118
|
+
panel.style.zIndex = String(config.dropdownZIndex);
|
|
119
|
+
panel.style.margin = '0';
|
|
120
|
+
panel.style.width = `${width}px`;
|
|
121
|
+
panel.style.minWidth = `${config.minPanelWidth}px`;
|
|
122
|
+
|
|
123
|
+
const viewportWidth = document.documentElement.clientWidth;
|
|
124
|
+
const viewportHeight = window.innerHeight;
|
|
125
|
+
const panelHeight = panel.offsetHeight;
|
|
126
|
+
const spaceBelow = viewportHeight - buttonRect.bottom - config.viewportPadding;
|
|
127
|
+
const spaceAbove = buttonRect.top - config.viewportPadding;
|
|
128
|
+
|
|
129
|
+
let top = buttonRect.bottom + config.dropdownGap;
|
|
130
|
+
|
|
131
|
+
if (panelHeight > spaceBelow && panelHeight <= spaceAbove) {
|
|
132
|
+
top = buttonRect.top - panelHeight - config.dropdownGap;
|
|
133
|
+
} else if (panelHeight > spaceBelow && panelHeight > spaceAbove) {
|
|
134
|
+
const optionsList = panel.querySelector(config.optionsListSelector) as HTMLElement | null;
|
|
135
|
+
const chromeHeight = optionsList ? panelHeight - optionsList.offsetHeight : panelHeight;
|
|
136
|
+
|
|
137
|
+
if (spaceBelow >= spaceAbove) {
|
|
138
|
+
top = buttonRect.bottom + config.dropdownGap;
|
|
139
|
+
if (optionsList) {
|
|
140
|
+
optionsList.style.maxHeight = `${Math.max(
|
|
141
|
+
config.minOptionsHeight,
|
|
142
|
+
spaceBelow - config.dropdownGap - chromeHeight,
|
|
143
|
+
)}px`;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
const constrainedOptionsHeight = Math.max(
|
|
147
|
+
config.minOptionsHeight,
|
|
148
|
+
spaceAbove - config.dropdownGap - chromeHeight,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
if (optionsList) {
|
|
152
|
+
optionsList.style.maxHeight = `${constrainedOptionsHeight}px`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const adjustedPanelHeight = chromeHeight + (optionsList?.offsetHeight ?? constrainedOptionsHeight);
|
|
156
|
+
top = buttonRect.top - adjustedPanelHeight - config.dropdownGap;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const finalPanelHeight = panel.offsetHeight;
|
|
161
|
+
top = Math.max(
|
|
162
|
+
config.viewportPadding,
|
|
163
|
+
Math.min(top, viewportHeight - finalPanelHeight - config.viewportPadding),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
let left = buttonRect.left;
|
|
167
|
+
const panelWidth = panel.offsetWidth;
|
|
168
|
+
|
|
169
|
+
if (left + panelWidth > viewportWidth - config.viewportPadding) {
|
|
170
|
+
left = viewportWidth - panelWidth - config.viewportPadding;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
left = Math.max(config.viewportPadding, left);
|
|
174
|
+
|
|
175
|
+
panel.style.top = `${top}px`;
|
|
176
|
+
panel.style.left = `${left}px`;
|
|
177
|
+
|
|
178
|
+
return { top, left, width: panelWidth };
|
|
179
|
+
}
|
package/src/lib/components/select/select-multi-dropdown/multi-dropdown-select.component.html
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
<!-- Trigger -->
|
|
1
2
|
<div class="relative w-full">
|
|
2
|
-
<div class="w-auto"
|
|
3
|
+
<div #selectButton class="w-auto">
|
|
3
4
|
<button
|
|
4
5
|
type="button"
|
|
5
6
|
[disabled]="isDisabled || isLoading"
|
|
@@ -7,91 +8,179 @@
|
|
|
7
8
|
class="flex w-full h-[40px] max-[400px]:h-[35px] text-[12px] items-center justify-between px-3 py-2 text-sm bg-background dark:bg-dark-background border border-border dark:border-dark-border rounded focus:outline-none focus:ring-2 focus:ring-primary select-none"
|
|
8
9
|
[ngClass]="{ 'opacity-50 cursor-not-allowed pointer-events-none': isDisabled || isLoading }"
|
|
9
10
|
>
|
|
10
|
-
<span
|
|
11
|
+
<span
|
|
12
|
+
class="truncate text-black dark:text-white"
|
|
13
|
+
[ngClass]="{
|
|
14
|
+
'opacity-70 text-muted-foreground dark:text-dark-muted-foreground':
|
|
15
|
+
selectedValues.length === 0,
|
|
16
|
+
}"
|
|
17
|
+
>
|
|
11
18
|
{{ displayLabel }}
|
|
12
19
|
</span>
|
|
13
20
|
|
|
14
21
|
<div class="flex items-center">
|
|
15
22
|
@if (showClear && selectedValues.length > 0) {
|
|
16
|
-
<button
|
|
17
|
-
|
|
18
|
-
|
|
23
|
+
<button
|
|
24
|
+
type="button"
|
|
25
|
+
(click)="clearSelection($event)"
|
|
26
|
+
class="pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
27
|
+
>
|
|
28
|
+
<JIcon
|
|
29
|
+
[icon]="Icons.X"
|
|
30
|
+
[size]="14"
|
|
31
|
+
iconClass="text-gray-400"
|
|
32
|
+
[ariaHidden]="true"
|
|
33
|
+
/>
|
|
19
34
|
</button>
|
|
20
35
|
}
|
|
21
36
|
@if (!isLoading) {
|
|
22
|
-
<
|
|
37
|
+
<JIcon
|
|
38
|
+
[icon]="Icons.ChevronDown"
|
|
39
|
+
[size]="16"
|
|
40
|
+
iconClass="transition duration-300 ease-in-out text-gray-400"
|
|
41
|
+
[ngClasses]="{ 'rotate-180': isDropdownOpen }"
|
|
42
|
+
[ariaHidden]="true"
|
|
43
|
+
/>
|
|
23
44
|
} @else {
|
|
24
|
-
<
|
|
45
|
+
<JIcon
|
|
46
|
+
[icon]="Icons.Loader2"
|
|
47
|
+
[size]="16"
|
|
48
|
+
iconClass="text-gray-400 animate-spin"
|
|
49
|
+
[ariaHidden]="true"
|
|
50
|
+
/>
|
|
25
51
|
}
|
|
26
52
|
</div>
|
|
27
53
|
</button>
|
|
28
54
|
</div>
|
|
29
55
|
</div>
|
|
30
56
|
|
|
57
|
+
<!-- Floating panel (position: fixed — see dropdown-select.util) -->
|
|
31
58
|
@if (isDropdownOpen) {
|
|
32
|
-
<div
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
59
|
+
<div
|
|
60
|
+
#dropdownPanel
|
|
61
|
+
@modalTransition
|
|
62
|
+
class="jdropdown-panel min-w-[250px] bg-background dark:bg-dark-background rounded-lg shadow-lg border border-border border-dark-border"
|
|
63
|
+
[style.width.px]="dropdownWidth"
|
|
64
|
+
>
|
|
37
65
|
<div class="pt-1 pl-3 pr-3 pb-3">
|
|
38
|
-
<div class="text-[10px] font-medium text-gray-500 dark:text-gray-500 mb-1">
|
|
66
|
+
<div class="text-[10px] font-medium text-gray-500 dark:text-gray-500 mb-1">
|
|
67
|
+
{{ title }}
|
|
68
|
+
</div>
|
|
39
69
|
|
|
40
|
-
<!-- Search (local
|
|
70
|
+
<!-- Search (local or remote depending on `type`) -->
|
|
41
71
|
@if (isSearch) {
|
|
42
72
|
<div class="mb-2 relative">
|
|
43
|
-
<input
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
73
|
+
<input
|
|
74
|
+
type="text"
|
|
75
|
+
[(ngModel)]="searchTerm"
|
|
76
|
+
(input)="onSearchInput()"
|
|
77
|
+
placeholder="Buscar..."
|
|
78
|
+
class="input bg-dark-foreground dark:bg-foreground text-black dark:text-white w-full px-3 py-2 text-sm max-[400px]:h-[35px] max-[400px]:text-[12px] border border-border dark:border-dark-border rounded focus:outline-none focus:ring-2 focus:ring-primary"
|
|
79
|
+
/>
|
|
48
80
|
<div class="absolute flex right-3 top-1/2 transform -translate-y-1/2">
|
|
49
81
|
@if (searchTerm) {
|
|
50
|
-
<button
|
|
51
|
-
|
|
52
|
-
|
|
82
|
+
<button
|
|
83
|
+
type="button"
|
|
84
|
+
(click)="clearSearchTerm()"
|
|
85
|
+
class="pr-1 mr-1 text-gray-400 hover:text-gray-600 focus:outline-none cursor-pointer"
|
|
86
|
+
>
|
|
87
|
+
<JIcon
|
|
88
|
+
[icon]="Icons.X"
|
|
89
|
+
[size]="16"
|
|
90
|
+
iconClass="text-gray-400"
|
|
91
|
+
[ariaHidden]="true"
|
|
92
|
+
/>
|
|
53
93
|
</button>
|
|
54
94
|
}
|
|
55
|
-
<
|
|
95
|
+
<JIcon
|
|
96
|
+
[icon]="Icons.Search"
|
|
97
|
+
[size]="16"
|
|
98
|
+
iconClass="text-gray-400"
|
|
99
|
+
[ariaHidden]="true"
|
|
100
|
+
/>
|
|
56
101
|
</div>
|
|
57
102
|
</div>
|
|
58
103
|
}
|
|
59
104
|
|
|
60
|
-
|
|
105
|
+
<!-- Option list -->
|
|
106
|
+
<div
|
|
107
|
+
class="jdropdown-options-list max-h-60 max-[400px]:max-h-36 overflow-auto flex flex-col gap-1 scroll-element"
|
|
108
|
+
>
|
|
61
109
|
@if (isLoading) {
|
|
62
|
-
<div
|
|
63
|
-
|
|
110
|
+
<div
|
|
111
|
+
class="flex gap-3 text-black/50 dark:text-white/50 items-center justify-center py-4"
|
|
112
|
+
>
|
|
113
|
+
<JIcon
|
|
114
|
+
[icon]="Icons.Loader2"
|
|
115
|
+
[size]="20"
|
|
116
|
+
iconClass="animate-spin"
|
|
117
|
+
[ariaHidden]="true"
|
|
118
|
+
/>
|
|
64
119
|
Cargando...
|
|
65
120
|
</div>
|
|
66
121
|
} @else {
|
|
67
|
-
|
|
68
|
-
<!-- Select All -->
|
|
69
122
|
@if (filteredProcessedOptions.length > 0 && enableSelectAll) {
|
|
70
|
-
<div
|
|
71
|
-
|
|
72
|
-
|
|
123
|
+
<div
|
|
124
|
+
onKeyPress
|
|
125
|
+
(click)="toggleSelectAll()"
|
|
126
|
+
class="flex gap-5 items-center border border-accent dark:border-dark-accent/50 px-4 py-2 cursor-pointer group rounded-md transition-all hover:bg-accent/50 hover:dark:bg-dark-accent/40"
|
|
127
|
+
[ngClass]="{ 'bg-accent! dark:bg-dark-accent/80!': isAllSelected() }"
|
|
128
|
+
>
|
|
73
129
|
<input type="checkbox" class="hidden" [checked]="isAllSelected()" />
|
|
74
130
|
@if (isAllSelected()) {
|
|
75
|
-
<
|
|
131
|
+
<JIcon
|
|
132
|
+
[icon]="Icons.Check"
|
|
133
|
+
[size]="15"
|
|
134
|
+
iconClass="transition text-black dark:text-white"
|
|
135
|
+
[ariaHidden]="true"
|
|
136
|
+
/>
|
|
76
137
|
} @else {
|
|
77
|
-
<
|
|
138
|
+
<JIcon
|
|
139
|
+
[icon]="Icons.SquareDashedMousePointer"
|
|
140
|
+
[size]="15"
|
|
141
|
+
iconClass="transition text-black dark:text-white opacity-40"
|
|
142
|
+
[ariaHidden]="true"
|
|
143
|
+
/>
|
|
78
144
|
}
|
|
79
|
-
<label
|
|
145
|
+
<label
|
|
146
|
+
class="text-black dark:text-white text-sm max-[400px]:h-[35px] max-[400px]:text-[12px] font-medium w-full"
|
|
147
|
+
>{{ labelSelectAll }}</label
|
|
148
|
+
>
|
|
80
149
|
</div>
|
|
81
150
|
}
|
|
82
151
|
|
|
83
|
-
<!-- Opciones (filtradas) -->
|
|
84
152
|
@for (option of filteredProcessedOptions; track option.value) {
|
|
85
|
-
<div
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
153
|
+
<div
|
|
154
|
+
onKeyPress
|
|
155
|
+
(click)="toggleOption(option)"
|
|
156
|
+
class="flex gap-5 items-center border border-accent dark:border-dark-accent/50 px-4 py-2 cursor-pointer group rounded-md transition-all hover:bg-accent/50 hover:dark:bg-dark-accent/40"
|
|
157
|
+
[ngClass]="{
|
|
158
|
+
'bg-accent! dark:bg-dark-accent/80!': selectedValues.includes(option.value),
|
|
159
|
+
}"
|
|
160
|
+
>
|
|
161
|
+
<input
|
|
162
|
+
type="checkbox"
|
|
163
|
+
class="hidden"
|
|
164
|
+
[checked]="selectedValues.includes(option.value)"
|
|
165
|
+
/>
|
|
89
166
|
@if (selectedValues.includes(option.value)) {
|
|
90
|
-
<
|
|
167
|
+
<JIcon
|
|
168
|
+
[icon]="Icons.Check"
|
|
169
|
+
[size]="15"
|
|
170
|
+
iconClass="transition text-black dark:text-white"
|
|
171
|
+
[ariaHidden]="true"
|
|
172
|
+
/>
|
|
91
173
|
} @else {
|
|
92
|
-
<
|
|
174
|
+
<JIcon
|
|
175
|
+
[icon]="Icons.SquareDashedMousePointer"
|
|
176
|
+
[size]="15"
|
|
177
|
+
iconClass="transition text-black dark:text-white opacity-40"
|
|
178
|
+
[ariaHidden]="true"
|
|
179
|
+
/>
|
|
93
180
|
}
|
|
94
|
-
<label class="text-black dark:text-white text-sm font-medium w-full">{{
|
|
181
|
+
<label class="text-black dark:text-white text-sm font-medium w-full">{{
|
|
182
|
+
option.text
|
|
183
|
+
}}</label>
|
|
95
184
|
</div>
|
|
96
185
|
}
|
|
97
186
|
@if (filteredProcessedOptions.length === 0) {
|