codeforlife 2.6.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 (147) hide show
  1. package/.eslintrc.json +47 -0
  2. package/.github/workflows/contributing.yaml +8 -0
  3. package/.github/workflows/main.yml +36 -0
  4. package/.prettierignore +5 -0
  5. package/.prettierrc.json +4 -0
  6. package/.vscode/launch.json +22 -0
  7. package/.vscode/settings.json +30 -0
  8. package/CHANGELOG.md +1864 -0
  9. package/CONTRIBUTING.md +3 -0
  10. package/LICENSE.md +3 -0
  11. package/README.md +94 -0
  12. package/codecov.yml +11 -0
  13. package/package.json +139 -0
  14. package/src/api/createApi.ts +84 -0
  15. package/src/api/endpoints/authFactor.ts +31 -0
  16. package/src/api/endpoints/index.ts +9 -0
  17. package/src/api/endpoints/klass.ts +87 -0
  18. package/src/api/endpoints/school.ts +34 -0
  19. package/src/api/endpoints/session.ts +40 -0
  20. package/src/api/endpoints/user.ts +70 -0
  21. package/src/api/index.ts +4 -0
  22. package/src/api/models.ts +144 -0
  23. package/src/api/tagTypes.ts +12 -0
  24. package/src/api/urls.ts +13 -0
  25. package/src/components/App.css +38 -0
  26. package/src/components/App.tsx +150 -0
  27. package/src/components/ClickableTooltip.tsx +43 -0
  28. package/src/components/CopyIconButton.test.tsx +16 -0
  29. package/src/components/CopyIconButton.tsx +27 -0
  30. package/src/components/Countdown.tsx +42 -0
  31. package/src/components/ElevatedAppBar.tsx +41 -0
  32. package/src/components/Image.tsx +41 -0
  33. package/src/components/InputFileButton.tsx +27 -0
  34. package/src/components/ItemizedList.tsx +61 -0
  35. package/src/components/OrderedGrid.tsx +92 -0
  36. package/src/components/ScrollIntoViewLink.tsx +23 -0
  37. package/src/components/SyncError.tsx +14 -0
  38. package/src/components/TablePagination.tsx +132 -0
  39. package/src/components/YouTubeVideo.tsx +26 -0
  40. package/src/components/form/ApiAutocompleteField.tsx +180 -0
  41. package/src/components/form/AutocompleteField.tsx +124 -0
  42. package/src/components/form/CheckboxField.tsx +81 -0
  43. package/src/components/form/CountryField.tsx +68 -0
  44. package/src/components/form/DatePickerField.tsx +119 -0
  45. package/src/components/form/EmailField.tsx +38 -0
  46. package/src/components/form/FirstNameField.tsx +40 -0
  47. package/src/components/form/Form.tsx +82 -0
  48. package/src/components/form/OtpField.tsx +28 -0
  49. package/src/components/form/PasswordField.tsx +71 -0
  50. package/src/components/form/RepeatField.tsx +115 -0
  51. package/src/components/form/SubmitButton.tsx +47 -0
  52. package/src/components/form/TextField.tsx +103 -0
  53. package/src/components/form/UkCountyField.tsx +67 -0
  54. package/src/components/form/index.tsx +28 -0
  55. package/src/components/index.ts +26 -0
  56. package/src/components/page/Banner.tsx +84 -0
  57. package/src/components/page/Notification.tsx +71 -0
  58. package/src/components/page/Page.tsx +73 -0
  59. package/src/components/page/Section.tsx +21 -0
  60. package/src/components/page/TabBar.tsx +131 -0
  61. package/src/components/page/index.ts +10 -0
  62. package/src/components/router/Link.tsx +22 -0
  63. package/src/components/router/LinkButton.tsx +21 -0
  64. package/src/components/router/LinkIconButton.tsx +21 -0
  65. package/src/components/router/LinkListItem.tsx +21 -0
  66. package/src/components/router/LinkTab.tsx +21 -0
  67. package/src/components/router/Navigate.tsx +33 -0
  68. package/src/components/router/index.tsx +12 -0
  69. package/src/components/table/CellStack.tsx +19 -0
  70. package/src/components/table/Table.tsx +55 -0
  71. package/src/components/table/index.tsx +10 -0
  72. package/src/features/InactiveDialog.tsx +40 -0
  73. package/src/features/ScreenTimeDialog.tsx +33 -0
  74. package/src/features/index.ts +4 -0
  75. package/src/fonts/Inter-VariableFont_slnt,wght.ttf +0 -0
  76. package/src/fonts/SpaceGrotesk-VariableFont_wght.ttf +0 -0
  77. package/src/hooks/api.tsx +37 -0
  78. package/src/hooks/auth.tsx +87 -0
  79. package/src/hooks/general.ts +110 -0
  80. package/src/hooks/index.ts +4 -0
  81. package/src/hooks/router.tsx +168 -0
  82. package/src/index.ts +2 -0
  83. package/src/middlewares/index.ts +1 -0
  84. package/src/middlewares/session.ts +16 -0
  85. package/src/public/images/brain.svg +1 -0
  86. package/src/schemas/user.ts +4 -0
  87. package/src/scripts/freshDesk.js +473 -0
  88. package/src/scripts/index.ts +1 -0
  89. package/src/server.js +181 -0
  90. package/src/settings/custom.ts +22 -0
  91. package/src/settings/index.ts +5 -0
  92. package/src/settings/vite.ts +26 -0
  93. package/src/setupTests.ts +1 -0
  94. package/src/slices/createSlice.ts +8 -0
  95. package/src/slices/index.ts +2 -0
  96. package/src/slices/session.ts +32 -0
  97. package/src/theme/ThemedBox.tsx +265 -0
  98. package/src/theme/colors.ts +57 -0
  99. package/src/theme/components/MuiAccordion.tsx +13 -0
  100. package/src/theme/components/MuiAutocomplete.tsx +11 -0
  101. package/src/theme/components/MuiButton.ts +70 -0
  102. package/src/theme/components/MuiCardActions.tsx +12 -0
  103. package/src/theme/components/MuiCheckbox.ts +12 -0
  104. package/src/theme/components/MuiContainer.ts +19 -0
  105. package/src/theme/components/MuiDialog.tsx +16 -0
  106. package/src/theme/components/MuiFormControlLabel.ts +18 -0
  107. package/src/theme/components/MuiFormHelperText.ts +12 -0
  108. package/src/theme/components/MuiGrid2.ts +16 -0
  109. package/src/theme/components/MuiInputBase.ts +14 -0
  110. package/src/theme/components/MuiLink.ts +41 -0
  111. package/src/theme/components/MuiList.ts +12 -0
  112. package/src/theme/components/MuiListItemText.ts +18 -0
  113. package/src/theme/components/MuiMenu.ts +14 -0
  114. package/src/theme/components/MuiMenuItem.ts +15 -0
  115. package/src/theme/components/MuiSelect.ts +16 -0
  116. package/src/theme/components/MuiTab.ts +29 -0
  117. package/src/theme/components/MuiTable.ts +29 -0
  118. package/src/theme/components/MuiTableBody.ts +15 -0
  119. package/src/theme/components/MuiTableHead.ts +26 -0
  120. package/src/theme/components/MuiTabs.ts +26 -0
  121. package/src/theme/components/MuiTextField.ts +86 -0
  122. package/src/theme/components/MuiToolbar.ts +11 -0
  123. package/src/theme/components/MuiTypography.ts +12 -0
  124. package/src/theme/components/_components.ts +93 -0
  125. package/src/theme/components/index.ts +57 -0
  126. package/src/theme/index.ts +25 -0
  127. package/src/theme/palette.ts +98 -0
  128. package/src/theme/spacing.ts +8 -0
  129. package/src/theme/typography.ts +101 -0
  130. package/src/utils/api.test.ts +19 -0
  131. package/src/utils/api.tsx +327 -0
  132. package/src/utils/auth.ts +17 -0
  133. package/src/utils/form.ts +153 -0
  134. package/src/utils/general.test.ts +42 -0
  135. package/src/utils/general.ts +498 -0
  136. package/src/utils/router.test.ts +156 -0
  137. package/src/utils/router.ts +67 -0
  138. package/src/utils/schema.ts +80 -0
  139. package/src/utils/store.ts +31 -0
  140. package/src/utils/test.tsx +82 -0
  141. package/src/utils/theme.tsx +82 -0
  142. package/src/utils/window.ts +9 -0
  143. package/src/vite-env.d.ts +1 -0
  144. package/tsconfig.json +31 -0
  145. package/tsconfig.node.json +11 -0
  146. package/types/fixes.d.ts +18 -0
  147. package/vite.config.ts +21 -0
