@lifecorner/angular-ui-kit 3.14.0 → 3.16.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/README.md +2 -1
- package/fesm2022/lifecorner-angular-ui-kit-app-shell.mjs +36 -2
- package/fesm2022/lifecorner-angular-ui-kit-app-shell.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-avatar-group.mjs +2 -1
- package/fesm2022/lifecorner-angular-ui-kit-avatar-group.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-avatar.mjs +23 -5
- package/fesm2022/lifecorner-angular-ui-kit-avatar.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs +39 -6
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-choice-prompt.mjs +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-choice-prompt.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-empty-state.mjs +42 -5
- package/fesm2022/lifecorner-angular-ui-kit-empty-state.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs +21 -3
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-icons.mjs +26 -2
- package/fesm2022/lifecorner-angular-ui-kit-icons.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs +10 -1
- package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs +30 -6
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-money.mjs +250 -0
- package/fesm2022/lifecorner-angular-ui-kit-money.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs +22 -2
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-page-header.mjs +20 -3
- package/fesm2022/lifecorner-angular-ui-kit-page-header.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-switch.mjs +21 -4
- package/fesm2022/lifecorner-angular-ui-kit-switch.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +72 -7
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit.mjs +1 -0
- package/package.json +5 -1
- package/src/styles/theme-contrast.spec.ts +74 -0
- package/types/lifecorner-angular-ui-kit-app-shell.d.ts +56 -0
- package/types/lifecorner-angular-ui-kit-avatar.d.ts +24 -0
- package/types/lifecorner-angular-ui-kit-button.d.ts +31 -0
- package/types/lifecorner-angular-ui-kit-empty-state.d.ts +38 -0
- package/types/lifecorner-angular-ui-kit-header.d.ts +15 -2
- package/types/lifecorner-angular-ui-kit-icon.d.ts +2 -1
- package/types/lifecorner-angular-ui-kit-icons.d.ts +5 -1
- package/types/lifecorner-angular-ui-kit-list.d.ts +38 -0
- package/types/lifecorner-angular-ui-kit-money.d.ts +150 -0
- package/types/lifecorner-angular-ui-kit-next-step-card.d.ts +26 -0
- package/types/lifecorner-angular-ui-kit-page-header.d.ts +20 -0
- package/types/lifecorner-angular-ui-kit-sidenav-placeholder.d.ts +4 -2
- package/types/lifecorner-angular-ui-kit-sidenav.d.ts +5 -2
- package/types/lifecorner-angular-ui-kit-switch.d.ts +19 -0
- package/types/lifecorner-angular-ui-kit-table.d.ts +42 -1
- package/types/lifecorner-angular-ui-kit.d.ts +1 -0
|
@@ -3,6 +3,7 @@ import { ChangeDetectionStrategy, Component, ViewChild, ViewEncapsulation, compu
|
|
|
3
3
|
import { NgClass } from "@angular/common";
|
|
4
4
|
var ButtonComponent = class ButtonComponent {
|
|
5
5
|
variant = input("primary", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
6
|
+
tone = input("neutral", ...ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []);
|
|
6
7
|
size = input("md", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
|
|
7
8
|
disabled = input(false, ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
|
|
8
9
|
loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
|
|
@@ -60,6 +61,13 @@ var ButtonComponent = class ButtonComponent {
|
|
|
60
61
|
isRequired: false,
|
|
61
62
|
transformFunction: null
|
|
62
63
|
},
|
|
64
|
+
tone: {
|
|
65
|
+
classPropertyName: "tone",
|
|
66
|
+
publicName: "tone",
|
|
67
|
+
isSignal: true,
|
|
68
|
+
isRequired: false,
|
|
69
|
+
transformFunction: null
|
|
70
|
+
},
|
|
63
71
|
size: {
|
|
64
72
|
classPropertyName: "size",
|
|
65
73
|
publicName: "size",
|
|
@@ -150,8 +158,8 @@ var ButtonComponent = class ButtonComponent {
|
|
|
150
158
|
descendants: true
|
|
151
159
|
}],
|
|
152
160
|
ngImport: i0,
|
|
153
|
-
template: "<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush()\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n",
|
|
154
|
-
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"],
|
|
161
|
+
template: "<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush(),\n 'btn-tone-primary': variant() === 'outline' && tone() === 'primary'\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n",
|
|
162
|
+
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-outline.btn-tone-primary{border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:hover:not(:disabled){background-color:var(--color-surface-selected);border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:active:not(:disabled){background-color:var(--color-primary-200);filter:none}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"],
|
|
155
163
|
dependencies: [{
|
|
156
164
|
kind: "directive",
|
|
157
165
|
type: NgClass,
|
|
@@ -175,8 +183,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
175
183
|
imports: [NgClass],
|
|
176
184
|
encapsulation: ViewEncapsulation.None,
|
|
177
185
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
178
|
-
template: "<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush()\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n",
|
|
179
|
-
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"]
|
|
186
|
+
template: "<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush(),\n 'btn-tone-primary': variant() === 'outline' && tone() === 'primary'\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n",
|
|
187
|
+
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-outline.btn-tone-primary{border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:hover:not(:disabled){background-color:var(--color-surface-selected);border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:active:not(:disabled){background-color:var(--color-primary-200);filter:none}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"]
|
|
180
188
|
}]
|
|
181
189
|
}],
|
|
182
190
|
propDecorators: {
|
|
@@ -188,6 +196,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
188
196
|
required: false
|
|
189
197
|
}]
|
|
190
198
|
}],
|
|
199
|
+
tone: [{
|
|
200
|
+
type: i0.Input,
|
|
201
|
+
args: [{
|
|
202
|
+
isSignal: true,
|
|
203
|
+
alias: "tone",
|
|
204
|
+
required: false
|
|
205
|
+
}]
|
|
206
|
+
}],
|
|
191
207
|
size: [{
|
|
192
208
|
type: i0.Input,
|
|
193
209
|
args: [{
|
|
@@ -296,6 +312,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
296
312
|
});
|
|
297
313
|
var ButtonLinkComponent = class ButtonLinkComponent {
|
|
298
314
|
variant = input("primary", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
|
|
315
|
+
tone = input("neutral", ...ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []);
|
|
299
316
|
size = input("md", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
|
|
300
317
|
fullWidth = input(false, ...ngDevMode ? [{ debugName: "fullWidth" }] : /* istanbul ignore next */ []);
|
|
301
318
|
iconOnly = input(false, ...ngDevMode ? [{ debugName: "iconOnly" }] : /* istanbul ignore next */ []);
|
|
@@ -311,6 +328,7 @@ var ButtonLinkComponent = class ButtonLinkComponent {
|
|
|
311
328
|
if (this.fullWidth()) classes.push("btn-full-width");
|
|
312
329
|
if (this.inline()) classes.push("btn-inline");
|
|
313
330
|
if (this.flush()) classes.push("btn-flush");
|
|
331
|
+
if (this.variant() === "outline" && this.tone() === "primary") classes.push("btn-tone-primary");
|
|
314
332
|
return classes.join(" ");
|
|
315
333
|
}, ...ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []);
|
|
316
334
|
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
@@ -335,6 +353,13 @@ var ButtonLinkComponent = class ButtonLinkComponent {
|
|
|
335
353
|
isRequired: false,
|
|
336
354
|
transformFunction: null
|
|
337
355
|
},
|
|
356
|
+
tone: {
|
|
357
|
+
classPropertyName: "tone",
|
|
358
|
+
publicName: "tone",
|
|
359
|
+
isSignal: true,
|
|
360
|
+
isRequired: false,
|
|
361
|
+
transformFunction: null
|
|
362
|
+
},
|
|
338
363
|
size: {
|
|
339
364
|
classPropertyName: "size",
|
|
340
365
|
publicName: "size",
|
|
@@ -377,7 +402,7 @@ var ButtonLinkComponent = class ButtonLinkComponent {
|
|
|
377
402
|
select="[slot='icon-after']"
|
|
378
403
|
/>`,
|
|
379
404
|
isInline: true,
|
|
380
|
-
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"],
|
|
405
|
+
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-outline.btn-tone-primary{border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:hover:not(:disabled){background-color:var(--color-surface-selected);border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:active:not(:disabled){background-color:var(--color-primary-200);filter:none}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"],
|
|
381
406
|
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
382
407
|
encapsulation: i0.ViewEncapsulation.None
|
|
383
408
|
});
|
|
@@ -397,7 +422,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
397
422
|
encapsulation: ViewEncapsulation.None,
|
|
398
423
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
399
424
|
host: { "[class]": "hostClasses()" },
|
|
400
|
-
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"]
|
|
425
|
+
styles: [".btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--spacing-2);font-family:var(--font-family-sans);font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);border:1px solid transparent;border-radius:var(--border-radius-full);cursor:pointer;transition-property:color,background-color,border-color,box-shadow;transition-duration:var(--animation-duration-base);transition-timing-function:var(--animation-timing-ease);white-space:normal;text-align:center;overflow-wrap:var(--lc-btn-overflow-wrap, break-word);-webkit-user-select:none;user-select:none}.btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:auto}a.btn{text-decoration:none}.btn-primary{background-color:var(--color-primary-fill);color:var(--color-on-primary)}.btn-primary:hover:not(:disabled){background-color:var(--color-primary-fill-hover)}.btn-primary:active:not(:disabled){background-color:var(--color-primary-fill-active)}.btn-secondary{background-color:var(--color-secondary-fill);color:var(--color-on-secondary)}.btn-secondary:hover:not(:disabled){background-color:var(--color-secondary-fill-hover)}.btn-secondary:active:not(:disabled){background-color:var(--color-secondary-fill-active)}.btn-outline{background-color:#84c7d40f;border-color:var(--color-border-strong);color:var(--color-text-primary)}.btn-outline:hover:not(:disabled){background-color:var(--color-primary-600);border-color:var(--color-primary-500);color:var(--color-neutral-white)}.btn-outline:active:not(:disabled){filter:brightness(.92)}.btn-outline.btn-tone-primary{border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:hover:not(:disabled){background-color:var(--color-surface-selected);border-color:var(--color-primary-600);color:var(--color-primary-700)}.btn-outline.btn-tone-primary:active:not(:disabled){background-color:var(--color-primary-200);filter:none}.btn-ghost{background-color:var(--lc-button-ghost-bg, transparent);color:var(--lc-button-ghost-fg, var(--color-text-secondary))}.btn-ghost:hover:not(:disabled){background-color:var(--lc-button-ghost-hover-bg, var(--color-surface-hover));color:var(--lc-button-ghost-hover-fg, var(--lc-button-ghost-fg, var(--color-text-primary)))}.btn-ghost:active:not(:disabled){background-color:var(--lc-button-ghost-active-bg, var(--color-surface-selected))}.btn-link{background-color:transparent;color:var(--lc-button-link-fg, var(--color-primary-600));padding:0;border:none}.btn-link:hover:not(:disabled){color:var(--lc-button-link-hover-fg, var(--color-primary-700));text-decoration:underline}.btn-link:active:not(:disabled){color:var(--lc-button-link-active-fg, var(--color-primary-800))}.btn-danger{background-color:var(--color-error-fill);color:var(--color-on-error)}.btn-danger:hover:not(:disabled){background-color:var(--color-error-fill-hover)}.btn-danger:active:not(:disabled){background-color:var(--color-error-fill-active)}.btn-warning{background-color:#e1a040;color:var(--color-on-warning)}.btn-warning:hover:not(:disabled){filter:brightness(1.05)}.btn-warning:active:not(:disabled){filter:brightness(.94)}.btn-info{background-color:#3b6588;color:var(--color-neutral-white)}.btn-info:hover:not(:disabled){background-color:#27445c}.btn-info:active:not(:disabled){background-color:#27445c;filter:brightness(.85)}.btn-inverse{background-color:var(--color-neutral-white);color:var(--lc-button-inverse-fg, #0d353d)}.btn-inverse:hover:not(:disabled){background-color:#f0f8fa}.btn-inverse:active:not(:disabled){background-color:#e0f1f4}.btn-inverse:focus-visible{outline-color:var(--color-neutral-white)}@media(forced-colors:active){.btn-inverse{border-color:ButtonText}a.btn-inverse{border-color:LinkText}.btn-inverse:focus-visible{outline-color:Highlight}}.btn-xs{padding:var(--spacing-1) var(--spacing-2);font-size:var(--font-size-xs)}.btn-sm{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm)}.btn-md{padding:var(--spacing-2-5) var(--spacing-4);font-size:var(--font-size-base)}.btn-lg{padding:var(--spacing-3) var(--spacing-6);font-size:var(--font-size-lg)}.btn-icon-only.btn-xs{padding:var(--spacing-1);width:calc(var(--spacing-1) * 2 + 1em);height:calc(var(--spacing-1) * 2 + 1em)}.btn-icon-only.btn-sm{padding:var(--spacing-2);width:calc(var(--spacing-2) * 2 + 1em);height:calc(var(--spacing-2) * 2 + 1em)}.btn-icon-only.btn-md{padding:var(--spacing-2-5);width:calc(var(--spacing-2-5) * 2 + 1em);height:calc(var(--spacing-2-5) * 2 + 1em)}.btn-icon-only.btn-lg{padding:var(--spacing-3);width:calc(var(--spacing-3) * 2 + 1.2em);height:calc(var(--spacing-3) * 2 + 1.2em)}.btn-full-width{width:100%}.btn-inline{display:inline;padding:0;font-size:inherit;font-weight:inherit;line-height:inherit;vertical-align:baseline;white-space:normal;text-align:inherit;border-radius:var(--border-radius-sm)}.btn.btn-inline{text-decoration:var(--lc-btn-inline-text-decoration, underline);text-decoration-thickness:max(1px,.0625em);text-underline-offset:.15em;transition-property:color,background-color,border-color,box-shadow}.btn.btn-inline:hover:not(:disabled){text-decoration-thickness:max(2px,.125em)}.btn-link.btn-flush:not(.btn-icon-only,.btn-inline){padding-inline:0;min-width:var(--size-min-touch-width, 2.75rem);min-height:var(--size-min-touch-height, 2.75rem);justify-content:var(--lc-btn-flush-align, start);text-align:var(--lc-btn-flush-align, start);border-radius:var(--border-radius-sm)}.loading-spinner{display:inline-block;width:1em;height:1em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.icon-before,.icon-after{display:inline-flex;align-items:center}\n"]
|
|
401
426
|
}]
|
|
402
427
|
}],
|
|
403
428
|
propDecorators: {
|
|
@@ -409,6 +434,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
409
434
|
required: false
|
|
410
435
|
}]
|
|
411
436
|
}],
|
|
437
|
+
tone: [{
|
|
438
|
+
type: i0.Input,
|
|
439
|
+
args: [{
|
|
440
|
+
isSignal: true,
|
|
441
|
+
alias: "tone",
|
|
442
|
+
required: false
|
|
443
|
+
}]
|
|
444
|
+
}],
|
|
412
445
|
size: [{
|
|
413
446
|
type: i0.Input,
|
|
414
447
|
args: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-button.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/button/button.component.ts","../../../../libs/angular-ui-kit/src/lib/button/button.component.html","../../../../libs/angular-ui-kit/src/lib/button/button-link.component.ts"],"sourcesContent":["import {\n Component,\n input,\n output,\n computed,\n ViewChild,\n ElementRef,\n ChangeDetectionStrategy,\n ViewEncapsulation,\n} from '@angular/core';\nimport { NgClass } from '@angular/common';\n\nexport type ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'outline'\n | 'ghost'\n | 'link'\n | 'danger'\n | 'warning'\n | 'info'\n | 'inverse';\nexport type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';\nexport type ButtonType = 'button' | 'submit' | 'reset';\n\n@Component({\n selector: 'lc-button',\n standalone: true,\n imports: [NgClass],\n templateUrl: './button.component.html',\n styleUrl: './button.component.scss',\n encapsulation: ViewEncapsulation.None, // Required for dynamic variant class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Button component for user actions and form submissions.\n *\n * Features:\n * - Multiple variants (primary, secondary, outline, ghost, link, danger,\n * warning, info, inverse)\n * - Size options (xs, sm, md, lg)\n * - Loading state with spinner\n * - Icon-only mode\n * - Full-width layout option\n * - Keyboard and focus handling\n * - Accessible with ARIA attributes\n *\n * CSS hook `--lc-btn-overflow-wrap` (`break-word | anywhere`, default\n * `break-word`): `anywhere` lets a single word wider than the button's line\n * break inside the word, so the button stays inside its container (WCAG 1.4.10\n * at 320 px or 200 % text). Set it on the button, the `lc-button` host or an\n * ancestor that is a wrapping row or a column. In a non-wrapping row it lets a\n * one-word button shrink with its neighbours, which is why the default stays\n * `break-word`. The kit sets it in `lc-footer`'s link row, the page-header\n * actions, the next-step-card's narrow actions and the narrow alert's actions.\n *\n * @example\n * ```html\n * <lc-button variant=\"primary\" size=\"md\">Save</lc-button>\n * ```\n */\nexport class ButtonComponent {\n /**\n * Visual variant. `inverse` is a white pill with dark ink and a white focus\n * ring for dark, coloured or image backgrounds that don't follow the theme,\n * such as the default `lc-hero` bands (primary, neutral, info, accent-purple,\n * accent-violet). It looks the same in both themes. Not for light backgrounds\n * or `variant=\"light\"` heroes. CSS hook `--lc-button-inverse-fg` (default\n * `#0d353d`) sets its ink; keep 4.5:1 on white.\n * @default 'primary'\n */\n readonly variant = input<ButtonVariant>('primary');\n readonly size = input<ButtonSize>('md');\n readonly disabled = input(false);\n readonly loading = input(false);\n readonly iconOnly = input(false);\n readonly fullWidth = input(false);\n readonly ariaLabel = input('');\n readonly type = input<ButtonType>('button');\n\n /**\n * Native tooltip (title attribute) on the button.\n */\n readonly title = input('');\n\n /**\n * Reason shown as tooltip while the button is disabled (or loading).\n * Takes precedence over `title` in that state. The tooltip also appears\n * over the disabled button — the component guarantees the inner button\n * never gets `pointer-events: none`.\n */\n readonly disabledReason = input('');\n\n /**\n * Render as an inline text button that inherits font size, weight and\n * line-height from the surrounding text (for links inside copy, clickable\n * row titles, linked counters). Pair with `variant=\"link\"`.\n * @default false\n */\n readonly inline = input(false);\n\n /**\n * Drop the inline padding so a `variant=\"link\"` button sits flush with the\n * content edge: the label starts at the edge, and the button keeps its height\n * and a 44 × 44 px minimum target. At the end edge of a row, set the CSS\n * hook `--lc-btn-flush-align: end` (default `start`) on the host or an\n * ancestor: every line of the label then ends at the edge. Ignored on other\n * variants and with `iconOnly` (3.9, AS-26).\n * @default false\n */\n readonly flush = input(false);\n\n readonly clicked = output<void>();\n readonly focused = output<void>();\n readonly blurred = output<void>();\n\n @ViewChild('buttonElement') buttonElement!: ElementRef<HTMLButtonElement>;\n\n readonly isDisabled = computed(() => this.disabled() || this.loading());\n\n /**\n * Tooltip actually applied to the button: `disabledReason` while disabled,\n * `title` otherwise.\n */\n readonly effectiveTitle = computed(() => {\n if (this.isDisabled() && this.disabledReason()) {\n return this.disabledReason();\n }\n return this.title() || null;\n });\n\n handleClick(): void {\n if (!this.isDisabled()) {\n this.clicked.emit();\n }\n }\n\n handleFocus(): void {\n this.focused.emit();\n }\n\n handleBlur(): void {\n this.blurred.emit();\n }\n\n focus(): void {\n this.buttonElement?.nativeElement.focus();\n }\n\n blur(): void {\n this.buttonElement?.nativeElement.blur();\n }\n}\n","<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush()\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\nimport type { ButtonSize, ButtonVariant } from './button.component';\n\n/**\n * `lc-button` styling on a native link: `<a lcButton href=\"…\">`.\n *\n * Use it for navigation that looks like a button — calls to action, \"read\n * more\" links, a language switch. The host *is* the anchor, so every native\n * link attribute (`href`, `hreflang`, `lang`, `rel`, `target`, `download`,\n * `title`, `aria-*`) passes through untouched, and the component adds no event\n * listeners: after server-side rendering or prerendering the markup is a plain\n * `<a class=\"btn btn-primary btn-md\" href=\"…\">` that works without JavaScript.\n * `routerLink` can sit on the same anchor for in-app navigation.\n *\n * Same variants, sizes and modifiers as `lc-button` (it shares its stylesheet).\n * Use `size=\"lg\"` (48.5 px) where the link must meet the 44 px touch target. A link\n * cannot be disabled or busy — render plain text or an `lc-button` for those\n * states. An `iconOnly` link needs an `aria-label`.\n *\n * CSS hook `--lc-btn-overflow-wrap` (`break-word | anywhere`, default\n * `break-word`): `anywhere` lets a single word wider than the button's line\n * break inside the word, so the button stays inside its container (WCAG 1.4.10\n * at 320 px or 200 % text). Set it on the button, the `lc-button` host or an\n * ancestor that is a wrapping row or a column. In a non-wrapping row it lets a\n * one-word button shrink with its neighbours, which is why the default stays\n * `break-word`. The kit sets it in `lc-footer`'s link row, the page-header\n * actions, the next-step-card's narrow actions and the narrow alert's actions.\n *\n * @example\n * ```html\n * <a lcButton variant=\"primary\" size=\"lg\" href=\"/de/neuigkeiten\">Schau uns beim Bauen zu</a>\n * <a lcButton variant=\"ghost\" href=\"/en/security\" hreflang=\"en\" lang=\"en\">English</a>\n * <a lcButton variant=\"outline\" href=\"https://www.linkedin.com/in/…\" rel=\"me\">\n * <lc-icon slot=\"icon-before\" name=\"external-link\" size=\"sm\" [decorative]=\"true\" />\n * LinkedIn\n * </a>\n * ```\n */\n@Component({\n // An attribute selector on purpose: the anchor must stay the element in the\n // DOM so native link behaviour and attributes are untouched.\n selector: 'a[lcButton]',\n template: `<ng-content select=\"[slot='icon-before']\" /><ng-content /><ng-content\n select=\"[slot='icon-after']\"\n />`,\n // The same stylesheet as lc-button: identical style text is registered once,\n // whichever of the two renders first.\n styleUrl: './button.component.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n },\n})\nexport class ButtonLinkComponent {\n /**\n * Visual variant. `inverse` is a white pill with dark ink and a white focus\n * ring for dark, coloured or image backgrounds that don't follow the theme,\n * such as the default `lc-hero` bands (primary, neutral, info, accent-purple,\n * accent-violet). It looks the same in both themes. Not for light backgrounds\n * or `variant=\"light\"` heroes. CSS hook `--lc-button-inverse-fg` (default\n * `#0d353d`) sets its ink; keep 4.5:1 on white.\n * @default 'primary'\n */\n readonly variant = input<ButtonVariant>('primary');\n /** Size, as on `lc-button`. `lg` (48.5 px high) meets the 44 px touch target. */\n readonly size = input<ButtonSize>('md');\n /** Stretch the link to the full width of its container. */\n readonly fullWidth = input(false);\n /** Square icon-only link. Give the anchor an `aria-label`. */\n readonly iconOnly = input(false);\n /**\n * Flow with the surrounding text instead of forming a pill (inherits font\n * size, weight and line-height). Pair with `variant=\"link\"`.\n */\n readonly inline = input(false);\n /**\n * Drop the inline padding so a `variant=\"link\"` link sits flush with the\n * content edge: the label starts at the edge, and the link keeps its height\n * and a 44 × 44 px minimum target. At the end edge of a row, set the CSS\n * hook `--lc-btn-flush-align: end` (default `start`) on the link or an\n * ancestor: every line of the label then ends at the edge. Ignored on other\n * variants and with `iconOnly` (3.9, AS-26).\n * @default false\n */\n readonly flush = input(false);\n\n /** Classes on the anchor; merged with the consumer's own `class`. */\n protected readonly hostClasses = computed(() => {\n const classes = ['btn', `btn-${this.variant()}`, `btn-${this.size()}`];\n if (this.iconOnly()) classes.push('btn-icon-only');\n if (this.fullWidth()) classes.push('btn-full-width');\n if (this.inline()) classes.push('btn-inline');\n if (this.flush()) classes.push('btn-flush');\n return classes.join(' ');\n });\n}\n"],"mappings":";;;AA6DA,IAAa,kBAAb,MAAa,gBAAe;CAUjB,UAAU,MAAqB,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CACzC,OAAO,MAAkB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAC9B,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACvB,UAAU,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACvB,YAAY,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACxB,YAAY,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACrB,OAAO,MAAkB,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAKlC,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAQjB,iBAAiB,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAQ1B,SAAS,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAWrB,QAAQ,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAEpB,UAAU,OAAM;CAChB,UAAU,OAAM;CAChB,UAAU,OAAM;CAEG;CAEnB,aAAa,eAAe,KAAK,SAAQ,KAAM,KAAK,QAAO,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAM9D,iBAAiB,eAAc;EACtC,IAAI,KAAK,WAAU,KAAM,KAAK,eAAc,GAC1C,OAAO,KAAK,eAAc;EAE5B,OAAO,KAAK,MAAK,KAAM;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,cAAW;EACT,IAAI,CAAC,KAAK,WAAU,GAClB,KAAK,QAAQ,KAAI;CAErB;CAEA,cAAW;EACT,KAAK,QAAQ,KAAI;CACnB;CAEA,aAAU;EACR,KAAK,QAAQ,KAAI;CACnB;CAEA,QAAK;EACH,KAAK,eAAe,cAAc,MAAK;CACzC;CAEA,OAAI;EACF,KAAK,eAAe,cAAc,KAAI;CACxC;CA1FW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAe,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAf,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAe,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,gBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA;GAAA,SAAA;GAAA,SAAA;GAAA,SAAA;EAAA;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,eAAA;GAAA,aAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UC7D5B;EA2CA,QAAA,CAAA,8wKAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MDfY;GAAO,UAAA;GAAA,QAAA,CAAA,SAAA,SAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AAiCN,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAe,YAAA,CAAA;EApC3B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAW,YACT;GAAI,SACP,CAAC,OAAO;GAAC,eAGH,kBAAkB;GAAI,iBACpB,wBAAwB;GAAM,UAAA;GAAA,QAAA,CAAA,8wKAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoF9C,MAAA;GAAU,MAAA,CAAA,eAAe;;;;AExD5B,IAAa,sBAAb,MAAa,oBAAmB;CAUrB,UAAU,MAAqB,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAEzC,OAAO,MAAkB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAE9B,YAAY,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAExB,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAKvB,SAAS,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAUrB,QAAQ,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAGV,cAAc,eAAc;EAC7C,MAAM,UAAU;GAAC;GAAO,OAAO,KAAK,QAAO;GAAM,OAAO,KAAK,KAAI;EAAI;EACrE,IAAI,KAAK,SAAQ,GAAI,QAAQ,KAAK,eAAe;EACjD,IAAI,KAAK,UAAS,GAAI,QAAQ,KAAK,gBAAgB;EACnD,IAAI,KAAK,OAAM,GAAI,QAAQ,KAAK,YAAY;EAC5C,IAAI,KAAK,MAAK,GAAI,QAAQ,KAAK,WAAW;EAC1C,OAAO,QAAQ,KAAK,GAAG;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAzCS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAmB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAnB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAmB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA,EAAA,YAAA,EAAA,SAAA,gBAAA,EAAA;EAAA,UAAA;EAAA,UAZpB;;;EAEL,UAAA;EAAA,QAAA,CAAA,8wKAAA;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AAUM,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAmB,YAAA,CAAA;EAhB/B,MAAA;EAGW,MAAA,CAAA;GAAA,UAAA;GAAa,UACb;;;GAEL,eAIU,kBAAkB;GAAI,iBACpB,wBAAwB;GAAM,MACzC,EACJ,WAAW,gBACZ;GAAA,QAAA,CAAA,8wKAAA;EAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-button.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/button/button.component.ts","../../../../libs/angular-ui-kit/src/lib/button/button.component.html","../../../../libs/angular-ui-kit/src/lib/button/button-link.component.ts"],"sourcesContent":["import {\n Component,\n input,\n output,\n computed,\n ViewChild,\n ElementRef,\n ChangeDetectionStrategy,\n ViewEncapsulation,\n} from '@angular/core';\nimport { NgClass } from '@angular/common';\n\nexport type ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'outline'\n | 'ghost'\n | 'link'\n | 'danger'\n | 'warning'\n | 'info'\n | 'inverse';\nexport type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';\nexport type ButtonType = 'button' | 'submit' | 'reset';\n\n/**\n * Colour tone of `variant=\"outline\"` (3.15). `primary`: text and border in the\n * primary colour. Other variants ignore it.\n */\nexport type ButtonTone = 'neutral' | 'primary';\n\n@Component({\n selector: 'lc-button',\n standalone: true,\n imports: [NgClass],\n templateUrl: './button.component.html',\n styleUrl: './button.component.scss',\n encapsulation: ViewEncapsulation.None, // Required for dynamic variant class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Button component for user actions and form submissions.\n *\n * Features:\n * - Multiple variants (primary, secondary, outline, ghost, link, danger,\n * warning, info, inverse)\n * - Size options (xs, sm, md, lg)\n * - Loading state with spinner\n * - Icon-only mode\n * - Full-width layout option\n * - Keyboard and focus handling\n * - Accessible with ARIA attributes\n *\n * CSS hook `--lc-btn-overflow-wrap` (`break-word | anywhere`, default\n * `break-word`): `anywhere` lets a single word wider than the button's line\n * break inside the word, so the button stays inside its container (WCAG 1.4.10\n * at 320 px or 200 % text). Set it on the button, the `lc-button` host or an\n * ancestor that is a wrapping row or a column. In a non-wrapping row it lets a\n * one-word button shrink with its neighbours, which is why the default stays\n * `break-word`. The kit sets it in `lc-footer`'s link row, the page-header\n * actions, the next-step-card's narrow actions and the narrow alert's actions.\n *\n * @example\n * ```html\n * <lc-button variant=\"primary\" size=\"md\">Save</lc-button>\n * ```\n */\nexport class ButtonComponent {\n /**\n * Visual variant. `inverse` is a white pill with dark ink and a white focus\n * ring for dark, coloured or image backgrounds that don't follow the theme,\n * such as the default `lc-hero` bands (primary, neutral, info, accent-purple,\n * accent-violet). It looks the same in both themes. Not for light backgrounds\n * or `variant=\"light\"` heroes. CSS hook `--lc-button-inverse-fg` (default\n * `#0d353d`) sets its ink; keep 4.5:1 on white.\n * @default 'primary'\n */\n readonly variant = input<ButtonVariant>('primary');\n\n /**\n * Colour tone of `variant=\"outline\"`: `'primary'` sets text and border to\n * the primary colour (`--color-primary-700` / `-600`; hover\n * `--color-surface-selected`, active `--color-primary-200`). Other variants\n * ignore it.\n * @default 'neutral'\n */\n readonly tone = input<ButtonTone>('neutral');\n readonly size = input<ButtonSize>('md');\n readonly disabled = input(false);\n readonly loading = input(false);\n readonly iconOnly = input(false);\n readonly fullWidth = input(false);\n readonly ariaLabel = input('');\n readonly type = input<ButtonType>('button');\n\n /**\n * Native tooltip (title attribute) on the button.\n */\n readonly title = input('');\n\n /**\n * Reason shown as tooltip while the button is disabled (or loading).\n * Takes precedence over `title` in that state. The tooltip also appears\n * over the disabled button — the component guarantees the inner button\n * never gets `pointer-events: none`.\n */\n readonly disabledReason = input('');\n\n /**\n * Render as an inline text button that inherits font size, weight and\n * line-height from the surrounding text (for links inside copy, clickable\n * row titles, linked counters). Pair with `variant=\"link\"`.\n * @default false\n */\n readonly inline = input(false);\n\n /**\n * Drop the inline padding so a `variant=\"link\"` button sits flush with the\n * content edge: the label starts at the edge, and the button keeps its height\n * and a 44 × 44 px minimum target. At the end edge of a row, set the CSS\n * hook `--lc-btn-flush-align: end` (default `start`) on the host or an\n * ancestor: every line of the label then ends at the edge. Ignored on other\n * variants and with `iconOnly` (3.9, AS-26).\n * @default false\n */\n readonly flush = input(false);\n\n readonly clicked = output<void>();\n readonly focused = output<void>();\n readonly blurred = output<void>();\n\n @ViewChild('buttonElement') buttonElement!: ElementRef<HTMLButtonElement>;\n\n readonly isDisabled = computed(() => this.disabled() || this.loading());\n\n /**\n * Tooltip actually applied to the button: `disabledReason` while disabled,\n * `title` otherwise.\n */\n readonly effectiveTitle = computed(() => {\n if (this.isDisabled() && this.disabledReason()) {\n return this.disabledReason();\n }\n return this.title() || null;\n });\n\n handleClick(): void {\n if (!this.isDisabled()) {\n this.clicked.emit();\n }\n }\n\n handleFocus(): void {\n this.focused.emit();\n }\n\n handleBlur(): void {\n this.blurred.emit();\n }\n\n focus(): void {\n this.buttonElement?.nativeElement.focus();\n }\n\n blur(): void {\n this.buttonElement?.nativeElement.blur();\n }\n}\n","<button\n #buttonElement\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.title]=\"effectiveTitle()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : 'false'\"\n [attr.aria-busy]=\"loading() ? 'true' : 'false'\"\n [ngClass]=\"{\n 'btn': true,\n 'btn-primary': variant() === 'primary',\n 'btn-secondary': variant() === 'secondary',\n 'btn-outline': variant() === 'outline',\n 'btn-ghost': variant() === 'ghost',\n 'btn-link': variant() === 'link',\n 'btn-danger': variant() === 'danger',\n 'btn-warning': variant() === 'warning',\n 'btn-info': variant() === 'info',\n 'btn-inverse': variant() === 'inverse',\n 'btn-xs': size() === 'xs',\n 'btn-sm': size() === 'sm',\n 'btn-md': size() === 'md',\n 'btn-lg': size() === 'lg',\n 'btn-icon-only': iconOnly(),\n 'btn-full-width': fullWidth(),\n 'btn-inline': inline(),\n 'btn-flush': flush(),\n 'btn-tone-primary': variant() === 'outline' && tone() === 'primary'\n }\"\n (click)=\"handleClick()\"\n (focus)=\"handleFocus()\"\n (blur)=\"handleBlur()\"\n>\n @if (loading()) {\n <span class=\"loading-spinner\"></span>\n }\n @if (!loading()) {\n <ng-content select=\"[slot='icon-before']\" />\n }\n <ng-content></ng-content>\n @if (!loading()) {\n <ng-content select=\"[slot='icon-after']\" />\n }\n</button>\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\nimport type { ButtonSize, ButtonTone, ButtonVariant } from './button.component';\n\n/**\n * `lc-button` styling on a native link: `<a lcButton href=\"…\">`.\n *\n * Use it for navigation that looks like a button — calls to action, \"read\n * more\" links, a language switch. The host *is* the anchor, so every native\n * link attribute (`href`, `hreflang`, `lang`, `rel`, `target`, `download`,\n * `title`, `aria-*`) passes through untouched, and the component adds no event\n * listeners: after server-side rendering or prerendering the markup is a plain\n * `<a class=\"btn btn-primary btn-md\" href=\"…\">` that works without JavaScript.\n * `routerLink` can sit on the same anchor for in-app navigation.\n *\n * Same variants, sizes and modifiers as `lc-button` (it shares its stylesheet).\n * Use `size=\"lg\"` (48.5 px) where the link must meet the 44 px touch target. A link\n * cannot be disabled or busy — render plain text or an `lc-button` for those\n * states. An `iconOnly` link needs an `aria-label`.\n *\n * CSS hook `--lc-btn-overflow-wrap` (`break-word | anywhere`, default\n * `break-word`): `anywhere` lets a single word wider than the button's line\n * break inside the word, so the button stays inside its container (WCAG 1.4.10\n * at 320 px or 200 % text). Set it on the button, the `lc-button` host or an\n * ancestor that is a wrapping row or a column. In a non-wrapping row it lets a\n * one-word button shrink with its neighbours, which is why the default stays\n * `break-word`. The kit sets it in `lc-footer`'s link row, the page-header\n * actions, the next-step-card's narrow actions and the narrow alert's actions.\n *\n * @example\n * ```html\n * <a lcButton variant=\"primary\" size=\"lg\" href=\"/de/neuigkeiten\">Schau uns beim Bauen zu</a>\n * <a lcButton variant=\"ghost\" href=\"/en/security\" hreflang=\"en\" lang=\"en\">English</a>\n * <a lcButton variant=\"outline\" href=\"https://www.linkedin.com/in/…\" rel=\"me\">\n * <lc-icon slot=\"icon-before\" name=\"external-link\" size=\"sm\" [decorative]=\"true\" />\n * LinkedIn\n * </a>\n * ```\n */\n@Component({\n // An attribute selector on purpose: the anchor must stay the element in the\n // DOM so native link behaviour and attributes are untouched.\n selector: 'a[lcButton]',\n template: `<ng-content select=\"[slot='icon-before']\" /><ng-content /><ng-content\n select=\"[slot='icon-after']\"\n />`,\n // The same stylesheet as lc-button: identical style text is registered once,\n // whichever of the two renders first.\n styleUrl: './button.component.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n },\n})\nexport class ButtonLinkComponent {\n /**\n * Visual variant. `inverse` is a white pill with dark ink and a white focus\n * ring for dark, coloured or image backgrounds that don't follow the theme,\n * such as the default `lc-hero` bands (primary, neutral, info, accent-purple,\n * accent-violet). It looks the same in both themes. Not for light backgrounds\n * or `variant=\"light\"` heroes. CSS hook `--lc-button-inverse-fg` (default\n * `#0d353d`) sets its ink; keep 4.5:1 on white.\n * @default 'primary'\n */\n readonly variant = input<ButtonVariant>('primary');\n /**\n * Colour tone of `variant=\"outline\"`, as on `lc-button`: `'primary'` sets\n * text and border to the primary colour (`--color-primary-700` / `-600`;\n * hover `--color-surface-selected`, active `--color-primary-200`). Other\n * variants ignore it.\n * @default 'neutral'\n */\n readonly tone = input<ButtonTone>('neutral');\n /** Size, as on `lc-button`. `lg` (48.5 px high) meets the 44 px touch target. */\n readonly size = input<ButtonSize>('md');\n /** Stretch the link to the full width of its container. */\n readonly fullWidth = input(false);\n /** Square icon-only link. Give the anchor an `aria-label`. */\n readonly iconOnly = input(false);\n /**\n * Flow with the surrounding text instead of forming a pill (inherits font\n * size, weight and line-height). Pair with `variant=\"link\"`.\n */\n readonly inline = input(false);\n /**\n * Drop the inline padding so a `variant=\"link\"` link sits flush with the\n * content edge: the label starts at the edge, and the link keeps its height\n * and a 44 × 44 px minimum target. At the end edge of a row, set the CSS\n * hook `--lc-btn-flush-align: end` (default `start`) on the link or an\n * ancestor: every line of the label then ends at the edge. Ignored on other\n * variants and with `iconOnly` (3.9, AS-26).\n * @default false\n */\n readonly flush = input(false);\n\n /** Classes on the anchor; merged with the consumer's own `class`. */\n protected readonly hostClasses = computed(() => {\n const classes = ['btn', `btn-${this.variant()}`, `btn-${this.size()}`];\n if (this.iconOnly()) classes.push('btn-icon-only');\n if (this.fullWidth()) classes.push('btn-full-width');\n if (this.inline()) classes.push('btn-inline');\n if (this.flush()) classes.push('btn-flush');\n if (this.variant() === 'outline' && this.tone() === 'primary') classes.push('btn-tone-primary');\n return classes.join(' ');\n });\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-choice-prompt.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/choice-prompt/choice-prompt.component.ts","../../../../libs/angular-ui-kit/src/lib/choice-prompt/choice-prompt.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n effect,\n input,\n isDevMode,\n output,\n signal,\n viewChild,\n viewChildren,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\n\n/** One selectable answer of an `lc-choice-prompt`. */\nexport interface ChoicePromptOption {\n id: string;\n label: string;\n /** Optional second line inside the option button. */\n description?: string;\n /** Marks the recommended answer: badge + first position. */\n recommended?: boolean;\n}\n\n/** A subordinate exit of the prompt (e.g. \"Selbst gelöst\" / \"Ignorieren\"). */\nexport interface ChoicePromptSecondaryAction {\n id: string;\n label: string;\n tooltip?: string;\n}\n\n/** Payload of the `(decided)` output — exactly one of the two fields is set. */\nexport interface ChoicePromptDecision {\n optionId?: string;\n customText?: string;\n}\n\nexport type ChoicePromptSize = 'sm' | 'md';\n\n/**\n * Inline decision prompt: predefined answer options (with a marked\n * recommendation) plus an optional free-text answer — no modal, directly in\n * the flow.\n *\n * Features:\n * - Options as buttons; `recommended` carries the badge and is sorted first\n * - Free-text lane behind a toggle link (`allowCustom`), submit via button or\n * Enter; empty text is never submittable\n * - `busy` after a decision: the clicked option shows a spinner, everything\n * else is disabled — prevents double submits. Focus stays on the triggering\n * element when `busy` ends.\n * - `disabled` requires a `disabledReason` (tooltip); missing reason logs a\n * dev warning\n * - Subordinate exits via `secondaryActions`\n * - `role=\"group\"` labelled via `promptLabel` (the question itself lives in\n * the surrounding layout)\n *\n * @example\n * ```html\n * <lc-choice-prompt\n * promptLabel=\"Wie soll der Konflikt gelöst werden?\"\n * [options]=\"[\n * { id: 'a', label: 'Variante A übernehmen', recommended: true },\n * { id: 'b', label: 'Beide behalten' },\n * ]\"\n * [busy]=\"saving()\"\n * (decided)=\"resolve($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-choice-prompt',\n standalone: true,\n imports: [ButtonComponent],\n templateUrl: './choice-prompt.component.html',\n styleUrls: ['./choice-prompt.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ChoicePromptComponent {\n /** Answer options. The recommended option is sorted to the front. */\n options = input.required<ChoicePromptOption[]>();\n\n /**\n * Whether the free-text lane is offered.\n * @default true\n */\n allowCustom = input<boolean>(true);\n\n /** Label of the link that opens the free-text lane. */\n customToggleLabel = input<string>('Eigene Antwort …');\n\n /** Placeholder of the free-text input. */\n customPlaceholder = input<string>('');\n\n /** Label of the free-text submit button. */\n submitLabel = input<string>('Übernehmen');\n\n /**\n * Set after a decision while it is being processed: the chosen element shows\n * a spinner, every other interaction is blocked (including Enter in the\n * free-text input).\n * @default false\n */\n busy = input<boolean>(false);\n\n /** Disables the whole prompt. Requires `disabledReason`. */\n disabled = input<boolean>(false);\n\n /** Why the prompt is disabled — shown as tooltip. */\n disabledReason = input<string>('');\n\n /** Subordinate exits, rendered as quiet text buttons after the options. */\n secondaryActions = input<ChoicePromptSecondaryAction[]>([]);\n\n /**\n * `sm` for dense lists (inbox rows).\n * @default 'md'\n */\n size = input<ChoicePromptSize>('md');\n\n /** Accessible name of the group — the question shown in the surroundings. */\n promptLabel = input<string>('');\n\n /** Label of the recommendation badge. */\n recommendedLabel = input<string>('Empfehlung');\n\n /** Fires immediately on option click, or on free-text submit. */\n decided = output<ChoicePromptDecision>();\n\n /** Fires with the id of a clicked secondary action. */\n secondaryAction = output<string>();\n\n /** Whether the free-text lane is open. */\n protected customOpen = signal(false);\n\n /** Current free-text value. */\n protected customText = signal('');\n\n /** Option that triggered the pending decision (spinner + focus anchor). */\n protected pendingOptionId = signal<string | null>(null);\n\n /** Whether the pending decision came from the free-text lane. */\n protected pendingCustom = signal(false);\n\n private customInput = viewChild<ElementRef<HTMLInputElement>>('customInput');\n private optionButtons = viewChildren<ElementRef<HTMLButtonElement>>('optionButton');\n private submitButton = viewChild<ButtonComponent>('submitButton');\n\n /** Options with the recommended one(s) first, original order otherwise. */\n protected sortedOptions = computed(() => {\n const options = this.options();\n return [...options.filter((o) => o.recommended), ...options.filter((o) => !o.recommended)];\n });\n\n /** No interaction while busy or disabled. */\n protected locked = computed(() => this.busy() || this.disabled());\n\n protected canSubmitCustom = computed(\n () => this.customText().trim().length > 0 && !this.locked(),\n );\n\n protected disabledTitle = computed(() =>\n this.disabled() && this.disabledReason() ? this.disabledReason() : null,\n );\n\n protected groupClasses = computed(() =>\n ['lc-choice-prompt', `lc-choice-prompt--${this.size()}`].join(' '),\n );\n\n constructor() {\n effect(() => {\n if (isDevMode() && this.disabled() && !this.disabledReason()) {\n console.warn(\n '[lc-choice-prompt] `disabled` is set without a `disabledReason`. ' +\n 'A disabled prompt must explain why (shown as tooltip).',\n );\n }\n });\n\n // When busy ends, focus returns to the element that triggered the\n // decision, then the pending markers reset.\n let wasBusy = false;\n effect(() => {\n const busy = this.busy();\n if (wasBusy && !busy) {\n this.restoreFocus();\n this.pendingOptionId.set(null);\n this.pendingCustom.set(false);\n }\n wasBusy = busy;\n });\n }\n\n protected isPendingOption(id: string): boolean {\n return this.busy() && this.pendingOptionId() === id;\n }\n\n protected chooseOption(option: ChoicePromptOption): void {\n if (this.locked()) return;\n this.pendingOptionId.set(option.id);\n this.pendingCustom.set(false);\n this.decided.emit({ optionId: option.id });\n }\n\n protected openCustom(): void {\n if (this.locked()) return;\n this.customOpen.set(true);\n // Focus the input once it is rendered.\n setTimeout(() => this.customInput()?.nativeElement.focus());\n }\n\n protected onCustomInput(event: Event): void {\n this.customText.set((event.target as HTMLInputElement).value);\n }\n\n protected submitCustom(): void {\n const text = this.customText().trim();\n if (!text || this.locked()) return;\n this.pendingCustom.set(true);\n this.pendingOptionId.set(null);\n this.decided.emit({ customText: text });\n }\n\n protected triggerSecondary(action: ChoicePromptSecondaryAction): void {\n if (this.locked()) return;\n this.secondaryAction.emit(action.id);\n }\n\n private restoreFocus(): void {\n const pendingId = this.pendingOptionId();\n if (pendingId !== null) {\n const button = this.optionButtons().find(\n (ref) => ref.nativeElement.dataset['optionId'] === pendingId,\n );\n button?.nativeElement.focus();\n } else if (this.pendingCustom()) {\n this.submitButton()?.focus();\n }\n }\n}\n","<div\n [class]=\"groupClasses()\"\n role=\"group\"\n [attr.aria-label]=\"promptLabel() || null\"\n [attr.aria-busy]=\"busy() ? 'true' : null\"\n>\n <div class=\"lc-choice-prompt__options\">\n @for (option of sortedOptions(); track option.id) {\n <!-- The busy (clicked) option keeps focus: aria-disabled instead of the\n native attribute, the click handler is guarded via locked(). -->\n <button\n #optionButton\n type=\"button\"\n class=\"lc-choice-prompt__option\"\n [class.lc-choice-prompt__option--recommended]=\"option.recommended\"\n [class.lc-choice-prompt__option--busy]=\"isPendingOption(option.id)\"\n [attr.data-option-id]=\"option.id\"\n [disabled]=\"locked() && !isPendingOption(option.id)\"\n [attr.aria-disabled]=\"locked() ? 'true' : null\"\n [attr.title]=\"disabledTitle()\"\n (click)=\"chooseOption(option)\"\n >\n <span class=\"lc-choice-prompt__option-main\">\n @if (isPendingOption(option.id)) {\n <span class=\"lc-choice-prompt__spinner\" aria-hidden=\"true\"></span>\n }\n <span class=\"lc-choice-prompt__option-label\">{{ option.label }}</span>\n @if (option.recommended) {\n <span class=\"lc-choice-prompt__badge\">{{ recommendedLabel() }}</span>\n }\n </span>\n @if (option.description) {\n <span class=\"lc-choice-prompt__option-description\">{{ option.description }}</span>\n }\n </button>\n }\n\n @if (allowCustom() && !customOpen()) {\n <button\n type=\"button\"\n class=\"lc-choice-prompt__custom-toggle\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle()\"\n (click)=\"openCustom()\"\n >\n {{ customToggleLabel() }}\n </button>\n }\n\n @for (action of secondaryActions(); track action.id) {\n <button\n type=\"button\"\n class=\"lc-choice-prompt__secondary\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle() ?? action.tooltip ?? null\"\n (click)=\"triggerSecondary(action)\"\n >\n {{ action.label }}\n </button>\n }\n </div>\n\n @if (allowCustom() && customOpen()) {\n <div class=\"lc-choice-prompt__custom\">\n <input\n #customInput\n type=\"text\"\n class=\"lc-choice-prompt__input\"\n [placeholder]=\"customPlaceholder()\"\n [value]=\"customText()\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle()\"\n [attr.aria-label]=\"customToggleLabel()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"submitCustom()\"\n />\n <lc-button\n #submitButton\n variant=\"primary\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [loading]=\"busy() && pendingCustom()\"\n [disabled]=\"!canSubmitCustom()\"\n [disabledReason]=\"disabledTitle() ?? ''\"\n (clicked)=\"submitCustom()\"\n >\n {{ submitLabel() }}\n </lc-button>\n </div>\n }\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-choice-prompt.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/choice-prompt/choice-prompt.component.ts","../../../../libs/angular-ui-kit/src/lib/choice-prompt/choice-prompt.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n computed,\n effect,\n input,\n isDevMode,\n output,\n signal,\n viewChild,\n viewChildren,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\n\n/** One selectable answer of an `lc-choice-prompt`. */\nexport interface ChoicePromptOption {\n id: string;\n label: string;\n /** Optional second line inside the option button. */\n description?: string;\n /** Marks the recommended answer: badge + first position. */\n recommended?: boolean;\n}\n\n/** A subordinate exit of the prompt (e.g. \"Selbst gelöst\" / \"Ignorieren\"). */\nexport interface ChoicePromptSecondaryAction {\n id: string;\n label: string;\n tooltip?: string;\n}\n\n/** Payload of the `(decided)` output — exactly one of the two fields is set. */\nexport interface ChoicePromptDecision {\n optionId?: string;\n customText?: string;\n}\n\nexport type ChoicePromptSize = 'sm' | 'md';\n\n/**\n * Inline decision prompt: predefined answer options (with a marked\n * recommendation) plus an optional free-text answer — no modal, directly in\n * the flow.\n *\n * Features:\n * - Options as buttons; `recommended` carries the badge and is sorted first\n * - Free-text lane behind a toggle link (`allowCustom`), submit via button or\n * Enter; empty text is never submittable\n * - `busy` after a decision: the clicked option shows a spinner, everything\n * else is disabled — prevents double submits. Focus stays on the triggering\n * element when `busy` ends.\n * - `disabled` requires a `disabledReason` (tooltip); missing reason logs a\n * dev warning\n * - Subordinate exits via `secondaryActions`\n * - `role=\"group\"` labelled via `promptLabel` (the question itself lives in\n * the surrounding layout)\n *\n * @example\n * ```html\n * <lc-choice-prompt\n * promptLabel=\"Wie soll der Konflikt gelöst werden?\"\n * [options]=\"[\n * { id: 'a', label: 'Variante A übernehmen', recommended: true },\n * { id: 'b', label: 'Beide behalten' },\n * ]\"\n * [busy]=\"saving()\"\n * (decided)=\"resolve($event)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-choice-prompt',\n standalone: true,\n imports: [ButtonComponent],\n templateUrl: './choice-prompt.component.html',\n styleUrls: ['./choice-prompt.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ChoicePromptComponent {\n /** Answer options. The recommended option is sorted to the front. */\n options = input.required<ChoicePromptOption[]>();\n\n /**\n * Whether the free-text lane is offered.\n * @default true\n */\n allowCustom = input<boolean>(true);\n\n /** Label of the link that opens the free-text lane. */\n customToggleLabel = input<string>('Eigene Antwort …');\n\n /** Placeholder of the free-text input. */\n customPlaceholder = input<string>('');\n\n /** Label of the free-text submit button. */\n submitLabel = input<string>('Übernehmen');\n\n /**\n * Set after a decision while it is being processed: the chosen element shows\n * a spinner, every other interaction is blocked (including Enter in the\n * free-text input).\n * @default false\n */\n busy = input<boolean>(false);\n\n /** Disables the whole prompt. Requires `disabledReason`. */\n disabled = input<boolean>(false);\n\n /** Why the prompt is disabled — shown as tooltip. */\n disabledReason = input<string>('');\n\n /** Subordinate exits, rendered as quiet text buttons after the options. */\n secondaryActions = input<ChoicePromptSecondaryAction[]>([]);\n\n /**\n * `sm` for dense lists (inbox rows).\n * @default 'md'\n */\n size = input<ChoicePromptSize>('md');\n\n /** Accessible name of the group — the question shown in the surroundings. */\n promptLabel = input<string>('');\n\n /** Label of the recommendation badge. */\n recommendedLabel = input<string>('Empfehlung');\n\n /** Fires immediately on option click, or on free-text submit. */\n decided = output<ChoicePromptDecision>();\n\n /** Fires with the id of a clicked secondary action. */\n secondaryAction = output<string>();\n\n /** Whether the free-text lane is open. */\n protected customOpen = signal(false);\n\n /** Current free-text value. */\n protected customText = signal('');\n\n /** Option that triggered the pending decision (spinner + focus anchor). */\n protected pendingOptionId = signal<string | null>(null);\n\n /** Whether the pending decision came from the free-text lane. */\n protected pendingCustom = signal(false);\n\n private customInput = viewChild<ElementRef<HTMLInputElement>>('customInput');\n private optionButtons = viewChildren<ElementRef<HTMLButtonElement>>('optionButton');\n private submitButton = viewChild<ButtonComponent>('submitButton');\n\n /** Options with the recommended one(s) first, original order otherwise. */\n protected sortedOptions = computed(() => {\n const options = this.options();\n return [...options.filter((o) => o.recommended), ...options.filter((o) => !o.recommended)];\n });\n\n /** No interaction while busy or disabled. */\n protected locked = computed(() => this.busy() || this.disabled());\n\n protected canSubmitCustom = computed(\n () => this.customText().trim().length > 0 && !this.locked(),\n );\n\n protected disabledTitle = computed(() =>\n this.disabled() && this.disabledReason() ? this.disabledReason() : null,\n );\n\n protected groupClasses = computed(() =>\n ['lc-choice-prompt', `lc-choice-prompt--${this.size()}`].join(' '),\n );\n\n constructor() {\n effect(() => {\n if (isDevMode() && this.disabled() && !this.disabledReason()) {\n console.warn(\n '[lc-choice-prompt] `disabled` is set without a `disabledReason`. ' +\n 'A disabled prompt must explain why (shown as tooltip).',\n );\n }\n });\n\n // When busy ends, focus returns to the element that triggered the\n // decision, then the pending markers reset.\n let wasBusy = false;\n effect(() => {\n const busy = this.busy();\n if (wasBusy && !busy) {\n this.restoreFocus();\n this.pendingOptionId.set(null);\n this.pendingCustom.set(false);\n }\n wasBusy = busy;\n });\n }\n\n protected isPendingOption(id: string): boolean {\n return this.busy() && this.pendingOptionId() === id;\n }\n\n protected chooseOption(option: ChoicePromptOption): void {\n if (this.locked()) return;\n this.pendingOptionId.set(option.id);\n this.pendingCustom.set(false);\n this.decided.emit({ optionId: option.id });\n }\n\n protected openCustom(): void {\n if (this.locked()) return;\n this.customOpen.set(true);\n // Focus the input once it is rendered.\n setTimeout(() => this.customInput()?.nativeElement.focus());\n }\n\n protected onCustomInput(event: Event): void {\n this.customText.set((event.target as HTMLInputElement).value);\n }\n\n protected submitCustom(): void {\n const text = this.customText().trim();\n if (!text || this.locked()) return;\n this.pendingCustom.set(true);\n this.pendingOptionId.set(null);\n this.decided.emit({ customText: text });\n }\n\n protected triggerSecondary(action: ChoicePromptSecondaryAction): void {\n if (this.locked()) return;\n this.secondaryAction.emit(action.id);\n }\n\n private restoreFocus(): void {\n const pendingId = this.pendingOptionId();\n if (pendingId !== null) {\n const button = this.optionButtons().find(\n (ref) => ref.nativeElement.dataset['optionId'] === pendingId,\n );\n button?.nativeElement.focus();\n } else if (this.pendingCustom()) {\n this.submitButton()?.focus();\n }\n }\n}\n","<div\n [class]=\"groupClasses()\"\n role=\"group\"\n [attr.aria-label]=\"promptLabel() || null\"\n [attr.aria-busy]=\"busy() ? 'true' : null\"\n>\n <div class=\"lc-choice-prompt__options\">\n @for (option of sortedOptions(); track option.id) {\n <!-- The busy (clicked) option keeps focus: aria-disabled instead of the\n native attribute, the click handler is guarded via locked(). -->\n <button\n #optionButton\n type=\"button\"\n class=\"lc-choice-prompt__option\"\n [class.lc-choice-prompt__option--recommended]=\"option.recommended\"\n [class.lc-choice-prompt__option--busy]=\"isPendingOption(option.id)\"\n [attr.data-option-id]=\"option.id\"\n [disabled]=\"locked() && !isPendingOption(option.id)\"\n [attr.aria-disabled]=\"locked() ? 'true' : null\"\n [attr.title]=\"disabledTitle()\"\n (click)=\"chooseOption(option)\"\n >\n <span class=\"lc-choice-prompt__option-main\">\n @if (isPendingOption(option.id)) {\n <span class=\"lc-choice-prompt__spinner\" aria-hidden=\"true\"></span>\n }\n <span class=\"lc-choice-prompt__option-label\">{{ option.label }}</span>\n @if (option.recommended) {\n <span class=\"lc-choice-prompt__badge\">{{ recommendedLabel() }}</span>\n }\n </span>\n @if (option.description) {\n <span class=\"lc-choice-prompt__option-description\">{{ option.description }}</span>\n }\n </button>\n }\n\n @if (allowCustom() && !customOpen()) {\n <button\n type=\"button\"\n class=\"lc-choice-prompt__custom-toggle\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle()\"\n (click)=\"openCustom()\"\n >\n {{ customToggleLabel() }}\n </button>\n }\n\n @for (action of secondaryActions(); track action.id) {\n <button\n type=\"button\"\n class=\"lc-choice-prompt__secondary\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle() ?? action.tooltip ?? null\"\n (click)=\"triggerSecondary(action)\"\n >\n {{ action.label }}\n </button>\n }\n </div>\n\n @if (allowCustom() && customOpen()) {\n <div class=\"lc-choice-prompt__custom\">\n <input\n #customInput\n type=\"text\"\n class=\"lc-choice-prompt__input\"\n [placeholder]=\"customPlaceholder()\"\n [value]=\"customText()\"\n [disabled]=\"locked()\"\n [attr.title]=\"disabledTitle()\"\n [attr.aria-label]=\"customToggleLabel()\"\n (input)=\"onCustomInput($event)\"\n (keydown.enter)=\"submitCustom()\"\n />\n <lc-button\n #submitButton\n variant=\"primary\"\n [size]=\"size() === 'sm' ? 'xs' : 'sm'\"\n [loading]=\"busy() && pendingCustom()\"\n [disabled]=\"!canSubmitCustom()\"\n [disabledReason]=\"disabledTitle() ?? ''\"\n (clicked)=\"submitCustom()\"\n >\n {{ submitLabel() }}\n </lc-button>\n </div>\n }\n</div>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from '@lifecorner/angular-ui-kit/icons';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from '@lifecorner/angular-ui-kit/icons';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHECK } from '@lifecorner/angular-ui-kit/icons';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CHECK])],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHECK } from '@lifecorner/angular-ui-kit/icons';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CHECK])],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"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"}
|