@retalia/pos-components 0.0.8 → 0.0.10

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,118 @@ 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
+ /** Bar buttons, in display order. Other envelope actions belong to other components. */
248
+ const BUTTONS = [
249
+ {
250
+ id: 'clearBasket',
251
+ label: 'Cancel',
252
+ className: 'pos-transaction-action-bar__button--cancel',
253
+ intent: { type: 'actionBar.clearBasket' },
254
+ },
255
+ {
256
+ id: 'tender',
257
+ label: 'Cash',
258
+ className: 'pos-transaction-action-bar__button--cash',
259
+ intent: { type: 'actionBar.tender' },
260
+ },
261
+ ];
262
+ class PosTransactionActionBar {
263
+ /** Action ids from the envelope. A button is shown only when its id is listed. */
264
+ availableActions = input([], ...(ngDevMode ? [{ debugName: "availableActions" }] : /* istanbul ignore next */ []));
265
+ /** Locks the shown buttons while the host is busy. Does not choose which actions exist. */
266
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
267
+ action = output();
268
+ buttons = computed(() => {
269
+ const offered = new Set(this.availableActions());
270
+ return BUTTONS.filter((button) => offered.has(button.id));
271
+ }, ...(ngDevMode ? [{ debugName: "buttons" }] : /* istanbul ignore next */ []));
272
+ onPress(button) {
273
+ if (this.disabled()) {
274
+ return;
275
+ }
276
+ this.action.emit(button.intent);
277
+ }
278
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTransactionActionBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
279
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.22", type: PosTransactionActionBar, isStandalone: true, selector: "pos-transaction-action-bar", inputs: { availableActions: { classPropertyName: "availableActions", publicName: "availableActions", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { attributes: { "role": "toolbar", "aria-label": "Sale actions" }, classAttribute: "pos-transaction-action-bar" }, ngImport: i0, template: "@for (button of buttons(); track button.id) {\r\n <button\r\n type=\"button\"\r\n [class]=\"'pos-transaction-action-bar__button ' + button.className\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onPress(button)\"\r\n >\r\n {{ button.label }}\r\n </button>\r\n}\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:stretch;gap:var(--pos-space-md);width:100%;box-sizing:border-box;padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}:host:empty{display:none}.pos-transaction-action-bar__button{flex:1 1 8rem;min-height:var(--pos-button-min-height);border:1px solid transparent;border-radius:var(--pos-radius-md);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer}.pos-transaction-action-bar__button--cancel{background:var(--pos-color-danger);color:var(--pos-color-on-danger)}.pos-transaction-action-bar__button--cash{background:var(--pos-color-success);color:var(--pos-color-on-success)}.pos-transaction-action-bar__button:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:default}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
280
+ }
281
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTransactionActionBar, decorators: [{
282
+ type: Component,
283
+ args: [{ selector: 'pos-transaction-action-bar', changeDetection: ChangeDetectionStrategy.OnPush, host: {
284
+ class: 'pos-transaction-action-bar',
285
+ role: 'toolbar',
286
+ 'aria-label': 'Sale actions',
287
+ }, template: "@for (button of buttons(); track button.id) {\r\n <button\r\n type=\"button\"\r\n [class]=\"'pos-transaction-action-bar__button ' + button.className\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onPress(button)\"\r\n >\r\n {{ button.label }}\r\n </button>\r\n}\r\n", styles: [":host{display:flex;flex-wrap:wrap;align-items:stretch;gap:var(--pos-space-md);width:100%;box-sizing:border-box;padding-top:var(--pos-space-md);border-top:1px solid var(--pos-color-border);color:var(--pos-color-text);font-family:var(--pos-font-family);font-size:var(--pos-font-size-md)}:host:empty{display:none}.pos-transaction-action-bar__button{flex:1 1 8rem;min-height:var(--pos-button-min-height);border:1px solid transparent;border-radius:var(--pos-radius-md);font:inherit;font-weight:var(--pos-font-weight-semibold);cursor:pointer}.pos-transaction-action-bar__button--cancel{background:var(--pos-color-danger);color:var(--pos-color-on-danger)}.pos-transaction-action-bar__button--cash{background:var(--pos-color-success);color:var(--pos-color-on-success)}.pos-transaction-action-bar__button:disabled{background:var(--pos-color-disabled);color:var(--pos-color-on-disabled);cursor:default}\n"] }]
288
+ }], propDecorators: { availableActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "availableActions", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
176
289
 
177
290
  class PosItemEntry {
178
291
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
292
+ /** Draws the panel frame. Off by default so the host can sit the field flush. */
293
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
179
294
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
180
295
  autofocus = input(true, ...(ngDevMode ? [{ debugName: "autofocus" }] : /* istanbul ignore next */ []));
181
296
  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 */ []));
297
+ placeholder = input('Scan barcode, search products', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
298
+ scannerStatus = input('scanner ready', ...(ngDevMode ? [{ debugName: "scannerStatus" }] : /* istanbul ignore next */ []));
299
+ /** Key that moves focus to the field. Empty hides the hint and the shortcut. */
300
+ focusHotkey = input('F2', ...(ngDevMode ? [{ debugName: "focusHotkey" }] : /* istanbul ignore next */ []));
184
301
  action = output();
185
302
  itemInput = viewChild('itemInput', ...(ngDevMode ? [{ debugName: "itemInput" }] : /* istanbul ignore next */ []));
186
303
  reference = signal('', ...(ngDevMode ? [{ debugName: "reference" }] : /* istanbul ignore next */ []));
@@ -192,6 +309,20 @@ class PosItemEntry {
192
309
  }
193
310
  });
