ud-components 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2274,29 +2274,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImpo
2274
2274
  }] } });
2275
2275
 
2276
2276
  class ToggleComponent {
2277
+ /** Key of the control inside the parent FormGroup (alternative to ngModel/formControl) */
2278
+ controlName;
2277
2279
  size = 'md';
2278
2280
  label;
2279
2281
  labelPosition = 'right';
2280
2282
  ariaLabel;
2281
- get isSm() {
2282
- return this.size === 'sm';
2283
- }
2284
- get isMd() {
2285
- return this.size === 'md';
2286
- }
2287
- get isLg() {
2288
- return this.size === 'lg';
2289
- }
2283
+ get isSm() { return this.size === 'sm'; }
2284
+ get isMd() { return this.size === 'md'; }
2285
+ get isLg() { return this.size === 'lg'; }
2290
2286
  checked = false;
2291
2287
  isDisabled = false;
2288
+ controlContainer = inject(ControlContainer, { optional: true, skipSelf: true });
2289
+ destroy$ = new Subject();
2292
2290
  onChange = () => { };
2293
2291
  onTouched = () => { };
2292
+ get formControl() {
2293
+ if (!this.controlName || !this.controlContainer?.control)
2294
+ return null;
2295
+ return this.controlContainer.control.get(this.controlName) ?? null;
2296
+ }
2297
+ ngOnInit() {
2298
+ const ctrl = this.formControl;
2299
+ if (!ctrl)
2300
+ return;
2301
+ ctrl.valueChanges
2302
+ .pipe(startWith(ctrl.value), takeUntil(this.destroy$))
2303
+ .subscribe((val) => {
2304
+ this.checked = !!val;
2305
+ this.isDisabled = ctrl.disabled;
2306
+ });
2307
+ }
2308
+ ngOnDestroy() {
2309
+ this.destroy$.next();
2310
+ this.destroy$.complete();
2311
+ }
2294
2312
  toggle() {
2295
2313
  if (this.isDisabled)
2296
2314
  return;
2297
- this.checked = !this.checked;
2298
- this.onChange(this.checked);
2299
- this.onTouched();
2315
+ const ctrl = this.formControl;
2316
+ if (ctrl) {
2317
+ ctrl.setValue(!this.checked);
2318
+ ctrl.markAsTouched();
2319
+ }
2320
+ else {
2321
+ this.checked = !this.checked;
2322
+ this.onChange(this.checked);
2323
+ this.onTouched();
2324
+ }
2300
2325
  }
2301
2326
  writeValue(value) {
2302
2327
  this.checked = !!value;
@@ -2311,13 +2336,18 @@ class ToggleComponent {
2311
2336
  this.isDisabled = isDisabled;
2312
2337
  }
2313
2338
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: ToggleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2314
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: ToggleComponent, isStandalone: true, selector: "ud-toggle", inputs: { size: "size", label: "label", labelPosition: "labelPosition", ariaLabel: "ariaLabel" }, host: { properties: { "class.size-sm": "this.isSm", "class.size-md": "this.isMd", "class.size-lg": "this.isLg" } }, providers: [
2339
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: ToggleComponent, isStandalone: true, selector: "ud-toggle", inputs: { controlName: "controlName", size: "size", label: "label", labelPosition: "labelPosition", ariaLabel: "ariaLabel" }, host: { properties: { "class.size-sm": "this.isSm", "class.size-md": "this.isMd", "class.size-lg": "this.isLg" } }, providers: [
2315
2340
  {
2316
2341
  provide: NG_VALUE_ACCESSOR,
2317
2342
  useExisting: forwardRef(() => ToggleComponent),
2318
2343
  multi: true,
2319
2344
  },
2320
- ], ngImport: i0, template: "<button\n type=\"button\"\n class=\"ud-toggle\"\n [class.checked]=\"checked\"\n [class.disabled]=\"isDisabled\"\n [class.label-left]=\"labelPosition === 'left'\"\n role=\"switch\"\n [attr.aria-checked]=\"checked\"\n [attr.aria-label]=\"ariaLabel || label\"\n [disabled]=\"isDisabled || null\"\n (click)=\"toggle()\">\n @if (label && labelPosition === 'left') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n <span class=\"track\" aria-hidden=\"true\">\n <span class=\"thumb\">\n <span class=\"thumb-core\"></span>\n </span>\n </span>\n @if (label && labelPosition === 'right') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n</button>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500&display=swap\";:host{display:inline-flex;align-items:center;--toggle-track-off: #d2d6de;--toggle-track-on: #1b2535;--toggle-thumb: #ffffff;--toggle-glow: rgba(27, 37, 53, .14);--toggle-label-color: #4a5568;--toggle-font: \"DM Sans\", system-ui, sans-serif;--toggle-duration: .3s;--toggle-spring: cubic-bezier(.34, 1.56, .64, 1)}:host(.size-sm){--track-w: 28px;--track-h: 16px;--thumb-d: 12px;--thumb-inset: 2px}:host(.size-md){--track-w: 44px;--track-h: 24px;--thumb-d: 18px;--thumb-inset: 3px}:host(.size-lg){--track-w: 56px;--track-h: 32px;--thumb-d: 24px;--thumb-inset: 4px}.ud-toggle{display:inline-flex;align-items:center;gap:.6rem;background:none;border:none;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;outline:none}.ud-toggle:focus-visible .track{outline:2px solid var(--toggle-track-on);outline-offset:2px}.ud-toggle.disabled{opacity:.38;cursor:not-allowed;pointer-events:none}.track{position:relative;display:block;width:var(--track-w);height:var(--track-h);border-radius:999px;background:var(--toggle-track-off);box-shadow:inset 0 1px 3px #0000002e,inset 0 0 0 1px #0000000f;transition:background var(--toggle-duration) ease;flex-shrink:0}.ud-toggle.checked .track{background:var(--toggle-track-on);box-shadow:inset 0 1px 3px #0000004d,inset 0 0 0 1px #00000026}.thumb{position:absolute;top:50%;left:0;width:var(--thumb-d);height:var(--thumb-d);border-radius:50%;background:var(--toggle-thumb);transform:translateY(-50%) translate(var(--thumb-inset));box-shadow:0 1px 2px #00000038,0 2px 6px #00000024;transition:transform var(--toggle-duration) var(--toggle-spring),box-shadow .22s ease;display:flex;align-items:center;justify-content:center}.ud-toggle.checked .thumb{transform:translateY(-50%) translate(calc(var(--track-w) - var(--thumb-d) - var(--thumb-inset)));box-shadow:0 1px 2px #0000002e,0 2px 6px #0000001a,0 0 0 4px var(--toggle-glow)}.thumb-core{width:4px;height:4px;border-radius:50%;background:#0000001a;transition:opacity .2s ease,transform .3s var(--toggle-spring)}:host(.size-sm) .thumb-core{display:none}.ud-toggle.checked .thumb-core{background:#1b25352e;transform:scale(1.4)}.toggle-label{font-family:var(--toggle-font);font-size:.875rem;font-weight:500;color:var(--toggle-label-color);line-height:1;white-space:nowrap}:host(.size-sm) .toggle-label{font-size:.8rem}:host(.size-lg) .toggle-label{font-size:.95rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
2345
+ ], ngImport: i0, template: "<button\n type=\"button\"\n class=\"ud-toggle\"\n [class.checked]=\"checked\"\n [class.disabled]=\"isDisabled\"\n [class.label-left]=\"labelPosition === 'left'\"\n role=\"switch\"\n [attr.aria-checked]=\"checked\"\n [attr.aria-label]=\"ariaLabel || label\"\n [disabled]=\"isDisabled || null\"\n (click)=\"toggle()\">\n @if (label && labelPosition === 'left') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n <span class=\"track\" aria-hidden=\"true\">\n <span class=\"thumb\">\n <span class=\"thumb-core\"></span>\n </span>\n </span>\n @if (label && labelPosition === 'right') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n</button>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500&display=swap\";:host{display:inline-flex;align-items:center;--toggle-track-off: #d2d6de;--toggle-track-on: #1b2535;--toggle-thumb: #ffffff;--toggle-glow: rgba(27, 37, 53, .14);--toggle-label-color: #4a5568;--toggle-font: \"DM Sans\", system-ui, sans-serif;--toggle-duration: .3s;--toggle-spring: cubic-bezier(.34, 1.56, .64, 1)}:host(.size-sm){--track-w: 28px;--track-h: 16px;--thumb-d: 12px;--thumb-inset: 2px}:host(.size-md){--track-w: 44px;--track-h: 24px;--thumb-d: 18px;--thumb-inset: 3px}:host(.size-lg){--track-w: 56px;--track-h: 32px;--thumb-d: 24px;--thumb-inset: 4px}.ud-toggle{display:inline-flex;align-items:center;gap:.6rem;background:none;border:none;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;outline:none}.ud-toggle:focus-visible .track{outline:2px solid var(--toggle-track-on);outline-offset:2px}.ud-toggle.disabled{opacity:.38;cursor:not-allowed;pointer-events:none}.track{position:relative;display:block;width:var(--track-w);height:var(--track-h);border-radius:999px;background:var(--toggle-track-off);box-shadow:inset 0 1px 3px #0000002e,inset 0 0 0 1px #0000000f;transition:background var(--toggle-duration) ease;flex-shrink:0}.ud-toggle.checked .track{background:var(--toggle-track-on);box-shadow:inset 0 1px 3px #0000004d,inset 0 0 0 1px #00000026}.thumb{position:absolute;top:50%;left:0;width:var(--thumb-d);height:var(--thumb-d);border-radius:50%;background:var(--toggle-thumb);transform:translateY(-50%) translate(var(--thumb-inset));box-shadow:0 1px 2px #00000038,0 2px 6px #00000024;transition:transform var(--toggle-duration) var(--toggle-spring),box-shadow .22s ease;display:flex;align-items:center;justify-content:center}.ud-toggle.checked .thumb{transform:translateY(-50%) translate(calc(var(--track-w) - var(--thumb-d) - var(--thumb-inset)));box-shadow:0 1px 2px #0000002e,0 2px 6px #0000001a,0 0 0 4px var(--toggle-glow)}.thumb-core{width:4px;height:4px;border-radius:50%;background:#0000001a;transition:opacity .2s ease,transform .3s var(--toggle-spring)}:host(.size-sm) .thumb-core{display:none}.ud-toggle.checked .thumb-core{background:#1b25352e;transform:scale(1.4)}.toggle-label{font-family:var(--toggle-font);font-size:.875rem;font-weight:500;color:var(--toggle-label-color);line-height:1;white-space:nowrap}:host(.size-sm) .toggle-label{font-size:.8rem}:host(.size-lg) .toggle-label{font-size:.95rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], viewProviders: [
2346
+ {
2347
+ provide: ControlContainer,
2348
+ useFactory: () => inject(ControlContainer, { optional: true, skipSelf: true }),
2349
+ },
2350
+ ] });
2321
2351
  }
