@retalia/pos-components 0.0.4 → 0.0.5

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.
Files changed (45) hide show
  1. package/fesm2022/retalia-pos-components.mjs +1089 -0
  2. package/fesm2022/retalia-pos-components.mjs.map +1 -0
  3. package/package.json +39 -17
  4. package/types/retalia-pos-components.d.ts +300 -0
  5. package/eslint.config.js +0 -32
  6. package/ng-package.json +0 -14
  7. package/src/lib/basket/pos-basket.html +0 -124
  8. package/src/lib/basket/pos-basket.scss +0 -285
  9. package/src/lib/basket/pos-basket.spec.ts +0 -198
  10. package/src/lib/basket/pos-basket.stories.ts +0 -114
  11. package/src/lib/basket/pos-basket.ts +0 -142
  12. package/src/lib/item-entry/pos-item-entry.html +0 -41
  13. package/src/lib/item-entry/pos-item-entry.scss +0 -145
  14. package/src/lib/item-entry/pos-item-entry.spec.ts +0 -123
  15. package/src/lib/item-entry/pos-item-entry.stories.ts +0 -31
  16. package/src/lib/item-entry/pos-item-entry.ts +0 -81
  17. package/src/lib/login/pos-login.html +0 -82
  18. package/src/lib/login/pos-login.scss +0 -238
  19. package/src/lib/login/pos-login.spec.ts +0 -89
  20. package/src/lib/login/pos-login.stories.ts +0 -36
  21. package/src/lib/login/pos-login.ts +0 -150
  22. package/src/lib/receipt/pos-receipt.html +0 -116
  23. package/src/lib/receipt/pos-receipt.scss +0 -367
  24. package/src/lib/receipt/pos-receipt.spec.ts +0 -188
  25. package/src/lib/receipt/pos-receipt.stories.ts +0 -163
  26. package/src/lib/receipt/pos-receipt.ts +0 -129
  27. package/src/lib/tender/pos-tender.html +0 -79
  28. package/src/lib/tender/pos-tender.scss +0 -318
  29. package/src/lib/tender/pos-tender.spec.ts +0 -150
  30. package/src/lib/tender/pos-tender.stories.ts +0 -47
  31. package/src/lib/tender/pos-tender.ts +0 -154
  32. package/src/lib/tokens/pos-theme-css.spec.ts +0 -75
  33. package/src/lib/tokens/pos-theme-css.ts +0 -123
  34. package/src/lib/tokens/pos-token-catalog.ts +0 -514
  35. package/src/lib/tokens/pos-tokens.html +0 -351
  36. package/src/lib/tokens/pos-tokens.scss +0 -437
  37. package/src/lib/tokens/pos-tokens.spec.ts +0 -164
  38. package/src/lib/tokens/pos-tokens.stories.ts +0 -22
  39. package/src/lib/tokens/pos-tokens.ts +0 -208
  40. package/src/public-api.ts +0 -37
  41. package/tsconfig.lib.json +0 -14
  42. package/tsconfig.lib.prod.json +0 -11
  43. package/tsconfig.spec.json +0 -11
  44. /package/{src/styles → styles}/styles.css +0 -0
  45. /package/{src/styles → styles}/tokens.css +0 -0
