@haruhimemoe/ui 0.7.0 → 0.9.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/README.md +246 -11
  3. package/dist/components/basics/Disclosure.d.ts +1 -1
  4. package/dist/components/basics/Disclosure.js +2 -2
  5. package/dist/components/basics/Prose.d.ts +9 -6
  6. package/dist/components/basics/Prose.js +4 -4
  7. package/dist/components/forms/Checkbox.d.ts +1 -1
  8. package/dist/components/forms/Checkbox.js +3 -1
  9. package/dist/components/forms/RadioGroup.js +3 -1
  10. package/dist/components/mdx/Callout.d.ts +24 -0
  11. package/dist/components/mdx/Callout.js +22 -0
  12. package/dist/components/mdx/CodeBlock.d.ts +26 -0
  13. package/dist/components/mdx/CodeBlock.js +48 -0
  14. package/dist/components/mdx/CodeCopyButton.d.ts +21 -0
  15. package/dist/components/mdx/CodeCopyButton.js +34 -0
  16. package/dist/components/mdx/MdxBlockquote.d.ts +23 -0
  17. package/dist/components/mdx/MdxBlockquote.js +17 -0
  18. package/dist/components/mdx/MdxHeading.d.ts +26 -0
  19. package/dist/components/mdx/MdxHeading.js +23 -0
  20. package/dist/components/mdx/MdxLink.d.ts +29 -0
  21. package/dist/components/mdx/MdxLink.js +26 -0
  22. package/dist/components/mdx/MdxPre.d.ts +25 -0
  23. package/dist/components/mdx/MdxPre.js +39 -0
  24. package/dist/components/mdx/MdxTable.d.ts +20 -0
  25. package/dist/components/mdx/MdxTable.js +23 -0
  26. package/dist/components/mdx/highlighter.d.ts +37 -0
  27. package/dist/components/mdx/highlighter.js +66 -0
  28. package/dist/components/mdx/mdxComponents.d.ts +21 -0
  29. package/dist/components/mdx/mdxComponents.js +22 -0
  30. package/dist/components/mdx/parseCodeMeta.d.ts +21 -0
  31. package/dist/components/mdx/parseCodeMeta.js +40 -0
  32. package/dist/components/mdx/textOf.d.ts +17 -0
  33. package/dist/components/mdx/textOf.js +28 -0
  34. package/dist/components/palette/CommandPalette.d.ts +21 -0
  35. package/dist/components/palette/CommandPalette.js +315 -0
  36. package/dist/components/palette/CommandPaletteButton.d.ts +21 -0
  37. package/dist/components/palette/CommandPaletteButton.js +26 -0
  38. package/dist/components/palette/PaletteFooter.d.ts +21 -0
  39. package/dist/components/palette/PaletteFooter.js +10 -0
  40. package/dist/components/palette/PaletteInput.d.ts +30 -0
  41. package/dist/components/palette/PaletteInput.js +23 -0
  42. package/dist/components/palette/PaletteList.d.ts +29 -0
  43. package/dist/components/palette/PaletteList.js +44 -0
  44. package/dist/components/palette/PaletteRow.d.ts +30 -0
  45. package/dist/components/palette/PaletteRow.js +33 -0
  46. package/dist/components/palette/calc.d.ts +28 -0
  47. package/dist/components/palette/calc.js +226 -0
  48. package/dist/components/palette/fuzzy.d.ts +51 -0
  49. package/dist/components/palette/fuzzy.js +138 -0
  50. package/dist/components/palette/hotkeys.d.ts +57 -0
  51. package/dist/components/palette/hotkeys.js +111 -0
  52. package/dist/components/palette/paletteEvents.d.ts +22 -0
  53. package/dist/components/palette/paletteEvents.js +22 -0
  54. package/dist/components/palette/platform.d.ts +13 -0
  55. package/dist/components/palette/platform.js +21 -0
  56. package/dist/components/palette/recents.d.ts +48 -0
  57. package/dist/components/palette/recents.js +85 -0
  58. package/dist/components/palette/rows.d.ts +63 -0
  59. package/dist/components/palette/rows.js +136 -0
  60. package/dist/components/palette/siteCommands.d.ts +38 -0
  61. package/dist/components/palette/siteCommands.js +152 -0
  62. package/dist/components/palette/store.d.ts +94 -0
  63. package/dist/components/palette/store.js +135 -0
  64. package/dist/components/palette/types.d.ts +102 -0
  65. package/dist/components/palette/types.js +11 -0
  66. package/dist/components/palette/useProviderSearch.d.ts +28 -0
  67. package/dist/components/palette/useProviderSearch.js +68 -0
  68. package/dist/components/shell/HeaderMenu.d.ts +1 -1
  69. package/dist/components/shell/HeaderMenu.js +2 -2
  70. package/dist/index.d.ts +8 -1
  71. package/dist/index.js +8 -1
  72. package/dist/mdx.d.ts +17 -0
  73. package/dist/mdx.js +17 -0
  74. package/dist/remark/callouts.d.ts +20 -0
  75. package/dist/remark/callouts.js +58 -0
  76. package/dist/remark/codeMeta.d.ts +17 -0
  77. package/dist/remark/codeMeta.js +22 -0
  78. package/dist/remark/headingIds.d.ts +16 -0
  79. package/dist/remark/headingIds.js +28 -0
  80. package/dist/remark/index.d.ts +29 -0
  81. package/dist/remark/index.js +33 -0
  82. package/dist/remark/mdast.d.ts +42 -0
  83. package/dist/remark/mdast.js +37 -0
  84. package/dist/remark/slugify.d.ts +23 -0
  85. package/dist/remark/slugify.js +40 -0
  86. package/dist/shiki.d.ts +13 -0
  87. package/dist/shiki.js +38 -0
  88. package/dist/theme.css +18 -0
  89. package/package.json +34 -4
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @file src/remark/index.ts
3
+ * @desc The public entry point for `@haruhimemoe/ui/remark`: one remark plugin for MDX and
4
+ * react-markdown that combines code meta, callouts and heading ids, plus the individual
5
+ * plugins and the slug helpers for callers who want only one piece.
6
+ * @author David @dvhsh (https://dvh.sh)
7
+ * @created Sat Oct 3, 2026
8
+ * @modified Sat Oct 3, 2026
9
+ */
10
+ import { remarkCallouts } from "./callouts.js";
11
+ import { remarkCodeMeta } from "./codeMeta.js";
12
+ import { remarkHeadingIds } from "./headingIds.js";
13
+ export { remarkCallouts } from "./callouts.js";
14
+ export { remarkCodeMeta } from "./codeMeta.js";
15
+ export { remarkHeadingIds } from "./headingIds.js";
16
+ export { createSlugger, slugify } from "./slugify.js";
17
+ /**
18
+ * @function remarkHaruhime
19
+ * @param options {RemarkHaruhimeOptions} per-plugin opt-outs; omit to run all three
20
+ * @returns {(tree: MdNode) => void} a remark transformer running code meta, callouts and heading
21
+ * ids over one tree. A default export, because Turbopack only takes MDX plugins by
22
+ * module name: `remarkPlugins: ["@haruhimemoe/ui/remark"]`.
23
+ */
24
+ export default function remarkHaruhime(options = {}) {
25
+ return (tree) => {
26
+ if (options.codeMeta !== false)
27
+ remarkCodeMeta()(tree);
28
+ if (options.callouts !== false)
29
+ remarkCallouts()(tree);
30
+ if (options.headingIds !== false)
31
+ remarkHeadingIds()(tree);
32
+ };
33
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file src/remark/mdast.ts
3
+ * @desc The slice of an mdast node these remark plugins read and write, plus three small
4
+ * helpers (`walk`, `setProperty`, `textContent`) that the plugins in this directory share.
5
+ * No `unist-util-visit` or `@types/mdast` import: this type is the whole contract.
6
+ * @author David @dvhsh (https://dvh.sh)
7
+ * @created Sat Oct 3, 2026
8
+ * @modified Sat Oct 3, 2026
9
+ */
10
+ /** The slice of an mdast node these plugins read and write. */
11
+ export type MdNode = {
12
+ type: string;
13
+ children?: MdNode[];
14
+ value?: string;
15
+ meta?: string | null;
16
+ depth?: number;
17
+ data?: {
18
+ hProperties?: Record<string, unknown>;
19
+ [key: string]: unknown;
20
+ };
21
+ };
22
+ /**
23
+ * @function walk
24
+ * @param node {MdNode} the node to start from
25
+ * @param visit {(node: MdNode) => void} called on `node`, then on every descendant, depth first
26
+ * @returns {void}
27
+ */
28
+ export declare const walk: (node: MdNode, visit: (node: MdNode) => void) => void;
29
+ /**
30
+ * @function setProperty
31
+ * @param node {MdNode} the node to annotate
32
+ * @param key {string} the hast property name (camelCase, e.g. `dataMeta`)
33
+ * @param value {unknown} the property's value
34
+ * @returns {void} sets one HTML attribute that mdast-util-to-hast copies onto the rendered element
35
+ */
36
+ export declare const setProperty: (node: MdNode, key: string, value: unknown) => void;
37
+ /**
38
+ * @function textContent
39
+ * @param node {MdNode} the node to read
40
+ * @returns {string} the node's plain text: its value, or its children's text joined
41
+ */
42
+ export declare const textContent: (node: MdNode) => string;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @file src/remark/mdast.ts
3
+ * @desc The slice of an mdast node these remark plugins read and write, plus three small
4
+ * helpers (`walk`, `setProperty`, `textContent`) that the plugins in this directory share.
5
+ * No `unist-util-visit` or `@types/mdast` import: this type is the whole contract.
6
+ * @author David @dvhsh (https://dvh.sh)
7
+ * @created Sat Oct 3, 2026
8
+ * @modified Sat Oct 3, 2026
9
+ */
10
+ /**
11
+ * @function walk
12
+ * @param node {MdNode} the node to start from
13
+ * @param visit {(node: MdNode) => void} called on `node`, then on every descendant, depth first
14
+ * @returns {void}
15
+ */
16
+ export const walk = (node, visit) => {
17
+ visit(node);
18
+ for (const child of node.children ?? [])
19
+ walk(child, visit);
20
+ };
21
+ /**
22
+ * @function setProperty
23
+ * @param node {MdNode} the node to annotate
24
+ * @param key {string} the hast property name (camelCase, e.g. `dataMeta`)
25
+ * @param value {unknown} the property's value
26
+ * @returns {void} sets one HTML attribute that mdast-util-to-hast copies onto the rendered element
27
+ */
28
+ export const setProperty = (node, key, value) => {
29
+ node.data ??= {};
30
+ node.data.hProperties = { ...node.data.hProperties, [key]: value };
31
+ };
32
+ /**
33
+ * @function textContent
34
+ * @param node {MdNode} the node to read
35
+ * @returns {string} the node's plain text: its value, or its children's text joined
36
+ */
37
+ export const textContent = (node) => typeof node.value === "string" ? node.value : (node.children ?? []).map(textContent).join("");
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file src/remark/slugify.ts
3
+ * @desc GitHub-style heading slugs: lowercase, drop punctuation (keeping letters, marks, digits
4
+ * and underscores from any script), turn each whitespace character into a hyphen, and
5
+ * suffix repeats `-1`, `-2` the way GitHub's own heading anchors do.
6
+ * @author David @dvhsh (https://dvh.sh)
7
+ * @created Sat Oct 3, 2026
8
+ * @modified Sat Oct 3, 2026
9
+ */
10
+ /**
11
+ * @function slugify
12
+ * @param text {string} the heading text
13
+ * @returns {string} a lowercase, hyphenated slug (letters/marks/digits/underscores from any
14
+ * script survive; everything else but whitespace and existing hyphens is dropped)
15
+ */
16
+ export declare const slugify: (text: string) => string;
17
+ /**
18
+ * @function createSlugger
19
+ * @returns {(text: string) => string} a function that slugs `text` and, on a repeat (the slug
20
+ * itself, or a literal heading that already claimed the suffixed form), appends `-1`,
21
+ * `-2`, … until it finds an unused candidate, like GitHub's heading anchors
22
+ */
23
+ export declare const createSlugger: () => ((text: string) => string);
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file src/remark/slugify.ts
3
+ * @desc GitHub-style heading slugs: lowercase, drop punctuation (keeping letters, marks, digits
4
+ * and underscores from any script), turn each whitespace character into a hyphen, and
5
+ * suffix repeats `-1`, `-2` the way GitHub's own heading anchors do.
6
+ * @author David @dvhsh (https://dvh.sh)
7
+ * @created Sat Oct 3, 2026
8
+ * @modified Sat Oct 3, 2026
9
+ */
10
+ /**
11
+ * @function slugify
12
+ * @param text {string} the heading text
13
+ * @returns {string} a lowercase, hyphenated slug (letters/marks/digits/underscores from any
14
+ * script survive; everything else but whitespace and existing hyphens is dropped)
15
+ */
16
+ export const slugify = (text) => text
17
+ .trim()
18
+ .toLowerCase()
19
+ .replace(/[^\p{L}\p{M}\p{N}\p{Pc}\s-]/gu, "")
20
+ .replace(/\s/g, "-");
21
+ /**
22
+ * @function createSlugger
23
+ * @returns {(text: string) => string} a function that slugs `text` and, on a repeat (the slug
24
+ * itself, or a literal heading that already claimed the suffixed form), appends `-1`,
25
+ * `-2`, … until it finds an unused candidate, like GitHub's heading anchors
26
+ */
27
+ export const createSlugger = () => {
28
+ const occurrences = new Map();
29
+ return (text) => {
30
+ const base = slugify(text);
31
+ let candidate = base;
32
+ while (occurrences.has(candidate)) {
33
+ const count = (occurrences.get(base) ?? 0) + 1;
34
+ occurrences.set(base, count);
35
+ candidate = `${base}-${count}`;
36
+ }
37
+ occurrences.set(candidate, 0);
38
+ return candidate;
39
+ };
40
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @file src/shiki.ts
3
+ * @desc The `@haruhimemoe/ui/shiki` subpath: registers the Shiki loader CodeBlock highlights
4
+ * with (a core highlighter, the CSS-variables theme, a fixed language set and the no-WASM
5
+ * JS regex engine). Apps that render code install `shiki` and import this once, for its
6
+ * side effect: `import "@haruhimemoe/ui/shiki";` (in mdx-components.tsx, say). Nothing
7
+ * else in the package names Shiki, so an app that skips this import builds without it
8
+ * and gets plain code blocks.
9
+ * @author David @dvhsh (https://dvh.sh)
10
+ * @created Sat Oct 3, 2026
11
+ * @modified Sat Oct 3, 2026
12
+ */
13
+ export {};
package/dist/shiki.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @file src/shiki.ts
3
+ * @desc The `@haruhimemoe/ui/shiki` subpath: registers the Shiki loader CodeBlock highlights
4
+ * with (a core highlighter, the CSS-variables theme, a fixed language set and the no-WASM
5
+ * JS regex engine). Apps that render code install `shiki` and import this once, for its
6
+ * side effect: `import "@haruhimemoe/ui/shiki";` (in mdx-components.tsx, say). Nothing
7
+ * else in the package names Shiki, so an app that skips this import builds without it
8
+ * and gets plain code blocks.
9
+ * @author David @dvhsh (https://dvh.sh)
10
+ * @created Sat Oct 3, 2026
11
+ * @modified Sat Oct 3, 2026
12
+ */
13
+ import { setHighlighterLoader, THEME } from "./components/mdx/highlighter.js";
14
+ /**
15
+ * @function loadShiki
16
+ * @returns {Promise<HighlighterCore>} a Shiki core highlighter with the package's theme and
17
+ * languages, loaded through dynamic import()
18
+ */
19
+ const loadShiki = async () => {
20
+ const [{ createCssVariablesTheme, createHighlighterCore }, { createJavaScriptRegexEngine }] = await Promise.all([import("shiki/core"), import("shiki/engine/javascript")]);
21
+ return createHighlighterCore({
22
+ themes: [createCssVariablesTheme({ name: THEME, variablePrefix: "--shiki-" })],
23
+ langs: [
24
+ import("shiki/langs/typescript.mjs"),
25
+ import("shiki/langs/tsx.mjs"),
26
+ import("shiki/langs/javascript.mjs"),
27
+ import("shiki/langs/json.mjs"),
28
+ import("shiki/langs/bash.mjs"),
29
+ import("shiki/langs/css.mjs"),
30
+ import("shiki/langs/html.mjs"),
31
+ import("shiki/langs/markdown.mjs"),
32
+ import("shiki/langs/diff.mjs"),
33
+ import("shiki/langs/yaml.mjs"),
34
+ ],
35
+ engine: createJavaScriptRegexEngine(),
36
+ });
37
+ };
38
+ setHighlighterLoader(loadShiki);
package/dist/theme.css CHANGED
@@ -45,6 +45,24 @@
45
45
  --font-sans: var(--font-nunito), ui-sans-serif, system-ui, sans-serif;
46
46
  }
47
47
 
48
+ /* CodeBlock reads these as Shiki's CSS-variables theme. Every token keeps 4.5:1 against both b6
49
+ (the block's background) and b4 (the highlighted-line tint) at every integer --hue. The keyword
50
+ and link tokens get their own hue-derived value instead of var(--color-h1): that variable's
51
+ default lightness (76%) falls to 4.33:1 against b4 at hue 240. */
52
+ :root {
53
+ --shiki-foreground: var(--color-c2);
54
+ --shiki-background: var(--color-b6);
55
+ --shiki-token-keyword: hsl(var(--hue) 100% 78%);
56
+ --shiki-token-string: hsl(calc(var(--hue) + 150) 55% 75%);
57
+ --shiki-token-string-expression: hsl(calc(var(--hue) + 150) 55% 75%);
58
+ --shiki-token-constant: hsl(calc(var(--hue) + 40) 55% 74%);
59
+ --shiki-token-function: hsl(calc(var(--hue) + 200) 55% 75%);
60
+ --shiki-token-parameter: hsl(calc(var(--hue) + 60) 55% 75%);
61
+ --shiki-token-comment: var(--color-c4);
62
+ --shiki-token-punctuation: var(--color-c3);
63
+ --shiki-token-link: hsl(var(--hue) 100% 78%);
64
+ }
65
+
48
66
  @layer base {
49
67
  :focus-visible {
50
68
  outline: 2px solid var(--color-h1);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@haruhimemoe/ui",
3
- "version": "0.7.0",
4
- "description": "React components for the haruhime.moe osu! tools on Next.js: the osu!-web-style palette as a Tailwind theme, buttons, cards, form fields and confirms, filter controls, tables, osu! beatmap display pieces and the site header and footer.",
3
+ "version": "0.9.0",
4
+ "description": "React components for the haruhime.moe osu! tools on Next.js: the osu!-web-style palette as a Tailwind theme, buttons, cards, form fields and confirms, filter controls, tables, osu! beatmap display pieces, a command palette and the site header and footer.",
5
5
  "keywords": [
6
6
  "osu",
7
7
  "osu!",
@@ -26,6 +26,18 @@
26
26
  "types": "./dist/index.d.ts",
27
27
  "default": "./dist/index.js"
28
28
  },
29
+ "./mdx": {
30
+ "types": "./dist/mdx.d.ts",
31
+ "default": "./dist/mdx.js"
32
+ },
33
+ "./remark": {
34
+ "types": "./dist/remark/index.d.ts",
35
+ "default": "./dist/remark/index.js"
36
+ },
37
+ "./shiki": {
38
+ "types": "./dist/shiki.d.ts",
39
+ "default": "./dist/shiki.js"
40
+ },
29
41
  "./theme.css": "./dist/theme.css",
30
42
  "./package.json": "./package.json"
31
43
  },
@@ -35,7 +47,8 @@
35
47
  "CHANGELOG.md"
36
48
  ],
37
49
  "sideEffects": [
38
- "**/*.css"
50
+ "**/*.css",
51
+ "./dist/shiki.js"
39
52
  ],
40
53
  "engines": {
41
54
  "node": ">=22.12"
@@ -50,11 +63,14 @@
50
63
  "build": "bun run clean && tsc -p tsconfig.build.json && node -e \"require('node:fs').copyFileSync('src/theme.css','dist/theme.css')\"",
51
64
  "check": "biome check .",
52
65
  "check:fix": "biome check --write .",
53
- "typecheck": "tsc --noEmit && tsc -p scripts/consumer-fixture/tsconfig.json",
66
+ "typecheck": "tsc --noEmit && tsc -p scripts/consumer-fixture/tsconfig.json && tsc -p playground/tsconfig.json",
54
67
  "test": "vitest run",
55
68
  "test:coverage": "vitest run --coverage",
56
69
  "test:watch": "vitest",
57
70
  "check:consumer": "node scripts/check-consumer.mjs",
71
+ "play": "next dev playground --webpack",
72
+ "play:build": "next build playground --webpack",
73
+ "play:axe": "node scripts/axe-playground.mjs",
58
74
  "prepublishOnly": "bun run check && bun run typecheck && bun run test && bun run build"
59
75
  },
60
76
  "dependencies": {
@@ -64,15 +80,26 @@
64
80
  "next": ">=16.0.0 <17",
65
81
  "react": ">=19.0.0",
66
82
  "react-dom": ">=19.0.0",
83
+ "shiki": ">=4.5.0 <5",
67
84
  "tailwindcss": ">=4.1.0 <5"
68
85
  },
86
+ "peerDependenciesMeta": {
87
+ "shiki": {
88
+ "optional": true
89
+ }
90
+ },
69
91
  "devDependencies": {
92
+ "@axe-core/playwright": "4.13.0",
70
93
  "@biomejs/biome": "2.5.14",
94
+ "@mdx-js/loader": "3.1.1",
95
+ "@mdx-js/react": "3.1.1",
96
+ "@next/mdx": "16.3.6",
71
97
  "@tailwindcss/postcss": "4.3.3",
72
98
  "@testing-library/dom": "10.4.2",
73
99
  "@testing-library/jest-dom": "7.0.1",
74
100
  "@testing-library/react": "16.3.3",
75
101
  "@testing-library/user-event": "14.6.7",
102
+ "@types/mdx": "2.0.14",
76
103
  "@types/node": "26.6.2",
77
104
  "@types/react": "19.3.0",
78
105
  "@types/react-dom": "19.3.0",
@@ -81,8 +108,11 @@
81
108
  "axe-core": "4.13.0",
82
109
  "jsdom": "30.1.1",
83
110
  "next": "16.3.6",
111
+ "playwright": "1.63.0",
84
112
  "react": "19.3.0",
85
113
  "react-dom": "19.3.0",
114
+ "remark-gfm": "4.0.1",
115
+ "shiki": "4.5.0",
86
116
  "tailwindcss": "4.3.3",
87
117
  "typescript": "7.0.2",
88
118
  "vitest": "5.0.1"