2322
2352
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: ToggleComponent, decorators: [{
2323
2353
  type: Component,
@@ -2327,8 +2357,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImpo
2327
2357
  useExisting: forwardRef(() => ToggleComponent),
2328
2358
  multi: true,
2329
2359
  },
2360
+ ], viewProviders: [
2361
+ {
2362
+ provide: ControlContainer,
2363
+ useFactory: () => inject(ControlContainer, { optional: true, skipSelf: true }),
2364
+ },
2330
2365
  ], template: "<button\n type=\"button\"\n class=\"ud-toggle\"\n [class.checked]=\"checked\"\n [class.disabled]=\"isDisabled\"\n [class.label-left]=\"labelPosition === 'left'\"\n role=\"switch\"\n [attr.aria-checked]=\"checked\"\n [attr.aria-label]=\"ariaLabel || label\"\n [disabled]=\"isDisabled || null\"\n (click)=\"toggle()\">\n @if (label && labelPosition === 'left') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n <span class=\"track\" aria-hidden=\"true\">\n <span class=\"thumb\">\n <span class=\"thumb-core\"></span>\n </span>\n </span>\n @if (label && labelPosition === 'right') {\n <span class=\"toggle-label\">{{ label }}</span>\n }\n</button>\n", styles: ["@import\"https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500&display=swap\";:host{display:inline-flex;align-items:center;--toggle-track-off: #d2d6de;--toggle-track-on: #1b2535;--toggle-thumb: #ffffff;--toggle-glow: rgba(27, 37, 53, .14);--toggle-label-color: #4a5568;--toggle-font: \"DM Sans\", system-ui, sans-serif;--toggle-duration: .3s;--toggle-spring: cubic-bezier(.34, 1.56, .64, 1)}:host(.size-sm){--track-w: 28px;--track-h: 16px;--thumb-d: 12px;--thumb-inset: 2px}:host(.size-md){--track-w: 44px;--track-h: 24px;--thumb-d: 18px;--thumb-inset: 3px}:host(.size-lg){--track-w: 56px;--track-h: 32px;--thumb-d: 24px;--thumb-inset: 4px}.ud-toggle{display:inline-flex;align-items:center;gap:.6rem;background:none;border:none;padding:0;cursor:pointer;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none;outline:none}.ud-toggle:focus-visible .track{outline:2px solid var(--toggle-track-on);outline-offset:2px}.ud-toggle.disabled{opacity:.38;cursor:not-allowed;pointer-events:none}.track{position:relative;display:block;width:var(--track-w);height:var(--track-h);border-radius:999px;background:var(--toggle-track-off);box-shadow:inset 0 1px 3px #0000002e,inset 0 0 0 1px #0000000f;transition:background var(--toggle-duration) ease;flex-shrink:0}.ud-toggle.checked .track{background:var(--toggle-track-on);box-shadow:inset 0 1px 3px #0000004d,inset 0 0 0 1px #00000026}.thumb{position:absolute;top:50%;left:0;width:var(--thumb-d);height:var(--thumb-d);border-radius:50%;background:var(--toggle-thumb);transform:translateY(-50%) translate(var(--thumb-inset));box-shadow:0 1px 2px #00000038,0 2px 6px #00000024;transition:transform var(--toggle-duration) var(--toggle-spring),box-shadow .22s ease;display:flex;align-items:center;justify-content:center}.ud-toggle.checked .thumb{transform:translateY(-50%) translate(calc(var(--track-w) - var(--thumb-d) - var(--thumb-inset)));box-shadow:0 1px 2px #0000002e,0 2px 6px #0000001a,0 0 0 4px var(--toggle-glow)}.thumb-core{width:4px;height:4px;border-radius:50%;background:#0000001a;transition:opacity .2s ease,transform .3s var(--toggle-spring)}:host(.size-sm) .thumb-core{display:none}.ud-toggle.checked .thumb-core{background:#1b25352e;transform:scale(1.4)}.toggle-label{font-family:var(--toggle-font);font-size:.875rem;font-weight:500;color:var(--toggle-label-color);line-height:1;white-space:nowrap}:host(.size-sm) .toggle-label{font-size:.8rem}:host(.size-lg) .toggle-label{font-size:.95rem}\n"] }]
2331
- }], propDecorators: { size: [{
2366
+ }], propDecorators: { controlName: [{
2367
+ type: Input
2368
+ }], size: [{
2332
2369
  type: Input
2333
2370
  }], label: [{
2334
2371
  type: Input