@xyd-js/framework 0.1.0-xyd.2 → 0.1.0-xyd.21

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 (40) hide show
  1. package/dist/hydration.js +63 -121
  2. package/dist/hydration.js.map +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +0 -17
  5. package/dist/index.js.map +1 -1
  6. package/dist/react.js +103 -1437
  7. package/dist/react.js.map +1 -1
  8. package/package.json +19 -18
  9. package/dist/hydration.d.mts +0 -11
  10. package/dist/hydration.mjs +0 -245
  11. package/dist/hydration.mjs.map +0 -1
  12. package/dist/index.d.mts +0 -6
  13. package/dist/index.mjs +0 -1
  14. package/dist/index.mjs.map +0 -1
  15. package/dist/react.d.mts +0 -32
  16. package/dist/react.mjs +0 -1938
  17. package/dist/react.mjs.map +0 -1
  18. package/dist/sidebar-Dwf54qYp.d.mts +0 -15
  19. package/packages/hydration/README.md +0 -3
  20. package/packages/hydration/index.ts +0 -3
  21. package/packages/hydration/settings-to-props.ts +0 -325
  22. package/packages/react/README.md +0 -3
  23. package/packages/react/components/index.tsx +0 -337
  24. package/packages/react/components/sidebar/index.ts +0 -3
  25. package/packages/react/components/sidebar/sidebar-group.tsx +0 -240
  26. package/packages/react/components/sidebar/sidebar.tsx +0 -127
  27. package/packages/react/contexts/framework.tsx +0 -78
  28. package/packages/react/contexts/index.ts +0 -2
  29. package/packages/react/contexts/ui.tsx +0 -6
  30. package/packages/react/hooks/index.ts +0 -3
  31. package/packages/react/hooks/useMatchedNav.tsx +0 -29
  32. package/packages/react/index.ts +0 -12
  33. package/packages/react/utils/manualHydration.ts +0 -25
  34. package/packages/theme/context.tsx +0 -19
  35. package/packages/theme/index.ts +0 -0
  36. package/postcss.config.cjs +0 -5
  37. package/src/index.ts +0 -1
  38. package/src/types.ts +0 -5
  39. package/tsconfig.json +0 -45
  40. package/tsup.config.ts +0 -28
