@adobe-commerce/elsie 1.4.1-alpha008 → 1.5.0-alpha1
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/bin/builders/gql/index.js +8 -4
- package/bin/builders/gql/validate.js +11 -10
- package/package.json +2 -2
- package/src/components/InputFile/InputFile.css +49 -0
- package/src/components/InputFile/InputFile.stories.tsx +90 -0
- package/src/components/InputFile/InputFile.tsx +59 -0
- package/src/components/InputFile/index.ts +11 -0
- package/src/components/ProductItemCard/ProductItemCardSkeleton.css +1 -14
- package/src/components/ProductItemCard/ProductItemCardSkeleton.tsx +5 -5
- package/src/components/index.ts +1 -0
|
@@ -77,20 +77,24 @@ module.exports = async function generateResourceBuilder(yargs) {
|
|
|
77
77
|
alias: 's',
|
|
78
78
|
describe: 'Path to the source code containing GraphQL operations',
|
|
79
79
|
type: 'array',
|
|
80
|
-
string: true,
|
|
81
80
|
demandOption: true,
|
|
82
81
|
})
|
|
82
|
+
.option('excluded', {
|
|
83
|
+
alias: 'x',
|
|
84
|
+
describe: 'Paths to exclude from validation',
|
|
85
|
+
type: 'array',
|
|
86
|
+
demandOption: false,
|
|
87
|
+
})
|
|
83
88
|
.option('endpoints', {
|
|
84
89
|
alias: 'e',
|
|
85
90
|
describe: 'Path to GraphQL endpoints',
|
|
86
91
|
type: 'array',
|
|
87
|
-
string: true,
|
|
88
92
|
demandOption: true,
|
|
89
93
|
});
|
|
90
94
|
},
|
|
91
95
|
async (argv) => {
|
|
92
|
-
const { source, endpoints } = argv;
|
|
93
|
-
await validate(source, endpoints);
|
|
96
|
+
const { source, excluded, endpoints } = argv;
|
|
97
|
+
await validate(source, endpoints, excluded);
|
|
94
98
|
},
|
|
95
99
|
)
|
|
96
100
|
.demandCommand(1, 1, 'choose a command: types, mocks or validate');
|
|
@@ -5,17 +5,20 @@ const parser = require('@babel/parser');
|
|
|
5
5
|
const traverse = require('@babel/traverse');
|
|
6
6
|
const { getIntrospectionQuery, buildClientSchema, parse, validate } = require('graphql');
|
|
7
7
|
|
|
8
|
-
async function walk(dir, collected = []) {
|
|
8
|
+
async function walk(dir, excludedPaths = [], collected = []) {
|
|
9
|
+
if (excludedPaths.includes(dir)) return collected;
|
|
10
|
+
|
|
9
11
|
const dirents = await fsPromises.readdir(dir, { withFileTypes: true });
|
|
10
12
|
|
|
11
13
|
for (const d of dirents) {
|
|
12
14
|
const full = path.resolve(dir, d.name);
|
|
13
15
|
|
|
14
16
|
if (d.isDirectory()) {
|
|
15
|
-
|
|
17
|
+
if (excludedPaths.includes(full)) continue;
|
|
16
18
|
if (d.name === 'node_modules' || d.name.startsWith('.')) continue;
|
|
17
|
-
await walk(full, collected);
|
|
19
|
+
await walk(full, excludedPaths, collected);
|
|
18
20
|
} else if (/\.(c?m?js|ts|tsx)$/.test(d.name)) {
|
|
21
|
+
if (excludedPaths.includes(full)) continue;
|
|
19
22
|
collected.push(full);
|
|
20
23
|
}
|
|
21
24
|
}
|
|
@@ -97,10 +100,10 @@ async function validateGqlOperations(endpoint, operation) {
|
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
|
|
100
|
-
async function getAllOperations(directories) {
|
|
103
|
+
async function getAllOperations(directories, excludedPaths = []) {
|
|
101
104
|
let fullContent = '';
|
|
102
105
|
for (const directory of directories) {
|
|
103
|
-
const files = await walk(path.resolve(directory));
|
|
106
|
+
const files = await walk(path.resolve(directory), excludedPaths.map(p => path.resolve(p)));
|
|
104
107
|
for (const f of files) {
|
|
105
108
|
const code = await fsPromises.readFile(f, 'utf8');
|
|
106
109
|
|
|
@@ -120,11 +123,9 @@ async function getAllOperations(directories) {
|
|
|
120
123
|
return fullContent;
|
|
121
124
|
}
|
|
122
125
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
module.exports = async function main(sources, endpoints) {
|
|
126
|
+
module.exports = async function main(sources, endpoints, excluded) {
|
|
126
127
|
for (const endpoint of endpoints) {
|
|
127
|
-
const operations = await getAllOperations(sources);
|
|
128
|
+
const operations = await getAllOperations(sources, excluded);
|
|
128
129
|
if (!operations) {
|
|
129
130
|
console.error('No GraphQL operations found in the specified directories.');
|
|
130
131
|
process.exitCode = 0;
|
|
@@ -132,4 +133,4 @@ module.exports = async function main(sources, endpoints) {
|
|
|
132
133
|
}
|
|
133
134
|
await validateGqlOperations(endpoint, operations);
|
|
134
135
|
}
|
|
135
|
-
}
|
|
136
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe-commerce/elsie",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0-alpha1",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
5
5
|
"description": "Domain Package SDK",
|
|
6
6
|
"engines": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"cleanup": "rimraf dist"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@adobe-commerce/event-bus": "1.0.1
|
|
29
|
+
"@adobe-commerce/event-bus": "~1.0.1",
|
|
30
30
|
"@adobe-commerce/fetch-graphql": "~1.1.0",
|
|
31
31
|
"@adobe-commerce/recaptcha": "~1.0.1",
|
|
32
32
|
"@adobe-commerce/storefront-design": "~1.0.0",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/********************************************************************
|
|
2
|
+
* Copyright 2025 Adobe
|
|
3
|
+
* All Rights Reserved.
|
|
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.
|
|
8
|
+
*******************************************************************/
|
|
9
|
+
|
|
10
|
+
/* https://cssguidelin.es/#bem-like-naming */
|
|
11
|
+
|
|
12
|
+
.dropin-input-file__input {
|
|
13
|
+
display: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.dropin-input-file__label {
|
|
17
|
+
border: 0 none;
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
border-radius: var(--shape-border-radius-3);
|
|
20
|
+
padding: var(--spacing-xsmall) var(--spacing-medium);
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
align-items: center;
|
|
24
|
+
background: var(--color-brand-500);
|
|
25
|
+
color: var(--color-neutral-50);
|
|
26
|
+
font: var(--type-button-2-font);
|
|
27
|
+
letter-spacing: var(--type-button-2-letter-spacing);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.dropin-input-file__label:hover {
|
|
31
|
+
background-color: var(--color-button-hover);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.dropin-input-file__icon {
|
|
35
|
+
height: 24px;
|
|
36
|
+
margin-right: var(--spacing-xsmall);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Medium (portrait tablets and large phones, 768px and up) */
|
|
40
|
+
/* @media only screen and (min-width: 768px) { } */
|
|
41
|
+
|
|
42
|
+
/* Large (landscape tablets, 1024px and up) */
|
|
43
|
+
/* @media only screen and (min-width: 1024px) { } */
|
|
44
|
+
|
|
45
|
+
/* XLarge (laptops/desktops, 1366px and up) */
|
|
46
|
+
/* @media only screen and (min-width: 1366px) { } */
|
|
47
|
+
|
|
48
|
+
/* XXlarge (large laptops and desktops, 1920px and up) */
|
|
49
|
+
/* @media only screen and (min-width: 1920px) { } */
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/********************************************************************
|
|
2
|
+
* Copyright 2025 Adobe
|
|
3
|
+
* All Rights Reserved.
|
|
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.
|
|
8
|
+
*******************************************************************/
|
|
9
|
+
|
|
10
|
+
// https://storybook.js.org/docs/7.0/preact/writing-stories/introduction
|
|
11
|
+
import type { Meta, StoryObj } from '@storybook/preact';
|
|
12
|
+
import { InputFile, InputFileProps } from '@adobe-commerce/elsie/components/InputFile';
|
|
13
|
+
import { action } from '@storybook/addon-actions';
|
|
14
|
+
import { IconsList } from '@adobe-commerce/elsie/components/Icon/Icon.stories.helpers';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Use InputFile to upload files.
|
|
18
|
+
*/
|
|
19
|
+
const meta: Meta<InputFileProps> = {
|
|
20
|
+
title: 'Components/InputFile',
|
|
21
|
+
component: InputFile,
|
|
22
|
+
argTypes: {
|
|
23
|
+
label: {
|
|
24
|
+
description: 'Label for the input file.',
|
|
25
|
+
type: 'string',
|
|
26
|
+
},
|
|
27
|
+
accept: {
|
|
28
|
+
description: 'Restrict selectable file types',
|
|
29
|
+
type: 'string',
|
|
30
|
+
},
|
|
31
|
+
multiple: {
|
|
32
|
+
description: 'Allow multiple files selection.',
|
|
33
|
+
type: {
|
|
34
|
+
name: 'boolean',
|
|
35
|
+
required: false
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
id: {
|
|
39
|
+
description: 'id',
|
|
40
|
+
type: {
|
|
41
|
+
required: false,
|
|
42
|
+
name: 'string'
|
|
43
|
+
},
|
|
44
|
+
control: 'text',
|
|
45
|
+
},
|
|
46
|
+
onChange: {
|
|
47
|
+
description: 'Handler for when the file selection changes.',
|
|
48
|
+
control: false,
|
|
49
|
+
table: {
|
|
50
|
+
type: {
|
|
51
|
+
summary: 'function'
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
icon: {
|
|
56
|
+
description: 'Optional icon.',
|
|
57
|
+
table: {
|
|
58
|
+
type: { summary: 'FunctionComponent' },
|
|
59
|
+
},
|
|
60
|
+
options: Object.keys(IconsList),
|
|
61
|
+
mapping: IconsList,
|
|
62
|
+
control: 'select',
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default meta;
|
|
68
|
+
|
|
69
|
+
type Story = StoryObj<InputFileProps>;
|
|
70
|
+
|
|
71
|
+
export const Default: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
label: 'Upload File',
|
|
74
|
+
id: 'single-file-input',
|
|
75
|
+
accept: ".pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .csv, .jpg, .jpeg, .png, .gif, .bmp, .tiff, .ico, .webp",
|
|
76
|
+
onChange: action('onChange'),
|
|
77
|
+
icon: 'none' as any,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const MultipleFiles: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
label: 'Upload Multiple Files',
|
|
84
|
+
id: 'multiple-files-input',
|
|
85
|
+
accept: ".pdf, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .txt, .csv, .jpg, .jpeg, .png, .gif, .bmp, .tiff, .ico, .webp",
|
|
86
|
+
multiple: true,
|
|
87
|
+
onChange: action('onChange'),
|
|
88
|
+
icon: 'none' as any,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/********************************************************************
|
|
2
|
+
* Copyright 2025 Adobe
|
|
3
|
+
* All Rights Reserved.
|
|
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.
|
|
8
|
+
*******************************************************************/
|
|
9
|
+
|
|
10
|
+
import { FunctionComponent, VNode } from 'preact';
|
|
11
|
+
import { useId } from 'preact/hooks';
|
|
12
|
+
import { HTMLAttributes } from 'preact/compat';
|
|
13
|
+
import { classes } from '@adobe-commerce/elsie/lib';
|
|
14
|
+
import '@adobe-commerce/elsie/components/InputFile/InputFile.css';
|
|
15
|
+
|
|
16
|
+
export interface InputFileProps extends Omit<HTMLAttributes<HTMLInputElement>, 'type' | 'icon'> {
|
|
17
|
+
accept?: string;
|
|
18
|
+
onChange?: (event: Event) => void;
|
|
19
|
+
label?: string;
|
|
20
|
+
multiple?: boolean;
|
|
21
|
+
icon?: VNode<HTMLAttributes<SVGSVGElement>>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const InputFile: FunctionComponent<InputFileProps> = ({
|
|
25
|
+
accept,
|
|
26
|
+
onChange,
|
|
27
|
+
label = 'Upload Document',
|
|
28
|
+
icon,
|
|
29
|
+
className,
|
|
30
|
+
multiple,
|
|
31
|
+
id: providedId,
|
|
32
|
+
...props
|
|
33
|
+
}) => {
|
|
34
|
+
|
|
35
|
+
const generatedId = useId();
|
|
36
|
+
const id = providedId || generatedId;
|
|
37
|
+
|
|
38
|
+
const handleChange = (e: Event) => {
|
|
39
|
+
onChange?.(e);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={classes(['dropin-input-file', className])}>
|
|
44
|
+
<label htmlFor={id} className="dropin-input-file__label">
|
|
45
|
+
{icon && <span className="dropin-input-file__icon">{icon}</span>}
|
|
46
|
+
{label}
|
|
47
|
+
</label>
|
|
48
|
+
<input
|
|
49
|
+
id={id}
|
|
50
|
+
type="file"
|
|
51
|
+
accept={accept}
|
|
52
|
+
multiple={multiple}
|
|
53
|
+
onChange={handleChange}
|
|
54
|
+
className="dropin-input-file__input"
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/********************************************************************
|
|
2
|
+
* Copyright 2025 Adobe
|
|
3
|
+
* All Rights Reserved.
|
|
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.
|
|
8
|
+
*******************************************************************/
|
|
9
|
+
|
|
10
|
+
export * from '@adobe-commerce/elsie/components/InputFile/InputFile';
|
|
11
|
+
export { InputFile as default } from '@adobe-commerce/elsie/components/InputFile/InputFile';
|
|
@@ -9,23 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
/* https://cssguidelin.es/#bem-like-naming */
|
|
11
11
|
|
|
12
|
-
.dropin-product-item-card__skeleton {
|
|
13
|
-
gap: var(--spacing-small);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
.dropin-product-item-card__skeleton__image {
|
|
17
|
-
height: 375px;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
.dropin-product-item-card__skeleton__content {
|
|
21
|
-
grid-column: 1/-1;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/* .dropin-product-item-card__skeleton__image {
|
|
25
13
|
width: 100%;
|
|
26
|
-
height:
|
|
14
|
+
height: 370px;
|
|
27
15
|
}
|
|
28
|
-
*/
|
|
29
16
|
|
|
30
17
|
/* Medium (portrait tablets and large phones, 768px and up) */
|
|
31
18
|
/* @media only screen and (min-width: 768px) { } */
|
|
@@ -19,10 +19,11 @@ export const ProductItemCardSkeleton: FunctionComponent = () => {
|
|
|
19
19
|
fullWidth={true}
|
|
20
20
|
className="dropin-product-item-card__skeleton__image"
|
|
21
21
|
/>
|
|
22
|
-
|
|
22
|
+
</Skeleton>
|
|
23
|
+
<Skeleton className="dropin-product-item-card__content dropin-product-item-card__skeleton__content">
|
|
23
24
|
<SkeletonRow
|
|
24
25
|
fullWidth={true}
|
|
25
|
-
size="
|
|
26
|
+
size="xsmall"
|
|
26
27
|
className="dropin-product-item-card__skeleton__item"
|
|
27
28
|
/>
|
|
28
29
|
<SkeletonRow
|
|
@@ -32,11 +33,10 @@ export const ProductItemCardSkeleton: FunctionComponent = () => {
|
|
|
32
33
|
/>
|
|
33
34
|
<SkeletonRow
|
|
34
35
|
fullWidth={true}
|
|
35
|
-
size="
|
|
36
|
+
size="xsmall"
|
|
36
37
|
className="dropin-product-item-card__skeleton__item"
|
|
37
38
|
/>
|
|
38
|
-
</
|
|
39
|
-
</Skeleton>
|
|
39
|
+
</Skeleton>
|
|
40
40
|
</div>
|
|
41
41
|
);
|
|
42
42
|
};
|
package/src/components/index.ts
CHANGED
|
@@ -48,3 +48,4 @@ export * from '@adobe-commerce/elsie/components/Tag';
|
|
|
48
48
|
export * from '@adobe-commerce/elsie/components/ContentGrid';
|
|
49
49
|
export * from '@adobe-commerce/elsie/components/Pagination';
|
|
50
50
|
export * from '@adobe-commerce/elsie/components/ProductItemCard';
|
|
51
|
+
export * from '@adobe-commerce/elsie/components/InputFile';
|