Skip to content

Commit c26bc36

Browse files
Merge pull request #1323 from Py4Js/development
Merge development to main (0.0.4 release)
2 parents 6925f40 + 7802bf4 commit c26bc36

28 files changed

+554
-329
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pyscript-react",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"main": "index.js",
55
"repository": "https://github.com/Py4Js/pyscript-react",
66
"author": "KrzysztofZawisla <zawislakrzysztof.zk@gmail.com>, BorysMalinowski <borysmalinowski0@gmail.com>",

source/library/components/py-box/py-box.tsx

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import propTypes from "prop-types";
2+
import { forwardRef, type ForwardedRef } from "react";
23
import type { PyBoxProperties, PyBoxTag } from "./py-box.types";
34

45
/**
@@ -7,12 +8,21 @@ import type { PyBoxProperties, PyBoxTag } from "./py-box.types";
78
* @param root0.children
89
* @deprecated
910
*/
10-
const PyBox: PyBoxTag = <T extends object>({
11-
children,
12-
...rest
13-
}: PyBoxProperties<T>): JSX.Element => {
14-
return <py-box {...rest}>{children}</py-box>;
15-
};
11+
const PyBox: PyBoxTag = forwardRef(
12+
<OptionalProperties extends object>(
13+
{ children, ...rest }: PyBoxProperties<OptionalProperties>,
14+
reference: ForwardedRef<HTMLElement> | undefined,
15+
// eslint-disable-next-line max-params
16+
): JSX.Element => {
17+
return (
18+
<py-box ref={reference} {...rest}>
19+
{children}
20+
</py-box>
21+
);
22+
},
23+
) as PyBoxTag;
24+
25+
PyBox.displayName = "PyBox";
1626