@@ -1,240 +0,0 @@
1
- import React, {createContext, useContext, useEffect, useState} from "react";
2
- import {useLocation, useNavigation, useNavigate} from "react-router";
3
-
4
- import {FwSidebarGroupProps, FwSidebarItemProps} from "./sidebar";
5
- import {UIContext} from "../../contexts/ui";
6
- import {useSidebarGroups} from "../../contexts";
7
-
8
-
9
- export interface FwGroupContext {
10
- active: (item: FwSidebarItemProps) => [boolean, () => void],
11
- onClick?: (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, item: FwSidebarItemProps) => void,
12
- }
13
-
14
- type GroupBehaviour = (item: FwSidebarItemProps) => [boolean, () => void]
15
-
16
- const groupContext = createContext<FwGroupContext>({
17
- active: () => [false, () => {
18
- }],
19
- onClick: () => null // TODO: should be deprecated?
20
- })
21
-
22
- export function FwSidebarGroupContext({
23
- children,
24
- onePathBehaviour,
25
- clientSideRouting,
26
- initialActiveItems,
27
- }:
28
- {
29
- children: React.ReactNode,
30
- onePathBehaviour?: boolean,
31
- clientSideRouting?: boolean // TODO: scrollRouting?,
32
- initialActiveItems: any[]
33
- }) {
34
-
35
- let groupBehaviour: GroupBehaviour
36
-
37
- if (onePathBehaviour) {
38
- groupBehaviour = useOnePathBehaviour(initialActiveItems)
39
- } else {
40
- groupBehaviour = useDefaultBehaviour(initialActiveItems)
41
- }
42
- const location = useLocation()
43
-
44
- const [href, setHref] = useState(location.pathname)
45
-
46
- return <UIContext.Provider value={{
47
- href: href,
48
- setHref: (value) => {
49
- setHref(value)
50
- }
51
- }}>
52
- <groupContext.Provider value={{
53
- active: groupBehaviour,
54
- onClick: clientSideRouting ? (event, item) => {
55
- setHref(item.href)
56
- scrollToDataSlug(event, item)
57
- // navigate(item.href)
58
- } : undefined
59
- }}>
60
- {children}
61
- </groupContext.Provider>
62
- </UIContext.Provider>
63
- }
64
-
65
- export function useGroup() {
66
- return useContext(groupContext)
67
- }
68
-
69
-
70
- // TODO: !!! better algorithm (JSON.stringify is not good) !!!!!
71
- // TODO: !!!! use array structure instad! !!!
72
-
73
- function getLastValue(set) {
74
- let value;
75
- for (value of set) ;
76
- return value;
77
- }
78
-
79
- function stringify(item: FwSidebarItemProps) {
80
- return JSON.stringify({
81
- title: item.title,
82
- href: item.href,
83
- items: item.items?.map((item) => stringify(item)),
84
- })
85
- }
86
-
87
- function recursiveSearch(items: FwSidebarItemProps[], href: string, levels: any[] = []) {
88
- for (let i = 0; i < items.length; i++) {
89
- const item = items[i]
90
-
91
- if (item.href === href) {
92
- return [...levels, i]
93
- }
94
-
95
- if (item.items) {
96
- const result = recursiveSearch(item.items, href, [...levels, i])
97
- if (result) {
98
- return result
99
- }
100
- }
101
- }
102
- return null
103
- }
104
-
105
- function calcActive(groups: FwSidebarGroupProps[], url: any) {
106
- const initialActiveItems: any[] = []
107
-
108
- groups.forEach(group => {
109
- const activeLevels = recursiveSearch(group.items, url) || []
110
-
111
- activeLevels.reduce((acc, index) => {
112
- initialActiveItems.push({
113
- ...acc[index],
114
- active: true
115
- })
116
- return acc[index].items
117
- }, group.items)
118
-
119
- return group
120
- })
121
-
122
- return initialActiveItems
123
- }
124
-
125
- function useDefaultBehaviour(initialActiveItems: any[]) {
126
- const groups = useSidebarGroups()
127
- const [weakSet] = useState(() => new Set<string>(initialActiveItems.map((item) => stringify(item))));
128
- const [, setForceUpdate] = useState(0);
129
-
130
- useEffect(() => {
131
- window.addEventListener('xyd.history.pushState', (event: CustomEvent) => {
132
- const url = event.detail?.url
133
-
134
- if (!url) {
135
- return
136
- }
137
- // TODO: better data structures
138
- const active = calcActive(groups, url)
139
- weakSet.clear()
140
- active.forEach((item) => {
141
- addItem(item)
142
- })
143
- });
144
- }, [])
145
-
146
- const forceUpdate = () => setForceUpdate((prev) => prev + 1);
147
-
148
- const addItem = (item: FwSidebarItemProps) => {
149
- weakSet.add(stringify(item));
150
- forceUpdate();
151
- };
152
-
153
- const deleteItem = (item: FwSidebarItemProps) => {
154
- weakSet.delete(stringify(item));
155
- forceUpdate();
156
- };
157
-
158
- const hasItem = (item: FwSidebarItemProps) => {
159
- return weakSet.has(stringify(item));
160
- };
161
-
162
- return (item: FwSidebarItemProps): [boolean, () => void] => [
163
- hasItem(item) || false,
164
- () => {
165
- if (hasItem(item)) {
166
- deleteItem(item);
167
- } else {
168
- addItem(item);
169
- }
170
- }
171
- ]
172
- }
173
-
174
- function useOnePathBehaviour(initialActiveItems: any[]) {
175
- const [weakSet] = useState(() => new Set<string>(initialActiveItems.map((item) => stringify(item))));
176
- const [lastLevel, setLastLevel] = useState<false | number | undefined>(false);
177
- const [, setForceUpdate] = useState(0);
178
-
179
- const forceUpdate = () => setForceUpdate((prev) => prev + 1);
180
-
181
- const addItem = (item: FwSidebarItemProps) => {
182
- weakSet.add(stringify(item));
183
- forceUpdate();
184
- };
185
-
186
- const deleteItem = (item: FwSidebarItemProps) => {
187
- weakSet.delete(stringify(item));
188
- forceUpdate();
189
- };
190
-
191
- const hasItem = (item: FwSidebarItemProps) => {
192
- return weakSet.has(stringify(item));
193
- };
194
-
195
- const clear = () => {
196
- weakSet.clear();
197
- forceUpdate();
198
- };
199
-
200
- return (item: FwSidebarItemProps): [boolean, () => void] => [
201
- hasItem(item),
202
- () => {
203
- setLastLevel(item.level)
204
- if (hasItem(item) && item.level == 0) {
205
- setLastLevel(false)
206
- clear()
207
- return
208
- }
209
-
210
- if (hasItem(item)) {
211
- setLastLevel(false)
212
- deleteItem(item);
213
- return
214
- }
215
-
216
-
217
- if (((item.level || 0) > (lastLevel || 0)) || lastLevel == false) {
218
- addItem(item)
219
- } else {
220
- const v = getLastValue(weakSet)
221
- deleteItem(JSON.parse(v))
222
- addItem(item)
223
- }
224
- }
225
- ]
226
- }
227
-
228
- function scrollToDataSlug(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>, item: FwSidebarItemProps) {
229
- event.preventDefault()
230
-
231
- // TODO: find another solution because data-slug is added by 'atlas'
232
-
233
- const dataSlug = document.querySelector(`[data-slug="${item.href}"]`)
234
-
235
- if (dataSlug) {
236
- dataSlug.scrollIntoView({block: "start", inline: "nearest"})
237
- }
238
- }
239
-
240
-
@@ -1,127 +0,0 @@
1
- import React, {} from "react"
2
-
3
- import {Badge} from "@xyd-js/components/writer"
4
- import {UISidebar} from "@xyd-js/ui";
5
-
6
- import {useGroup} from "./sidebar-group";
7
-
8
- // TODO: custom hooks for active onclick handler etc?
9
-
10
- export interface FwSidebarGroupProps {
11
- group: string
12
-
13
- items: FwSidebarItemProps[]
14
- }
15
-
16
- export function FwSidebarItemGroup(props: FwSidebarGroupProps) {
17
- return <>
18
- <UISidebar.ItemHeader>
19
- {props.group}
20
- </UISidebar.ItemHeader>
21
-
22
- {props.items.map((item, index) => <FwSidebarItem
23
- key={index + item.href}
24
- title={item.title}
25
- href={item.href}
26
- items={item.items}
27
- active={item.active}
28
- level={0}
29
- />)}
30
- </>
31
- }
32
-
33
- export interface FwSidebarItemProps {
34
- title: string | {
35
- code: string
36
- }
37
-
38
- href: string
39
-
40
- items?: FwSidebarItemProps[]
41
-
42
- active?: boolean
43
-
44
- // internal
45
- readonly level?: number
46
- // internal
47
- }
48
-
49
- // TODO: move to @xyd-js/components/content
50
- const components = {
51
- Frontmatter: {
52
- // TODO: css
53
- Title: ({children}) => <div style={{
54
- display: "flex",
55
- alignItems: "center",
56
- justifyContent: "space-between",
57
- width: "100%",
58
- gap: "10px",
59
- }}>
60
- {children}
61
- </div>,
62
- },
63
- Badge: ({children}) => <Badge>
64
- {children}
65
- </Badge>
66
- }
67
-
68
- function mdxExport(code: string, components: any) {
69
- const scope = {
70
- Fragment: React.Fragment,
71
- jsxs: React.createElement,
72
- jsx: React.createElement,
73
- jsxDEV: React.createElement,
74
- _jsxs: React.createElement,
75
- _jsx: React.createElement,
76
- ...components
77
- }
78
- const fn = new Function(...Object.keys(scope), `return ${code}`)
79
- return fn(...Object.values(scope))
80
- }
81
-
82
- function FwSidebarItem(props: FwSidebarItemProps) {
83
- const {active, onClick} = useGroup()
84
- const [isActive, setActive] = active(props)
85
-
86
- let Title: any
87
-
88
- if (typeof props.title === "object" && "code" in props.title) {
89
- const code = props.title.code
90
-
91
- Title = () => mdxExport(
92
- // TODO: in the future better mechanism + support props + better components (provider?) - similar to codehik
93
- code.replace("() => ", ""),
94
- components
95
- )
96
- } else {
97
- Title = () => props.title
98
- }
99
-
100
- return <UISidebar.Item
101
- button={!!props.items?.length}
102
- href={props.href}
103
- active={isActive}
104
- onClick={() => {
105
- setActive()
106
- }}
107
- >
108
- <Title/>
109
-
110
- {
111
- props.items?.length && <UISidebar.SubTree isOpen={isActive}>
112
- <>
113
- {
114
- props.items?.map((item, index) => <FwSidebarItem
115
- key={index + item.href}
116
- title={item.title}
117
- href={item.href}
118
- items={item.items}
119
- active={active(item)[0]}
120
- level={(props.level || 0) + 1}
121
- />)
122
- }
123
- </>
124
- </UISidebar.SubTree>
125
- }
126
- </UISidebar.Item>
127
- }
@@ -1,78 +0,0 @@
1
- import React, {createContext, useContext} from "react";
2
-
3
- import {Settings} from "@xyd-js/core";
4
- import type {ITOC, IBreadcrumb, INavLinks} from "@xyd-js/ui";
5
-
6
- import {FwSidebarGroupProps} from "../components/sidebar";
7
-
8
- export interface IFramework {
9
- settings: Settings
10
-
11
- sidebarGroups: FwSidebarGroupProps[]
12
-
13
- toc?: ITOC[]
14
-
15
- breadcrumbs?: IBreadcrumb[]
16
-
17
- navlinks?: INavLinks
18
- }
19
-
20
- // TODO: page context + app context?
21
- const framework: IFramework = {
22
- settings: {},
23
- sidebarGroups: []
24
- }
25
- const FrameworkContext = createContext<IFramework>(framework)
26
-
27
- export interface FrameworkProps {
28
- children: React.ReactNode
29
-
30
- settings: Settings,
31
- sidebarGroups: FwSidebarGroupProps[],
32
- toc?: ITOC[],
33
- breadcrumbs?: IBreadcrumb[],
34
- navlinks?: INavLinks
35
- }
36
-
37
- export function Framework(props: FrameworkProps) {
38
- return <FrameworkContext.Provider value={{
39
- settings: props.settings,
40
- sidebarGroups: props.sidebarGroups,
41
- toc: props.toc,
42
- breadcrumbs: props.breadcrumbs,
43
- navlinks: props.navlinks,
44
- }}>
45
- {props.children}
46
- </FrameworkContext.Provider>
47
- }
48
-
49
-
50
- export function useSidebarGroups() {
51
- const ctx = useContext(FrameworkContext)
52
-
53
- return ctx.sidebarGroups
54
- }
55
-
56
- export function useSettings() {
57
- const ctx = useContext(FrameworkContext)
58
-
59
- return ctx.settings
60
- }
61
-
62
- export function useToC() {
63
- const ctx = useContext(FrameworkContext)
64
-
65
- return ctx.toc
66
- }
67
-
68
- export function useBreadcrumbs() {
69
- const ctx = useContext(FrameworkContext)
70
-
71
- return ctx.breadcrumbs
72
- }
73
-
74
- export function useNavLinks() {
75
- const ctx = useContext(FrameworkContext)
76
-
77
- return ctx.navlinks
78
- }
@@ -1,2 +0,0 @@
1
- export * from "./framework"
2
-
@@ -1,6 +0,0 @@
1
- import {createContext} from 'react';
2
-
3
- export const UIContext = createContext({
4
- href: '',
5
- setHref: (v: any) => {}
6
- });
@@ -1,3 +0,0 @@
1
- export {
2
- useMatchedSubNav
3
- } from "./useMatchedNav";
@@ -1,29 +0,0 @@
1
- import {useLocation} from "react-router";
2
-
3
- import {useSettings} from "../contexts";
4
-
5
- import {manualHydration} from "../utils/manualHydration";
6
-
7
- function normalizeHref(href: string) {
8
- if (href.startsWith("/")) {
9
- return href
10
- }
11
-
12
- return `/${href}`
13
- }
14
-
15
- // TODO: better data structures
16
- export function useMatchedSubNav() {
17
- const settings = useSettings()
18
- const location = useLocation()
19
-
20
- const matchedSubnav = settings.structure?.header
21
- ?.filter(item => item.sub)
22
- ?.find(item => normalizeHref(location.pathname).startsWith(normalizeHref(item.sub?.match || "")))
23
-
24
- if (!matchedSubnav) {
25
- return null
26
- }
27
-
28
- return matchedSubnav.sub || null
29
- }
@@ -1,12 +0,0 @@
1
- export * from "./components"
2
-
3
- export {Framework} from "./contexts"
4
- export type {FrameworkProps} from "./contexts"
5
-
6
- export {
7
- useMatchedSubNav
8
- } from "./hooks"
9
-
10
- export type {
11
- FwSidebarGroupProps
12
- } from "./components/sidebar/sidebar"
@@ -1,25 +0,0 @@
1
- import React, {ReactElement} from "react";
2
-
3
- export function manualHydration(obj: any, key = 0): ReactElement<any, string | React.JSXElementConstructor<any>> {
4
- if (typeof obj !== 'object' || obj === null) {
5
- return React.createElement(React.Fragment, {key});
6
- }
7
-
8
- const {type, props} = obj || {};
9
- if (typeof type !== 'string' && typeof type !== 'function') {
10
- return React.createElement(React.Fragment, {key});
11
- }
12
-
13
- let children: ReactElement<any, string | React.JSXElementConstructor<any>>[] = [];
14
- if (props?.children) {
15
- if (Array.isArray(props.children)) {
16
- children = props.children.map((child: any, i) => manualHydration(child, key + i)) || [];
17
- } else {
18
- children = [manualHydration(props.children, key)];
19
- }
20
- }
21
-
22
- const elementProps = {...props, children, key};
23
-
24
- return React.createElement(type, elementProps);
25
- }
@@ -1,19 +0,0 @@
1
- import {createContext, useContext} from "react";
2
-
3
- import type {ITheme} from "@xyd-js/framework";
4
-
5
- const theme = createContext<ITheme<any> | null>(null)
6
-
7
- const Provider = theme.Provider
8
-
9
- // TODO: finish theme context
10
-
11
- export function withTheme(Component) {
12
- return <Provider value={null}>
13
- <Component/>
14
- </Provider>
15
- }
16
-
17
- export function useTheme<T>(): ITheme<any> | null {
18
- return useContext(theme)
19
- }
File without changes
@@ -1,5 +0,0 @@
1
- module.exports = {
2
- plugins: {
3
- autoprefixer: {},
4
- },
5
- }
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export type * from "./types";
package/src/types.ts DELETED
@@ -1,5 +0,0 @@
1
- export interface ITheme<T> {
2
- children: JSX.Element | JSX.Element[]
3
-
4
- themeSettings?: T
5
- }
package/tsconfig.json DELETED
@@ -1,45 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "module": "esnext",
4
- "esModuleInterop": true,
5
- "moduleResolution": "bundler",
6
- "target": "ES6",
7
- "compilerOptions": {
8
- "baseUrl": ".",
9
- "paths": {
10
- "@/components/*": ["@/components/*"],
11
- "@/lib/utils/*": ["@/lib/utils/*"],
12
- "@/components/ui/*": ["@/components/ui/*"],
13
- "@/components/magicui/*": ["@/components/magicui/*"]
14
- }
15
- },
16
- "lib": [
17
- "dom",
18
- "dom.iterable",
19
- "esnext"
20
- ],
21
- "allowJs": true,
22
- "skipLibCheck": true,
23
- "strict": false,
24
- "noEmit": true,
25
- "incremental": false,
26
- "resolveJsonModule": true,
27
- "isolatedModules": true,
28
- "jsx": "preserve",
29
- "plugins": [
30
- {
31
- "name": "next"
32
- }
33
- ],
34
- "strictNullChecks": true
35
- },
36
- "include": [
37
- "next-env.d.ts",
38
- "**/*.ts",
39
- "**/*.tsx",
40
- ".next/types/**/*.ts"
41
- ],
42
- "exclude": [
43
- "node_modules"
44
- ]
45
- }
package/tsup.config.ts DELETED
@@ -1,28 +0,0 @@
1
- import {defineConfig} from 'tsup';
2
-
3
- export default defineConfig({
4
- entry: {
5
- index: 'src/index.ts',
6
- react: 'packages/react/index.ts',
7
- hydration: 'packages/hydration/index.ts',
8
- },
9
- format: ['esm', 'cjs'], // Output both ESM and CJS formats
10
- target: 'node16', // Ensure compatibility with Node.js 16
11
- dts: {
12
- entry: {
13
- index: 'src/index.ts',
14
- react: 'packages/react/index.ts',
15
- hydration: 'packages/hydration/index.ts',
16
- },
17
- resolve: true, // Resolve external types
18
- },
19
- splitting: false, // Disable code splitting
20
- sourcemap: true, // Generate source maps
21
- clean: true, // Clean the output directory before each build
22
- esbuildOptions: (options) => {
23
- options.platform = 'node'; // Ensure the platform is set to Node.js
24
- options.external = ['node:fs/promises', 'react-router']; // Mark 'node:fs/promises' as external
25
- options.loader = {'.js': 'jsx'}; // Ensure proper handling of .js files
26
- },
27
- ignoreWatch: ['node_modules', 'dist', '.git', 'build'] // Exclude unnecessary directories
28
- });