@hitachivantara/uikit-cli 6.0.1

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 (109) hide show
  1. package/README.md +46 -0
  2. package/package.json +68 -0
  3. package/src/app-shell.js +106 -0
  4. package/src/baselines/app-shell/vite/_gitignore +30 -0
  5. package/src/baselines/app-shell/vite/_oxlintrc.json +5 -0
  6. package/src/baselines/app-shell/vite/_package.json +55 -0
  7. package/src/baselines/app-shell/vite/public/locales/en/example.json +8 -0
  8. package/src/baselines/app-shell/vite/src/lib/data/config.ts +15 -0
  9. package/src/baselines/app-shell/vite/src/lib/i18n.ts +44 -0
  10. package/src/baselines/app-shell/vite/src/pages/Example/index.tsx +25 -0
  11. package/src/baselines/app-shell/vite/src/providers/Provider.tsx +31 -0
  12. package/src/baselines/app-shell/vite/src/tests/mocks.ts +1 -0
  13. package/src/baselines/app-shell/vite/src/tests/providers.tsx +13 -0
  14. package/src/baselines/app-shell/vite/src/tests/setupTests.ts +24 -0
  15. package/src/baselines/app-shell/vite/src/types/theme.d.ts +8 -0
  16. package/src/baselines/app-shell/vite/src/types/vite-env.d.ts +1 -0
  17. package/src/baselines/app-shell/vite/tsconfig.json +10 -0
  18. package/src/baselines/app-shell/vite/tsconfig.node.json +9 -0
  19. package/src/baselines/app-shell/vite/uno.config.ts +6 -0
  20. package/src/baselines/app-shell/vite/vite.config.ts +45 -0
  21. package/src/baselines/vite/_gitignore +30 -0
  22. package/src/baselines/vite/_oxlintrc.json +5 -0
  23. package/src/baselines/vite/_package.json +53 -0
  24. package/src/baselines/vite/index.html +18 -0
  25. package/src/baselines/vite/public/favicon.ico +0 -0
  26. package/src/baselines/vite/public/locales/en/common.json +16 -0
  27. package/src/baselines/vite/public/locales/en/home.json +4 -0
  28. package/src/baselines/vite/public/logo192.png +0 -0
  29. package/src/baselines/vite/src/App.tsx +31 -0
  30. package/src/baselines/vite/src/assets/HitachiLogo.tsx +27 -0
  31. package/src/baselines/vite/src/components/common/Loading/Loading.test.tsx +18 -0
  32. package/src/baselines/vite/src/components/common/Loading/Loading.tsx +15 -0
  33. package/src/baselines/vite/src/components/common/Loading/index.ts +1 -0
  34. package/src/baselines/vite/src/context/NavigationContext.tsx +67 -0
  35. package/src/baselines/vite/src/lib/i18n.ts +29 -0
  36. package/src/baselines/vite/src/main.tsx +12 -0
  37. package/src/baselines/vite/src/pages/Home/index.tsx +13 -0
  38. package/src/baselines/vite/src/pages/NotFound/NotFound.tsx +39 -0
  39. package/src/baselines/vite/src/pages/NotFound/index.tsx +1 -0
  40. package/src/baselines/vite/src/pages/layout/navigation.tsx +82 -0
  41. package/src/baselines/vite/src/routes.tsx +14 -0
  42. package/src/baselines/vite/src/tests/mocks.ts +1 -0
  43. package/src/baselines/vite/src/tests/providers.tsx +13 -0
  44. package/src/baselines/vite/src/tests/setupTests.ts +24 -0
  45. package/src/baselines/vite/src/types/theme.d.ts +8 -0
  46. package/src/baselines/vite/src/vite-env.d.ts +1 -0
  47. package/src/baselines/vite/tsconfig.json +10 -0
  48. package/src/baselines/vite/tsconfig.node.json +9 -0
  49. package/src/baselines/vite/uno.config.ts +6 -0
  50. package/src/baselines/vite/vite.config.ts +31 -0
  51. package/src/contents.js +63 -0
  52. package/src/create.js +172 -0
  53. package/src/index.js +22 -0
  54. package/src/navigation.js +21 -0
  55. package/src/package.js +37 -0
  56. package/src/plop-templates/README.md.hbs +10 -0
  57. package/src/plop-templates/app-shell/app-shell.config.ts.hbs +54 -0
  58. package/src/plop-templates/app-shell/index.html.hbs +15 -0
  59. package/src/plopfile.js +61 -0
  60. package/src/templates/AssetInventory/CardView.tsx +167 -0
  61. package/src/templates/AssetInventory/ListView.tsx +56 -0
  62. package/src/templates/AssetInventory/data.tsx +255 -0
  63. package/src/templates/AssetInventory/index.tsx +198 -0
  64. package/src/templates/AssetInventory/usePaginationData.ts +158 -0
  65. package/src/templates/Canvas/Context.tsx +49 -0
  66. package/src/templates/Canvas/ListView.tsx +189 -0
  67. package/src/templates/Canvas/Node.tsx +203 -0
  68. package/src/templates/Canvas/Sidebar.tsx +51 -0
  69. package/src/templates/Canvas/StatusEdge.tsx +75 -0
  70. package/src/templates/Canvas/StickyNode.tsx +475 -0
  71. package/src/templates/Canvas/Table.tsx +202 -0
  72. package/src/templates/Canvas/TreeView.tsx +211 -0
  73. package/src/templates/Canvas/dependencies.json +7 -0
  74. package/src/templates/Canvas/index.tsx +363 -0
  75. package/src/templates/Canvas/styles.tsx +41 -0
  76. package/src/templates/Canvas/utils.tsx +70 -0
  77. package/src/templates/Dashboard/GridPanel.tsx +33 -0
  78. package/src/templates/Dashboard/Kpi.tsx +107 -0
  79. package/src/templates/Dashboard/Map.styles.ts +681 -0
  80. package/src/templates/Dashboard/Map.tsx +71 -0
  81. package/src/templates/Dashboard/data.ts +67 -0
  82. package/src/templates/Dashboard/dependencies.json +11 -0
  83. package/src/templates/Dashboard/index.tsx +173 -0
  84. package/src/templates/DetailsView/KPIs.tsx +70 -0
  85. package/src/templates/DetailsView/MetadataItem.tsx +35 -0
  86. package/src/templates/DetailsView/Properties.tsx +127 -0
  87. package/src/templates/DetailsView/Table.tsx +104 -0
  88. package/src/templates/DetailsView/data.ts +67 -0
  89. package/src/templates/DetailsView/index.tsx +102 -0
  90. package/src/templates/DetailsView/usePaginationData.ts +155 -0
  91. package/src/templates/DetailsView/utils.ts +51 -0
  92. package/src/templates/Form/index.tsx +107 -0
  93. package/src/templates/KanbanBoard/ColumnContainer.tsx +89 -0
  94. package/src/templates/KanbanBoard/TaskCard.tsx +130 -0
  95. package/src/templates/KanbanBoard/data.tsx +140 -0
  96. package/src/templates/KanbanBoard/dependencies.json +6 -0
  97. package/src/templates/KanbanBoard/index.tsx +179 -0
  98. package/src/templates/KanbanBoard/styles.tsx +76 -0
  99. package/src/templates/KanbanBoard/types.ts +21 -0
  100. package/src/templates/ListView/Indicator.tsx +42 -0
  101. package/src/templates/ListView/Kpi.tsx +120 -0
  102. package/src/templates/ListView/Table.tsx +55 -0
  103. package/src/templates/ListView/data.tsx +179 -0
  104. package/src/templates/ListView/dependencies.json +5 -0
  105. package/src/templates/ListView/index.tsx +245 -0
  106. package/src/templates/ListView/usePaginationData.ts +158 -0
  107. package/src/templates/Welcome/index.tsx +101 -0
  108. package/src/templates/package.json +30 -0
  109. package/src/utils.js +37 -0
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" href="/favicon.ico" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <link rel="apple-touch-icon" href="/logo192.png" />
8
+ <title>UI Kit App</title>
9
+ <link
10
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600&family=Open+Sans:wght@400;600&display=swap"
11
+ rel="stylesheet"
12
+ />
13
+ </head>
14
+ <body>
15
+ <div id="hv-root"></div>
16
+ <script type="module" src="/src/main.tsx"></script>
17
+ </body>
18
+ </html>
@@ -0,0 +1,16 @@
1
+ {
2
+ "title": "Lumada App",
3
+
4
+ "loading": {
5
+ "label": "Loading Page",
6
+ "errorTitle": "Unable to load page",
7
+ "errorMessage": "If this problem persists, please contact administrator.",
8
+ "errorAction": "Here has link to reload page."
9
+ },
10
+
11
+ "notFound": {
12
+ "title": "404 Page not found",
13
+ "message": "The page you followed may be broken or item has been removed.",
14
+ "action": "Click here to go back."
15
+ }
16
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "title": "Homepage",
3
+ "description": "This is an example homepage"
4
+ }
@@ -0,0 +1,31 @@
1
+ import "./lib/i18n";
2
+ import "virtual:uno.css";
3
+
4
+ import {
5
+ createBrowserRouter,
6
+ RouteObject,
7
+ RouterProvider,
8
+ } from "react-router-dom";
9
+ import { HvProvider } from "@hitachivantara/uikit-react-core";
10
+
11
+ import { appRoutes } from "./routes";
12
+
13
+ export const routes: RouteObject[] = [
14
+ {
15
+ lazy: () => import("./pages/layout/navigation"),
16
+ children: appRoutes,
17
+ },
18
+ { path: "*", lazy: () => import("./pages/NotFound") },
19
+ ];
20
+
21
+ export const router = createBrowserRouter(routes, {
22
+ basename: import.meta.env.BASE_URL,
23
+ });
24
+
25
+ export default function App() {
26
+ return (
27
+ <HvProvider rootElementId="hv-root">
28
+ <RouterProvider router={router} />
29
+ </HvProvider>
30
+ );
31
+ }
@@ -0,0 +1,27 @@
1
+ export const HitachiLogo = ({ ...others }: React.SVGProps<SVGSVGElement>) => {
2
+ return (
3
+ <svg
4
+ role="img"
5
+ viewBox="0 0 80 16"
6
+ width={72}
7
+ fill="currentColor"
8
+ {...others}
9
+ >
10
+ <title>Logo</title>
11
+ <path d="M63.6,2.5c0,0,0,4.8,0,4.7H70c0,0,0-4.7,0-4.7s3.1,0,3.1,0c0,0,0,11.8,0,11.9H70c0,0,0-5.2,0-5.2c0,0-6.3,0-6.3,0c0,0,0,5.2,0,5.2h-3.1c0,0,0-11.9,0-11.9C60.5,2.5,63.6,2.5,63.6,2.5z" />
12
+ <path d="M33.9,2.5c0,0,0,2,0,2h-4.8v9.8h-3.1V4.5h-4.8v-2C21.1,2.5,33.9,2.5,33.9,2.5z" />
13
+ <path d="M46,14.3c0,0-3.5,0-3.5,0l-1-2.6h-5.9c0,0-1,2.6-1,2.6h-3.5l5.5-11.9h3.8L46,14.3z M38.6,4.5l-2.2,5.4h4.4L38.6,4.5" />
14
+ <rect x="75.6" y="2.5" width="3.1" height="11.9" />
15
+ <path d="M4.9,2.5c0,0,0,4.8,0,4.7h6.3c0,0,0-4.7,0-4.7s3.1,0,3.1,0c0,0,0,11.8,0,11.9h-3.1c0,0,0-5.2,0-5.2c0,0-6.3,0-6.3,0c0,0,0,5.2,0,5.2H1.7c0,0,0-11.9,0-11.9C1.7,2.5,4.9,2.5,4.9,2.5z" />
16
+ <rect x="16.9" y="2.5" width="3.1" height="11.9" />
17
+ <path
18
+ d="M45.9,11c-0.3-0.8-0.4-1.6-0.4-2.5c0-1.2,0.2-2.4,0.8-3.4c0.6-1,1.5-1.8,2.7-2.2
19
+ c1.1-0.4,2.2-0.6,3.5-0.6c1.4,0,2.7,0.3,4,0.8c1.1,0.5,2,1.5,2.2,2.7c0.1,0.3,0.1,0.5,0.1,0.8h-3.3c0-0.3-0.1-0.6-0.2-0.9
20
+ c-0.3-0.6-0.8-1.2-1.5-1.4c-0.4-0.1-0.9-0.2-1.4-0.2c-0.5,0-1.1,0.1-1.5,0.3c-0.8,0.3-1.4,0.9-1.7,1.7
21
+ c-0.3,0.8-0.4,1.6-0.4,2.5c0,0.7,0.1,1.4,0.3,2.1c0.2,0.9,0.9,1.6,1.7,1.9c0.5,0.2,1.1,0.3,1.7,0.3c0.5,0,1-0.1,1.5-0.2
22
+ c0.6-0.2,1.1-0.6,1.4-1.2c0.2-0.4,0.3-0.8,0.3-1.3h3.3c0,0.4-0.1,0.8-0.2,1.1c-0.3,1.2-1.1,2.2-2.2,2.6
23
+ c-1.2,0.5-2.6,0.8-4,0.8c-1.1,0-2.2-0.2-3.2-0.5C47.8,13.6,46.5,12.5,45.9,11z"
24
+ />
25
+ </svg>
26
+ );
27
+ };
@@ -0,0 +1,18 @@
1
+ import { render, screen } from "@testing-library/react";
2
+
3
+ import { Loading } from "./Loading";
4
+
5
+ describe("<Loading />", () => {
6
+ it("renders the label", () => {
7
+ const MOCK_LABEL = "MOCK_LABEL";
8
+ render(<Loading label={MOCK_LABEL} />);
9
+
10
+ expect(screen.getByText(MOCK_LABEL)).toBeInTheDocument();
11
+ });
12
+
13
+ it("renders the aria loading", () => {
14
+ render(<Loading />);
15
+
16
+ expect(screen.getByRole("progressbar")).toBeInTheDocument();
17
+ });
18
+ });
@@ -0,0 +1,15 @@
1
+ import { HvLoading } from "@hitachivantara/uikit-react-core";
2
+
3
+ export interface LoadingProps {
4
+ label?: string;
5
+ }
6
+
7
+ /** _Fullscreen_ `HvLoading` component to use with `Suspense` and other loading fallbacks */
8
+ export const Loading: React.FC<LoadingProps> = ({ label }) => (
9
+ <HvLoading
10
+ role="progressbar"
11
+ label={label}
12
+ aria-valuetext={label}
13
+ className="size-full z-overlay"
14
+ />
15
+ );
@@ -0,0 +1 @@
1
+ export * from "./Loading";
@@ -0,0 +1,67 @@
1
+ import { createContext, useContext, useMemo } from "react";
2
+ import { useLocation } from "react-router-dom";
3
+
4
+ export interface NavigationData {
5
+ id: string;
6
+ label: string;
7
+ path?: string;
8
+ data?: NavigationData[];
9
+ }
10
+
11
+ export interface NavigationProviderProps {
12
+ children: React.ReactNode;
13
+ navigation: NavigationData[];
14
+ }
15
+
16
+ export interface NavigationContextValue {
17
+ navigation: NavigationData[];
18
+ activePath: NavigationData | undefined;
19
+ }
20
+
21
+ export const NavigationContext = createContext<NavigationContextValue>({
22
+ navigation: [],
23
+ activePath: undefined,
24
+ });
25
+
26
+ const getActivePath = (pathname: string, navigation: NavigationData[]) => {
27
+ return navigation.reduce((acc, item) => {
28
+ if (item.path && pathname.includes(item.path)) return item;
29
+ if (item.data) {
30
+ const found = item.data.find((child) => child.path === pathname);
31
+ if (found) return found;
32
+ }
33
+
34
+ return acc;
35
+ }, navigation[0]);
36
+ };
37
+
38
+ export const NavigationProvider = ({
39
+ children,
40
+ navigation,
41
+ }: NavigationProviderProps) => {
42
+ const { pathname } = useLocation();
43
+
44
+ const value = useMemo(
45
+ () => ({
46
+ navigation,
47
+ activePath: getActivePath(pathname, navigation),
48
+ }),
49
+ [navigation, pathname],
50
+ );
51
+
52
+ return (
53
+ <NavigationContext.Provider value={value}>
54
+ {children}
55
+ </NavigationContext.Provider>
56
+ );
57
+ };
58
+
59
+ export function useNavigationContext() {
60
+ const context = useContext(NavigationContext);
61
+ if (!context) {
62
+ throw new Error(
63
+ "useNavigationContext must be used within a NavigationProvider",
64
+ );
65
+ }
66
+ return context;
67
+ }
@@ -0,0 +1,29 @@
1
+ import { initReactI18next } from "react-i18next";
2
+ import { createInstance, type i18n } from "i18next";
3
+ import LanguageDetector from "i18next-browser-languagedetector";
4
+ import Backend, { type HttpBackendOptions } from "i18next-http-backend";
5
+
6
+ export const i18nInstance: i18n = createInstance();
7
+
8
+ i18nInstance
9
+ // load translation using xhr -> see /public/locales
10
+ // learn more: https://github.com/i18next/i18next-xhr-backend
11
+ .use(Backend)
12
+ // detect user language
13
+ // learn more: https://github.com/i18next/i18next-browser-languageDetector
14
+ .use(LanguageDetector)
15
+ // pass the i18n instance to react-i18next.
16
+ .use(initReactI18next)
17
+ // init i18next
18
+ // for all options read: https://www.i18next.com/overview/configuration-options
19
+ .init<HttpBackendOptions>({
20
+ fallbackLng: "en",
21
+ supportedLngs: ["en"],
22
+ backend: {
23
+ loadPath: "/locales/{{lng}}/{{ns}}.json",
24
+ },
25
+ interpolation: {
26
+ escapeValue: false, // not needed for react as it escapes by default
27
+ },
28
+ load: "languageOnly",
29
+ });
@@ -0,0 +1,12 @@
1
+ import { Suspense } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+
4
+ import App from "./App";
5
+
6
+ const root = createRoot(document.getElementById("hv-root")!);
7
+
8
+ root.render(
9
+ <Suspense fallback>
10
+ <App />
11
+ </Suspense>,
12
+ );
@@ -0,0 +1,13 @@
1
+ import { useTranslation } from "react-i18next";
2
+ import { HvTypography } from "@hitachivantara/uikit-react-core";
3
+
4
+ export function Component() {
5
+ const { t } = useTranslation("home");
6
+
7
+ return (
8
+ <div className="grid gap-sm">
9
+ <HvTypography variant="title1">{t("title")}</HvTypography>
10
+ <HvTypography>{t("description")}</HvTypography>
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,39 @@
1
+ import { useTranslation } from "react-i18next";
2
+ import { useNavigate } from "react-router-dom";
3
+ import { css } from "@emotion/css";
4
+ import {
5
+ HvButton,
6
+ HvEmptyState,
7
+ theme,
8
+ } from "@hitachivantara/uikit-react-core";
9
+ import { Info } from "@hitachivantara/uikit-react-icons";
10
+
11
+ const classes = {
12
+ root: css({
13
+ height: `calc(100vh - ${theme.header.height})`,
14
+ }),
15
+ empty: css({
16
+ alignItems: "center",
17
+ }),
18
+ };
19
+
20
+ export const Component = () => {
21
+ const { t } = useTranslation("common");
22
+ const navigate = useNavigate();
23
+
24
+ return (
25
+ <div className={classes.root}>
26
+ <HvEmptyState
27
+ className={classes.empty}
28
+ title={t("notFound.title")}
29
+ message={t("notFound.message")}
30
+ icon={<Info />}
31
+ action={
32
+ <HvButton variant="primaryGhost" onClick={() => navigate(-1)}>
33
+ {t("notFound.action")}
34
+ </HvButton>
35
+ }
36
+ />
37
+ </div>
38
+ );
39
+ };
@@ -0,0 +1 @@
1
+ export * from "./NotFound";
@@ -0,0 +1,82 @@
1
+ import { Suspense } from "react";
2
+ import { Outlet, useNavigate } from "react-router-dom";
3
+ import { useTheme } from "@mui/material/styles";
4
+ import useMediaQuery from "@mui/material/useMediaQuery";
5
+ import {
6
+ HvButton,
7
+ HvContainer,
8
+ HvContainerProps,
9
+ HvHeader,
10
+ HvHeaderBrand,
11
+ HvHeaderNavigation,
12
+ theme,
13
+ } from "@hitachivantara/uikit-react-core";
14
+ import { Menu } from "@hitachivantara/uikit-react-icons";
15
+
16
+ import { HitachiLogo } from "../../assets/HitachiLogo";
17
+ import { Loading } from "../../components/common/Loading";
18
+ import {
19
+ NavigationProvider,
20
+ useNavigationContext,
21
+ } from "../../context/NavigationContext";
22
+ import { navigationData } from "../../routes";
23
+
24
+ export function Component() {
25
+ return (
26
+ <NavigationProvider navigation={navigationData}>
27
+ <Header />
28
+ <Container maxWidth="xl">
29
+ <Outlet />
30
+ </Container>
31
+ </NavigationProvider>
32
+ );
33
+ }
34
+
35
+ function Header() {
36
+ const navigate = useNavigate();
37
+ const theme = useTheme();
38
+ const { activePath, navigation } = useNavigationContext();
39
+
40
+ const isMdUp = useMediaQuery(theme.breakpoints.up("md"));
41
+ const isXs = useMediaQuery(theme.breakpoints.only("xs"));
42
+
43
+ return (
44
+ <HvHeader>
45
+ {!isMdUp && (
46
+ <div>
47
+ <HvButton variant="primaryGhost" icon>
48
+ <Menu />
49
+ </HvButton>
50
+ </div>
51
+ )}
52
+
53
+ <HvHeaderBrand
54
+ logo={<HitachiLogo />}
55
+ name={!isXs ? "Lumada App" : undefined}
56
+ />
57
+
58
+ {isMdUp && (
59
+ <HvHeaderNavigation
60
+ data={navigation}
61
+ selected={activePath?.id}
62
+ onClick={(event, selection) => {
63
+ if (selection.path) navigate(selection.path);
64
+ }}
65
+ />
66
+ )}
67
+ </HvHeader>
68
+ );
69
+ }
70
+
71
+ function Container({ maxWidth = "lg", children }: HvContainerProps) {
72
+ return (
73
+ <div
74
+ className="flex pb-lg min-h-screen"
75
+ style={{ paddingTop: `calc(${theme.header.height} + ${theme.space.lg})` }}
76
+ >
77
+ <HvContainer maxWidth={maxWidth} component="main">
78
+ <Suspense fallback={<Loading />}>{children}</Suspense>
79
+ </HvContainer>
80
+ </div>
81
+ );
82
+ }
@@ -0,0 +1,14 @@
1
+ import type { RouteObject } from "react-router-dom";
2
+ import type { NavigationData } from "@hitachivantara/uikit-react-core";
3
+
4
+ export const appRoutes: RouteObject[] = [
5
+ { index: true, path: "/", lazy: () => import("./pages/Home") },
6
+ // APP ROUTES
7
+ ];
8
+
9
+ // Automatic `navigationData`. Change to manual & i18n labels if needed.
10
+ export const navigationData = appRoutes.map<NavigationData>((route) => ({
11
+ id: route.path ?? "",
12
+ label: (route.path ?? "").split("-").join(" "),
13
+ path: route.path,
14
+ }));
@@ -0,0 +1 @@
1
+ export const SUSPENSE_LABEL = "LOADING";
@@ -0,0 +1,13 @@
1
+ import { Suspense } from "react";
2
+ import { HvProvider } from "@hitachivantara/uikit-react-core";
3
+
4
+ import { SUSPENSE_LABEL } from "./mocks";
5
+
6
+ /** Base Test Provider */
7
+ export const TestProvider = ({ children }: { children: React.ReactNode }) => {
8
+ return (
9
+ <Suspense fallback={SUSPENSE_LABEL}>
10
+ <HvProvider>{children}</HvProvider>
11
+ </Suspense>
12
+ );
13
+ };
@@ -0,0 +1,24 @@
1
+ import type { TransProps } from "react-i18next";
2
+ import type { ThirdPartyModule, TOptionsBase } from "i18next";
3
+ import { vi } from "vitest";
4
+
5
+ import "@testing-library/jest-dom";
6
+
7
+ vi.mock("react-i18next", async () => {
8
+ const { initReactI18next } = await vi.importActual<{
9
+ initReactI18next: ThirdPartyModule;
10
+ }>("react-i18next");
11
+
12
+ const t = (str: string, options?: TOptionsBase) =>
13
+ options?.returnObjects ? undefined : str;
14
+
15
+ return {
16
+ initReactI18next,
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ Trans: ({ i18nKey }: TransProps<any>) => i18nKey,
19
+ useTranslation: () => ({
20
+ t,
21
+ i18n: { changeLanguage: async () => t },
22
+ }),
23
+ };
24
+ });
@@ -0,0 +1,8 @@
1
+ import type { Theme } from "@mui/material/styles";
2
+
3
+ // makeStyles is now exported from @mui/styles package which does not know about Theme
4
+ // we need to augment the DefaultTheme (empty object) in @mui/styles with Theme from the core.
5
+ declare module "@mui/private-theming" {
6
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
7
+ interface DefaultTheme extends Theme {}
8
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "@hitachivantara/uikit-config/tsconfig",
3
+ "compilerOptions": {},
4
+ "include": ["src"],
5
+ "references": [
6
+ {
7
+ "path": "./tsconfig.node.json"
8
+ }
9
+ ]
10
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowSyntheticDefaultImports": true
7
+ },
8
+ "include": ["vite.config.ts"]
9
+ }
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from "unocss";
2
+ import { presetHv } from "@hitachivantara/uikit-uno-preset";
3
+
4
+ export default defineConfig({
5
+ presets: [presetHv()],
6
+ });
@@ -0,0 +1,31 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="vitest" />
3
+
4
+ import react from "@vitejs/plugin-react";
5
+ import unoCSS from "unocss/vite";
6
+ import { defineConfig } from "vite";
7
+ import tsconfigPaths from "vite-tsconfig-paths";
8
+
9
+ export default defineConfig({
10
+ plugins: [react(), tsconfigPaths(), unoCSS()],
11
+ test: {
12
+ globals: true,
13
+ environment: "happy-dom",
14
+ setupFiles: ["src/tests/setupTests.ts"],
15
+ reporters: "default",
16
+ coverage: {
17
+ enabled: false, // disabled by default. run vitest with --coverage
18
+ provider: "v8",
19
+ reporter: "lcov",
20
+ include: ["src/**/*.ts?(x)"],
21
+ exclude: [
22
+ "src/**/mocks/*",
23
+ "src/**/tests/*",
24
+ "src/**/*.test.ts?(x)",
25
+ "src/**/styles.[jt]s?(x)",
26
+ "src/**/*.d.ts",
27
+ "src/*.tsx",
28
+ ],
29
+ },
30
+ },
31
+ });
@@ -0,0 +1,63 @@
1
+ import chalk from "chalk";
2
+ import fs from "fs-extra";
3
+ import nodePlop from "node-plop";
4
+
5
+ import { __dirname, mergeDependenciesObject } from "./utils.js";
6
+
7
+ const plop = await nodePlop(`${__dirname}/plopfile.js`);
8
+
9
+ const createReadMe = plop.getGenerator("createReadMe");
10
+
11
+ const getTemplateDependencies = (templatePath) => {
12
+ // read and remove template dependencies.json file if exists
13
+ const dependenciesPath = `${templatePath}/dependencies.json`;
14
+ const dependenciesExist = fs.existsSync(dependenciesPath);
15
+ const dependencies = dependenciesExist
16
+ ? fs.readJsonSync(dependenciesPath)
17
+ : {};
18
+
19
+ fs.removeSync(dependenciesPath);
20
+
21
+ return dependencies;
22
+ };
23
+
24
+ const copyTemplateContents = (appPath, templates) => {
25
+ const destPath = `${appPath}/src`;
26
+
27
+ // object for collecting extra dependencies coming from selected templates or other options
28
+ const dependencies = {
29
+ dependencies: {},
30
+ devDependencies: {},
31
+ };
32
+
33
+ for (const template of templates) {
34
+ console.log(`Creating template: ${chalk.cyan(template)}`);
35
+
36
+ const templateSrc = `${__dirname}/templates/${template}`;
37
+ const templateDest = `${destPath}/pages/${template}`;
38
+
39
+ fs.copySync(templateSrc, templateDest, { overwrite: true });
40
+
41
+ mergeDependenciesObject(
42
+ getTemplateDependencies(templateDest),
43
+ dependencies,
44
+ );
45
+ }
46
+
47
+ return dependencies;
48
+ };
49
+
50
+ const createReadMeFile = async (path, name) => {
51
+ await createReadMe.runActions({
52
+ path,
53
+ appName: name.replace(/([a-z])([A-Z])/g, "$1 $2"),
54
+ });
55
+ };
56
+
57
+ export const createAppContents = async (appPath, name, templates) => {
58
+ console.log(`Creating ${chalk.cyan(name)} contents\n`);
59
+
60
+ await createReadMeFile(appPath, name);
61
+
62
+ return templates?.length ? copyTemplateContents(appPath, templates) : {};
63
+ };