@retalia/pos-components 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,21 +2,37 @@ import * as i0 from '@angular/core';
2
2
  import { input, output, signal, computed, ChangeDetectionStrategy, Component, viewChild, afterNextRender } from '@angular/core';
3
3
 
4
4
  const DEFAULT_SESSION = { status: 'signedOut' };
5
- const KEYPAD_ROWS$1 = [
6
- ['1', '2', '3'],
7
- ['4', '5', '6'],
8
- ['7', '8', '9'],
9
- ['0', '.', '←'],
10
- ];
5
+ const DIGIT_KEYS = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
11
6
  class PosLogin {
12
7
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
13
8
  session = input(DEFAULT_SESSION, ...(ngDevMode ? [{ debugName: "session" }] : /* istanbul ignore next */ []));
14
- titleClerkNumber = input('Enter Clerk Number', ...(ngDevMode ? [{ debugName: "titleClerkNumber" }] : /* istanbul ignore next */ []));
15
- titleClerkPassword = input('Enter Clerk Password', ...(ngDevMode ? [{ debugName: "titleClerkPassword" }] : /* istanbul ignore next */ []));
9
+ heading = input('Clerk sign in', ...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
10
+ titleClerkNumber = input('Enter clerk PIN', ...(ngDevMode ? [{ debugName: "titleClerkNumber" }] : /* istanbul ignore next */ []));
11
+ titleClerkPassword = input('Enter clerk password', ...(ngDevMode ? [{ debugName: "titleClerkPassword" }] : /* istanbul ignore next */ []));
16
12
  nextLabel = input('Next', ...(ngDevMode ? [{ debugName: "nextLabel" }] : /* istanbul ignore next */ []));
17
13
  loginLabel = input('Login', ...(ngDevMode ? [{ debugName: "loginLabel" }] : /* istanbul ignore next */ []));
14
+ /** Shop context beside the keypad. Off leaves the keypad on its own. */
15
+ showAside = input(true, ...(ngDevMode ? [{ debugName: "showAside" }] : /* istanbul ignore next */ []));
16
+ /** Draws a frame around the login shell. Off by default. */
17
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
18
+ /** When false, the brand image is omitted, including the built-in mark. */
19
+ showBrandImage = input(true, ...(ngDevMode ? [{ debugName: "showBrandImage" }] : /* istanbul ignore next */ []));
20
+ /** Partner image URL. Empty, while `showBrandImage` is true, uses the built-in Retalia mark. */
21
+ brandImage = input('', ...(ngDevMode ? [{ debugName: "brandImage" }] : /* istanbul ignore next */ []));
22
+ /** Wordmark after the image. Empty shows no text. */
23
+ brandLabel = input('RETALIA', ...(ngDevMode ? [{ debugName: "brandLabel" }] : /* istanbul ignore next */ []));
24
+ /** First address line under the brand. Empty hides it. */
25
+ locationName = input('Address1', ...(ngDevMode ? [{ debugName: "locationName" }] : /* istanbul ignore next */ []));
26
+ /** Second address line. Empty hides it. */
27
+ terminalLine = input('Address2', ...(ngDevMode ? [{ debugName: "terminalLine" }] : /* istanbul ignore next */ []));
28
+ /** Shop line. Empty hides it. */
29
+ shopName = input('shop 1', ...(ngDevMode ? [{ debugName: "shopName" }] : /* istanbul ignore next */ []));
30
+ dateLabel = input('Date', ...(ngDevMode ? [{ debugName: "dateLabel" }] : /* istanbul ignore next */ []));
31
+ posNumberLabel = input('POS No', ...(ngDevMode ? [{ debugName: "posNumberLabel" }] : /* istanbul ignore next */ []));
32
+ /** Empty hides the POS number tile. */
33
+ posNumber = input('001', ...(ngDevMode ? [{ debugName: "posNumber" }] : /* istanbul ignore next */ []));
18
34
  action = output();
19
- keypadRows = KEYPAD_ROWS$1;
35
+ digitKeys = DIGIT_KEYS;
20
36
  inputValue = signal('', ...(ngDevMode ? [{ debugName: "inputValue" }] : /* istanbul ignore next */ []));
21
37
  stage = signal('clerkNumber', ...(ngDevMode ? [{ debugName: "stage" }] : /* istanbul ignore next */ []));
22
38
  clerkNumber = signal('', ...(ngDevMode ? [{ debugName: "clerkNumber" }] : /* istanbul ignore next */ []));
@@ -24,13 +40,25 @@ class PosLogin {
24
40
  ? this.titleClerkNumber()
25
41
  : this.titleClerkPassword(), ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
26
42
  maskInput = computed(() => this.stage() === 'password', ...(ngDevMode ? [{ debugName: "maskInput" }] : /* istanbul ignore next */ []));
43
+ hasEntry = computed(() => this.inputValue().length > 0, ...(ngDevMode ? [{ debugName: "hasEntry" }] : /* istanbul ignore next */ []));
44
+ displayText = computed(() => {
45
+ const value = this.inputValue();
46
+ if (!value) {
47
+ return this.title();
48
+ }
49
+ return this.maskInput() ? '•'.repeat(value.length) : value;
50
+ }, ...(ngDevMode ? [{ debugName: "displayText" }] : /* istanbul ignore next */ []));
27
51
  showBack = computed(() => this.stage() === 'password', ...(ngDevMode ? [{ debugName: "showBack" }] : /* istanbul ignore next */ []));
28
52
  primaryLabel = computed(() => this.stage() === 'password' ? this.loginLabel() : this.nextLabel(), ...(ngDevMode ? [{ debugName: "primaryLabel" }] : /* istanbul ignore next */ []));
29
- primaryEnabled = computed(() => this.inputValue().length > 0 && !this.interactionLocked(), ...(ngDevMode ? [{ debugName: "primaryEnabled" }] : /* istanbul ignore next */ []));
30
53
  interactionLocked = computed(() => {
31
54
  const status = this.session().status;
32
55
  return status === 'busy' || status === 'signedIn';
33
56
  }, ...(ngDevMode ? [{ debugName: "interactionLocked" }] : /* istanbul ignore next */ []));
57
+ shownDate = computed(() => new Intl.DateTimeFormat('en-GB', {
58
+ weekday: 'long',
59
+ day: 'numeric',
60
+ month: 'long',
61
+ }).format(new Date()), ...(ngDevMode ? [{ debugName: "shownDate" }] : /* istanbul ignore next */ []));
34
62
  sessionStatusText = computed(() => {
35
63
  const current = this.session();
36
64
  if (current.status === 'busy') {
@@ -88,14 +116,14 @@ class PosLogin {
88
116
  this.action.emit({ type: 'login.back' });
89
117
  }
90
118
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosLogin, deps: [], target: i0.ɵɵFactoryTarget.Component });
91
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosLogin, isStandalone: true, selector: "pos-login", inputs: { errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, session: { classPropertyName: "session", publicName: "session", isSignal: true, isRequired: false, transformFunction: null }, titleClerkNumber: { classPropertyName: "titleClerkNumber", publicName: "titleClerkNumber", isSignal: true, isRequired: false, transformFunction: null }, titleClerkPassword: { classPropertyName: "titleClerkPassword", publicName: "titleClerkPassword", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, loginLabel: { classPropertyName: "loginLabel", publicName: "loginLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-login" }, ngImport: i0, template: "<section class=\"pos-login__panel\" [attr.aria-busy]=\"session().status === 'busy' ? true : null\">\r\n <header class=\"pos-login__header\">\r\n <p class=\"pos-login__kicker\">Adaptive POS</p>\r\n <h1 class=\"pos-login__title\">{{ title() }}</h1>\r\n </header>\r\n\r\n <div class=\"pos-login__status\" aria-live=\"polite\">\r\n @if (sessionStatusText()) {\r\n <p>{{ sessionStatusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-login__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-login__body\">\r\n <div class=\"pos-login__display\">\r\n <input\r\n class=\"pos-login__input\"\r\n [attr.type]=\"maskInput() ? 'password' : 'text'\"\r\n [value]=\"inputValue()\"\r\n maxlength=\"12\"\r\n readonly\r\n tabindex=\"-1\"\r\n placeholder=\"\u00B7 \u00B7 \u00B7 \u00B7\"\r\n (keydown)=\"$event.preventDefault()\"\r\n aria-label=\"Login code\"\r\n />\r\n </div>\r\n\r\n <div class=\"pos-login__keypad\" role=\"group\" aria-label=\"Keypad\">\r\n @for (row of keypadRows; track $index) {\r\n <div class=\"pos-login__keypad-row\">\r\n @for (key of row; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [class.pos-login__key--action]=\"key === '\u2190' || key === '.'\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-login__actions\">\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__back\"\r\n aria-label=\"Back\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onBack()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M15 6 9 12l6 6\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n <span>Back</span>\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__primary\"\r\n [class.pos-login__primary--disabled]=\"!primaryEnabled()\"\r\n [disabled]=\"!primaryEnabled()\"\r\n (click)=\"onPrimary()\"\r\n >\r\n {{ primaryLabel() }}\r\n </button>\r\n </div>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;max-width:26rem;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-login__panel{position:relative;display:flex;flex-direction:column;min-height:100%;padding:var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-login__header{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:var(--pos-space-sm);padding-right:var(--pos-space-2xl)}.pos-login__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-login__title{margin:0;max-width:14ch;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em;line-height:1.15}.pos-login__status{min-height:1.5rem;margin:var(--pos-space-md) 0 var(--pos-space-sm);display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-login__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__error{padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:#d6454514;color:var(--pos-color-danger)}.pos-login__key:disabled,.pos-login__back:disabled{cursor:not-allowed;opacity:.55}.pos-login__body{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-xl);width:100%}.pos-login__display{border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-display);box-shadow:inset 0 1px #ffffff0f;padding:var(--pos-space-lg) var(--pos-space-xl)}.pos-login__input{display:block;width:100%;margin:0;border:0;background:transparent;color:var(--pos-color-on-display);font-family:var(--pos-font-family-display);font-size:clamp(1.35rem,3vw,1.85rem);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-display);text-align:center;outline:none}.pos-login__input::placeholder{color:#e8edf259;letter-spacing:.45em}.pos-login__keypad{display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-login__keypad-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-md)}.pos-login__key{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-key-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);font-family:inherit;font-size:1.15rem;font-weight:var(--pos-font-weight-bold);cursor:pointer;transition:background .12s ease,color .12s ease,border-color .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-login__key--action{color:var(--pos-color-text-muted);background:var(--pos-color-surface-muted)}.pos-login__key:active{background:var(--pos-color-key-active);border-color:var(--pos-color-key-active);color:var(--pos-color-on-key-active);transform:translateY(1px)}.pos-login__actions{display:flex;align-items:stretch;gap:var(--pos-space-md);margin-top:auto}.pos-login__back{display:inline-flex;flex:0 0 auto;align-items:center;gap:var(--pos-space-xs);min-height:var(--pos-button-min-height);padding:0 var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated);color:var(--pos-color-text);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer}.pos-login__primary{flex:1 1 auto;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-size:1.05rem;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:filter .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-login__primary:not(:disabled):hover{filter:brightness(.97)}.pos-login__primary:not(:disabled):active{transform:translateY(1px)}.pos-login__primary--disabled,.pos-login__primary:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;filter:none;transform:none}@media(min-width:768px){.pos-login__panel{padding:var(--pos-space-2xl)}.pos-login__key{min-height:var(--pos-keypad-size-md)}}@media(min-width:1100px){.pos-login__key{min-height:var(--pos-keypad-size-lg);font-size:1.25rem}}@media(prefers-reduced-motion:reduce){.pos-login__key,.pos-login__primary{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
119
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosLogin, isStandalone: true, selector: "pos-login", inputs: { errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, session: { classPropertyName: "session", publicName: "session", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, titleClerkNumber: { classPropertyName: "titleClerkNumber", publicName: "titleClerkNumber", isSignal: true, isRequired: false, transformFunction: null }, titleClerkPassword: { classPropertyName: "titleClerkPassword", publicName: "titleClerkPassword", isSignal: true, isRequired: false, transformFunction: null }, nextLabel: { classPropertyName: "nextLabel", publicName: "nextLabel", isSignal: true, isRequired: false, transformFunction: null }, loginLabel: { classPropertyName: "loginLabel", publicName: "loginLabel", isSignal: true, isRequired: false, transformFunction: null }, showAside: { classPropertyName: "showAside", publicName: "showAside", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, showBrandImage: { classPropertyName: "showBrandImage", publicName: "showBrandImage", isSignal: true, isRequired: false, transformFunction: null }, brandImage: { classPropertyName: "brandImage", publicName: "brandImage", isSignal: true, isRequired: false, transformFunction: null }, brandLabel: { classPropertyName: "brandLabel", publicName: "brandLabel", isSignal: true, isRequired: false, transformFunction: null }, locationName: { classPropertyName: "locationName", publicName: "locationName", isSignal: true, isRequired: false, transformFunction: null }, terminalLine: { classPropertyName: "terminalLine", publicName: "terminalLine", isSignal: true, isRequired: false, transformFunction: null }, shopName: { classPropertyName: "shopName", publicName: "shopName", isSignal: true, isRequired: false, transformFunction: null }, dateLabel: { classPropertyName: "dateLabel", publicName: "dateLabel", isSignal: true, isRequired: false, transformFunction: null }, posNumberLabel: { classPropertyName: "posNumberLabel", publicName: "posNumberLabel", isSignal: true, isRequired: false, transformFunction: null }, posNumber: { classPropertyName: "posNumber", publicName: "posNumber", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-login" }, ngImport: i0, template: "<div\r\n class=\"pos-login__shell\"\r\n [class.pos-login__shell--aside]=\"showAside()\"\r\n [class.pos-login__shell--bordered]=\"bordered()\"\r\n>\r\n @if (showAside()) {\r\n <aside class=\"pos-login__aside\">\r\n @if (showBrandImage() || brandLabel()) {\r\n <div class=\"pos-login__brand\">\r\n @if (showBrandImage()) {\r\n @if (brandImage()) {\r\n <img\r\n class=\"pos-login__brand-image\"\r\n [src]=\"brandImage()\"\r\n [alt]=\"brandLabel() ? '' : 'Brand'\"\r\n />\r\n } @else {\r\n <svg\r\n class=\"pos-login__brand-image\"\r\n viewBox=\"492.40 241.70 51.34 54.94\"\r\n [attr.aria-hidden]=\"brandLabel() ? true : null\"\r\n [attr.aria-label]=\"brandLabel() ? null : 'Retalia'\"\r\n >\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 522.628906 291.910156 C 522.636719 293.0625 523.441406 293.511719 524.425781 292.914062 L 540.464844 283.207031 C 541.449219 282.613281 542.246094 281.195312 542.246094 280.046875 L 542.246094 261.132812 C 542.246094 259.980469 541.441406 259.523438 540.453125 260.113281 L 524.292969 269.691406 C 523.300781 270.277344 522.503906 271.683594 522.511719 272.835938 Z M 522.628906 291.910156\"\r\n />\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 539.097656 253.351562 L 517.101562 243.664062 C 516.066406 243.203125 514.417969 243.265625 513.421875 243.804688 L 495.835938 253.308594 C 494.839844 253.847656 494.027344 255.214844 494.023438 256.367188 L 493.910156 280.140625 C 493.902344 281.292969 494.699219 282.679688 495.683594 283.234375 L 501.734375 286.640625 C 502.71875 287.199219 503.503906 286.71875 503.480469 285.566406 L 503.214844 271.488281 C 503.207031 271.082031 503.492188 270.894531 503.855469 271.066406 L 506.128906 272.148438 C 507.152344 272.636719 507.980469 273.960938 507.980469 275.113281 L 507.980469 287.839844 C 507.980469 288.992188 508.773438 290.394531 509.746094 290.972656 L 515.777344 294.5625 C 516.753906 295.140625 517.554688 294.679688 517.566406 293.527344 L 517.800781 273.300781 C 517.808594 272.488281 517.539062 271.238281 517.195312 270.503906 L 515.460938 266.789062 C 515.292969 266.421875 515.476562 266.109375 515.871094 266.089844 L 518.925781 265.941406 C 520.050781 265.886719 521.761719 265.378906 522.738281 264.808594 L 539.195312 255.21875 C 540.175781 254.648438 540.132812 253.8125 539.097656 253.351562 M 520.609375 255.050781 L 518.019531 256.585938 C 516.914062 257.125 515.734375 257.289062 514.710938 256.804688 L 511.078125 255.101562 C 510.054688 254.621094 510.023438 253.773438 511.003906 253.210938 L 513.835938 251.597656 C 514.53125 251.203125 515.691406 251.132812 516.425781 251.445312 L 520.449219 253.128906 C 521.488281 253.570312 521.5625 254.429688 520.609375 255.050781\"\r\n />\r\n </svg>\r\n }\r\n }\r\n @if (brandLabel()) {\r\n <span class=\"pos-login__brand-label\">{{ brandLabel() }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (locationName() || terminalLine()) {\r\n <div class=\"pos-login__place\">\r\n @if (locationName()) {\r\n <p class=\"pos-login__location\">{{ locationName() }}</p>\r\n }\r\n @if (terminalLine()) {\r\n <p class=\"pos-login__terminal\">{{ terminalLine() }}</p>\r\n }\r\n @if (shopName()) {\r\n <p class=\"pos-login__terminal\">{{ shopName() }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-login__facts\">\r\n <div class=\"pos-login__fact\">\r\n <p class=\"pos-login__fact-label\">{{ dateLabel() }}</p>\r\n <p class=\"pos-login__fact-value\">{{ shownDate() }}</p>\r\n </div>\r\n @if (posNumber()) {\r\n <div class=\"pos-login__fact\">\r\n <p class=\"pos-login__fact-label\">{{ posNumberLabel() }}</p>\r\n <p class=\"pos-login__fact-value\">{{ posNumber() }}</p>\r\n </div>\r\n }\r\n </div>\r\n </aside>\r\n }\r\n\r\n<section class=\"pos-login__panel\" [attr.aria-busy]=\"session().status === 'busy' ? true : null\">\r\n <div class=\"pos-login__main\">\r\n <header class=\"pos-login__header\">\r\n <h1 class=\"pos-login__heading\">{{ heading() }}</h1>\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__back\"\r\n aria-label=\"Back\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onBack()\"\r\n >\r\n Back\r\n </button>\r\n }\r\n </header>\r\n\r\n <div class=\"pos-login__display\">\r\n <p class=\"pos-login__title\" [class.pos-login__title--entry]=\"hasEntry()\">{{ displayText() }}</p>\r\n <input\r\n class=\"pos-login__input\"\r\n [attr.type]=\"maskInput() ? 'password' : 'text'\"\r\n [value]=\"inputValue()\"\r\n maxlength=\"12\"\r\n readonly\r\n tabindex=\"-1\"\r\n (keydown)=\"$event.preventDefault()\"\r\n aria-label=\"Login code\"\r\n />\r\n </div>\r\n\r\n <div class=\"pos-login__keypad\" role=\"group\" aria-label=\"Keypad\">\r\n @for (key of digitKeys; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key pos-login__key--delete\"\r\n aria-label=\"Delete\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad('\u2190')\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M8 5h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H8l-5-7 5-7Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"m14 10 4 4m0-4-4 4\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad('0')\"\r\n >\r\n 0\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__primary\"\r\n [attr.aria-label]=\"primaryLabel()\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onPrimary()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M5 12.5 9.5 17 19 7.5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n @if (sessionStatusText() || errorMessage()) {\r\n <div class=\"pos-login__status\" aria-live=\"polite\">\r\n @if (sessionStatusText()) {\r\n <p>{{ sessionStatusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-login__error\" role=\"alert\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</section>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;min-height:100vh;align-items:center;justify-content:center;padding:var(--pos-space-lg);color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md);background:transparent}*{box-sizing:border-box}.pos-login__shell{display:flex;flex-direction:column;width:min(22rem,100%);min-width:0}.pos-login__shell--aside{width:min(56rem,100%);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface);box-shadow:var(--pos-shadow-overlay);overflow:hidden}.pos-login__shell--bordered{border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg)}.pos-login__aside{display:flex;flex-direction:column;gap:var(--pos-space-xl);min-width:0;padding:var(--pos-space-xl);border-bottom:1px solid var(--pos-color-border)}.pos-login__brand{display:flex;align-items:center;gap:var(--pos-space-sm)}.pos-login__brand-image{flex:0 0 auto;width:auto;height:var(--pos-space-xl);color:var(--pos-color-ink)}.pos-login__brand-label{font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-brand)}.pos-login__place{display:flex;flex-direction:column;gap:var(--pos-space-xs)}.pos-login__location{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-login__terminal{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-login__facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pos-space-md)}.pos-login__fact{min-width:0;padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg)}.pos-login__fact-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-brand);text-transform:uppercase}.pos-login__fact-value{margin:var(--pos-space-xs) 0 0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.25}.pos-login__panel{display:flex;flex:1 1 auto;align-items:flex-start;justify-content:center;width:100%;min-width:0;padding:var(--pos-space-xl)}.pos-login__shell:not(.pos-login__shell--aside) .pos-login__panel{padding:0}.pos-login__main{display:flex;flex-direction:column;gap:var(--pos-space-md);width:min(22rem,100%)}.pos-login__header{display:flex;align-items:center;justify-content:space-between;gap:var(--pos-space-sm);min-height:var(--pos-space-xl)}.pos-login__heading{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-login__display{position:relative;display:flex;align-items:center;justify-content:center;width:100%;min-width:0;min-height:calc(var(--pos-button-min-height) + var(--pos-space-lg));padding:var(--pos-space-md) var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface-muted)}.pos-login__title{margin:0;max-width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:calc(var(--pos-font-size-xl) * 1.3);font-weight:var(--pos-font-weight-bold);line-height:1.2;text-align:center;overflow-wrap:anywhere}.pos-login__title--entry{letter-spacing:var(--pos-letter-spacing-display)}.pos-login__input{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.pos-login__keypad{display:grid;width:100%;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-sm)}.pos-login__key,.pos-login__primary,.pos-login__back{font-family:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-login__key,.pos-login__primary{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);box-shadow:var(--pos-shadow-key);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-semibold);transition:background .12s ease,border-color .12s ease,color .12s ease,transform 80ms ease,filter .12s ease}.pos-login__key--delete{color:var(--pos-color-text-muted)}.pos-login__key:hover:not(:disabled){border-color:var(--pos-color-primary);background:color-mix(in srgb,var(--pos-color-primary) 22%,var(--pos-color-surface));color:var(--pos-color-text)}.pos-login__key:active:not(:disabled),.pos-login__primary:active:not(:disabled),.pos-login__back:active:not(:disabled){transform:scale(.985)}.pos-login__key:disabled,.pos-login__back:disabled,.pos-login__primary:disabled{cursor:not-allowed;opacity:.45;transform:none;filter:none}.pos-login__key:focus-visible,.pos-login__primary:focus-visible,.pos-login__back:focus-visible{outline:3px solid var(--pos-color-primary);outline-offset:2px}.pos-login__primary{border-color:var(--pos-color-primary);background:var(--pos-color-primary);color:var(--pos-color-on-primary)}.pos-login__primary:hover:not(:disabled){filter:brightness(1.06)}.pos-login__back{border:0;background:transparent;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__back:hover:not(:disabled){color:var(--pos-color-text)}.pos-login__status{display:flex;flex-direction:column;gap:var(--pos-space-xs);text-align:center}.pos-login__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__error{color:var(--pos-color-danger)}@media(min-width:768px){.pos-login__shell--aside{flex-direction:row;align-items:stretch}.pos-login__aside,.pos-login__panel{flex:1 1 50%}.pos-login__aside{border-bottom:0;border-right:1px solid var(--pos-color-border);padding:var(--pos-space-2xl)}.pos-login__key,.pos-login__primary{min-height:var(--pos-keypad-size-md)}}@media(prefers-reduced-motion:reduce){.pos-login__key,.pos-login__primary,.pos-login__back{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
92
120
  }
93
121
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosLogin, decorators: [{
94
122
  type: Component,
95
123
  args: [{ selector: 'pos-login', changeDetection: ChangeDetectionStrategy.OnPush, host: {
96
124
  class: 'pos-login',
97
- }, template: "<section class=\"pos-login__panel\" [attr.aria-busy]=\"session().status === 'busy' ? true : null\">\r\n <header class=\"pos-login__header\">\r\n <p class=\"pos-login__kicker\">Adaptive POS</p>\r\n <h1 class=\"pos-login__title\">{{ title() }}</h1>\r\n </header>\r\n\r\n <div class=\"pos-login__status\" aria-live=\"polite\">\r\n @if (sessionStatusText()) {\r\n <p>{{ sessionStatusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-login__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-login__body\">\r\n <div class=\"pos-login__display\">\r\n <input\r\n class=\"pos-login__input\"\r\n [attr.type]=\"maskInput() ? 'password' : 'text'\"\r\n [value]=\"inputValue()\"\r\n maxlength=\"12\"\r\n readonly\r\n tabindex=\"-1\"\r\n placeholder=\"\u00B7 \u00B7 \u00B7 \u00B7\"\r\n (keydown)=\"$event.preventDefault()\"\r\n aria-label=\"Login code\"\r\n />\r\n </div>\r\n\r\n <div class=\"pos-login__keypad\" role=\"group\" aria-label=\"Keypad\">\r\n @for (row of keypadRows; track $index) {\r\n <div class=\"pos-login__keypad-row\">\r\n @for (key of row; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [class.pos-login__key--action]=\"key === '\u2190' || key === '.'\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-login__actions\">\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__back\"\r\n aria-label=\"Back\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onBack()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M15 6 9 12l6 6\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n <span>Back</span>\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__primary\"\r\n [class.pos-login__primary--disabled]=\"!primaryEnabled()\"\r\n [disabled]=\"!primaryEnabled()\"\r\n (click)=\"onPrimary()\"\r\n >\r\n {{ primaryLabel() }}\r\n </button>\r\n </div>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;max-width:26rem;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-login__panel{position:relative;display:flex;flex-direction:column;min-height:100%;padding:var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-login__header{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:var(--pos-space-sm);padding-right:var(--pos-space-2xl)}.pos-login__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-login__title{margin:0;max-width:14ch;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em;line-height:1.15}.pos-login__status{min-height:1.5rem;margin:var(--pos-space-md) 0 var(--pos-space-sm);display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-login__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__error{padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:#d6454514;color:var(--pos-color-danger)}.pos-login__key:disabled,.pos-login__back:disabled{cursor:not-allowed;opacity:.55}.pos-login__body{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-xl);width:100%}.pos-login__display{border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-display);box-shadow:inset 0 1px #ffffff0f;padding:var(--pos-space-lg) var(--pos-space-xl)}.pos-login__input{display:block;width:100%;margin:0;border:0;background:transparent;color:var(--pos-color-on-display);font-family:var(--pos-font-family-display);font-size:clamp(1.35rem,3vw,1.85rem);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-display);text-align:center;outline:none}.pos-login__input::placeholder{color:#e8edf259;letter-spacing:.45em}.pos-login__keypad{display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-login__keypad-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-md)}.pos-login__key{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-key-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);font-family:inherit;font-size:1.15rem;font-weight:var(--pos-font-weight-bold);cursor:pointer;transition:background .12s ease,color .12s ease,border-color .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-login__key--action{color:var(--pos-color-text-muted);background:var(--pos-color-surface-muted)}.pos-login__key:active{background:var(--pos-color-key-active);border-color:var(--pos-color-key-active);color:var(--pos-color-on-key-active);transform:translateY(1px)}.pos-login__actions{display:flex;align-items:stretch;gap:var(--pos-space-md);margin-top:auto}.pos-login__back{display:inline-flex;flex:0 0 auto;align-items:center;gap:var(--pos-space-xs);min-height:var(--pos-button-min-height);padding:0 var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated);color:var(--pos-color-text);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer}.pos-login__primary{flex:1 1 auto;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-size:1.05rem;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:filter .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-login__primary:not(:disabled):hover{filter:brightness(.97)}.pos-login__primary:not(:disabled):active{transform:translateY(1px)}.pos-login__primary--disabled,.pos-login__primary:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;filter:none;transform:none}@media(min-width:768px){.pos-login__panel{padding:var(--pos-space-2xl)}.pos-login__key{min-height:var(--pos-keypad-size-md)}}@media(min-width:1100px){.pos-login__key{min-height:var(--pos-keypad-size-lg);font-size:1.25rem}}@media(prefers-reduced-motion:reduce){.pos-login__key,.pos-login__primary{transition:none}}\n"] }]
98
- }], propDecorators: { errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], session: [{ type: i0.Input, args: [{ isSignal: true, alias: "session", required: false }] }], titleClerkNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleClerkNumber", required: false }] }], titleClerkPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleClerkPassword", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], loginLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loginLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
125
+ }, template: "<div\r\n class=\"pos-login__shell\"\r\n [class.pos-login__shell--aside]=\"showAside()\"\r\n [class.pos-login__shell--bordered]=\"bordered()\"\r\n>\r\n @if (showAside()) {\r\n <aside class=\"pos-login__aside\">\r\n @if (showBrandImage() || brandLabel()) {\r\n <div class=\"pos-login__brand\">\r\n @if (showBrandImage()) {\r\n @if (brandImage()) {\r\n <img\r\n class=\"pos-login__brand-image\"\r\n [src]=\"brandImage()\"\r\n [alt]=\"brandLabel() ? '' : 'Brand'\"\r\n />\r\n } @else {\r\n <svg\r\n class=\"pos-login__brand-image\"\r\n viewBox=\"492.40 241.70 51.34 54.94\"\r\n [attr.aria-hidden]=\"brandLabel() ? true : null\"\r\n [attr.aria-label]=\"brandLabel() ? null : 'Retalia'\"\r\n >\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 522.628906 291.910156 C 522.636719 293.0625 523.441406 293.511719 524.425781 292.914062 L 540.464844 283.207031 C 541.449219 282.613281 542.246094 281.195312 542.246094 280.046875 L 542.246094 261.132812 C 542.246094 259.980469 541.441406 259.523438 540.453125 260.113281 L 524.292969 269.691406 C 523.300781 270.277344 522.503906 271.683594 522.511719 272.835938 Z M 522.628906 291.910156\"\r\n />\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 539.097656 253.351562 L 517.101562 243.664062 C 516.066406 243.203125 514.417969 243.265625 513.421875 243.804688 L 495.835938 253.308594 C 494.839844 253.847656 494.027344 255.214844 494.023438 256.367188 L 493.910156 280.140625 C 493.902344 281.292969 494.699219 282.679688 495.683594 283.234375 L 501.734375 286.640625 C 502.71875 287.199219 503.503906 286.71875 503.480469 285.566406 L 503.214844 271.488281 C 503.207031 271.082031 503.492188 270.894531 503.855469 271.066406 L 506.128906 272.148438 C 507.152344 272.636719 507.980469 273.960938 507.980469 275.113281 L 507.980469 287.839844 C 507.980469 288.992188 508.773438 290.394531 509.746094 290.972656 L 515.777344 294.5625 C 516.753906 295.140625 517.554688 294.679688 517.566406 293.527344 L 517.800781 273.300781 C 517.808594 272.488281 517.539062 271.238281 517.195312 270.503906 L 515.460938 266.789062 C 515.292969 266.421875 515.476562 266.109375 515.871094 266.089844 L 518.925781 265.941406 C 520.050781 265.886719 521.761719 265.378906 522.738281 264.808594 L 539.195312 255.21875 C 540.175781 254.648438 540.132812 253.8125 539.097656 253.351562 M 520.609375 255.050781 L 518.019531 256.585938 C 516.914062 257.125 515.734375 257.289062 514.710938 256.804688 L 511.078125 255.101562 C 510.054688 254.621094 510.023438 253.773438 511.003906 253.210938 L 513.835938 251.597656 C 514.53125 251.203125 515.691406 251.132812 516.425781 251.445312 L 520.449219 253.128906 C 521.488281 253.570312 521.5625 254.429688 520.609375 255.050781\"\r\n />\r\n </svg>\r\n }\r\n }\r\n @if (brandLabel()) {\r\n <span class=\"pos-login__brand-label\">{{ brandLabel() }}</span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (locationName() || terminalLine()) {\r\n <div class=\"pos-login__place\">\r\n @if (locationName()) {\r\n <p class=\"pos-login__location\">{{ locationName() }}</p>\r\n }\r\n @if (terminalLine()) {\r\n <p class=\"pos-login__terminal\">{{ terminalLine() }}</p>\r\n }\r\n @if (shopName()) {\r\n <p class=\"pos-login__terminal\">{{ shopName() }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-login__facts\">\r\n <div class=\"pos-login__fact\">\r\n <p class=\"pos-login__fact-label\">{{ dateLabel() }}</p>\r\n <p class=\"pos-login__fact-value\">{{ shownDate() }}</p>\r\n </div>\r\n @if (posNumber()) {\r\n <div class=\"pos-login__fact\">\r\n <p class=\"pos-login__fact-label\">{{ posNumberLabel() }}</p>\r\n <p class=\"pos-login__fact-value\">{{ posNumber() }}</p>\r\n </div>\r\n }\r\n </div>\r\n </aside>\r\n }\r\n\r\n<section class=\"pos-login__panel\" [attr.aria-busy]=\"session().status === 'busy' ? true : null\">\r\n <div class=\"pos-login__main\">\r\n <header class=\"pos-login__header\">\r\n <h1 class=\"pos-login__heading\">{{ heading() }}</h1>\r\n @if (showBack()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__back\"\r\n aria-label=\"Back\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onBack()\"\r\n >\r\n Back\r\n </button>\r\n }\r\n </header>\r\n\r\n <div class=\"pos-login__display\">\r\n <p class=\"pos-login__title\" [class.pos-login__title--entry]=\"hasEntry()\">{{ displayText() }}</p>\r\n <input\r\n class=\"pos-login__input\"\r\n [attr.type]=\"maskInput() ? 'password' : 'text'\"\r\n [value]=\"inputValue()\"\r\n maxlength=\"12\"\r\n readonly\r\n tabindex=\"-1\"\r\n (keydown)=\"$event.preventDefault()\"\r\n aria-label=\"Login code\"\r\n />\r\n </div>\r\n\r\n <div class=\"pos-login__keypad\" role=\"group\" aria-label=\"Keypad\">\r\n @for (key of digitKeys; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key pos-login__key--delete\"\r\n aria-label=\"Delete\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad('\u2190')\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M8 5h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H8l-5-7 5-7Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path\r\n d=\"m14 10 4 4m0-4-4 4\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__key\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onKeypad('0')\"\r\n >\r\n 0\r\n </button>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-login__primary\"\r\n [attr.aria-label]=\"primaryLabel()\"\r\n [disabled]=\"interactionLocked()\"\r\n (click)=\"onPrimary()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"26\" height=\"26\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M5 12.5 9.5 17 19 7.5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n @if (sessionStatusText() || errorMessage()) {\r\n <div class=\"pos-login__status\" aria-live=\"polite\">\r\n @if (sessionStatusText()) {\r\n <p>{{ sessionStatusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-login__error\" role=\"alert\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n</section>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;box-sizing:border-box;width:100%;height:100%;min-height:100vh;align-items:center;justify-content:center;padding:var(--pos-space-lg);color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md);background:transparent}*{box-sizing:border-box}.pos-login__shell{display:flex;flex-direction:column;width:min(22rem,100%);min-width:0}.pos-login__shell--aside{width:min(56rem,100%);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface);box-shadow:var(--pos-shadow-overlay);overflow:hidden}.pos-login__shell--bordered{border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg)}.pos-login__aside{display:flex;flex-direction:column;gap:var(--pos-space-xl);min-width:0;padding:var(--pos-space-xl);border-bottom:1px solid var(--pos-color-border)}.pos-login__brand{display:flex;align-items:center;gap:var(--pos-space-sm)}.pos-login__brand-image{flex:0 0 auto;width:auto;height:var(--pos-space-xl);color:var(--pos-color-ink)}.pos-login__brand-label{font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-brand)}.pos-login__place{display:flex;flex-direction:column;gap:var(--pos-space-xs)}.pos-login__location{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-login__terminal{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-login__facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pos-space-md)}.pos-login__fact{min-width:0;padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg)}.pos-login__fact-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-brand);text-transform:uppercase}.pos-login__fact-value{margin:var(--pos-space-xs) 0 0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.25}.pos-login__panel{display:flex;flex:1 1 auto;align-items:flex-start;justify-content:center;width:100%;min-width:0;padding:var(--pos-space-xl)}.pos-login__shell:not(.pos-login__shell--aside) .pos-login__panel{padding:0}.pos-login__main{display:flex;flex-direction:column;gap:var(--pos-space-md);width:min(22rem,100%)}.pos-login__header{display:flex;align-items:center;justify-content:space-between;gap:var(--pos-space-sm);min-height:var(--pos-space-xl)}.pos-login__heading{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-login__display{position:relative;display:flex;align-items:center;justify-content:center;width:100%;min-width:0;min-height:calc(var(--pos-button-min-height) + var(--pos-space-lg));padding:var(--pos-space-md) var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface-muted)}.pos-login__title{margin:0;max-width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:calc(var(--pos-font-size-xl) * 1.3);font-weight:var(--pos-font-weight-bold);line-height:1.2;text-align:center;overflow-wrap:anywhere}.pos-login__title--entry{letter-spacing:var(--pos-letter-spacing-display)}.pos-login__input{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.pos-login__keypad{display:grid;width:100%;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-sm)}.pos-login__key,.pos-login__primary,.pos-login__back{font-family:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-login__key,.pos-login__primary{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);box-shadow:var(--pos-shadow-key);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-semibold);transition:background .12s ease,border-color .12s ease,color .12s ease,transform 80ms ease,filter .12s ease}.pos-login__key--delete{color:var(--pos-color-text-muted)}.pos-login__key:hover:not(:disabled){border-color:var(--pos-color-primary);background:color-mix(in srgb,var(--pos-color-primary) 22%,var(--pos-color-surface));color:var(--pos-color-text)}.pos-login__key:active:not(:disabled),.pos-login__primary:active:not(:disabled),.pos-login__back:active:not(:disabled){transform:scale(.985)}.pos-login__key:disabled,.pos-login__back:disabled,.pos-login__primary:disabled{cursor:not-allowed;opacity:.45;transform:none;filter:none}.pos-login__key:focus-visible,.pos-login__primary:focus-visible,.pos-login__back:focus-visible{outline:3px solid var(--pos-color-primary);outline-offset:2px}.pos-login__primary{border-color:var(--pos-color-primary);background:var(--pos-color-primary);color:var(--pos-color-on-primary)}.pos-login__primary:hover:not(:disabled){filter:brightness(1.06)}.pos-login__back{border:0;background:transparent;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__back:hover:not(:disabled){color:var(--pos-color-text)}.pos-login__status{display:flex;flex-direction:column;gap:var(--pos-space-xs);text-align:center}.pos-login__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-login__error{color:var(--pos-color-danger)}@media(min-width:768px){.pos-login__shell--aside{flex-direction:row;align-items:stretch}.pos-login__aside,.pos-login__panel{flex:1 1 50%}.pos-login__aside{border-bottom:0;border-right:1px solid var(--pos-color-border);padding:var(--pos-space-2xl)}.pos-login__key,.pos-login__primary{min-height:var(--pos-keypad-size-md)}}@media(prefers-reduced-motion:reduce){.pos-login__key,.pos-login__primary,.pos-login__back{transition:none}}\n"] }]
126
+ }], propDecorators: { errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], session: [{ type: i0.Input, args: [{ isSignal: true, alias: "session", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], titleClerkNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleClerkNumber", required: false }] }], titleClerkPassword: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleClerkPassword", required: false }] }], nextLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "nextLabel", required: false }] }], loginLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loginLabel", required: false }] }], showAside: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAside", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], showBrandImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBrandImage", required: false }] }], brandImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandImage", required: false }] }], brandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabel", required: false }] }], locationName: [{ type: i0.Input, args: [{ isSignal: true, alias: "locationName", required: false }] }], terminalLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "terminalLine", required: false }] }], shopName: [{ type: i0.Input, args: [{ isSignal: true, alias: "shopName", required: false }] }], dateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dateLabel", required: false }] }], posNumberLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "posNumberLabel", required: false }] }], posNumber: [{ type: i0.Input, args: [{ isSignal: true, alias: "posNumber", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
99
127
 
100
128
  const EMPTY_TOTALS$1 = {
101
129
  gross: 0,
@@ -109,12 +137,12 @@ class PosBasket {
109
137
  lines = input([], ...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
110
138
  totals = input(EMPTY_TOTALS$1, ...(ngDevMode ? [{ debugName: "totals" }] : /* istanbul ignore next */ []));
111
139
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
140
+ /** Draws the panel frame. Off by default so the host can sit the basket flush. */
141
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
112
142
  title = input('Basket', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
113
143
  emptyMessage = input('Basket is empty', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
114
- clearLabel = input('Clear basket', ...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
115
144
  action = output();
116
145
  hasLines = computed(() => this.lines().length > 0, ...(ngDevMode ? [{ debugName: "hasLines" }] : /* istanbul ignore next */ []));
117
- canClear = computed(() => this.hasLines() && !this.disabled(), ...(ngDevMode ? [{ debugName: "canClear" }] : /* istanbul ignore next */ []));
118
146
  formatMoney(amount) {
119
147
  return new Intl.NumberFormat(undefined, {
120
148
  style: 'currency',
@@ -158,29 +186,86 @@ class PosBasket {
158
186
  }
159
187
  this.action.emit({ type: 'basket.voidLine', lineId: line.lineId });
160
188
  }
161
- onClear() {
162
- if (!this.canClear()) {
163
- return;
164
- }
165
- this.action.emit({ type: 'basket.clear' });
166
- }
167
189
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosBasket, deps: [], target: i0.ɵɵFactoryTarget.Component });
168
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosBasket, isStandalone: true, selector: "pos-basket", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, totals: { classPropertyName: "totals", publicName: "totals", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-basket" }, ngImport: i0, template: "<section\r\n class=\"pos-basket__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-basket__header\">\r\n <h2 class=\"pos-basket__title\">{{ title() }}</h2>\r\n <p class=\"pos-basket__count\">\r\n {{ lines().length }}\r\n {{ lines().length === 1 ? 'line' : 'lines' }}\r\n </p>\r\n </header>\r\n\r\n <ul class=\"pos-basket__lines\" aria-label=\"Basket lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-basket__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-basket__line\"\r\n [class.pos-basket__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-basket__line-info\">\r\n <h3 class=\"pos-basket__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-basket__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-basket__line-voided\">Voided</p>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-basket__stepper\"\r\n role=\"group\"\r\n [attr.aria-label]=\"'Quantity for ' + line.name\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Decrease quantity\"\r\n [disabled]=\"!canDecrement(line)\"\r\n (click)=\"onDecrement(line)\"\r\n >\r\n \u2212\r\n </button>\r\n <span class=\"pos-basket__qty\" aria-live=\"polite\">{{ line.qty }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Increase quantity\"\r\n [disabled]=\"!canChangeQuantity(line)\"\r\n (click)=\"onIncrement(line)\"\r\n >\r\n +\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-basket__line-prices\">\r\n <p class=\"pos-basket__unit-price\">{{ formatMoney(line.unitPrice) }}</p>\r\n <p class=\"pos-basket__line-total\">{{ formatMoney(line.lineTotal) }}</p>\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__void\"\r\n [attr.aria-label]=\"'Void ' + line.name\"\r\n [disabled]=\"!canVoid(line)\"\r\n (click)=\"onVoid(line)\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M6 6l12 12M18 6 6 18\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <footer class=\"pos-basket__footer\">\r\n <dl class=\"pos-basket__totals\" aria-live=\"polite\">\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row pos-basket__total-row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__clear\"\r\n [disabled]=\"!canClear()\"\r\n (click)=\"onClear()\"\r\n >\r\n {{ clearLabel() }}\r\n </button>\r\n </footer>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-basket__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-basket__header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin-bottom:var(--pos-space-md)}.pos-basket__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em}.pos-basket__count{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-basket__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:0;padding:0;overflow-y:auto;list-style:none}.pos-basket__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-basket__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info void\" \"stepper prices\";align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-basket__line-info{grid-area:info;min-width:0}.pos-basket__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-basket__line-sku,.pos-basket__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-basket__line-sku{color:var(--pos-color-text-muted)}.pos-basket__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-basket__stepper{grid-area:stepper;display:inline-flex;align-items:center;gap:var(--pos-space-xs);width:fit-content;padding:var(--pos-space-xs);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface)}.pos-basket__qty-btn,.pos-basket__void{display:inline-flex;align-items:center;justify-content:center;margin:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__qty-btn{min-width:2.75rem;min-height:2.75rem;border-radius:var(--pos-radius-sm);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__qty-btn:not(:disabled):active,.pos-basket__void:not(:disabled):active{background:var(--pos-color-key-active);color:var(--pos-color-on-key-active)}.pos-basket__qty{min-width:1.75rem;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);text-align:center}.pos-basket__line-prices{grid-area:prices;display:flex;flex-direction:column;align-items:flex-end;gap:var(--pos-space-xs)}.pos-basket__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-basket__void{grid-area:void;justify-self:end;min-width:2.75rem;min-height:2.75rem;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);color:var(--pos-color-text-muted)}.pos-basket__qty-btn:disabled,.pos-basket__void:disabled,.pos-basket__clear:disabled{cursor:not-allowed;opacity:.55}.pos-basket__qty-btn:focus-visible,.pos-basket__void:focus-visible,.pos-basket__clear:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-basket__line--voided .pos-basket__line-name,.pos-basket__line--voided .pos-basket__line-sku,.pos-basket__line--voided .pos-basket__line-prices{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-basket__footer{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-basket__totals{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-basket__total-row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__total-row dt,.pos-basket__total-row dd{margin:0}.pos-basket__total-row--due{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__clear{min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-danger);color:var(--pos-color-on-danger);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__clear:not(:disabled):active{transform:translateY(1px)}.pos-basket__clear:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);transform:none}@media(min-width:768px){.pos-basket__panel{padding:var(--pos-space-xl)}.pos-basket__line{grid-template-columns:minmax(0,1fr) auto auto auto;grid-template-areas:\"info stepper prices void\";gap:var(--pos-space-md)}}@media(prefers-reduced-motion:reduce){.pos-basket__clear{transform:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
190
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosBasket, isStandalone: true, selector: "pos-basket", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, totals: { classPropertyName: "totals", publicName: "totals", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-basket" }, ngImport: i0, template: "<section\r\n class=\"pos-basket__panel\"\r\n [class.pos-basket__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-basket__header\">\r\n <h2 class=\"pos-basket__title\">{{ title() }}</h2>\r\n <p class=\"pos-basket__count\">\r\n {{ lines().length }}\r\n {{ lines().length === 1 ? 'line' : 'lines' }}\r\n </p>\r\n </header>\r\n\r\n <ul class=\"pos-basket__lines\" aria-label=\"Basket lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-basket__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-basket__line\"\r\n [class.pos-basket__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-basket__line-info\">\r\n <h3 class=\"pos-basket__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-basket__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-basket__line-voided\">Voided</p>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-basket__stepper\"\r\n role=\"group\"\r\n [attr.aria-label]=\"'Quantity for ' + line.name\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Decrease quantity\"\r\n [disabled]=\"!canDecrement(line)\"\r\n (click)=\"onDecrement(line)\"\r\n >\r\n \u2212\r\n </button>\r\n <span class=\"pos-basket__qty\" aria-live=\"polite\">{{ line.qty }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Increase quantity\"\r\n [disabled]=\"!canChangeQuantity(line)\"\r\n (click)=\"onIncrement(line)\"\r\n >\r\n +\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-basket__line-prices\">\r\n <p class=\"pos-basket__unit-price\">{{ formatMoney(line.unitPrice) }}</p>\r\n <p class=\"pos-basket__line-total\">{{ formatMoney(line.lineTotal) }}</p>\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__void\"\r\n [attr.aria-label]=\"'Void ' + line.name\"\r\n [disabled]=\"!canVoid(line)\"\r\n (click)=\"onVoid(line)\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M6 6l12 12M18 6 6 18\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <footer class=\"pos-basket__footer\">\r\n <dl class=\"pos-basket__totals\" aria-live=\"polite\">\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row pos-basket__total-row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n </footer>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-basket__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-basket__panel--bordered{border:1px solid var(--pos-color-border)}.pos-basket__header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin-bottom:var(--pos-space-md)}.pos-basket__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-tight)}.pos-basket__count{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-basket__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:0;padding:0;overflow-y:auto;list-style:none}.pos-basket__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-basket__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info void\" \"stepper prices\";align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-basket__line-info{grid-area:info;min-width:0}.pos-basket__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-basket__line-sku,.pos-basket__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-basket__line-sku{color:var(--pos-color-text-muted)}.pos-basket__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-basket__stepper{grid-area:stepper;display:inline-flex;align-items:center;gap:var(--pos-space-xs);width:fit-content;padding:var(--pos-space-xs);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface)}.pos-basket__qty-btn,.pos-basket__void{display:inline-flex;align-items:center;justify-content:center;margin:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__qty-btn{min-width:2.75rem;min-height:2.75rem;border-radius:var(--pos-radius-sm);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__qty-btn:not(:disabled):active,.pos-basket__void:not(:disabled):active{background:var(--pos-color-key-active);color:var(--pos-color-on-key-active)}.pos-basket__qty{min-width:1.75rem;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);text-align:center}.pos-basket__line-prices{grid-area:prices;display:flex;flex-direction:column;align-items:flex-end;gap:var(--pos-space-xs)}.pos-basket__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-basket__void{grid-area:void;justify-self:end;min-width:2.75rem;min-height:2.75rem;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);color:var(--pos-color-text-muted)}.pos-basket__qty-btn:disabled,.pos-basket__void:disabled{cursor:not-allowed;opacity:.55}.pos-basket__qty-btn:focus-visible,.pos-basket__void:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-basket__line--voided .pos-basket__line-name,.pos-basket__line--voided .pos-basket__line-sku,.pos-basket__line--voided .pos-basket__line-prices{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-basket__footer{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-basket__totals{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-basket__total-row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__total-row dt,.pos-basket__total-row dd{margin:0}.pos-basket__total-row--due{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}@media(min-width:768px){.pos-basket__panel{padding:var(--pos-space-xl)}.pos-basket__line{grid-template-columns:minmax(0,1fr) auto auto auto;grid-template-areas:\"info stepper prices void\";gap:var(--pos-space-md)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
169
191
  }
170
192
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosBasket, decorators: [{
171
193
  type: Component,
172
194
  args: [{ selector: 'pos-basket', changeDetection: ChangeDetectionStrategy.OnPush, host: {
173
195
  class: 'pos-basket',
174
- }, template: "<section\r\n class=\"pos-basket__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-basket__header\">\r\n <h2 class=\"pos-basket__title\">{{ title() }}</h2>\r\n <p class=\"pos-basket__count\">\r\n {{ lines().length }}\r\n {{ lines().length === 1 ? 'line' : 'lines' }}\r\n </p>\r\n </header>\r\n\r\n <ul class=\"pos-basket__lines\" aria-label=\"Basket lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-basket__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-basket__line\"\r\n [class.pos-basket__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-basket__line-info\">\r\n <h3 class=\"pos-basket__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-basket__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-basket__line-voided\">Voided</p>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-basket__stepper\"\r\n role=\"group\"\r\n [attr.aria-label]=\"'Quantity for ' + line.name\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Decrease quantity\"\r\n [disabled]=\"!canDecrement(line)\"\r\n (click)=\"onDecrement(line)\"\r\n >\r\n \u2212\r\n </button>\r\n <span class=\"pos-basket__qty\" aria-live=\"polite\">{{ line.qty }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Increase quantity\"\r\n [disabled]=\"!canChangeQuantity(line)\"\r\n (click)=\"onIncrement(line)\"\r\n >\r\n +\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-basket__line-prices\">\r\n <p class=\"pos-basket__unit-price\">{{ formatMoney(line.unitPrice) }}</p>\r\n <p class=\"pos-basket__line-total\">{{ formatMoney(line.lineTotal) }}</p>\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__void\"\r\n [attr.aria-label]=\"'Void ' + line.name\"\r\n [disabled]=\"!canVoid(line)\"\r\n (click)=\"onVoid(line)\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M6 6l12 12M18 6 6 18\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <footer class=\"pos-basket__footer\">\r\n <dl class=\"pos-basket__totals\" aria-live=\"polite\">\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row pos-basket__total-row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__clear\"\r\n [disabled]=\"!canClear()\"\r\n (click)=\"onClear()\"\r\n >\r\n {{ clearLabel() }}\r\n </button>\r\n </footer>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-basket__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-basket__header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin-bottom:var(--pos-space-md)}.pos-basket__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em}.pos-basket__count{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-basket__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:0;padding:0;overflow-y:auto;list-style:none}.pos-basket__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-basket__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info void\" \"stepper prices\";align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-basket__line-info{grid-area:info;min-width:0}.pos-basket__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-basket__line-sku,.pos-basket__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-basket__line-sku{color:var(--pos-color-text-muted)}.pos-basket__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-basket__stepper{grid-area:stepper;display:inline-flex;align-items:center;gap:var(--pos-space-xs);width:fit-content;padding:var(--pos-space-xs);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface)}.pos-basket__qty-btn,.pos-basket__void{display:inline-flex;align-items:center;justify-content:center;margin:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__qty-btn{min-width:2.75rem;min-height:2.75rem;border-radius:var(--pos-radius-sm);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__qty-btn:not(:disabled):active,.pos-basket__void:not(:disabled):active{background:var(--pos-color-key-active);color:var(--pos-color-on-key-active)}.pos-basket__qty{min-width:1.75rem;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);text-align:center}.pos-basket__line-prices{grid-area:prices;display:flex;flex-direction:column;align-items:flex-end;gap:var(--pos-space-xs)}.pos-basket__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-basket__void{grid-area:void;justify-self:end;min-width:2.75rem;min-height:2.75rem;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);color:var(--pos-color-text-muted)}.pos-basket__qty-btn:disabled,.pos-basket__void:disabled,.pos-basket__clear:disabled{cursor:not-allowed;opacity:.55}.pos-basket__qty-btn:focus-visible,.pos-basket__void:focus-visible,.pos-basket__clear:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-basket__line--voided .pos-basket__line-name,.pos-basket__line--voided .pos-basket__line-sku,.pos-basket__line--voided .pos-basket__line-prices{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-basket__footer{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-basket__totals{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-basket__total-row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__total-row dt,.pos-basket__total-row dd{margin:0}.pos-basket__total-row--due{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__clear{min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-danger);color:var(--pos-color-on-danger);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__clear:not(:disabled):active{transform:translateY(1px)}.pos-basket__clear:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);transform:none}@media(min-width:768px){.pos-basket__panel{padding:var(--pos-space-xl)}.pos-basket__line{grid-template-columns:minmax(0,1fr) auto auto auto;grid-template-areas:\"info stepper prices void\";gap:var(--pos-space-md)}}@media(prefers-reduced-motion:reduce){.pos-basket__clear{transform:none}}\n"] }]
175
- }], propDecorators: { lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], totals: [{ type: i0.Input, args: [{ isSignal: true, alias: "totals", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
196
+ }, template: "<section\r\n class=\"pos-basket__panel\"\r\n [class.pos-basket__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-basket__header\">\r\n <h2 class=\"pos-basket__title\">{{ title() }}</h2>\r\n <p class=\"pos-basket__count\">\r\n {{ lines().length }}\r\n {{ lines().length === 1 ? 'line' : 'lines' }}\r\n </p>\r\n </header>\r\n\r\n <ul class=\"pos-basket__lines\" aria-label=\"Basket lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-basket__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-basket__line\"\r\n [class.pos-basket__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-basket__line-info\">\r\n <h3 class=\"pos-basket__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-basket__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-basket__line-voided\">Voided</p>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-basket__stepper\"\r\n role=\"group\"\r\n [attr.aria-label]=\"'Quantity for ' + line.name\"\r\n >\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Decrease quantity\"\r\n [disabled]=\"!canDecrement(line)\"\r\n (click)=\"onDecrement(line)\"\r\n >\r\n \u2212\r\n </button>\r\n <span class=\"pos-basket__qty\" aria-live=\"polite\">{{ line.qty }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__qty-btn\"\r\n aria-label=\"Increase quantity\"\r\n [disabled]=\"!canChangeQuantity(line)\"\r\n (click)=\"onIncrement(line)\"\r\n >\r\n +\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-basket__line-prices\">\r\n <p class=\"pos-basket__unit-price\">{{ formatMoney(line.unitPrice) }}</p>\r\n <p class=\"pos-basket__line-total\">{{ formatMoney(line.lineTotal) }}</p>\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"pos-basket__void\"\r\n [attr.aria-label]=\"'Void ' + line.name\"\r\n [disabled]=\"!canVoid(line)\"\r\n (click)=\"onVoid(line)\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n width=\"18\"\r\n height=\"18\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <path\r\n d=\"M6 6l12 12M18 6 6 18\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <footer class=\"pos-basket__footer\">\r\n <dl class=\"pos-basket__totals\" aria-live=\"polite\">\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-basket__total-row pos-basket__total-row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n </footer>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-basket__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-basket__panel--bordered{border:1px solid var(--pos-color-border)}.pos-basket__header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin-bottom:var(--pos-space-md)}.pos-basket__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-tight)}.pos-basket__count{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-basket__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:0;padding:0;overflow-y:auto;list-style:none}.pos-basket__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-basket__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info void\" \"stepper prices\";align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-basket__line-info{grid-area:info;min-width:0}.pos-basket__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-basket__line-sku,.pos-basket__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-basket__line-sku{color:var(--pos-color-text-muted)}.pos-basket__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-basket__stepper{grid-area:stepper;display:inline-flex;align-items:center;gap:var(--pos-space-xs);width:fit-content;padding:var(--pos-space-xs);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface)}.pos-basket__qty-btn,.pos-basket__void{display:inline-flex;align-items:center;justify-content:center;margin:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-basket__qty-btn{min-width:2.75rem;min-height:2.75rem;border-radius:var(--pos-radius-sm);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-basket__qty-btn:not(:disabled):active,.pos-basket__void:not(:disabled):active{background:var(--pos-color-key-active);color:var(--pos-color-on-key-active)}.pos-basket__qty{min-width:1.75rem;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);text-align:center}.pos-basket__line-prices{grid-area:prices;display:flex;flex-direction:column;align-items:flex-end;gap:var(--pos-space-xs)}.pos-basket__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-basket__void{grid-area:void;justify-self:end;min-width:2.75rem;min-height:2.75rem;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);color:var(--pos-color-text-muted)}.pos-basket__qty-btn:disabled,.pos-basket__void:disabled{cursor:not-allowed;opacity:.55}.pos-basket__qty-btn:focus-visible,.pos-basket__void:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-basket__line--voided .pos-basket__line-name,.pos-basket__line--voided .pos-basket__line-sku,.pos-basket__line--voided .pos-basket__line-prices{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-basket__footer{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-basket__totals{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-basket__total-row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-basket__total-row dt,.pos-basket__total-row dd{margin:0}.pos-basket__total-row--due{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}@media(min-width:768px){.pos-basket__panel{padding:var(--pos-space-xl)}.pos-basket__line{grid-template-columns:minmax(0,1fr) auto auto auto;grid-template-areas:\"info stepper prices void\";gap:var(--pos-space-md)}}\n"] }]
197
+ }], propDecorators: { lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], totals: [{ type: i0.Input, args: [{ isSignal: true, alias: "totals", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
198
+
199
+ class PosHeader {
200
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
201
+ context = input('', ...(ngDevMode ? [{ debugName: "context" }] : /* istanbul ignore next */ []));
202
+ /** When false, the brand image is omitted, including the built-in mark. */
203
+ showBrandImage = input(true, ...(ngDevMode ? [{ debugName: "showBrandImage" }] : /* istanbul ignore next */ []));
204
+ /** Partner image URL. Empty, while `showBrandImage` is true, uses the built-in Retalia mark. */
205
+ brandImage = input('', ...(ngDevMode ? [{ debugName: "brandImage" }] : /* istanbul ignore next */ []));
206
+ /** Wordmark after the image. Empty shows no text. */
207
+ brandLabel = input('', ...(ngDevMode ? [{ debugName: "brandLabel" }] : /* istanbul ignore next */ []));
208
+ clerkName = input('', ...(ngDevMode ? [{ debugName: "clerkName" }] : /* istanbul ignore next */ []));
209
+ clerkRole = input('', ...(ngDevMode ? [{ debugName: "clerkRole" }] : /* istanbul ignore next */ []));
210
+ signOutLabel = input('Portal Logout', ...(ngDevMode ? [{ debugName: "signOutLabel" }] : /* istanbul ignore next */ []));
211
+ menuLabel = input('Menu', ...(ngDevMode ? [{ debugName: "menuLabel" }] : /* istanbul ignore next */ []));
212
+ canSignOut = input(true, ...(ngDevMode ? [{ debugName: "canSignOut" }] : /* istanbul ignore next */ []));
213
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
214
+ action = output();
215
+ menuOpen = signal(false, ...(ngDevMode ? [{ debugName: "menuOpen" }] : /* istanbul ignore next */ []));
216
+ initial = computed(() => {
217
+ const name = this.clerkName().trim();
218
+ return name ? name.charAt(0).toUpperCase() : '';
219
+ }, ...(ngDevMode ? [{ debugName: "initial" }] : /* istanbul ignore next */ []));
220
+ toggleMenu() {
221
+ if (this.disabled() || !this.canSignOut()) {
222
+ return;
223
+ }
224
+ this.menuOpen.update((open) => !open);
225
+ }
226
+ closeMenu() {
227
+ this.menuOpen.set(false);
228
+ }
229
+ onSignOut() {
230
+ if (this.disabled() || !this.canSignOut()) {
231
+ return;
232
+ }
233
+ this.menuOpen.set(false);
234
+ this.action.emit({ type: 'header.signOut' });
235
+ }
236
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
237
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosHeader, isStandalone: true, selector: "pos-header", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, showBrandImage: { classPropertyName: "showBrandImage", publicName: "showBrandImage", isSignal: true, isRequired: false, transformFunction: null }, brandImage: { classPropertyName: "brandImage", publicName: "brandImage", isSignal: true, isRequired: false, transformFunction: null }, brandLabel: { classPropertyName: "brandLabel", publicName: "brandLabel", isSignal: true, isRequired: false, transformFunction: null }, clerkName: { classPropertyName: "clerkName", publicName: "clerkName", isSignal: true, isRequired: false, transformFunction: null }, clerkRole: { classPropertyName: "clerkRole", publicName: "clerkRole", isSignal: true, isRequired: false, transformFunction: null }, signOutLabel: { classPropertyName: "signOutLabel", publicName: "signOutLabel", isSignal: true, isRequired: false, transformFunction: null }, menuLabel: { classPropertyName: "menuLabel", publicName: "menuLabel", isSignal: true, isRequired: false, transformFunction: null }, canSignOut: { classPropertyName: "canSignOut", publicName: "canSignOut", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { attributes: { "role": "banner" }, classAttribute: "pos-header" }, ngImport: i0, template: "<div class=\"pos-header__identity\">\r\n @if (showBrandImage() || brandLabel()) {\r\n <div class=\"pos-header__brand\">\r\n @if (showBrandImage()) {\r\n @if (brandImage()) {\r\n <img\r\n class=\"pos-header__brand-image\"\r\n [src]=\"brandImage()\"\r\n [alt]=\"brandLabel() ? '' : 'Brand'\"\r\n />\r\n } @else {\r\n <svg\r\n class=\"pos-header__brand-image\"\r\n viewBox=\"492.40 241.70 51.34 54.94\"\r\n [attr.aria-hidden]=\"brandLabel() ? true : null\"\r\n [attr.aria-label]=\"brandLabel() ? null : 'Retalia'\"\r\n >\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 522.628906 291.910156 C 522.636719 293.0625 523.441406 293.511719 524.425781 292.914062 L 540.464844 283.207031 C 541.449219 282.613281 542.246094 281.195312 542.246094 280.046875 L 542.246094 261.132812 C 542.246094 259.980469 541.441406 259.523438 540.453125 260.113281 L 524.292969 269.691406 C 523.300781 270.277344 522.503906 271.683594 522.511719 272.835938 Z M 522.628906 291.910156\"\r\n />\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 539.097656 253.351562 L 517.101562 243.664062 C 516.066406 243.203125 514.417969 243.265625 513.421875 243.804688 L 495.835938 253.308594 C 494.839844 253.847656 494.027344 255.214844 494.023438 256.367188 L 493.910156 280.140625 C 493.902344 281.292969 494.699219 282.679688 495.683594 283.234375 L 501.734375 286.640625 C 502.71875 287.199219 503.503906 286.71875 503.480469 285.566406 L 503.214844 271.488281 C 503.207031 271.082031 503.492188 270.894531 503.855469 271.066406 L 506.128906 272.148438 C 507.152344 272.636719 507.980469 273.960938 507.980469 275.113281 L 507.980469 287.839844 C 507.980469 288.992188 508.773438 290.394531 509.746094 290.972656 L 515.777344 294.5625 C 516.753906 295.140625 517.554688 294.679688 517.566406 293.527344 L 517.800781 273.300781 C 517.808594 272.488281 517.539062 271.238281 517.195312 270.503906 L 515.460938 266.789062 C 515.292969 266.421875 515.476562 266.109375 515.871094 266.089844 L 518.925781 265.941406 C 520.050781 265.886719 521.761719 265.378906 522.738281 264.808594 L 539.195312 255.21875 C 540.175781 254.648438 540.132812 253.8125 539.097656 253.351562 M 520.609375 255.050781 L 518.019531 256.585938 C 516.914062 257.125 515.734375 257.289062 514.710938 256.804688 L 511.078125 255.101562 C 510.054688 254.621094 510.023438 253.773438 511.003906 253.210938 L 513.835938 251.597656 C 514.53125 251.203125 515.691406 251.132812 516.425781 251.445312 L 520.449219 253.128906 C 521.488281 253.570312 521.5625 254.429688 520.609375 255.050781\"\r\n />\r\n </svg>\r\n }\r\n }\r\n @if (brandLabel()) {\r\n <span class=\"pos-header__brand-label\">{{ brandLabel() }}</span>\r\n }\r\n </div>\r\n }\r\n @if (title()) {\r\n <h1 class=\"pos-header__title\">{{ title() }}</h1>\r\n }\r\n @if (context()) {\r\n <p class=\"pos-header__context\">{{ context() }}</p>\r\n }\r\n</div>\r\n\r\n<div class=\"pos-header__session\">\r\n @if (clerkName()) {\r\n <div class=\"pos-header__clerk\">\r\n @if (canSignOut()) {\r\n <div class=\"pos-header__menu-anchor\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__menu-button\"\r\n [attr.aria-label]=\"menuLabel()\"\r\n [attr.aria-expanded]=\"menuOpen()\"\r\n aria-haspopup=\"menu\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"toggleMenu()\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\r\n <circle cx=\"5\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"12\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"19\" cy=\"12\" r=\"1.6\" />\r\n </svg>\r\n </button>\r\n </div>\r\n }\r\n <span class=\"pos-header__avatar\" aria-hidden=\"true\">{{ initial() }}</span>\r\n <span class=\"pos-header__clerk-text\">\r\n <span class=\"pos-header__clerk-name\">{{ clerkName() }}</span>\r\n @if (clerkRole()) {\r\n <span class=\"pos-header__clerk-role\">{{ clerkRole() }}</span>\r\n }\r\n </span>\r\n </div>\r\n }\r\n @if (menuOpen()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__backdrop\"\r\n aria-label=\"Close menu\"\r\n (click)=\"closeMenu()\"\r\n ></button>\r\n <div class=\"pos-header__menu\" role=\"menu\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__logout\"\r\n role=\"menuitem\"\r\n (click)=\"onSignOut()\"\r\n >\r\n {{ signOutLabel() }}\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--pos-space-sm) var(--pos-space-md);box-sizing:border-box;width:100%;min-width:0;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-header__identity,.pos-header__session{display:flex;flex-wrap:wrap;align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);min-width:0}.pos-header__session{position:relative;margin-left:auto}.pos-header__brand{display:flex;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-header__brand-image{flex:0 0 auto;width:auto;height:var(--pos-space-xl);color:var(--pos-color-ink)}.pos-header__brand-label{font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-brand)}.pos-header__title{margin:0;font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold)}.pos-header__context{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-header__clerk{display:flex;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-header__avatar{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);border-radius:var(--pos-radius-pill);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-header__clerk-text{display:flex;flex-direction:column;min-width:0}.pos-header__clerk-name{font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-header__clerk-role{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);line-height:1.2;text-transform:lowercase}.pos-header__menu-anchor{position:relative;flex:0 0 auto}.pos-header__menu-button{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);padding:0;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-pill);background:var(--pos-color-surface);color:var(--pos-color-text-muted);cursor:pointer}.pos-header__menu-button svg{width:1.25rem;height:1.25rem;fill:currentColor}.pos-header__menu-button:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:default}.pos-header__backdrop{position:fixed;inset:0;z-index:1;border:0;background:transparent;cursor:default}.pos-header__menu{position:absolute;top:calc(100% + var(--pos-space-xs));right:0;z-index:2;box-sizing:border-box;width:16rem;padding:var(--pos-space-sm);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface);box-shadow:var(--pos-shadow-overlay)}.pos-header__logout{display:flex;align-items:center;width:100%;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-md);border:0;border-radius:var(--pos-radius-md);background:transparent;color:var(--pos-color-danger);font:inherit;font-weight:var(--pos-font-weight-semibold);text-align:left;cursor:pointer}.pos-header__logout:hover{background:color-mix(in srgb,var(--pos-color-danger) 12%,var(--pos-color-surface))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
238
+ }
239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosHeader, decorators: [{
240
+ type: Component,
241
+ args: [{ selector: 'pos-header', changeDetection: ChangeDetectionStrategy.OnPush, host: {
242
+ class: 'pos-header',
243
+ role: 'banner',
244
+ }, template: "<div class=\"pos-header__identity\">\r\n @if (showBrandImage() || brandLabel()) {\r\n <div class=\"pos-header__brand\">\r\n @if (showBrandImage()) {\r\n @if (brandImage()) {\r\n <img\r\n class=\"pos-header__brand-image\"\r\n [src]=\"brandImage()\"\r\n [alt]=\"brandLabel() ? '' : 'Brand'\"\r\n />\r\n } @else {\r\n <svg\r\n class=\"pos-header__brand-image\"\r\n viewBox=\"492.40 241.70 51.34 54.94\"\r\n [attr.aria-hidden]=\"brandLabel() ? true : null\"\r\n [attr.aria-label]=\"brandLabel() ? null : 'Retalia'\"\r\n >\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 522.628906 291.910156 C 522.636719 293.0625 523.441406 293.511719 524.425781 292.914062 L 540.464844 283.207031 C 541.449219 282.613281 542.246094 281.195312 542.246094 280.046875 L 542.246094 261.132812 C 542.246094 259.980469 541.441406 259.523438 540.453125 260.113281 L 524.292969 269.691406 C 523.300781 270.277344 522.503906 271.683594 522.511719 272.835938 Z M 522.628906 291.910156\"\r\n />\r\n <path\r\n fill=\"currentColor\"\r\n d=\"M 539.097656 253.351562 L 517.101562 243.664062 C 516.066406 243.203125 514.417969 243.265625 513.421875 243.804688 L 495.835938 253.308594 C 494.839844 253.847656 494.027344 255.214844 494.023438 256.367188 L 493.910156 280.140625 C 493.902344 281.292969 494.699219 282.679688 495.683594 283.234375 L 501.734375 286.640625 C 502.71875 287.199219 503.503906 286.71875 503.480469 285.566406 L 503.214844 271.488281 C 503.207031 271.082031 503.492188 270.894531 503.855469 271.066406 L 506.128906 272.148438 C 507.152344 272.636719 507.980469 273.960938 507.980469 275.113281 L 507.980469 287.839844 C 507.980469 288.992188 508.773438 290.394531 509.746094 290.972656 L 515.777344 294.5625 C 516.753906 295.140625 517.554688 294.679688 517.566406 293.527344 L 517.800781 273.300781 C 517.808594 272.488281 517.539062 271.238281 517.195312 270.503906 L 515.460938 266.789062 C 515.292969 266.421875 515.476562 266.109375 515.871094 266.089844 L 518.925781 265.941406 C 520.050781 265.886719 521.761719 265.378906 522.738281 264.808594 L 539.195312 255.21875 C 540.175781 254.648438 540.132812 253.8125 539.097656 253.351562 M 520.609375 255.050781 L 518.019531 256.585938 C 516.914062 257.125 515.734375 257.289062 514.710938 256.804688 L 511.078125 255.101562 C 510.054688 254.621094 510.023438 253.773438 511.003906 253.210938 L 513.835938 251.597656 C 514.53125 251.203125 515.691406 251.132812 516.425781 251.445312 L 520.449219 253.128906 C 521.488281 253.570312 521.5625 254.429688 520.609375 255.050781\"\r\n />\r\n </svg>\r\n }\r\n }\r\n @if (brandLabel()) {\r\n <span class=\"pos-header__brand-label\">{{ brandLabel() }}</span>\r\n }\r\n </div>\r\n }\r\n @if (title()) {\r\n <h1 class=\"pos-header__title\">{{ title() }}</h1>\r\n }\r\n @if (context()) {\r\n <p class=\"pos-header__context\">{{ context() }}</p>\r\n }\r\n</div>\r\n\r\n<div class=\"pos-header__session\">\r\n @if (clerkName()) {\r\n <div class=\"pos-header__clerk\">\r\n @if (canSignOut()) {\r\n <div class=\"pos-header__menu-anchor\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__menu-button\"\r\n [attr.aria-label]=\"menuLabel()\"\r\n [attr.aria-expanded]=\"menuOpen()\"\r\n aria-haspopup=\"menu\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"toggleMenu()\"\r\n >\r\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\r\n <circle cx=\"5\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"12\" cy=\"12\" r=\"1.6\" />\r\n <circle cx=\"19\" cy=\"12\" r=\"1.6\" />\r\n </svg>\r\n </button>\r\n </div>\r\n }\r\n <span class=\"pos-header__avatar\" aria-hidden=\"true\">{{ initial() }}</span>\r\n <span class=\"pos-header__clerk-text\">\r\n <span class=\"pos-header__clerk-name\">{{ clerkName() }}</span>\r\n @if (clerkRole()) {\r\n <span class=\"pos-header__clerk-role\">{{ clerkRole() }}</span>\r\n }\r\n </span>\r\n </div>\r\n }\r\n @if (menuOpen()) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__backdrop\"\r\n aria-label=\"Close menu\"\r\n (click)=\"closeMenu()\"\r\n ></button>\r\n <div class=\"pos-header__menu\" role=\"menu\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-header__logout\"\r\n role=\"menuitem\"\r\n (click)=\"onSignOut()\"\r\n >\r\n {{ signOutLabel() }}\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--pos-space-sm) var(--pos-space-md);box-sizing:border-box;width:100%;min-width:0;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-header__identity,.pos-header__session{display:flex;flex-wrap:wrap;align-items:center;gap:var(--pos-space-sm) var(--pos-space-md);min-width:0}.pos-header__session{position:relative;margin-left:auto}.pos-header__brand{display:flex;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-header__brand-image{flex:0 0 auto;width:auto;height:var(--pos-space-xl);color:var(--pos-color-ink)}.pos-header__brand-label{font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-brand)}.pos-header__title{margin:0;font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold)}.pos-header__context{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-header__clerk{display:flex;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-header__avatar{display:inline-flex;flex:0 0 auto;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);border-radius:var(--pos-radius-pill);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-header__clerk-text{display:flex;flex-direction:column;min-width:0}.pos-header__clerk-name{font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-header__clerk-role{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);line-height:1.2;text-transform:lowercase}.pos-header__menu-anchor{position:relative;flex:0 0 auto}.pos-header__menu-button{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);padding:0;border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-pill);background:var(--pos-color-surface);color:var(--pos-color-text-muted);cursor:pointer}.pos-header__menu-button svg{width:1.25rem;height:1.25rem;fill:currentColor}.pos-header__menu-button:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:default}.pos-header__backdrop{position:fixed;inset:0;z-index:1;border:0;background:transparent;cursor:default}.pos-header__menu{position:absolute;top:calc(100% + var(--pos-space-xs));right:0;z-index:2;box-sizing:border-box;width:16rem;padding:var(--pos-space-sm);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-surface);box-shadow:var(--pos-shadow-overlay)}.pos-header__logout{display:flex;align-items:center;width:100%;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-md);border:0;border-radius:var(--pos-radius-md);background:transparent;color:var(--pos-color-danger);font:inherit;font-weight:var(--pos-font-weight-semibold);text-align:left;cursor:pointer}.pos-header__logout:hover{background:color-mix(in srgb,var(--pos-color-danger) 12%,var(--pos-color-surface))}\n"] }]
245
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], showBrandImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBrandImage", required: false }] }], brandImage: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandImage", required: false }] }], brandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabel", required: false }] }], clerkName: [{ type: i0.Input, args: [{ isSignal: true, alias: "clerkName", required: false }] }], clerkRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "clerkRole", required: false }] }], signOutLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "signOutLabel", required: false }] }], menuLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuLabel", required: false }] }], canSignOut: [{ type: i0.Input, args: [{ isSignal: true, alias: "canSignOut", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
246
+
247
+ class PosTransactionActionBar {
248
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTransactionActionBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
249
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.22", type: PosTransactionActionBar, isStandalone: true, selector: "pos-transaction-action-bar", host: { classAttribute: "pos-transaction-action-bar" }, ngImport: i0, template: "<ng-content />\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:stretch;gap:var(--pos-space-sm);width:100%;box-sizing:border-box}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
250
+ }
251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTransactionActionBar, decorators: [{
252
+ type: Component,
253
+ args: [{ selector: 'pos-transaction-action-bar', changeDetection: ChangeDetectionStrategy.OnPush, host: {
254
+ class: 'pos-transaction-action-bar',
255
+ }, template: "<ng-content />\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:stretch;gap:var(--pos-space-sm);width:100%;box-sizing:border-box}\n"] }]
256
+ }] });
176
257
 
177
258
  class PosItemEntry {
178
259
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
260
+ /** Draws the panel frame. Off by default so the host can sit the field flush. */
261
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
179
262
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
180
263
  autofocus = input(true, ...(ngDevMode ? [{ debugName: "autofocus" }] : /* istanbul ignore next */ []));
181
264
  label = input('Item', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
182
- placeholder = input('Scan or enter item', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
183
- addLabel = input('Add', ...(ngDevMode ? [{ debugName: "addLabel" }] : /* istanbul ignore next */ []));
265
+ placeholder = input('Scan barcode, search products', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
266
+ scannerStatus = input('scanner ready', ...(ngDevMode ? [{ debugName: "scannerStatus" }] : /* istanbul ignore next */ []));
267
+ /** Key that moves focus to the field. Empty hides the hint and the shortcut. */
268
+ focusHotkey = input('F2', ...(ngDevMode ? [{ debugName: "focusHotkey" }] : /* istanbul ignore next */ []));
184
269
  action = output();
185
270
  itemInput = viewChild('itemInput', ...(ngDevMode ? [{ debugName: "itemInput" }] : /* istanbul ignore next */ []));
186
271
  reference = signal('', ...(ngDevMode ? [{ debugName: "reference" }] : /* istanbul ignore next */ []));
@@ -192,6 +277,20 @@ class PosItemEntry {
192
277
  }
193
278
  });
194
279
  }
280
+ onDocumentKeydown(event) {
281
+ const hotkey = this.focusHotkey();
282
+ if (!hotkey || event.key !== hotkey || event.repeat) {
283
+ return;
284
+ }
285
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
286
+ return;
287
+ }
288
+ if (this.disabled()) {
289
+ return;
290
+ }
291
+ event.preventDefault();
292
+ this.focusInput();
293
+ }
195
294
  onInput(event) {
196
295
  const target = event.target;
197
296
  if (!(target instanceof HTMLInputElement)) {
@@ -201,13 +300,10 @@ class PosItemEntry {
201
300
  }
202
301
  onSubmit(event) {
203
302
  event.preventDefault();
204
- if (this.disabled()) {
303
+ if (!this.canSubmit()) {
205
304
  return;
206
305
  }
207
306
  const reference = this.reference().trim();
208
- if (!reference) {
209
- return;
210
- }
211
307
  this.action.emit({ type: 'itemEntry.submit', reference });
212
308
  this.reference.set('');
213
309
  this.focusInput();
@@ -216,60 +312,23 @@ class PosItemEntry {
216
312
  this.itemInput()?.nativeElement.focus();
217
313
  }
218
314
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosItemEntry, deps: [], target: i0.ɵɵFactoryTarget.Component });
219
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosItemEntry, isStandalone: true, selector: "pos-item-entry", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, addLabel: { classPropertyName: "addLabel", publicName: "addLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-item-entry" }, viewQueries: [{ propertyName: "itemInput", first: true, predicate: ["itemInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<section\r\n class=\"pos-item-entry__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <form class=\"pos-item-entry__form\" (submit)=\"onSubmit($event)\">\r\n <label class=\"pos-item-entry__field\">\r\n <span class=\"pos-item-entry__label\">{{ label() }}</span>\r\n <input\r\n #itemInput\r\n class=\"pos-item-entry__input\"\r\n type=\"text\"\r\n name=\"itemReference\"\r\n autocomplete=\"off\"\r\n spellcheck=\"false\"\r\n [attr.autocorrect]=\"'off'\"\r\n [attr.autocapitalize]=\"'none'\"\r\n enterkeyhint=\"done\"\r\n [placeholder]=\"placeholder()\"\r\n [value]=\"reference()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\r\n (input)=\"onInput($event)\"\r\n />\r\n </label>\r\n\r\n <button\r\n type=\"submit\"\r\n class=\"pos-item-entry__add\"\r\n [class.pos-item-entry__add--disabled]=\"!canSubmit()\"\r\n [disabled]=\"!canSubmit()\"\r\n >\r\n {{ addLabel() }}\r\n </button>\r\n </form>\r\n\r\n <div class=\"pos-item-entry__status\" aria-live=\"polite\">\r\n @if (errorMessage()) {\r\n <p class=\"pos-item-entry__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-item-entry__panel{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-item-entry__form{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-item-entry__field{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-xs);min-width:0}.pos-item-entry__label{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-item-entry__input{box-sizing:border-box;width:100%;min-height:var(--pos-button-min-height);margin:0;padding:0 var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated);color:var(--pos-color-text);font:inherit;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-semibold);outline:none}.pos-item-entry__input::placeholder{color:var(--pos-color-text-muted);font-weight:var(--pos-font-weight-semibold);opacity:.8}.pos-item-entry__input:disabled{cursor:not-allowed;background:var(--pos-color-disabled);color:var(--pos-color-on-disabled)}.pos-item-entry__input[aria-invalid=true]{border-color:var(--pos-color-danger)}.pos-item-entry__add{flex:0 0 auto;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-xl);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-item-entry__add:not(:disabled):active{transform:translateY(1px)}.pos-item-entry__add--disabled,.pos-item-entry__add:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-item-entry__input:focus-visible{border-color:var(--pos-color-primary);outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-item-entry__add:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-item-entry__status{min-height:0}.pos-item-entry__error{margin:0;padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:color-mix(in srgb,var(--pos-color-danger) 12%,transparent);color:var(--pos-color-danger);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}@media(min-width:768px){.pos-item-entry__panel{padding:var(--pos-space-xl)}.pos-item-entry__form{flex-direction:row;align-items:flex-end;gap:var(--pos-space-md)}.pos-item-entry__add{min-width:7.5rem}}@media(prefers-reduced-motion:reduce){.pos-item-entry__add{transform:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
315
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosItemEntry, isStandalone: true, selector: "pos-item-entry", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, autofocus: { classPropertyName: "autofocus", publicName: "autofocus", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, scannerStatus: { classPropertyName: "scannerStatus", publicName: "scannerStatus", isSignal: true, isRequired: false, transformFunction: null }, focusHotkey: { classPropertyName: "focusHotkey", publicName: "focusHotkey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { listeners: { "document:keydown": "onDocumentKeydown($event)" }, classAttribute: "pos-item-entry" }, viewQueries: [{ propertyName: "itemInput", first: true, predicate: ["itemInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<section\r\n class=\"pos-item-entry__panel\"\r\n [class.pos-item-entry__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <form class=\"pos-item-entry__form\" (submit)=\"onSubmit($event)\">\r\n <div\r\n class=\"pos-item-entry__omnibox\"\r\n [class.pos-item-entry__omnibox--disabled]=\"disabled()\"\r\n >\r\n <label class=\"pos-item-entry__field\">\r\n <span class=\"pos-item-entry__label\">{{ label() }}</span>\r\n <svg\r\n class=\"pos-item-entry__search\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\r\n </svg>\r\n <input\r\n #itemInput\r\n class=\"pos-item-entry__input\"\r\n type=\"text\"\r\n name=\"itemReference\"\r\n autocomplete=\"off\"\r\n spellcheck=\"false\"\r\n [attr.autocorrect]=\"'off'\"\r\n [attr.autocapitalize]=\"'none'\"\r\n enterkeyhint=\"done\"\r\n [placeholder]=\"placeholder()\"\r\n [value]=\"reference()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\r\n [attr.aria-keyshortcuts]=\"focusHotkey() || null\"\r\n (input)=\"onInput($event)\"\r\n />\r\n </label>\r\n\r\n <span class=\"pos-item-entry__scanner\">\r\n <svg\r\n class=\"pos-item-entry__scan\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <line x1=\"4\" y1=\"6\" x2=\"4\" y2=\"18\" />\r\n <line x1=\"7\" y1=\"6\" x2=\"7\" y2=\"18\" />\r\n <line x1=\"11\" y1=\"6\" x2=\"11\" y2=\"18\" />\r\n <line x1=\"14\" y1=\"6\" x2=\"14\" y2=\"18\" />\r\n <line x1=\"18\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n <line x1=\"21\" y1=\"6\" x2=\"21\" y2=\"18\" />\r\n </svg>\r\n {{ scannerStatus() }}\r\n </span>\r\n\r\n @if (focusHotkey()) {\r\n <kbd class=\"pos-item-entry__hotkey\">{{ focusHotkey() }}</kbd>\r\n }\r\n </div>\r\n </form>\r\n\r\n <div class=\"pos-item-entry__status\" aria-live=\"polite\">\r\n @if (errorMessage()) {\r\n <p class=\"pos-item-entry__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-item-entry__panel{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-item-entry__panel--bordered{padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-item-entry__form{min-width:0}.pos-item-entry__omnibox{display:flex;align-items:center;gap:var(--pos-space-sm);box-sizing:border-box;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-md) 0 var(--pos-space-lg);border:1px solid transparent;border-radius:var(--pos-radius-pill);background:var(--pos-color-surface-muted);transition:border-color .12s ease,box-shadow .12s ease,background-color .12s ease}.pos-item-entry__omnibox:focus-within{border-color:var(--pos-color-primary);background:var(--pos-color-surface);box-shadow:0 0 0 3px color-mix(in srgb,var(--pos-color-primary) 35%,transparent)}.pos-item-entry__omnibox:has(.pos-item-entry__input[aria-invalid=true]){border-color:var(--pos-color-danger)}.pos-item-entry__omnibox--disabled{cursor:not-allowed;background:var(--pos-color-disabled)}.pos-item-entry__field{display:flex;flex:1 1 auto;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-item-entry__label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pos-item-entry__search,.pos-item-entry__scan{flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.pos-item-entry__search{width:15px;height:15px;color:var(--pos-color-text-muted)}.pos-item-entry__input{box-sizing:border-box;flex:1 1 auto;width:100%;min-width:0;min-height:calc(var(--pos-button-min-height) - 8px);margin:0;padding:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;outline:none}.pos-item-entry__input::placeholder{color:var(--pos-color-text-muted);opacity:1}.pos-item-entry__input:disabled{cursor:not-allowed;color:var(--pos-color-on-disabled)}.pos-item-entry__scanner{display:inline-flex;flex:0 0 auto;align-items:center;gap:var(--pos-space-xs);padding:2px var(--pos-space-sm);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-sm);background:var(--pos-color-surface);color:var(--pos-color-text-muted);font-size:.72em;line-height:1.2;white-space:nowrap}.pos-item-entry__omnibox--disabled .pos-item-entry__scanner{color:var(--pos-color-on-disabled)}.pos-item-entry__scan{width:11px;height:11px}.pos-item-entry__hotkey{flex:0 0 auto;margin:0;padding:0;border:0;background:transparent;color:var(--pos-color-text-muted);font-family:inherit;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);line-height:1}.pos-item-entry__status{min-height:0}.pos-item-entry__error{margin:0;padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:color-mix(in srgb,var(--pos-color-danger) 12%,transparent);color:var(--pos-color-danger);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}@media(max-width:479px){.pos-item-entry__hotkey{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}}@media(min-width:768px){.pos-item-entry__panel--bordered{padding:var(--pos-space-xl)}}@media(prefers-reduced-motion:reduce){.pos-item-entry__omnibox{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
220
316
  }
221
317
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosItemEntry, decorators: [{
222
318
  type: Component,
223
319
  args: [{ selector: 'pos-item-entry', changeDetection: ChangeDetectionStrategy.OnPush, host: {
224
320
  class: 'pos-item-entry',
225
- }, template: "<section\r\n class=\"pos-item-entry__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <form class=\"pos-item-entry__form\" (submit)=\"onSubmit($event)\">\r\n <label class=\"pos-item-entry__field\">\r\n <span class=\"pos-item-entry__label\">{{ label() }}</span>\r\n <input\r\n #itemInput\r\n class=\"pos-item-entry__input\"\r\n type=\"text\"\r\n name=\"itemReference\"\r\n autocomplete=\"off\"\r\n spellcheck=\"false\"\r\n [attr.autocorrect]=\"'off'\"\r\n [attr.autocapitalize]=\"'none'\"\r\n enterkeyhint=\"done\"\r\n [placeholder]=\"placeholder()\"\r\n [value]=\"reference()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\r\n (input)=\"onInput($event)\"\r\n />\r\n </label>\r\n\r\n <button\r\n type=\"submit\"\r\n class=\"pos-item-entry__add\"\r\n [class.pos-item-entry__add--disabled]=\"!canSubmit()\"\r\n [disabled]=\"!canSubmit()\"\r\n >\r\n {{ addLabel() }}\r\n </button>\r\n </form>\r\n\r\n <div class=\"pos-item-entry__status\" aria-live=\"polite\">\r\n @if (errorMessage()) {\r\n <p class=\"pos-item-entry__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-item-entry__panel{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-item-entry__form{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-item-entry__field{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-xs);min-width:0}.pos-item-entry__label{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-item-entry__input{box-sizing:border-box;width:100%;min-height:var(--pos-button-min-height);margin:0;padding:0 var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated);color:var(--pos-color-text);font:inherit;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-semibold);outline:none}.pos-item-entry__input::placeholder{color:var(--pos-color-text-muted);font-weight:var(--pos-font-weight-semibold);opacity:.8}.pos-item-entry__input:disabled{cursor:not-allowed;background:var(--pos-color-disabled);color:var(--pos-color-on-disabled)}.pos-item-entry__input[aria-invalid=true]{border-color:var(--pos-color-danger)}.pos-item-entry__add{flex:0 0 auto;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-xl);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-item-entry__add:not(:disabled):active{transform:translateY(1px)}.pos-item-entry__add--disabled,.pos-item-entry__add:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-item-entry__input:focus-visible{border-color:var(--pos-color-primary);outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-item-entry__add:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-item-entry__status{min-height:0}.pos-item-entry__error{margin:0;padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:color-mix(in srgb,var(--pos-color-danger) 12%,transparent);color:var(--pos-color-danger);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}@media(min-width:768px){.pos-item-entry__panel{padding:var(--pos-space-xl)}.pos-item-entry__form{flex-direction:row;align-items:flex-end;gap:var(--pos-space-md)}.pos-item-entry__add{min-width:7.5rem}}@media(prefers-reduced-motion:reduce){.pos-item-entry__add{transform:none}}\n"] }]
226
- }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], addLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "addLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }], itemInput: [{ type: i0.ViewChild, args: ['itemInput', { isSignal: true }] }] } });
321
+ '(document:keydown)': 'onDocumentKeydown($event)',
322
+ }, template: "<section\r\n class=\"pos-item-entry__panel\"\r\n [class.pos-item-entry__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <form class=\"pos-item-entry__form\" (submit)=\"onSubmit($event)\">\r\n <div\r\n class=\"pos-item-entry__omnibox\"\r\n [class.pos-item-entry__omnibox--disabled]=\"disabled()\"\r\n >\r\n <label class=\"pos-item-entry__field\">\r\n <span class=\"pos-item-entry__label\">{{ label() }}</span>\r\n <svg\r\n class=\"pos-item-entry__search\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\r\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\r\n </svg>\r\n <input\r\n #itemInput\r\n class=\"pos-item-entry__input\"\r\n type=\"text\"\r\n name=\"itemReference\"\r\n autocomplete=\"off\"\r\n spellcheck=\"false\"\r\n [attr.autocorrect]=\"'off'\"\r\n [attr.autocapitalize]=\"'none'\"\r\n enterkeyhint=\"done\"\r\n [placeholder]=\"placeholder()\"\r\n [value]=\"reference()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-invalid]=\"errorMessage() ? true : null\"\r\n [attr.aria-keyshortcuts]=\"focusHotkey() || null\"\r\n (input)=\"onInput($event)\"\r\n />\r\n </label>\r\n\r\n <span class=\"pos-item-entry__scanner\">\r\n <svg\r\n class=\"pos-item-entry__scan\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n aria-hidden=\"true\"\r\n >\r\n <line x1=\"4\" y1=\"6\" x2=\"4\" y2=\"18\" />\r\n <line x1=\"7\" y1=\"6\" x2=\"7\" y2=\"18\" />\r\n <line x1=\"11\" y1=\"6\" x2=\"11\" y2=\"18\" />\r\n <line x1=\"14\" y1=\"6\" x2=\"14\" y2=\"18\" />\r\n <line x1=\"18\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n <line x1=\"21\" y1=\"6\" x2=\"21\" y2=\"18\" />\r\n </svg>\r\n {{ scannerStatus() }}\r\n </span>\r\n\r\n @if (focusHotkey()) {\r\n <kbd class=\"pos-item-entry__hotkey\">{{ focusHotkey() }}</kbd>\r\n }\r\n </div>\r\n </form>\r\n\r\n <div class=\"pos-item-entry__status\" aria-live=\"polite\">\r\n @if (errorMessage()) {\r\n <p class=\"pos-item-entry__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-item-entry__panel{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-item-entry__panel--bordered{padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-item-entry__form{min-width:0}.pos-item-entry__omnibox{display:flex;align-items:center;gap:var(--pos-space-sm);box-sizing:border-box;min-height:var(--pos-button-min-height);padding:0 var(--pos-space-md) 0 var(--pos-space-lg);border:1px solid transparent;border-radius:var(--pos-radius-pill);background:var(--pos-color-surface-muted);transition:border-color .12s ease,box-shadow .12s ease,background-color .12s ease}.pos-item-entry__omnibox:focus-within{border-color:var(--pos-color-primary);background:var(--pos-color-surface);box-shadow:0 0 0 3px color-mix(in srgb,var(--pos-color-primary) 35%,transparent)}.pos-item-entry__omnibox:has(.pos-item-entry__input[aria-invalid=true]){border-color:var(--pos-color-danger)}.pos-item-entry__omnibox--disabled{cursor:not-allowed;background:var(--pos-color-disabled)}.pos-item-entry__field{display:flex;flex:1 1 auto;align-items:center;gap:var(--pos-space-sm);min-width:0}.pos-item-entry__label{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pos-item-entry__search,.pos-item-entry__scan{flex:0 0 auto;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.pos-item-entry__search{width:15px;height:15px;color:var(--pos-color-text-muted)}.pos-item-entry__input{box-sizing:border-box;flex:1 1 auto;width:100%;min-width:0;min-height:calc(var(--pos-button-min-height) - 8px);margin:0;padding:0;border:0;background:transparent;color:var(--pos-color-text);font:inherit;outline:none}.pos-item-entry__input::placeholder{color:var(--pos-color-text-muted);opacity:1}.pos-item-entry__input:disabled{cursor:not-allowed;color:var(--pos-color-on-disabled)}.pos-item-entry__scanner{display:inline-flex;flex:0 0 auto;align-items:center;gap:var(--pos-space-xs);padding:2px var(--pos-space-sm);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-sm);background:var(--pos-color-surface);color:var(--pos-color-text-muted);font-size:.72em;line-height:1.2;white-space:nowrap}.pos-item-entry__omnibox--disabled .pos-item-entry__scanner{color:var(--pos-color-on-disabled)}.pos-item-entry__scan{width:11px;height:11px}.pos-item-entry__hotkey{flex:0 0 auto;margin:0;padding:0;border:0;background:transparent;color:var(--pos-color-text-muted);font-family:inherit;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);line-height:1}.pos-item-entry__status{min-height:0}.pos-item-entry__error{margin:0;padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:color-mix(in srgb,var(--pos-color-danger) 12%,transparent);color:var(--pos-color-danger);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}@media(max-width:479px){.pos-item-entry__hotkey{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}}@media(min-width:768px){.pos-item-entry__panel--bordered{padding:var(--pos-space-xl)}}@media(prefers-reduced-motion:reduce){.pos-item-entry__omnibox{transition:none}}\n"] }]
323
+ }], ctorParameters: () => [], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], autofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "autofocus", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], scannerStatus: [{ type: i0.Input, args: [{ isSignal: true, alias: "scannerStatus", required: false }] }], focusHotkey: [{ type: i0.Input, args: [{ isSignal: true, alias: "focusHotkey", required: false }] }], action: [{ type: i0.Output, args: ["action"] }], itemInput: [{ type: i0.ViewChild, args: ['itemInput', { isSignal: true }] }] } });
227
324
 
