@d1vij/jassm 0.1.19-beta.1 → 0.1.20

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.
package/README.md CHANGED
@@ -1,20 +1,38 @@
1
1
  # Just another static site maker
2
2
 
3
- Create content driven sites using mdx (markdown + react) with added support typescript based autocompletion for the pages.
3
+ Create content-driven sites using MDX (Markdown + React) with TypeScript-powered
4
+ autocompletion and route awareness.
4
5
 
5
- ## What is this ??
6
+ ---
7
+
8
+ ## What is this?
9
+
10
+ JASSM is a lightweight abstraction layer over [mdx-js](https://mdxjs.com/) and
11
+ its Vite plugin for building route-aware MDX registries.
6
12
 
7
- JASSM is a simple abstraction layer over [mdx-js](https://mdxjs.com/) and its vite plugin for creating a route/file aware loader for mdx file.
13
+ It creates a single source of truth for MDX pages and exposes:
8
14
 
9
- Each page is configured at a single source of truth (registry) and thereby provides typesafe access throughout.
15
+ - type-safe route keys
16
+ - lazy React components
17
+ - metadata registries
18
+ - raw module exports
10
19
 
11
- (ps the DX is similar to that of TanstackRouter or Elysia)
20
+ The developer experience is similar to TanStack Router or Elysia where
21
+ route definitions produce strongly typed APIs.
22
+
23
+ ---
12
24
 
13
25
  ## Usage
14
26
 
15
- 0. Initialize a react app using vite
27
+ ## 0. Initialize a React app using Vite
28
+
29
+ ```bash
30
+ npm create vite@latest
31
+ ```
32
+
33
+ ---
16
34
 
17
- 1. Install jassm
35
+ ## 1. Install JASSM
18
36
 
19
37
  ```bash
20
38
  npm install @d1vij/jassm
@@ -24,7 +42,9 @@ pnpm add @d1vij/jassm
24
42
  bun add @d1vij/jassm
25
43
  ```
26
44
 
27
- 2. Setup vite plugin in vite config
45
+ ---
46
+
47
+ ## 2. Setup the Vite plugin
28
48
 
29
49
  ```ts
30
50
  import { defineConfig } from "vite";
@@ -33,128 +53,248 @@ import react from "@vitejs/plugin-react";
33
53
  import jassm from "@d1vij/jassm/plugin";
34
54
 
35
55
  export default defineConfig({
36
- plugins: [
37
- jassm(), // Put jassm plugin before react's plugin
38
- react(),
39
- ],
56
+ plugins: [
57
+ jassm(), // must come before react plugin
58
+ react(),
59
+ ],
40
60
  });
41
61
  ```
42
62
 
43
- 3. Create a folder with `.mdx` assets
63
+ ---
44
64
 
45
- ```bash
46
- mkdir assets/mdx
47
- cd assets/mdx
48
- echo "# This is a Heading" > sample.mdx
65
+ ## 3. Create a folder with `.mdx` assets
66
+
67
+ Example project structure:
68
+
69
+ ```text
70
+ src/
71
+ assets/
72
+ mdx/
73
+ sample.mdx
74
+ sample.meta.ts
75
+ ```
76
+
77
+ Example MDX file:
78
+
79
+ ```mdx
80
+ # Hello world
81
+
82
+ This is my first mdx page.
49
83
  ```
50
84
 
51
- 4. Setup a mdx registry
85
+ Example metadata file:
52
86
 
53
87
  ```ts
54
- // src/Registry.tsx
88
+ export default {
89
+ title: "Sample Page",
90
+ };
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 4. Create an MDX registry
96
+
97
+ The registry maps `filesystem MDX files -> route keys`.
98
+
99
+ ```ts
100
+ // src/content/registry.ts
55
101
 
56
102
  import { Registry } from "@d1vij/jassm";
57
103
 
58
104
  export const registry = new Registry({
59
- modules: import.meta.glob("/src/assets/mdx/**/*.mdx"),
60
- source: "/src/assets/mdx",
61
- mountOn: "/root",
62
- records: {
63
- "/sample": "/example.mdx",
64
- },
105
+ modulesGlob: import.meta.glob("/src/assets/mdx/**/*.mdx"),
106
+
107
+ metadataGlob: import.meta.glob("/src/assets/mdx/**/*.meta.ts", {
108
+ eager: true,
109
+ import: "default",
110
+ }),
111
+
112
+ root: "/src/assets/mdx",
113
+
114
+ // virtual mount point for routes
115
+ virtual: "/blog",
65
116
  });
66
117
  ```
67
118
 
68
- 5. Setup style classes
119
+ Given the file:
120
+
121
+ ```text
122
+ /src/assets/mdx/sample.mdx
123
+ ```
124
+
125
+ The generated route becomes:
126
+
127
+ ```text
128
+ /blog/sample
129
+ ```
130
+
131
+ All routes are available in:
132
+
133
+ ```ts
134
+ registry.keys;
135
+ ```
136
+
137
+ ---
138
+
139
+ ## 5. Setup style classes
140
+
141
+ JASSM maps MDX elements to CSS classes using a StyleClassesMap.
142
+
143
+ ## Using global CSS
69
144
 
70
145
  ```ts
71
146
  // src/stylesmap.ts
72
- import type { StyleClassesMap } from "jassm";
73
147
 
74
- // import stylesheet
75
- import "myStyles.css";
148
+ import type { StyleClassesMap } from "@d1vij/jassm";
149
+
150
+ import "./styles.css";
76
151
 
77
152
  export const stylesmap: StyleClassesMap = {
78
- header: "myHeader",
79
- paragraph: "pee",
153
+ header: "myHeader",
154
+ paragraph: "myParagraph",
80
155
  };
81
156
  ```
82
157
 
83
- Or using css modules
158
+ ---
159
+
160
+ ### Using CSS modules
84
161
 
85
162
  ```ts
86
- import styles from "myStyles.module.css";
163
+ import styles from "./styles.module.css";
87
164
 
88
- import type { StyleClassesMap } from "jassm";
165
+ import type { StyleClassesMap } from "@d1vij/jassm";
89
166
 
90
167
  export const stylesmap: StyleClassesMap = {
91
- header: styles.myHeader,
92
- paragraph: styles.pee,
168
+ header: styles.header,
169
+ paragraph: styles.paragraph,
93
170
  };
94
171
  ```
95
172
 
96
- 6. Using the registry in any other component
173
+ ---
97
174
 
98
- ```tsx
99
- // importing defined registry
100
- import { registry } from "./Registry";
175
+ ## 6. Using the registry in a component
101
176
 
102
- // importing styles map
103
- import {stylesmap} from "./stylesmap";
177
+ ```tsx
178
+ import { registry } from "./content/registry";
179
+ import { stylesmap } from "./stylesmap";
104
180
 
105
- import {MDXFromComponent} from "jassm";
181
+ import { MDXFromComponent } from "@d1vij/jassm";
106
182
 
107
- import {use} from "react";
183
+ import { use } from "react";
108
184
 
109
185
  type ExportType = {
110
186
  meta: {
111
- title: string
112
- }
187
+ title: string;
188
+ };
113
189
  };
114
190
 
115
191
  export default function Content() {
116
- const Component = registry.getComponent("/root/sample");
117
- const exports = use(registry.getExport<ExportType>("/root/sample")) // consuming the 'import' promise using use
192
+ const Component = registry.getComponent("/blog/sample");
193
+
194
+ const exports = use(registry.getExport<ExportType>("/blog/sample"));
195
+
118
196
  return (
119
197
  <div>
120
- {exports.meta.title}
198
+ <h1>{exports.meta.title}</h1>
199
+
121
200
  <MDXFromComponent
122
201
  SourceComponent={Component}
123
202
  styles={stylesmap}
124
-
125
- {/* Optional fallback component for suspense*/}
126
- fallback={<div>Loading</div>}
203
+ fallback={<div>Loading...</div>}
127
204
  />
128
- <div/>
129
- )
205
+ </div>
206
+ );
130
207
  }
