southpaw 0.2.7

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 (169) hide show
  1. package/README.md +51 -0
  2. package/api/client.ts +83 -0
  3. package/api/helpers/fs.ts +98 -0
  4. package/api/helpers/stream.ts +6 -0
  5. package/api/index.ts +50 -0
  6. package/api/server.ts +566 -0
  7. package/constants/fonts.ts +1583 -0
  8. package/constants/icons.ts +2124 -0
  9. package/constants/langs.ts +2592 -0
  10. package/constants/ssr-loading.tsx +17 -0
  11. package/contexts/dev.tsx +124 -0
  12. package/hooks/useDebounceCb.ts +21 -0
  13. package/modules/app.tsx +102 -0
  14. package/modules/behaviors.ts +161 -0
  15. package/modules/component.tsx +483 -0
  16. package/modules/config/index.ts +8 -0
  17. package/modules/database.ts +25 -0
  18. package/modules/document.tsx +23 -0
  19. package/modules/error.tsx +16 -0
  20. package/modules/page/autozoom.tsx +92 -0
  21. package/modules/page/browser.tsx +166 -0
  22. package/modules/page/index.tsx +327 -0
  23. package/modules/page/insert-modal.tsx +225 -0
  24. package/modules/page/inspect/index.tsx +237 -0
  25. package/modules/page/inspect/wrapper.tsx +88 -0
  26. package/modules/page/knobs/action.tsx +58 -0
  27. package/modules/page/knobs/color.tsx +78 -0
  28. package/modules/page/knobs/helpers.ts +71 -0
  29. package/modules/page/knobs/icon.tsx +85 -0
  30. package/modules/page/knobs/linker.tsx +188 -0
  31. package/modules/page/knobs/list-json.tsx +149 -0
  32. package/modules/page/knobs/list-text.tsx +129 -0
  33. package/modules/page/knobs/number.tsx +84 -0
  34. package/modules/page/knobs/segmented.tsx +81 -0
  35. package/modules/page/knobs/select.tsx +89 -0
  36. package/modules/page/knobs/size.tsx +106 -0
  37. package/modules/page/knobs/switch.tsx +75 -0
  38. package/modules/page/knobs/text.tsx +93 -0
  39. package/modules/page/left-tabs.tsx +36 -0
  40. package/modules/page/right-tabs.tsx +31 -0
  41. package/modules/page/seo.tsx +69 -0
  42. package/modules/page/tree.tsx +860 -0
  43. package/modules/state.ts +787 -0
  44. package/modules/store.ts +37 -0
  45. package/modules/theme.ts +105 -0
  46. package/modules/translations.ts +15 -0
  47. package/package.json +68 -0
  48. package/scripts/bin.js +607 -0
  49. package/scripts/test.js +145 -0
  50. package/themes/base.tsx +8962 -0
  51. package/themes/index.ts +4 -0
  52. package/themes/m2.ts +39 -0
  53. package/themes/newspaper.ts +39 -0
  54. package/types/api.ts +57 -0
  55. package/types/fiber_node.ts +69 -0
  56. package/types/react_element.ts +14 -0
  57. package/ui/accordion.tsx +70 -0
  58. package/ui/actionicon.tsx +41 -0
  59. package/ui/affix.tsx +14 -0
  60. package/ui/alert.tsx +37 -0
  61. package/ui/anchor.tsx +52 -0
  62. package/ui/arrow.tsx +116 -0
  63. package/ui/aspectratio.tsx +21 -0
  64. package/ui/autocomplete.tsx +34 -0
  65. package/ui/avatar.tsx +36 -0
  66. package/ui/backgroundimage.tsx +16 -0
  67. package/ui/badge.tsx +28 -0
  68. package/ui/blockquote.tsx +15 -0
  69. package/ui/blocks/faq.tsx +145 -0
  70. package/ui/blocks/features.tsx +167 -0
  71. package/ui/blocks/footer.tsx +182 -0
  72. package/ui/blocks/herobanner.tsx +391 -0
  73. package/ui/blocks/index.ts +44 -0
  74. package/ui/blocks/leftnav.tsx +141 -0
  75. package/ui/blocks/pricing.tsx +210 -0
  76. package/ui/blocks/testimonials.tsx +149 -0
  77. package/ui/blocks/uidocs.tsx +1429 -0
  78. package/ui/box.tsx +27 -0
  79. package/ui/breadcrumbs.tsx +33 -0
  80. package/ui/burger.tsx +23 -0
  81. package/ui/button.tsx +85 -0
  82. package/ui/card.tsx +28 -0
  83. package/ui/center.tsx +26 -0
  84. package/ui/checkbox.tsx +35 -0
  85. package/ui/chip.tsx +32 -0
  86. package/ui/closebutton.tsx +15 -0
  87. package/ui/code.tsx +104 -0
  88. package/ui/collapse.tsx +16 -0
  89. package/ui/colorinput.tsx +32 -0
  90. package/ui/colorpicker.tsx +26 -0
  91. package/ui/colorswatch.tsx +17 -0
  92. package/ui/combobox.tsx +80 -0
  93. package/ui/container.tsx +27 -0
  94. package/ui/dialog.tsx +15 -0
  95. package/ui/divider.tsx +58 -0
  96. package/ui/drawer.tsx +28 -0
  97. package/ui/fieldset.tsx +15 -0
  98. package/ui/filebutton.tsx +23 -0
  99. package/ui/fileinput.tsx +36 -0
  100. package/ui/flex.tsx +139 -0
  101. package/ui/focustrap.tsx +15 -0
  102. package/ui/form.tsx +26 -0
  103. package/ui/grid.tsx +69 -0
  104. package/ui/highlight.tsx +15 -0
  105. package/ui/hoverable.tsx +66 -0
  106. package/ui/hovercard.tsx +45 -0
  107. package/ui/icon.tsx +76 -0
  108. package/ui/image.tsx +32 -0
  109. package/ui/index.ts +1355 -0
  110. package/ui/indicator.tsx +42 -0
  111. package/ui/infobox.tsx +200 -0
  112. package/ui/input.tsx +18 -0
  113. package/ui/inviewport.tsx +23 -0
  114. package/ui/jsoninput.tsx +35 -0
  115. package/ui/kbd.tsx +20 -0
  116. package/ui/list.tsx +33 -0
  117. package/ui/loader.tsx +26 -0
  118. package/ui/loadingoverlay.tsx +22 -0
  119. package/ui/mark.tsx +15 -0
  120. package/ui/menu.tsx +89 -0
  121. package/ui/modal.tsx +27 -0
  122. package/ui/multiselect.tsx +42 -0
  123. package/ui/nativeselect.tsx +17 -0
  124. package/ui/navlink.tsx +40 -0
  125. package/ui/notification.tsx +25 -0
  126. package/ui/numberformatter.tsx +15 -0
  127. package/ui/numberinput.tsx +37 -0
  128. package/ui/overlay.tsx +15 -0
  129. package/ui/pagination.tsx +21 -0
  130. package/ui/paper.tsx +33 -0
  131. package/ui/passwordinput.tsx +36 -0
  132. package/ui/pill.tsx +17 -0
  133. package/ui/pillsinput.tsx +37 -0
  134. package/ui/pininput.tsx +30 -0
  135. package/ui/popover.tsx +43 -0
  136. package/ui/portal.tsx +15 -0
  137. package/ui/progress.tsx +49 -0
  138. package/ui/props.ts +91 -0
  139. package/ui/propsDef.ts +38 -0
  140. package/ui/radio.tsx +30 -0
  141. package/ui/rating.tsx +25 -0
  142. package/ui/ringprogress.tsx +17 -0
  143. package/ui/scrollarea.tsx +27 -0
  144. package/ui/segmentedcontrol.tsx +38 -0
  145. package/ui/select.tsx +43 -0
  146. package/ui/simplegrid.tsx +23 -0
  147. package/ui/skeleton.tsx +15 -0
  148. package/ui/slider.tsx +31 -0
  149. package/ui/space.tsx +19 -0
  150. package/ui/spoiler.tsx +23 -0
  151. package/ui/stepper.tsx +63 -0
  152. package/ui/switch.tsx +29 -0
  153. package/ui/table.tsx +93 -0
  154. package/ui/tabs.tsx +80 -0
  155. package/ui/tagsinput.tsx +19 -0
  156. package/ui/terminal.tsx +44 -0
  157. package/ui/text.tsx +168 -0
  158. package/ui/textarea.tsx +36 -0
  159. package/ui/textinput.tsx +34 -0
  160. package/ui/timeline.tsx +30 -0
  161. package/ui/title.tsx +42 -0
  162. package/ui/tooltip.tsx +32 -0
  163. package/ui/transition.tsx +21 -0
  164. package/ui/tree.tsx +42 -0
  165. package/ui/typographystylesprovider.tsx +20 -0
  166. package/ui/unstyledbutton.tsx +18 -0
  167. package/ui/video.tsx +16 -0
  168. package/ui/visuallyhidden.tsx +15 -0
  169. package/utils/index.ts +76 -0