228
- const KEYPAD_ROWS = [
229
- ['1', '2', '3'],
230
- ['4', '5', '6'],
231
- ['7', '8', '9'],
232
- ['0', '.', '←'],
233
- ];
234
- const MAX_WHOLE_DIGITS = 8;
235
- function parseCashAmount(raw) {
236
- if (!raw) {
237
- return null;
238
- }
239
- const amount = Number(raw);
240
- if (!Number.isFinite(amount) || amount <= 0) {
241
- return null;
242
- }
325
+ const COIN_AMOUNTS = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2];
326
+ const NOTE_AMOUNTS = [5, 10, 20, 50];
327
+ function roundMoney(amount) {
243
328
  return Math.round(amount * 100) / 100;
244
329
  }
245
- function appendCashKey(current, key) {
246
- if (key === '←') {
247
- return current.slice(0, -1);
248
- }
249
- if (key === '.') {
250
- if (current.includes('.')) {
251
- return current;
252
- }
253
- return current === '' ? '0.' : `${current}.`;
254
- }
255
- if (!/^\d$/.test(key)) {
256
- return current;
257
- }
258
- if (current === '0') {
259
- return key;
260
- }
261
- const [whole = '', fraction] = current.split('.');
262
- if (fraction !== undefined) {
263
- if (fraction.length >= 2) {
264
- return current;
265
- }
266
- return current + key;
267
- }
268
- const significant = whole.replace(/^0+/, '');
269
- if (significant.length >= MAX_WHOLE_DIGITS) {
270
- return current;
271
- }
272
- return current + key;
330
+ function roundUp(amount, step) {
331
+ return roundMoney(Math.ceil(amount / step) * step);
273
332
  }
274
333
  class PosTender {
275
334
  /** Display-only amount due from the host envelope — not calculated here. */
@@ -279,19 +338,40 @@ class PosTender {
279
338
  currency = input('EUR', ...(ngDevMode ? [{ debugName: "currency" }] : /* istanbul ignore next */ []));
280
339
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
281
340
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
282
- title = input('Cash tender', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
283
- amountDueLabel = input('Amount due', ...(ngDevMode ? [{ debugName: "amountDueLabel" }] : /* istanbul ignore next */ []));
284
- tenderedLabel = input('Amount tendered', ...(ngDevMode ? [{ debugName: "tenderedLabel" }] : /* istanbul ignore next */ []));
341
+ title = input('Cash Payment', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
342
+ amountDueLabel = input('Remaining', ...(ngDevMode ? [{ debugName: "amountDueLabel" }] : /* istanbul ignore next */ []));
343
+ tenderedLabel = input('Amount given', ...(ngDevMode ? [{ debugName: "tenderedLabel" }] : /* istanbul ignore next */ []));
285
344
  changeDueLabel = input('Change due', ...(ngDevMode ? [{ debugName: "changeDueLabel" }] : /* istanbul ignore next */ []));
286
- tenderLabel = input('Tender cash', ...(ngDevMode ? [{ debugName: "tenderLabel" }] : /* istanbul ignore next */ []));
345
+ tenderLabel = input('Pay Now', ...(ngDevMode ? [{ debugName: "tenderLabel" }] : /* istanbul ignore next */ []));
346
+ cancelLabel = input('Cancel', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
347
+ hint = input('tap coins and notes, or use a quick amount.', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
287
348
  processingLabel = input('Processing tender…', ...(ngDevMode ? [{ debugName: "processingLabel" }] : /* istanbul ignore next */ []));
288
349
  action = output();
289
- keypadRows = KEYPAD_ROWS;
290
- amountInput = signal('', ...(ngDevMode ? [{ debugName: "amountInput" }] : /* istanbul ignore next */ []));
291
- parsedAmount = computed(() => parseCashAmount(this.amountInput()), ...(ngDevMode ? [{ debugName: "parsedAmount" }] : /* istanbul ignore next */ []));
350
+ coins = COIN_AMOUNTS;
351
+ notes = NOTE_AMOUNTS;
352
+ given = signal(0, ...(ngDevMode ? [{ debugName: "given" }] : /* istanbul ignore next */ []));
353
+ parsedAmount = computed(() => {
354
+ const amount = this.given();
355
+ return amount > 0 ? amount : null;
356
+ }, ...(ngDevMode ? [{ debugName: "parsedAmount" }] : /* istanbul ignore next */ []));
292
357
  canTender = computed(() => this.parsedAmount() !== null && !this.disabled(), ...(ngDevMode ? [{ debugName: "canTender" }] : /* istanbul ignore next */ []));
293
358
  hasChangeDue = computed(() => this.changeDue() !== null, ...(ngDevMode ? [{ debugName: "hasChangeDue" }] : /* istanbul ignore next */ []));
294
- displayTendered = computed(() => this.amountInput() || '0', ...(ngDevMode ? [{ debugName: "displayTendered" }] : /* istanbul ignore next */ []));
359
+ displayGiven = computed(() => this.given().toFixed(2), ...(ngDevMode ? [{ debugName: "displayGiven" }] : /* istanbul ignore next */ []));
360
+ quickAmounts = computed(() => {
361
+ const remaining = this.amountDue();
362
+ if (!(remaining > 0)) {
363
+ return [];
364
+ }
365
+ const values = [
366
+ remaining,
367
+ roundUp(remaining, 5),
368
+ roundUp(remaining, 10),
369
+ roundUp(remaining, 20),
370
+ ].map((value) => roundMoney(value));
371
+ return values
372
+ .filter((value, index) => value >= remaining - 0.001 && values.indexOf(value) === index)
373
+ .slice(0, 4);
374
+ }, ...(ngDevMode ? [{ debugName: "quickAmounts" }] : /* istanbul ignore next */ []));
295
375
  statusText = computed(() => {
296
376
  if (this.disabled() && !this.hasChangeDue()) {
297
377
  return this.processingLabel();
@@ -306,11 +386,51 @@ class PosTender {
306
386
  maximumFractionDigits: 2,
307
387
  }).format(amount);
308
388
  }
309
- onKeypad(key) {
389
+ denominationLabel(amount) {
390
+ const currency = (this.currency() || 'EUR').toUpperCase();
391
+ if (amount >= 1) {
392
+ return new Intl.NumberFormat(undefined, {
393
+ style: 'currency',
394
+ currency,
395
+ minimumFractionDigits: 0,
396
+ maximumFractionDigits: 0,
397
+ }).format(amount);
398
+ }
399
+ const minor = Math.round(amount * 100);
400
+ if (currency === 'GBP') {
401
+ return `${minor}p`;
402
+ }
403
+ if (currency === 'EUR') {
404
+ return `${minor}c`;
405
+ }
406
+ return this.formatMoney(amount);
407
+ }
408
+ quickLabel(amount) {
409
+ const formatted = this.formatMoney(amount);
410
+ return roundMoney(amount) === roundMoney(this.amountDue())
411
+ ? `Exact ${formatted}`
412
+ : formatted;
413
+ }
414
+ isExact(amount) {
415
+ return roundMoney(amount) === roundMoney(this.amountDue());
416
+ }
417
+ addAmount(amount) {
310
418
  if (this.disabled()) {
311
419
  return;
312
420
  }
313
- this.amountInput.update((value) => appendCashKey(value, key));
421
+ this.given.update((current) => roundMoney(current + amount));
422
+ }
423
+ setAmount(amount) {
424
+ if (this.disabled()) {
425
+ return;
426
+ }
427
+ this.given.set(roundMoney(amount));
428
+ }
429
+ resetAmount() {
430
+ if (this.disabled()) {
431
+ return;
432
+ }
433
+ this.given.set(0);
314
434
  }
315
435
  onTender() {
316
436
  if (!this.canTender()) {
@@ -322,15 +442,21 @@ class PosTender {
322
442
  }
323
443
  this.action.emit({ type: 'tender.cash', amount });
324
444
  }
445
+ onCancel() {
446
+ if (this.disabled()) {
447
+ return;
448
+ }
449
+ this.action.emit({ type: 'tender.cancel' });
450
+ }
325
451
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTender, deps: [], target: i0.ɵɵFactoryTarget.Component });
326
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosTender, isStandalone: true, selector: "pos-tender", inputs: { amountDue: { classPropertyName: "amountDue", publicName: "amountDue", isSignal: true, isRequired: false, transformFunction: null }, changeDue: { classPropertyName: "changeDue", publicName: "changeDue", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, amountDueLabel: { classPropertyName: "amountDueLabel", publicName: "amountDueLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderedLabel: { classPropertyName: "tenderedLabel", publicName: "tenderedLabel", isSignal: true, isRequired: false, transformFunction: null }, changeDueLabel: { classPropertyName: "changeDueLabel", publicName: "changeDueLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderLabel: { classPropertyName: "tenderLabel", publicName: "tenderLabel", isSignal: true, isRequired: false, transformFunction: null }, processingLabel: { classPropertyName: "processingLabel", publicName: "processingLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-tender" }, ngImport: i0, template: "<section\r\n class=\"pos-tender__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-tender__header\">\r\n <p class=\"pos-tender__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-tender__title\">{{ title() }}</h2>\r\n </header>\r\n\r\n <div class=\"pos-tender__status\" aria-live=\"polite\">\r\n @if (statusText()) {\r\n <p>{{ statusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-tender__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__summary\">\r\n <dl class=\"pos-tender__due\">\r\n <div class=\"pos-tender__row\">\r\n <dt>{{ amountDueLabel() }}</dt>\r\n <dd>{{ formatMoney(amountDue()) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasChangeDue()) {\r\n <div class=\"pos-tender__change\" role=\"status\" aria-live=\"polite\">\r\n <p class=\"pos-tender__change-label\">{{ changeDueLabel() }}</p>\r\n <p class=\"pos-tender__change-value\">\r\n {{ formatMoney(changeDue() ?? 0) }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-tender__display\"\r\n role=\"group\"\r\n [attr.aria-label]=\"tenderedLabel()\"\r\n >\r\n <p class=\"pos-tender__display-label\">{{ tenderedLabel() }}</p>\r\n <p class=\"pos-tender__display-value\" aria-live=\"polite\">\r\n <span class=\"pos-tender__currency\">{{ currency() }}</span>\r\n <span class=\"pos-tender__digits\">{{ displayTendered() }}</span>\r\n </p>\r\n </div>\r\n\r\n <div class=\"pos-tender__keypad\" role=\"group\" aria-label=\"Cash amount keypad\">\r\n @for (row of keypadRows; track $index) {\r\n <div class=\"pos-tender__keypad-row\">\r\n @for (key of row; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__key\"\r\n [class.pos-tender__key--action]=\"key === '\u2190' || key === '.'\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"key === '\u2190' ? 'Backspace' : key === '.' ? 'Decimal point' : key\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__primary\"\r\n [class.pos-tender__primary--disabled]=\"!canTender()\"\r\n [disabled]=\"!canTender()\"\r\n (click)=\"onTender()\"\r\n >\r\n {{ tenderLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;max-width:42rem;min-width:0;container-type:inline-size;container-name:pos-tender;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-tender__panel{min-width:0;display:grid;grid-template-areas:\"header\" \"status\" \"summary\" \"display\" \"keypad\" \"actions\";gap:var(--pos-space-md);padding:var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-tender__header{grid-area:header;display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-tender__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-tender__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em;line-height:1.15}.pos-tender__status{grid-area:status;min-height:1.5rem;display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-tender__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__error{padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:#d6454514;color:var(--pos-color-danger)}.pos-tender__summary{grid-area:summary;display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-tender__due{margin:0}.pos-tender__row{display:flex;justify-content:space-between;align-items:baseline;gap:var(--pos-space-md);margin:0;padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-tender__row dt,.pos-tender__row dd{margin:0}.pos-tender__row dt{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__row dd{font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-tender__display{grid-area:display;min-width:0;padding:var(--pos-space-lg) var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-display);box-shadow:inset 0 1px #ffffff0f}.pos-tender__display-label{margin:0 0 var(--pos-space-sm);color:#e8edf2b3;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:.08em;text-transform:uppercase}.pos-tender__display-value{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-on-display);font-family:var(--pos-font-family-display)}.pos-tender__currency{font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.12em}.pos-tender__digits{min-width:0;overflow-wrap:anywhere;font-size:clamp(1.5rem,4vw,2rem);font-weight:var(--pos-font-weight-semibold);letter-spacing:.04em;font-variant-numeric:tabular-nums}.pos-tender__keypad{grid-area:keypad;display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-tender__keypad-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-md)}.pos-tender__key{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-key-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);font-family:inherit;font-size:1.15rem;font-weight:var(--pos-font-weight-bold);cursor:pointer;transition:background .12s ease,color .12s ease,border-color .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-tender__key--action{color:var(--pos-color-text-muted);background:var(--pos-color-surface-muted)}.pos-tender__key:not(:disabled):active{background:var(--pos-color-key-active);border-color:var(--pos-color-key-active);color:var(--pos-color-on-key-active);transform:translateY(1px)}.pos-tender__key:disabled,.pos-tender__primary:disabled{cursor:not-allowed}.pos-tender__key:disabled{opacity:.55}.pos-tender__key:focus-visible,.pos-tender__primary:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-tender__change{display:flex;flex-direction:column;gap:var(--pos-space-xs);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-tender__change-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__change-value{margin:0;color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-tender__actions{grid-area:actions;display:flex;margin-top:0}.pos-tender__primary{flex:1 1 auto;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-size:1.05rem;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:filter .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-tender__primary:not(:disabled):hover{filter:brightness(.97)}.pos-tender__primary:not(:disabled):active{transform:translateY(1px)}.pos-tender__primary--disabled,.pos-tender__primary:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);filter:none;transform:none}@media(min-width:768px){.pos-tender__key{min-height:var(--pos-keypad-size-md)}}@container pos-tender (min-width: 36rem){.pos-tender__panel{grid-template-columns:minmax(0,1fr) minmax(16rem,1.1fr);grid-template-areas:\"header header\" \"status status\" \"summary keypad\" \"display keypad\" \"actions keypad\";gap:var(--pos-space-lg);padding:var(--pos-space-2xl);align-items:start}.pos-tender__keypad{align-self:start}}@media(min-width:1100px){.pos-tender__key{min-height:var(--pos-keypad-size-lg);font-size:1.25rem}}@media(prefers-reduced-motion:reduce){.pos-tender__key,.pos-tender__primary{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
452
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosTender, isStandalone: true, selector: "pos-tender", inputs: { amountDue: { classPropertyName: "amountDue", publicName: "amountDue", isSignal: true, isRequired: false, transformFunction: null }, changeDue: { classPropertyName: "changeDue", publicName: "changeDue", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, amountDueLabel: { classPropertyName: "amountDueLabel", publicName: "amountDueLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderedLabel: { classPropertyName: "tenderedLabel", publicName: "tenderedLabel", isSignal: true, isRequired: false, transformFunction: null }, changeDueLabel: { classPropertyName: "changeDueLabel", publicName: "changeDueLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderLabel: { classPropertyName: "tenderLabel", publicName: "tenderLabel", isSignal: true, isRequired: false, transformFunction: null }, cancelLabel: { classPropertyName: "cancelLabel", publicName: "cancelLabel", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, processingLabel: { classPropertyName: "processingLabel", publicName: "processingLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-tender" }, ngImport: i0, template: "<section class=\"pos-tender__panel\" [attr.aria-busy]=\"disabled() ? true : null\">\r\n <header class=\"pos-tender__header\">\r\n <h2 class=\"pos-tender__title\">{{ title() }}</h2>\r\n <p class=\"pos-tender__hint\">\r\n {{ amountDueLabel() }}:\r\n <span class=\"pos-tender__due\">{{ formatMoney(amountDue()) }}</span>\r\n - {{ hint() }}\r\n </p>\r\n @if (hasChangeDue()) {\r\n <div class=\"pos-tender__change\" role=\"status\" aria-live=\"polite\">\r\n <p class=\"pos-tender__change-label\">{{ changeDueLabel() }}</p>\r\n <p class=\"pos-tender__change-value\">{{ formatMoney(changeDue() ?? 0) }}</p>\r\n </div>\r\n }\r\n </header>\r\n\r\n @if (statusText() || errorMessage()) {\r\n <div class=\"pos-tender__status\" aria-live=\"polite\">\r\n @if (statusText()) {\r\n <p>{{ statusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-tender__error\" role=\"alert\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-tender__money\">\r\n <div class=\"pos-tender__coins\" role=\"group\" aria-label=\"Coins\">\r\n @for (amount of coins; track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__coin\"\r\n [attr.data-amount]=\"amount\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"'Add ' + denominationLabel(amount)\"\r\n (click)=\"addAmount(amount)\"\r\n >\r\n {{ denominationLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__notes\" role=\"group\" aria-label=\"Notes\">\r\n @for (amount of notes; track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__note\"\r\n [attr.data-amount]=\"amount\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"'Add ' + denominationLabel(amount)\"\r\n (click)=\"addAmount(amount)\"\r\n >\r\n {{ denominationLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (quickAmounts().length) {\r\n <div class=\"pos-tender__quick\" role=\"group\" aria-label=\"Quick amounts\">\r\n @for (amount of quickAmounts(); track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__pill\"\r\n [class.pos-tender__pill--exact]=\"isExact(amount)\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"setAmount(amount)\"\r\n >\r\n {{ quickLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-tender__given\">\r\n <label class=\"pos-tender__given-label\" for=\"pos-tender-given\">{{ tenderedLabel() }}</label>\r\n <input\r\n id=\"pos-tender-given\"\r\n class=\"pos-tender__digits\"\r\n [value]=\"displayGiven()\"\r\n readonly\r\n tabindex=\"-1\"\r\n aria-label=\"Amount given\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__reset\"\r\n aria-label=\"Reset amount\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"resetAmount()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M8 5h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H8l-5-7 5-7Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path d=\"m14 10 4 4m0-4-4 4\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-tender__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__cancel\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onCancel()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path d=\"M6 6l12 12M18 6 6 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n {{ cancelLabel() }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__primary\"\r\n [disabled]=\"!canTender()\"\r\n (click)=\"onTender()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M5 12.5 9.5 17 19 7.5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n {{ tenderLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;box-sizing:border-box;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md);background:var(--pos-color-surface)}*{box-sizing:border-box}.pos-tender__panel{display:flex;flex-direction:column;gap:var(--pos-space-lg);width:100%;padding:var(--pos-space-lg);background:var(--pos-color-surface)}.pos-tender__header{display:flex;flex-direction:column;gap:var(--pos-space-xs)}.pos-tender__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-tender__hint,.pos-tender__given-label,.pos-tender__change-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-tender__due{color:var(--pos-color-text);font-weight:var(--pos-font-weight-semibold)}.pos-tender__change{display:flex;align-items:baseline;gap:var(--pos-space-sm)}.pos-tender__change-value{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-tender__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__error{color:var(--pos-color-danger)}.pos-tender__money{display:flex;flex-direction:column;gap:var(--pos-space-lg)}.pos-tender__coins{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--pos-keypad-size),1fr));gap:var(--pos-space-md);width:100%;justify-content:start}.pos-tender__notes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pos-space-md)}.pos-tender__coin,.pos-tender__note,.pos-tender__pill,.pos-tender__reset,.pos-tender__cancel,.pos-tender__primary{font-family:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-tender__coin,.pos-tender__note,.pos-tender__pill,.pos-tender__reset{border:1px solid var(--pos-color-border);background:var(--pos-color-surface);color:var(--pos-color-text);box-shadow:var(--pos-shadow-key)}.pos-tender__coin{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-keypad-size-lg);height:var(--pos-keypad-size-lg);border-radius:var(--pos-radius-pill)}.pos-tender__note{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-button-min-height);border-radius:var(--pos-radius-md)}.pos-tender__coin:hover:not(:disabled),.pos-tender__note:hover:not(:disabled),.pos-tender__pill:hover:not(:disabled){border-color:var(--pos-color-success)}.pos-tender__quick{display:flex;flex-wrap:wrap;gap:var(--pos-space-sm)}.pos-tender__pill{min-height:var(--pos-button-min-height);padding:0 var(--pos-space-lg);border-radius:var(--pos-radius-pill)}.pos-tender__pill--exact{border-color:var(--pos-color-primary);background:color-mix(in srgb,var(--pos-color-primary) 28%,var(--pos-color-surface));color:var(--pos-color-text)}.pos-tender__given{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--pos-space-md)}.pos-tender__digits{width:min(15rem,100%);min-height:var(--pos-button-min-height);margin:0;padding:0 var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface);color:var(--pos-color-text);font:inherit;font-size:var(--pos-font-size-lg);text-align:right}.pos-tender__reset{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);border-radius:var(--pos-radius-sm);color:var(--pos-color-danger);box-shadow:none}.pos-tender__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--pos-space-md)}.pos-tender__cancel,.pos-tender__primary{display:inline-flex;flex:1 1 10rem;align-items:center;justify-content:center;gap:var(--pos-space-sm);max-width:14rem;min-height:calc(var(--pos-button-min-height) + var(--pos-space-sm));border:0;border-radius:var(--pos-radius-md)}.pos-tender__cancel{background:var(--pos-color-danger);color:var(--pos-color-on-danger)}.pos-tender__primary{background:var(--pos-color-success);color:var(--pos-color-on-success)}.pos-tender__primary:hover:not(:disabled){filter:brightness(1.06)}.pos-tender__coin:disabled,.pos-tender__note:disabled,.pos-tender__pill:disabled,.pos-tender__reset:disabled,.pos-tender__cancel:disabled,.pos-tender__primary:disabled{border-color:var(--pos-color-disabled);background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);box-shadow:none;cursor:not-allowed;filter:none}.pos-tender__coin:focus-visible,.pos-tender__note:focus-visible,.pos-tender__pill:focus-visible,.pos-tender__reset:focus-visible,.pos-tender__cancel:focus-visible,.pos-tender__primary:focus-visible{outline:3px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-tender__panel{padding:var(--pos-space-xl)}.pos-tender__money{flex-direction:row;align-items:flex-start}.pos-tender__coins{flex:1 1 auto;width:auto;min-width:0;grid-template-columns:repeat(5,var(--pos-keypad-size-lg))}.pos-tender__notes{display:flex;flex:0 0 auto;flex-direction:column;width:calc(var(--pos-keypad-size-lg) + var(--pos-space-3xl))}.pos-tender__cancel,.pos-tender__primary{flex:0 0 auto;min-width:10rem}}@media(prefers-reduced-motion:reduce){.pos-tender__primary{filter:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
327
453
  }
328
454
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTender, decorators: [{
329
455
  type: Component,
330
456
  args: [{ selector: 'pos-tender', changeDetection: ChangeDetectionStrategy.OnPush, host: {
331
457
  class: 'pos-tender',
332
- }, template: "<section\r\n class=\"pos-tender__panel\"\r\n [attr.aria-busy]=\"disabled() ? true : null\"\r\n>\r\n <header class=\"pos-tender__header\">\r\n <p class=\"pos-tender__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-tender__title\">{{ title() }}</h2>\r\n </header>\r\n\r\n <div class=\"pos-tender__status\" aria-live=\"polite\">\r\n @if (statusText()) {\r\n <p>{{ statusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-tender__error\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__summary\">\r\n <dl class=\"pos-tender__due\">\r\n <div class=\"pos-tender__row\">\r\n <dt>{{ amountDueLabel() }}</dt>\r\n <dd>{{ formatMoney(amountDue()) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasChangeDue()) {\r\n <div class=\"pos-tender__change\" role=\"status\" aria-live=\"polite\">\r\n <p class=\"pos-tender__change-label\">{{ changeDueLabel() }}</p>\r\n <p class=\"pos-tender__change-value\">\r\n {{ formatMoney(changeDue() ?? 0) }}\r\n </p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"pos-tender__display\"\r\n role=\"group\"\r\n [attr.aria-label]=\"tenderedLabel()\"\r\n >\r\n <p class=\"pos-tender__display-label\">{{ tenderedLabel() }}</p>\r\n <p class=\"pos-tender__display-value\" aria-live=\"polite\">\r\n <span class=\"pos-tender__currency\">{{ currency() }}</span>\r\n <span class=\"pos-tender__digits\">{{ displayTendered() }}</span>\r\n </p>\r\n </div>\r\n\r\n <div class=\"pos-tender__keypad\" role=\"group\" aria-label=\"Cash amount keypad\">\r\n @for (row of keypadRows; track $index) {\r\n <div class=\"pos-tender__keypad-row\">\r\n @for (key of row; track key) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__key\"\r\n [class.pos-tender__key--action]=\"key === '\u2190' || key === '.'\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"key === '\u2190' ? 'Backspace' : key === '.' ? 'Decimal point' : key\"\r\n (click)=\"onKeypad(key)\"\r\n >\r\n {{ key }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__primary\"\r\n [class.pos-tender__primary--disabled]=\"!canTender()\"\r\n [disabled]=\"!canTender()\"\r\n (click)=\"onTender()\"\r\n >\r\n {{ tenderLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;width:100%;max-width:42rem;min-width:0;container-type:inline-size;container-name:pos-tender;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-tender__panel{min-width:0;display:grid;grid-template-areas:\"header\" \"status\" \"summary\" \"display\" \"keypad\" \"actions\";gap:var(--pos-space-md);padding:var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-tender__header{grid-area:header;display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-tender__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-tender__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em;line-height:1.15}.pos-tender__status{grid-area:status;min-height:1.5rem;display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-tender__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__error{padding:var(--pos-space-sm) var(--pos-space-md);border-left:3px solid var(--pos-color-danger);background:#d6454514;color:var(--pos-color-danger)}.pos-tender__summary{grid-area:summary;display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-tender__due{margin:0}.pos-tender__row{display:flex;justify-content:space-between;align-items:baseline;gap:var(--pos-space-md);margin:0;padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-tender__row dt,.pos-tender__row dd{margin:0}.pos-tender__row dt{color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__row dd{font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-tender__display{grid-area:display;min-width:0;padding:var(--pos-space-lg) var(--pos-space-xl);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:var(--pos-color-display);box-shadow:inset 0 1px #ffffff0f}.pos-tender__display-label{margin:0 0 var(--pos-space-sm);color:#e8edf2b3;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:.08em;text-transform:uppercase}.pos-tender__display-value{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-on-display);font-family:var(--pos-font-family-display)}.pos-tender__currency{font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.12em}.pos-tender__digits{min-width:0;overflow-wrap:anywhere;font-size:clamp(1.5rem,4vw,2rem);font-weight:var(--pos-font-weight-semibold);letter-spacing:.04em;font-variant-numeric:tabular-nums}.pos-tender__keypad{grid-area:keypad;display:flex;flex-direction:column;gap:var(--pos-space-md)}.pos-tender__keypad-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--pos-space-md)}.pos-tender__key{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-keypad-size);border:1px solid var(--pos-color-key-border);border-radius:var(--pos-radius-md);background:var(--pos-color-key);color:var(--pos-color-text);font-family:inherit;font-size:1.15rem;font-weight:var(--pos-font-weight-bold);cursor:pointer;transition:background .12s ease,color .12s ease,border-color .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-tender__key--action{color:var(--pos-color-text-muted);background:var(--pos-color-surface-muted)}.pos-tender__key:not(:disabled):active{background:var(--pos-color-key-active);border-color:var(--pos-color-key-active);color:var(--pos-color-on-key-active);transform:translateY(1px)}.pos-tender__key:disabled,.pos-tender__primary:disabled{cursor:not-allowed}.pos-tender__key:disabled{opacity:.55}.pos-tender__key:focus-visible,.pos-tender__primary:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}.pos-tender__change{display:flex;flex-direction:column;gap:var(--pos-space-xs);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-tender__change-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__change-value{margin:0;color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-tender__actions{grid-area:actions;display:flex;margin-top:0}.pos-tender__primary{flex:1 1 auto;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-size:1.05rem;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;transition:filter .12s ease,transform .12s ease;-webkit-tap-highlight-color:transparent}.pos-tender__primary:not(:disabled):hover{filter:brightness(.97)}.pos-tender__primary:not(:disabled):active{transform:translateY(1px)}.pos-tender__primary--disabled,.pos-tender__primary:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);filter:none;transform:none}@media(min-width:768px){.pos-tender__key{min-height:var(--pos-keypad-size-md)}}@container pos-tender (min-width: 36rem){.pos-tender__panel{grid-template-columns:minmax(0,1fr) minmax(16rem,1.1fr);grid-template-areas:\"header header\" \"status status\" \"summary keypad\" \"display keypad\" \"actions keypad\";gap:var(--pos-space-lg);padding:var(--pos-space-2xl);align-items:start}.pos-tender__keypad{align-self:start}}@media(min-width:1100px){.pos-tender__key{min-height:var(--pos-keypad-size-lg);font-size:1.25rem}}@media(prefers-reduced-motion:reduce){.pos-tender__key,.pos-tender__primary{transition:none}}\n"] }]
333
- }], propDecorators: { amountDue: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountDue", required: false }] }], changeDue: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeDue", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], amountDueLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountDueLabel", required: false }] }], tenderedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderedLabel", required: false }] }], changeDueLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeDueLabel", required: false }] }], tenderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderLabel", required: false }] }], processingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "processingLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
458
+ }, template: "<section class=\"pos-tender__panel\" [attr.aria-busy]=\"disabled() ? true : null\">\r\n <header class=\"pos-tender__header\">\r\n <h2 class=\"pos-tender__title\">{{ title() }}</h2>\r\n <p class=\"pos-tender__hint\">\r\n {{ amountDueLabel() }}:\r\n <span class=\"pos-tender__due\">{{ formatMoney(amountDue()) }}</span>\r\n - {{ hint() }}\r\n </p>\r\n @if (hasChangeDue()) {\r\n <div class=\"pos-tender__change\" role=\"status\" aria-live=\"polite\">\r\n <p class=\"pos-tender__change-label\">{{ changeDueLabel() }}</p>\r\n <p class=\"pos-tender__change-value\">{{ formatMoney(changeDue() ?? 0) }}</p>\r\n </div>\r\n }\r\n </header>\r\n\r\n @if (statusText() || errorMessage()) {\r\n <div class=\"pos-tender__status\" aria-live=\"polite\">\r\n @if (statusText()) {\r\n <p>{{ statusText() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"pos-tender__error\" role=\"alert\">{{ errorMessage() }}</p>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-tender__money\">\r\n <div class=\"pos-tender__coins\" role=\"group\" aria-label=\"Coins\">\r\n @for (amount of coins; track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__coin\"\r\n [attr.data-amount]=\"amount\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"'Add ' + denominationLabel(amount)\"\r\n (click)=\"addAmount(amount)\"\r\n >\r\n {{ denominationLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-tender__notes\" role=\"group\" aria-label=\"Notes\">\r\n @for (amount of notes; track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__note\"\r\n [attr.data-amount]=\"amount\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"'Add ' + denominationLabel(amount)\"\r\n (click)=\"addAmount(amount)\"\r\n >\r\n {{ denominationLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (quickAmounts().length) {\r\n <div class=\"pos-tender__quick\" role=\"group\" aria-label=\"Quick amounts\">\r\n @for (amount of quickAmounts(); track amount) {\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__pill\"\r\n [class.pos-tender__pill--exact]=\"isExact(amount)\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"setAmount(amount)\"\r\n >\r\n {{ quickLabel(amount) }}\r\n </button>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pos-tender__given\">\r\n <label class=\"pos-tender__given-label\" for=\"pos-tender-given\">{{ tenderedLabel() }}</label>\r\n <input\r\n id=\"pos-tender-given\"\r\n class=\"pos-tender__digits\"\r\n [value]=\"displayGiven()\"\r\n readonly\r\n tabindex=\"-1\"\r\n aria-label=\"Amount given\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__reset\"\r\n aria-label=\"Reset amount\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"resetAmount()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M8 5h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H8l-5-7 5-7Z\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"1.7\"\r\n stroke-linejoin=\"round\"\r\n />\r\n <path d=\"m14 10 4 4m0-4-4 4\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"pos-tender__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__cancel\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onCancel()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path d=\"M6 6l12 12M18 6 6 18\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n {{ cancelLabel() }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"pos-tender__primary\"\r\n [disabled]=\"!canTender()\"\r\n (click)=\"onTender()\"\r\n >\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M5 12.5 9.5 17 19 7.5\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2.2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </svg>\r\n {{ tenderLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:block;box-sizing:border-box;width:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md);background:var(--pos-color-surface)}*{box-sizing:border-box}.pos-tender__panel{display:flex;flex-direction:column;gap:var(--pos-space-lg);width:100%;padding:var(--pos-space-lg);background:var(--pos-color-surface)}.pos-tender__header{display:flex;flex-direction:column;gap:var(--pos-space-xs)}.pos-tender__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold);line-height:1.2}.pos-tender__hint,.pos-tender__given-label,.pos-tender__change-label{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-tender__due{color:var(--pos-color-text);font-weight:var(--pos-font-weight-semibold)}.pos-tender__change{display:flex;align-items:baseline;gap:var(--pos-space-sm)}.pos-tender__change-value{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold)}.pos-tender__status p{margin:0;font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-tender__error{color:var(--pos-color-danger)}.pos-tender__money{display:flex;flex-direction:column;gap:var(--pos-space-lg)}.pos-tender__coins{display:grid;grid-template-columns:repeat(auto-fill,minmax(var(--pos-keypad-size),1fr));gap:var(--pos-space-md);width:100%;justify-content:start}.pos-tender__notes{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--pos-space-md)}.pos-tender__coin,.pos-tender__note,.pos-tender__pill,.pos-tender__reset,.pos-tender__cancel,.pos-tender__primary{font-family:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-tender__coin,.pos-tender__note,.pos-tender__pill,.pos-tender__reset{border:1px solid var(--pos-color-border);background:var(--pos-color-surface);color:var(--pos-color-text);box-shadow:var(--pos-shadow-key)}.pos-tender__coin{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-keypad-size-lg);height:var(--pos-keypad-size-lg);border-radius:var(--pos-radius-pill)}.pos-tender__note{display:inline-flex;align-items:center;justify-content:center;min-height:var(--pos-button-min-height);border-radius:var(--pos-radius-md)}.pos-tender__coin:hover:not(:disabled),.pos-tender__note:hover:not(:disabled),.pos-tender__pill:hover:not(:disabled){border-color:var(--pos-color-success)}.pos-tender__quick{display:flex;flex-wrap:wrap;gap:var(--pos-space-sm)}.pos-tender__pill{min-height:var(--pos-button-min-height);padding:0 var(--pos-space-lg);border-radius:var(--pos-radius-pill)}.pos-tender__pill--exact{border-color:var(--pos-color-primary);background:color-mix(in srgb,var(--pos-color-primary) 28%,var(--pos-color-surface));color:var(--pos-color-text)}.pos-tender__given{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--pos-space-md)}.pos-tender__digits{width:min(15rem,100%);min-height:var(--pos-button-min-height);margin:0;padding:0 var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface);color:var(--pos-color-text);font:inherit;font-size:var(--pos-font-size-lg);text-align:right}.pos-tender__reset{display:inline-flex;align-items:center;justify-content:center;width:var(--pos-button-min-height);height:var(--pos-button-min-height);border-radius:var(--pos-radius-sm);color:var(--pos-color-danger);box-shadow:none}.pos-tender__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:var(--pos-space-md)}.pos-tender__cancel,.pos-tender__primary{display:inline-flex;flex:1 1 10rem;align-items:center;justify-content:center;gap:var(--pos-space-sm);max-width:14rem;min-height:calc(var(--pos-button-min-height) + var(--pos-space-sm));border:0;border-radius:var(--pos-radius-md)}.pos-tender__cancel{background:var(--pos-color-danger);color:var(--pos-color-on-danger)}.pos-tender__primary{background:var(--pos-color-success);color:var(--pos-color-on-success)}.pos-tender__primary:hover:not(:disabled){filter:brightness(1.06)}.pos-tender__coin:disabled,.pos-tender__note:disabled,.pos-tender__pill:disabled,.pos-tender__reset:disabled,.pos-tender__cancel:disabled,.pos-tender__primary:disabled{border-color:var(--pos-color-disabled);background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);box-shadow:none;cursor:not-allowed;filter:none}.pos-tender__coin:focus-visible,.pos-tender__note:focus-visible,.pos-tender__pill:focus-visible,.pos-tender__reset:focus-visible,.pos-tender__cancel:focus-visible,.pos-tender__primary:focus-visible{outline:3px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-tender__panel{padding:var(--pos-space-xl)}.pos-tender__money{flex-direction:row;align-items:flex-start}.pos-tender__coins{flex:1 1 auto;width:auto;min-width:0;grid-template-columns:repeat(5,var(--pos-keypad-size-lg))}.pos-tender__notes{display:flex;flex:0 0 auto;flex-direction:column;width:calc(var(--pos-keypad-size-lg) + var(--pos-space-3xl))}.pos-tender__cancel,.pos-tender__primary{flex:0 0 auto;min-width:10rem}}@media(prefers-reduced-motion:reduce){.pos-tender__primary{filter:none}}\n"] }]
459
+ }], propDecorators: { amountDue: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountDue", required: false }] }], changeDue: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeDue", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], amountDueLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountDueLabel", required: false }] }], tenderedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderedLabel", required: false }] }], changeDueLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeDueLabel", required: false }] }], tenderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderLabel", required: false }] }], cancelLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], processingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "processingLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
334
460
 