131
208
  ```
132
209
 
133
- Using `MDXSourceComponent` automatically sets up the required enclosing StyleContext and Suspense component.
210
+ `MDXFromComponent` automatically provides:
211
+
212
+ - `StyleContext`
213
+ - `Suspense`
214
+ - MDX element mappings
215
+
216
+ ---
134
217
 
135
- The setup can also be done manually as follows
218
+ ## Manual setup (advanced)
219
+
220
+ You can manually compose the rendering pipeline.
136
221
 
137
222
  ```tsx
138
223
  import { StyleContext, Elements } from "@d1vij/jassm";
139
224
 
140
- import { registry } from "./Registry";
225
+ import { registry } from "./content/registry";
141
226
  import { stylesmap } from "./stylesmap";
142
227
 
143
228
  import { Suspense } from "react";
144
229
 
145
- export default function MyLoader() {
146
- const Component = registry["/root/sample"];
147
-
148
- return (
149
- <div>
150
- <StyleContext styles={stylesmap}>
151
- <Suspense>
152
- <Component components={Elements} />
153
- </Suspense>
154
- </StyleContext>
155
- </div>
156
- );
230
+ export default function Loader() {
231
+ const Component = registry.getComponent("/blog/sample");
232
+
233
+ return (
234
+ <StyleContext styles={stylesmap}>
235
+ <Suspense fallback={<div>Loading</div>}>
236
+ <Component components={Elements} />
237
+ </Suspense>
238
+ </StyleContext>
239
+ );
157
240
  }
158
241
  ```
159
242
 
160
243
  ---
244
+
245
+ ## Metadata access
246
+
247
+ Metadata files (`*.meta.ts`) are eagerly loaded and accessible through the registry.
248
+
249
+ ```ts
250
+ const metadata = registry.getMetadata("/blog/sample");
251
+
252
+ console.log(metadata.title);
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Registry utilities
258
+
259
+ The registry exposes:
260
+
261
+ ```ts
262
+ registry.keys; // all route keys
263
+ registry.components; // lazy components
264
+ registry.exports; // raw module exports
265
+ registry.metadata; // metadata registry
266
+ ```
267
+
268
+ It also provides a **consistency checker**:
269
+
270
+ ```ts
271
+ registry.diffKeys();
272
+ ```
273
+
274
+ This verifies that:
275
+
276
+ - components
277
+ - exports
278
+ - metadata
279
+
280
+ all share the same route keys.
281
+
282
+ ---
283
+
284
+ ## Multiple content directories
285
+
286
+ Multiple registries can be merged:
287
+
288
+ ```ts
289
+ import { CoalescedRegistry } from "@d1vij/jassm";
290
+
291
+ const registry = new CoalescedRegistry(
292
+ blogRegistry,
293
+ docsRegistry,
294
+ guidesRegistry,
295
+ );
296
+ ```
297
+
298
+ This produces a single unified registry.
299
+
300
+ ---
package/dist/index.d.ts CHANGED
@@ -43,7 +43,7 @@ type MustNotEndWithSlash<T extends string> = T extends `${string}/` ? never : T;
43
43
  * - starts with `/`
44
44
  * - does not end with `/`
45
45
  */
46
- type PathCheck<T extends string> = MustStartWithSlash<T> & MustNotEndWithSlash<T>;
46
+ type PathCheck<T extends string> = T extends "" | "/" ? T : MustStartWithSlash<T> & MustNotEndWithSlash<T>;
47
47
  /**
48
48
  * Type returned by `import.meta.glob`
49
49
  */
@@ -56,7 +56,10 @@ type GlobResult<T> = Record<string, T>;
56
56
  * Removes `.mdx` extension from a path
57
57
  */
58
58
  type StripExtension<T extends string> = T extends `${infer Rest}.mdx` ? Rest : T;
59
- type ResolveEmptyVirtual<Virtual extends string> = Virtual extends "/" ? "" : Virtual;
59
+ type JoinVirtual<
60
+ V extends string,
61
+ P extends string
62
+ > = V extends "" ? P : `${V}/${P}`;
60
63
  /**
61
64
  * Derives the route keys produced by the registry and
62
65
  * replace filesystem root with a virtual route prefix
@@ -73,7 +76,7 @@ type RouteKey<
73
76
  Modules extends Record<string, unknown>,
74
77
  Root extends string,
75
78
  Virtual extends string
76
- > = keyof { [K in keyof Modules as K extends `${string}${Root}/${infer Rest}.mdx` ? `${ResolveEmptyVirtual<Virtual>}/${Rest}` : never] : true } & string;
79
+ > = Extract<keyof Modules, `${Root}/${string}.mdx`> extends `${Root}/${infer Rest}.mdx` ? JoinVirtual<Virtual, Rest> : never;
77
80
  /**
78
81
  * Options passed to {@link generateRegistry}
79
82
  */
@@ -98,7 +101,7 @@ type RegistryOptions<
98
101
  /**
99
102
  * Virtual route mount point
100
103
  */
101
- virtual: PathCheck<Virtual>;
104
+ virtual: Virtual;
102
105
  };