@@ -1,437 +0,0 @@
1
- :host {
2
- display: block;
3
- color: var(--pos-color-text);
4
- font-family: var(--pos-font-family);
5
- font-size: var(--pos-font-size-md);
6
- line-height: 1.5;
7
- }
8
-
9
- .pos-tokens__page {
10
- display: flex;
11
- flex-direction: column;
12
- gap: var(--pos-space-2xl);
13
- padding: var(--pos-space-xl);
14
- border: 1px solid var(--pos-color-border);
15
- border-radius: var(--pos-radius-lg);
16
- background: var(--pos-color-surface);
17
- }
18
-
19
- .pos-tokens__kicker {
20
- margin: 0 0 var(--pos-space-sm);
21
- color: var(--pos-color-primary);
22
- font-size: var(--pos-font-size-sm);
23
- font-weight: var(--pos-font-weight-bold);
24
- letter-spacing: 0.12em;
25
- text-transform: uppercase;
26
- }
27
-
28
- .pos-tokens__title {
29
- margin: 0 0 var(--pos-space-sm);
30
- font-family: var(--pos-font-family-display);
31
- font-size: var(--pos-font-size-xl);
32
- font-weight: var(--pos-font-weight-bold);
33
- letter-spacing: -0.02em;
34
- }
35
-
36
- .pos-tokens__lede {
37
- margin: 0;
38
- max-width: 48rem;
39
- color: var(--pos-color-text-muted);
40
- }
41
-
42
- .pos-tokens__lede code,
43
- .pos-tokens__swatch-var,
44
- .pos-tokens__default code {
45
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
46
- font-size: 0.85em;
47
- }
48
-
49
- .pos-tokens__toolbar {
50
- display: flex;
51
- flex-wrap: wrap;
52
- gap: var(--pos-space-sm);
53
- margin-top: var(--pos-space-lg);
54
- }
55
-
56
- .pos-tokens__file {
57
- position: absolute;
58
- width: 1px;
59
- height: 1px;
60
- padding: 0;
61
- margin: -1px;
62
- overflow: hidden;
63
- clip: rect(0 0 0 0);
64
- white-space: nowrap;
65
- border: 0;
66
- }
67
-
68
- .pos-tokens__tool {
69
- min-height: var(--pos-button-min-height);
70
- padding: 0 var(--pos-space-lg);
71
- border: 1px solid var(--pos-color-border);
72
- border-radius: var(--pos-radius-md);
73
- background: var(--pos-color-panel-elevated);
74
- color: var(--pos-color-text);
75
- font: inherit;
76
- font-weight: var(--pos-font-weight-semibold);
77
- cursor: pointer;
78
- }
79
-
80
- .pos-tokens__tool:hover,
81
- .pos-tokens__tool:focus-visible {
82
- border-color: var(--pos-color-primary);
83
- }
84
-
85
- .pos-tokens__tool:focus-visible,
86
- .pos-tokens__pick:focus-visible,
87
- .pos-tokens__sample:focus-visible,
88
- .pos-tokens__reset:focus-visible,
89
- .pos-tokens__value:focus-visible,
90
- .pos-tokens__color:focus-visible {
91
- outline: 2px solid var(--pos-color-primary);
92
- outline-offset: 2px;
93
- }
94
-
95
- .pos-tokens__tool:disabled {
96
- cursor: not-allowed;
97
- opacity: 0.55;
98
- }
99
-
100
- .pos-tokens__tool--primary {
101
- border-color: transparent;
102
- background: var(--pos-color-primary);
103
- color: var(--pos-color-on-primary);
104
- font-weight: var(--pos-font-weight-bold);
105
- }
106
-
107
- .pos-tokens__tool--quiet {
108
- min-height: 2.5rem;
109
- padding: 0 var(--pos-space-md);
110
- font-size: var(--pos-font-size-sm);
111
- }
112
-
113
- .pos-tokens__status {
114
- min-height: 1.25rem;
115
- margin: var(--pos-space-sm) 0 0;
116
- color: var(--pos-color-text-muted);
117
- font-size: var(--pos-font-size-sm);
118
- }
119
-
120
- .pos-tokens__layout {
121
- display: grid;
122
- gap: var(--pos-space-xl);
123
- }
124
-
125
- .pos-tokens__gallery,
126
- .pos-tokens__section {
127
- display: flex;
128
- flex-direction: column;
129
- gap: var(--pos-space-lg);
130
- }
131
-
132
- .pos-tokens__heading {
133
- margin: 0;
134
- font-size: var(--pos-font-size-lg);
135
- font-weight: var(--pos-font-weight-bold);
136
- }
137
-
138
- .pos-tokens__hint {
139
- margin: 0;
140
- color: var(--pos-color-text-muted);
141
- font-size: var(--pos-font-size-sm);
142
- }
143
-
144
- .pos-tokens__samples {
145
- display: flex;
146
- flex-wrap: wrap;
147
- align-items: stretch;
148
- gap: var(--pos-space-md);
149
- }
150
-
151
- .pos-tokens__sample {
152
- display: flex;
153
- align-items: center;
154
- margin: 0;
155
- padding: var(--pos-space-xs);
156
- border: 1px solid transparent;
157
- border-radius: var(--pos-radius-md);
158
- background: transparent;
159
- color: inherit;
160
- font: inherit;
161
- cursor: pointer;
162
- }
163
-
164
- .pos-tokens__sample--text {
165
- width: 100%;
166
- justify-content: flex-start;
167
- padding: var(--pos-space-sm);
168
- }
169
-
170
- .pos-tokens__sample:hover,
171
- .pos-tokens__sample:focus-visible {
172
- border-color: var(--pos-color-border);
173
- background: var(--pos-color-surface-muted);
174
- }
175
-
176
- .pos-tokens__sample--selected {
177
- border-color: var(--pos-color-primary);
178
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--pos-color-primary) 35%, transparent);
179
- }
180
-
181
- .pos-tokens__btn {
182
- display: inline-flex;
183
- align-items: center;
184
- justify-content: center;
185
- min-height: var(--pos-button-min-height);
186
- padding: 0 var(--pos-space-lg);
187
- border: 0;
188
- border-radius: var(--pos-radius-md);
189
- font: inherit;
190
- font-weight: var(--pos-font-weight-bold);
191
- pointer-events: none;
192
- }
193
-
194
- .pos-tokens__btn--primary {
195
- background: var(--pos-color-primary);
196
- color: var(--pos-color-on-primary);
197
- }
198
-
199
- .pos-tokens__btn--success {
200
- background: var(--pos-color-success);
201
- color: var(--pos-color-on-success);
202
- }
203
-
204
- .pos-tokens__btn--danger {
205
- background: var(--pos-color-danger);
206
- color: var(--pos-color-on-danger);
207
- }
208
-
209
- .pos-tokens__btn--disabled {
210
- background: var(--pos-color-disabled);
211
- color: var(--pos-color-on-disabled);
212
- }
213
-
214
- .pos-tokens__sample-text {
215
- margin: 0;
216
- }
217
-
218
- .pos-tokens__sample-muted {
219
- color: var(--pos-color-text-muted);
220
- }
221
-
222
- .pos-tokens__sample-danger {
223
- margin: 0;
224
- color: var(--pos-color-danger);
225
- font-weight: var(--pos-font-weight-semibold);
226
- }
227
-
228
- .pos-tokens__swatch-grid,
229
- .pos-tokens__radius-row,
230
- .pos-tokens__space-list,
231
- .pos-tokens__type-list,
232
- .pos-tokens__control-list,
233
- .pos-tokens__fields {
234
- display: grid;
235
- gap: var(--pos-space-md);
236
- margin: 0;
237
- padding: 0;
238
- list-style: none;
239
- }
240
-
241
- .pos-tokens__swatch-grid {
242
- grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
243
- }
244
-
245
- .pos-tokens__radius-row {
246
- grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
247
- }
248
-
249
- .pos-tokens__pick {
250
- display: flex;
251
- flex-direction: column;
252
- align-items: flex-start;
253
- gap: var(--pos-space-sm);
254
- width: 100%;
255
- min-height: 48px;
256
- margin: 0;
257
- padding: var(--pos-space-sm);
258
- border: 1px solid transparent;
259
- border-radius: var(--pos-radius-md);
260
- background: transparent;
261
- color: inherit;
262
- font: inherit;
263
- text-align: left;
264
- cursor: pointer;
265
- }
266
-
267
- .pos-tokens__pick--row {
268
- flex-direction: row;
269
- align-items: center;
270
- }
271
-
272
- .pos-tokens__pick:hover,
273
- .pos-tokens__pick:focus-visible {
274
- border-color: var(--pos-color-border);
275
- background: var(--pos-color-surface-muted);
276
- }
277
-
278
- .pos-tokens__pick--selected {
279
- border-color: var(--pos-color-primary);
280
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--pos-color-primary) 35%, transparent);
281
- }
282
-
283
- .pos-tokens__chip {
284
- display: block;
285
- width: 100%;
286
- height: 3.25rem;
287
- border: 1px solid var(--pos-color-border);
288
- border-radius: var(--pos-radius-md);
289
- }
290
-
291
- .pos-tokens__swatch-meta {
292
- display: flex;
293
- flex-direction: column;
294
- gap: 2px;
295
- }
296
-
297
- .pos-tokens__swatch-name {
298
- display: flex;
299
- flex-wrap: wrap;
300
- align-items: center;
301
- gap: var(--pos-space-xs);
302
- font-weight: var(--pos-font-weight-semibold);
303
- }
304
-
305
- .pos-tokens__edited {
306
- color: var(--pos-color-primary);
307
- font-size: var(--pos-font-size-sm);
308
- font-weight: var(--pos-font-weight-bold);
309
- }
310
-
311
- .pos-tokens__swatch-var {
312
- color: var(--pos-color-text-muted);
313
- word-break: break-all;
314
- }
315
-
316
- .pos-tokens__radius-box,
317
- .pos-tokens__size-box {
318
- flex: 0 0 auto;
319
- width: 4.5rem;
320
- height: 4.5rem;
321
- border: 2px solid var(--pos-color-primary);
322
- background: var(--pos-color-panel);
323
- }
324
-
325
- .pos-tokens__space-bar {
326
- flex: 0 0 auto;
327
- min-width: 4px;
328
- height: 1.25rem;
329
- background: var(--pos-color-primary);
330
- border-radius: var(--pos-radius-sm);
331
- }
332
-
333
- .pos-tokens__type-preview {
334
- font-family: var(--pos-font-family-display);
335
- }
336
-
337
- .pos-tokens__type-preview--caps {
338
- font-weight: var(--pos-font-weight-bold);
339
- text-transform: uppercase;
340
- }
341
-
342
- .pos-tokens__inspector {
343
- display: flex;
344
- flex-direction: column;
345
- gap: var(--pos-space-lg);
346
- padding: var(--pos-space-lg);
347
- border: 1px solid var(--pos-color-border);
348
- border-radius: var(--pos-radius-lg);
349
- background: var(--pos-color-panel);
350
- }
351
-
352
- .pos-tokens__inspector-header {
353
- display: flex;
354
- align-items: center;
355
- justify-content: space-between;
356
- gap: var(--pos-space-sm);
357
- }
358
-
359
- .pos-tokens__fields {
360
- gap: var(--pos-space-lg);
361
- }
362
-
363
- .pos-tokens__field {
364
- display: flex;
365
- flex-direction: column;
366
- gap: var(--pos-space-xs);
367
- }
368
-
369
- .pos-tokens__field-label {
370
- font-weight: var(--pos-font-weight-semibold);
371
- }
372
-
373
- .pos-tokens__field-controls {
374
- display: flex;
375
- align-items: center;
376
- gap: var(--pos-space-sm);
377
- }
378
-
379
- .pos-tokens__color {
380
- flex: 0 0 auto;
381
- width: 2.75rem;
382
- height: 2.75rem;
383
- padding: 0;
384
- border: 1px solid var(--pos-color-border);
385
- border-radius: var(--pos-radius-sm);
386
- background: var(--pos-color-panel-elevated);
387
- cursor: pointer;
388
- }
389
-
390
- .pos-tokens__value {
391
- flex: 1 1 auto;
392
- min-width: 0;
393
- min-height: var(--pos-button-min-height);
394
- padding: 0 var(--pos-space-md);
395
- border: 1px solid var(--pos-color-border);
396
- border-radius: var(--pos-radius-md);
397
- background: var(--pos-color-panel-elevated);
398
- color: inherit;
399
- font: inherit;
400
- }
401
-
402
- .pos-tokens__default {
403
- margin: 0;
404
- color: var(--pos-color-text-muted);
405
- font-size: var(--pos-font-size-sm);
406
- }
407
-
408
- .pos-tokens__reset {
409
- align-self: flex-start;
410
- min-height: 2.5rem;
411
- padding: 0;
412
- border: 0;
413
- background: transparent;
414
- color: var(--pos-color-primary);
415
- font: inherit;
416
- font-size: var(--pos-font-size-sm);
417
- font-weight: var(--pos-font-weight-bold);
418
- cursor: pointer;
419
- }
420
-
421
- @media (min-width: 960px) {
422
- .pos-tokens__layout {
423
- grid-template-columns: minmax(0, 1fr) 22rem;
424
- align-items: start;
425
- }
426
-
427
- .pos-tokens__inspector {
428
- position: sticky;
429
- top: var(--pos-space-lg);
430
- }
431
- }
432
-
433
- @media (max-width: 600px) {
434
- .pos-tokens__page {
435
- padding: var(--pos-space-lg);
436
- }
437
- }
@@ -1,164 +0,0 @@
1
- import { ComponentFixture, TestBed } from '@angular/core/testing';
2
-
3
- import { POS_TOKEN_CATALOG, POS_TOKEN_DEFAULTS } from './pos-token-catalog';
4
- import { PosTokens } from './pos-tokens';
5
-
6
- describe('PosTokens', () => {
7
- let fixture: ComponentFixture<PosTokens>;
8
- let component: PosTokens;
9
-
10
- beforeEach(async () => {
11
- await TestBed.configureTestingModule({
12
- imports: [PosTokens],
13
- }).compileComponents();
14
-
15
- fixture = TestBed.createComponent(PosTokens);
16
- component = fixture.componentInstance;
17
- await fixture.whenStable();
18
- });
19
-
20
- function compiled(): HTMLElement {
21
- return fixture.nativeElement as HTMLElement;
22
- }
23
-
24
- function clickTokenNamed(name: string): HTMLButtonElement {
25
- const button = Array.from(compiled().querySelectorAll('.pos-tokens__pick')).find(
26
- (element) =>
27
- element.querySelector('.pos-tokens__swatch-name')?.textContent?.includes(name),
28
- ) as HTMLButtonElement | undefined;
29
-
30
- if (!button) {
31
- throw new Error(`Token "${name}" not found`);
32
- }
33
-
34
- button.click();
35
- return button;
36
- }
37
-
38
- it('should render the design tokens gallery', () => {
39
- expect(compiled().querySelector('.pos-tokens__title')?.textContent).toContain(
40
- 'Design tokens',
41
- );
42
- expect(compiled().textContent).toContain('--pos-color-primary');
43
- expect(compiled().querySelector('.pos-tokens__btn--primary')).toBeTruthy();
44
- expect(compiled().querySelector('.pos-tokens__tool--primary')?.textContent).toContain(
45
- 'Export CSS',
46
- );
47
- });
48
-
49
- it('should open the inspector when a token is clicked', async () => {
50
- clickTokenNamed('Primary');
51
- await fixture.whenStable();
52
-
53
- expect(compiled().querySelector('#pos-tokens-inspector-title')?.textContent).toContain(
54
- 'Primary',
55
- );
56
- expect(
57
- (compiled().querySelector('.pos-tokens__value') as HTMLInputElement | null)?.value,
58
- ).toBe('#c9b5f0');
59
- });
60
-
61
- it('should apply a live override without changing package defaults', async () => {
62
- clickTokenNamed('Primary');
63
- await fixture.whenStable();
64
-
65
- const input = compiled().querySelector('.pos-tokens__value') as HTMLInputElement;
66
- input.value = '#111111';
67
- input.dispatchEvent(new Event('input', { bubbles: true }));
68
- await fixture.whenStable();
69
-
70
- expect(compiled().querySelector('.pos-tokens__edited')?.textContent).toContain('Edited');
71
- expect(compiled().textContent).toContain('Default');
72
- expect(compiled().querySelector('.pos-tokens__default')?.textContent).toContain('#c9b5f0');
73
- expect(component.themeCss()).toContain('--pos-color-primary: #111111;');
74
- expect(POS_TOKEN_DEFAULTS['--pos-color-primary']).toBe('#c9b5f0');
75
- expect(
76
- POS_TOKEN_CATALOG.find((token) => token.variable === '--pos-color-primary')
77
- ?.defaultValue,
78
- ).toBe('#c9b5f0');
79
- });
80
-
81
- it('should open related tokens when a sample is clicked', async () => {
82
- const primarySample = compiled().querySelector(
83
- '.pos-tokens__sample',
84
- ) as HTMLButtonElement;
85
- primarySample.click();
86
- await fixture.whenStable();
87
-
88
- const fields = Array.from(compiled().querySelectorAll('.pos-tokens__field-label')).map(
89
- (label) => label.textContent?.trim(),
90
- );
91
- expect(fields).toContain('Primary');
92
- expect(fields).toContain('On primary');
93
- expect(fields).toContain('Radius md');
94
- });
95
-
96
- it('should export a complete CSS file for the host POS', () => {
97
- const css = component.themeCss();
98
- expect(css).toContain(':root {');
99
- for (const token of POS_TOKEN_CATALOG) {
100
- expect(css).toContain(`${token.variable}: ${token.defaultValue};`);
101
- }
102
- });
103
-
104
- it('should import an exported theme as overrides only', async () => {
105
- component.loadThemeCss(`
106
- :root {
107
- --pos-color-primary: #00aa00;
108
- --pos-color-success: #16dbcc;
109
- }
110
- `);
111
- await fixture.whenStable();
112
-
113
- expect(component.themeCss()).toContain('--pos-color-primary: #00aa00;');
114
- expect(component.themeCss()).toContain('--pos-color-success: #16dbcc;');
115
- expect(compiled().querySelector('.pos-tokens__status')?.textContent).toContain(
116
- 'Package defaults are unchanged',
117
- );
118
-
119
- clickTokenNamed('Primary');
120
- await fixture.whenStable();
121
- expect(compiled().querySelector('.pos-tokens__edited')).toBeTruthy();
122
-
123
- clickTokenNamed('Success');
124
- await fixture.whenStable();
125
- expect(
126
- compiled().querySelector('.pos-tokens__pick--selected .pos-tokens__edited'),
127
- ).toBeNull();
128
- });
129
-
130
- it('should reset live overrides back to package defaults', async () => {
131
- component.loadThemeCss(':root { --pos-radius-md: 20px; }');
132
- component.resetTheme();
133
- await fixture.whenStable();
134
-
135
- expect(component.themeCss()).toContain('--pos-radius-md: 8px;');
136
- expect(compiled().querySelector('.pos-tokens__edited')).toBeNull();
137
- });
138
-
139
- it('should download the exported CSS file', async () => {
140
- const createObjectURL = vi
141
- .spyOn(URL, 'createObjectURL')
142
- .mockReturnValue('blob:pos-theme');
143
- const revokeObjectURL = vi
144
- .spyOn(URL, 'revokeObjectURL')
145
- .mockImplementation(() => undefined);
146
- const click = vi
147
- .spyOn(HTMLAnchorElement.prototype, 'click')
148
- .mockImplementation(() => undefined);
149
-
150
- const exportButton = compiled().querySelector(
151
- '.pos-tokens__tool--primary',
152
- ) as HTMLButtonElement;
153
- exportButton.click();
154
- await fixture.whenStable();
155
-
156
- expect(createObjectURL).toHaveBeenCalled();
157
- expect(click).toHaveBeenCalled();
158
- expect(revokeObjectURL).toHaveBeenCalled();
159
-
160
- createObjectURL.mockRestore();
161
- revokeObjectURL.mockRestore();
162
- click.mockRestore();
163
- });
164
- });
@@ -1,22 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/angular-vite';
2
-
3
- import { PosTokens } from './pos-tokens';
4
-
5
- const meta: Meta<PosTokens> = {
6
- title: 'Theme / Tokens',
7
- component: PosTokens,
8
- parameters: {
9
- docs: {
10
- description: {
11
- component:
12
- 'Click a sample or token to edit live overrides, then export a complete CSS file for the host POS. Import that file later to resume. Package defaults are never overwritten.',
13
- },
14
- },
15
- },
16
- };
17
-
18
- export default meta;
19
-
20
- type Story = StoryObj<PosTokens>;
21
-
22
- export const Default: Story = {};