instui-markdown 0.0.9 → 0.1.0
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/dist/index.mjs +74 -16
- package/index.d.mts +25 -0
- package/index.d.ts +25 -0
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import rehypeRaw from "rehype-raw";
|
|
|
5
5
|
import rehypeSlug from "rehype-slug";
|
|
6
6
|
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
|
7
7
|
import { rehypeColorCodes, rehypeInstUIIconTokens, rehypeUnwrapBlockquoteParagraphs } from "rehype-instui-markdown";
|
|
8
|
+
import * as SimpleIcons from "simple-icons";
|
|
8
9
|
import { Text } from "@instructure/ui-text/v11_7";
|
|
9
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
import { Link } from "@instructure/ui-link/v11_7";
|
|
@@ -22,6 +23,50 @@ import { Badge } from "@instructure/ui-badge/v11_7";
|
|
|
22
23
|
import { SourceCodeEditor } from "@instructure/ui-source-code-editor/v11_7";
|
|
23
24
|
import { Alert } from "@instructure/ui-alerts/v11_7";
|
|
24
25
|
import { Table } from "@instructure/ui-table/v11_7";
|
|
26
|
+
//#region src/simple-icons-resolver.ts
|
|
27
|
+
function isSimpleIconLike(value) {
|
|
28
|
+
return typeof value === "object" && value !== null && "path" in value && "title" in value && typeof value.path === "string";
|
|
29
|
+
}
|
|
30
|
+
function normalizeSimpleIconCode(code) {
|
|
31
|
+
return code.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
32
|
+
}
|
|
33
|
+
function toSimpleIconExportName(code) {
|
|
34
|
+
return `si${code.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((word) => word.toLowerCase()).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("")}`;
|
|
35
|
+
}
|
|
36
|
+
function buildSimpleIconLookup(iconsRegistry) {
|
|
37
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
38
|
+
for (const [exportName, iconCandidate] of Object.entries(iconsRegistry)) {
|
|
39
|
+
if (!exportName.startsWith("si") || !isSimpleIconLike(iconCandidate)) continue;
|
|
40
|
+
const slug = iconCandidate.slug ?? exportName.slice(2);
|
|
41
|
+
lookup.set(normalizeSimpleIconCode(slug), {
|
|
42
|
+
title: iconCandidate.title,
|
|
43
|
+
path: iconCandidate.path,
|
|
44
|
+
viewBox: iconCandidate.viewBox ?? "0 0 24 24"
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return lookup;
|
|
48
|
+
}
|
|
49
|
+
function createSimpleIconsResolver(iconsRegistry) {
|
|
50
|
+
const lookup = buildSimpleIconLookup(iconsRegistry);
|
|
51
|
+
return (code) => {
|
|
52
|
+
const normalizedCode = normalizeSimpleIconCode(code);
|
|
53
|
+
const normalizedWithoutPrefix = normalizedCode.startsWith("si") ? normalizedCode.slice(2) : normalizedCode;
|
|
54
|
+
const bySlug = lookup.get(normalizedCode) ?? (normalizedCode.startsWith("si") ? lookup.get(normalizedWithoutPrefix) : void 0);
|
|
55
|
+
if (bySlug) return bySlug;
|
|
56
|
+
const exportNameCandidates = [toSimpleIconExportName(code)];
|
|
57
|
+
if (normalizedCode.startsWith("si")) exportNameCandidates.push(toSimpleIconExportName(normalizedWithoutPrefix));
|
|
58
|
+
for (const exportName of exportNameCandidates) {
|
|
59
|
+
const iconCandidate = iconsRegistry[exportName];
|
|
60
|
+
if (isSimpleIconLike(iconCandidate)) return {
|
|
61
|
+
title: iconCandidate.title,
|
|
62
|
+
path: iconCandidate.path,
|
|
63
|
+
viewBox: iconCandidate.viewBox ?? "0 0 24 24"
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const resolveSimpleIconToken = createSimpleIconsResolver(SimpleIcons);
|
|
69
|
+
//#endregion
|
|
25
70
|
//#region src/components/text-components.tsx
|
|
26
71
|
function createEmComponent() {
|
|
27
72
|
return ({ children }) => /* @__PURE__ */ jsx(Text, {
|
|
@@ -442,8 +487,12 @@ function createBlockquoteComponent(options) {
|
|
|
442
487
|
}
|
|
443
488
|
//#endregion
|
|
444
489
|
//#region src/components/span-component.tsx
|
|
445
|
-
|
|
446
|
-
|
|
490
|
+
const INSTUI_ICON_LOOKUP = new Map(Object.entries(InstUIIcons).map(([name, value]) => [name.toLowerCase(), value]));
|
|
491
|
+
function findInstUIIcon(candidates) {
|
|
492
|
+
for (const candidate of candidates) {
|
|
493
|
+
const IconComponent = INSTUI_ICON_LOOKUP.get(candidate.toLowerCase());
|
|
494
|
+
if (IconComponent) return IconComponent;
|
|
495
|
+
}
|
|
447
496
|
}
|
|
448
497
|
function parseIconTokenName(iconName) {
|
|
449
498
|
const withoutPrefix = iconName.startsWith("Icon") ? iconName.slice(4) : iconName;
|
|
@@ -461,6 +510,9 @@ function parseIconTokenName(iconName) {
|
|
|
461
510
|
};
|
|
462
511
|
}
|
|
463
512
|
function getSimpleIconCodes(iconName, root, withoutPrefix) {
|
|
513
|
+
const lowerWords = root.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^a-zA-Z0-9]+/).filter(Boolean).map((word) => word.toLowerCase());
|
|
514
|
+
const compact = lowerWords.join("");
|
|
515
|
+
const kebab = lowerWords.join("-");
|
|
464
516
|
const camel = root.charAt(0).toLowerCase() + root.slice(1);
|
|
465
517
|
const lower = root.toLowerCase();
|
|
466
518
|
return Array.from(new Set([
|
|
@@ -468,7 +520,9 @@ function getSimpleIconCodes(iconName, root, withoutPrefix) {
|
|
|
468
520
|
withoutPrefix,
|
|
469
521
|
root,
|
|
470
522
|
camel,
|
|
471
|
-
lower
|
|
523
|
+
lower,
|
|
524
|
+
compact,
|
|
525
|
+
kebab
|
|
472
526
|
]));
|
|
473
527
|
}
|
|
474
528
|
function createSpanComponent(options) {
|
|
@@ -479,12 +533,11 @@ function createSpanComponent(options) {
|
|
|
479
533
|
if (iconName) {
|
|
480
534
|
const { withoutPrefix, isSolid, isInstUI, root } = parseIconTokenName(iconName);
|
|
481
535
|
if (options.enableInstuiIcons) {
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
`Icon${
|
|
486
|
-
|
|
487
|
-
]).map((name) => InstUIIcons[name]).find(Boolean);
|
|
536
|
+
const IconComponent = findInstUIIcon(isSolid ? [`Icon${root}Solid`] : isInstUI ? [`${root}InstUIIcon`] : [
|
|
537
|
+
`${root}InstUIIcon`,
|
|
538
|
+
`Icon${root}Line`,
|
|
539
|
+
`Icon${root}`
|
|
540
|
+
]);
|
|
488
541
|
if (IconComponent) {
|
|
489
542
|
const resolvedColor = inlineIconColor ?? options.iconColor;
|
|
490
543
|
const normalizedIconColor = resolvedColor && isLiteralColorValue(resolvedColor) ? normalizeColorForSwatch(resolvedColor) : void 0;
|
|
@@ -511,12 +564,18 @@ function createSpanComponent(options) {
|
|
|
511
564
|
const normalizedIconColor = resolvedColor && isLiteralColorValue(resolvedColor) ? normalizeColorForSwatch(resolvedColor) : void 0;
|
|
512
565
|
const label = simpleIcon.title ?? root;
|
|
513
566
|
return /* @__PURE__ */ jsx("span", {
|
|
514
|
-
style:
|
|
567
|
+
style: {
|
|
568
|
+
display: "inline-flex",
|
|
569
|
+
alignItems: "center",
|
|
570
|
+
verticalAlign: "middle",
|
|
571
|
+
lineHeight: 1,
|
|
572
|
+
...normalizedIconColor ? { color: normalizedIconColor } : {}
|
|
573
|
+
},
|
|
515
574
|
children: /* @__PURE__ */ jsxs(InlineSVG, {
|
|
516
|
-
inline:
|
|
575
|
+
inline: true,
|
|
517
576
|
viewBox: simpleIcon.viewBox ?? "0 0 24 24",
|
|
518
|
-
width: simpleIcon.width ?? "
|
|
519
|
-
height: simpleIcon.height ?? "
|
|
577
|
+
width: simpleIcon.width ?? "1.125em",
|
|
578
|
+
height: simpleIcon.height ?? "1.125em",
|
|
520
579
|
role: "img",
|
|
521
580
|
"aria-label": label,
|
|
522
581
|
children: [/* @__PURE__ */ jsx("title", { children: label }), /* @__PURE__ */ jsx("path", {
|
|
@@ -706,7 +765,6 @@ function createInstuiMarkdownComponents(renderOptions = {}) {
|
|
|
706
765
|
const enableInstuiIcons = renderOptions.icons?.providers?.instui ?? true;
|
|
707
766
|
const enableSimpleIcons = renderOptions.icons?.providers?.simpleIcons ?? true;
|
|
708
767
|
const simpleIconColor = renderOptions.icons?.simpleIcons?.color;
|
|
709
|
-
const resolveSimpleIcon = renderOptions.icons?.simpleIcons?.resolve;
|
|
710
768
|
return {
|
|
711
769
|
span: createSpanComponent({
|
|
712
770
|
showColorCodes,
|
|
@@ -715,7 +773,7 @@ function createInstuiMarkdownComponents(renderOptions = {}) {
|
|
|
715
773
|
enableInstuiIcons,
|
|
716
774
|
enableSimpleIcons,
|
|
717
775
|
simpleIconColor,
|
|
718
|
-
resolveSimpleIcon
|
|
776
|
+
resolveSimpleIcon: renderOptions.icons?.simpleIcons?.resolve ?? resolveSimpleIconToken
|
|
719
777
|
}),
|
|
720
778
|
a: createLinkComponent({
|
|
721
779
|
showExternalIcon,
|
|
@@ -810,4 +868,4 @@ function InstuiMdxProvider({ children, renderOptions }) {
|
|
|
810
868
|
});
|
|
811
869
|
}
|
|
812
870
|
//#endregion
|
|
813
|
-
export { InstuiMarkdown, InstuiMdxProvider, createInstuiMarkdownComponents, instuiMarkdownComponents };
|
|
871
|
+
export { InstuiMarkdown, InstuiMdxProvider, createInstuiMarkdownComponents, createSimpleIconsResolver, instuiMarkdownComponents, resolveSimpleIconToken };
|
package/index.d.mts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { Components } from "react-markdown";
|
|
3
3
|
|
|
4
|
+
export type SimpleIconResolver = (code: string) => SimpleIconTokenData | undefined;
|
|
5
|
+
export type SimpleIconsRegistry = Record<string, unknown>;
|
|
6
|
+
|
|
4
7
|
export interface InstuiMarkdownRenderOptions {
|
|
5
8
|
alert?: {
|
|
6
9
|
closeButton?: boolean;
|
|
@@ -30,9 +33,25 @@ export interface InstuiMarkdownRenderOptions {
|
|
|
30
33
|
icons?: {
|
|
31
34
|
enabled?: boolean;
|
|
32
35
|
color?: string;
|
|
36
|
+
providers?: {
|
|
37
|
+
instui?: boolean;
|
|
38
|
+
simpleIcons?: boolean;
|
|
39
|
+
};
|
|
40
|
+
simpleIcons?: {
|
|
41
|
+
color?: string;
|
|
42
|
+
resolve?: (code: string) => SimpleIconTokenData | undefined;
|
|
43
|
+
};
|
|
33
44
|
};
|
|
34
45
|
}
|
|
35
46
|
|
|
47
|
+
export interface SimpleIconTokenData {
|
|
48
|
+
path: string;
|
|
49
|
+
title?: string;
|
|
50
|
+
viewBox?: string;
|
|
51
|
+
width?: string | number;
|
|
52
|
+
height?: string | number;
|
|
53
|
+
}
|
|
54
|
+
|
|
36
55
|
export interface InstuiMarkdownProps {
|
|
37
56
|
children: string;
|
|
38
57
|
renderOptions?: InstuiMarkdownRenderOptions;
|
|
@@ -52,3 +71,9 @@ export declare function createInstuiMarkdownComponents(
|
|
|
52
71
|
export declare function InstuiMarkdown(props: InstuiMarkdownProps): ReactNode;
|
|
53
72
|
|
|
54
73
|
export declare function InstuiMdxProvider(props: InstuiMdxProviderProps): ReactNode;
|
|
74
|
+
|
|
75
|
+
export declare function createSimpleIconsResolver(
|
|
76
|
+
iconsRegistry: SimpleIconsRegistry,
|
|
77
|
+
): SimpleIconResolver;
|
|
78
|
+
|
|
79
|
+
export declare const resolveSimpleIconToken: SimpleIconResolver;
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { Components } from "react-markdown";
|
|
3
3
|
|
|
4
|
+
export type SimpleIconResolver = (code: string) => SimpleIconTokenData | undefined;
|
|
5
|
+
export type SimpleIconsRegistry = Record<string, unknown>;
|
|
6
|
+
|
|
4
7
|
export interface InstuiMarkdownRenderOptions {
|
|
5
8
|
alert?: {
|
|
6
9
|
closeButton?: boolean;
|
|
@@ -30,9 +33,25 @@ export interface InstuiMarkdownRenderOptions {
|
|
|
30
33
|
icons?: {
|
|
31
34
|
enabled?: boolean;
|
|
32
35
|
color?: string;
|
|
36
|
+
providers?: {
|
|
37
|
+
instui?: boolean;
|
|
38
|
+
simpleIcons?: boolean;
|
|
39
|
+
};
|
|
40
|
+
simpleIcons?: {
|
|
41
|
+
color?: string;
|
|
42
|
+
resolve?: (code: string) => SimpleIconTokenData | undefined;
|
|
43
|
+
};
|
|
33
44
|
};
|
|
34
45
|
}
|
|
35
46
|
|
|
47
|
+
export interface SimpleIconTokenData {
|
|
48
|
+
path: string;
|
|
49
|
+
title?: string;
|
|
50
|
+
viewBox?: string;
|
|
51
|
+
width?: string | number;
|
|
52
|
+
height?: string | number;
|
|
53
|
+
}
|
|
54
|
+
|
|
36
55
|
export interface InstuiMarkdownProps {
|
|
37
56
|
children: string;
|
|
38
57
|
renderOptions?: InstuiMarkdownRenderOptions;
|
|
@@ -52,3 +71,9 @@ export declare function createInstuiMarkdownComponents(
|
|
|
52
71
|
export declare function InstuiMarkdown(props: InstuiMarkdownProps): ReactNode;
|
|
53
72
|
|
|
54
73
|
export declare function InstuiMdxProvider(props: InstuiMdxProviderProps): ReactNode;
|
|
74
|
+
|
|
75
|
+
export declare function createSimpleIconsResolver(
|
|
76
|
+
iconsRegistry: SimpleIconsRegistry,
|
|
77
|
+
): SimpleIconResolver;
|
|
78
|
+
|
|
79
|
+
export declare const resolveSimpleIconToken: SimpleIconResolver;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "instui-markdown",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "InstUI markdown renderer components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"rehype-instui-markdown": "0.0
|
|
24
|
+
"rehype-instui-markdown": "0.1.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^24",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"rehype-autolink-headings": "*",
|
|
52
52
|
"rehype-raw": "*",
|
|
53
53
|
"rehype-slug": "*",
|
|
54
|
-
"remark-gfm": "*"
|
|
54
|
+
"remark-gfm": "*",
|
|
55
|
+
"simple-icons": "*"
|
|
55
56
|
},
|
|
56
57
|
"scripts": {
|
|
57
58
|
"build": "vp pack",
|