@@ -0,0 +1,156 @@
1
+ import { path as p, type Parameters, type Path } from "./router"
2
+
3
+ const m = <SubMatches extends Record<string, Path>>(
4
+ _: string,
5
+ __: string | Parameters,
6
+ subMatches: SubMatches = {} as SubMatches,
7
+ ) => ({ _, __, ...subMatches })
8
+
9
+ function testPaths({
10
+ name,
11
+ paths,
12
+ match,
13
+ }: {
14
+ name: string
15
+ paths: Path
16
+ match: Path
17
+ }) {
18
+ test(name, () => {
19
+ expect(paths).toMatchObject(match)
20
+ })
21
+ }
22
+
23
+ testPaths({
24
+ name: "no nested paths",
25
+ paths: p(""),
26
+ match: m("/", ""),
27
+ })
28
+
29
+ testPaths({
30
+ name: "nested paths",
31
+ paths: p("", {
32
+ a: p("/a", {
33
+ b: p("/b"),
34
+ }),
35
+ }),
36
+ match: m("/", "", {
37
+ a: m("/a", "/a"),
38
+ }),
39
+ })
40
+
41
+ testPaths({
42
+ name: "one param",
43
+ paths: p("", {
44
+ person: p("/person", {
45
+ name: p("/:name", {
46
+ sam: p({ name: "samantha" }),
47
+ }),
48
+ }),
49
+ }),
50
+ match: m("/", "", {
51
+ person: m("/person", "/person", {
52
+ name: m("/person/:name", "/:name", {
53
+ sam: m("/person/samantha", { name: "samantha" }),
54
+ }),
55
+ }),
56
+ }),
57
+ })
58
+
59
+ testPaths({
60
+ name: "multiple params",
61
+ paths: p("", {
62
+ hero: p("/hero", {
63
+ firstAndLastName: p("/:firstName/:lastName", {
64
+ spiderMan: p(
65
+ { firstName: "peter", lastName: "parker" },
66
+ {
67
+ mainVillain: p("/green-goblin"),
68
+ },
69
+ ),
70
+ }),
71
+ }),
72
+ }),
73
+ match: m("/", "", {
74
+ hero: m("/hero", "/hero", {
75
+ firstAndLastName: m(
76
+ "/hero/:firstName/:lastName",
77
+ "/:firstName/:lastName",
78
+ {
79
+ spiderMan: m(
80
+ "/hero/peter/parker",
81
+ { firstName: "peter", lastName: "parker" },
82
+ {
83
+ mainVillain: m(
84
+ "/hero/peter/parker/green-goblin",
85
+ "/green-goblin",
86
+ ),
87
+ },
88
+ ),
89
+ },
90
+ ),
91
+ }),
92
+ }),
93
+ })
94
+
95
+ testPaths({
96
+ name: "nested params",
97
+ paths: p("", {
98
+ hero: p("/hero", {
99
+ firstName: p("/:firstName", {
100
+ spiderMan: p({ firstName: "peter" }),
101
+ lastName: p("/:lastName?", {
102
+ superMan: p(
103
+ { firstName: "clark" },
104
+ {
105
+ superMan: p({ lastName: "kent" }),
106
+ },
107
+ ),
108
+ }),
109
+ batMan: p(
110
+ { firstName: "bruce" },
111
+ {
112
+ lastName: p("/:lastName", {
113
+ batMan: p(
114
+ { lastName: "wayne" },
115
+ {
116
+ mainVillain: p("/joker"),
117
+ },
118
+ ),
119
+ }),
120
+ },
121
+ ),
122
+ }),
123
+ }),
124
+ }),
125
+ match: m("/", "", {
126
+ hero: m("/hero", "/hero", {
127
+ firstName: m("/hero/:firstName", "/:firstName", {
128
+ spiderMan: m("/hero/peter", { firstName: "peter" }),
129
+ lastName: m("/hero/:firstName/:lastName?", "/:lastName?", {
130
+ superMan: m(
131
+ "/hero/clark",
132
+ { firstName: "clark" },
133
+ {
134
+ superMan: m("/hero/clark/kent", { lastName: "kent" }),
135
+ },
136
+ ),
137
+ }),
138
+ batMan: m(
139
+ "/hero/bruce",
140
+ { firstName: "bruce" },
141
+ {
142
+ lastName: m("/hero/bruce/:lastName", "/:lastName", {
143
+ batMan: m(
144
+ "/hero/bruce/wayne",
145
+ { lastName: "wayne" },
146
+ {
147
+ mainVillain: m("/hero/bruce/wayne/joker", "/joker"),
148
+ },
149
+ ),
150
+ }),
151
+ },
152
+ ),
153
+ }),
154
+ }),
155
+ }),
156
+ })
@@ -0,0 +1,67 @@
1
+ import {
2
+ generatePath,
3
+ type LinkProps as _LinkProps,
4
+ type To,
5
+ } from "react-router-dom"
6
+
7
+ import { type PageState } from "../components/page/Page"
8
+
9
+ export type LinkProps<
10
+ Override extends "delta" | "to",
11
+ State extends Record<string, any> = Record<string, any>,
12
+ > = Omit<_LinkProps, "to" | "state"> &
13
+ (Override extends "delta"
14
+ ? { to: number }
15
+ : { to: To; state?: State & Partial<PageState> })
16
+
17
+ export type ReadOnly<T> = {
18
+ readonly [P in keyof T]: T[P]
19
+ }
20
+
21
+ export type Parameters = Record<string, string>
22
+
23
+ export interface Path {
24
+ _: string
25
+ __: string | Parameters
26
+ [subpath: string]: string | Path | Parameters
27
+ }
28
+
29
+ export function path<Subpaths extends Record<string, Path>>(
30
+ _: string | Parameters,
31
+ subpaths: Subpaths = {} as Subpaths,
32
+ ): Path & Subpaths {
33
+ function updatePath(path: Path, root: boolean, params?: Parameters) {
34
+ if (typeof path.__ === "object") {
35
+ params = params ? { ...params, ...path.__ } : path.__
36
+ }
37
+
38
+ const _path = typeof _ === "string" && params ? generatePath(_, params) : _
39
+
40
+ Object.entries(path).forEach(([key, subpath]) => {
41
+ if (key !== "__") {
42
+ subpath = subpath as string | Path
43
+ if (typeof subpath === "string") {
44
+ if (typeof _path === "string" && (!root || key !== "_")) {
45
+ let __path = _path + subpath
46
+ if (__path.endsWith("/")) __path = __path.slice(0, -1)
47
+ path[key] = __path
48
+ }
49
+ } else {
50
+ updatePath(subpath, false, params)
51
+ }
52
+ }
53
+ })
54
+ }
55
+
56
+ const path = { ...subpaths, _: typeof _ === "string" ? _ : "", __: _ }
57
+ if (_ === "") {
58
+ path._ = "/"
59
+ } else {
60
+ updatePath(path, true)
61
+ }
62
+ return path
63
+ }
64
+
65
+ export function getParam(path: Path, key: string) {
66
+ return (path.__ as Parameters)[key]
67
+ }
@@ -0,0 +1,80 @@
1
+ import {
2
+ ValidationError,
3
+ type AnyObject,
4
+ type DefaultFromShape,
5
+ type InferType,
6
+ type MakePartial,
7
+ type ObjectSchema,
8
+ type ObjectShape,
9
+ type Schema,
10
+ type TypeFromShape,
11
+ type ValidateOptions,
12
+ } from "yup"
13
+
14
+ export type _<T> = T extends {}
15
+ ? {
16
+ [k in keyof T]: T[k]
17
+ }
18
+ : T
19
+
20
+ export type MakeKeysOptional<T> = T extends AnyObject ? _<MakePartial<T>> : T
21
+
22
+ export type ObjectFromShape<Shape extends ObjectShape> = MakeKeysOptional<
23
+ _<TypeFromShape<Shape, AnyObject>>
24
+ >
25
+
26
+ export type ObjectSchemaFromShape<Shape extends ObjectShape> = ObjectSchema<
27
+ _<TypeFromShape<Shape, AnyObject>>,
28
+ AnyObject,
29
+ _<DefaultFromShape<Shape>>,
30
+ ""
31
+ >
32
+
33
+ // -----------------------------------------------------------------------------
34
+ // Try Validate Sync
35
+ // -----------------------------------------------------------------------------
36
+
37
+ export type TryValidateSyncOnErrorRT<S extends Schema> = InferType<S> | void
38
+
39
+ export type TryValidateSyncRT<
40
+ S extends Schema,
41
+ OnErrorRT extends TryValidateSyncOnErrorRT<S>,
42
+ > = OnErrorRT extends InferType<S> ? InferType<S> : InferType<S> | undefined
43
+
44
+ export type TryValidateSyncOptions<
45
+ S extends Schema,
46
+ OnErrorRT extends TryValidateSyncOnErrorRT<S>,
47
+ > = ValidateOptions & {
48
+ onError?: (error: ValidationError) => OnErrorRT
49
+ }
50
+
51
+ export function tryValidateSync<S extends Schema>(
52
+ value: any,
53
+ schema: S,
54
+ options?: ValidateOptions,
55
+ ): InferType<S> | undefined
56
+
57
+ export function tryValidateSync<
58
+ S extends Schema,
59
+ OnErrorRT extends TryValidateSyncOnErrorRT<S>,
60
+ >(
61
+ value: any,
62
+ schema: S,
63
+ options?: ValidateOptions & {
64
+ onError: (error: ValidationError) => OnErrorRT
65
+ },
66
+ ): TryValidateSyncRT<S, OnErrorRT>
67
+
68
+ export function tryValidateSync<
69
+ S extends Schema,
70
+ OnErrorRT extends TryValidateSyncOnErrorRT<S>,
71
+ >(value: any, schema: S, options?: TryValidateSyncOptions<S, OnErrorRT>) {
72
+ const { onError, ...validateOptions } = options || {}
73
+
74
+ try {
75
+ return schema.validateSync(value, validateOptions)
76
+ } catch (error) {
77
+ if (!(error instanceof ValidationError)) throw error
78
+ else if (onError) return onError(error)
79
+ }
80
+ }
@@ -0,0 +1,31 @@
1
+ import type { Middleware, Reducer } from "@reduxjs/toolkit"
2
+ import { configureStore } from "@reduxjs/toolkit"
3
+ import { setupListeners } from "@reduxjs/toolkit/query"
4
+
5
+ // The store setup is wrapped in `makeStore` to allow reuse
6
+ // when setting up tests that need the same store config
7
+ export function makeStore<R extends Reducer>({
8
+ reducer,
9
+ middlewares = [],
10
+ preloadedState = {},
11
+ }: {
12
+ reducer: R
13
+ middlewares?: Middleware[]
14
+ preloadedState?: Partial<ReturnType<R>>
15
+ }) {
16
+ const store = configureStore({
17
+ reducer,
18
+ // Adding the api middleware enables caching, invalidation, polling,
19
+ // and other useful features of `rtk-query`.
20
+ middleware: getDefaultMiddleware => {
21
+ return getDefaultMiddleware().concat(middlewares)
22
+ },
23
+ preloadedState,
24
+ })
25
+
26
+ // configure listeners using the provided defaults
27
+ // optional, but required for `refetchOnFocus`/`refetchOnReconnect` behaviors
28
+ setupListeners(store.dispatch)
29
+
30
+ return store
31
+ }
@@ -0,0 +1,82 @@
1
+ import type { Middleware, Reducer, Store } from "@reduxjs/toolkit"
2
+ import type { RenderOptions } from "@testing-library/react"
3
+ import { render } from "@testing-library/react"
4
+ import userEvent from "@testing-library/user-event"
5
+ import type { PropsWithChildren, ReactElement } from "react"
6
+ import { Provider } from "react-redux"
7
+
8
+ import { makeStore } from "./store"
9
+
10
+ export function renderWithUser(
11
+ ui: ReactElement,
12
+ renderOptions: RenderOptions = {},
13
+ ) {
14
+ return {
15
+ user: userEvent.setup(),
16
+ ...render(ui, renderOptions),
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Renders the given React element with Redux Provider and custom store.
22
+ * This function is useful for testing components that are connected to the
23
+ * Redux store.
24
+ *
25
+ * @param ui - The React component or element to render.
26
+ * @param reducer - The root reducer to use for the store.
27
+ * @param extendedRenderOptions - Optional configuration options for rendering.
28
+ * This includes `preloadedState` for initial Redux state and `store` for a
29
+ * specific Redux store instance. Any additional properties are passed to React
30
+ * Testing Library's render function.
31
+ * @returns An object containing the Redux store used in the render, User event
32
+ * API for simulating user interactions in tests, and all of React Testing
33
+ * Library's query functions for testing the component.
34
+ */
35
+ export function renderWithStore<R extends Reducer>(
36
+ ui: ReactElement,
37
+ reducer: R,
38
+ extendedRenderOptions: RenderOptions & {
39
+ /**
40
+ * The middlewares used to create the Redux store.
41
+ */
42
+ middlewares?: Middleware[]
43
+
44
+ /**
45
+ * Defines a specific portion or the entire initial state for the Redux store.
46
+ * This is particularly useful for initializing the state in a
47
+ * controlled manner during testing, allowing components to be rendered
48
+ * with predetermined state conditions.
49
+ */
50
+ preloadedState?: Partial<ReturnType<R>>
51
+
52
+ /**
53
+ * Allows the use of a specific Redux store instance instead of a
54
+ * default or global store. This flexibility is beneficial when
55
+ * testing components with unique store requirements or when isolating
56
+ * tests from a global store state. The custom store should be configured
57
+ * to match the structure and middleware of the store used by the application.
58
+ *
59
+ * @default makeStore({reducer,middlewares,preloadedState})
60
+ */
61
+ store?: Store
62
+ } = {},
63
+ ) {
64
+ const {
65
+ middlewares,
66
+ preloadedState,
67
+ // Automatically create a store instance if no store was passed in
68
+ store = makeStore({ reducer, middlewares, preloadedState }),
69
+ ...renderOptions
70
+ } = extendedRenderOptions
71
+
72
+ const Wrapper = ({ children }: PropsWithChildren) => (
73
+ <Provider store={store}>{children}</Provider>
74
+ )
75
+
76
+ // Return an object with the store and all of RTL's query functions
77
+ return {
78
+ store,
79
+ user: userEvent.setup(),
80
+ ...render(ui, { wrapper: Wrapper, ...renderOptions }),
81
+ }
82
+ }
@@ -0,0 +1,82 @@
1
+ import type React from "react"
2
+ import { Divider, type DividerProps, type ThemeOptions } from "@mui/material"
3
+ import { type CommonProps } from "@mui/material/OverridableComponent"
4
+
5
+ import _components from "../theme/components"
6
+
7
+ export function insertDividerBetweenElements({
8
+ elements,
9
+ dividerProps,
10
+ }: {
11
+ elements: React.ReactElement[]
12
+ dividerProps?: DividerProps
13
+ }): React.ReactElement[] {
14
+ return elements.map((element, index) => (
15
+ <>
16
+ {element}
17
+ {index !== elements.length - 1 ? (
18
+ <Divider {...dividerProps} />
19
+ ) : undefined}
20
+ </>
21
+ ))
22
+ }
23
+
24
+ export function getStyleOverrides(
25
+ ownerState: CommonProps,
26
+ componentKey: keyof NonNullable<ThemeOptions["components"]>,
27
+ muiClassName: string = "root",
28
+ components: ThemeOptions["components"] = _components,
29
+ ): object {
30
+ if (components !== undefined) {
31
+ const component = components[componentKey]
32
+
33
+ if (
34
+ component !== undefined &&
35
+ "styleOverrides" in component &&
36
+ typeof component.styleOverrides === "object" &&
37
+ muiClassName in component.styleOverrides
38
+ ) {
39
+ const muiClass = (component.styleOverrides as Record<string, any>)[
40
+ muiClassName
41
+ ]
42
+
43
+ switch (typeof muiClass) {
44
+ case "function":
45
+ return muiClass({ ownerState })
46
+ case "object":
47
+ return muiClass
48
+ }
49
+ }
50
+ }
51
+
52
+ return {}
53
+ }
54
+
55
+ export function getClassNames(props: CommonProps): string[] {
56
+ return props.className?.split(" ") ?? []
57
+ }
58
+
59
+ export function includesClassNames(
60
+ propsOrClassNames: CommonProps | string[],
61
+ includes: string[],
62
+ ): boolean {
63
+ const classNames = Array.isArray(propsOrClassNames)
64
+ ? propsOrClassNames
65
+ : getClassNames(propsOrClassNames)
66
+
67
+ return includes.every(className => classNames.includes(className))
68
+ }
69
+
70
+ export function matchClassNames(
71
+ propsOrClassNames: CommonProps | string[],
72
+ pattern: string | RegExp,
73
+ ): RegExpMatchArray[] {
74
+ const classNames = Array.isArray(propsOrClassNames)
75
+ ? propsOrClassNames
76
+ : getClassNames(propsOrClassNames)
77
+
78
+ return classNames
79
+ .map(className => className.match(pattern))
80
+ .filter(match => match !== null)
81
+ .map(match => match as RegExpMatchArray)
82
+ }
@@ -0,0 +1,9 @@
1
+ export function configureFreshworksWidget(display: "open" | "hide"): void {
2
+ // @ts-expect-error defined in external script
3
+ window.FreshworksWidget(display)
4
+ }
5
+
6
+ export function toggleOneTrustInfoDisplay(): void {
7
+ // @ts-expect-error defined in external script
8
+ window.Optanon.ToggleInfoDisplay()
9
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
package/tsconfig.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "useDefineForClassFields": true,
5
+ "lib": [
6
+ "DOM",
7
+ "DOM.Iterable",
8
+ "ESNext"
9
+ ],
10
+ "allowJs": false,
11
+ "skipLibCheck": true,
12
+ "esModuleInterop": false,
13
+ "allowSyntheticDefaultImports": true,
14
+ "strict": true,
15
+ "module": "ESNext",
16
+ "moduleResolution": "bundler",
17
+ "resolveJsonModule": true,
18
+ "isolatedModules": true,
19
+ "noEmit": true,
20
+ "jsx": "react-jsx",
21
+ "types": [
22
+ "vitest/globals",
23
+ "node"
24
+ ]
25
+ },
26
+ "references": [
27
+ {
28
+ "path": "./tsconfig.node.json"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "allowSyntheticDefaultImports": true
7
+ },
8
+ "include": [
9
+ "vite.config.ts"
10
+ ]
11
+ }
@@ -0,0 +1,18 @@
1
+ /*
2
+ * Namespace 'React' has no exported member 'StatelessComponent'
3
+ * in formik, react-mapbox-gl
4
+ */
5
+ declare namespace React {
6
+ type StatelessComponent<P> = React.FunctionComponent<P>
7
+ }
8
+
9
+ declare module "*.svg" {
10
+ const content: string
11
+ export default content
12
+ }
13
+
14
+ /*
15
+ * Don't care about the typings of external libraries.
16
+ * All libraries without typings will be imported as `any`.
17
+ */
18
+ declare module "*" {}
package/vite.config.ts ADDED
@@ -0,0 +1,21 @@
1
+ import react from "@vitejs/plugin-react"
2
+ import { defineConfig } from "vitest/config"
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ server: {
8
+ open: true,
9
+ },
10
+ test: {
11
+ globals: true,
12
+ environment: "jsdom",
13
+ setupFiles: "src/setupTests",
14
+ mockReset: true,
15
+ coverage: {
16
+ enabled: true,
17
+ provider: "istanbul",
18
+ reporter: ["html", "cobertura"],
19
+ },
20
+ },
21
+ })