@@ -0,0 +1,17 @@
1
+ import { Alert } from "@mantine/core";
2
+ import { DynamicOptionsLoadingProps } from "next/dynamic";
3
+
4
+ export const loading: (
5
+ loadingProps: DynamicOptionsLoadingProps
6
+ ) => React.ReactNode = (loadingProps) => {
7
+ if (loadingProps.error) {
8
+ return (
9
+ <Alert variant="filled" color="red" title="Loading error">
10
+ {loadingProps.error.message}
11
+ </Alert>
12
+ );
13
+ }
14
+ // TODO: figure out a way to define width and height
15
+ // return <Skeleton visible miw={500} mih={50} />;
16
+ return null;
17
+ };
@@ -0,0 +1,124 @@
1
+ import {
2
+ Dispatch,
3
+ Context as ContextType,
4
+ createContext,
5
+ FC,
6
+ PropsWithChildren,
7
+ useContext,
8
+ useReducer,
9
+ } from "react";
10
+ import { TreeNodeData } from "@mantine/core";
11
+
12
+ export type TNode = TreeNodeData;
13
+ const initialState = {
14
+ modals: {
15
+ insert: false,
16
+ },
17
+ tree: {
18
+ selectedNode: null as TNode | null,
19
+ menuNode: {
20
+ insertMode: "within",
21
+ node: {},
22
+ } as {
23
+ insertMode: "within" | "before" | "after";
24
+ node: TNode;
25
+ },
26
+ },
27
+ };
28
+
29
+ type TActions = {
30
+ TREE_SELECT_NODE: {
31
+ type: "TREE_SELECT_NODE";
32
+ args: { selectedNode: typeof initialState.tree.selectedNode };
33
+ };
34
+ TREE_SET_MENU_NODE: {
35
+ type: "TREE_SET_MENU_NODE";
36
+ args: typeof initialState.tree.menuNode;
37
+ };
38
+ MODALS_OPEN: {
39
+ type: "MODALS_OPEN";
40
+ args: { name: keyof (typeof initialState)["modals"] };
41
+ };
42
+ MODALS_CLOSE: {
43
+ type: "MODALS_CLOSE";
44
+ args: { name: keyof (typeof initialState)["modals"] };
45
+ };
46
+ };
47
+ function reducer<T extends keyof TActions>(
48
+ state: typeof initialState,
49
+ action: TActions[T]
50
+ ) {
51
+ switch (action.type) {
52
+ case "TREE_SELECT_NODE": {
53
+ {
54
+ return {
55
+ ...state,
56
+ tree: {
57
+ ...state.tree,
58
+ selectedNode: action.args.selectedNode,
59
+ },
60
+ };
61
+ }
62
+ }
63
+ case "TREE_SET_MENU_NODE": {
64
+ {
65
+ return {
66
+ ...state,
67
+ tree: {
68
+ ...state.tree,
69
+ menuNode: action.args,
70
+ },
71
+ };
72
+ }
73
+ }
74
+ case "MODALS_OPEN": {
75
+ {
76
+ return {
77
+ ...state,
78
+ modals: {
79
+ ...state.modals,
80
+ [action.args.name]: true,
81
+ },
82
+ };
83
+ }
84
+ }
85
+ case "MODALS_CLOSE": {
86
+ {
87
+ return {
88
+ ...state,
89
+ modals: {
90
+ ...state.modals,
91
+ [action.args.name]: false,
92
+ },
93
+ };
94
+ }
95
+ }
96
+
97
+ default:
98
+ throw Error("Unknown action");
99
+ }
100
+ }
101
+
102
+ type TContextType = {
103
+ state: typeof initialState;
104
+ dispatch: Dispatch<TActions[keyof TActions]>;
105
+ };
106
+ const Context: ContextType<TContextType> = createContext({} as TContextType);
107
+
108
+ export const useContextDev = () => {
109
+ return useContext(Context);
110
+ };
111
+ export const ContextProviderDev: FC<PropsWithChildren> = ({ children }) => {
112
+ const [state, dispatch] = useReducer(reducer, initialState);
113
+
114
+ return (
115
+ <Context.Provider
116
+ value={{
117
+ state,
118
+ dispatch,
119
+ }}
120
+ >
121
+ {children}
122
+ </Context.Provider>
123
+ );
124
+ };
@@ -0,0 +1,21 @@
1
+ import { useRef, useCallback } from "react";
2
+
3
+ export function useDebounceCb<T extends (...args: unknown[]) => void>(
4
+ callback: T,
5
+ delay: number
6
+ ) {
7
+ const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
8
+
9
+ const debouncedCallback = useCallback(
10
+ (...args: Parameters<T>) => {
11
+ if (timerRef.current) clearTimeout(timerRef.current);
12
+
13
+ timerRef.current = setTimeout(() => {
14
+ callback(...args);
15
+ }, delay);
16
+ },
17
+ [callback, delay]
18
+ );
19
+
20
+ return debouncedCallback;
21
+ }
@@ -0,0 +1,102 @@
1
+ import { AppProps } from "next/app";
2
+ import { useState, useEffect } from "react";
3
+ import { MantineProvider, MantineTheme } from "@mantine/core";
4
+ import { ModalsProvider } from "@mantine/modals";
5
+
6
+ import { m2 } from "../themes";
7
+ import { create_translations } from "./translations";
8
+ import { ThemeBase } from "../themes/base";
9
+ import { ContextProviderDev } from "southpaw/contexts/dev";
10
+ import { useRouter } from "next/router";
11
+ import { Components } from "@/components";
12
+
13
+ type Params = {
14
+ name: string;
15
+ description: string;
16
+ version: string;
17
+ behaviors: Behaviors;
18
+ components: typeof Components;
19
+ theme?: MantineTheme;
20
+ } & Partial<{
21
+ translations: Record<string, ReturnType<typeof create_translations>>;
22
+ }>;
23
+
24
+ export const create_app = (params: Params) => {
25
+ const behaviors = params.behaviors;
26
+ const translations = params.translations!;
27
+ const theme = params.theme || m2;
28
+ // const components = params.components;
29
+ // globalThis.Components = components;
30
+
31
+ const Fn = ({ Component, pageProps }: AppProps) => {
32
+ const router = useRouter();
33
+ const [colorScheme, setColorScheme] = useState<"dark" | "light">("light");
34
+ const [lang, setLang] = useState<(typeof translations)[string]["lang"]>(
35
+ translations[Object.keys(translations)[0]].lang,
36
+ );
37
+ const isIframe = globalThis.window && window.self !== window.top;
38
+ const isTest = navigator.webdriver === true;
39
+ const isDev =
40
+ !Object.keys(router.query).includes("isPreview") &&
41
+ process.env.NODE_ENV === "development" &&
42
+ !isTest;
43
+ const setTransLang = (l: typeof lang) => {
44
+ setLang(l);
45
+ };
46
+ const trans = Object.entries(translations).reduce(
47
+ (acc, [key, value]) => {
48
+ const fn = (name: keyof Translations, ...args: unknown[]) => {
49
+ const fn = value.translations[name];
50
+ const result = fn(...args)[lang];
51
+ return result;
52
+ };
53
+ (acc as Record<string, typeof fn>)[key] = fn;
54
+ return acc;
55
+ },
56
+ {} as Record<
57
+ string,
58
+ (name: keyof Translations, ...args: unknown[]) => string
59
+ >,
60
+ );
61
+
62
+ const loadFonts = async () => {
63
+ const WebFont = await import("webfontloader");
64
+ WebFont.load({
65
+ google: {
66
+ families: [
67
+ `${theme.fontFamily}:100,200,300,400,500,600,700,800,900`,
68
+ theme.fontFamilyMonospace,
69
+ ],
70
+ },
71
+ });
72
+ };
73
+
74
+ useEffect(() => {
75
+ loadFonts();
76
+ if (isDev && !isIframe) {
77
+ }
78
+ }, []);
79
+
80
+ return (
81
+ <ContextProviderDev>
82
+ <ThemeBase />
83
+ <MantineProvider theme={theme} forceColorScheme={colorScheme}>
84
+ <ModalsProvider>
85
+ {/* {!isIframe && <LoadingOverlay visible={!ragReady} />} */}
86
+ <Component
87
+ {...pageProps}
88
+ behaviors={behaviors}
89
+ trans={trans}
90
+ lang={lang}
91
+ setTransLang={setTransLang}
92
+ colorScheme={colorScheme}
93
+ setColorScheme={setColorScheme}
94
+ />
95
+ </ModalsProvider>
96
+ </MantineProvider>
97
+ </ContextProviderDev>
98
+ );
99
+ };
100
+ Fn.displayName = params.name;
101
+ return Fn;
102
+ };
@@ -0,0 +1,161 @@
1
+ // TODO: add types for the store and actions
2
+ // NOTE: types are intentionally conservative here to avoid breaking existing apps.
3
+ import ObservableSlim from "./state";
4
+
5
+ const PAGE_UPDATE_EVENT = "--page-update";
6
+
7
+ type StoreType<
8
+ STATE extends Record<string, any>,
9
+ ACTIONS extends Record<string, any>,
10
+ > = {
11
+ state: STATE;
12
+ actions: ACTIONS;
13
+ };
14
+
15
+ type BoundActionsType<STATE extends Record<string, any>> = Record<
16
+ string,
17
+ (this: { state: STATE }, ...args: any[]) => Promise<void>
18
+ >;
19
+
20
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
21
+ type DefinitionsType<STORE extends StoreType<{}, {}>> = {
22
+ when: Record<
23
+ string,
24
+ (
25
+ this: {
26
+ store: {
27
+ state: STORE["state"];
28
+ actions: {
29
+ [ACTION_NAME in keyof STORE["actions"]]: OmitThisParameter<
30
+ STORE["actions"][ACTION_NAME]
31
+ >;
32
+ };
33
+ };
34
+ },
35
+ ...args: any[]
36
+ ) => Promise<void>
37
+ >;
38
+ then: Record<string, (this: { store: STORE }, ...args: any[]) => any>;
39
+ given: Record<
40
+ string,
41
+ (this: { store: STORE }, ...args: any[]) => Promise<void>
42
+ >;
43
+ };
44
+
45
+ export const create_behaviors = <
46
+ STATE extends Record<string, any>,
47
+ ACTIONS extends BoundActionsType<STATE>,
48
+ STORE extends {
49
+ state: STATE;
50
+ actions: ACTIONS;
51
+ },
52
+ DEFINITIONS extends DefinitionsType<STORE>,
53
+ >(
54
+ _store: StoreType<STATE, ACTIONS>,
55
+ definitions: DEFINITIONS,
56
+ ) => {
57
+ const $$typeof = Symbol("southpaw.behaviors");
58
+ const state: STORE["state"] = ObservableSlim.create(
59
+ { ..._store.state, __isProxy: false, __getTarget: _store.state },
60
+ false,
61
+ function (changes: any) {
62
+ const event = new CustomEvent(PAGE_UPDATE_EVENT, { detail: changes });
63
+ document.dispatchEvent(event);
64
+ },
65
+ ) as unknown as STORE["state"];
66
+ const actions = Object.keys(_store.actions).reduce((acc, name) => {
67
+ (acc as Record<string, any>)[name] = (
68
+ _store.actions[
69
+ name
70
+ ] as (typeof _store.actions)[keyof typeof _store.actions]
71
+ ).bind({ state }) as OmitThisParameter<
72
+ (typeof _store.actions)[keyof typeof _store.actions]
73
+ >;
74
+ return acc;
75
+ }, {} as ACTIONS);
76
+ const store = {
77
+ state,
78
+ actions,
79
+ };
80
+ return {
81
+ $$typeof,
82
+ definitions,
83
+ given<NAME extends keyof DEFINITIONS["given"]>(
84
+ name: NAME,
85
+ ...args: Parameters<DEFINITIONS["given"][NAME]>
86
+ ) {
87
+ const fn = (definitions.given as DEFINITIONS["given"])[name];
88
+ const condition = fn.bind({ store: store as STORE })(...args);
89
+ return condition;
90
+ },
91
+ when<NAME extends keyof DEFINITIONS["when"]>(name: NAME) {
92
+ const fn = (definitions.when as DEFINITIONS["when"])[name];
93
+ const cb = (...args: Parameters<DEFINITIONS["when"][NAME]>) =>
94
+ fn.bind({
95
+ store: {
96
+ state: store.state,
97
+ actions: actions as {
98
+ [ACTION_NAME in keyof STORE["actions"]]: OmitThisParameter<
99
+ STORE["actions"][ACTION_NAME]
100
+ >;
101
+ },
102
+ },
103
+ })(...args);
104
+ return cb;
105
+ },
106
+ then<NAME extends keyof DEFINITIONS["then"]>(
107
+ name: NAME,
108
+ ...args: Parameters<OmitThisParameter<DEFINITIONS["then"][NAME]>>
109
+ ): {
110
+ get: () => ReturnType<DEFINITIONS["then"][NAME]>;
111
+ ifEqual: (value: any) => boolean;
112
+ shouldEqual: (
113
+ value: ReturnType<DEFINITIONS["then"][NAME]>,
114
+ ) => Promise<string>;
115
+ } {
116
+ const fn = (definitions.then as DEFINITIONS["then"])[name];
117
+ const value = fn.bind({ store: store as STORE })(...args);
118
+ return {
119
+ get() {
120
+ return value as ReturnType<DEFINITIONS["then"][NAME]>;
121
+ },
122
+ ifEqual(equals: any) {
123
+ const condition = value === equals;
124
+ return condition;
125
+ },
126
+ shouldEqual(equals: any) {
127
+ const condition = value === equals;
128
+ if (condition) {
129
+ return Promise.resolve("Test passed !");
130
+ }
131
+ throw new Error(
132
+ `Expected "${String(name)}" to equal ${equals}, received ${value}`,
133
+ );
134
+ },
135
+ };
136
+ },
137
+ do<NAME extends keyof DEFINITIONS["when"]>(name: NAME) {
138
+ const fn = (definitions.when as DEFINITIONS["when"])[name];
139
+ const cb = (...args: Parameters<DEFINITIONS["when"][NAME]>) =>
140
+ fn.bind({
141
+ store: {
142
+ state: store.state,
143
+ actions: actions as {
144
+ [ACTION_NAME in keyof STORE["actions"]]: OmitThisParameter<
145
+ STORE["actions"][ACTION_NAME]
146
+ >;
147
+ },
148
+ },
149
+ })(...args);
150
+ return cb;
151
+ },
152
+ get<NAME extends keyof DEFINITIONS["then"]>(
153
+ name: NAME,
154
+ ...args: Parameters<OmitThisParameter<DEFINITIONS["then"][NAME]>>
155
+ ): ReturnType<DEFINITIONS["then"][NAME]> {
156
+ const fn = (definitions.then as DEFINITIONS["then"])[name];
157
+ const value = fn.bind({ store: store as STORE })(...args);
158
+ return value as ReturnType<DEFINITIONS["then"][NAME]>;
159
+ },
160
+ };
161
+ };