1727
PyBox.propTypes = {
1828
children: propTypes.oneOfType([

source/library/components/py-box/py-box.types.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type {
22
DetailedHTMLProps,
3+
ForwardedRef,
34
HTMLAttributes,
45
PropsWithChildren,
56
WeakValidationMap,
@@ -14,11 +15,17 @@ export type PyBoxPropertiesBase = PropsWithChildren<
1415
}
1516
>;
1617

17-
export type PyBoxProperties<T> = T extends infer T
18-
? T & PyBoxPropertiesBase
19-
: PyBoxPropertiesBase;
18+
export type PyBoxProperties<OptionalProperties> =
19+
OptionalProperties extends infer OptionalProperties
20+
? OptionalProperties & PyBoxPropertiesBase
21+
: PyBoxPropertiesBase;
2022

2123
export type PyBoxTag = {
22-
<T extends object>(properties: PyBoxProperties<T>): JSX.Element;
23-
propTypes: WeakValidationMap<PyBoxPropertiesBase>;
24+
<OptionalProperties extends object>(
25+
properties: PyBoxProperties<OptionalProperties>,
26+
reference?: ForwardedRef<HTMLElement>,
27+
): JSX.Element;
28+
displayName?: string;
29+
defaultProps?: Partial<PyBoxPropertiesBase>;
30+
propTypes?: WeakValidationMap<PyBoxPropertiesBase>;
2431
};

source/library/components/py-button/py-button.tsx

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import propTypes from "prop-types";
2+
import { forwardRef, type ForwardedRef } from "react";
23
import type { PyButtonProperties, PyButtonTag } from "./py-button.types";
34

45
/**
@@ -7,17 +8,21 @@ import type { PyButtonProperties, PyButtonTag } from "./py-button.types";
78
* @param root0.label
89
* @deprecated
910
*/
10-
const PyButton: PyButtonTag = <T extends object>({
11-
children,
12-
label,
13-
...rest
14-
}: PyButtonProperties<T>): JSX.Element => {
15-
return (
16-
<py-button {...rest} label={label}>
17-
{children}
18-
</py-button>
19-
);
20-
};
11+
const PyButton: PyButtonTag = forwardRef(
12+
<OptionalProperties extends object>(
13+
{ children, label, ...rest }: PyButtonProperties<OptionalProperties>,
14+
reference: ForwardedRef<HTMLElement> | undefined,
15+
// eslint-disable-next-line max-params
16+
): JSX.Element => {
17+
return (
18+
<py-button ref={reference} {...rest} label={label}>
19+
{children}
20+
</py-button>
21+
);
22+
},
23+
) as PyButtonTag;
24+
25+
PyButton.displayName = "PyButton";
2126

2227
PyButton.propTypes = {
2328
children: propTypes.string.isRequired,
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type {
22
DetailedHTMLProps,
3+
ForwardedRef,
34
HTMLAttributes,
45
WeakValidationMap,
56
} from "react";
6-
import ReactElementProps from "~types/react-element-properties/react-element-properties";
7+
import type ReactElementProps from "~types/react-element-properties/react-element-properties";
78

89
export type PyButtonPropertiesBase = Omit<
910
ReactElementProps<
@@ -15,11 +16,17 @@ export type PyButtonPropertiesBase = Omit<
1516
label: string;
1617
};
1718

18-
export type PyButtonProperties<T> = T extends infer T
19-
? T & PyButtonPropertiesBase
20-
: PyButtonPropertiesBase;
19+
export type PyButtonProperties<OptionalProperties> =
20+
OptionalProperties extends infer OptionalProperties
21+
? OptionalProperties & PyButtonPropertiesBase
22+
: PyButtonPropertiesBase;
2123

2224
export type PyButtonTag = {
23-
<T extends object>(properties: PyButtonProperties<T>): JSX.Element;
24-
propTypes: WeakValidationMap<PyButtonPropertiesBase>;
25+
<OptionalProperties extends object>(
26+
properties: PyButtonProperties<OptionalProperties>,
27+
reference?: ForwardedRef<HTMLElement>,
28+
): JSX.Element;
29+
displayName?: string;
30+
defaultProps?: Partial<PyButtonPropertiesBase>;
31+
propTypes?: WeakValidationMap<PyButtonPropertiesBase>;
2532
};

source/library/components/py-config/py-config.story.tsx

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import type { Meta, StoryFn } from "@storybook/react";
2-
32
import PyScriptProvider from "~root/source/library/components/py-script-provider/py-script-provider";
4-
53
import PyConfig from "./py-config";
6-
74
import type { PyConfigProperties, PyConfigTag } from "./py-config.types";
85

96
export default {
107
component: PyConfig,
118
} as Meta<typeof PyConfig>;
129

10+
const pythonTestFile: string = "./test_file.py";
11+
1312
const Template: StoryFn<PyConfigTag> = <T extends object>({
1413
...rest
1514
}: PyConfigProperties<T>): JSX.Element => {
@@ -26,25 +25,27 @@ PyConfigExample.args = {
2625
type: "json",
2726
packages: new Set(["matplotlib", "numpy", "folium"]),
2827
plugins: new Set(["https://pyscript.net/latest/plugins/python/py_tutor.py"]),
29-
fetch: {
30-
files: new Set(["./test_file.py"]),
31-
},
28+
fetch: [
29+
{
30+
files: new Set([pythonTestFile]),
31+
},
32+
],
3233
};
3334

3435
export const PyConfigExternalJsonConfigExample: StoryFn<typeof PyConfig> =
3536
Template.bind({});
3637

3738
PyConfigExternalJsonConfigExample.args = {
3839
type: "json",
39-
source: "./test_file.py",
40+
source: pythonTestFile,
4041
};
4142

4243
export const PyConfigExternalTomlConfigExample: StoryFn<typeof PyConfig> =
4344
Template.bind({});
4445

4546
PyConfigExternalTomlConfigExample.args = {
4647
type: "toml",
47-
source: "./test_file.py",
48+
source: pythonTestFile,
4849
};
4950

5051
export const PyConfigTomlConfigExample: StoryFn<typeof PyConfig> =

source/library/components/py-config/py-config.tsx

+91-73
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import propTypes from "prop-types";
2-
import { WeakValidationMap, useEffect, useMemo } from "react";
2+
import {
3+
forwardRef,
4+
useEffect,
5+
useMemo,
6+
type ForwardedRef,
7+
type WeakValidationMap,
8+
} from "react";
39
import type {
410
PyConfigFetch,
511
PyConfigFetchItem,
@@ -37,79 +43,91 @@ const checkForAnyKey = (
3743
* @see {@link https://docs.pyscript.net/latest/reference/elements/py-config.html} Original py-config element documentation.
3844
* @see {@link https://pyscript-react.github.io/} Pyscript-react element documentation.
3945
*/
40-
const PyConfig: PyConfigTag = <T extends object>({
41-
children,
42-
source,
43-
type,
44-
splashscreen,
45-
interpreters,
46-
fetch,
47-
packages,
48-
plugins,
49-
...rest
50-
}: PyConfigProperties<T>): JSX.Element => {
51-
// eslint-disable-next-line sonarjs/cognitive-complexity
52-
const config: string = useMemo((): string => {
53-
if (type === "json") {
54-
const transformedPlugins: string[] = [
55-
...(plugins || []),
56-
...(children?.plugins || []),
57-
];
58-
const transformedPackages: string[] = [
59-
...(packages || []),
60-
...(children?.packages || []),
61-
];
62-
const transformedFetch: PyConfigFetch = [
63-
...(fetch || []),
64-
...(children?.fetch || []),
65-
].map(({ files, ...restItem }: PyConfigFetchItem): PyConfigFetchItem => {
66-
const transformedFiles: string[] = [...(files || [])];
67-
return {
68-
files: transformedFiles.length ? transformedFiles : undefined,
69-
...restItem,
46+
const PyConfig: PyConfigTag = forwardRef(
47+
<OptionalProperties extends object>(
48+
{
49+
children,
50+
source,
51+
type,
52+
splashscreen,
53+
interpreters,
54+
fetch,
55+
packages,
56+
plugins,
57+
...rest
58+
}: PyConfigProperties<OptionalProperties>,
59+
reference: ForwardedRef<HTMLElement> | undefined,
60+
// eslint-disable-next-line max-params, sonarjs/cognitive-complexity
61+
): JSX.Element => {
62+
const config: string = useMemo((): string => {
63+
if (type === "json") {
64+
const transformedPlugins: string[] = [
65+
...(plugins ?? []),
66+
...(children?.plugins ?? []),
67+
];
68+
const transformedPackages: string[] = [
69+
...(packages ?? []),
70+
...(children?.packages ?? []),
71+
];
72+
const transformedFetch: PyConfigFetch = [
73+
...(fetch ?? []),
74+
...(children?.fetch ?? []),
75+
].map(
76+
({ files, ...restItem }: PyConfigFetchItem): PyConfigFetchItem => {
77+
const transformedFiles: string[] = [...(files ?? [])];
78+
return {
79+
files: transformedFiles.length ? transformedFiles : undefined,
80+
...restItem,
81+
};
82+
},
83+
);
84+
const transformedInterpreters: Omit<PyConfigInterpreters, "source"> & {
85+
src?: string;
86+
} = {
87+
src: interpreters?.source,
88+
name: interpreters?.name,
89+
language: interpreters?.language,
90+
...children?.interpreters,
7091
};
71-
});
72-
const transformedInterpreters: Omit<PyConfigInterpreters, "source"> & {
73-
src?: string;
74-
} = {
75-
src: interpreters?.source,
76-
name: interpreters?.name,
77-
language: interpreters?.language,
78-
...children?.interpreters,
79-
};
80-
const transformedSplashscreen: PyConfigSplashscreen = {
81-
autoclose: splashscreen?.autoclose,
82-
...children?.splashscreen,
83-
};
84-
const config: string = JSON.stringify({
85-
splashscreen: checkForAnyKey(transformedSplashscreen)
86-
? transformedSplashscreen
87-
: undefined,
88-
interpreters: checkForAnyKey(transformedInterpreters)
89-
? transformedInterpreters
90-
: undefined,
91-
fetch: transformedFetch.length ? transformedFetch : undefined,
92-
packages: transformedPackages.length ? transformedPackages : undefined,
93-
plugins: transformedPlugins.length ? transformedPlugins : undefined,
94-
...children,
95-
});
96-
return config;
97-
}
98-
return `${children || ""}`;
99-
}, [children, splashscreen, interpreters, fetch, packages, plugins]);
100-
useEffect((): void => {
101-
source &&
102-
children &&
103-
console.warn(
104-
"Children is passed with source. It may create undefined behavior. Remove one of these properties.",
105-
);
106-
}, [source, children]);
107-
return (
108-
<py-config {...rest} type={type} src={source}>
109-
{!source ? config : undefined}
110-
</py-config>
111-
);
112-
};
92+
const transformedSplashscreen: PyConfigSplashscreen = {
93+
autoclose: splashscreen?.autoclose,
94+
...children?.splashscreen,
95+
};
96+
const config: string = JSON.stringify({
97+
splashscreen: checkForAnyKey(transformedSplashscreen)
98+
? transformedSplashscreen
99+
: undefined,
100+
interpreters: checkForAnyKey(transformedInterpreters)
101+
? transformedInterpreters
102+
: undefined,
103+
fetch: transformedFetch.length ? transformedFetch : undefined,
104+
packages: transformedPackages.length
105+
? transformedPackages
106+
: undefined,
107+
plugins: transformedPlugins.length ? transformedPlugins : undefined,
108+
...children,
109+
});
110+
return config;
111+
}
112+
return `${children ?? ""}`;
113+
}, [children, splashscreen, interpreters, fetch, packages, plugins]);
114+
useEffect((): void => {
115+
source &&
116+
children &&
117+
// eslint-disable-next-line no-console
118+
console.warn(
119+
"Children is passed with source. It may create undefined behavior. Remove one of these properties.",
120+
);
121+
}, [source, children]);
122+
return (
123+
<py-config ref={reference} {...rest} type={type} src={source}>
124+
{!source ? config : undefined}
125+
</py-config>
126+
);
127+
},
128+
) as PyConfigTag;
129+
130+
PyConfig.displayName = "PyConfig";
113131

114132
PyConfig.propTypes = {
115133
children: propTypes.oneOfType([

0 commit comments

Comments
 (0)