@joanroucoux/cairn-ui 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +99 -0
- package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs +57 -53
- package/fesm2022/joanroucoux-cairn-ui-action-bar.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-alert.mjs +155 -47
- package/fesm2022/joanroucoux-cairn-ui-alert.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-amount.mjs +220 -110
- package/fesm2022/joanroucoux-cairn-ui-amount.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-async.mjs +392 -216
- package/fesm2022/joanroucoux-cairn-ui-async.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-avatar.mjs +145 -68
- package/fesm2022/joanroucoux-cairn-ui-avatar.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-back-link.mjs +87 -47
- package/fesm2022/joanroucoux-cairn-ui-back-link.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-badge.mjs +83 -43
- package/fesm2022/joanroucoux-cairn-ui-badge.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-button.mjs +184 -104
- package/fesm2022/joanroucoux-cairn-ui-button.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-card.mjs +232 -137
- package/fesm2022/joanroucoux-cairn-ui-card.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs +298 -102
- package/fesm2022/joanroucoux-cairn-ui-choice-chips.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-control.mjs +4 -17
- package/fesm2022/joanroucoux-cairn-ui-control.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-delta.mjs +150 -83
- package/fesm2022/joanroucoux-cairn-ui-delta.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-dialog.mjs +508 -471
- package/fesm2022/joanroucoux-cairn-ui-dialog.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-donut.mjs +255 -157
- package/fesm2022/joanroucoux-cairn-ui-donut.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-drawer.mjs +303 -0
- package/fesm2022/joanroucoux-cairn-ui-drawer.mjs.map +1 -0
- package/fesm2022/joanroucoux-cairn-ui-empty.mjs +76 -35
- package/fesm2022/joanroucoux-cairn-ui-empty.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-external-link.mjs +40 -31
- package/fesm2022/joanroucoux-cairn-ui-external-link.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-fact.mjs +188 -79
- package/fesm2022/joanroucoux-cairn-ui-fact.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-field.mjs +309 -173
- package/fesm2022/joanroucoux-cairn-ui-field.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs +165 -87
- package/fesm2022/joanroucoux-cairn-ui-filter-chips.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-group-header.mjs +269 -0
- package/fesm2022/joanroucoux-cairn-ui-group-header.mjs.map +1 -0
- package/fesm2022/joanroucoux-cairn-ui-input.mjs +205 -85
- package/fesm2022/joanroucoux-cairn-ui-input.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs +838 -512
- package/fesm2022/joanroucoux-cairn-ui-line-chart.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-menu.mjs +401 -225
- package/fesm2022/joanroucoux-cairn-ui-menu.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-meter.mjs +143 -57
- package/fesm2022/joanroucoux-cairn-ui-meter.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-motion.mjs +367 -399
- package/fesm2022/joanroucoux-cairn-ui-motion.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs +73 -44
- package/fesm2022/joanroucoux-cairn-ui-nav-item.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-result-group.mjs +191 -0
- package/fesm2022/joanroucoux-cairn-ui-result-group.mjs.map +1 -0
- package/fesm2022/joanroucoux-cairn-ui-row.mjs +376 -146
- package/fesm2022/joanroucoux-cairn-ui-row.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-segmented.mjs +183 -81
- package/fesm2022/joanroucoux-cairn-ui-segmented.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs +233 -0
- package/fesm2022/joanroucoux-cairn-ui-select-pill.mjs.map +1 -0
- package/fesm2022/joanroucoux-cairn-ui-select.mjs +121 -67
- package/fesm2022/joanroucoux-cairn-ui-select.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs +129 -51
- package/fesm2022/joanroucoux-cairn-ui-skeleton.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs +80 -39
- package/fesm2022/joanroucoux-cairn-ui-stale-link.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-stat.mjs +85 -55
- package/fesm2022/joanroucoux-cairn-ui-stat.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-switch.mjs +48 -35
- package/fesm2022/joanroucoux-cairn-ui-switch.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs +113 -69
- package/fesm2022/joanroucoux-cairn-ui-tab-bar.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-table.mjs +1036 -310
- package/fesm2022/joanroucoux-cairn-ui-table.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui-toast.mjs +240 -127
- package/fesm2022/joanroucoux-cairn-ui-toast.mjs.map +1 -1
- package/fesm2022/joanroucoux-cairn-ui.mjs +0 -4
- package/package.json +17 -1
- package/styles/motion.css +1 -13
- package/styles/tokens.css +35 -64
- package/types/joanroucoux-cairn-ui-action-bar.d.ts +9 -14
- package/types/joanroucoux-cairn-ui-alert.d.ts +29 -15
- package/types/joanroucoux-cairn-ui-amount.d.ts +64 -32
- package/types/joanroucoux-cairn-ui-async.d.ts +85 -38
- package/types/joanroucoux-cairn-ui-avatar.d.ts +34 -22
- package/types/joanroucoux-cairn-ui-back-link.d.ts +20 -15
- package/types/joanroucoux-cairn-ui-badge.d.ts +22 -14
- package/types/joanroucoux-cairn-ui-button.d.ts +36 -18
- package/types/joanroucoux-cairn-ui-card.d.ts +48 -23
- package/types/joanroucoux-cairn-ui-choice-chips.d.ts +91 -35
- package/types/joanroucoux-cairn-ui-control.d.ts +9 -18
- package/types/joanroucoux-cairn-ui-delta.d.ts +46 -24
- package/types/joanroucoux-cairn-ui-dialog.d.ts +124 -57
- package/types/joanroucoux-cairn-ui-donut.d.ts +83 -46
- package/types/joanroucoux-cairn-ui-drawer.d.ts +73 -0
- package/types/joanroucoux-cairn-ui-empty.d.ts +20 -13
- package/types/joanroucoux-cairn-ui-external-link.d.ts +6 -10
- package/types/joanroucoux-cairn-ui-fact.d.ts +49 -25
- package/types/joanroucoux-cairn-ui-field.d.ts +72 -49
- package/types/joanroucoux-cairn-ui-filter-chips.d.ts +35 -20
- package/types/joanroucoux-cairn-ui-group-header.d.ts +58 -0
- package/types/joanroucoux-cairn-ui-input.d.ts +59 -37
- package/types/joanroucoux-cairn-ui-line-chart.d.ts +199 -89
- package/types/joanroucoux-cairn-ui-menu.d.ts +81 -44
- package/types/joanroucoux-cairn-ui-meter.d.ts +44 -22
- package/types/joanroucoux-cairn-ui-motion.d.ts +61 -75
- package/types/joanroucoux-cairn-ui-nav-item.d.ts +15 -13
- package/types/joanroucoux-cairn-ui-result-group.d.ts +52 -0
- package/types/joanroucoux-cairn-ui-row.d.ts +79 -37
- package/types/joanroucoux-cairn-ui-segmented.d.ts +51 -27
- package/types/joanroucoux-cairn-ui-select-pill.d.ts +52 -0
- package/types/joanroucoux-cairn-ui-select.d.ts +28 -18
- package/types/joanroucoux-cairn-ui-skeleton.d.ts +35 -18
- package/types/joanroucoux-cairn-ui-stale-link.d.ts +23 -16
- package/types/joanroucoux-cairn-ui-stat.d.ts +26 -21
- package/types/joanroucoux-cairn-ui-switch.d.ts +7 -11
- package/types/joanroucoux-cairn-ui-tab-bar.d.ts +20 -17
- package/types/joanroucoux-cairn-ui-table.d.ts +251 -89
- package/types/joanroucoux-cairn-ui-toast.d.ts +46 -36
- package/types/joanroucoux-cairn-ui.d.ts +1 -2
- package/fesm2022/joanroucoux-cairn-ui.mjs.map +0 -1
|
@@ -1,162 +1,223 @@
|
|
|
1
|
-
import * as i0 from
|
|
2
|
-
import { Directive,
|
|
3
|
-
import { UI_CONTROL } from
|
|
4
|
-
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { Component, Directive, ElementRef, afterRenderEffect, booleanAttribute, computed, contentChild, inject, input } from "@angular/core";
|
|
3
|
+
import { UI_CONTROL } from "@joanroucoux/cairn-ui/control";
|
|
5
4
|
const nextId = (() => {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
let count = 0;
|
|
6
|
+
return () => `ui-field-${++count}`;
|
|
8
7
|
})();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class UiFieldTrailing {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
8
|
+
var UiFieldLeading = class UiFieldLeading {
|
|
9
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
10
|
+
minVersion: "12.0.0",
|
|
11
|
+
version: "22.2.0",
|
|
12
|
+
ngImport: i0,
|
|
13
|
+
type: UiFieldLeading,
|
|
14
|
+
deps: [],
|
|
15
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
16
|
+
});
|
|
17
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
18
|
+
minVersion: "14.0.0",
|
|
19
|
+
version: "22.2.0",
|
|
20
|
+
type: UiFieldLeading,
|
|
21
|
+
isStandalone: true,
|
|
22
|
+
selector: "[uiFieldLeading]",
|
|
23
|
+
host: {
|
|
24
|
+
attributes: { "aria-hidden": "true" },
|
|
25
|
+
classAttribute: "pointer-events-none absolute left-3 flex text-(--muted-foreground)"
|
|
26
|
+
},
|
|
27
|
+
ngImport: i0
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
31
|
+
minVersion: "12.0.0",
|
|
32
|
+
version: "22.2.0",
|
|
33
|
+
ngImport: i0,
|
|
34
|
+
type: UiFieldLeading,
|
|
35
|
+
decorators: [{
|
|
36
|
+
type: Directive,
|
|
37
|
+
args: [{
|
|
38
|
+
selector: "[uiFieldLeading]",
|
|
39
|
+
host: {
|
|
40
|
+
class: "pointer-events-none absolute left-3 flex text-(--muted-foreground)",
|
|
41
|
+
"aria-hidden": "true"
|
|
42
|
+
}
|
|
43
|
+
}]
|
|
44
|
+
}]
|
|
45
|
+
});
|
|
46
|
+
var UiFieldTrailing = class UiFieldTrailing {
|
|
47
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
48
|
+
minVersion: "12.0.0",
|
|
49
|
+
version: "22.2.0",
|
|
50
|
+
ngImport: i0,
|
|
51
|
+
type: UiFieldTrailing,
|
|
52
|
+
deps: [],
|
|
53
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
54
|
+
});
|
|
55
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
56
|
+
minVersion: "14.0.0",
|
|
57
|
+
version: "22.2.0",
|
|
58
|
+
type: UiFieldTrailing,
|
|
59
|
+
isStandalone: true,
|
|
60
|
+
selector: "[uiFieldTrailing]",
|
|
61
|
+
host: { classAttribute: "absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)" },
|
|
62
|
+
ngImport: i0
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
66
|
+
minVersion: "12.0.0",
|
|
67
|
+
version: "22.2.0",
|
|
68
|
+
ngImport: i0,
|
|
69
|
+
type: UiFieldTrailing,
|
|
70
|
+
decorators: [{
|
|
71
|
+
type: Directive,
|
|
72
|
+
args: [{
|
|
73
|
+
selector: "[uiFieldTrailing]",
|
|
74
|
+
host: { class: "absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)" }
|
|
75
|
+
}]
|
|
76
|
+
}]
|
|
77
|
+
});
|
|
78
|
+
var UiField = class UiField {
|
|
79
|
+
label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
80
|
+
labelHidden = input(false, {
|
|
81
|
+
...ngDevMode ? { debugName: "labelHidden" } : /* istanbul ignore next */ {},
|
|
82
|
+
transform: booleanAttribute
|
|
83
|
+
});
|
|
84
|
+
hint = input(...ngDevMode ? [void 0, { debugName: "hint" }] : /* istanbul ignore next */ []);
|
|
85
|
+
error = input(...ngDevMode ? [void 0, { debugName: "error" }] : /* istanbul ignore next */ []);
|
|
86
|
+
unit = input(...ngDevMode ? [void 0, { debugName: "unit" }] : /* istanbul ignore next */ []);
|
|
87
|
+
optional = input(...ngDevMode ? [void 0, { debugName: "optional" }] : /* istanbul ignore next */ []);
|
|
88
|
+
invalid = input(false, {
|
|
89
|
+
...ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {},
|
|
90
|
+
transform: booleanAttribute
|
|
91
|
+
});
|
|
92
|
+
#id = nextId();
|
|
93
|
+
hintId = `${this.#id}-hint`;
|
|
94
|
+
errorId = `${this.#id}-error`;
|
|
95
|
+
#host = inject(ElementRef);
|
|
96
|
+
control = contentChild(UI_CONTROL, ...ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []);
|
|
97
|
+
leading = contentChild(UiFieldLeading, ...ngDevMode ? [{ debugName: "leading" }] : /* istanbul ignore next */ []);
|
|
98
|
+
trailing = contentChild(UiFieldTrailing, ...ngDevMode ? [{ debugName: "trailing" }] : /* istanbul ignore next */ []);
|
|
99
|
+
rowClasses = computed(() => [
|
|
100
|
+
"relative flex items-center",
|
|
101
|
+
this.leading() ? "[&>input]:pl-[38px]" : "",
|
|
102
|
+
this.trailing() ? "[&>input]:pr-12 lg:[&>input]:pr-11" : ""
|
|
103
|
+
].filter(Boolean).join(" "), ...ngDevMode ? [{ debugName: "rowClasses" }] : /* istanbul ignore next */ []);
|
|
104
|
+
labelClasses = computed(() => this.labelHidden() ? "sr-only" : "text-label leading-[17px] font-medium text-(--muted-foreground)", ...ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []);
|
|
105
|
+
message = computed(() => {
|
|
106
|
+
const explicit = this.error();
|
|
107
|
+
if (explicit) return explicit;
|
|
108
|
+
const control = this.control();
|
|
109
|
+
if (!control?.touched()) return;
|
|
110
|
+
return control.errors().find((error) => error.message)?.message;
|
|
111
|
+
}, ...ngDevMode ? [{ debugName: "message" }] : /* istanbul ignore next */ []);
|
|
112
|
+
constructor() {
|
|
113
|
+
let markedByField = false;
|
|
114
|
+
afterRenderEffect(() => {
|
|
115
|
+
const control = this.#host.nativeElement.querySelector("input, select, textarea");
|
|
116
|
+
if (!control) return;
|
|
117
|
+
control.id ||= this.#id;
|
|
118
|
+
this.#host.nativeElement.querySelector("label").htmlFor = control.id;
|
|
119
|
+
const describedBy = [this.hint() ? this.hintId : null, this.message() ? this.errorId : null].filter(Boolean);
|
|
120
|
+
if (describedBy.length > 0) control.setAttribute("aria-describedby", describedBy.join(" "));
|
|
121
|
+
else control.removeAttribute("aria-describedby");
|
|
122
|
+
if (this.message() || this.invalid()) {
|
|
123
|
+
control.setAttribute("aria-invalid", "true");
|
|
124
|
+
markedByField = true;
|
|
125
|
+
} else if (markedByField) {
|
|
126
|
+
control.removeAttribute("aria-invalid");
|
|
127
|
+
markedByField = false;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
132
|
+
minVersion: "12.0.0",
|
|
133
|
+
version: "22.2.0",
|
|
134
|
+
ngImport: i0,
|
|
135
|
+
type: UiField,
|
|
136
|
+
deps: [],
|
|
137
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
138
|
+
});
|
|
139
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
140
|
+
minVersion: "17.0.0",
|
|
141
|
+
version: "22.2.0",
|
|
142
|
+
type: UiField,
|
|
143
|
+
isStandalone: true,
|
|
144
|
+
selector: "ui-field",
|
|
145
|
+
inputs: {
|
|
146
|
+
label: {
|
|
147
|
+
classPropertyName: "label",
|
|
148
|
+
publicName: "label",
|
|
149
|
+
isSignal: true,
|
|
150
|
+
isRequired: true,
|
|
151
|
+
transformFunction: null
|
|
152
|
+
},
|
|
153
|
+
labelHidden: {
|
|
154
|
+
classPropertyName: "labelHidden",
|
|
155
|
+
publicName: "labelHidden",
|
|
156
|
+
isSignal: true,
|
|
157
|
+
isRequired: false,
|
|
158
|
+
transformFunction: null
|
|
159
|
+
},
|
|
160
|
+
hint: {
|
|
161
|
+
classPropertyName: "hint",
|
|
162
|
+
publicName: "hint",
|
|
163
|
+
isSignal: true,
|
|
164
|
+
isRequired: false,
|
|
165
|
+
transformFunction: null
|
|
166
|
+
},
|
|
167
|
+
error: {
|
|
168
|
+
classPropertyName: "error",
|
|
169
|
+
publicName: "error",
|
|
170
|
+
isSignal: true,
|
|
171
|
+
isRequired: false,
|
|
172
|
+
transformFunction: null
|
|
173
|
+
},
|
|
174
|
+
unit: {
|
|
175
|
+
classPropertyName: "unit",
|
|
176
|
+
publicName: "unit",
|
|
177
|
+
isSignal: true,
|
|
178
|
+
isRequired: false,
|
|
179
|
+
transformFunction: null
|
|
180
|
+
},
|
|
181
|
+
optional: {
|
|
182
|
+
classPropertyName: "optional",
|
|
183
|
+
publicName: "optional",
|
|
184
|
+
isSignal: true,
|
|
185
|
+
isRequired: false,
|
|
186
|
+
transformFunction: null
|
|
187
|
+
},
|
|
188
|
+
invalid: {
|
|
189
|
+
classPropertyName: "invalid",
|
|
190
|
+
publicName: "invalid",
|
|
191
|
+
isSignal: true,
|
|
192
|
+
isRequired: false,
|
|
193
|
+
transformFunction: null
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
queries: [
|
|
197
|
+
{
|
|
198
|
+
propertyName: "control",
|
|
199
|
+
first: true,
|
|
200
|
+
predicate: UI_CONTROL,
|
|
201
|
+
descendants: true,
|
|
202
|
+
isSignal: true
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
propertyName: "leading",
|
|
206
|
+
first: true,
|
|
207
|
+
predicate: UiFieldLeading,
|
|
208
|
+
descendants: true,
|
|
209
|
+
isSignal: true
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
propertyName: "trailing",
|
|
213
|
+
first: true,
|
|
214
|
+
predicate: UiFieldTrailing,
|
|
215
|
+
descendants: true,
|
|
216
|
+
isSignal: true
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
ngImport: i0,
|
|
220
|
+
template: `
|
|
160
221
|
<div class="group flex flex-col gap-1.5">
|
|
161
222
|
<!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->
|
|
162
223
|
<label [class]="labelClasses()"
|
|
@@ -185,13 +246,20 @@ class UiField {
|
|
|
185
246
|
</p>
|
|
186
247
|
}
|
|
187
248
|
</div>
|
|
188
|
-
`,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
249
|
+
`,
|
|
250
|
+
isInline: true
|
|
251
|
+
});
|
|
252
|
+
};
|
|
253
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
254
|
+
minVersion: "12.0.0",
|
|
255
|
+
version: "22.2.0",
|
|
256
|
+
ngImport: i0,
|
|
257
|
+
type: UiField,
|
|
258
|
+
decorators: [{
|
|
259
|
+
type: Component,
|
|
260
|
+
args: [{
|
|
261
|
+
selector: "ui-field",
|
|
262
|
+
template: `
|
|
195
263
|
<div class="group flex flex-col gap-1.5">
|
|
196
264
|
<!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->
|
|
197
265
|
<label [class]="labelClasses()"
|
|
@@ -220,13 +288,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImpor
|
|
|
220
288
|
</p>
|
|
221
289
|
}
|
|
222
290
|
</div>
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
291
|
+
`
|
|
292
|
+
}]
|
|
293
|
+
}],
|
|
294
|
+
ctorParameters: () => [],
|
|
295
|
+
propDecorators: {
|
|
296
|
+
label: [{
|
|
297
|
+
type: i0.Input,
|
|
298
|
+
args: [{
|
|
299
|
+
isSignal: true,
|
|
300
|
+
alias: "label",
|
|
301
|
+
required: true
|
|
302
|
+
}]
|
|
303
|
+
}],
|
|
304
|
+
labelHidden: [{
|
|
305
|
+
type: i0.Input,
|
|
306
|
+
args: [{
|
|
307
|
+
isSignal: true,
|
|
308
|
+
alias: "labelHidden",
|
|
309
|
+
required: false
|
|
310
|
+
}]
|
|
311
|
+
}],
|
|
312
|
+
hint: [{
|
|
313
|
+
type: i0.Input,
|
|
314
|
+
args: [{
|
|
315
|
+
isSignal: true,
|
|
316
|
+
alias: "hint",
|
|
317
|
+
required: false
|
|
318
|
+
}]
|
|
319
|
+
}],
|
|
320
|
+
error: [{
|
|
321
|
+
type: i0.Input,
|
|
322
|
+
args: [{
|
|
323
|
+
isSignal: true,
|
|
324
|
+
alias: "error",
|
|
325
|
+
required: false
|
|
326
|
+
}]
|
|
327
|
+
}],
|
|
328
|
+
unit: [{
|
|
329
|
+
type: i0.Input,
|
|
330
|
+
args: [{
|
|
331
|
+
isSignal: true,
|
|
332
|
+
alias: "unit",
|
|
333
|
+
required: false
|
|
334
|
+
}]
|
|
335
|
+
}],
|
|
336
|
+
optional: [{
|
|
337
|
+
type: i0.Input,
|
|
338
|
+
args: [{
|
|
339
|
+
isSignal: true,
|
|
340
|
+
alias: "optional",
|
|
341
|
+
required: false
|
|
342
|
+
}]
|
|
343
|
+
}],
|
|
344
|
+
invalid: [{
|
|
345
|
+
type: i0.Input,
|
|
346
|
+
args: [{
|
|
347
|
+
isSignal: true,
|
|
348
|
+
alias: "invalid",
|
|
349
|
+
required: false
|
|
350
|
+
}]
|
|
351
|
+
}],
|
|
352
|
+
control: [{
|
|
353
|
+
type: i0.ContentChild,
|
|
354
|
+
args: [i0.forwardRef(() => UI_CONTROL), { isSignal: true }]
|
|
355
|
+
}],
|
|
356
|
+
leading: [{
|
|
357
|
+
type: i0.ContentChild,
|
|
358
|
+
args: [i0.forwardRef(() => UiFieldLeading), { isSignal: true }]
|
|
359
|
+
}],
|
|
360
|
+
trailing: [{
|
|
361
|
+
type: i0.ContentChild,
|
|
362
|
+
args: [i0.forwardRef(() => UiFieldTrailing), { isSignal: true }]
|
|
363
|
+
}]
|
|
364
|
+
}
|
|
365
|
+
});
|
|
231
366
|
export { UiField, UiFieldLeading, UiFieldTrailing };
|
|
232
|
-
|
|
367
|
+
|
|
368
|
+
//# sourceMappingURL=joanroucoux-cairn-ui-field.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"joanroucoux-cairn-ui-field.mjs","sources":["../../../projects/ui/field/field.ts","../../../projects/ui/field/joanroucoux-cairn-ui-field.ts"],"sourcesContent":["import {\n Component,\n Directive,\n ElementRef,\n afterRenderEffect,\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n} from '@angular/core';\n\nimport { UI_CONTROL } from '@joanroucoux/cairn-ui/control';\n\nconst nextId = (() => {\n let count = 0;\n\n return (): string => `ui-field-${++count}`;\n})();\n\n/**\n * Marks an element, typically an 18px svg icon, as the leading content of a `ui-field`: it sits\n * inside the control's left edge and the control's text is inset to clear it. Decorative, so hidden\n * from assistive technologies.\n *\n * @example\n * <ui-field label=\"Search\" labelHidden>\n * <svg uiFieldLeading width=\"18\" height=\"18\" viewBox=\"0 0 24 24\">...</svg>\n * <input uiInput type=\"search\" />\n * </ui-field>\n */\n@Directive({\n selector: '[uiFieldLeading]',\n host: {\n class: 'pointer-events-none absolute left-3 flex text-(--muted-foreground)',\n 'aria-hidden': 'true',\n },\n})\nexport class UiFieldLeading {}\n\n/**\n * Marks an element, typically an icon button, as the trailing action of a `ui-field`: it sits on the\n * control's right edge, square to the control's height, and the control's text is padded to clear it.\n *\n * @example\n * <ui-field label=\"Password\">\n * <input uiInput type=\"password\" size=\"xl\" />\n * <button uiFieldTrailing type=\"button\" aria-label=\"Show the password\" [attr.aria-pressed]=\"shown()\">...</button>\n * </ui-field>\n *\n * A toggle such as this one should carry `aria-pressed`. The slot shares the right edge with `unit`:\n * set one or the other, not both.\n */\n@Directive({\n selector: '[uiFieldTrailing]',\n host: {\n class:\n 'absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)',\n },\n})\nexport class UiFieldTrailing {}\n\n/**\n * Label, control, hint and error as one unit. The control stays a plain native element:\n * the field finds it in its own projected content and wires the ARIA attributes onto it.\n *\n * The message comes from the caller's `error`, or, where none is set, from the projected control's\n * own validation state once it is touched.\n *\n * @example\n * <ui-field label=\"Quantity\" hint=\"Leave empty if unknown\">\n * <input uiInput type=\"number\" [formField]=\"form.quantity\" />\n * </ui-field>\n *\n * @example\n * <ui-field label=\"ISIN or name\" [error]=\"blank() ? 'Enter an ISIN' : undefined\">\n * <input uiInput type=\"search\" />\n * </ui-field>\n *\n * @example\n * <ui-field label=\"Search holdings\" labelHidden>\n * <input uiInput type=\"search\" placeholder=\"Instrument or account\" />\n * </ui-field>\n */\n@Component({\n selector: 'ui-field',\n template: `\n <div class=\"group flex flex-col gap-1.5\">\n <!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->\n <label [class]=\"labelClasses()\"\n >{{ label() }}\n @if (optional()) {\n {{ ' ' }}<span class=\"font-normal text-(--subtle-foreground)\">{{ optional() }}</span>\n }\n </label>\n\n <div [class]=\"rowClasses()\">\n <ng-content select=\"[uiFieldLeading]\" />\n <ng-content />\n <ng-content select=\"[uiFieldTrailing]\" />\n @if (unit()) {\n <span class=\"text-label pointer-events-none absolute right-3 text-(--subtle-foreground)\">{{ unit() }}</span>\n }\n </div>\n\n @if (hint()) {\n <span class=\"text-label text-(--muted-foreground)\" [id]=\"hintId\">{{ hint() }}</span>\n }\n\n @if (message()) {\n <p animate.enter=\"ui-enter-fade\" class=\"text-label font-medium text-(--negative)\" role=\"alert\" [id]=\"errorId\">\n {{ message() }}\n </p>\n }\n </div>\n `,\n})\nexport class UiField {\n readonly label = input.required<string>();\n readonly labelHidden = input(false, { transform: booleanAttribute });\n readonly hint = input<string>();\n readonly error = input<string>();\n readonly unit = input<string>();\n readonly optional = input<string>();\n readonly invalid = input(false, { transform: booleanAttribute });\n\n readonly #id = nextId();\n protected readonly hintId = `${this.#id}-hint`;\n protected readonly errorId = `${this.#id}-error`;\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly control = contentChild(UI_CONTROL);\n protected readonly leading = contentChild(UiFieldLeading);\n\n protected readonly trailing = contentChild(UiFieldTrailing);\n\n protected readonly rowClasses = computed(() =>\n [\n 'relative flex items-center',\n this.leading() ? '[&>input]:pl-[38px]' : '',\n this.trailing() ? '[&>input]:pr-12 lg:[&>input]:pr-11' : '',\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n protected readonly labelClasses = computed(() =>\n this.labelHidden() ? 'sr-only' : 'text-label leading-[17px] font-medium text-(--muted-foreground)',\n );\n\n /**\n * The caller's own `error` wins: it is the only way to report something the control does not\n * know about, such as a search box refusing an empty query.\n */\n protected readonly message = computed(() => {\n const explicit = this.error();\n\n if (explicit) {\n return explicit;\n }\n\n const control = this.control();\n\n if (!control?.touched()) {\n return undefined;\n }\n\n return control.errors().find((error) => error.message)?.message;\n });\n\n constructor() {\n let markedByField = false;\n\n afterRenderEffect(() => {\n // querySelector, not viewChild.required, so the \"no control found\" guard below stays reachable and testable.\n const control = this.#host.nativeElement.querySelector<HTMLElement>('input, select, textarea');\n\n if (!control) {\n return;\n }\n\n control.id ||= this.#id;\n this.#host.nativeElement.querySelector('label')!.htmlFor = control.id;\n\n const describedBy = [this.hint() ? this.hintId : null, this.message() ? this.errorId : null].filter(Boolean);\n\n if (describedBy.length > 0) {\n control.setAttribute('aria-describedby', describedBy.join(' '));\n } else {\n control.removeAttribute('aria-describedby');\n }\n\n if (this.message() || this.invalid()) {\n control.setAttribute('aria-invalid', 'true');\n markedByField = true;\n } else if (markedByField) {\n control.removeAttribute('aria-invalid');\n markedByField = false;\n }\n });\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"joanroucoux-cairn-ui-field.mjs","names":[],"sources":["../../../projects/ui/field/field.ts"],"sourcesContent":["import {\n Component,\n Directive,\n ElementRef,\n afterRenderEffect,\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n} from '@angular/core';\n\nimport { UI_CONTROL } from '@joanroucoux/cairn-ui/control';\n\nconst nextId = (() => {\n let count = 0;\n\n return (): string => `ui-field-${++count}`;\n})();\n\n/**\n * Marks an element, typically an 18px svg icon, as the leading content of a `ui-field`, inside the\n * control's left edge. Decorative, so hidden from assistive technologies.\n *\n * @example\n * <ui-field label=\"Search\" labelHidden>\n * <svg uiFieldLeading width=\"18\" height=\"18\" viewBox=\"0 0 24 24\">...</svg>\n * <input uiInput type=\"search\" />\n * </ui-field>\n */\n@Directive({\n selector: '[uiFieldLeading]',\n host: {\n class: 'pointer-events-none absolute left-3 flex text-(--muted-foreground)',\n 'aria-hidden': 'true',\n },\n})\nexport class UiFieldLeading {}\n\n/**\n * Marks an element, typically an icon button, as the trailing action of a `ui-field`, on the\n * control's right edge. A toggle should carry `aria-pressed`. The slot shares the right edge with\n * `unit`: set one or the other, not both.\n *\n * @example\n * <ui-field label=\"Password\">\n * <input uiInput type=\"password\" size=\"xl\" />\n * <button uiFieldTrailing type=\"button\" aria-label=\"Show the password\" [attr.aria-pressed]=\"shown()\">...</button>\n * </ui-field>\n */\n@Directive({\n selector: '[uiFieldTrailing]',\n host: {\n class:\n 'absolute right-0 grid h-full aspect-square place-items-center rounded-control cursor-pointer text-(--muted-foreground) transition-[color] duration-(--duration-fast) ease-out hover:text-(--foreground) focus-visible:outline-2 focus-visible:-outline-offset-4 focus-visible:outline-(--ring)',\n },\n})\nexport class UiFieldTrailing {}\n\n/**\n * Label, control, hint and error as one unit. The projected native control is found and wired with\n * the ARIA attributes. The message comes from `error`, which wins, or else from the control's own\n * validation state once touched.\n *\n * @example\n * <ui-field label=\"Quantity\" hint=\"Leave empty if unknown\">\n * <input uiInput type=\"number\" [formField]=\"form.quantity\" />\n * </ui-field>\n *\n * @example\n * <ui-field label=\"ISIN or name\" [error]=\"blank() ? 'Enter an ISIN' : undefined\">\n * <input uiInput type=\"search\" />\n * </ui-field>\n *\n * @example\n * <ui-field label=\"Search holdings\" labelHidden>\n * <input uiInput type=\"search\" placeholder=\"Instrument or account\" />\n * </ui-field>\n */\n@Component({\n selector: 'ui-field',\n template: `\n <div class=\"group flex flex-col gap-1.5\">\n <!-- eslint-disable-next-line @angular-eslint/template/label-has-associated-control -- htmlFor is wired at runtime, once the projected control's id is known -->\n <label [class]=\"labelClasses()\"\n >{{ label() }}\n @if (optional()) {\n {{ ' ' }}<span class=\"font-normal text-(--subtle-foreground)\">{{ optional() }}</span>\n }\n </label>\n\n <div [class]=\"rowClasses()\">\n <ng-content select=\"[uiFieldLeading]\" />\n <ng-content />\n <ng-content select=\"[uiFieldTrailing]\" />\n @if (unit()) {\n <span class=\"text-label pointer-events-none absolute right-3 text-(--subtle-foreground)\">{{ unit() }}</span>\n }\n </div>\n\n @if (hint()) {\n <span class=\"text-label text-(--muted-foreground)\" [id]=\"hintId\">{{ hint() }}</span>\n }\n\n @if (message()) {\n <p animate.enter=\"ui-enter-fade\" class=\"text-label font-medium text-(--negative)\" role=\"alert\" [id]=\"errorId\">\n {{ message() }}\n </p>\n }\n </div>\n `,\n})\nexport class UiField {\n readonly label = input.required<string>();\n readonly labelHidden = input(false, { transform: booleanAttribute });\n readonly hint = input<string>();\n readonly error = input<string>();\n readonly unit = input<string>();\n readonly optional = input<string>();\n readonly invalid = input(false, { transform: booleanAttribute });\n\n readonly #id = nextId();\n protected readonly hintId = `${this.#id}-hint`;\n protected readonly errorId = `${this.#id}-error`;\n readonly #host = inject<ElementRef<HTMLElement>>(ElementRef);\n protected readonly control = contentChild(UI_CONTROL);\n protected readonly leading = contentChild(UiFieldLeading);\n\n protected readonly trailing = contentChild(UiFieldTrailing);\n\n protected readonly rowClasses = computed(() =>\n [\n 'relative flex items-center',\n this.leading() ? '[&>input]:pl-[38px]' : '',\n this.trailing() ? '[&>input]:pr-12 lg:[&>input]:pr-11' : '',\n ]\n .filter(Boolean)\n .join(' '),\n );\n\n protected readonly labelClasses = computed(() =>\n this.labelHidden() ? 'sr-only' : 'text-label leading-[17px] font-medium text-(--muted-foreground)',\n );\n\n protected readonly message = computed(() => {\n const explicit = this.error();\n\n if (explicit) {\n return explicit;\n }\n\n const control = this.control();\n\n if (!control?.touched()) {\n return undefined;\n }\n\n return control.errors().find((error) => error.message)?.message;\n });\n\n constructor() {\n let markedByField = false;\n\n afterRenderEffect(() => {\n const control = this.#host.nativeElement.querySelector<HTMLElement>('input, select, textarea');\n\n if (!control) {\n return;\n }\n\n control.id ||= this.#id;\n this.#host.nativeElement.querySelector('label')!.htmlFor = control.id;\n\n const describedBy = [this.hint() ? this.hintId : null, this.message() ? this.errorId : null].filter(Boolean);\n\n if (describedBy.length > 0) {\n control.setAttribute('aria-describedby', describedBy.join(' '));\n } else {\n control.removeAttribute('aria-describedby');\n }\n\n if (this.message() || this.invalid()) {\n control.setAttribute('aria-invalid', 'true');\n markedByField = true;\n } else if (markedByField) {\n control.removeAttribute('aria-invalid');\n markedByField = false;\n }\n });\n }\n}\n"],"mappings":"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"}
|