@adobe-commerce/elsie 1.6.0 → 1.7.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -2
- package/src/components/CartItem/CartItem.css +22 -3
- package/src/components/CartItem/CartItem.stories.tsx +102 -57
- package/src/components/CartItem/CartItem.tsx +10 -0
- package/src/components/CartList/CartList.stories.tsx +66 -3
- package/src/components/Field/Field.css +3 -3
- package/src/components/Field/Field.stories.tsx +45 -3
- package/src/components/Field/Field.tsx +22 -20
- package/src/components/Input/Input.css +3 -3
- package/src/components/Input/Input.stories.tsx +42 -3
- package/src/components/Input/Input.tsx +14 -6
- package/src/components/Picker/Picker.css +3 -3
- package/src/components/Picker/Picker.stories.tsx +74 -3
- package/src/components/Picker/Picker.tsx +8 -7
- package/src/components/RadioButton/RadioButton.css +8 -3
- package/src/components/RadioButton/RadioButton.stories.tsx +37 -3
- package/src/components/RadioButton/RadioButton.tsx +18 -4
- package/src/components/RadioButton/index.ts +3 -3
- package/src/components/TextArea/TextArea.css +4 -4
- package/src/components/TextArea/TextArea.stories.tsx +54 -7
- package/src/components/TextArea/TextArea.tsx +5 -5
- package/src/components/UIProvider/normalize.css +8 -3
- package/src/lib/debounce.ts +5 -1
- package/src/lib/get-price-formatter.ts +1 -1
- package/src/lib/index.ts +1 -0
- package/src/lib/wrap-required-asterisk.tsx +70 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe-commerce/elsie",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0-beta2",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"description": "Domain Package SDK",
|
|
6
6
|
"engines": {
|
|
@@ -58,7 +58,6 @@
|
|
|
58
58
|
"@storybook/preact": "^8.2.3",
|
|
59
59
|
"@storybook/preact-vite": "^8.2.3",
|
|
60
60
|
"@storybook/preact-webpack5": "^8.2.3",
|
|
61
|
-
"@storybook/storybook-deployer": "^2.8.16",
|
|
62
61
|
"@storybook/test": "^8.2.3",
|
|
63
62
|
"@storybook/test-runner": "^0.19.1",
|
|
64
63
|
"@storybook/theming": "^8.2.3",
|
|
@@ -45,6 +45,16 @@
|
|
|
45
45
|
height: auto;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
.dropin-cart-item__image:is(a),
|
|
49
|
+
.dropin-cart-item__image a {
|
|
50
|
+
display: inline-block;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.dropin-cart-item__image:is(a) img,
|
|
54
|
+
.dropin-cart-item__image a img {
|
|
55
|
+
display: block;
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
.dropin-cart-item__title {
|
|
49
59
|
font: var(--type-body-1-default-font);
|
|
50
60
|
letter-spacing: var(--type-body-1-default-letter-spacing);
|
|
@@ -266,6 +276,13 @@
|
|
|
266
276
|
color: var(--color-neutral-800);
|
|
267
277
|
}
|
|
268
278
|
|
|
279
|
+
.dropin-cart-item__row-total-footer {
|
|
280
|
+
margin-top: var(--spacing-xsmall);
|
|
281
|
+
font: var(--type-body-2-emphasized-font);
|
|
282
|
+
letter-spacing: var(--type-body-2-emphasized-letter-spacing);
|
|
283
|
+
color: var(--color-neutral-800);
|
|
284
|
+
}
|
|
285
|
+
|
|
269
286
|
.dropin-cart-item__total-tax-message {
|
|
270
287
|
margin-left: var(--spacing-xxsmall);
|
|
271
288
|
}
|
|
@@ -283,7 +300,8 @@
|
|
|
283
300
|
}
|
|
284
301
|
|
|
285
302
|
/* Smallish / Medium */
|
|
286
|
-
@container cart-item (width >=
|
|
303
|
+
@container cart-item (width >=400px) and (width < 737px) {
|
|
304
|
+
|
|
287
305
|
.dropin-cart-item__title,
|
|
288
306
|
.dropin-cart-item__sku,
|
|
289
307
|
.dropin-cart-item__attributes,
|
|
@@ -313,7 +331,8 @@
|
|
|
313
331
|
}
|
|
314
332
|
|
|
315
333
|
/* Large */
|
|
316
|
-
@container cart-item (width >=
|
|
334
|
+
@container cart-item (width >=737px) and (width < 1192px) {
|
|
335
|
+
|
|
317
336
|
/* Grid */
|
|
318
337
|
.dropin-cart-item__wrapper {
|
|
319
338
|
grid-template-columns: repeat(12, 1fr);
|
|
@@ -391,7 +410,7 @@
|
|
|
391
410
|
}
|
|
392
411
|
|
|
393
412
|
/* Extra Large */
|
|
394
|
-
@container cart-item (width >=
|
|
413
|
+
@container cart-item (width >=1192px) {
|
|
395
414
|
.dropin-cart-item {
|
|
396
415
|
--item-group-spacing: var(--spacing-xxsmall);
|
|
397
416
|
--group-spacing: var(--spacing-small);
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
CartItem as component,
|
|
18
18
|
CartItemProps,
|
|
19
19
|
CartItemSkeleton,
|
|
20
|
-
Icon,
|
|
20
|
+
Icon,
|
|
21
|
+
Button,
|
|
21
22
|
} from '@adobe-commerce/elsie/components';
|
|
22
23
|
import { WarningWithCircle } from '@adobe-commerce/elsie/icons';
|
|
23
24
|
|
|
@@ -43,13 +44,13 @@ const meta: Meta<CartItemProps> = {
|
|
|
43
44
|
options: ['Image', 'None'],
|
|
44
45
|
mapping: {
|
|
45
46
|
Image: (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
<Image
|
|
48
|
+
src="https://picsum.photos/132/184"
|
|
49
|
+
width="132"
|
|
50
|
+
height="184"
|
|
51
|
+
alt="Some alternative text"
|
|
52
|
+
loading="lazy"
|
|
53
|
+
/>
|
|
53
54
|
),
|
|
54
55
|
None: undefined,
|
|
55
56
|
},
|
|
@@ -83,9 +84,9 @@ const meta: Meta<CartItemProps> = {
|
|
|
83
84
|
options: ['Description', 'None'],
|
|
84
85
|
mapping: {
|
|
85
86
|
Description: (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
<div>
|
|
88
|
+
Secondary product information such as brand name, description, etc.
|
|
89
|
+
</div>
|
|
89
90
|
),
|
|
90
91
|
None: undefined,
|
|
91
92
|
},
|
|
@@ -118,12 +119,12 @@ const meta: Meta<CartItemProps> = {
|
|
|
118
119
|
options: ['Attributes', 'none'],
|
|
119
120
|
mapping: {
|
|
120
121
|
Attributes: (
|
|
122
|
+
<div>
|
|
121
123
|
<div>
|
|
122
|
-
|
|
123
|
-
Activity: Gym, Hiking, Overnight, School, Trail, Travel, Urban
|
|
124
|
-
</div>
|
|
125
|
-
<div>Material: Nylon, Polyester</div>
|
|
124
|
+
Activity: Gym, Hiking, Overnight, School, Trail, Travel, Urban
|
|
126
125
|
</div>
|
|
126
|
+
<div>Material: Nylon, Polyester</div>
|
|
127
|
+
</div>
|
|
127
128
|
),
|
|
128
129
|
none: undefined,
|
|
129
130
|
},
|
|
@@ -170,10 +171,10 @@ const meta: Meta<CartItemProps> = {
|
|
|
170
171
|
options: ['Total', 'Final', 'None'],
|
|
171
172
|
mapping: {
|
|
172
173
|
Total: (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
<>
|
|
175
|
+
<Price amount={59.98} variant="strikethrough" />
|
|
176
|
+
<Price amount={55.95} sale />
|
|
177
|
+
</>
|
|
177
178
|
),
|
|
178
179
|
Final: <Price amount={55.95} sale />,
|
|
179
180
|
None: undefined,
|
|
@@ -192,9 +193,9 @@ const meta: Meta<CartItemProps> = {
|
|
|
192
193
|
options: ['totalExcludingTax', 'None'],
|
|
193
194
|
mapping: {
|
|
194
195
|
totalExcludingTax: (
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
<>
|
|
197
|
+
<Price amount={53.99} weight="normal" />
|
|
198
|
+
</>
|
|
198
199
|
),
|
|
199
200
|
None: undefined,
|
|
200
201
|
},
|
|
@@ -277,9 +278,9 @@ const meta: Meta<CartItemProps> = {
|
|
|
277
278
|
mapping: {
|
|
278
279
|
none: null,
|
|
279
280
|
RunningOut: (
|
|
280
|
-
|
|
281
|
+
<span>
|
|
281
282
|
<Icon source={WarningWithCircle} size={'16'} aria-hidden={true} />{' '}
|
|
282
|
-
|
|
283
|
+
Out of stock!
|
|
283
284
|
</span>
|
|
284
285
|
),
|
|
285
286
|
},
|
|
@@ -325,26 +326,42 @@ const meta: Meta<CartItemProps> = {
|
|
|
325
326
|
type: 'select',
|
|
326
327
|
labels: {
|
|
327
328
|
Button: 'Button',
|
|
328
|
-
None: 'None'
|
|
329
|
+
None: 'None',
|
|
329
330
|
},
|
|
330
331
|
},
|
|
331
332
|
description: 'Wishlist control.',
|
|
332
333
|
options: ['Button', 'None'],
|
|
333
334
|
mapping: {
|
|
334
335
|
Button: (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
336
|
+
<Button
|
|
337
|
+
size="medium"
|
|
338
|
+
type="submit"
|
|
339
|
+
icon={<Icon source="Heart" />}
|
|
340
|
+
variant="tertiary"
|
|
341
|
+
>
|
|
342
|
+
Move to wishlist
|
|
343
|
+
</Button>
|
|
343
344
|
),
|
|
344
345
|
None: undefined,
|
|
345
346
|
},
|
|
346
347
|
table: { defaultValue: { summary: 'null' } },
|
|
347
348
|
},
|
|
349
|
+
rowTotalFooter: {
|
|
350
|
+
control: {
|
|
351
|
+
type: 'check',
|
|
352
|
+
labels: ['Super Offer Badge'],
|
|
353
|
+
},
|
|
354
|
+
description: 'Content displayed right below the total row price.',
|
|
355
|
+
options: ['SuperOffer'],
|
|
356
|
+
mapping: {
|
|
357
|
+
SuperOffer: (
|
|
358
|
+
<div style={{ color: 'var(--color-alert-800)', fontWeight: 'bold' }}>
|
|
359
|
+
Super offer
|
|
360
|
+
</div>
|
|
361
|
+
),
|
|
362
|
+
},
|
|
363
|
+
table: { defaultValue: { summary: 'null' } },
|
|
364
|
+
},
|
|
348
365
|
footer: {
|
|
349
366
|
control: {
|
|
350
367
|
type: 'check',
|
|
@@ -354,24 +371,24 @@ const meta: Meta<CartItemProps> = {
|
|
|
354
371
|
'Final Sales and Returns Policy',
|
|
355
372
|
],
|
|
356
373
|
},
|
|
357
|
-
description: 'Footer content.',
|
|
374
|
+
description: 'Footer content displayed at the bottom of the cart item.',
|
|
358
375
|
options: ['Promotions', 'Delivery', 'Returns'],
|
|
359
376
|
mapping: {
|
|
360
377
|
Promotions: <div>Extra 20% Off Clearance with Code: EXTRA20</div>,
|
|
361
378
|
Delivery: (
|
|
379
|
+
<div>
|
|
380
|
+
<div>Free Shipping</div>
|
|
362
381
|
<div>
|
|
363
|
-
|
|
364
|
-
<
|
|
365
|
-
Delivery Estimate
|
|
366
|
-
<p>Order now for delivery Aug 26 - Aug 28 to ZIP code: 80201</p>
|
|
367
|
-
</div>
|
|
382
|
+
Delivery Estimate
|
|
383
|
+
<p>Order now for delivery Aug 26 - Aug 28 to ZIP code: 80201</p>
|
|
368
384
|
</div>
|
|
385
|
+
</div>
|
|
369
386
|
),
|
|
370
387
|
Returns: (
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
388
|
+
<div>
|
|
389
|
+
Final-sale items, identified by a price ending in .99 or .97, cannot
|
|
390
|
+
be canceled or returned.
|
|
391
|
+
</div>
|
|
375
392
|
),
|
|
376
393
|
},
|
|
377
394
|
table: { defaultValue: { summary: 'null' } },
|
|
@@ -440,7 +457,6 @@ export const CartItem: Story = {
|
|
|
440
457
|
discount: 'none' as any,
|
|
441
458
|
savings: 'none' as any,
|
|
442
459
|
actions: 'Button' as any,
|
|
443
|
-
footer: null as any,
|
|
444
460
|
warning: 'none' as any,
|
|
445
461
|
alert: 'none' as any,
|
|
446
462
|
loading: false,
|
|
@@ -453,48 +469,48 @@ export const CartItem: Story = {
|
|
|
453
469
|
},
|
|
454
470
|
play: async () => {
|
|
455
471
|
const canvasElement = document.querySelector(
|
|
456
|
-
|
|
472
|
+
'#storybook-root'
|
|
457
473
|
) as HTMLElement;
|
|
458
474
|
const canvas = within(canvasElement);
|
|
459
475
|
|
|
460
476
|
const itemImage = document.querySelector(
|
|
461
|
-
|
|
477
|
+
'.dropin-cart-item__image'
|
|
462
478
|
) as HTMLElement;
|
|
463
479
|
expect(itemImage).toBeVisible();
|
|
464
480
|
const itemTitle = document.querySelector(
|
|
465
|
-
|
|
481
|
+
'.dropin-cart-item__title'
|
|
466
482
|
) as HTMLElement;
|
|
467
483
|
expect(itemTitle).toBeVisible();
|
|
468
484
|
const itemSku = document.querySelector(
|
|
469
|
-
|
|
485
|
+
'.dropin-cart-item__sku'
|
|
470
486
|
) as HTMLElement;
|
|
471
487
|
expect(itemSku).toBeVisible();
|
|
472
488
|
const itemConfigurations = document.querySelector(
|
|
473
|
-
|
|
489
|
+
'.dropin-cart-item__configurations'
|
|
474
490
|
) as HTMLElement;
|
|
475
491
|
expect(itemConfigurations).toBeVisible();
|
|
476
492
|
const itemPrice = document.querySelector(
|
|
477
|
-
|
|
493
|
+
'.dropin-cart-item__price'
|
|
478
494
|
) as HTMLElement;
|
|
479
495
|
expect(itemPrice).toBeVisible();
|
|
480
496
|
const quantityStepper = document.querySelector(
|
|
481
|
-
|
|
497
|
+
'.dropin-cart-item__quantity'
|
|
482
498
|
) as HTMLElement;
|
|
483
499
|
expect(quantityStepper).toBeVisible();
|
|
484
500
|
const itemTotal = document.querySelector(
|
|
485
|
-
|
|
501
|
+
'.dropin-cart-item__total'
|
|
486
502
|
) as HTMLElement;
|
|
487
503
|
expect(itemTotal).toBeVisible();
|
|
488
504
|
const actions = document.querySelector(
|
|
489
|
-
|
|
505
|
+
'.dropin-cart-item__buttons'
|
|
490
506
|
) as HTMLElement;
|
|
491
507
|
expect(actions).toBeVisible();
|
|
492
508
|
|
|
493
509
|
const increaseButton = document.querySelector(
|
|
494
|
-
|
|
510
|
+
'button[aria-label="Increase Quantity"]'
|
|
495
511
|
) as HTMLElement;
|
|
496
512
|
const decreaseButton = document.querySelector(
|
|
497
|
-
|
|
513
|
+
'button[aria-label="Decrease Quantity"]'
|
|
498
514
|
) as HTMLElement;
|
|
499
515
|
|
|
500
516
|
// Without this wait test failing intermittently as click event is triggering before even element fully loaded
|
|
@@ -542,7 +558,6 @@ export const ReadOnly: Story = {
|
|
|
542
558
|
attributes: 'none' as any,
|
|
543
559
|
quantity: 1,
|
|
544
560
|
description: 'Description' as any,
|
|
545
|
-
footer: null as any,
|
|
546
561
|
warning: 'none' as any,
|
|
547
562
|
alert: 'none' as any,
|
|
548
563
|
discount: 'none' as any,
|
|
@@ -608,7 +623,6 @@ export const DropdownQuantity: Story = {
|
|
|
608
623
|
description: 'Description' as any,
|
|
609
624
|
discount: 'none' as any,
|
|
610
625
|
savings: 'none' as any,
|
|
611
|
-
footer: null as any,
|
|
612
626
|
warning: 'none' as any,
|
|
613
627
|
alert: 'none' as any,
|
|
614
628
|
loading: false,
|
|
@@ -626,3 +640,34 @@ export const DropdownQuantity: Story = {
|
|
|
626
640
|
quantityType: 'dropdown',
|
|
627
641
|
},
|
|
628
642
|
};
|
|
643
|
+
|
|
644
|
+
export const WithPromotionalBadge: Story = {
|
|
645
|
+
args: {
|
|
646
|
+
ariaLabel: 'Short Name',
|
|
647
|
+
image: 'Image' as any,
|
|
648
|
+
title: 'Short' as any,
|
|
649
|
+
price: 'Price' as any,
|
|
650
|
+
rowTotalFooter: 'SuperOffer' as any,
|
|
651
|
+
total: 'Final' as any,
|
|
652
|
+
sku: 'Sku' as any,
|
|
653
|
+
quantity: 1,
|
|
654
|
+
warning: 'none' as any,
|
|
655
|
+
alert: 'none' as any,
|
|
656
|
+
discount: 'none' as any,
|
|
657
|
+
savings: 'none' as any,
|
|
658
|
+
loading: false,
|
|
659
|
+
updating: false,
|
|
660
|
+
configurations: {
|
|
661
|
+
Color: 'Blue',
|
|
662
|
+
Size: 'L',
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
play: async ({ canvasElement }) => {
|
|
666
|
+
// Verify row total footer is rendered below the total
|
|
667
|
+
const rowTotalFooter = canvasElement.querySelector(
|
|
668
|
+
'.dropin-cart-item__row-total-footer'
|
|
669
|
+
) as HTMLElement;
|
|
670
|
+
expect(rowTotalFooter).toBeTruthy();
|
|
671
|
+
expect(rowTotalFooter?.textContent).toContain('Super offer');
|
|
672
|
+
},
|
|
673
|
+
};
|
|
@@ -30,6 +30,7 @@ export interface CartItemProps
|
|
|
30
30
|
image?: VNode;
|
|
31
31
|
title?: VNode;
|
|
32
32
|
price?: VNode;
|
|
33
|
+
rowTotalFooter?: VNode;
|
|
33
34
|
taxIncluded?: boolean;
|
|
34
35
|
taxExcluded?: boolean;
|
|
35
36
|
total?: VNode;
|
|
@@ -62,6 +63,7 @@ export const CartItem: FunctionComponent<CartItemProps> = ({
|
|
|
62
63
|
image,
|
|
63
64
|
title,
|
|
64
65
|
price,
|
|
66
|
+
rowTotalFooter,
|
|
65
67
|
taxIncluded = false,
|
|
66
68
|
taxExcluded = false,
|
|
67
69
|
total,
|
|
@@ -434,6 +436,14 @@ export const CartItem: FunctionComponent<CartItemProps> = ({
|
|
|
434
436
|
className={classes(['dropin-cart-item__savings'])}
|
|
435
437
|
/>
|
|
436
438
|
)}
|
|
439
|
+
|
|
440
|
+
{/* Row Total Footer */}
|
|
441
|
+
{rowTotalFooter && (
|
|
442
|
+
<VComponent
|
|
443
|
+
node={rowTotalFooter}
|
|
444
|
+
className={classes(['dropin-cart-item__row-total-footer'])}
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
437
447
|
</div>
|
|
438
448
|
|
|
439
449
|
{/* Footer */}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright 2024 Adobe
|
|
3
3
|
* All Rights Reserved.
|
|
4
4
|
*
|
|
5
|
-
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
-
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
-
* accompanying it.
|
|
5
|
+
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
+
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
+
* accompanying it.
|
|
8
8
|
*******************************************************************/
|
|
9
9
|
|
|
10
10
|
// https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
|
|
@@ -67,6 +67,12 @@ export const CartList: Story = {
|
|
|
67
67
|
tags: ['skip'],
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
export const WithPromotionalBadges: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
children: renderItemsWithPromos(3),
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
70
76
|
function renderItems(count: number) {
|
|
71
77
|
return Array.from({ length: count }, (_, i) => i + 1).map((key) => (
|
|
72
78
|
<CartItem
|
|
@@ -109,3 +115,60 @@ function renderItems(count: number) {
|
|
|
109
115
|
/>
|
|
110
116
|
));
|
|
111
117
|
}
|
|
118
|
+
|
|
119
|
+
function renderItemsWithPromos(count: number) {
|
|
120
|
+
return Array.from({ length: count }, (_, i) => i + 1).map((key) => {
|
|
121
|
+
// Show promo badge on first and third items as an example
|
|
122
|
+
const showPromo = key === 1 || key === 3;
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<CartItem
|
|
126
|
+
key={key}
|
|
127
|
+
image={
|
|
128
|
+
<Image
|
|
129
|
+
src="https://picsum.photos/132/184"
|
|
130
|
+
width="132"
|
|
131
|
+
height="184"
|
|
132
|
+
alt="Some alternative text"
|
|
133
|
+
loading="lazy"
|
|
134
|
+
/>
|
|
135
|
+
}
|
|
136
|
+
title={<div>Product Name {key}</div>}
|
|
137
|
+
description={
|
|
138
|
+
<div>
|
|
139
|
+
Secondary product information such as brand name, description, etc.
|
|
140
|
+
</div>
|
|
141
|
+
}
|
|
142
|
+
sku={<div>SKU: 59YK{key}</div>}
|
|
143
|
+
quantity={1}
|
|
144
|
+
price={
|
|
145
|
+
<span>
|
|
146
|
+
<Price
|
|
147
|
+
amount={53.99}
|
|
148
|
+
style={{ fontWeight: 'inherit', color: 'inherit' }}
|
|
149
|
+
/>
|
|
150
|
+
</span>
|
|
151
|
+
}
|
|
152
|
+
rowTotalFooter={
|
|
153
|
+
showPromo ? (
|
|
154
|
+
<div
|
|
155
|
+
style={{ color: 'var(--color-alert-800)', fontWeight: 'bold' }}
|
|
156
|
+
>
|
|
157
|
+
Super offer
|
|
158
|
+
</div>
|
|
159
|
+
) : undefined
|
|
160
|
+
}
|
|
161
|
+
total={
|
|
162
|
+
<span>
|
|
163
|
+
<Price amount={59.98} variant="strikethrough" />{' '}
|
|
164
|
+
<Price amount={55.95} sale />
|
|
165
|
+
</span>
|
|
166
|
+
}
|
|
167
|
+
configurations={{ Color: 'Blue', Size: 'L' }}
|
|
168
|
+
onRemove={() => {}}
|
|
169
|
+
onQuantity={() => {}}
|
|
170
|
+
taxIncluded={true}
|
|
171
|
+
/>
|
|
172
|
+
);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright 2024 Adobe
|
|
3
3
|
* All Rights Reserved.
|
|
4
4
|
*
|
|
5
|
-
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
-
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
-
* accompanying it.
|
|
5
|
+
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
+
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
+
* accompanying it.
|
|
8
8
|
*******************************************************************/
|
|
9
9
|
|
|
10
10
|
/* https://cssguidelin.es/#bem-like-naming */
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright 2024 Adobe
|
|
3
3
|
* All Rights Reserved.
|
|
4
4
|
*
|
|
5
|
-
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
-
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
-
* accompanying it.
|
|
5
|
+
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
+
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
+
* accompanying it.
|
|
8
8
|
*******************************************************************/
|
|
9
9
|
|
|
10
10
|
// https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
|
|
@@ -230,6 +230,48 @@ export const CheckboxField: Story = {
|
|
|
230
230
|
},
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Field with a label that includes a required asterisk.
|
|
235
|
+
* The asterisk is automatically wrapped in a `<span class="dropin-label-required">` for consistent styling.
|
|
236
|
+
*
|
|
237
|
+
* ```ts
|
|
238
|
+
* import { Field } from '@adobe-commerce/elsie/components/Field';
|
|
239
|
+
* import { Input } from '@adobe-commerce/elsie/components/Input';
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* This example demonstrates:
|
|
243
|
+
* - Automatic asterisk wrapping in field labels
|
|
244
|
+
* - The asterisk can be styled independently using `.dropin-label-required`
|
|
245
|
+
* - Works with any child component (Input, Picker, etc.)
|
|
246
|
+
*/
|
|
247
|
+
export const WithRequiredAsterisk: Story = {
|
|
248
|
+
render: (args) => (
|
|
249
|
+
<Field {...args}>
|
|
250
|
+
<Input name="requiredField" placeholder="Enter your email" />
|
|
251
|
+
</Field>
|
|
252
|
+
),
|
|
253
|
+
args: {
|
|
254
|
+
label: 'Email Address',
|
|
255
|
+
hint: 'We will never share your email',
|
|
256
|
+
required: true,
|
|
257
|
+
error: '',
|
|
258
|
+
success: '',
|
|
259
|
+
size: 'medium',
|
|
260
|
+
disabled: false,
|
|
261
|
+
},
|
|
262
|
+
play: async ({ canvasElement }) => {
|
|
263
|
+
// Verify the label is rendered
|
|
264
|
+
const label = canvasElement.querySelector('.dropin-field__label');
|
|
265
|
+
await expect(label).toBeTruthy();
|
|
266
|
+
await expect(label?.textContent).toBe('Email Address *');
|
|
267
|
+
|
|
268
|
+
// Verify the asterisk is wrapped in a span with required class
|
|
269
|
+
const asteriskSpan = label?.querySelector('.dropin-label-required');
|
|
270
|
+
await expect(asteriskSpan).toBeTruthy();
|
|
271
|
+
await expect(asteriskSpan?.textContent).toBe('*');
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
|
|
233
275
|
/**
|
|
234
276
|
* ```ts
|
|
235
277
|
* import { Field } from '@adobe-commerce/elsie/components/Field';
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
* Copyright 2024 Adobe
|
|
3
3
|
* All Rights Reserved.
|
|
4
4
|
*
|
|
5
|
-
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
-
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
-
* accompanying it.
|
|
5
|
+
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
+
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
+
* accompanying it.
|
|
8
8
|
*******************************************************************/
|
|
9
9
|
|
|
10
10
|
import '@adobe-commerce/elsie/components/Field/Field.css';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
classes,
|
|
13
|
+
VComponent,
|
|
14
|
+
wrapRequiredAsterisk,
|
|
15
|
+
} from '@adobe-commerce/elsie/lib';
|
|
12
16
|
import { FunctionComponent, VNode } from 'preact';
|
|
13
17
|
import { HTMLAttributes } from 'preact/compat';
|
|
14
18
|
|
|
@@ -32,6 +36,7 @@ export const Field: FunctionComponent<FieldProps> = ({
|
|
|
32
36
|
size = 'medium',
|
|
33
37
|
disabled = false,
|
|
34
38
|
children,
|
|
39
|
+
required,
|
|
35
40
|
...props
|
|
36
41
|
}) => {
|
|
37
42
|
const id =
|
|
@@ -40,20 +45,19 @@ export const Field: FunctionComponent<FieldProps> = ({
|
|
|
40
45
|
let fieldContent: VNode | string | null = null;
|
|
41
46
|
|
|
42
47
|
if (children && typeof children !== 'string') {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
fieldContent = (
|
|
49
|
+
<VComponent
|
|
50
|
+
node={children}
|
|
51
|
+
id={id}
|
|
52
|
+
key={children.key}
|
|
53
|
+
disabled={disabled}
|
|
54
|
+
size={size}
|
|
55
|
+
error={!!error}
|
|
56
|
+
success={!!success && !error}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
|
|
57
61
|
return (
|
|
58
62
|
<div {...props} className={classes(['dropin-field', className])}>
|
|
59
63
|
{label && (
|
|
@@ -65,13 +69,11 @@ export const Field: FunctionComponent<FieldProps> = ({
|
|
|
65
69
|
])}
|
|
66
70
|
htmlFor={id}
|
|
67
71
|
>
|
|
68
|
-
{label}
|
|
72
|
+
{wrapRequiredAsterisk(label, !!required)}
|
|
69
73
|
</label>
|
|
70
74
|
)}
|
|
71
75
|
|
|
72
|
-
<div className={classes(['dropin-field__content'])}>
|
|
73
|
-
{fieldContent}
|
|
74
|
-
</div>
|
|
76
|
+
<div className={classes(['dropin-field__content'])}>{fieldContent}</div>
|
|
75
77
|
|
|
76
78
|
<div
|
|
77
79
|
className={classes([
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Copyright 2024 Adobe
|
|
3
3
|
* All Rights Reserved.
|
|
4
4
|
*
|
|
5
|
-
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
-
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
-
* accompanying it.
|
|
5
|
+
* NOTICE: Adobe permits you to use, modify, and distribute this
|
|
6
|
+
* file in accordance with the terms of the Adobe license agreement
|
|
7
|
+
* accompanying it.
|
|
8
8
|
*******************************************************************/
|
|
9
9
|
|
|
10
10
|
/* https://cssguidelin.es/#bem-like-naming */
|