194
311
  }
312
+ onDocumentKeydown(event) {
313
+ const hotkey = this.focusHotkey();
314
+ if (!hotkey || event.key !== hotkey || event.repeat) {
315
+ return;
316
+ }
317
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
318
+ return;
319
+ }
320
+ if (this.disabled()) {
321
+ return;
322
+ }
323
+ event.preventDefault();
324
+ this.focusInput();
325
+ }
195
326
  onInput(event) {
196
327
  const target = event.target;
197
328
  if (!(target instanceof HTMLInputElement)) {
@@ -201,13 +332,10 @@ class PosItemEntry {
201
332
  }
202
333
  onSubmit(event) {
203
334
  event.preventDefault();
204
- if (this.disabled()) {
335
+ if (!this.canSubmit()) {
205
336
  return;
206
337
  }
207
338
  const reference = this.reference().trim();
208
- if (!reference) {
209
- return;
210
- }
211
339
  this.action.emit({ type: 'itemEntry.submit', reference });
212
340
  this.reference.set('');
213
341
  this.focusInput();
@@ -216,60 +344,23 @@ class PosItemEntry {
216
344
  this.itemInput()?.nativeElement.focus();
217
345
  }
218
346
  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 });
347
+ 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
348
  }
221
349
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosItemEntry, decorators: [{
222
350
  type: Component,
223
351
  args: [{ selector: 'pos-item-entry', changeDetection: ChangeDetectionStrategy.OnPush, host: {
224
352
  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 }] }] } });
353
+ '(document:keydown)': 'onDocumentKeydown($event)',
354
+ }, 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"] }]
355
+ }], 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
356
 
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
- }
357
+ const COIN_AMOUNTS = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2];
358
+ const NOTE_AMOUNTS = [5, 10, 20, 50];
359
+ function roundMoney(amount) {
243
360
  return Math.round(amount * 100) / 100;
244
361
  }
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;
362
+ function roundUp(amount, step) {
363
+ return roundMoney(Math.ceil(amount / step) * step);
273
364
  }
274
365
  class PosTender {
275
366
  /** Display-only amount due from the host envelope — not calculated here. */
@@ -279,19 +370,40 @@ class PosTender {
279
370
  currency = input('EUR', ...(ngDevMode ? [{ debugName: "currency" }] : /* istanbul ignore next */ []));
280
371
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
281
372
  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 */ []));
