@maiyunnet/kebab 8.6.4 → 9.0.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.
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-600:oklch(57.7% .245 27.325);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-700:oklch(55.5% .163 48.998);--color-green-100:oklch(96.2% .044 156.743);--color-green-700:oklch(52.7% .154 150.069);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-2xl:42rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.static{position:static}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.table{display:table}.h-10{height:calc(var(--spacing) * 10)}.min-h-screen{min-height:100vh}.w-10{width:calc(var(--spacing) * 10)}.w-28{width:calc(var(--spacing) * 28)}.w-fit{width:fit-content}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-300{border-color:var(--color-slate-300)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-500{background-color:var(--color-blue-500)}.bg-green-100{background-color:var(--color-green-100)}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-white{background-color:var(--color-white)}.p-1{padding:calc(var(--spacing) * 1)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-10{padding-block:calc(var(--spacing) * 10)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-amber-700{color:var(--color-amber-700)}.text-blue-700{color:var(--color-blue-700)}.text-green-700{color:var(--color-green-700)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-800{color:var(--color-slate-800)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.shadow,.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)}.hover\:text-slate-600:hover{color:var(--color-slate-600)}.hover\:text-slate-900:hover{color:var(--color-slate-900)}}.disabled\:opacity-50:disabled{opacity:.5}@media (min-width:40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * --- Kebab React 全页面示例组件 ---
3
+ *
4
+ * 【使用方式】
5
+ * 在 Ctr 方法中调用 _loadReactPage('view/react-page', { ...props }),
6
+ * 框架自动注入 _importMapJson / _hydrateScript / _propsJson 三个内部 props,
7
+ * 组件在 <head> 和 <body> 末尾渲染对应的 <script> 标签即可,其余部分与普通 React 组件无异。
8
+ *
9
+ * 【多页面 / 共用组件】
10
+ * 将公共 UI(如 Button/Card/Badge)放在 stc/lib/ 目录,各页面 import 进来。
11
+ * tsc watch 会自动将所有 .tsx 编译为同路径的 .js,无需打包工具。
12
+ *
13
+ * 【编译方式】
14
+ * 本文件 (.tsx) 已集成到 source/tsconfig.json 的 include 中,
15
+ * 开启 `tsc: watch - source/tsconfig.json` 即可自动编译,无需额外命令。
16
+ * 编译输出:stc/view/react-page.js(由 tsc 覆盖写入,勿手动编辑 .js 文件)
17
+ *
18
+ * 【运行时机】
19
+ * - 服务端(Node.js):_loadReactPage() 调用 renderToString(),产出完整 HTML 字符串。
20
+ * - 客户端(浏览器):import map 将 bare import 解析到 esm.sh,hydrateRoot 接管 document。
21
+ * - 两端使用同一份 JS 文件:服务端从磁盘读,浏览器从静态 URL 下载。
22
+ *
23
+ * 【限制】
24
+ * - 不能包含 Node.js 专属代码(fs/path/lDb 等),数据必须通过 props 传入。
25
+ * - 等价于 Next.js 的 Client Component,而非 Server Component。
26
+ */
27
+ interface IProps {
28
+ 'title': string;
29
+ 'serverTime': string;
30
+ 'node': string;
31
+ '_urlBase': string;
32
+ '_urlStc': string;
33
+ '_urlFull': string;
34
+ '_staticVer': string;
35
+ /** --- 框架注入:import map JSON 字符串,<head> 中以 type="importmap" <script> 渲染 --- */
36
+ '_importMapJson'?: string;
37
+ /**
38
+ * --- 框架注入:水合 JS 代码字符串,</body> 前以 type="module" <script> 渲染 ---
39
+ * --- 内容:import hydrateRoot + import App + hydrateRoot(document, createElement(App, p)) ---
40
+ */
41
+ '_hydrateScript'?: string;
42
+ /**
43
+ * --- 框架注入:fullProps 的 JSON 序列化(不含 _propsJson 本身)---
44
+ * --- 客户端水合脚本读取此值重建 props,suppressHydrationWarning 处理服务端/客户端内容差异 ---
45
+ */
46
+ '_propsJson'?: string;
47
+ }
48
+ /** --- Kebab React 全页面演示 --- */
49
+ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc, _importMapJson, _hydrateScript, _propsJson }: IProps): import("react/jsx-runtime").JSX.Element;
50
+ export {};
@@ -0,0 +1,136 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * --- Kebab React 全页面示例组件 ---
4
+ *
5
+ * 【使用方式】
6
+ * 在 Ctr 方法中调用 _loadReactPage('view/react-page', { ...props }),
7
+ * 框架自动注入 _importMapJson / _hydrateScript / _propsJson 三个内部 props,
8
+ * 组件在 <head> 和 <body> 末尾渲染对应的 <script> 标签即可,其余部分与普通 React 组件无异。
9
+ *
10
+ * 【多页面 / 共用组件】
11
+ * 将公共 UI(如 Button/Card/Badge)放在 stc/lib/ 目录,各页面 import 进来。
12
+ * tsc watch 会自动将所有 .tsx 编译为同路径的 .js,无需打包工具。
13
+ *
14
+ * 【编译方式】
15
+ * 本文件 (.tsx) 已集成到 source/tsconfig.json 的 include 中,
16
+ * 开启 `tsc: watch - source/tsconfig.json` 即可自动编译,无需额外命令。
17
+ * 编译输出:stc/view/react-page.js(由 tsc 覆盖写入,勿手动编辑 .js 文件)
18
+ *
19
+ * 【运行时机】
20
+ * - 服务端(Node.js):_loadReactPage() 调用 renderToString(),产出完整 HTML 字符串。
21
+ * - 客户端(浏览器):import map 将 bare import 解析到 esm.sh,hydrateRoot 接管 document。
22
+ * - 两端使用同一份 JS 文件:服务端从磁盘读,浏览器从静态 URL 下载。
23
+ *
24
+ * 【限制】
25
+ * - 不能包含 Node.js 专属代码(fs/path/lDb 等),数据必须通过 props 传入。
26
+ * - 等价于 Next.js 的 Client Component,而非 Server Component。
27
+ */
28
+ import { useState, useEffect } from 'react';
29
+ import { MemoryRouter, Routes, Route, Link, useParams, useNavigate } from 'react-router-dom';
30
+ // ─── shadcn/ui 风格基础控件 ───────────────────────────────────────────────────
31
+ // 以下组件是 Tailwind + React 的轻量实现,与 shadcn/ui 源码结构完全一致。
32
+ // 生产环境可直接替换为 shadcn/ui 官方组件,import map 会通过 esm.sh 自动
33
+ // 解析 Radix UI 等所有依赖,无需本地 npm install 也无需打包工具。
34
+ /** --- 卡片容器 --- */
35
+ function Card({ children, className = '' }) {
36
+ return (_jsx("div", { className: `bg-white rounded-xl shadow-sm border border-slate-200 p-6 ${className}`, children: children }));
37
+ }
38
+ /** --- 标签徽章 --- */
39
+ function Badge({ children, variant = 'default' }) {
40
+ const styles = {
41
+ 'default': 'bg-blue-100 text-blue-700',
42
+ 'success': 'bg-green-100 text-green-700',
43
+ 'warn': 'bg-amber-100 text-amber-700',
44
+ };
45
+ return (_jsx("span", { className: `inline-flex px-2.5 py-0.5 rounded-md text-xs font-semibold ${styles[variant]}`, children: children }));
46
+ }
47
+ /** --- 按钮 --- */
48
+ function Btn({ children, onClick, disabled = false, outline = false }) {
49
+ /** --- 填充/轮廓两种样式 --- */
50
+ const style = outline
51
+ ? 'border border-slate-300 text-slate-700 hover:bg-slate-50'
52
+ : 'bg-blue-500 hover:bg-blue-600 text-white';
53
+ return (_jsx("button", { onClick: onClick, disabled: disabled, className: `inline-flex items-center px-4 py-2 rounded-lg text-sm font-medium transition-colors disabled:opacity-50 cursor-pointer ${style}`, children: children }));
54
+ }
55
+ // ─── Router 演示子页面 ─────────────────────────────────────────────────────────
56
+ /** --- 路由 Home 页 --- */
57
+ function RouterHome() {
58
+ return (_jsxs("div", { children: [_jsxs("p", { className: "text-slate-700 text-sm font-medium mb-3", children: ["\u5F53\u524D\u8DEF\u7531\uFF1A", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/" })] }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx(Link, { to: "/about", className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium", children: "\u2192 /about" }), _jsx(Link, { to: "/user/42", className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium", children: "\u2192 /user/42" }), _jsx(Link, { to: "/user/hello", className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium", children: "\u2192 /user/hello" })] })] }));
59
+ }
60
+ /** --- 路由 About 页 --- */
61
+ function RouterAbout() {
62
+ const navigate = useNavigate();
63
+ return (_jsxs("div", { children: [_jsxs("p", { className: "text-slate-700 text-sm font-medium mb-3", children: ["\u5F53\u524D\u8DEF\u7531\uFF1A", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/about" })] }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "useNavigate() \u6F14\u793A\u7F16\u7A0B\u5BFC\u822A\uFF08\u4E0D\u4F7F\u7528 Link \u7EC4\u4EF6\uFF09\uFF1A" }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: () => navigate('/'), className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer", children: "\u2190 \u8FD4\u56DE /" }), _jsx("button", { onClick: () => navigate('/user/99'), className: "inline-flex items-center px-3 py-1.5 rounded-lg bg-blue-500 hover:bg-blue-600 text-white text-xs font-medium cursor-pointer", children: "\u2192 /user/99" })] })] }));
64
+ }
65
+ /** --- 路由 User 动态参数页 --- */
66
+ function RouterUser() {
67
+ const { id } = useParams();
68
+ const navigate = useNavigate();
69
+ return (_jsxs("div", { children: [_jsxs("p", { className: "text-slate-700 text-sm font-medium mb-1", children: ["\u5F53\u524D\u8DEF\u7531\uFF1A", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/user/:id" })] }), _jsxs("p", { className: "text-slate-500 text-xs mb-3", children: ["useParams() \u8BFB\u53D6\u52A8\u6001\u6BB5\uFF1A", _jsxs("code", { className: "bg-slate-100 px-1 rounded", children: ["id = \"", id, "\""] })] }), _jsx("button", { onClick: () => navigate('/'), className: "inline-flex items-center px-3 py-1.5 rounded-lg border border-slate-300 hover:bg-slate-50 text-slate-700 text-xs font-medium cursor-pointer", children: "\u2190 \u8FD4\u56DE /" })] }));
70
+ }
71
+ // ─── 页面主组件 ────────────────────────────────────────────────────────────────
72
+ /** --- Kebab React 全页面演示 --- */
73
+ export default function ReactPage({ title, serverTime, node, _urlBase, _urlStc, _importMapJson, _hydrateScript, _propsJson }) {
74
+ // --- useState 在 SSR 阶段使用初始值渲染,客户端水合后变为可交互状态 ---
75
+ const [count, setCount] = useState(0);
76
+ const [tab, setTab] = useState('overview');
77
+ const [fetchResult, setFetchResult] = useState(null);
78
+ const [isFetching, setIsFetching] = useState(false);
79
+ /** --- 仅客户端为 true,用于展示水合已完成 --- */
80
+ const [hydrated, setHydrated] = useState(false);
81
+ // --- useEffect 在 SSR 阶段不执行,只在浏览器端水合完成后触发 ---
82
+ useEffect(() => {
83
+ setHydrated(true);
84
+ }, []);
85
+ /**
86
+ * --- 发起 fetch 请求并更新结果状态 ---
87
+ * @param url 请求地址
88
+ */
89
+ function doFetch(url) {
90
+ setIsFetching(true);
91
+ setFetchResult(null);
92
+ fetch(url)
93
+ .then(r => r.json())
94
+ .then((data) => {
95
+ setFetchResult(JSON.stringify(data, null, 2));
96
+ setIsFetching(false);
97
+ })
98
+ .catch((e) => {
99
+ setFetchResult(`Error: ${e.message}`);
100
+ setIsFetching(false);
101
+ });
102
+ }
103
+ return (
104
+ // --- 组件渲染完整 HTML 文档,无需外部 EJS 模板 ---
105
+ _jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }), _jsx("title", { children: title }), _importMapJson && (_jsx("script", { type: "importmap", dangerouslySetInnerHTML: { '__html': _importMapJson } })), _jsx("script", { src: "https://cdn.tailwindcss.com" })] }), _jsxs("body", { className: "bg-slate-50 min-h-screen font-sans", children: [_jsxs("div", { className: "max-w-3xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex gap-2 mb-2", children: [_jsx(Badge, { children: "SSR \u00B7 Kebab" }), _jsx(Badge, { variant: hydrated ? 'success' : 'warn', children: hydrated ? 'Hydrated ✓' : 'Rendering...' })] }), _jsx("h1", { className: "text-2xl font-bold text-slate-900", children: title }), _jsxs("p", { className: "text-slate-500 text-sm mt-1", children: [serverTime, " \u00B7 ", node] })] }), _jsx("div", { className: "flex gap-1 bg-slate-100 p-1 rounded-lg w-fit", children: ['overview', 'routing', 'fetch'].map(t => (_jsx("button", { onClick: () => setTab(t), className: [
106
+ 'px-4 py-2 rounded-md text-sm font-medium transition-colors cursor-pointer',
107
+ tab === t ? 'bg-white shadow text-slate-900' : 'text-slate-500 hover:text-slate-900',
108
+ ].join(' '), children: t.charAt(0).toUpperCase() + t.slice(1) }, t))) }), tab === 'overview' && (_jsxs("div", { className: "space-y-4", children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "Counter\uFF08useState + hydration\uFF09" }), _jsx("p", { className: "text-slate-500 text-xs mb-4", children: "SSR \u6E32\u67D3\u521D\u59CB\u503C 0\uFF0Cprops \u5E8F\u5217\u5316\u4E3A\u5185\u8054 JSON\u3002 \u6C34\u5408\u5B8C\u6210\u540E state \u53D8\u4E3A\u53EF\u4EA4\u4E92\uFF0C\u70B9\u51FB\u6309\u94AE\u6D4B\u8BD5\uFF1A" }), _jsxs("div", { className: "flex items-center gap-4", children: [_jsx("button", { onClick: () => setCount(c => c - 1), className: "w-10 h-10 rounded-lg border border-slate-300 hover:bg-slate-50 font-bold text-slate-700 text-xl cursor-pointer", children: "\u2212" }), _jsx("span", { className: "text-3xl font-bold text-slate-900 w-10 text-center tabular-nums", children: count }), _jsx("button", { onClick: () => setCount(c => c + 1), className: "w-10 h-10 rounded-lg bg-blue-500 hover:bg-blue-600 text-white font-bold text-xl cursor-pointer", children: "+" })] })] }), _jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-3", children: "Server Props\uFF08\u6765\u81EA Ctr \u65B9\u6CD5\uFF09" }), _jsxs("p", { className: "text-slate-500 text-xs mb-3", children: ["\u901A\u8FC7", ' ', _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_loadReactPage(path, props)" }), ' ', "\u4F20\u5165\uFF0C\u6846\u67B6\u81EA\u52A8\u6CE8\u5165 _urlBase \u7B49\u5E38\u91CF\uFF0C \u6574\u4F53\u5E8F\u5217\u5316\u4E3A\u5185\u8054 JSON\uFF0C\u5BA2\u6237\u7AEF\u6C34\u5408\u65F6\u76F4\u63A5\u590D\u7528\uFF0C\u65E0\u9700\u4E8C\u6B21\u8BF7\u6C42\u3002"] }), _jsx("div", { className: "space-y-2", children: [
109
+ ['serverTime', serverTime],
110
+ ['node', node],
111
+ ['_urlBase', _urlBase],
112
+ ['_urlStc', _urlStc],
113
+ ].map(([k, v]) => (_jsxs("div", { className: "flex text-xs gap-4", children: [_jsx("span", { className: "text-slate-400 font-mono w-28 shrink-0", children: k }), _jsx("span", { className: "font-mono text-slate-700 truncate", children: v })] }, k))) })] }), _jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "shadcn/ui \u517C\u5BB9\u6027" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "shadcn/ui = Tailwind + Radix UI\u3002\u672C\u9875\u7684 Card/Badge/Btn \u662F\u7B49\u6548\u7684\u8F7B\u91CF\u5B9E\u73B0\u3002 \u4F7F\u7528\u5B98\u65B9 shadcn/ui \u7EC4\u4EF6\u65F6\uFF0C\u5176 Radix UI \u4F9D\u8D56\u7531 esm.sh \u9012\u5F52\u89E3\u6790\uFF0C \u4E0E\u6253\u5305\u5DE5\u5177\u7684\u5904\u7406\u7ED3\u679C\u5B8C\u5168\u7B49\u4EF7\uFF0C\u65E0\u9700\u672C\u5730 npm install\u3002" }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "success", children: "Card \u2713" }), _jsx(Badge, { variant: "success", children: "Badge \u2713" }), _jsx(Badge, { variant: "success", children: "Btn \u2713" }), _jsx(Badge, { children: "Radix UI Dialog \u540C\u6837\u652F\u6301" })] })] })] })), tab === 'routing' && (
114
+ /*
115
+ MemoryRouter:路由状态保存在内存中,服务端 SSR 和客户端水合均可运行,
116
+ 无需服务端配置 catch-all 路由,适合在页面内嵌入独立的路由演示。
117
+ 若要整页接管 URL,改用 BrowserRouter(需服务端对所有子路径返回同一页面)。
118
+ */
119
+ _jsxs(MemoryRouter, { children: [_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-1", children: "React Router \u6F14\u793A" }), _jsxs("p", { className: "text-slate-500 text-xs mb-4", children: ["\u4F7F\u7528 ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "MemoryRouter" }), ' ', "\u6F14\u793A\u8DEF\u7531\u8DF3\u8F6C\u3001\u52A8\u6001\u53C2\u6570\uFF08useParams\uFF09\u548C\u7F16\u7A0B\u5BFC\u822A\uFF08useNavigate\uFF09\uFF0C \u670D\u52A1\u7AEF SSR \u4E0E\u5BA2\u6237\u7AEF\u6C34\u5408\u5747\u53EF\u8FD0\u884C\uFF0C\u65E0\u9700\u989D\u5916\u670D\u52A1\u7AEF\u914D\u7F6E\u3002"] }), _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(RouterHome, {}) }), _jsx(Route, { path: "/about", element: _jsx(RouterAbout, {}) }), _jsx(Route, { path: "/user/:id", element: _jsx(RouterUser, {}) })] })] }), _jsxs(Card, { className: "mt-4", children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-2", children: "\u6574\u9875 BrowserRouter \u914D\u7F6E" }), _jsx("p", { className: "text-slate-500 text-xs mb-3", children: "\u82E5\u8981\u8BA9 React Router \u63A5\u7BA1\u6574\u4E2A\u9875\u9762\u7684\u771F\u5B9E URL\uFF08\u5982 /app\u3001/app/about\uFF09\uFF0C \u5C06 MemoryRouter \u66FF\u6362\u4E3A BrowserRouter\uFF0C\u5E76\u5728\u670D\u52A1\u7AEF\u5C06\u6240\u6709\u5B50\u8DEF\u5F84\u8DEF\u7531\u5230\u540C\u4E00 Ctr \u65B9\u6CD5\uFF1A" }), _jsx("pre", { className: "bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: `// 1. route.json:将所有子路径指向同一 Ctr 方法
120
+ {
121
+ "app": "ctr/app@reactPage",
122
+ "app\\/.*": "ctr/app@reactPage"
123
+ }
124
+
125
+ // 2. 客户端(浏览器):BrowserRouter 自动读取当前 URL
126
+ import { BrowserRouter } from 'react-router-dom';
127
+ hydrateRoot(document,
128
+ createElement(BrowserRouter, { basename: '/app' },
129
+ createElement(App, props)));
130
+
131
+ // 3. 服务端 SSR:StaticRouter 使用请求 URL,避免水合差异
132
+ import { StaticRouter } from 'react-router-dom/server';
133
+ renderToString(
134
+ createElement(StaticRouter, { location: reqPath },
135
+ createElement(App, props)));` })] })] })), tab === 'fetch' && (_jsxs(Card, { children: [_jsx("h2", { className: "font-semibold text-slate-900 mb-3", children: "Client Fetch Demo" }), _jsx("p", { className: "text-slate-500 text-xs mb-4", children: "\u6C34\u5408\u5B8C\u6210\u540E\uFF0C\u70B9\u51FB\u6309\u94AE\u53D1\u8D77 GET \u8BF7\u6C42\u3002setState \u89E6\u53D1\u5C40\u90E8\u91CD\u6E32\u67D3\uFF0C\u65E0\u9875\u9762\u5237\u65B0\u3002" }), _jsxs("div", { className: "flex gap-3 flex-wrap", children: [_jsx(Btn, { onClick: () => doFetch(`${_urlBase}test/json?type=4`), disabled: isFetching, children: isFetching ? 'Fetching...' : 'GET /test/json?type=4' }), _jsx(Btn, { outline: true, onClick: () => doFetch(`${_urlBase}test/json?type=2`), disabled: isFetching, children: "GET type=2 (error resp)" })] }), fetchResult !== null ? (_jsx("pre", { className: "mt-4 bg-slate-50 border border-slate-200 rounded-lg p-4 text-xs overflow-auto leading-relaxed text-slate-700", children: fetchResult })) : (_jsx("p", { className: "mt-3 text-slate-400 text-xs", children: "Click a button above to see the response" }))] }))] }), _jsx("script", { id: "__kebab_props__", type: "application/json", suppressHydrationWarning: true, dangerouslySetInnerHTML: { '__html': _propsJson ?? '' } }), _hydrateScript && (_jsx("script", { type: "module", dangerouslySetInnerHTML: { '__html': _hydrateScript } }))] })] }));
136
+ }