103
106
  /**
104
107
  * Internal function used by {@link Registry}.
@@ -175,15 +178,15 @@ declare abstract class AbstractRegistry<
175
178
  /**
176
179
  * Retrieve a React component by route key
177
180
  */
178
- getComponent(key: string): Components[keyof Components];
181
+ getComponent(key: keyof Components): Components[keyof Components];
179
182
  /**
180
183
  * Retrieve raw module exports for a route
181
184
  */
182
- getExport(key: string): Exports[keyof Exports];
185
+ getExport(key: keyof Exports): Exports[keyof Exports];
183
186
  /**
184
187
  * Retrieve metadata for a route
185
188
  */
186
- getMetadata(key: string): Metadata[keyof Metadata];
189
+ getMetadata(key: keyof Metadata): Metadata[keyof Metadata];
187
190
  }
188
191
  /**
189
192
  * Primary registry implementation.
@@ -193,7 +196,7 @@ declare abstract class AbstractRegistry<
193
196
  */
194
197
  declare class Registry<
195
198
  MetaType,
196
- Modules extends Record<`${Root}/${string}.mdx`, WrappedUnknownPromise>,
199
+ Modules extends Record<string, WrappedUnknownPromise>,
197
200
  Root extends string,
198
201
  Virtual extends string
199
202
  > extends AbstractRegistry<RouteKey<Modules, Root, Virtual>, Record<RouteKey<Modules, Root, Virtual>, React.LazyExoticComponent<React.ComponentType>>, Record<RouteKey<Modules, Root, Virtual>, unknown>, Record<RouteKey<Modules, Root, Virtual>, MetaType>> {
package/dist/index.js CHANGED
@@ -1,661 +1,21 @@
1
- // src/components/Elements/Anchor.tsx
2
- import { cn } from "@d1vij/shit-i-always-use";
3
- import { useMemo, useState } from "react";
4
-
5
- // src/lib/StyleContext.ts
6
- import { createContext, useContext } from "react";
7
- var StyleClassesList = [
8
- "header",
9
- "header_button",
10
- "header_1",
11
- "header_2",
12
- "header_3",
13
- "header_4",
14
- "header_5",
15
- "header_6",
16
- "header_icon",
17
- "anchor",
18
- "button",
19
- "bold",
20
- "italic",
21
- "span",
22
- "striked",
23
- "paragraph",
24
- "code",
25
- "preformatted",
26
- "blockquote",
27
- "horizontal_line",
28
- "image",
29
- "list",
30
- "unordered_list",
31
- "ordered_list",
32
- "list_item",
33
- "table",
34
- "table_head",
35
- "table_head_cell",
36
- "table_body",
37
- "table_row",
38
- "table_data",
39
- "table_container",
40
- "table_action_buttons_details",
41
- "table_action_buttons_summary",
42
- "table_action_button",
43
- "table_action_button_html",
44
- "table_action_button_csv",
45
- "table_action_button_json",
46
- "table_action_button_markdown"
47
- ];
48
- var StyleContext = createContext(null);
49
- function useStyles() {
50
- const ctx = useContext(StyleContext);
51
- if (ctx === null)
52
- throw new Error("No stylesmap found at any parent level. Either you forgot to pass the stylesmap to component loader or didnt wrap your component in StyleContext");
53
- return ctx;
54
- }
55
-
56
- // src/components/Elements/Anchor.tsx
57
- import { jsx } from "react/jsx-runtime";
58
- function Anchor(props) {
59
- const selfOrigin = useMemo(() => new URL(window.location.href).origin.toString(), []);
60
- const styles = useStyles();
61
- const [target] = useState(() => {
62
- const href = props.href;
63
- if (href?.match(/^#.*/)) {
64
- return "_self";
65
- }
66
- const targetOrigin = new URL(props.href ?? "").origin.toString();
67
- return targetOrigin === selfOrigin ? "_self" : "_blank";
68
- });
69
- return /* @__PURE__ */ jsx("a", {
70
- className: cn(styles.anchor),
71
- target,
72
- href: props.href,
73
- children: props.children
74
- });
75
- }
76
-
77
- // src/components/Elements/BlockQuote.tsx
78
- import { cn as cn2 } from "@d1vij/shit-i-always-use";
79
- import { jsx as jsx2 } from "react/jsx-runtime";
80
- function BlockQuote(props) {
81
- const styles = useStyles();
82
- return /* @__PURE__ */ jsx2("blockquote", {
83
- className: cn2(styles.blockquote),
84
- children: props.children
85
- });
86
- }
87
-
88
- // src/components/Elements/Bold.tsx
89
- import { cn as cn3 } from "@d1vij/shit-i-always-use";
90
- import { jsx as jsx3 } from "react/jsx-runtime";
91
- function Bold(props) {
92
- const styles = useStyles();
93
- return /* @__PURE__ */ jsx3("span", {
94
- className: cn3(styles.bold),
95
- children: props.children
96
- });
97
- }
98
-
99
- // src/components/Elements/Code.tsx
100
- import { cn as cn4 } from "@d1vij/shit-i-always-use";
101
- import { jsx as jsx4 } from "react/jsx-runtime";
102
- function Code(props) {
103
- const styles = useStyles();
104
- const lang = /language-(\w+)/.exec(props.className || "")?.[1];
105
- return /* @__PURE__ */ jsx4("code", {
106
- className: cn4(styles.code, lang && `language-${lang}`),
107
- children: props.children
108
- });
109
- }
110
-
111
- // src/components/Elements/Heading.tsx
112
- import { cn as cn5, useClipboardText } from "@d1vij/shit-i-always-use";
113
- import { useEffect, useRef, useState as useState2 } from "react";
114
- import { jsx as jsx5 } from "react/jsx-runtime";
115
- function Header(props) {
116
- const styles = useStyles();
117
- const headerRef = useRef(null);
118
- const [id, setId] = useState2("");
119
- const { copy } = useClipboardText();
120
- async function handleClick() {
121
- const url = new URL(`/#${id}`, window.location.origin).toString();
122
- console.log("clicked");
123
- await copy(url);
124
- }
125
- useEffect(() => {
126
- if (!headerRef.current)
127
- return;
128
- const raw = headerRef.current.textContent ?? "";
129
- const safe = raw.toLowerCase().replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-").slice(0, 30);
130
- setId(safe);
131
- }, []);
132
- return /* @__PURE__ */ jsx5("h1", {
133
- className: cn5(styles.header, styles[`header_${props.level}`]),
134
- children: /* @__PURE__ */ jsx5("button", {
135
- onClick: () => void handleClick(),
136
- ref: headerRef,
137
- id,
138
- className: cn5(styles.header_button),
139
- type: "button",
140
- children: props.children
141
- })
142
- });
143
- }
144
-
145
- // src/components/Elements/HorizontalLine.tsx
146
- import { cn as cn6 } from "@d1vij/shit-i-always-use";
147
- import { jsx as jsx6 } from "react/jsx-runtime";
148
- function HorizontalLine(_) {
149
- const styles = useStyles();
150
- return /* @__PURE__ */ jsx6("hr", {
151
- className: cn6(styles.horizontal_line)
152
- });
153
- }
154
-
155
- // src/components/Elements/Image.tsx
156
- import { cn as cn7 } from "@d1vij/shit-i-always-use";
157
- import { jsx as jsx7 } from "react/jsx-runtime";
158
- function Image(props) {
159
- const styles = useStyles();
160
- return /* @__PURE__ */ jsx7("img", {
161
- className: cn7(styles.image),
162
- alt: props.alt,
163
- title: props.title,
164
- src: props.src
165
- });
166
- }
167
-
168
- // src/components/Elements/Italics.tsx
169
- import { cn as cn8 } from "@d1vij/shit-i-always-use";
170
- import { jsx as jsx8 } from "react/jsx-runtime";
171
- function Italics(props) {
172
- const styles = useStyles();
173
- return /* @__PURE__ */ jsx8("span", {
174
- className: cn8(styles.italic),
175
- children: props.children
176
- });
177
- }
178
-
179
- // src/components/Elements/List.tsx
180
- import { cn as cn9 } from "@d1vij/shit-i-always-use";
181
- import { jsx as jsx9 } from "react/jsx-runtime";
182
- function List(props) {
183
- const styles = useStyles();
184
- const L = props.type === "ordered" ? "ol" : "ul";
185
- return /* @__PURE__ */ jsx9(L, {
186
- className: cn9(styles.list, props.type === "ordered" && styles.ordered_list, props.type === "unordered" && styles.unordered_list),
187
- children: props.children
188
- });
189
- }
190
- function ListItem(props) {
191
- const styles = useStyles();
192
- return /* @__PURE__ */ jsx9("li", {
193
- className: cn9(styles.list_item),
194
- children: props.children
195
- });
196
- }
197
-
198
- // src/components/Elements/Paragraph.tsx
199
- import { cn as cn10 } from "@d1vij/shit-i-always-use";
200
- import { jsx as jsx10 } from "react/jsx-runtime";
201
- function Paragraph(props) {
202
- const styles = useStyles();
203
- return /* @__PURE__ */ jsx10("p", {
204
- className: cn10(styles.paragraph),
205
- children: props.children
206
- });
207
- }
208
-
209
- // src/components/Elements/Preformatted.tsx
210
- import { cn as cn11 } from "@d1vij/shit-i-always-use";
211
- import { jsx as jsx11 } from "react/jsx-runtime";
212
- function Preformatted(props) {
213
- const styles = useStyles();
214
- return /* @__PURE__ */ jsx11("pre", {
215
- className: cn11(styles.preformatted),
216
- children: props.children
217
- });
218
- }
219
-
220
- // src/components/Elements/Striked.tsx
221
- import { cn as cn12 } from "@d1vij/shit-i-always-use";
222
- import { jsx as jsx12 } from "react/jsx-runtime";
223
- function Striked(props) {
224
- const styles = useStyles();
225
- return /* @__PURE__ */ jsx12("span", {
226
- className: cn12(styles.striked),
227
- children: props.children
228
- });
229
- }
230
-
231
- // src/components/Elements/Table.tsx
232
- import {
233
- cn as cn13,
234
- useClipboardText as useClipboardText2
235
- } from "@d1vij/shit-i-always-use";
236
- import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
237
- import { jsx as jsx13, jsxs } from "react/jsx-runtime";
238
- function TableActionButton({
239
- label,
240
- onClick,
241
- setOpen
242
- }) {
243
- const styles = useStyles();
244
- function handleClick(e) {
245
- setOpen(false);
246
- onClick(e);
247
- }
248
- return /* @__PURE__ */ jsx13("button", {
249
- onClick: handleClick,
250
- className: cn13(styles.table_action_button),
251
- type: "button",
252
- children: label
253
- });
254
- }
255
- function getTableAsJson(elm) {
256
- const headings = [];
257
- const theadElms = elm.querySelectorAll("thead > tr > th");
258
- theadElms.forEach((th) => {
259
- headings.push(th.innerText.trim());
260
- });
261
- const rows = [];
262
- const rowElms = elm.querySelectorAll("tbody > tr");
263
- rowElms.forEach((tr) => {
264
- const row = [];
265
- tr.querySelectorAll("td").forEach((td, idx) => {
266
- row.push({
267
- column: headings[idx] ?? idx.toString(),
268
- content: td.innerText.trim()
269
- });
270
- });
271
- rows.push(row);
272
- });
273
- return {
274
- meta: {
275
- columns: headings.length,
276
- rows: rowElms.length
277
- },
278
- headings,
279
- rows
280
- };
281
- }
282
- function getTableJsonAsCsv(json) {
283
- const heading = json.headings.join(",");
284
- const rows = json.rows.map((row) => row.map((cell) => cell.content).join(",")).join(`
285
- `);
286
- return [heading, rows].join(`
287
- `);
288
- }
289
- function getTableJsonAsHtml(json) {
290
- const heading = json.headings.map((h) => `<th>${h}</th>`).join("");
291
- const rows = json.rows.map((row) => {
292
- const cells = row.map((c) => `<td>${c.content}</td>`).join("");
293
- return `<tr>${cells}</tr>`;
294
- });
295
- return [
296
- "<table>",
297
- "<thead>",
298
- `<tr>${heading}</tr>`,
299
- "</thead>",
300
- "<tbody>",
301
- ...rows,
302
- "</tbody>",
303
- "</table>"
304
- ].join(`
305
- `);
306
- }
307
- function getTableJsonAsMarkdown(json) {
308
- const heading = `|${json.headings.join("|")}|`;
309
- const separator = `|${json.headings.map(() => "-----").join("|")}|`;
310
- const rows = json.rows.map((row) => `|${row.map((cell) => cell.content).join("|")}|`);
311
- return [heading, separator, ...rows].join(`
312
- `);
313
- }
314
- function Table(props) {
315
- const styles = useStyles();
316
- const ref = useRef2(null);
317
- const detailsRef = useRef2(null);
318
- const [open, setOpen] = useState3(false);
319
- const { copy } = useClipboardText2();
320
- useEffect2(() => {
321
- const elm = detailsRef.current;
322
- if (!elm)
323
- return;
324
- function handleMouseLeave() {
325
- setOpen(false);
326
- }
327
- function handleMouseEnter() {
328
- setOpen(true);
329
- }
330
- elm.addEventListener("mouseenter", handleMouseEnter);
331
- elm.addEventListener("mouseleave", handleMouseLeave);
332
- return () => {
333
- elm.removeEventListener("mouseenter", handleMouseEnter);
334
- elm.removeEventListener("mouseleave", handleMouseLeave);
335
- };
336
- }, []);
337
- const copyAs = useCallback((format) => {
338
- return async () => {
339
- const elm = ref.current;
340
- if (!elm)
341
- return;
342
- const json = getTableAsJson(elm);
343
- let extractedText;
344
- switch (format) {
345
- case "html":
346
- extractedText = getTableJsonAsHtml(json);
347
- break;
348
- case "csv":
349
- extractedText = getTableJsonAsCsv(json);
350
- break;
351
- case "markdown":
352
- extractedText = getTableJsonAsMarkdown(json);
353
- break;
354
- case "json":
355
- extractedText = JSON.stringify(json, null, 4);
356
- break;
357
- default:
358
- return;
359
- }
360
- await copy(extractedText);
361
- };
362
- }, [copy]);
363
- return /* @__PURE__ */ jsxs("div", {
364
- className: cn13(styles.table_container),
365
- children: [
366
- /* @__PURE__ */ jsx13("table", {
367
- ref,
368
- className: cn13(styles.table),
369
- children: props.children
370
- }),
371
- /* @__PURE__ */ jsxs("details", {
372
- ref: detailsRef,
373
- className: cn13(styles.table_action_buttons_details),
374
- open,
375
- children: [
376
- /* @__PURE__ */ jsx13("summary", {
377
- className: cn13(styles.table_action_buttons_summary),
378
- children: "Copy"
379
- }),
380
- /* @__PURE__ */ jsx13(TableActionButton, {
381
- setOpen,
382
- label: "HTML",
383
- onClick: copyAs("html")
384
- }),
385
- /* @__PURE__ */ jsx13(TableActionButton, {
386
- setOpen,
387
- label: "CSV",
388
- onClick: copyAs("csv")
389
- }),
390
- /* @__PURE__ */ jsx13(TableActionButton, {
391
- setOpen,
392
- label: "Json",
393
- onClick: copyAs("json")
394
- }),
395
- /* @__PURE__ */ jsx13(TableActionButton, {
396
- setOpen,
397
- label: "Markdown",
398
- onClick: copyAs("markdown")
399
- })
400
- ]
401
- })
402
- ]
403
- });
404
- }
405
- function TableHead(props) {
406
- const styles = useStyles();
407
- return /* @__PURE__ */ jsx13("thead", {
408
- className: cn13(styles.table_head),
409
- children: props.children
410
- });
411
- }
412
- function TableBody(props) {
413
- const styles = useStyles();
414
- return /* @__PURE__ */ jsx13("tbody", {
415
- className: cn13(styles.table_body),
416
- children: props.children
417
- });
418
- }
419
- function TableRow(props) {
420
- const styles = useStyles();
421
- return /* @__PURE__ */ jsx13("tr", {
422
- className: cn13(styles.table_row),
423
- children: props.children
424
- });
425
- }
426
- function TableHeadCell(props) {
427
- const styles = useStyles();
428
- return /* @__PURE__ */ jsx13("th", {
429
- className: cn13(styles.table_head_cell),
430
- children: props.children
431
- });
432
- }
433
- function TableData(props) {
434
- const styles = useStyles();
435
- return /* @__PURE__ */ jsx13("td", {
436
- className: cn13(styles.table_data),
437
- children: props.children
438
- });
439
- }
440
-
441
- // src/components/Elements/Elements.tsx
442
- var BaseElementTags = [
443
- "h1",
444
- "h2",
445
- "h3",
446
- "h4",
447
- "h5",
448
- "h6",
449
- "a",
450
- "em",
451
- "del",
452
- "strong",
453
- "code",
454
- "blockquote",
455
- "pre",
456
- "p",
457
- "hr",
458
- "ol",
459
- "ul",
460
- "li",
461
- "img",
462
- "table",
463
- "thead",
464
- "tbody",
465
- "th",
466
- "tr",
467
- "td"
468
- ];
469
- var BaseElements = {
470
- h1: (props) => Header({ ...props, level: 1 }),
471
- h2: (props) => Header({ ...props, level: 2 }),
472
- h3: (props) => Header({ ...props, level: 3 }),
473
- h4: (props) => Header({ ...props, level: 4 }),
474
- h5: (props) => Header({ ...props, level: 5 }),
475
- h6: (props) => Header({ ...props, level: 6 }),
476
- a: Anchor,
477
- em: Italics,
478
- del: Striked,
479
- strong: Bold,
480
- code: Code,
481
- blockquote: BlockQuote,
482
- pre: Preformatted,
483
- p: Paragraph,
484
- hr: HorizontalLine,
485
- ol: (props) => List({ ...props, type: "ordered" }),
486
- ul: (props) => List({ ...props, type: "unordered" }),
487
- li: ListItem,
488
- img: Image,
489
- table: Table,
490
- thead: TableHead,
491
- tbody: TableBody,
492
- th: TableHeadCell,
493
- tr: TableRow,
494
- td: TableData
495
- };
496
- // src/components/Loader.tsx
497
- import { Suspense } from "react";
498
-
499
- // src/lib/generateElements.ts
500
- function generateElementsFrom(elements, baseElements = true) {
501
- if (baseElements) {
502
- return { ...BaseElements, ...elements };
503
- } else
504
- return { ...elements };
505
- }
506
- // src/lib/Registry.ts
507
- import { lazy } from "react";
508
- function generateRegistry({
509
- modulesGlob,
510
- metadataGlob,
511
- root,
512
- virtual
513
- }) {
514
- const paths = Object.keys(modulesGlob);
515
- const keys = [];
516
- const _components = [];
517
- const _exports = [];
518
- const _metadata = [];
519
- for (const path of paths) {
520
- const route = path.replace(root, virtual).replace(".mdx", "");
521
- const loader = modulesGlob[path];
522
- keys.push(route);
523
- _components.push([route, lazy(loader)]);
524
- _exports.push([route, loader()]);
525
- const metaLoader = metadataGlob[path.replace(".mdx", ".meta.ts")];
526
- console.log(typeof metaLoader);
527
- _metadata.push([route, metaLoader]);
528
- }
529
- return {
530
- keys,
531
- components: Object.fromEntries(_components),
532
- exports: Object.fromEntries(_exports),
533
- metadata: Object.fromEntries(_metadata)
534
- };
535
- }
536
-
537
- class AbstractRegistry {
538
- diffKeys() {
539
- const keySet = new Set(this.keys);
540
- const exportsSet = new Set(Object.keys(this.exports));
541
- const metadataSet = new Set(Object.keys(this.metadata));
542
- const exportsDiff = keySet.symmetricDifference(exportsSet);
543
- const metadataDiff = keySet.symmetricDifference(metadataSet);
544
- const errMsg = [];
545
- const diffs = {
546
- inComponentsButNotInExports: undefined,
547
- inComponentsButNotInMetadata: undefined,
548
- inExportsButNotInComponents: undefined,
549
- inMetadataButNotInComponents: undefined
550
- };
551
- if (exportsDiff.size !== 0) {
552
- diffs.inComponentsButNotInExports = Array.from(keySet.difference(exportsSet));
553
- diffs.inExportsButNotInComponents = Array.from(exportsSet.difference(keySet));
554
- errMsg.push(`Exports Registry and Component Registry have ${exportsDiff.size} key mismatches.
1
+ import{cn as Z}from"@d1vij/shit-i-always-use";import{useMemo as R,useState as G}from"react";import{createContext as W,useContext as Y}from"react";var $o=["header","header_button","header_1","header_2","header_3","header_4","header_5","header_6","header_icon","anchor","button","bold","italic","span","striked","paragraph","code","preformatted","blockquote","horizontal_line","image","list","unordered_list","ordered_list","list_item","table","table_head","table_head_cell","table_body","table_row","table_data","table_container","table_action_buttons_details","table_action_buttons_summary","table_action_button","table_action_button_html","table_action_button_csv","table_action_button_json","table_action_button_markdown"],J=W(null);function e(){let o=Y(J);if(o===null)throw Error("No stylesmap found at any parent level. Either you forgot to pass the stylesmap to component loader or didnt wrap your component in StyleContext");return o}import{jsx as x}from"react/jsx-runtime";function H(o){let t=R(()=>new URL(window.location.href).origin.toString(),[]),r=e(),[n]=G(()=>{if(o.href?.match(/^#.*/))return"_self";return new URL(o.href??"").origin.toString()===t?"_self":"_blank"});return x("a",{className:Z(r.anchor),target:n,href:o.href,children:o.children})}import{cn as j}from"@d1vij/shit-i-always-use";import{jsx as oo}from"react/jsx-runtime";function E(o){let t=e();return oo("blockquote",{className:j(t.blockquote),children:o.children})}import{cn as to}from"@d1vij/shit-i-always-use";import{jsx as eo}from"react/jsx-runtime";function _(o){let t=e();return eo("span",{className:to(t.bold),children:o.children})}import{cn as ro}from"@d1vij/shit-i-always-use";import{jsx as no}from"react/jsx-runtime";function P(o){let t=e(),r=/language-(\w+)/.exec(o.className||"")?.[1];return no("code",{className:ro(t.code,r&&`language-${r}`),children:o.children})}import{cn as v,useClipboardText as lo}from"@d1vij/shit-i-always-use";import{useEffect as so,useRef as mo,useState as co}from"react";import{jsx as B}from"react/jsx-runtime";function h(o){let t=e(),r=mo(null),[n,s]=co(""),{copy:l}=lo();async function m(){let a=new URL(`/#${n}`,window.location.origin).toString();console.log("clicked"),await l(a)}return so(()=>{if(!r.current)return;let c=(r.current.textContent??"").toLowerCase().replace(/[^a-z0-9\s-]/g,"").trim().replace(/\s+/g,"-").slice(0,30);s(c)},[]),B("h1",{className:v(t.header,t[`header_${o.level}`]),children:B("button",{onClick:()=>void m(),ref:r,id:n,className:v(t.header_button),type:"button",children:o.children})})}import{cn as ao}from"@d1vij/shit-i-always-use";import{jsx as po}from"react/jsx-runtime";function S(o){let t=e();return po("hr",{className:ao(t.horizontal_line)})}import{cn as io}from"@d1vij/shit-i-always-use";import{jsx as uo}from"react/jsx-runtime";function X(o){let t=e();return uo("img",{className:io(t.image),alt:o.alt,title:o.title,src:o.src})}import{cn as fo}from"@d1vij/shit-i-always-use";import{jsx as ho}from"react/jsx-runtime";function O(o){let t=e();return ho("span",{className:fo(t.italic),children:o.children})}import{cn as q}from"@d1vij/shit-i-always-use";import{jsx as M}from"react/jsx-runtime";function b(o){let t=e(),r=o.type==="ordered"?"ol":"ul";return M(r,{className:q(t.list,o.type==="ordered"&&t.ordered_list,o.type==="unordered"&&t.unordered_list),children:o.children})}function C(o){let t=e();return M("li",{className:q(t.list_item),children:o.children})}import{cn as bo}from"@d1vij/shit-i-always-use";import{jsx as yo}from"react/jsx-runtime";function $(o){let t=e();return yo("p",{className:bo(t.paragraph),children:o.children})}import{cn as To}from"@d1vij/shit-i-always-use";import{jsx as Jo}from"react/jsx-runtime";function g(o){let t=e();return Jo("pre",{className:To(t.preformatted),children:o.children})}import{cn as Eo}from"@d1vij/shit-i-always-use";import{jsx as Po}from"react/jsx-runtime";function k(o){let t=e();return Po("span",{className:Eo(t.striked),children:o.children})}import{cn as u,useClipboardText as So}from"@d1vij/shit-i-always-use";import{useCallback as Xo,useEffect as go,useRef as I,useState as wo}from"react";import{jsx as p,jsxs as z}from"react/jsx-runtime";function y({label:o,onClick:t,setOpen:r}){let n=e();function s(l){r(!1),t(l)}return p("button",{onClick:s,className:u(n.table_action_button),type:"button",children:o})}function No(o){let t=[];o.querySelectorAll("thead > tr > th").forEach((l)=>{t.push(l.innerText.trim())});let n=[],s=o.querySelectorAll("tbody > tr");return s.forEach((l)=>{let m=[];l.querySelectorAll("td").forEach((a,c)=>{m.push({column:t[c]??c.toString(),content:a.innerText.trim()})}),n.push(m)}),{meta:{columns:t.length,rows:s.length},headings:t,rows:n}}function Lo(o){let t=o.headings.join(","),r=o.rows.map((n)=>n.map((s)=>s.content).join(",")).join(`
2
+ `);return[t,r].join(`
3
+ `)}function Ao(o){let t=o.headings.map((n)=>`<th>${n}</th>`).join(""),r=o.rows.map((n)=>{return`<tr>${n.map((l)=>`<td>${l.content}</td>`).join("")}</tr>`});return["<table>","<thead>",`<tr>${t}</tr>`,"</thead>","<tbody>",...r,"</tbody>","</table>"].join(`
4
+ `)}function Ho(o){let t=`|${o.headings.join("|")}|`,r=`|${o.headings.map(()=>"-----").join("|")}|`,n=o.rows.map((s)=>`|${s.map((l)=>l.content).join("|")}|`);return[t,r,...n].join(`
5
+ `)}function Q(o){let t=e(),r=I(null),n=I(null),[s,l]=wo(!1),{copy:m}=So();go(()=>{let c=n.current;if(!c)return;function f(){l(!1)}function i(){l(!0)}return c.addEventListener("mouseenter",i),c.addEventListener("mouseleave",f),()=>{c.removeEventListener("mouseenter",i),c.removeEventListener("mouseleave",f)}},[]);let a=Xo((c)=>{return async()=>{let f=r.current;if(!f)return;let i=No(f),d;switch(c){case"html":d=Ao(i);break;case"csv":d=Lo(i);break;case"markdown":d=Ho(i);break;case"json":d=JSON.stringify(i,null,4);break;default:return}await m(d)}},[m]);return z("div",{className:u(t.table_container),children:[p("table",{ref:r,className:u(t.table),children:o.children}),z("details",{ref:n,className:u(t.table_action_buttons_details),open:s,children:[p("summary",{className:u(t.table_action_buttons_summary),children:"Copy"}),p(y,{setOpen:l,label:"HTML",onClick:a("html")}),p(y,{setOpen:l,label:"CSV",onClick:a("csv")}),p(y,{setOpen:l,label:"Json",onClick:a("json")}),p(y,{setOpen:l,label:"Markdown",onClick:a("markdown")})]})]})}function D(o){let t=e();return p("thead",{className:u(t.table_head),children:o.children})}function U(o){let t=e();return p("tbody",{className:u(t.table_body),children:o.children})}function V(o){let t=e();return p("tr",{className:u(t.table_row),children:o.children})}function F(o){let t=e();return p("th",{className:u(t.table_head_cell),children:o.children})}function K(o){let t=e();return p("td",{className:u(t.table_data),children:o.children})}var jt=["h1","h2","h3","h4","h5","h6","a","em","del","strong","code","blockquote","pre","p","hr","ol","ul","li","img","table","thead","tbody","th","tr","td"],T={h1:(o)=>h({...o,level:1}),h2:(o)=>h({...o,level:2}),h3:(o)=>h({...o,level:3}),h4:(o)=>h({...o,level:4}),h5:(o)=>h({...o,level:5}),h6:(o)=>h({...o,level:6}),a:H,em:O,del:k,strong:_,code:P,blockquote:E,pre:g,p:$,hr:S,ol:(o)=>b({...o,type:"ordered"}),ul:(o)=>b({...o,type:"unordered"}),li:C,img:X,table:Q,thead:D,tbody:U,th:F,tr:V,td:K};import{Suspense as qo}from"react";function ne(o,t=!0){if(t)return{...T,...o};else return{...o}}import{lazy as _o}from"react";function vo({modulesGlob:o,metadataGlob:t,root:r,virtual:n}){let s=Object.keys(o),l=[],m=[],a=[],c=[],f=n==="/"||n===""?"":n;console.log("virtual",f);for(let i of s){let d=i.replace(`${r}/`,f).replace(".mdx","");console.log(d);let L=o[i];l.push(d),m.push([d,_o(L)]),a.push([d,L()]);let A=t[i.replace(".mdx",".meta.ts")];console.log(typeof A),c.push([d,A])}return{keys:l,components:Object.fromEntries(m),exports:Object.fromEntries(a),metadata:Object.fromEntries(c)}}class w{diffKeys(){let o=new Set(this.keys),t=new Set(Object.keys(this.exports)),r=new Set(Object.keys(this.metadata)),n=o.symmetricDifference(t),s=o.symmetricDifference(r),l=[],m={inComponentsButNotInExports:void 0,inComponentsButNotInMetadata:void 0,inExportsButNotInComponents:void 0,inMetadataButNotInComponents:void 0};if(n.size!==0)m.inComponentsButNotInExports=Array.from(o.difference(t)),m.inExportsButNotInComponents=Array.from(t.difference(o)),l.push(`Exports Registry and Component Registry have ${n.size} key mismatches.
555
6
  Keys which are present in Component map but not in Exports
556
- ${diffs.inComponentsButNotInExports.join(`
7
+ ${m.inComponentsButNotInExports.join(`
557
8
  `)}
558
9
  and the keys present in Exports but not in component map are
559
- ${diffs.inExportsButNotInComponents.join(`
10
+ ${m.inExportsButNotInComponents.join(`
560
11
  `)}
561
- `);
562
- }
563
- if (metadataDiff.size !== 0) {
564
- diffs.inComponentsButNotInMetadata = Array.from(keySet.difference(metadataSet));
565
- diffs.inMetadataButNotInComponents = Array.from(metadataDiff.difference(keySet));
566
- errMsg.push(`Metadata Registry and Component Registry have ${metadataDiff.size} key mismatches.
12
+ `);if(s.size!==0)m.inComponentsButNotInMetadata=Array.from(o.difference(r)),m.inMetadataButNotInComponents=Array.from(s.difference(o)),l.push(`Metadata Registry and Component Registry have ${s.size} key mismatches.
567
13
  Keys which are present in Component map but not in Metadata
568
- ${diffs.inComponentsButNotInMetadata.join(`
14
+ ${m.inComponentsButNotInMetadata.join(`
569
15
  `)}
570
16
  and the keys present in Metadata but not in Component map are
571
- ${diffs.inMetadataButNotInComponents.join(`
17
+ ${m.inMetadataButNotInComponents.join(`
572
18
  `)}
573
- `);
574
- }
575
- if (errMsg.length === 0)
576
- return null;
577
- return {
578
- diffs,
579
- error: new Error(errMsg.join(`
580
-
581
- `))
582
- };
583
- }
584
- get(_from, key) {
585
- const value = _from[key];
586
- if (!value) {
587
- throw new Error(`Invalid key passed ${key.toString()} to access whatever the fuck we were extractign`);
588
- }
589
- return value;
590
- }
591
- getComponent(key) {
592
- return this.get(this.components, key);
593
- }
594
- getExport(key) {
595
- return this.get(this.exports, key);
596
- }
597
- getMetadata(key) {
598
- return this.get(this.metadata, key);
599
- }
600
- }
601
-
602
- class Registry extends AbstractRegistry {
603
- keys;
604
- components;
605
- exports;
606
- metadata;
607
- constructor(opts) {
608
- super();
609
- const result = generateRegistry(opts);
610
- this.keys = result.keys;
611
- this.components = result.components;
612
- this.exports = result.exports;
613
- this.metadata = result.metadata;
614
- }
615
- }
19
+ `);if(l.length===0)return null;return{diffs:m,error:Error(l.join(`
616
20
 
617
- class CoalescedRegistry extends AbstractRegistry {
618
- keys = [];
619
- components = {};
620
- exports = {};
621
- metadata = {};
622
- constructor(...registries) {
623
- super();
624
- for (const registry of registries) {
625
- this.keys.push(...registry.keys);
626
- Object.assign(this.components, registry.components);
627
- Object.assign(this.exports, registry.exports);
628
- Object.assign(this.metadata, registry.metadata);
629
- }
630
- }
631
- }
632
- // src/components/Loader.tsx
633
- import { jsx as jsx14 } from "react/jsx-runtime";
634
- function MDXFromComponent({
635
- source: SourceComponent,
636
- styles,
637
- fallback,
638
- elements = BaseElements
639
- }) {
640
- return /* @__PURE__ */ jsx14(StyleContext, {
641
- value: styles,
642
- children: /* @__PURE__ */ jsx14(Suspense, {
643
- fallback,
644
- children: /* @__PURE__ */ jsx14(SourceComponent, {
645
- components: elements
646
- })
647
- })
648
- });
649
- }
650
- export {
651
- useStyles,
652
- generateRegistry,
653
- generateElementsFrom,
654
- StyleContext,
655
- StyleClassesList,
656
- Registry,
657
- MDXFromComponent,
658
- CoalescedRegistry,
659
- BaseElements,
660
- BaseElementTags
661
- };
21
+ `))}}get(o,t){let r=o[t];if(!r)throw Error(`Invalid key passed ${t.toString()} to access whatever the fuck we were extractign`);return r}getComponent(o){return this.get(this.components,o)}getExport(o){return this.get(this.exports,o)}getMetadata(o){return this.get(this.metadata,o)}}class Bo extends w{keys;components;exports;metadata;constructor(o){super();let t=vo(o);this.keys=t.keys,this.components=t.components,this.exports=t.exports,this.metadata=t.metadata}}class Oo extends w{keys=[];components={};exports={};metadata={};constructor(...o){super();for(let t of o)this.keys.push(...t.keys),Object.assign(this.components,t.components),Object.assign(this.exports,t.exports),Object.assign(this.metadata,t.metadata)}}import{jsx as N}from"react/jsx-runtime";function Co({source:o,styles:t,fallback:r,elements:n=T}){return N(J,{value:t,children:N(qo,{fallback:r,children:N(o,{components:n})})})}export{e as useStyles,vo as generateRegistry,ne as generateElementsFrom,J as StyleContext,$o as StyleClassesList,Bo as Registry,Co as MDXFromComponent,Oo as CoalescedRegistry,T as BaseElements,jt as BaseElementTags};
@@ -1,14 +1 @@
1
- // src/vitePlugin.ts
2
- import mdx from "@mdx-js/rollup";
3
- import remarkGFM from "remark-gfm";
4
- function MDXLoaderPlugin(opts) {
5
- return mdx({
6
- ...opts,
7
- remarkPlugins: [remarkGFM]
8
- });
9
- }
10
- var vitePlugin_default = MDXLoaderPlugin;
11
- export {
12
- vitePlugin_default as default,
13
- MDXLoaderPlugin
14
- };
1
+ import q from"@mdx-js/rollup";import z from"remark-gfm";function A(b){return q({...b,remarkPlugins:[z]})}var H=A;export{H as default,A as MDXLoaderPlugin};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d1vij/jassm",
3
- "version": "0.1.19-beta.1",
3
+ "version": "0.1.20",
4
4
  "description": "Just another static site maker. Create simple content driven sites using MDX and React along with Typescript safety.",
5
5
  "homepage": "https://github.com/d1vij/jassm",
6
6
  "license": "MIT",