373
+ title = input('Cash Payment', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
374
+ amountDueLabel = input('Remaining', ...(ngDevMode ? [{ debugName: "amountDueLabel" }] : /* istanbul ignore next */ []));
375
+ tenderedLabel = input('Amount given', ...(ngDevMode ? [{ debugName: "tenderedLabel" }] : /* istanbul ignore next */ []));
285
376
  changeDueLabel = input('Change due', ...(ngDevMode ? [{ debugName: "changeDueLabel" }] : /* istanbul ignore next */ []));
286
- tenderLabel = input('Tender cash', ...(ngDevMode ? [{ debugName: "tenderLabel" }] : /* istanbul ignore next */ []));
377
+ tenderLabel = input('Pay Now', ...(ngDevMode ? [{ debugName: "tenderLabel" }] : /* istanbul ignore next */ []));
378
+ cancelLabel = input('Cancel', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
379
+ hint = input('tap coins and notes, or use a quick amount.', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
287
380
  processingLabel = input('Processing tender…', ...(ngDevMode ? [{ debugName: "processingLabel" }] : /* istanbul ignore next */ []));
288
381
  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 */ []));
382
+ coins = COIN_AMOUNTS;
383
+ notes = NOTE_AMOUNTS;
384
+ given = signal(0, ...(ngDevMode ? [{ debugName: "given" }] : /* istanbul ignore next */ []));
385
+ parsedAmount = computed(() => {
386
+ const amount = this.given();
387
+ return amount > 0 ? amount : null;
388
+ }, ...(ngDevMode ? [{ debugName: "parsedAmount" }] : /* istanbul ignore next */ []));
292
389
  canTender = computed(() => this.parsedAmount() !== null && !this.disabled(), ...(ngDevMode ? [{ debugName: "canTender" }] : /* istanbul ignore next */ []));
293
390
  hasChangeDue = computed(() => this.changeDue() !== null, ...(ngDevMode ? [{ debugName: "hasChangeDue" }] : /* istanbul ignore next */ []));
294
- displayTendered = computed(() => this.amountInput() || '0', ...(ngDevMode ? [{ debugName: "displayTendered" }] : /* istanbul ignore next */ []));
391
+ displayGiven = computed(() => this.given().toFixed(2), ...(ngDevMode ? [{ debugName: "displayGiven" }] : /* istanbul ignore next */ []));
392
+ quickAmounts = computed(() => {
393
+ const remaining = this.amountDue();
394
+ if (!(remaining > 0)) {
395
+ return [];
396
+ }
397
+ const values = [
398
+ remaining,
399
+ roundUp(remaining, 5),
400
+ roundUp(remaining, 10),
401
+ roundUp(remaining, 20),
402
+ ].map((value) => roundMoney(value));
403
+ return values
404
+ .filter((value, index) => value >= remaining - 0.001 && values.indexOf(value) === index)
405
+ .slice(0, 4);
406
+ }, ...(ngDevMode ? [{ debugName: "quickAmounts" }] : /* istanbul ignore next */ []));
295
407
  statusText = computed(() => {
296
408
  if (this.disabled() && !this.hasChangeDue()) {
297
409
  return this.processingLabel();
@@ -306,11 +418,51 @@ class PosTender {
306
418
  maximumFractionDigits: 2,
307
419
  }).format(amount);
308
420
  }
309
- onKeypad(key) {
421
+ denominationLabel(amount) {
422
+ const currency = (this.currency() || 'EUR').toUpperCase();
423
+ if (amount >= 1) {
424
+ return new Intl.NumberFormat(undefined, {
425
+ style: 'currency',
426
+ currency,
427
+ minimumFractionDigits: 0,
428
+ maximumFractionDigits: 0,
429
+ }).format(amount);
430
+ }
431
+ const minor = Math.round(amount * 100);
432
+ if (currency === 'GBP') {
433
+ return `${minor}p`;
434
+ }
435
+ if (currency === 'EUR') {
436
+ return `${minor}c`;
437
+ }
438
+ return this.formatMoney(amount);
439
+ }
440
+ quickLabel(amount) {
441
+ const formatted = this.formatMoney(amount);
442
+ return roundMoney(amount) === roundMoney(this.amountDue())
443
+ ? `Exact ${formatted}`
444
+ : formatted;
445
+ }
446
+ isExact(amount) {
447
+ return roundMoney(amount) === roundMoney(this.amountDue());
448
+ }
449
+ addAmount(amount) {
450
+ if (this.disabled()) {
451
+ return;
452
+ }
453
+ this.given.update((current) => roundMoney(current + amount));
454
+ }
455
+ setAmount(amount) {
310
456
  if (this.disabled()) {
311
457
  return;
312
458
  }
313
- this.amountInput.update((value) => appendCashKey(value, key));
459
+ this.given.set(roundMoney(amount));
460
+ }
461
+ resetAmount() {
462
+ if (this.disabled()) {
463
+ return;
464
+ }
465
+ this.given.set(0);
314
466
  }
315
467
  onTender() {
316
468
  if (!this.canTender()) {
@@ -322,15 +474,21 @@ class PosTender {
322
474
  }
323
475
  this.action.emit({ type: 'tender.cash', amount });
324
476
  }
477
+ onCancel() {
478
+ if (this.disabled()) {
479
+ return;
480
+ }
481
+ this.action.emit({ type: 'tender.cancel' });
482
+ }
325
483
  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 });
484
+ 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
485
  }
328
486
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosTender, decorators: [{
329
487
  type: Component,
330
488
  args: [{ selector: 'pos-tender', changeDetection: ChangeDetectionStrategy.OnPush, host: {
331
489
  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"] }] } });
490
+ }, 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"] }]
491
+ }], 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
492
 
335
493
  const EMPTY_TOTALS = {
336
494
  gross: 0,
@@ -350,6 +508,8 @@ class PosReceipt {
350
508
  payments = input([], ...(ngDevMode ? [{ debugName: "payments" }] : /* istanbul ignore next */ []));
351
509
  document = input(EMPTY_DOCUMENT, ...(ngDevMode ? [{ debugName: "document" }] : /* istanbul ignore next */ []));
352
510
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
511
+ /** Draws the panel frame. Off by default so the host can sit the receipt flush. */
512
+ bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
353
513
  title = input('Receipt', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
354
514
  emptyMessage = input('No receipt lines', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
355
515
  preparingLabel = input('Preparing receipt…', ...(ngDevMode ? [{ debugName: "preparingLabel" }] : /* istanbul ignore next */ []));
@@ -382,14 +542,14 @@ class PosReceipt {
382
542
  this.action.emit({ type: 'receipt.newSale' });
383
543
  }
384
544
  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 });
545
+ 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
546
  }
387
547
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: PosReceipt, decorators: [{
388
548
  type: Component,
389
549
  args: [{ selector: 'pos-receipt', changeDetection: ChangeDetectionStrategy.OnPush, host: {
390
550
  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"] }] } });
551
+ }, 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"] }]
552
+ }], 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
553
 
394
554
  const POS_TOKEN_CATALOG = [
395
555
  {
@@ -462,7 +622,7 @@ const POS_TOKEN_CATALOG = [
462
622
  kind: 'color',
463
623
  group: 'color',
464
624
  preview: 'color',
465
- defaultValue: '#333333',
625
+ defaultValue: '#1a1a1a',
466
626
  },
467
627
  {
468
628
  name: 'Text muted',
@@ -470,7 +630,7 @@ const POS_TOKEN_CATALOG = [
470
630
  kind: 'color',
471
631
  group: 'color',
472
632
  preview: 'color',
473
- defaultValue: '#999999',
633
+ defaultValue: '#666a70',
474
634
  },
475
635
  {
476
636
  name: 'Surface',
@@ -486,7 +646,7 @@ const POS_TOKEN_CATALOG = [
486
646
  kind: 'color',
487
647
  group: 'color',
488
648
  preview: 'color',
489
- defaultValue: '#f5f5f5',
649
+ defaultValue: '#f5f5f7',
490
650
  },
491
651
  {
492
652
  name: 'Panel',
@@ -494,7 +654,7 @@ const POS_TOKEN_CATALOG = [
494
654
  kind: 'color',
495
655
  group: 'color',
496
656
  preview: 'color',
497
- defaultValue: '#f5f5f5',
657
+ defaultValue: '#ffffff',
498
658
  },
499
659
  {
500
660
  name: 'Panel elevated',
@@ -510,7 +670,7 @@ const POS_TOKEN_CATALOG = [
510
670
  kind: 'color',
511
671
  group: 'color',
512
672
  preview: 'color',
513
- defaultValue: '#333333',
673
+ defaultValue: '#1a1a1a',
514
674
  },
515
675
  {
516
676
  name: 'Border',
@@ -518,7 +678,7 @@ const POS_TOKEN_CATALOG = [
518
678
  kind: 'color',
519
679
  group: 'color',
520
680
  preview: 'color',
521
- defaultValue: '#dddddd',
681
+ defaultValue: '#ececf0',
522
682
  },
523
683
  {
524
684
  name: 'Disabled',
@@ -542,7 +702,7 @@ const POS_TOKEN_CATALOG = [
542
702
  kind: 'color',
543
703
  group: 'color',
544
704
  preview: 'color',
545
- defaultValue: '#333333',
705
+ defaultValue: '#1a1a1a',
546
706
  },
547
707
  {
548
708
  name: 'On display',
@@ -566,7 +726,7 @@ const POS_TOKEN_CATALOG = [
566
726
  kind: 'color',
567
727
  group: 'color',
568
728
  preview: 'color',
569
- defaultValue: '#dddddd',
729
+ defaultValue: '#ececf0',
570
730
  },
571
731
  {
572
732
  name: 'Key active',
@@ -574,7 +734,7 @@ const POS_TOKEN_CATALOG = [
574
734
  kind: 'color',
575
735
  group: 'color',
576
736
  preview: 'color',
577
- defaultValue: '#c9b5f0',
737
+ defaultValue: '#f0e6fd',
578
738
  },
579
739
  {
580
740
  name: 'On key active',
@@ -582,7 +742,7 @@ const POS_TOKEN_CATALOG = [
582
742
  kind: 'color',
583
743
  group: 'color',
584
744
  preview: 'color',
585
- defaultValue: '#333333',
745
+ defaultValue: '#1a1a1a',
586
746
  },
587
747
  {
588
748
  name: 'Radius sm',
@@ -678,7 +838,7 @@ const POS_TOKEN_CATALOG = [
678
838
  kind: 'font-family',
679
839
  group: 'type',
680
840
  preview: 'font-family',
681
- defaultValue: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif",
841
+ defaultValue: "'Chakra Petch', ui-sans-serif, system-ui, sans-serif",
682
842
  },
683
843
  {
684
844
  name: 'Font family display',
@@ -686,7 +846,7 @@ const POS_TOKEN_CATALOG = [
686
846
  kind: 'font-family',
687
847
  group: 'type',
688
848
  preview: 'font-family',
689
- defaultValue: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif",
849
+ defaultValue: "'Helvetica Neue', Helvetica, Arial, sans-serif",
690
850
  },
691
851
  {
692
852
  name: 'Font size sm',
@@ -702,7 +862,7 @@ const POS_TOKEN_CATALOG = [
702
862
  kind: 'length',
703
863
  group: 'type',
704
864
  preview: 'font-size',
705
- defaultValue: '0.875rem',
865
+ defaultValue: '0.90625rem',
706
866
  },
707
867
  {
708
868
  name: 'Font size lg',
@@ -744,6 +904,38 @@ const POS_TOKEN_CATALOG = [
744
904
  preview: 'letter-spacing',
745
905
  defaultValue: '0.28em',
746
906
  },
907
+ {
908
+ name: 'Letter spacing brand',
909
+ variable: '--pos-letter-spacing-brand',
910
+ kind: 'length',
911
+ group: 'type',
912
+ preview: 'letter-spacing',
913
+ defaultValue: '0.08em',
914
+ },
915
+ {
916
+ name: 'Letter spacing tight',
917
+ variable: '--pos-letter-spacing-tight',
918
+ kind: 'length',
919
+ group: 'type',
920
+ preview: 'letter-spacing',
921
+ defaultValue: '-0.03em',
922
+ },
923
+ {
924
+ name: 'Shadow key',
925
+ variable: '--pos-shadow-key',
926
+ kind: 'other',
927
+ group: 'shadow',
928
+ preview: 'shadow',
929
+ defaultValue: '0 1px 3px color-mix(in srgb, var(--pos-color-ink) 8%, transparent)',
930
+ },
931
+ {
932
+ name: 'Shadow overlay',
933
+ variable: '--pos-shadow-overlay',
934
+ kind: 'other',
935
+ group: 'shadow',
936
+ preview: 'shadow',
937
+ defaultValue: '0 var(--pos-space-md) var(--pos-space-2xl) color-mix(in srgb, var(--pos-color-ink) 14%, transparent)',
938
+ },
747
939
  {
748
940
  name: 'Button min height',
749
941
  variable: '--pos-button-min-height',
@@ -944,6 +1136,7 @@ class PosTokens {
944
1136
  radiusTokens = tokensInGroup('radius');
945
1137
  spaceTokens = tokensInGroup('space');
946
1138
  typeTokens = tokensInGroup('type');
1139
+ shadowTokens = tokensInGroup('shadow');
947
1140
  controlTokens = tokensInGroup('control');
948
1141
  overrides = signal({}, ...(ngDevMode ? [{ debugName: "overrides" }] : /* istanbul ignore next */ []));
949
1142
  selection = signal(null, ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
@@ -1085,5 +1278,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1085
1278
  * Generated bundle index. Do not edit.
1086
1279
  */
1087
1280
 
1088
- export { PosBasket, PosItemEntry, PosLogin, PosReceipt, PosTender, PosTokens };
1281
+ export { PosBasket, PosHeader, PosItemEntry, PosLogin, PosReceipt, PosTender, PosTokens, PosTransactionActionBar };
1089
1282
  //# sourceMappingURL=retalia-pos-components.mjs.map