@nanahoshi/mona-ui 0.13.0 → 0.13.1
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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NgTemplateOutlet } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, TemplateRef, Directive, computed, contentChild, input, output, model, Component } from '@angular/core';
|
|
3
|
+
import { inject, TemplateRef, Directive, DestroyRef, ElementRef, computed, signal, contentChild, viewChildren, input, output, model, afterRenderEffect, afterNextRender, Component } from '@angular/core';
|
|
4
4
|
import { themeControlSurfaceClasses, createElementControlId } from '@nanahoshi/mona-ui/internal';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
6
6
|
import { cva } from 'class-variance-authority';
|
|
@@ -27,7 +27,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
27
27
|
}] });
|
|
28
28
|
|
|
29
29
|
const segmentedContainerThemeVariants = cva(`
|
|
30
|
-
inline-flex items-center gap-0.5
|
|
30
|
+
relative inline-flex items-center gap-0.5
|
|
31
31
|
${themeControlSurfaceClasses}
|
|
32
32
|
border border-input-border
|
|
33
33
|
p-1
|
|
@@ -56,11 +56,11 @@ const segmentedOptionThemeVariants = cva(`
|
|
|
56
56
|
data-[disabled='true']:cursor-not-allowed
|
|
57
57
|
data-[disabled='true']:opacity-50
|
|
58
58
|
data-[disabled='true']:text-disabled-foreground
|
|
59
|
-
data-[selected='true']:
|
|
60
|
-
data-[selected='true']:shadow-sm data-[selected='true']:ring-1 data-[selected='true']:ring-selected-border
|
|
59
|
+
data-[selected='true']:text-primary-foreground
|
|
61
60
|
data-[selected='false']:text-muted-foreground
|
|
62
61
|
data-[selected='false']:hover:bg-hover data-[selected='false']:hover:text-foreground
|
|
63
62
|
data-[disabled='true']:data-[selected='false']:text-disabled-foreground
|
|
63
|
+
data-[selected='true']:transition-none
|
|
64
64
|
`, {
|
|
65
65
|
variants: {
|
|
66
66
|
rounded: {
|
|
@@ -81,6 +81,30 @@ const segmentedOptionThemeVariants = cva(`
|
|
|
81
81
|
size: "medium"
|
|
82
82
|
}
|
|
83
83
|
});
|
|
84
|
+
const segmentedIndicatorThemeVariants = cva(`
|
|
85
|
+
pointer-events-none absolute top-0 left-0
|
|
86
|
+
bg-primary shadow-sm ring-1 ring-selected-border
|
|
87
|
+
data-[disabled='true']:opacity-50
|
|
88
|
+
motion-reduce:transition-none
|
|
89
|
+
`, {
|
|
90
|
+
variants: {
|
|
91
|
+
animate: {
|
|
92
|
+
true: "transition-[transform,width,height] duration-(--mona-motion-fast) ease-out",
|
|
93
|
+
false: "transition-none"
|
|
94
|
+
},
|
|
95
|
+
rounded: {
|
|
96
|
+
none: "rounded-none",
|
|
97
|
+
small: "rounded-xs",
|
|
98
|
+
medium: "rounded-sm",
|
|
99
|
+
large: "rounded-md",
|
|
100
|
+
full: "rounded-full"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
defaultVariants: {
|
|
104
|
+
animate: true,
|
|
105
|
+
rounded: "medium"
|
|
106
|
+
}
|
|
107
|
+
});
|
|
84
108
|
const segmentedInputThemeVariants = cva(`
|
|
85
109
|
peer absolute inset-0 z-10 h-full w-full
|
|
86
110
|
cursor-pointer appearance-none opacity-0
|
|
@@ -89,13 +113,37 @@ const segmentedInputThemeVariants = cva(`
|
|
|
89
113
|
`);
|
|
90
114
|
|
|
91
115
|
class SegmentedComponent {
|
|
116
|
+
#destroyRef;
|
|
117
|
+
#hostElementRef;
|
|
118
|
+
#lastAnimatedIndex;
|
|
119
|
+
#lastOptions;
|
|
120
|
+
#lastSize;
|
|
121
|
+
#resizeObserver;
|
|
92
122
|
constructor() {
|
|
123
|
+
this.#destroyRef = inject(DestroyRef);
|
|
124
|
+
this.#hostElementRef = inject(ElementRef);
|
|
125
|
+
this.#lastAnimatedIndex = null;
|
|
126
|
+
this.#lastOptions = null;
|
|
127
|
+
this.#lastSize = null;
|
|
128
|
+
this.#resizeObserver = null;
|
|
93
129
|
this.containerClasses = computed(() => {
|
|
94
130
|
const classes = segmentedContainerThemeVariants({ rounded: this.rounded() });
|
|
95
131
|
return twMerge(classes, this.userClass());
|
|
96
132
|
}, /* @ts-ignore */
|
|
97
133
|
...(ngDevMode ? [{ debugName: "containerClasses" }] : /* istanbul ignore next */ []));
|
|
98
134
|
this.groupName = createElementControlId();
|
|
135
|
+
this.indicatorClasses = computed(() => {
|
|
136
|
+
const animate = this.animate() && this.indicatorTransitionEnabled();
|
|
137
|
+
const rounded = this.rounded();
|
|
138
|
+
return segmentedIndicatorThemeVariants({ animate, rounded });
|
|
139
|
+
}, /* @ts-ignore */
|
|
140
|
+
...(ngDevMode ? [{ debugName: "indicatorClasses" }] : /* istanbul ignore next */ []));
|
|
141
|
+
this.indicatorGeometry = signal(null, /* @ts-ignore */
|
|
142
|
+
...(ngDevMode ? [{ debugName: "indicatorGeometry" }] : /* istanbul ignore next */ []));
|
|
143
|
+
this.indicatorInitialized = signal(false, /* @ts-ignore */
|
|
144
|
+
...(ngDevMode ? [{ debugName: "indicatorInitialized" }] : /* istanbul ignore next */ []));
|
|
145
|
+
this.indicatorTransitionEnabled = signal(false, /* @ts-ignore */
|
|
146
|
+
...(ngDevMode ? [{ debugName: "indicatorTransitionEnabled" }] : /* istanbul ignore next */ []));
|
|
99
147
|
this.inputClasses = computed(() => segmentedInputThemeVariants(), /* @ts-ignore */
|
|
100
148
|
...(ngDevMode ? [{ debugName: "inputClasses" }] : /* istanbul ignore next */ []));
|
|
101
149
|
this.invalidState = computed(() => this.touched() && this.invalid(), /* @ts-ignore */
|
|
@@ -107,6 +155,29 @@ class SegmentedComponent {
|
|
|
107
155
|
return segmentedOptionThemeVariants({ rounded, size });
|
|
108
156
|
}, /* @ts-ignore */
|
|
109
157
|
...(ngDevMode ? [{ debugName: "optionClasses" }] : /* istanbul ignore next */ []));
|
|
158
|
+
this.optionElements = viewChildren("optionElement", /* @ts-ignore */
|
|
159
|
+
...(ngDevMode ? [{ debugName: "optionElements" }] : /* istanbul ignore next */ []));
|
|
160
|
+
this.selectedIndex = computed(() => {
|
|
161
|
+
const value = this.value();
|
|
162
|
+
return this.options().findIndex(option => option.value === value);
|
|
163
|
+
}, /* @ts-ignore */
|
|
164
|
+
...(ngDevMode ? [{ debugName: "selectedIndex" }] : /* istanbul ignore next */ []));
|
|
165
|
+
this.selectedOptionDisabled = computed(() => {
|
|
166
|
+
const selectedIndex = this.selectedIndex();
|
|
167
|
+
if (selectedIndex === -1) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
const option = this.options()[selectedIndex];
|
|
171
|
+
return this.disabled() || !!option?.disabled;
|
|
172
|
+
}, /* @ts-ignore */
|
|
173
|
+
...(ngDevMode ? [{ debugName: "selectedOptionDisabled" }] : /* istanbul ignore next */ []));
|
|
174
|
+
/**
|
|
175
|
+
* @description Controls whether the selection indicator animates between selected options.
|
|
176
|
+
* When false, selection changes are applied immediately without transition.
|
|
177
|
+
* @default true
|
|
178
|
+
*/
|
|
179
|
+
this.animate = input(true, /* @ts-ignore */
|
|
180
|
+
...(ngDevMode ? [{ debugName: "animate" }] : /* istanbul ignore next */ []));
|
|
110
181
|
/**
|
|
111
182
|
* @description Accessible name for the radio group. Provide either `aria-label` or `aria-labelledby`.
|
|
112
183
|
* @default null
|
|
@@ -170,6 +241,30 @@ class SegmentedComponent {
|
|
|
170
241
|
*/
|
|
171
242
|
this.value = model(null, /* @ts-ignore */
|
|
172
243
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
244
|
+
afterRenderEffect({
|
|
245
|
+
read: () => {
|
|
246
|
+
this.selectedIndex();
|
|
247
|
+
this.optionElements();
|
|
248
|
+
this.rounded();
|
|
249
|
+
this.animate();
|
|
250
|
+
const size = this.size();
|
|
251
|
+
const options = this.options();
|
|
252
|
+
const isSizeChange = this.#lastSize !== null && this.#lastSize !== size;
|
|
253
|
+
const isOptionsChange = this.#lastOptions !== null && this.#lastOptions !== options;
|
|
254
|
+
const suppressTransition = isSizeChange || isOptionsChange;
|
|
255
|
+
this.#lastSize = size;
|
|
256
|
+
this.#lastOptions = options;
|
|
257
|
+
this.updateIndicatorGeometry({ suppressTransition });
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
afterNextRender({
|
|
261
|
+
read: () => {
|
|
262
|
+
this.setupResizeObserver();
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
this.#destroyRef.onDestroy(() => {
|
|
266
|
+
this.#resizeObserver?.disconnect();
|
|
267
|
+
});
|
|
173
268
|
}
|
|
174
269
|
createOptionContext(option, index) {
|
|
175
270
|
return {
|
|
@@ -190,8 +285,57 @@ class SegmentedComponent {
|
|
|
190
285
|
this.value.set(option.value);
|
|
191
286
|
this.touch.emit();
|
|
192
287
|
}
|
|
288
|
+
setupResizeObserver() {
|
|
289
|
+
if (typeof ResizeObserver === "undefined") {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
this.#resizeObserver = new ResizeObserver(() => {
|
|
293
|
+
this.updateIndicatorGeometry({ suppressTransition: true });
|
|
294
|
+
});
|
|
295
|
+
this.#resizeObserver.observe(this.#hostElementRef.nativeElement);
|
|
296
|
+
}
|
|
297
|
+
updateIndicatorGeometry(options) {
|
|
298
|
+
const selectedIndex = this.selectedIndex();
|
|
299
|
+
if (selectedIndex === -1) {
|
|
300
|
+
this.#lastAnimatedIndex = null;
|
|
301
|
+
this.indicatorGeometry.set(null);
|
|
302
|
+
this.indicatorTransitionEnabled.set(false);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const optionElements = this.optionElements();
|
|
306
|
+
const selectedElementRef = optionElements[selectedIndex];
|
|
307
|
+
if (!selectedElementRef?.nativeElement) {
|
|
308
|
+
this.#lastAnimatedIndex = null;
|
|
309
|
+
this.indicatorGeometry.set(null);
|
|
310
|
+
this.indicatorTransitionEnabled.set(false);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const host = this.#hostElementRef.nativeElement;
|
|
314
|
+
const option = selectedElementRef.nativeElement;
|
|
315
|
+
const hostRect = host.getBoundingClientRect();
|
|
316
|
+
const optionRect = option.getBoundingClientRect();
|
|
317
|
+
const x = optionRect.left - hostRect.left - (host.clientLeft || 0);
|
|
318
|
+
const y = optionRect.top - hostRect.top - (host.clientTop || 0);
|
|
319
|
+
const width = optionRect.width;
|
|
320
|
+
const height = optionRect.height;
|
|
321
|
+
const shouldAnimate = !options?.suppressTransition &&
|
|
322
|
+
this.animate() &&
|
|
323
|
+
this.indicatorInitialized() &&
|
|
324
|
+
this.#lastAnimatedIndex !== null &&
|
|
325
|
+
this.#lastAnimatedIndex !== selectedIndex;
|
|
326
|
+
this.indicatorTransitionEnabled.set(shouldAnimate);
|
|
327
|
+
this.indicatorGeometry.set({
|
|
328
|
+
height,
|
|
329
|
+
transform: `translate3d(${x}px, ${y}px, 0)`,
|
|
330
|
+
width
|
|
331
|
+
});
|
|
332
|
+
this.#lastAnimatedIndex = selectedIndex;
|
|
333
|
+
if (!this.indicatorInitialized()) {
|
|
334
|
+
this.indicatorInitialized.set(true);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
193
337
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SegmentedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
194
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: SegmentedComponent, isStandalone: true, selector: "mona-segmented", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { touch: "touch", value: "valueChange" }, host: { properties: { "attr.aria-disabled": "disabled() || undefined", "attr.aria-invalid": "invalidState() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-labelledby": "ariaLabelledBy()", "attr.data-disabled": "disabled()", "attr.data-invalid": "invalidState() || null", "attr.role": "'radiogroup'", "class": "containerClasses()" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: SegmentedItemTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: "@for (option of options(); track option.value) {\n @let selected = option.value === value();\n @let optionDisabled = disabled() || option.disabled;\n\n <label
|
|
338
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: SegmentedComponent, isStandalone: true, selector: "mona-segmented", inputs: { animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelledBy: { classPropertyName: "ariaLabelledBy", publicName: "aria-labelledby", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { touch: "touch", value: "valueChange" }, host: { properties: { "attr.aria-disabled": "disabled() || undefined", "attr.aria-invalid": "invalidState() ? 'true' : null", "attr.aria-label": "ariaLabel()", "attr.aria-labelledby": "ariaLabelledBy()", "attr.data-disabled": "disabled()", "attr.data-invalid": "invalidState() || null", "attr.role": "'radiogroup'", "class": "containerClasses()" } }, queries: [{ propertyName: "itemTemplate", first: true, predicate: SegmentedItemTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "optionElements", predicate: ["optionElement"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (indicatorGeometry(); as geometry) {\n <div\n aria-hidden=\"true\"\n [class]=\"indicatorClasses()\"\n [attr.data-disabled]=\"selectedOptionDisabled() ? 'true' : null\"\n [style.transform]=\"geometry.transform\"\n [style.width.px]=\"geometry.width\"\n [style.height.px]=\"geometry.height\"></div>\n}\n\n@for (option of options(); track option.value) {\n @let selected = option.value === value();\n @let optionDisabled = disabled() || option.disabled;\n\n <label\n #optionElement\n [class]=\"optionClasses()\"\n [attr.data-selected]=\"selected\"\n [attr.data-disabled]=\"optionDisabled\">\n <input\n type=\"radio\"\n [name]=\"groupName\"\n [value]=\"option.value\"\n [checked]=\"selected\"\n [disabled]=\"optionDisabled\"\n [class]=\"inputClasses()\"\n (change)=\"onOptionChange(option)\"\n (blur)=\"onOptionBlur()\" />\n\n <span\n class=\"pointer-events-none flex flex-1 items-center justify-center gap-1\n [border-radius:inherit]\n peer-focus-visible:ring-2\n peer-focus-visible:ring-focus-indicator/35\">\n @if (itemTemplate(); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"createOptionContext(option, $index)\"></ng-container>\n } @else {\n {{ option.label }}\n }\n </span>\n </label>\n}\n\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
|
|
195
339
|
}
|
|
196
340
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: SegmentedComponent, decorators: [{
|
|
197
341
|
type: Component,
|
|
@@ -204,8 +348,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
|
|
|
204
348
|
"[attr.data-invalid]": "invalidState() || null",
|
|
205
349
|
"[attr.role]": "'radiogroup'",
|
|
206
350
|
"[class]": "containerClasses()"
|
|
207
|
-
}, template: "@for (option of options(); track option.value) {\n @let selected = option.value === value();\n @let optionDisabled = disabled() || option.disabled;\n\n <label
|
|
208
|
-
}], propDecorators: { itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SegmentedItemTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
351
|
+
}, template: "@if (indicatorGeometry(); as geometry) {\n <div\n aria-hidden=\"true\"\n [class]=\"indicatorClasses()\"\n [attr.data-disabled]=\"selectedOptionDisabled() ? 'true' : null\"\n [style.transform]=\"geometry.transform\"\n [style.width.px]=\"geometry.width\"\n [style.height.px]=\"geometry.height\"></div>\n}\n\n@for (option of options(); track option.value) {\n @let selected = option.value === value();\n @let optionDisabled = disabled() || option.disabled;\n\n <label\n #optionElement\n [class]=\"optionClasses()\"\n [attr.data-selected]=\"selected\"\n [attr.data-disabled]=\"optionDisabled\">\n <input\n type=\"radio\"\n [name]=\"groupName\"\n [value]=\"option.value\"\n [checked]=\"selected\"\n [disabled]=\"optionDisabled\"\n [class]=\"inputClasses()\"\n (change)=\"onOptionChange(option)\"\n (blur)=\"onOptionBlur()\" />\n\n <span\n class=\"pointer-events-none flex flex-1 items-center justify-center gap-1\n [border-radius:inherit]\n peer-focus-visible:ring-2\n peer-focus-visible:ring-focus-indicator/35\">\n @if (itemTemplate(); as template) {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"createOptionContext(option, $index)\"></ng-container>\n } @else {\n {{ option.label }}\n }\n </span>\n </label>\n}\n\n" }]
|
|
352
|
+
}], ctorParameters: () => [], propDecorators: { itemTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SegmentedItemTemplateDirective), { ...{ read: TemplateRef }, isSignal: true }] }], optionElements: [{ type: i0.ViewChildren, args: ["optionElement", { isSignal: true }] }], animate: [{ type: i0.Input, args: [{ isSignal: true, alias: "animate", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-labelledby", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], touch: [{ type: i0.Output, args: ["touch"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], userClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
|
|
209
353
|
|
|
210
354
|
/*
|
|
211
355
|
* Public API Surface of @nanahoshi/mona-ui/segmented
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { TemplateRef } from '@angular/core';
|
|
2
|
+
import { TemplateRef, ElementRef } from '@angular/core';
|
|
3
3
|
import { FormValueControl } from '@angular/forms/signals';
|
|
4
4
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
5
|
import { VariantProps } from 'class-variance-authority';
|
|
6
6
|
import { VariantInputs } from '@nanahoshi/mona-ui/internal';
|
|
7
7
|
import * as _nanahoshi_mona_ui_segmented from '@nanahoshi/mona-ui/segmented';
|
|
8
8
|
|
|
9
|
+
interface SegmentedIndicatorGeometry {
|
|
10
|
+
height: number;
|
|
11
|
+
transform: string;
|
|
12
|
+
width: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
9
15
|
type SegmentedValue = string | number;
|
|
10
16
|
|
|
11
17
|
interface SegmentedOption<T extends SegmentedValue = SegmentedValue> {
|
|
@@ -55,12 +61,26 @@ type SegmentedVariantProps = SegmentedContainerVariantProps & SegmentedOptionVar
|
|
|
55
61
|
type SegmentedVariantInput = SegmentedContainerVariantInput & SegmentedOptionVariantInput;
|
|
56
62
|
|
|
57
63
|
declare class SegmentedComponent<T extends SegmentedValue = SegmentedValue> implements SegmentedVariantInput, FormValueControl<T | null> {
|
|
64
|
+
#private;
|
|
58
65
|
protected readonly containerClasses: _angular_core.Signal<string>;
|
|
59
66
|
protected readonly groupName: string;
|
|
67
|
+
protected readonly indicatorClasses: _angular_core.Signal<string>;
|
|
68
|
+
protected readonly indicatorGeometry: _angular_core.WritableSignal<SegmentedIndicatorGeometry | null>;
|
|
69
|
+
protected readonly indicatorInitialized: _angular_core.WritableSignal<boolean>;
|
|
70
|
+
protected readonly indicatorTransitionEnabled: _angular_core.WritableSignal<boolean>;
|
|
60
71
|
protected readonly inputClasses: _angular_core.Signal<string>;
|
|
61
72
|
protected readonly invalidState: _angular_core.Signal<boolean>;
|
|
62
73
|
protected readonly itemTemplate: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
63
74
|
protected readonly optionClasses: _angular_core.Signal<string>;
|
|
75
|
+
protected readonly optionElements: _angular_core.Signal<readonly ElementRef<HTMLLabelElement>[]>;
|
|
76
|
+
protected readonly selectedIndex: _angular_core.Signal<number>;
|
|
77
|
+
protected readonly selectedOptionDisabled: _angular_core.Signal<boolean>;
|
|
78
|
+
/**
|
|
79
|
+
* @description Controls whether the selection indicator animates between selected options.
|
|
80
|
+
* When false, selection changes are applied immediately without transition.
|
|
81
|
+
* @default true
|
|
82
|
+
*/
|
|
83
|
+
readonly animate: _angular_core.InputSignal<boolean>;
|
|
64
84
|
/**
|
|
65
85
|
* @description Accessible name for the radio group. Provide either `aria-label` or `aria-labelledby`.
|
|
66
86
|
* @default null
|
|
@@ -117,11 +137,14 @@ declare class SegmentedComponent<T extends SegmentedValue = SegmentedValue> impl
|
|
|
117
137
|
* @default null
|
|
118
138
|
*/
|
|
119
139
|
readonly value: _angular_core.ModelSignal<T | null>;
|
|
140
|
+
constructor();
|
|
120
141
|
protected createOptionContext(option: SegmentedOption<T>, index: number): SegmentedItemTemplateContext<T>;
|
|
121
142
|
protected onOptionBlur(): void;
|
|
122
143
|
protected onOptionChange(option: SegmentedOption<T>): void;
|
|
144
|
+
private setupResizeObserver;
|
|
145
|
+
private updateIndicatorGeometry;
|
|
123
146
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SegmentedComponent<any>, never>;
|
|
124
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SegmentedComponent<any>, "mona-segmented", never, { "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledBy": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "touch": "touch"; "value": "valueChange"; }, ["itemTemplate"], never, true, never>;
|
|
147
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SegmentedComponent<any>, "mona-segmented", never, { "animate": { "alias": "animate"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "aria-label"; "required": false; "isSignal": true; }; "ariaLabelledBy": { "alias": "aria-labelledby"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "invalid": { "alias": "invalid"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": true; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "touched": { "alias": "touched"; "required": false; "isSignal": true; }; "userClass": { "alias": "class"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "touch": "touch"; "value": "valueChange"; }, ["itemTemplate"], never, true, never>;
|
|
125
148
|
}
|
|
126
149
|
|
|
127
150
|
/**
|