335
461
  const EMPTY_TOTALS = {
336
462
  gross: 0,
@@ -350,6 +476,8 @@ class PosReceipt {
350
476
  payments = input([], ...(ngDevMode ? [{ debugName: "payments" }] : /* istanbul ignore next */ []));
351
477
  document = input(EMPTY_DOCUMENT, ...(ngDevMode ? [{ debugName: "document" }] : /* istanbul ignore next */ []));
352
478
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
479
+ /** Draws the panel frame. Off by default so the host can sit the receipt flush. */
480
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
353
481
  title = input('Receipt', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
354
482
  emptyMessage = input('No receipt lines', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
355
483
  preparingLabel = input('Preparing receipt…', ...(ngDevMode ? [{ debugName: "preparingLabel" }] : /* istanbul ignore next */ []));
@@ -382,14 +510,14 @@ class PosReceipt {
382
510
  this.action.emit({ type: 'receipt.newSale' });
383
511
  }
384
512
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosReceipt, deps: [], target: i0.ɵɵFactoryTarget.Component });
385
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosReceipt, isStandalone: true, selector: "pos-receipt", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, totals: { classPropertyName: "totals", publicName: "totals", isSignal: true, isRequired: false, transformFunction: null }, payments: { classPropertyName: "payments", publicName: "payments", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, preparingLabel: { classPropertyName: "preparingLabel", publicName: "preparingLabel", isSignal: true, isRequired: false, transformFunction: null }, readyLabel: { classPropertyName: "readyLabel", publicName: "readyLabel", isSignal: true, isRequired: false, transformFunction: null }, newSaleLabel: { classPropertyName: "newSaleLabel", publicName: "newSaleLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderLabel: { classPropertyName: "tenderLabel", publicName: "tenderLabel", isSignal: true, isRequired: false, transformFunction: null }, amountLabel: { classPropertyName: "amountLabel", publicName: "amountLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderedLabel: { classPropertyName: "tenderedLabel", publicName: "tenderedLabel", isSignal: true, isRequired: false, transformFunction: null }, changeLabel: { classPropertyName: "changeLabel", publicName: "changeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-receipt" }, ngImport: i0, template: "<section\r\n class=\"pos-receipt__panel\"\r\n [attr.aria-busy]=\"disabled() || !document().receiptReady ? true : null\"\r\n>\r\n <header class=\"pos-receipt__header\">\r\n <div class=\"pos-receipt__heading\">\r\n <p class=\"pos-receipt__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-receipt__title\">{{ title() }}</h2>\r\n </div>\r\n @if (hasDocumentNumber()) {\r\n <p class=\"pos-receipt__number\" aria-label=\"Document number\">\r\n {{ document().number }}\r\n </p>\r\n }\r\n </header>\r\n\r\n <p class=\"pos-receipt__status\" aria-live=\"polite\">{{ statusText() }}</p>\r\n\r\n <ul class=\"pos-receipt__lines\" aria-label=\"Receipt lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-receipt__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-receipt__line\"\r\n [class.pos-receipt__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-receipt__line-info\">\r\n <h3 class=\"pos-receipt__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-receipt__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-receipt__line-voided\">Voided</p>\r\n }\r\n </div>\r\n <p class=\"pos-receipt__qty\">{{ line.qty }}</p>\r\n <div class=\"pos-receipt__line-prices\">\r\n <p class=\"pos-receipt__unit-price\">\r\n {{ formatMoney(line.unitPrice) }}\r\n </p>\r\n <p class=\"pos-receipt__line-total\">\r\n {{ formatMoney(line.lineTotal) }}\r\n </p>\r\n </div>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <div class=\"pos-receipt__summary\">\r\n <dl class=\"pos-receipt__totals\" aria-live=\"polite\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasPayments()) {\r\n <section class=\"pos-receipt__tender\">\r\n <h3 class=\"pos-receipt__tender-title\">{{ tenderLabel() }}</h3>\r\n <ul class=\"pos-receipt__payments\">\r\n @for (payment of payments(); track $index) {\r\n <li class=\"pos-receipt__payment\">\r\n <header class=\"pos-receipt__payment-header\">\r\n <p class=\"pos-receipt__payment-tender\">{{ payment.tender }}</p>\r\n <p class=\"pos-receipt__payment-state\">{{ payment.state }}</p>\r\n </header>\r\n <dl class=\"pos-receipt__payment-amounts\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ amountLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.amount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ tenderedLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.tendered) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--change\">\r\n <dt>{{ changeLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.change) }}</dd>\r\n </div>\r\n </dl>\r\n </li>\r\n }\r\n </ul>\r\n </section>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-receipt__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-receipt__new-sale\"\r\n [disabled]=\"!canStartNewSale()\"\r\n (click)=\"onNewSale()\"\r\n >\r\n {{ newSaleLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-receipt__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-receipt__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__heading{display:flex;flex-direction:column;gap:var(--pos-space-sm);min-width:0}.pos-receipt__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-receipt__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em}.pos-receipt__number{margin:0;color:var(--pos-color-text-muted);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);overflow-wrap:anywhere;text-align:right}.pos-receipt__status{margin:var(--pos-space-md) 0 0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:var(--pos-space-md) 0 0;padding:0;overflow-y:auto;list-style:none}.pos-receipt__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-receipt__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info qty\" \"prices prices\";align-items:center;gap:var(--pos-space-xs) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-receipt__line-info{grid-area:info;min-width:0}.pos-receipt__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-receipt__line-sku,.pos-receipt__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-receipt__line-sku{color:var(--pos-color-text-muted)}.pos-receipt__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__qty{grid-area:qty;margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums;text-align:right}.pos-receipt__line-prices{grid-area:prices;display:flex;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-receipt__line--voided .pos-receipt__line-name,.pos-receipt__line--voided .pos-receipt__line-sku,.pos-receipt__line--voided .pos-receipt__line-prices,.pos-receipt__line--voided .pos-receipt__qty{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-receipt__summary{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-receipt__totals,.pos-receipt__payment-amounts{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-receipt__row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__row dt,.pos-receipt__row dd{margin:0}.pos-receipt__row dd{font-variant-numeric:tabular-nums}.pos-receipt__row--due,.pos-receipt__row--change{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-receipt__tender{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-receipt__tender-title{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:.08em;text-transform:uppercase}.pos-receipt__payments{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0;padding:0;list-style:none}.pos-receipt__payment{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-receipt__payment-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__payment-tender{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-bold)}.pos-receipt__payment-state{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__actions{margin-top:var(--pos-space-md)}.pos-receipt__new-sale{width:100%;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-receipt__new-sale:not(:disabled):active{transform:translateY(1px)}.pos-receipt__new-sale:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-receipt__new-sale:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-receipt__panel{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(16rem,1fr);grid-template-areas:\"header header\" \"status status\" \"lines summary\" \"actions actions\";gap:var(--pos-space-lg);padding:var(--pos-space-xl);align-items:start}.pos-receipt__header{grid-area:header}.pos-receipt__status{grid-area:status;margin:0}.pos-receipt__lines{grid-area:lines;margin:0}.pos-receipt__line{grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:\"info qty prices\";gap:var(--pos-space-md)}.pos-receipt__line-prices{flex-direction:column;align-items:flex-end;justify-content:center}.pos-receipt__summary{grid-area:summary;margin:0;padding:0;border-top:0}.pos-receipt__actions{grid-area:actions;margin:0}}@media(prefers-reduced-motion:reduce){.pos-receipt__new-sale{transform:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
513
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosReceipt, isStandalone: true, selector: "pos-receipt", inputs: { lines: { classPropertyName: "lines", publicName: "lines", isSignal: true, isRequired: false, transformFunction: null }, totals: { classPropertyName: "totals", publicName: "totals", isSignal: true, isRequired: false, transformFunction: null }, payments: { classPropertyName: "payments", publicName: "payments", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, preparingLabel: { classPropertyName: "preparingLabel", publicName: "preparingLabel", isSignal: true, isRequired: false, transformFunction: null }, readyLabel: { classPropertyName: "readyLabel", publicName: "readyLabel", isSignal: true, isRequired: false, transformFunction: null }, newSaleLabel: { classPropertyName: "newSaleLabel", publicName: "newSaleLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderLabel: { classPropertyName: "tenderLabel", publicName: "tenderLabel", isSignal: true, isRequired: false, transformFunction: null }, amountLabel: { classPropertyName: "amountLabel", publicName: "amountLabel", isSignal: true, isRequired: false, transformFunction: null }, tenderedLabel: { classPropertyName: "tenderedLabel", publicName: "tenderedLabel", isSignal: true, isRequired: false, transformFunction: null }, changeLabel: { classPropertyName: "changeLabel", publicName: "changeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "pos-receipt" }, ngImport: i0, template: "<section\r\n class=\"pos-receipt__panel\"\r\n [class.pos-receipt__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() || !document().receiptReady ? true : null\"\r\n>\r\n <header class=\"pos-receipt__header\">\r\n <div class=\"pos-receipt__heading\">\r\n <p class=\"pos-receipt__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-receipt__title\">{{ title() }}</h2>\r\n </div>\r\n @if (hasDocumentNumber()) {\r\n <p class=\"pos-receipt__number\" aria-label=\"Document number\">\r\n {{ document().number }}\r\n </p>\r\n }\r\n </header>\r\n\r\n <p class=\"pos-receipt__status\" aria-live=\"polite\">{{ statusText() }}</p>\r\n\r\n <ul class=\"pos-receipt__lines\" aria-label=\"Receipt lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-receipt__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-receipt__line\"\r\n [class.pos-receipt__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-receipt__line-info\">\r\n <h3 class=\"pos-receipt__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-receipt__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-receipt__line-voided\">Voided</p>\r\n }\r\n </div>\r\n <p class=\"pos-receipt__qty\">{{ line.qty }}</p>\r\n <div class=\"pos-receipt__line-prices\">\r\n <p class=\"pos-receipt__unit-price\">\r\n {{ formatMoney(line.unitPrice) }}\r\n </p>\r\n <p class=\"pos-receipt__line-total\">\r\n {{ formatMoney(line.lineTotal) }}\r\n </p>\r\n </div>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <div class=\"pos-receipt__summary\">\r\n <dl class=\"pos-receipt__totals\" aria-live=\"polite\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasPayments()) {\r\n <section class=\"pos-receipt__tender\">\r\n <h3 class=\"pos-receipt__tender-title\">{{ tenderLabel() }}</h3>\r\n <ul class=\"pos-receipt__payments\">\r\n @for (payment of payments(); track $index) {\r\n <li class=\"pos-receipt__payment\">\r\n <header class=\"pos-receipt__payment-header\">\r\n <p class=\"pos-receipt__payment-tender\">{{ payment.tender }}</p>\r\n <p class=\"pos-receipt__payment-state\">{{ payment.state }}</p>\r\n </header>\r\n <dl class=\"pos-receipt__payment-amounts\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ amountLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.amount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ tenderedLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.tendered) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--change\">\r\n <dt>{{ changeLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.change) }}</dd>\r\n </div>\r\n </dl>\r\n </li>\r\n }\r\n </ul>\r\n </section>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-receipt__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-receipt__new-sale\"\r\n [disabled]=\"!canStartNewSale()\"\r\n (click)=\"onNewSale()\"\r\n >\r\n {{ newSaleLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-receipt__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-receipt__panel--bordered{border:1px solid var(--pos-color-border)}.pos-receipt__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__heading{display:flex;flex-direction:column;gap:var(--pos-space-sm);min-width:0}.pos-receipt__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-receipt__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-tight)}.pos-receipt__number{margin:0;color:var(--pos-color-text-muted);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);overflow-wrap:anywhere;text-align:right}.pos-receipt__status{margin:var(--pos-space-md) 0 0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:var(--pos-space-md) 0 0;padding:0;overflow-y:auto;list-style:none}.pos-receipt__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-receipt__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info qty\" \"prices prices\";align-items:center;gap:var(--pos-space-xs) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-receipt__line-info{grid-area:info;min-width:0}.pos-receipt__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-receipt__line-sku,.pos-receipt__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-receipt__line-sku{color:var(--pos-color-text-muted)}.pos-receipt__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__qty{grid-area:qty;margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums;text-align:right}.pos-receipt__line-prices{grid-area:prices;display:flex;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-receipt__line--voided .pos-receipt__line-name,.pos-receipt__line--voided .pos-receipt__line-sku,.pos-receipt__line--voided .pos-receipt__line-prices,.pos-receipt__line--voided .pos-receipt__qty{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-receipt__summary{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-receipt__totals,.pos-receipt__payment-amounts{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-receipt__row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__row dt,.pos-receipt__row dd{margin:0}.pos-receipt__row dd{font-variant-numeric:tabular-nums}.pos-receipt__row--due,.pos-receipt__row--change{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-receipt__tender{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-receipt__tender-title{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-brand);text-transform:uppercase}.pos-receipt__payments{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0;padding:0;list-style:none}.pos-receipt__payment{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-receipt__payment-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__payment-tender{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-bold)}.pos-receipt__payment-state{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__actions{margin-top:var(--pos-space-md)}.pos-receipt__new-sale{width:100%;min-height:var(--pos-button-min-height);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface);color:var(--pos-color-text);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-receipt__new-sale:not(:disabled):active{transform:translateY(1px)}.pos-receipt__new-sale:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-receipt__new-sale:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-receipt__panel{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(16rem,1fr);grid-template-areas:\"header header\" \"status status\" \"lines summary\" \"actions actions\";gap:var(--pos-space-lg);padding:var(--pos-space-xl);align-items:start}.pos-receipt__header{grid-area:header}.pos-receipt__status{grid-area:status;margin:0}.pos-receipt__lines{grid-area:lines;margin:0}.pos-receipt__line{grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:\"info qty prices\";gap:var(--pos-space-md)}.pos-receipt__line-prices{flex-direction:column;align-items:flex-end;justify-content:center}.pos-receipt__summary{grid-area:summary;margin:0;padding:0;border-top:0}.pos-receipt__actions{grid-area:actions;margin:0}}@media(prefers-reduced-motion:reduce){.pos-receipt__new-sale{transform:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
386
514
  }
387
515
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosReceipt, decorators: [{
388
516
  type: Component,
389
517
  args: [{ selector: 'pos-receipt', changeDetection: ChangeDetectionStrategy.OnPush, host: {
390
518
  class: 'pos-receipt',
391
- }, template: "<section\r\n class=\"pos-receipt__panel\"\r\n [attr.aria-busy]=\"disabled() || !document().receiptReady ? true : null\"\r\n>\r\n <header class=\"pos-receipt__header\">\r\n <div class=\"pos-receipt__heading\">\r\n <p class=\"pos-receipt__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-receipt__title\">{{ title() }}</h2>\r\n </div>\r\n @if (hasDocumentNumber()) {\r\n <p class=\"pos-receipt__number\" aria-label=\"Document number\">\r\n {{ document().number }}\r\n </p>\r\n }\r\n </header>\r\n\r\n <p class=\"pos-receipt__status\" aria-live=\"polite\">{{ statusText() }}</p>\r\n\r\n <ul class=\"pos-receipt__lines\" aria-label=\"Receipt lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-receipt__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-receipt__line\"\r\n [class.pos-receipt__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-receipt__line-info\">\r\n <h3 class=\"pos-receipt__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-receipt__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-receipt__line-voided\">Voided</p>\r\n }\r\n </div>\r\n <p class=\"pos-receipt__qty\">{{ line.qty }}</p>\r\n <div class=\"pos-receipt__line-prices\">\r\n <p class=\"pos-receipt__unit-price\">\r\n {{ formatMoney(line.unitPrice) }}\r\n </p>\r\n <p class=\"pos-receipt__line-total\">\r\n {{ formatMoney(line.lineTotal) }}\r\n </p>\r\n </div>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <div class=\"pos-receipt__summary\">\r\n <dl class=\"pos-receipt__totals\" aria-live=\"polite\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasPayments()) {\r\n <section class=\"pos-receipt__tender\">\r\n <h3 class=\"pos-receipt__tender-title\">{{ tenderLabel() }}</h3>\r\n <ul class=\"pos-receipt__payments\">\r\n @for (payment of payments(); track $index) {\r\n <li class=\"pos-receipt__payment\">\r\n <header class=\"pos-receipt__payment-header\">\r\n <p class=\"pos-receipt__payment-tender\">{{ payment.tender }}</p>\r\n <p class=\"pos-receipt__payment-state\">{{ payment.state }}</p>\r\n </header>\r\n <dl class=\"pos-receipt__payment-amounts\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ amountLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.amount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ tenderedLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.tendered) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--change\">\r\n <dt>{{ changeLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.change) }}</dd>\r\n </div>\r\n </dl>\r\n </li>\r\n }\r\n </ul>\r\n </section>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-receipt__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-receipt__new-sale\"\r\n [disabled]=\"!canStartNewSale()\"\r\n (click)=\"onNewSale()\"\r\n >\r\n {{ newSaleLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-receipt__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-lg);background:radial-gradient(120% 80% at 100% 0%,rgba(0,194,178,.08),transparent 55%),var(--pos-color-panel)}.pos-receipt__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__heading{display:flex;flex-direction:column;gap:var(--pos-space-sm);min-width:0}.pos-receipt__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-receipt__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:-.03em}.pos-receipt__number{margin:0;color:var(--pos-color-text-muted);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);overflow-wrap:anywhere;text-align:right}.pos-receipt__status{margin:var(--pos-space-md) 0 0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:var(--pos-space-md) 0 0;padding:0;overflow-y:auto;list-style:none}.pos-receipt__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-receipt__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info qty\" \"prices prices\";align-items:center;gap:var(--pos-space-xs) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-receipt__line-info{grid-area:info;min-width:0}.pos-receipt__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-receipt__line-sku,.pos-receipt__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-receipt__line-sku{color:var(--pos-color-text-muted)}.pos-receipt__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__qty{grid-area:qty;margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums;text-align:right}.pos-receipt__line-prices{grid-area:prices;display:flex;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-receipt__line--voided .pos-receipt__line-name,.pos-receipt__line--voided .pos-receipt__line-sku,.pos-receipt__line--voided .pos-receipt__line-prices,.pos-receipt__line--voided .pos-receipt__qty{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-receipt__summary{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-receipt__totals,.pos-receipt__payment-amounts{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-receipt__row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__row dt,.pos-receipt__row dd{margin:0}.pos-receipt__row dd{font-variant-numeric:tabular-nums}.pos-receipt__row--due,.pos-receipt__row--change{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-receipt__tender{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-receipt__tender-title{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:.08em;text-transform:uppercase}.pos-receipt__payments{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0;padding:0;list-style:none}.pos-receipt__payment{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-receipt__payment-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__payment-tender{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-bold)}.pos-receipt__payment-state{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__actions{margin-top:var(--pos-space-md)}.pos-receipt__new-sale{width:100%;min-height:var(--pos-button-min-height);border:0;border-radius:var(--pos-radius-md);background:var(--pos-color-primary);color:var(--pos-color-on-primary);font:inherit;font-weight:var(--pos-font-weight-bold);letter-spacing:.04em;text-transform:uppercase;cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-receipt__new-sale:not(:disabled):active{transform:translateY(1px)}.pos-receipt__new-sale:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-receipt__new-sale:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-receipt__panel{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(16rem,1fr);grid-template-areas:\"header header\" \"status status\" \"lines summary\" \"actions actions\";gap:var(--pos-space-lg);padding:var(--pos-space-xl);align-items:start}.pos-receipt__header{grid-area:header}.pos-receipt__status{grid-area:status;margin:0}.pos-receipt__lines{grid-area:lines;margin:0}.pos-receipt__line{grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:\"info qty prices\";gap:var(--pos-space-md)}.pos-receipt__line-prices{flex-direction:column;align-items:flex-end;justify-content:center}.pos-receipt__summary{grid-area:summary;margin:0;padding:0;border-top:0}.pos-receipt__actions{grid-area:actions;margin:0}}@media(prefers-reduced-motion:reduce){.pos-receipt__new-sale{transform:none}}\n"] }]
392
- }], propDecorators: { lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], totals: [{ type: i0.Input, args: [{ isSignal: true, alias: "totals", required: false }] }], payments: [{ type: i0.Input, args: [{ isSignal: true, alias: "payments", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], preparingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "preparingLabel", required: false }] }], readyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "readyLabel", required: false }] }], newSaleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "newSaleLabel", required: false }] }], tenderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderLabel", required: false }] }], amountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountLabel", required: false }] }], tenderedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderedLabel", required: false }] }], changeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
519
+ }, template: "<section\r\n class=\"pos-receipt__panel\"\r\n [class.pos-receipt__panel--bordered]=\"bordered()\"\r\n [attr.aria-busy]=\"disabled() || !document().receiptReady ? true : null\"\r\n>\r\n <header class=\"pos-receipt__header\">\r\n <div class=\"pos-receipt__heading\">\r\n <p class=\"pos-receipt__kicker\">Adaptive POS</p>\r\n <h2 class=\"pos-receipt__title\">{{ title() }}</h2>\r\n </div>\r\n @if (hasDocumentNumber()) {\r\n <p class=\"pos-receipt__number\" aria-label=\"Document number\">\r\n {{ document().number }}\r\n </p>\r\n }\r\n </header>\r\n\r\n <p class=\"pos-receipt__status\" aria-live=\"polite\">{{ statusText() }}</p>\r\n\r\n <ul class=\"pos-receipt__lines\" aria-label=\"Receipt lines\">\r\n @if (!hasLines()) {\r\n <li class=\"pos-receipt__empty\">{{ emptyMessage() }}</li>\r\n } @else {\r\n @for (line of lines(); track line.lineId) {\r\n <li>\r\n <article\r\n class=\"pos-receipt__line\"\r\n [class.pos-receipt__line--voided]=\"line.struckThrough\"\r\n >\r\n <div class=\"pos-receipt__line-info\">\r\n <h3 class=\"pos-receipt__line-name\">{{ line.name }}</h3>\r\n <p class=\"pos-receipt__line-sku\">{{ line.sku }}</p>\r\n @if (line.struckThrough) {\r\n <p class=\"pos-receipt__line-voided\">Voided</p>\r\n }\r\n </div>\r\n <p class=\"pos-receipt__qty\">{{ line.qty }}</p>\r\n <div class=\"pos-receipt__line-prices\">\r\n <p class=\"pos-receipt__unit-price\">\r\n {{ formatMoney(line.unitPrice) }}\r\n </p>\r\n <p class=\"pos-receipt__line-total\">\r\n {{ formatMoney(line.lineTotal) }}\r\n </p>\r\n </div>\r\n </article>\r\n </li>\r\n }\r\n }\r\n </ul>\r\n\r\n <div class=\"pos-receipt__summary\">\r\n <dl class=\"pos-receipt__totals\" aria-live=\"polite\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>Gross</dt>\r\n <dd>{{ formatMoney(totals().gross) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Net</dt>\r\n <dd>{{ formatMoney(totals().net) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>VAT</dt>\r\n <dd>{{ formatMoney(totals().vat) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>Discount</dt>\r\n <dd>{{ formatMoney(totals().discount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--due\">\r\n <dt>Due</dt>\r\n <dd>{{ formatMoney(totals().due) }}</dd>\r\n </div>\r\n </dl>\r\n\r\n @if (hasPayments()) {\r\n <section class=\"pos-receipt__tender\">\r\n <h3 class=\"pos-receipt__tender-title\">{{ tenderLabel() }}</h3>\r\n <ul class=\"pos-receipt__payments\">\r\n @for (payment of payments(); track $index) {\r\n <li class=\"pos-receipt__payment\">\r\n <header class=\"pos-receipt__payment-header\">\r\n <p class=\"pos-receipt__payment-tender\">{{ payment.tender }}</p>\r\n <p class=\"pos-receipt__payment-state\">{{ payment.state }}</p>\r\n </header>\r\n <dl class=\"pos-receipt__payment-amounts\">\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ amountLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.amount) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row\">\r\n <dt>{{ tenderedLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.tendered) }}</dd>\r\n </div>\r\n <div class=\"pos-receipt__row pos-receipt__row--change\">\r\n <dt>{{ changeLabel() }}</dt>\r\n <dd>{{ formatMoney(payment.change) }}</dd>\r\n </div>\r\n </dl>\r\n </li>\r\n }\r\n </ul>\r\n </section>\r\n }\r\n </div>\r\n\r\n <div class=\"pos-receipt__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"pos-receipt__new-sale\"\r\n [disabled]=\"!canStartNewSale()\"\r\n (click)=\"onNewSale()\"\r\n >\r\n {{ newSaleLabel() }}\r\n </button>\r\n </div>\r\n</section>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:0;width:100%;height:100%;color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}.pos-receipt__panel{display:flex;flex-direction:column;min-height:0;height:100%;padding:var(--pos-space-lg);border-radius:var(--pos-radius-lg);background:var(--pos-color-panel)}.pos-receipt__panel--bordered{border:1px solid var(--pos-color-border)}.pos-receipt__header{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__heading{display:flex;flex-direction:column;gap:var(--pos-space-sm);min-width:0}.pos-receipt__kicker{margin:0;color:var(--pos-color-primary);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-bold);letter-spacing:.14em;text-transform:uppercase}.pos-receipt__title{margin:0;font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-xl);font-weight:var(--pos-font-weight-bold);letter-spacing:var(--pos-letter-spacing-tight)}.pos-receipt__number{margin:0;color:var(--pos-color-text-muted);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);overflow-wrap:anywhere;text-align:right}.pos-receipt__status{margin:var(--pos-space-md) 0 0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__lines{display:flex;flex:1 1 auto;flex-direction:column;gap:var(--pos-space-sm);min-height:8rem;margin:var(--pos-space-md) 0 0;padding:0;overflow-y:auto;list-style:none}.pos-receipt__empty{margin:auto 0;padding:var(--pos-space-2xl) var(--pos-space-md);color:var(--pos-color-text-muted);text-align:center}.pos-receipt__line{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"info qty\" \"prices prices\";align-items:center;gap:var(--pos-space-xs) var(--pos-space-md);padding:var(--pos-space-md);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-panel-elevated)}.pos-receipt__line-info{grid-area:info;min-width:0}.pos-receipt__line-name{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-semibold);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pos-receipt__line-sku,.pos-receipt__line-voided{margin:var(--pos-space-xs) 0 0;font-size:var(--pos-font-size-sm)}.pos-receipt__line-sku{color:var(--pos-color-text-muted)}.pos-receipt__line-voided{color:var(--pos-color-danger);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__qty{grid-area:qty;margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums;text-align:right}.pos-receipt__line-prices{grid-area:prices;display:flex;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__unit-price{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__line-total{margin:0;font-family:var(--pos-font-family-display);font-weight:var(--pos-font-weight-bold);font-variant-numeric:tabular-nums}.pos-receipt__line--voided .pos-receipt__line-name,.pos-receipt__line--voided .pos-receipt__line-sku,.pos-receipt__line--voided .pos-receipt__line-prices,.pos-receipt__line--voided .pos-receipt__qty{color:var(--pos-color-text-muted);text-decoration:line-through}.pos-receipt__summary{display:flex;flex-direction:column;gap:var(--pos-space-md);margin-top:var(--pos-space-md);padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border)}.pos-receipt__totals,.pos-receipt__payment-amounts{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0}.pos-receipt__row{display:flex;justify-content:space-between;gap:var(--pos-space-md);margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm)}.pos-receipt__row dt,.pos-receipt__row dd{margin:0}.pos-receipt__row dd{font-variant-numeric:tabular-nums}.pos-receipt__row--due,.pos-receipt__row--change{padding-top:var(--pos-space-sm);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family-display);font-size:var(--pos-font-size-lg);font-weight:var(--pos-font-weight-bold)}.pos-receipt__tender{display:flex;flex-direction:column;gap:var(--pos-space-sm)}.pos-receipt__tender-title{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold);letter-spacing:var(--pos-letter-spacing-brand);text-transform:uppercase}.pos-receipt__payments{display:flex;flex-direction:column;gap:var(--pos-space-sm);margin:0;padding:0;list-style:none}.pos-receipt__payment{display:flex;flex-direction:column;gap:var(--pos-space-sm);padding:var(--pos-space-md) var(--pos-space-lg);border:1px solid var(--pos-color-success);border-radius:var(--pos-radius-md);background:color-mix(in srgb,var(--pos-color-success) 14%,var(--pos-color-panel-elevated))}.pos-receipt__payment-header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--pos-space-md)}.pos-receipt__payment-tender{margin:0;font-size:var(--pos-font-size-md);font-weight:var(--pos-font-weight-bold)}.pos-receipt__payment-state{margin:0;color:var(--pos-color-text-muted);font-size:var(--pos-font-size-sm);font-weight:var(--pos-font-weight-semibold)}.pos-receipt__actions{margin-top:var(--pos-space-md)}.pos-receipt__new-sale{width:100%;min-height:var(--pos-button-min-height);border:1px solid var(--pos-color-border);border-radius:var(--pos-radius-md);background:var(--pos-color-surface);color:var(--pos-color-text);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer;-webkit-tap-highlight-color:transparent}.pos-receipt__new-sale:not(:disabled):active{transform:translateY(1px)}.pos-receipt__new-sale:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:not-allowed;transform:none}.pos-receipt__new-sale:focus-visible{outline:2px solid var(--pos-color-primary);outline-offset:2px}@media(min-width:768px){.pos-receipt__panel{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(16rem,1fr);grid-template-areas:\"header header\" \"status status\" \"lines summary\" \"actions actions\";gap:var(--pos-space-lg);padding:var(--pos-space-xl);align-items:start}.pos-receipt__header{grid-area:header}.pos-receipt__status{grid-area:status;margin:0}.pos-receipt__lines{grid-area:lines;margin:0}.pos-receipt__line{grid-template-columns:minmax(0,1fr) auto auto;grid-template-areas:\"info qty prices\";gap:var(--pos-space-md)}.pos-receipt__line-prices{flex-direction:column;align-items:flex-end;justify-content:center}.pos-receipt__summary{grid-area:summary;margin:0;padding:0;border-top:0}.pos-receipt__actions{grid-area:actions;margin:0}}@media(prefers-reduced-motion:reduce){.pos-receipt__new-sale{transform:none}}\n"] }]
520
+ }], propDecorators: { lines: [{ type: i0.Input, args: [{ isSignal: true, alias: "lines", required: false }] }], totals: [{ type: i0.Input, args: [{ isSignal: true, alias: "totals", required: false }] }], payments: [{ type: i0.Input, args: [{ isSignal: true, alias: "payments", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], preparingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "preparingLabel", required: false }] }], readyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "readyLabel", required: false }] }], newSaleLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "newSaleLabel", required: false }] }], tenderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderLabel", required: false }] }], amountLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "amountLabel", required: false }] }], tenderedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tenderedLabel", required: false }] }], changeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "changeLabel", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
393
521
 
394
522
  const POS_TOKEN_CATALOG = [
395
523
  {
@@ -462,7 +590,7 @@ const POS_TOKEN_CATALOG = [
462
590
  kind: 'color',
463
591
  group: 'color',
464
592
  preview: 'color',
465
- defaultValue: '#333333',
593
+ defaultValue: '#1a1a1a',
466
594
  },
467
595
  {
468
596
  name: 'Text muted',
@@ -470,7 +598,7 @@ const POS_TOKEN_CATALOG = [
470
598
  kind: 'color',
471
599
  group: 'color',
472
600
  preview: 'color',
473
- defaultValue: '#999999',
601
+ defaultValue: '#666a70',
474
602
  },
475
603
  {
476
604
  name: 'Surface',
@@ -486,7 +614,7 @@ const POS_TOKEN_CATALOG = [
486
614
  kind: 'color',
487
615
  group: 'color',
488
616
  preview: 'color',
489
- defaultValue: '#f5f5f5',
617
+ defaultValue: '#f5f5f7',
490
618
  },
491
619
  {
492
620
  name: 'Panel',
@@ -494,7 +622,7 @@ const POS_TOKEN_CATALOG = [
494
622
  kind: 'color',
495
623
  group: 'color',
496
624
  preview: 'color',
497
- defaultValue: '#f5f5f5',
625
+ defaultValue: '#ffffff',
498
626
  },
499
627
  {
500
628
  name: 'Panel elevated',
@@ -510,7 +638,7 @@ const POS_TOKEN_CATALOG = [
510
638
  kind: 'color',
511
639
  group: 'color',
512
640
  preview: 'color',
513
- defaultValue: '#333333',
641
+ defaultValue: '#1a1a1a',
514
642
  },
515
643
  {
516
644
  name: 'Border',
@@ -518,7 +646,7 @@ const POS_TOKEN_CATALOG = [
518
646
  kind: 'color',
519
647
  group: 'color',
520
648
  preview: 'color',
521
- defaultValue: '#dddddd',
649
+ defaultValue: '#ececf0',
522
650
  },
523
651
  {
524
652
  name: 'Disabled',
@@ -542,7 +670,7 @@ const POS_TOKEN_CATALOG = [
542
670
  kind: 'color',
543
671
  group: 'color',
544
672
  preview: 'color',
545
- defaultValue: '#333333',
673
+ defaultValue: '#1a1a1a',
546
674
  },
547
675
  {
548
676
  name: 'On display',
@@ -566,7 +694,7 @@ const POS_TOKEN_CATALOG = [
566
694
  kind: 'color',
567
695
  group: 'color',
568
696
  preview: 'color',
569
- defaultValue: '#dddddd',
697
+ defaultValue: '#ececf0',
570
698
  },
571
699
  {
572
700
  name: 'Key active',
@@ -574,7 +702,7 @@ const POS_TOKEN_CATALOG = [
574
702
  kind: 'color',
575
703
  group: 'color',
576
704
  preview: 'color',
577
- defaultValue: '#c9b5f0',
705
+ defaultValue: '#f0e6fd',
578
706
  },
579
707
  {
580
708
  name: 'On key active',
@@ -582,7 +710,7 @@ const POS_TOKEN_CATALOG = [
582
710
  kind: 'color',
583
711
  group: 'color',
584
712
  preview: 'color',
585
- defaultValue: '#333333',
713
+ defaultValue: '#1a1a1a',
586
714
  },
587
715
  {
588
716
  name: 'Radius sm',
@@ -678,7 +806,7 @@ const POS_TOKEN_CATALOG = [
678
806
  kind: 'font-family',
679
807
  group: 'type',
680
808
  preview: 'font-family',
681
- defaultValue: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif",
809
+ defaultValue: "'Chakra Petch', ui-sans-serif, system-ui, sans-serif",
682
810
  },
683
811
  {
684
812
  name: 'Font family display',
@@ -686,7 +814,7 @@ const POS_TOKEN_CATALOG = [
686
814
  kind: 'font-family',
687
815
  group: 'type',
688
816
  preview: 'font-family',
689
- defaultValue: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif",
817
+ defaultValue: "'Helvetica Neue', Helvetica, Arial, sans-serif",
690
818
  },
691
819
  {
692
820
  name: 'Font size sm',
@@ -702,7 +830,7 @@ const POS_TOKEN_CATALOG = [
702
830
  kind: 'length',
703
831
  group: 'type',
704
832
  preview: 'font-size',
705
- defaultValue: '0.875rem',
833
+ defaultValue: '0.90625rem',
706
834
  },
707
835
  {
708
836
  name: 'Font size lg',
@@ -744,6 +872,38 @@ const POS_TOKEN_CATALOG = [
744
872
  preview: 'letter-spacing',
745
873
  defaultValue: '0.28em',
746
874
  },
875
+ {
876
+ name: 'Letter spacing brand',
877
+ variable: '--pos-letter-spacing-brand',
878
+ kind: 'length',
879
+ group: 'type',
880
+ preview: 'letter-spacing',
881
+ defaultValue: '0.08em',
882
+ },
883
+ {
884
+ name: 'Letter spacing tight',
885
+ variable: '--pos-letter-spacing-tight',
886
+ kind: 'length',
887
+ group: 'type',
888
+ preview: 'letter-spacing',
889
+ defaultValue: '-0.03em',
890
+ },
891
+ {
892
+ name: 'Shadow key',
893
+ variable: '--pos-shadow-key',
894
+ kind: 'other',
895
+ group: 'shadow',
896
+ preview: 'shadow',
897
+ defaultValue: '0 1px 3px color-mix(in srgb, var(--pos-color-ink) 8%, transparent)',
898
+ },
899
+ {
900
+ name: 'Shadow overlay',
901
+ variable: '--pos-shadow-overlay',
902
+ kind: 'other',
903
+ group: 'shadow',
904
+ preview: 'shadow',
905
+ defaultValue: '0 var(--pos-space-md) var(--pos-space-2xl) color-mix(in srgb, var(--pos-color-ink) 14%, transparent)',
906
+ },
747
907
  {
748
908
  name: 'Button min height',
749
909
  variable: '--pos-button-min-height',
@@ -944,6 +1104,7 @@ class PosTokens {
944
1104
  radiusTokens = tokensInGroup('radius');
945
1105
  spaceTokens = tokensInGroup('space');
946
1106
  typeTokens = tokensInGroup('type');
1107
+ shadowTokens = tokensInGroup('shadow');
947
1108
  controlTokens = tokensInGroup('control');
948
1109
  overrides = signal({}, ...(ngDevMode ? [{ debugName: "overrides" }] : /* istanbul ignore next */ []));
949
1110
  selection = signal(null, ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
@@ -1085,5 +1246,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1085
1246
  * Generated bundle index. Do not edit.
1086
1247
  */
1087
1248
 
1088
- export { PosBasket, PosItemEntry, PosLogin, PosReceipt, PosTender, PosTokens };
1249
+ export { PosBasket, PosHeader, PosItemEntry, PosLogin, PosReceipt, PosTender, PosTokens, PosTransactionActionBar };
1089
1250
  //# sourceMappingURL=retalia-pos-components.mjs.map